06-22-2022 05:44 PM
I've done some experimenting with automating software installs using powershell and winget. As many of you know, one of the primary blockers to winget is the fact that it runs in the user session. After a few hours of reading discussions on github, I came across this thread with a promising approach from rothgecw to running winget as system. This opened up a world of possibility!
In my testing I discovered that when winget upgrades, the old directory in C:\Program Files\WindowsApps isn't always deleted so I needed a way to find the most up to date version of winget in the WindowsApps folder. Hence the first part of the script below. I start by finding the directory winget is installed in, if there are multiple versions, I sort the directories by path and save the last path as a variable. From there I write the output of the variable to the console for sanity and troubleshooting purposes so I can see the directory in the command results from within the JumpCloud admin console. Then I cd to that directory and we are ready to start using winget as system.
Note: winget must be installed for this to work.
#Powershell script that checks if apps are installed and installs them if they aren't
#Query for directory most updated winget.exe is stored in
$wingetdir = (Resolve-Path "C:\Program Files\WindowsApps\Microsoft.DesktopAppInstaller_*_x64__8wekyb3d8bbwe" | Sort-Object -Property Path | Select-Object -Last 1)
#Output directory
Write-Host "cd to directory: $wingetdir"
#navigate to directory containing winget.exe
cd $wingetdir
After navigating to the correct directory, we can pass commands to winget. Below is an example of a powershell script that installs Adobe Acrobat Reader on a system if it isn't already installed. I start by searching the device for the software using winget list. Then I use an if statement to determine whether or not the software needs installed. If the software does need installed, I pass the following command to winget for a silent install of Adobe Acrobat Reader: winget install --id 'Adobe.Acrobat.Reader.64-bit' --silent --accept-package-agreements --accept-source-agreements.
#Variable containing results of search for app on the system
$AdobeReader = (.\winget.exe list --id 'Adobe.Acrobat.Reader.64-bit')
#If statement to install app or move on
If ($AdobeReader -like '*No installed package found*')
{
.\winget.exe install --id 'Adobe.Acrobat.Reader.64-bit' --silent --accept-package-agreements --accept-source-agreements
}
else
{
Write-Host 'Adobe Reader is already installed.'
}
All together:
#Script that checks if apps are installed and installs them if they aren't
#Query for directory most updated winget.exe is stored in
$wingetdir = (Resolve-Path "C:\Program Files\WindowsApps\Microsoft.DesktopAppInstaller_*_x64__8wekyb3d8bbwe" | Sort-Object -Property Path | Select-Object -Last 1)
#Output directory
Write-Host "cd to directory: $wingetdir"
#navigate to directory containing winget.exe
cd $wingetdir
#Variable containing results of search for app on the system
$AdobeReader = (.\winget.exe list --id 'Adobe.Acrobat.Reader.64-bit')
#If statement to install app or move on
If ($AdobeReader -like '*No installed package found*')
{
.\winget.exe install --id 'Adobe.Acrobat.Reader.64-bit' --silent --accept-package-agreements --accept-source-agreements
}
else
{
Write-Host 'Adobe Reader is already installed.'
}
Winget has a very helpful feature that allows users to update all of their apps with a single command: winget upgrade --all
To make use of this, I have a JumpCloud command that creates a scheduled task on the users machine and moves a script to a desired directory to be ran at each user login.
Full disclosure: we aren't using this portion below in production yet, we are currently testing the user experience.
Script containing winget upgrade --all command:
#Query for directory most updated winget.exe is stored in
$wingetdir = (Resolve-Path "C:\Program Files\WindowsApps\Microsoft.DesktopAppInstaller_*_x64__8wekyb3d8bbwe" | Sort-Object -Property Path | Select-Object -Last 1)
#Output directory
Write-Host "cd to directory: $wingetdir"
#navigate to directory containing winget.exe
cd $wingetdir
#Command to update all apps with updates available. | Outfile is optional but I find it helpful for knowing the script ran on login.
.\winget.exe upgrade --all --silent --accept-package-agreements --accept-source-agreements | Out-File -FilePath 'C:\Path\To\CommandResults.txt' -Force
Script that creates the scheduled task to run the above script on each user login as system:
#Move the Winget Upgrade script to the desired directory here.
#Once the script is in the correct directory, create the scheduled task.
#Create Task to run at logon
echo 'Creating scheduled task'
#Create variables needed for the task
$action = New-ScheduledTaskAction -Execute "C:\Windows\System32\WindowsPowershell\v1.0\powershell.exe" -Argument '-ExecutionPolicy Bypass -File "C:\Path\To\WingetUpgrade.ps1"'
$trigger = New-ScheduledTaskTrigger -AtLogon
$principal = New-ScheduledTaskPrincipal -UserID "NT AUTHORITY\SYSTEM" -LogonType ServiceAccount -RunLevel Highest
$settings = New-ScheduledTaskSettingsSet
$description = 'runs: winget upgrade --all --silent --accept-package-agreemments --accept-source-agreements at logon to keep applications up to date.'
#Create the Task
$task = New-ScheduledTask -Action $action -Principal $principal -Trigger $trigger -Settings $settings -Description $description
#Register the Task
Register-ScheduledTask WingetUpgrade -InputObject $task
#Enable the task
Enable-ScheduledTask -TaskName "WingetUpgrade"
#Test task was created
$TestTask = (Get-ScheduledTask -TaskName 'WingetUpgrade')
echo 'Outputting result of task creation'
Write-Host $TestTask
}
08-03-2022 11:23 AM
Thanks for sharing Jacob. Been following winget for a while but running with Jumpcloud has never been successful.
Just tested the script above to install an app but it just returns Adobe Reader is already installed, but actually its not installed on the device.
Have you stumbled across this issue before ? Or where do you reckon I might have gone wrong?
08-03-2022 11:52 AM
Want to share the script as you are running it and the message you receive, @chhetriabi? Maybe that will help @JacobLawson and others.
Like someone's post? Give them a kudo!
Did someone's answer help you? Please mark it as a solution.
08-03-2022 01:12 PM
@BeckyScott Sure thing.
So the script is literally the same as @JacobLawson has posted above but to install OpenVPN Connect. I have tried the above script and the result is the same for Adobe Reader too.
Here is the screen recording: https://drive.google.com/file/d/12ngwFLfiERZGgy_eXmDJgvIpqvbDP9o5/view?usp=sharing
Here is the script from Jacob where I have just replaced Adobe to install OpenVPN
$wingetdir = (Resolve-Path "C:\Program Files\WindowsApps\Microsoft.DesktopAppInstaller_*_x64__8wekyb3d8bbwe" | Sort-Object -Property Path | Select-Object -Last 1)
Write-Host "cd to directory: $wingetdir"
cd $wingetdir
$OpenVPNConnect = (.\winget.exe list --id 'OpenVPNTechnologies.OpenVPNConnect')
If ($OpenVPNConnect -like '*No installed package found*')
{
.\winget.exe install --id 'OpenVPNTechnologies.OpenVPNConnect' --silent --accept-package-agreements --accept-source-agreements
}
else
{
Write-Host 'OpenVPN Connect is already installed.'
}
I have the ps file uploaded to the command and have just executed from there
08-03-2022 02:01 PM
Hi @chhetriabi
I copied and pasted your script from above for OpenVPN Connect and it worked. Here are my results:
cd to directory: C:\Program Files\WindowsApps\microsoft.desktopappinstaller_1.18.2091.0_x64__8wek
yb3d8bbwe
-\
███▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ 1024 KB / 8.55 MB
███████▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ 2.00 MB / 8.55 MB
██████████▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ 3.00 MB / 8.55 MB
██████████████▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ 4.00 MB / 8.55 MB
█████████████████▒▒▒▒▒▒▒▒▒▒▒▒▒ 5.00 MB / 8.55 MB
█████████████████████▒▒▒▒▒▒▒▒▒ 6.00 MB / 8.55 MB
████████████████████████▒▒▒▒▒▒ 7.00 MB / 8.55 MB
████████████████████████████▒▒ 8.00 MB / 8.55 MB
██████████████████████████████ 8.55 MB / 8.55 MB
Found OpenVPN Connect [OpenVPNTechnologies.OpenVPNConnect] Version 3.3.6
This application is licensed to you by its owner.
Microsoft is not responsible for, nor does it grant any licenses to, third-party packages.
Downloading https://swupdate.openvpn.net/downloads/connect/openvpn-connect-3.3.6.2752_signed.msi
-\|/
█▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ 3.00 MB / 67.7 MB
█████▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ 11.7 MB / 67.7 MB
█████████▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ 21.7 MB / 67.7 MB
█████████████▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ 30.7 MB / 67.7 MB
████████████████████▒▒▒▒▒▒▒▒▒▒ 45.7 MB / 67.7 MB
███████████████████████████▒▒▒ 62.7 MB / 67.7 MB
██████████████████████████████ 67.7 MB / 67.7 MB
Successfully verified installer hash
Starting package install...
-\|/-\|/-\|
Successfully installed
Can you share the results JC collects from when you run it?
A couple things come to mind:
I'm curious to see what your results are currently. If you could share those, that would be great.
08-03-2022 02:12 PM - edited 08-03-2022 02:13 PM
I just watched the video you shared and you cleared up a couple things. Winget is installed and OpenVPN isn't already installed, at least for that user session.
The if statement is showing as false so I'm curious what the output of $OpenVPNConnect is. Can you run this and share the results?
$wingetdir = (Resolve-Path "C:\Program Files\WindowsApps\Microsoft.DesktopAppInstaller_*_x64__8wekyb3d8bbwe" | Sort-Object -Property Path | Select-Object -Last 1)
Write-Host "cd to directory: $wingetdir"
cd $wingetdir
$OpenVPNConnect = (.\winget.exe list --id 'OpenVPNTechnologies.OpenVPNConnect')
$OpenVPNConnect
If ($OpenVPNConnect -like '*No installed package found*')
{
.\winget.exe install --id 'OpenVPNTechnologies.OpenVPNConnect' --silent --accept-package-agreements --accept-source-agreements
}
else
{
Write-Host 'OpenVPN Connect is already installed.'
}
09-13-2022 12:22 PM
Hey @JacobLawson ,
Sorry about the delay. I have given this a go again and this has worked by calling the winget.exe.
cd "C:\Program Files\WindowsApps\Microsoft.DesktopAppInstaller_*_x64__8wekyb3d8bbwe"
.\winget.exe install --id 'SlackTechnologies.Slack' --silent --accept-package-agreements --accept-source-agreements --scope machine
Where I wanted to force update the MS Store to update winget (App Installer) to the latest version I ran this:
Get-CimInstance -Namespace "Root\cimv2\mdm\dmmap" -ClassName "MDM_EnterpriseModernAppManagement_AppManagement01" | Invoke-CimMethod -MethodName UpdateScanMethod
It does take a while to kick off the update (around 10 min ish) - I am not sure why.
I noticed that for installing you need the parametres
--accept-package-agreements --accept-source-agreements
But to uninstall the above parametres does not work if you are uninstalling an application (atleast for me), so I just used,
--accept-source-agreements
Appreciate your help @JacobLawson .Looking forward to this being integrated to JumpCloud as it can now run from commands.
09-16-2022 07:14 AM
I am curious to know why you do not use the Jumpcloud built-in Chocolatey functionality, do you mind sharing your thoughts behind?
09-16-2022 07:30 AM
winget is microsoft's own project. Its a trust thing for me, personally
11-01-2022 09:06 AM
Yeah, a trust thing for us as well. My team's leadership is more inclined to trust winget's repo.
New to the site? Take a look at these additional resources:
Ready to join us? You can register here.