Keeping your software up to date using winget and PowerShell

  • Gérald Barré

winget is a package manager for Windows. You can use winget install <package> to install new software. You can also use winget upgrade <package> or winget upgrade --all --silent to upgrade one or all installed software. But what if you want to upgrade only a subset of your installed software? Or what if you want to schedule the upgrade to run every night? In this post, I describe how to use winget and PowerShell Core to keep your software up to date on a Windows machine.

There are multiple winget clients. You can use it using the winget.exe or using PowerShell. The PowerShell flavor is the one I'm going to use in this post. The interesting point of PowerShell is that you can easily query installed packages and filter them out.

Before using winget from PowerShell, you must install it using the following command:

Install-Module -Name Microsoft.WinGet.Client

You can query all packages having an update available using the following command:

Get-WinGetPackage | Where-Object { $_.IsUpdateAvailable }

You can update all packages using:

Get-WinGetPackage | Where-Object { $_.IsUpdateAvailable } | Update-WinGetPackage

If you want to exclude specific packages from the update, you can use the following command:

Get-WinGetPackage `
    | Where-Object { $_.IsUpdateAvailable } `
    | Where-Object { $_.Id -notlike "TechSmith.*" } `
    | Update-WinGetPackage

#Auto update using a scheduled task

  1. Create a new file named WingetUpdate.ps1 ps1 file:

    WingetUpdate.ps1 (PowerShell)
    Install-Module -Name Microsoft.WinGet.Client
        | Where-Object {$_.IsUpdateAvailable}
        | Where-Object {$_.Id -notlike "TechSmith*"} # You can filter out packages you don't want to update
        | Update-WinGetPackage
  2. Create a new scheduled task using the following command:

    # Note: This script must be run as admin if "-RunLevel Highest" is present
    # TODO replace with the actual path to the script
    $ScriptPath=(Resolve-Path "WingetUpdate.ps1").Path
    $WinGet = "$env:LOCALAPPDATA\Microsoft\WindowsApps\winget.exe"
    $Pwsh = (Get-Command pwsh).Source
    $Time = New-ScheduledTaskTrigger -At 04:00 -Daily
    $Actions = @(
        # Update all sources, so that winget can find the latest version of the packages
        New-ScheduledTaskAction -Execute "$WinGet" -Argument "source update"
        New-ScheduledTaskAction -Execute "$Pwsh" -Argument "`"$ScriptPath`"}`""
    $Settings = New-ScheduledTaskSettingsSet -WakeToRun:$false `
                                            -MultipleInstances IgnoreNew `
                                            -RunOnlyIfNetworkAvailable:$true `
    Register-ScheduledTask -TaskName "Update winget" -TaskPath Updates `
                           -Trigger $Time -Action $Actions -Settings $Settings `
                           -RunLevel Highest # Remove this one if you don't want to run the task as admin

You can open the Task Scheduler to see the new task. You can also run it manually to see if it works as expected.

Do you have a question or a suggestion about this post? Contact me!

Follow me:
Enjoy this blog?Buy Me A Coffee💖 Sponsor on GitHub