Hi everyone!
As we are now using Ninja to serve our customers and their third-party apps list is kinda poor for now, we are trying to make Winget work, but it is proving quite difficult so far.
There is a thread about it in the Ninja Dojo: https://ninjarmm.zendesk.com/hc/fr/community/posts/4420149880973-Winget
Basically, we have a script that creates a new admin account on each workstation (this part runs fine), and then we have another script that periodically launches winget to upgrade the apps.
It only works if we use the âcurrent logged in userâ option. If we use another admin account, it says that winget command is not recognized, even if we open the powershell and type the command ourselves.
PATH is okay, and the command works fine when we log into the account directly on the computer, so we donât know what could be missingâŚ
Has anyone ran into this issue too?
Iâve run into a similar issue when running the Winget command from a PowerShell script run as the âsystemâ account. I canât see the post you linked to as you have to have login I have worked around it and can explain in more detail, but I donât have time right now. Iâll try and remember to update this post this evening.
I donât know if this is related to your issue or not, but the issue when running it as âsystemâ is because it doesnât actually exist, or at least not as âWingetâ. As Winget is a modern Windows App (urgh), the executable is located under the running users local profile, but in the case of âsystemâ there is no such thing as a profile, so Winget cannot be called. However, Winget is actually a program called âAppInstallerCLI.exeâ which resides under âC:\Program Files\WindowsApps\Microsoft.DesktopAppInstaller_*_x64__8wekyb3d8bbweâ (where * is a version number) and can only be run as âsystemâ. So to run as the âsystemâ account you simply need to call this in place of Winget. Below is an example script Iâve written to show you how you can work around this issue.
<#
.SYNOPSIS
A basic script to demonstrate Winget
.DESCRIPTION
A basic script to demonstrate Winget running as either a logged on user or as the 'System' user.
Use with PSExec https://docs.microsoft.com/en-gb/sysinternals/downloads/psexec to see it running as the 'System' user
.INPUTS
None.
.OUTPUTS
When run with '-debug', a debug log file will be created under the current users 'temp' folder, as well as details being output to the console. The log file is useful if running the script as 'system' on a scheduled task etc. as obviously you can not see the console output.
.EXAMPLE
PS> .\wingetExample.ps1
.EXAMPLE
PS> .\wingetExample.ps1 -debug
#>
[CmdletBinding()]
param()
#Editable Variables
$excludedPackages = @("Microsoft.Office", "Microsoft.dotnet", "7zip.7zip") #Skip these packages as they cause issues when upgrading
$logFile = $env:TEMP + "\Winget_log.txt"
#Variables
$Head = 0
$packageCount = 0
$runningUser = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name
#Function to write debug information to a log file
function debugMessage($message) {
if ($DebugPreference -eq 'Continue') {
add-content -Encoding ASCII $logFile ("$(get-date -f dd-MM-yyyy_hh:mm:ss) $message")
}
Write-Debug ("$message")
}
#Wipe previous log file if it exists
if (Test-Path -Path $logFile -PathType Leaf) {
Remove-Item $logFile
}
debugMessage -message "Running as $runningUser"
#Get a list of packages to upgrade
if ($runningUser -eq "NT Authority\system") {
$AppPath = Resolve-Path "C:\Program Files\WindowsApps\Microsoft.DesktopAppInstaller_*_x64__8wekyb3d8bbwe"
set-location -path $AppPath
((.\AppInstallerCLI.exe upgrade --accept-source-agreements | Format-Table -AutoSize) | Out-String).Split([Environment]::NewLine, [System.StringSplitOptions]::RemoveEmptyEntries) > $null #Run this to accept agreements, doesn't work as one command for 'upgrade'
$Winget_Upgrade_Search = ((.\AppInstallerCLI.exe upgrade | Format-Table -AutoSize) | Out-String).Split([Environment]::NewLine, [System.StringSplitOptions]::RemoveEmptyEntries)
}
else {
((winget upgrade --accept-source-agreements | Format-Table -AutoSize) | Out-String).Split([Environment]::NewLine, [System.StringSplitOptions]::RemoveEmptyEntries) > $null
$Winget_Upgrade_Search = ((winget upgrade | Format-Table -AutoSize) | Out-String).Split([Environment]::NewLine, [System.StringSplitOptions]::RemoveEmptyEntries)
}
#If we have packages to upgrade convert the list to a PowerShell object so we can work with items more easliy
If ($Winget_Upgrade_Search[$Winget_Upgrade_Search.Count - 1] -like "*upgrades available*") {
#Get the header details
$Winget_Upgrade_Search | ForEach-Object {
If ($_ -like "------------------------------*") {
$Head = ($Winget_Upgrade_Search.IndexOf($_))
}
}
$Winget_Header = $Winget_Upgrade_Search[($Head) - 1] -split "\s{2,}"
$Winget_Upgrade_App_List = @()
$Winget_Upgrade_Search[($Head + 1)..($Winget_Upgrade_Search.Count + 1)] | ForEach-Object {
If ($_ -notlike "*upgrades available*") {
$results = $_ | Select-String "([^\s]+)" -AllMatches
$Splits = @('', '', '', '')
$Splits[3] = $results.Matches[$results.Matches.Length - 2]
$Splits[2] = $results.Matches[$results.Matches.Length - 3]
$Splits[1] = $results.Matches[$results.Matches.Length - 4]
for ($i = 0; $i -lt ($results.Matches.Length - 4); $i++) {
if ($i -ne ($results.Matches.Length - 5)) {
$Splits[0] += $results.Matches[$i].Value + " "
}
else {
$Splits[0] += $results.Matches[$i].Value
}
}
$Stack = new-object psobject
$Stack | Add-Member -membertype noteproperty -name "$($Winget_Header[0])" -Value $($Splits[0])
$Stack | Add-Member -membertype noteproperty -name "$($Winget_Header[1])" -Value $($Splits[1])
$Stack | Add-Member -membertype noteproperty -name "$($Winget_Header[2])" -Value $($Splits[2])
$Stack | Add-Member -membertype noteproperty -name "$($Winget_Header[3])" -Value $($Splits[3])
$Winget_Upgrade_App_List += $Stack
}
}
}
foreach ($item in $Winget_Upgrade_App_List) {
if (!$excludedPackages.Contains($item.Id.Value)) {
debugMessage -message "Upgrade available for $($item.Name), from $($item.Version.Value), to $($item.Available.Value)"
$packageCount ++
}
else {
debugMessage -message "Skipping $($item.Name) as it is on an exclusion list"
}
}
debugMessage -message "$packageCount with upgrades available"
Thank you very much for your insights, I will investigate as soon as I can 
Seems like something MS could simplify a little bit though!
Yes it is a bit odd. I get the feeling Winget was a program developed on the side and someone thought âhey this is great letâs release it!â Before they put any real thought into it.
1 Like
I will have a look at Chocolatey as an alternative ! It seems like their paid version is able to sync the list of programs already installed and take over their updates management. They also have a dashboard, which will be pretty handy, and prices are very affordable ! (provided they donât have a minimum number of licenses to order)
One thing that I donât know is if it is quite easy to add up licenses directly from their dashboard, without the need to get in touch with a sales rep first !
I looked at chocolatey and if you can get the budget (min 100 licenses) then itâs probably far far better, sadly I couldnât.
OuchâŚ100 licences upfrontâŚI donât have that many workstations to manage for the moment.
It seems kinda hard to find affordable solutions to provide interesting packages when youâre starting small !
Hi again 
We finally decided to let go of Winget and give PatchMyPC a shot, and it seems like a good trade so far !
We just downloaded the EXE and put it in a folder in c:\ (which will be the same for all workstations), and we created a simple script on Ninja that launches the proper command (basically the name of the EXE with /s ).
After all this, the software runs smootly at set intervals (even as System) and does its job 
Ninja partners with Ivanti for the third-party side of things, but I fail to understand why they canât have a repo as thorough as winget or chocolatey haveâŚ
PatchMyPC seems to work a little bit differently, as they download the executables directly from the official link.