Modern Desktop Architect

Using Winget with custom manifests (and auto updates) -Updated


With the release of Winget, we now have another app deployment method which works nicely with Intune.

At the moment building a custom Winget repo is not an easy task, but you can deploy using a custom manifest.

This blog post will cover how to use a custom manifest stored online to deploy an application and then using a runbook

The first thing to note is that a custom manifest has to be local, either on the machine itself, or on a network drive. Therefore we’ll grab the file and store it locally

The scripts I’m using are here: https://github.com/andrew-s-taylor/public/tree/main/Powershell%20Scripts/Winget

If you want to grab some manifests to test, the official repo is here: https://github.com/microsoft/winget-pkgs/tree/master/manifests

If we use Chrome as an example, most manifests will include 3 files, an installer, a locale and an app one, we need to get all 3

Update 12/11/21 – Thanks to the excellent work of Phil Jorgensen this can now run in the System Context which removes the admin rights requirement

First up, create a temp folder for the files to live in (I’ve opted for a random with the date):

$directory = $env:TEMP
#Create Temp location
$random = Get-Random -Maximum 1000 
$random = $random.ToString()
$date =get-date -format yyMMddmmss
$date = $date.ToString()
$path2 = $random + "-"  + $date
$path = $directory + "\" + $path2 + "\"
new-item -ItemType Directory -Path $path

Now specify the filenames to use:

##File Name
$templateFilePathinstaller = $path + "chrome.installer.yaml"
$templateFilePathlocale = $path + "chrome.locale.yaml"
$templateFilePathversion = $path + "chrome.yaml"

Then download them:

Invoke-WebRequest `
   -Uri "https://raw.githubusercontent.com/andrew-s-taylor/winget/main/manifests/g/Google/Chrome/92.0.4515.107/Google.Chrome.installer.yaml" `
   -OutFile $templateFilePathinstaller `
   -UseBasicParsing `
   -Headers @{"Cache-Control"="no-cache"}


   Invoke-WebRequest `
   -Uri "https://raw.githubusercontent.com/andrew-s-taylor/winget/main/manifests/g/Google/Chrome/92.0.4515.107/Google.Chrome.locale.en-US.yaml" `
   -OutFile $templateFilePathlocale `
   -UseBasicParsing `
   -Headers @{"Cache-Control"="no-cache"}
   
   

   Invoke-WebRequest `
   -Uri "https://raw.githubusercontent.com/andrew-s-taylor/winget/main/manifests/g/Google/Chrome/92.0.4515.107/Google.Chrome.yaml" `
   -OutFile $templateFilePathversion `
   -UseBasicParsing `
   -Headers @{"Cache-Control"="no-cache"}  

Finally, install them. Note, as it is a multi-file manifest, the path is the containing folder which is why it’s best to download each into their own folder. With a single file manifest, you can specify the manifest file, but I find it’s easier to use the folder to keep things the same

winget install --silent  --manifest $path

Or to run in the system context, create a variable for Winget to the AppInstallerCLI and use that

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

   &$winget install --silent  --manifest $templateFilePath

The next thing we can do is use Proactive Remediations to keep your apps up to date:

Again, scripts are both on github:
https://github.com/andrew-s-taylor/public/blob/main/Powershell%20Scripts/winget-update-check.ps1

https://github.com/andrew-s-taylor/public/blob/main/Powershell%20Scripts/winget-upgrade.ps1

Winget at present isn’t the most powershell friendly so the check is simply counting the number of lines returned, anything 3 or less means no updates

Try {
    $updatecheck = winget upgrade
    If ($updatecheck.count -lt 3){
        Write-Output "Compliant"
        Exit 0
    } 
    Write-Warning "Not Compliant"
    Exit 1
} 
Catch {
    Write-Warning "Not Compliant"
    Exit 1
}

Update: Using the system context:

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

    $updatecheck = &$winget upgrade
    If ($updatecheck.count -lt 3){
        Write-Output "Compliant"
        Exit 0
    } 
    Write-Warning "Not Compliant"
    Exit 1
} 
Catch {
    Write-Warning "Not Compliant"
    Exit 1
}

Then upgrade:

winget upgrade --all --force --silent

Update: System Context:

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

&$winget upgrade --all --force --silent

Note 1: I haven’t yet found a way to exclude an application from an -all upgrade which is slightly annoying because I’d prefer office updates to be handled via Intune directly. If anyone has found a way, let me know in the comments!

Note 2 – WHEN NOT USING NEW SYSTEM CONTEXT: When adding to Intune, make sure to select Run in the logged-in credentials or the scripts will fail:

That’s it, run at whatever schedule suits you and let the apps update themselves. Remember if it’s a custom app with a custom manifest, you’ll need to update the manifest file version too.

I’ll add a post on a custom repo once it’s a bit more user friendly

2 Comments

Add a Comment

Your email address will not be published. Required fields are marked *