Ensure Microsoft Updates that match the passed criteria are installed.
    Updates will be downloaded if needed.

    This state allows you to update a system without specifying a specific
    update to apply. All matching updates will be installed.

    Args:

        name (str):
            The name has no functional value and is only used as a tracking
            reference

        software (bool):
            Include software updates in the results (default is True)

        drivers (bool):
            Include driver updates in the results (default is False)

        skip_hidden (bool):
            Skip updates that have been hidden. Default is False.

        skip_mandatory (bool):
            Skip mandatory updates. Default is False.

        skip_reboot (bool):
            Skip updates that require a reboot. Default is True.

        categories (list):
            Specify the categories to list. Must be passed as a list. All
            categories returned by default.

            Categories include the following:

            * Critical Updates
            * Definition Updates
            * Drivers (make sure you set drivers=True)
            * Feature Packs
            * Security Updates
            * Update Rollups
            * Updates
            * Update Rollups
            * Windows 7
            * Windows 8.1
            * Windows 8.1 drivers
            * Windows 8.1 and later drivers
            * Windows Defender

        severities (list):
            Specify the severities to include. Must be passed as a list. All
            severities returned by default.

            Severities include the following:

            * Critical
            * Important


    Returns:
        dict: A dictionary containing the results of the update

    CLI Example:

    .. code-block:: yaml

        # Update the system using the state defaults
        update_system:
          wua.uptodate

        # Update the drivers
        update_drivers:
          wua.uptodate:
            - software: False
            - drivers: True
            - skip_reboot: False

        # Apply all critical updates
        update_critical:
          wua.uptodate:
            - severities:
              - Critical

def uptodate(name,
             software=True,
             drivers=False,
             skip_hidden=False,
             skip_mandatory=False,
             skip_reboot=True,
             categories=None,
             severities=None,):
    '''
    Ensure Microsoft Updates that match the passed criteria are installed.
    Updates will be downloaded if needed.

    This state allows you to update a system without specifying a specific
    update to apply. All matching updates will be installed.

    Args:

        name (str):
            The name has no functional value and is only used as a tracking
            reference

        software (bool):
            Include software updates in the results (default is True)

        drivers (bool):
            Include driver updates in the results (default is False)

        skip_hidden (bool):
            Skip updates that have been hidden. Default is False.

        skip_mandatory (bool):
            Skip mandatory updates. Default is False.

        skip_reboot (bool):
            Skip updates that require a reboot. Default is True.

        categories (list):
            Specify the categories to list. Must be passed as a list. All
            categories returned by default.

            Categories include the following:

            * Critical Updates
            * Definition Updates
            * Drivers (make sure you set drivers=True)
            * Feature Packs
            * Security Updates
            * Update Rollups
            * Updates
            * Update Rollups
            * Windows 7
            * Windows 8.1
            * Windows 8.1 drivers
            * Windows 8.1 and later drivers
            * Windows Defender

        severities (list):
            Specify the severities to include. Must be passed as a list. All
            severities returned by default.

            Severities include the following:

            * Critical
            * Important


    Returns:
        dict: A dictionary containing the results of the update

    CLI Example:

    .. code-block:: yaml

        # Update the system using the state defaults
        update_system:
          wua.uptodate

        # Update the drivers
        update_drivers:
          wua.uptodate:
            - software: False
            - drivers: True
            - skip_reboot: False

        # Apply all critical updates
        update_critical:
          wua.uptodate:
            - severities:
              - Critical
    '''
    ret = {'name': name,
           'changes': {},
           'result': True,
           'comment': ''}

    wua = salt.utils.win_update.WindowsUpdateAgent()

    available_updates = wua.available(
        skip_hidden=skip_hidden, skip_installed=True,
        skip_mandatory=skip_mandatory, skip_reboot=skip_reboot,
        software=software, drivers=drivers, categories=categories,
        severities=severities)

    # No updates found
    if available_updates.count() == 0:
        ret['comment'] = 'No updates found'
        return ret

    updates = list(available_updates.list().keys())

    # Search for updates
    install_list = wua.search(updates)

    # List of updates to download
    download = salt.utils.win_update.Updates()
    for item in install_list.updates:
        if not salt.utils.data.is_true(item.IsDownloaded):
            download.updates.Add(item)

    # List of updates to install
    install = salt.utils.win_update.Updates()
    for item in install_list.updates:
        if not salt.utils.data.is_true(item.IsInstalled):
            install.updates.Add(item)

    # Return comment of changes if test.
    if __opts__['test']:
        ret['result'] = None
        ret['comment'] = 'Updates will be installed:'
        for update in install.updates:
            ret['comment'] += '\n'
            ret['comment'] += ': '.join(
                [update.Identity.UpdateID, update.Title])
        return ret

    # Download updates
    wua.download(download)

    # Install updates
    wua.install(install)

    # Refresh windows update info
    wua.refresh()

    post_info = wua.updates().list()

    # Verify the installation
    for item in install.list():
        if not salt.utils.data.is_true(post_info[item]['Installed']):
            ret['changes']['failed'] = {
                item: {'Title': post_info[item]['Title'][:40] + '...',
                       'KBs': post_info[item]['KBs']}
            }
            ret['result'] = False
        else:
            ret['changes']['installed'] = {
                item: {'Title': post_info[item]['Title'][:40] + '...',
                       'NeedsReboot': post_info[item]['NeedsReboot'],
                       'KBs': post_info[item]['KBs']}
            }

    if ret['changes'].get('failed', False):
        ret['comment'] = 'Updates failed'
    else:
        ret['comment'] = 'Updates installed successfully'

    return ret