ninja-one/winget.ps1
|
#Requires -Version 5.1 <# .SYNOPSIS Install, Uninstall, or Upgrade a package using WinGet. .DESCRIPTION Install, Uninstall, or Upgrade a package using WinGet. #> # RUNNING AS SYSTEM DOES NOT INSTALL MS STORE APPS USING WINGET.EXE param( [Parameter()] [String]$Action, [Parameter()] [String]$PackageId, [Parameter()] [String]$PackageIdSelect, [Parameter()] [switch]$MachineScope = [System.Convert]::ToBoolean($env:machineScope) ) begin { # Check for required PowerShell version (7+) if (!($PSVersionTable.PSVersion.Major -ge 7)) { try { # Install PowerShell 7 if missing if (!(Test-Path "$env:SystemDrive\Program Files\PowerShell\7")) { Write-Output 'Installing PowerShell version 7...' Invoke-Expression "& { $( Invoke-RestMethod https://aka.ms/install-powershell.ps1 ) } -UseMSI -Quiet" } # Refresh PATH $env:Path = [System.Environment]::GetEnvironmentVariable('Path', 'Machine') + ';' + [System.Environment]::GetEnvironmentVariable('Path', 'User') # Restart script in PowerShell 7 pwsh -File "`"$PSCommandPath`"" @PSBoundParameters } catch { Write-Output '[ERROR] PowerShell 7 was not installed. Update PowerShell and try again.' Write-Error $_ exit 1 } finally { exit $LASTEXITCODE } } else { $PSStyle.OutputRendering = 'PlainText' } function Test-IsElevated { $id = [System.Security.Principal.WindowsIdentity]::GetCurrent() $p = New-Object System.Security.Principal.WindowsPrincipal($id) return $p.IsInRole([System.Security.Principal.WindowsBuiltInRole]::Administrator) } if (-not (Test-IsElevated)) { Write-Warning "Many apps require administrator privileges in order to install, uninstall, or upgrade. This action may fail however some apps like Zoom may work." } # generate timestamp string $timestamp = Get-Date -Format "yyyy-MM-dd_HH-mm-ss" Start-Transcript -Path "$env:TEMP\ninja_winget-$timestamp.log" -IncludeInvocationHeader } process { try { $silent = "--silent" $acceptpackageagreements = "--accept-package-agreements" $acceptsourceagreements = "--accept-source-agreements" $disableinteractivity = "--disable-interactivity" $uninstallArgs = $acceptsourceagreements, $disableinteractivity, $silent $installArgs = $silent, $acceptsourceagreements, $disableinteractivity, $acceptpackageagreements if ($MachineScope) { $installArgs += "--scope", "machine" $uninstallArgs += "--scope", "machine" } else { $installArgs += "--scope", "user" $uninstallArgs += "--scope", "user" } $WinGetPath = "$ENV:PROGRAMDATA\JRE-WinGet" function InstallWinGet() { function BuildWinGet() { New-Item -Path $WinGetPath -Name "build" -ItemType "directory" -Force | Out-Null $WinGetDepsUrl = ((Invoke-RestMethod -uri 'https://api.github.com/repos/microsoft/winget-cli/releases/latest').assets | Where-Object { $_.browser_download_url.EndsWith('DesktopAppInstaller_Dependencies.zip') } | Select-Object -First 1).browser_download_url Invoke-WebRequest $WinGetDepsUrl -OutFile "$WinGetPath/build/Microsoft.DesktopAppInstallerDependencies.zip" -UseBasicParsing Expand-Archive -Path "$WinGetPath/build/Microsoft.DesktopAppInstallerDependencies.zip" -DestinationPath "$WinGetPath/build/Microsoft.DesktopAppInstallerDependencies" foreach ($file in Get-ChildItem -Path "$WinGetPath/build/Microsoft.DesktopAppInstallerDependencies/x64" -Filter "*.msix") { Rename-Item -Path $file.FullName -NewName ($file.BaseName + ".zip") Expand-Archive -Path "$WinGetPath/build/Microsoft.DesktopAppInstallerDependencies/x64/$($file.BaseName).zip" -DestinationPath "$WinGetPath/build/WinGet" -Force } $WinGetUrl = ((Invoke-RestMethod -uri 'https://api.github.com/repos/microsoft/winget-cli/releases/latest').assets | Where-Object { $_.browser_download_url.EndsWith('msixbundle') } | Select-Object -First 1).browser_download_url Invoke-WebRequest $WinGetUrl -OutFile "$WinGetPath/build/Microsoft.DesktopAppInstaller.zip" -UseBasicParsing Expand-Archive -Path "$WinGetPath/build/Microsoft.DesktopAppInstaller.zip" -DestinationPath "$WinGetPath/build/Microsoft.DesktopAppInstaller" Rename-Item -Path "$WinGetPath/build/Microsoft.DesktopAppInstaller/AppInstaller_x64.msix" -NewName "AppInstaller_x64.zip" Expand-Archive -Path "$WinGetPath/build/Microsoft.DesktopAppInstaller/AppInstaller_x64.zip" -DestinationPath "$WinGetPath/build/WinGet" -Force Remove-Item -Path "$WinGetPath/WinGet" -Recurse -Force -ErrorAction SilentlyContinue Move-Item -Path "$WinGetPath/build/WinGet" -Destination $WinGetPath -PassThru Remove-Item -Path "$WinGetPath/build" -Recurse -Force -ErrorAction SilentlyContinue # cmd /c setx /M PATH "%PATH%;$ENV:PROGRAMFILES\WinGet" # give the Users group full control over the WinGet directory $acl = Get-Acl -Path $WinGetPath $rule = New-Object System.Security.AccessControl.FileSystemAccessRule("Authenticated Users", "FullControl", "ContainerInherit,ObjectInherit", "None", "Allow") $acl.SetAccessRule($rule) Set-Acl -Path $WinGetPath -AclObject $acl } if (-not (Test-Path "$WinGetPath\WinGet\winget.exe" -PathType Leaf)) { Write-Output "Downloading WinGet and dependencies..." BuildWinGet } else { Write-Output "WinGet is already installed. Checking for updates..." $WinGetVersion = (Invoke-RestMethod -uri 'https://api.github.com/repos/microsoft/winget-cli/releases/latest').tag_name $WinGetInstalledVersion = & "$WinGetPath\WinGet\winget.exe" --version if ($WinGetInstalledVersion -eq $WinGetVersion) { Write-Output "WinGet is already at the latest version ($WinGetVersion). Skipping installation." return } Write-Output "Updating WinGet to version $WinGetVersion..." Remove-Item -Path $WinGetPath -Recurse -Force -ErrorAction Stop BuildWinGet } } try { InstallWinGet } catch { if ($_.Exception.Message -match "no valid module file was found") { Write-Host "[INFO] WinGet directory found but module not loaded. Removing and retrying..." Remove-Item -Path $WinGetPath -Recurse -Force InstallWinGet } else { throw $_ } } $WinGetPath = "$WinGetPath\WinGet\winget.exe" $spinners = '\', '/', '|', '-' | ForEach-Object { "^\s*\$_\s*`$" } | Join-String -Separator '|' $progressBars = '█', '▒' | ForEach-Object { "^.+\$_.+`$" } | Join-String -Separator '|' $blankLine = '^\s*$' $skip = "$spinners|$progressBars|$blankLine" if (-not $Action) { if ($env:action -and $env:action -notlike "null") { $Action = $env:action } else { Write-Host "[Error] You must specify an action to take (Install, Uninstall or Upgrade)" exit 1 } } if (-not $PackageId) { if ($env:packageId -and $env:packageId -notlike "null") { $PackageId = $env:packageId } } if (-not $PackageId -and -not $PackageIdSelect) { if ($env:packageIdSelect -and $env:packageIdSelect -notlike "null") { $PackageId = $env:packageIdSelect } } Write-Host "[INFO] Running WinGet with action: $Action" Write-Host "[INFO] Running WinGet with Package ID: $PackageId" if ($Action -like "Install") { if (-not $PackageId) { Write-Host "[ERROR] You must specify a Package ID to install" exit 1 } if ($PackageId -like "*`,*") { $packageIds = $PackageId -split "," | ForEach-Object { $_.Trim() } foreach ($tmpPackageId in $packageIds) { & $WinGetPath install --id $tmpPackageId $installArgs | Where-Object { $_ -notmatch $skip } } } else { & $WinGetPath install --id $PackageId $installArgs | Where-Object { $_ -notmatch $skip } } } if ($Action -like "Uninstall") { if (-not $PackageId) { Write-Host "[ERROR] You must specify a Package ID to uninstall" exit 1 } if ($PackageId -like "*`,*") { $packageIds = $PackageId -split "," | ForEach-Object { $_.Trim() } foreach ($tmpPackageId in $packageIds) { Write-Host "[INFO] Uninstalling $tmpPackageId..." & $WinGetPath uninstall --id $tmpPackageId $uninstallArgs | Where-Object { $_ -notmatch $skip } } } else { Write-Host "[INFO] Uninstalling $PackageId..." & $WinGetPath uninstall --id $PackageId $uninstallArgs | Where-Object { $_ -notmatch $skip } } } if ($Action -like "Upgrade" -OR $Action -like "Update") { if (-not $PackageId) { & $WinGetPath upgrade --all $installArgs | Where-Object { $_ -notmatch $skip } } else { if ($PackageId -like "*`,*") { $packageIds = $PackageId -split "," | ForEach-Object { $_.Trim() } foreach ($tmpPackageId in $packageIds) { Write-Host "[INFO] Updating $tmpPackageId..." & $WinGetPath upgrade --id $tmpPackageId $installArgs | Where-Object { $_ -notmatch $skip } } } else { Write-Host "[INFO] Updating $PackageId..." & $WinGetPath upgrade --id $PackageId $installArgs | Where-Object { $_ -notmatch $skip } } } } Write-Host "[INFO] Completed running WinGet." exit 0 } catch { Write-Host "[ERROR] Error running WinGet." Write-Host "[ERROR] Error occurred at line number: $($_.InvocationInfo.ScriptLineNumber)" Write-Error $_.exception exit 1 } } end { Stop-Transcript } |