winget updates Proactive Remediations

winget Updates | Proactive Remediations

  • 13. September 2022

The easiest way to perform updates for all winget applications via Intune or in general is via Scheduled Task or with a Proactive Remediation script. However, it is not always desirable or sensible to update all applications. That's why I've started updating selected winget applications with the Proactive Remediations feature.

In the following I will show you how you can update both variants, all applications or just one selectively.

The Proactive Remediations feature is NOT licensed under "Microsoft 365 Business Premium”!
How you can still use them, I'll show you here: "Proactive Remediation for Business" | scloud

Table of Contents

Update all applications

With the command "winget upgrade --all" you can update all pending updates that are available in the Windows Package Manager.
We can trigger this function with a Proactive Remediations package as soon as winget updates are on the horizon.

It is important to note that Everyone (also not installed via winget) packages on the computer receive updates.

You can download both scripts here:

Winget cannot be used in the system context simply with the command wings be called. That is why you will find the resolution of the path to winget.exe in all scripts that we run in the system context:

$Winget = Get-ChildItem -Path (Join-Path -Path (Join-Path -Path $env:ProgramFiles -ChildPath "WindowsApps") -ChildPath "Microsoft.DesktopAppInstaller*_x64*\winget.exe") 
Code language: PowerShell (powershell)

This is then used in code with the command &$winget called.

Detection Rule - Are there any winget updates?

To find out if any update is available, we can simply run the command "wing upgrade" and then check whether it gives us feedback.

$Winget = Get-ChildItem -Path (Join-Path -Path (Join-Path -Path $env:ProgramFiles -ChildPath "WindowsApps") -ChildPath "Microsoft.DesktopAppInstaller*_x64*\winget.exe")

if ($(&$winget upgrade) -gt 3) {
	Write-Host "Upgrade(s) available."
	exit 1 # upgrade available, remediation needed
else {
	Write-Host "No Upgrade available"
	exit 0 # no upgrade, no action needed
Code language: PowerShell (powershell)

Remediation Script - perform all updates

If the detection script ends with the exit code "1", this signals that the remediation script must be executed.
In this we now trigger the upgrade command with the necessary parameters to ensure that the user sees nothing and that the updates run "silently".

    $Winget = Get-ChildItem -Path (Join-Path -Path (Join-Path -Path $env:ProgramFiles -ChildPath "WindowsApps") -ChildPath "Microsoft.DesktopAppInstaller*_x64*\winget.exe")

    # upgrade command for ALL
    &$winget upgrade --all
    exit 0

    Write-Error "Error while installing upgrade for: $app_2upgrade"
    exit 1
Code language: PowerShell (powershell)

Until recently, winget's update command was as follows. Unfortunately, this does not work with the current version.

&$winget upgrade --all --silent --force --accept-package-agreements --accept-source-agreements

Update specific application

Much rather than updating all the apps, I only update the ones I want and preferably control them per application.
In addition, I then have an individual group for each application, which is assigned to both the app and the Proactive Remediations package.

Because creating per app is a bit more tedious, I created a script that prepares the corresponding package right away. More on that below.

Detection rule for winget updates

To detect if a specific app has an update, I call the command again wing upgrade on. But this time I filter it by the winget ID and only trigger the remediation if it is recognized in the pending updates.
In the detection it is important that you enter the desired ID in the first line instead of WINGETPROGRAMID (e.g. Microsoft.VisualStudioCode).

$app_2upgrade = "WINGETPROGRAMID"

# resolve and navigate to winget.exe
$Winget = Get-ChildItem -Path (Join-Path -Path (Join-Path -Path $env:ProgramFiles -ChildPath "WindowsApps") -ChildPath "Microsoft.DesktopAppInstaller*_x64*\winget.exe")

if ($(&$winget upgrade) -like "* $app_2upgrade *") {
	Write-Host "Upgrade available for: $app_2upgrade"
	exit 1 # upgrade available, remediation needed
else {
	Write-Host "No Upgrade available"
	exit 0 # no upgrade, no action needed
Code language: PowerShell (powershell)

Remediation - update of a single app

Now we have recognized that our app has a pending update and of course we want to run it.
To do this, we call the upgrade command with the --exactly parameters and the corresponding ID. You can store the ID again in the top line.

$app_2upgrade = "WINGETPROGRAMID"

    # resolve and navigate to winget.exe
    $Winget = Get-ChildItem -Path (Join-Path -Path (Join-Path -Path $env:ProgramFiles -ChildPath "WindowsApps") -ChildPath "Microsoft.DesktopAppInstaller*_x64*\winget.exe")

    # upgrade command
    &$winget upgrade --exact $app_2upgrade --silent --force --accept-package-agreements --accept-source-agreements
    exit 0

    Write-Error "Error while installing upgrade for: $app_2upgrade"
    exit 1
Code language: PowerShell (powershell)

Create / Upload Proactive Remediation Script

It doesn't matter whether you have decided to update all apps or a specific one. Creating the package in Endpoint Manager is the same for both.

The Proactive Remediation feature is a bit hidden, you can find it at:
Reports > Endpoint analytics > Proactive remediations
Here you select "Create script package" and assign a meaningful name:

In the second step you can already upload the detection and remediation script. If you are updating a specific app, don't forget to adjust the ID before uploading.
So that the resolution of winget.exe works correctly, we run the script in the x64 bit context.

Proactive remediations, scripts

You don't necessarily have to set a scope tag.

When assigning you know the desired target group.
For specific apps, I select a group with the app name, to which I can then assign devices or other groups.
I set the interval to "Daily". If the device is not active at execution time, the task is caught up on.

Proactive remediations, Zuweisung und Schedule

Now all you have to do is click "Next" and send the configuration.

Automatically create proactive remediations

If you now have 10, 20 or more applications and want to set up a PAR rule for all of them, you have to adapt the detection and remediation script each time, upload and assign them - tedious!
So I made a simple script to automate it.

The script takes the same files as described above as a basis and also changes the string "WINGETPROGRAMID". In addition, it uploads the package, assigns it and sets the schedule.

Application (easy)

  1. Download the script "procative-remediation-creation.ps1".
  2. Run the script via PowerShell (right click "Run with PowerShell" or via Terminal)
  3. Fill in the requested data
    1. PAR_name = friendly name of the package
    2. winget_id = ID of the desired winget APP
    3. PAR_AADGroup = Group to which the package is assigned
  4. If the required PowerShell modules are not yet installed, they will be installed (Microsoft.Graph, AzureAD)
  5. The package is created and the two scripts are stored in the execution folder.
  6. Script package is uploaded and assigned to the specified group.
    During this time you have to log in twice. The first time is for the upload to the Endpoint Manager and the second time to read out the group ID for assignment.

Application for advanced

You can call up the script via the terminal with additional parameters, for example to store your own description.
Here are all possible parameters:

Publisherwird in der PAR-Übersicht angezeigt
PAR_nameAnzeige Name des Pakets
winget_idWinget ID, die in den beiden Scripts verwendet wird
PAR_descriptionBeschreibung des Pakets
Standard: Automatically created via PowerShell
PAR_RunAssystem (default) oder user
PAR_SchedulerDaily (default) oder Hourly
PAR_FrequencyIntervall der Ausführung, default: 1
PAR_StartTimeStartzeit für "Daily" Ausführung
PAR_RunAs32$true für Ausführung im 32bit Kontext
$false für Ausführung im 64bit Kontext (default)
PAR_AADGroupGruppe für die Zuweisung des PAR-Pakets
PAR_script_detectionPfad zum Detection Script (wird automatisch erstellt)
PAR_script_remediationPfad zum Remediation Script (wird automatisch erstellt)

Here is an example of how the script can be called:

call procative-remediation-creation.ps1 script

Kudos and further automation

Thanks @AndrewTaylor for the idea and your Proactive Remediations upload script: Creating Intune Proactive Remediation via Powershell

I will also include the updates via winget and proactive remediations function in my "Intune Win32 Deployer" integrate.