Скрипт для обновления приложений через WinGet не запускается через GPO.

Вопрос или проблема

Я написал следующий скрипт на PowerShell для обновления приложений через WinGet и принудительной деинсталляции и повторной установки, если обновление не удается:

<#
.SYNOPSIS
    Устанавливает модуль клиента Powershell WinGet.
.DESCRIPTION
    Проверяет, установлен ли модуль клиента Powershell WinGet. Если нет, пытается установить его.
    Если установка не удается, программа завершает выполнение.
.NOTES
    Модуль можно найти здесь: https://www.powershellgallery.com/packages/Microsoft.WinGet.Client/1.10.320.
#>
function Install-WinGetClientModule {
    # Проверка, установлен ли официальный клиент Powershell WinGet.
    if (Get-Module -ListAvailable -Name Microsoft.WinGet.Client) {
        Write-Host "Модуль Powershell для клиента диспетчера пакетов Windows установлен."
    } else {
        # Установка поставщика пакетов NuGet, который необходим для установки модуля.
        Write-Host "Установка NuGet..."
        Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force

        # Проверка успешности установки NuGet.
        if ($?) {
            Write-Host "Успешно установлено." -ForegroundColor Green
        } else {
            # Если установка не была завершена, выход из скрипта.
            Write-Host "Не удалось установить NuGet." -ForegroundColor Red
            exit
        }

        # Установка PSGallery как доверенного репозитория для установки.
        Set-PSRepository -Name "PSGallery" -InstallationPolicy Trusted

        # Установка модуля.
        Write-Host "Установка модуля Powershell для клиента диспетчера пакетов Windows..."
        Install-Module -Name Microsoft.WinGet.Client

        # Проверка успешности установки модуля.
        if ($?) {
            Write-Host "Успешно установлено." -ForegroundColor Green
        } else {
            # Если установка не была завершена, выход из скрипта.
            Write-Host "Не удалось установить модуль Powershell для клиента диспетчера пакетов Windows." -ForegroundColor Red
            exit
        }
    }
}


<#
.SYNOPSIS
    Получить приложения WinGet, требующие обновления.
#>
function Get-ApplicationsWithUpdates {
    # Сохраняет приложения с доступными обновлениями через WinGet
    $applicationsWithUpdates = Get-WinGetPackage | Where-Object IsUpdateAvailable

    return $applicationsWithUpdates
}

<#
.SYNOPSIS
    Обновление приложений через WinGet.
#>
function Update-Applications {
    param (
        [Parameter(Mandatory = $true)]
        [Array]$applicationsToUpdate
    )
    
    # Обновление каждого указанного приложения.
    foreach ($app in $applicationsToUpdate) {
        $appName = $app.Name
        $appId = $app.Id
        Write-Host "Обновление $appName..."
        
        # Обновление приложения
        winget upgrade --id $appId --accept-package-agreements --accept-source-agreements
        
        # Проверка успешности обновления приложения.
        if ($?) {
            Write-Host "$appName обновлено до последней версии." -ForegroundColor Green
        } else {
            # Если обновление не удалось, попытка переустановки.
            Write-Host "Не удалось обновить $appName. Пытаемся переустановить..."
            winget uninstall --id $appId --silent --accept-source-agreements
            winget install --id $appId --accept-package-agreements --accept-source-agreements

            # Проверка успешности переустановки приложения.
            if ($?) {
                Write-Host "$appName обновлено до последней версии." -ForegroundColor Green
            } else {
                Write-Host "Не удалось обновить $appName." -ForegroundColor Red
            }
        }
    }
}


function Main {
    # Получение клиента Powershell WinGet.
    Install-WinGetClientModule

    # Проверка обновлений приложения через WinGet.
    $applicationsToUpdate = Get-ApplicationsWithUpdates
    Write-Host $applicationsToUpdate

    # Проверка, что число приложений для обновления не равно 0.
    if ($applicationsToUpdate.Count -gt 0) {
        # Обновление приложений.
        Update-Applications -ApplicationsToUpdate $applicationsToUpdate
    } else {
        Write-Host "Все приложения обновлены."
    } 
}


# Запуск скрипта.
Main

Когда я запускаю его вручную через терминал, он работает, как ожидалось. Однако он не работает как скрипт запуска групповой политики по пути Конфигурация компьютера\Политики\Параметры Windows\Сценарии(запуск/завершение работы).

Я включил выполнение сценариев в Конфигурация компьютера\Политики\Административные шаблоны\Компоненты Windows\Windows Powershell, установив политику выполнения на “Разрешены все скрипты” (это только для тестирования и не развертывается для всех пользователей).

Я тестировал работу скрипта, устанавливая более старые версии программ через WinGet, принудительно обновляя групповые политики, перезапуская компьютер и ожидая более 5 минут, чтобы скрипт мог выполняться асинхронно. Пока мне не удалось заставить скрипт работать.

Есть ли что-то, что я упускаю, чтобы этот скрипт работал при запуске?

Ответ или решение

Безусловно, запуск сценариев через Group Policy в Windows может быть не самым простым процессом, особенно когда речь идет о сценариях обновления приложений с использованием WinGet. Во-первых, давайте рассмотрим теорию, которая стоит за структурой работы групповой политики и выполнения сценариев начальной загрузки.

Теория

Сценарии запуска через групповые политики выполняются во время процесса загрузки компьютера, до входа пользователя в систему. Это значит, что они выполняются в контексте локальной системы, а не пользователя. Сценарии запуска требуют административных привилегий, и если они полагаются на пользовательские сеансы, может возникнуть множество нюансов.

Из-за особенностей выполнения, существуют некоторые ограничения на окружение, в котором запуск сценария может проходить. Например:

  1. Ограниченные права доступа: Поскольку сценарий выполняется в контексте локальной системы, он имеет доступ ко всем системным ресурсам, но не имеет доступа к ресурсам пользователя.
  2. Задержки в применении GPO: Порой может требоваться несколько загрузок, чтобы групповые политики корректно применились.
  3. Отсутствие пользовательских настроек среды: Когда PowerShell запускается как часть сценария запуска, он может не иметь доступ к переменным среды, как в интерактивной сессии.

Пример

Рассмотрим ваш сценарий. Он пытается установить NuGet и модуль Microsoft.WinGet.Client, что требует установки доверительных репозиториев и наличия сети. В контексте запуска по групповой политике, могли возникнуть следующие проблемы:

  • Сетевые ограничения: Если на момент запуска сценария сеть еще не доступна, установка может не пройти.
  • Политики доверительных репозиториев: Если репозиторий PSGallery не отмечен как доверительный, установка из него может не сработать.

Применение

Чтобы ваш сценарий работал корректно, рассмотрите следующие изменения и рекомендации:

  1. Проверка среды выполнения: Убедитесь, что при запуске сценария доступны все необходимые сетевые ресурсы. Вы можете встроить логирование в ваш сценарий для отслеживания, где именно он может прерываться.

  2. Логирование процесса: Добавьте логи в сценарий, которые будут выводиться в файл, чтобы вы могли увидеть, на каком этапе и почему он может прерываться.

Start-Transcript -Path C:\Logs\StartupScriptLog.txt -Append
  1. Планировщик задач: Рассмотрите возможность использования Планировщика задач для выполнения сценария после загрузки системы или входа пользователя в систему, что понизит вероятность отсутствия сети.

  2. Проверка репозиториев: Выполняйте установку необходимых модулей и пакетов в отдельный пользовательский сценарий, который можно запустить в интерактивном сеансе с конкретными привилегиями проверки репозиториев и политики доверия.

  3. Модификация политики исполнения: Убедитесь, что ваша политика исполнения позволяет выполнение сценариев. Даже временное изменение политики может быть оправдано для отладки и верификации работы полноценного сценария.

Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Scope LocalMachine
  1. Инициализация инфраструктуры: В случае наличия других зависимостей \ лицензий, следует убедиться, что они доступны и корректно инициализированы до запуска основного процесса.

  2. Обновление GPO: Убедитесь, что машина получает последние обновления GPO. Используйте команды gpresult /r или gpupdate /force, чтобы удостовериться в этом.

Заключительно, любой сценарий или процесс, задуманный для автоматизации, требует тщательной проверки и часто итеративного тестирования, чтобы поддерживать непрерывность его выполнения. Сочетание логирования, промежутков восстановления и поведения во время разрыва связи должны быть тщательно протестированы в различных условиях.

Оцените материал
Добавить комментарий

Капча загружается...