Installs and repairs the Windows Package Manager and its dependencies so software deployment works unattended, including the awkward cases: Server SKUs, the SYSTEM account context and a broken App Installer registration. Based on the well-known winget-install work by asheroto, credited in the header, and the prerequisite for deploying software through ServerEngine.
powershell
# - - - - - PowerShell - - - - - #
# This prepares Windows Package Manager (WinGet) for automated software
# deployment through ServerEngine. It ensures WinGet is properly installed,
# configured, and functional for enterprise software management.
# Credits: Based on work from: https://github.com/asheroto/winget-install/blob/master/winget-install.ps1
#----------------------------------------------------------------------
# After successfully running this, you are ready to use
# ServerEngine software deployment
#----------------------------------------------------------------------
# Requires Administrator privilegues
$isadm = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
if (-not $isadm) {
Write-Host "<WRITE-LOG = ""*Please run ServerEngine as Administrator.*"">"
Write-Host "<WRITE-LOG = ""*If this was a remote execution please provide Administrator credentials.*"">"
Write-Error "Warning: Not running as Administrator."
}
$Force = $false
$ForceClose = $false
$AlternateInstallMethod = $false
$Wait = $false
$NoExit = $false
$Version = $false
$Help = $false
if ($Help) {
Get-Help -Name $MyInvocation.MyCommand.Source -Full
exit 0
}
if ($PSBoundParameters.ContainsKey('Verbose') -and $PSBoundParameters['Verbose']) {
$PSVersionTable
Get-Host
}
if ($PSBoundParameters.ContainsKey('Debug') -and $PSBoundParameters['Debug']) {
$DebugPreference = 'Continue'
$ConfirmPreference = 'None'
}
$RunAsSystem = $false
if ([System.Security.Principal.WindowsIdentity]::GetCurrent().Name -match "NT AUTHORITY\\SYSTEM") {
$RunAsSystem = $true
}
function Find-WinGet {
try {
$WinGetPathToResolve = Join-Path -Path $ENV:ProgramFiles -ChildPath 'WindowsApps\Microsoft.DesktopAppInstaller_*_*__8wekyb3d8bbwe'
$ResolveWinGetPath = Resolve-Path -Path $WinGetPathToResolve -ErrorAction Stop | Sort-Object {
[version]($_.Path -replace '^[^\d]+_((\d+\.)*\d+)_.*', '$1')
}
if ($ResolveWinGetPath) {
$WinGetPath = $ResolveWinGetPath[-1].Path
}
$WinGet = Join-Path $WinGetPath 'winget.exe'
if (Test-Path -Path $WinGet) {
return $WinGet
} else {
return $null
}
} catch {
return $null
}
}
function Get-OSInfo {
[CmdletBinding()]
param ()
try {
$registryValues = Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion"
$releaseIdValue = $registryValues.ReleaseId
$displayVersionValue = $registryValues.DisplayVersion
$nameValue = $registryValues.ProductName
$editionIdValue = $registryValues.EditionId
$editionIdValue = $editionIdValue -replace "Server", ""
try {
$osDetails = Get-CimInstance -ClassName Win32_OperatingSystem -ErrorAction Stop
} catch {
throw "Unable to run Get-CimInstance."
}
$nameValue = $osDetails.Caption
$architecture = ($osDetails.OSArchitecture -replace "[^\d]").Trim()
if ($architecture -eq "32") {
$architecture = "x32"
} elseif ($architecture -eq "64") {
$architecture = "x64"
}
$versionValue = [System.Environment]::OSVersion.Version
if ($osDetails.ProductType -eq 1) {
$typeValue = "Workstation"
} elseif ($osDetails.ProductType -eq 2 -or $osDetails.ProductType -eq 3) {
$typeValue = "Server"
} else {
$typeValue = "Unknown"
}
$numericVersion = ($nameValue -replace "[^\d]").Trim()
if ($numericVersion -ge 10 -and $osDetails.Caption -match "multi-session") {
$typeValue = "Workstation"
}
$result = [PSCustomObject]@{
ReleaseId = $releaseIdValue
DisplayVersion = $displayVersionValue
Name = $nameValue
Type = $typeValue
NumericVersion = $numericVersion
EditionId = $editionIdValue
Version = $versionValue
Architecture = $architecture
}
return $result
} catch {
Write-Error "Unable to get OS version details."
ExitWithDelay 1
}
}
function Get-GitHubRelease {
[CmdletBinding()]
param (
[string]$Owner,
[string]$Repo
)
try {
$url = "https://api.github.com/repos/$Owner/$Repo/releases/latest"
$response = Invoke-RestMethod -Uri $url -ErrorAction Stop
$latestVersion = $response.tag_name
$publishedAt = $response.published_at
$UtcDateTime = [DateTime]::Parse($publishedAt, [System.Globalization.CultureInfo]::InvariantCulture, [System.Globalization.DateTimeStyles]::RoundtripKind)
$PublishedLocalDateTime = $UtcDateTime.ToLocalTime()
[PSCustomObject]@{
LatestVersion = $latestVersion
PublishedDateTime = $PublishedLocalDateTime
}
} catch {
Write-Error "Unable to check for updates."
exit 1
}
}
function Get-WingetDownloadUrl {
[CmdletBinding()]
param (
[Parameter(Mandatory = $true)]
[string]$Match
)
$uri = "https://api.github.com/repos/microsoft/winget-cli/releases"
$releases = Invoke-RestMethod -uri $uri -Method Get -ErrorAction Stop
foreach ($release in $releases) {
if ($release.name -match "preview") {
continue
}
$data = $release.assets | Where-Object name -Match $Match
if ($data) {
return $data.browser_download_url
}
}
$latestRelease = $releases | Select-Object -First 1
$data = $latestRelease.assets | Where-Object name -Match $Match
return $data.browser_download_url
}
function Get-WingetStatus {
if ($RunAsSystem) {
$wingetPath = Find-WinGet
if ($null -ne $wingetPath) {
$winget = & $wingetPath -v
} else {
$winget = $null
}
} else {
$winget = Get-Command -Name winget -ErrorAction SilentlyContinue
}
if ($null -ne $winget -and $winget -notlike '*failed to run*') {
return $true
}
return $false
}
function Handle-Error {
param($ErrorRecord)
$OriginalErrorActionPreference = $ErrorActionPreference
$ErrorActionPreference = 'SilentlyContinue'
if ($ErrorRecord.Exception.Message -match '0x80073D06') {
Write-Warning "Higher version already installed."
Write-Warning "That's okay, continuing..."
} elseif ($ErrorRecord.Exception.Message -match '0x80073CF0') {
Write-Warning "Same version already installed."
Write-Warning "That's okay, continuing..."
} elseif ($ErrorRecord.Exception.Message -match '0x80073D02') {
Write-Warning "Resources modified are in-use. Try closing Windows Terminal / PowerShell / Command Prompt and try again."
Write-Warning "Run the script with the -ForceClose parameter which will relaunch the script in conhost.exe."
return $ErrorRecord
} elseif ($ErrorRecord.Exception.Message -match '0x80073CF3') {
Write-Warning "Problem with one of the prerequisites."
Write-Warning "Try running the script again or with the -ForceClose parameter."
return $ErrorRecord
} elseif ($ErrorRecord.Exception.Message -match '0x80073CF9') {
Write-Warning "Registering winget failed with error code 0x80073CF9."
Write-Warning "The SYSTEM account may not work. Run using an Administrator account."
} elseif ($ErrorRecord.Exception.Message -match 'Unable to connect to the remote server') {
Write-Warning "Cannot connect to the Internet to download the required files."
return $ErrorRecord
} elseif ($ErrorRecord.Exception.Message -match "The remote name could not be resolved") {
Write-Warning "Cannot connect to the Internet to download the required files."
} else {
return $ErrorRecord
}
$ErrorActionPreference = $OriginalErrorActionPreference
}
function Get-CurrentProcess {
$oldTitle = $host.ui.RawUI.WindowTitle
$tempTitle = ([Guid]::NewGuid())
$host.ui.RawUI.WindowTitle = $tempTitle
Start-Sleep 1
$currentProcess = Get-Process | Where-Object { $_.MainWindowTitle -eq $tempTitle }
$currentProcess = [PSCustomObject]@{
Name = $currentProcess.Name
Id = $currentProcess.Id
}
$host.ui.RawUI.WindowTitle = $oldTitle
return $currentProcess
}
function ExitWithDelay {
param (
[int]$ExitCode,
[int]$Seconds = 10
)
if ($Wait) {
Write-Output "`nWaiting for $Seconds seconds before exiting..."
Start-Sleep -Seconds $Seconds
}
if ($NoExit) {
Write-Output "Script completed. Pausing indefinitely. Press any key to exit..."
Read-Host
}
if ($MyInvocation.CommandOrigin -eq "Runspace") {
Break
} else {
Exit $ExitCode
}
}
function Import-GlobalVariable {
[CmdletBinding()]
param(
[string]$VariableName
)
try {
$globalValue = Get-Variable -Name $VariableName -ValueOnly -Scope Global -ErrorAction Stop
Set-Variable -Name $VariableName -Value $globalValue -Scope Script
} catch {}
}
function Test-AdminPrivileges {
if (([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
return $true
}
return $false
}
Function New-TemporaryFile2 {
$tempPath = [System.IO.Path]::GetTempPath()
$tempFile = [System.IO.Path]::Combine($tempPath, [System.IO.Path]::GetRandomFileName())
$null = New-Item -Path $tempFile -ItemType File -Force
return $tempFile
}
function Path-ExistsInEnvironment {
param (
[string]$PathToCheck,
[string]$Scope = 'Both'
)
$pathExists = $false
if ($Scope -eq 'User' -or $Scope -eq 'Both') {
$userEnvPath = $env:PATH
if (($userEnvPath -split ';').Contains($PathToCheck)) {
$pathExists = $true
}
}
if ($Scope -eq 'System' -or $Scope -eq 'Both') {
$systemEnvPath = [System.Environment]::GetEnvironmentVariable('PATH', [System.EnvironmentVariableTarget]::Machine)
if (($systemEnvPath -split ';').Contains($PathToCheck)) {
$pathExists = $true
}
}
return $pathExists
}
function Add-ToEnvironmentPath {
param (
[Parameter(Mandatory = $true)]
[string]$PathToAdd,
[Parameter(Mandatory = $true)]
[ValidateSet('User', 'System')]
[string]$Scope
)
if (-not (Path-ExistsInEnvironment -PathToCheck $PathToAdd -Scope $Scope)) {
if ($Scope -eq 'System') {
$systemEnvPath = [System.Environment]::GetEnvironmentVariable('PATH', [System.EnvironmentVariableTarget]::Machine)
$systemEnvPath += ";$PathToAdd"
[System.Environment]::SetEnvironmentVariable('PATH', $systemEnvPath, [System.EnvironmentVariableTarget]::Machine)
} elseif ($Scope -eq 'User') {
$userEnvPath = [System.Environment]::GetEnvironmentVariable('PATH', [System.EnvironmentVariableTarget]::User)
$userEnvPath += ";$PathToAdd"
[System.Environment]::SetEnvironmentVariable('PATH', $userEnvPath, [System.EnvironmentVariableTarget]::User)
}
if (-not ($env:PATH -split ';').Contains($PathToAdd)) {
$env:PATH += ";$PathToAdd"
}
}
}
function Set-PathPermissions {
param (
[string]$FolderPath
)
$administratorsGroupSid = New-Object System.Security.Principal.SecurityIdentifier("S-1-5-32-544")
$administratorsGroup = $administratorsGroupSid.Translate([System.Security.Principal.NTAccount])
$acl = Get-Acl -Path $FolderPath
$accessRule = New-Object System.Security.AccessControl.FileSystemAccessRule(
$administratorsGroup,
"FullControl",
"ContainerInherit,ObjectInherit",
"None",
"Allow"
)
$acl.SetAccessRule($accessRule)
Set-Acl -Path $FolderPath -AclObject $acl
}
function Test-VCRedistInstalled {
$64BitOS = [System.Environment]::Is64BitOperatingSystem
$64BitProcess = [System.Environment]::Is64BitProcess
if ($64BitOS -and -not $64BitProcess) {
Throw 'Please run PowerShell in the system native architecture.'
}
$registryPath = [string]::Format(
'Registry::HKEY_LOCAL_MACHINE\SOFTWARE\{0}\Microsoft\VisualStudio\14.0\VC\Runtimes\X{1}',
$(if ($64BitOS -and $64BitProcess) { 'WOW6432Node' } else { '' }),
$(if ($64BitOS) { '64' } else { '86' })
)
$registryExists = Test-Path -Path $registryPath
$majorVersion = if ($registryExists) {
(Get-ItemProperty -Path $registryPath -Name 'Major').Major
} else {
0
}
$version = if ($registryExists) {
(Get-ItemProperty -Path $registryPath -Name 'Version').Version
} else {
0
}
$dllPath = [string]::Format(
'{0}\system32\concrt140.dll',
$env:windir
)
$dllExists = [System.IO.File]::Exists($dllPath)
return $registryExists -and $majorVersion -eq 14 -and $dllExists
}
function TryRemove {
param (
[Parameter(Mandatory = $true)]
[string]$FilePath
)
try {
if (Test-Path -Path $FilePath) {
Remove-Item -Path $FilePath -ErrorAction SilentlyContinue
}
} catch {}
}
function Install-NuGetIfRequired {
if (-not (Get-PackageProvider -Name NuGet -ListAvailable -ErrorAction SilentlyContinue)) {
if ($PSVersionTable.PSVersion.Major -lt 7) {
try {
Install-PackageProvider -Name "NuGet" -Force -ForceBootstrap -ErrorAction SilentlyContinue | Out-Null
} catch {}
}
}
}
function Get-ManifestVersion {
param(
[Parameter(Mandatory)]
[string]$Lib_Path
)
Add-Type -AssemblyName System.IO.Compression.FileSystem
$zip = [System.IO.Compression.ZipFile]::OpenRead($Lib_Path)
$entry = $zip.Entries | Where-Object { $_.FullName -eq "AppxManifest.xml" }
if ($entry) {
$stream = $entry.Open()
$reader = New-Object System.IO.StreamReader($stream)
[xml]$xml = $reader.ReadToEnd()
$reader.Close()
$zip.Dispose()
$DownloadedLibVersion = $xml.Package.Identity.Version
return $DownloadedLibVersion
} else {
Write-Error "AppxManifest.xml not found."
}
}
function Get-InstalledLibVersion {
param(
[Parameter(Mandatory)]
[string]$Lib_Name
)
$InstalledLib = Get-AppxPackage -Name "*$($Lib_Name)*" -ErrorAction SilentlyContinue | Sort-Object Version -Descending | Select-Object -First 1
if ($InstalledLib) {
$InstalledLibVersion = $InstalledLib.Version
return $InstalledLibVersion
} else {
$InstalledLibVersion = $null
return $InstalledLibVersion
}
}
function Install-LibIfRequired {
param(
[Parameter(Mandatory)]
[string]$Lib_Name,
[Parameter(Mandatory)]
[string]$Lib_Path
)
$InstalledLibVersion = Get-InstalledLibVersion -Lib_Name $Lib_Name
$DownloadedLibVersion = Get-ManifestVersion -Lib_Path $Lib_Path
if (!$InstalledLibVersion -or !$DownloadedLibVersion -or ($DownloadedLibVersion -gt $InstalledLibVersion)) {
if ($RunAsSystem) {
$null = Add-ProvisionedAppxPackage -Online -SkipLicense -PackagePath $Lib_Path
} else {
$null = Add-AppxPackage -Path $Lib_Path
}
}
}
Import-GlobalVariable -VariableName "Debug"
Import-GlobalVariable -VariableName "ForceClose"
Import-GlobalVariable -VariableName "Force"
Import-GlobalVariable -VariableName "AlternateInstallMethod"
Write-Host "<WRITE-LOG = ""*Checking WinGet Envirement...*"">"
if (-not (Test-AdminPrivileges)) {
Write-Warning "Run the script as an Administrator."
ExitWithDelay 1
}
$osVersion = Get-OSInfo
$arch = $osVersion.Architecture
$currentProcess = Get-CurrentProcess
if ($osVersion.Type -eq "Workstation" -and $osVersion.NumericVersion -lt 10) {
Write-Error "Requires Windows 10 or later."
ExitWithDelay 1
}
if ($osVersion.Type -eq "Workstation" -and $osVersion.NumericVersion -eq 10 -and $osVersion.ReleaseId -lt 1809) {
Write-Error "Requires Windows 10 version 1809 or later."
ExitWithDelay 1
}
if ($osVersion.Type -eq "Server" -and $osVersion.NumericVersion -lt 2019) {
Write-Error "Requires Windows Server 2019 or newer."
ExitWithDelay 1
}
if (Get-WingetStatus) {
if ($Force -eq $false) {
Write-Host "<WRITE-LOG = ""*WinGet is already installed.*"">"
ExitWithDelay 0 5
}
}
if ($ForceClose) {
if ($currentProcess.Name -eq "WindowsTerminal") {
Start-Sleep -Seconds 10
$command = "cd '$pwd'; $($MyInvocation.Line)"
if ($Force -and !($command -imatch '\s-Force\b')) { $command += " -Force" }
if ($ForceClose -and !($command -imatch '\s-ForceClose\b')) { $command += " -ForceClose" }
if ($Debug -and !($command -imatch '\s-Debug\b')) { $command += " -Debug" }
if ([Environment]::Is64BitOperatingSystem) {
if ([Environment]::Is64BitProcess) {
Start-Process -FilePath "conhost.exe" -ArgumentList "powershell -ExecutionPolicy Bypass -Command &{$command}" -Verb RunAs
} else {
Start-Process -FilePath "$env:windir\sysnative\conhost.exe" -ArgumentList "powershell -ExecutionPolicy Bypass -Command &{$command}" -Verb RunAs
}
} else {
Start-Process -FilePath "conhost.exe" -ArgumentList "powershell -ExecutionPolicy Bypass -Command &{$command}" -Verb RunAs
}
Stop-Process -id $currentProcess.Id
}
}
try {
if ($osVersion.NumericVersion -ne 2019 -and $AlternateInstallMethod -eq $false -and $RunAsSystem -eq $false) {
try {
Install-NuGetIfRequired
Write-Host "<WRITE-LOG = ""*Installing Microsoft.WinGet.Client module...*"">"
try { Install-Module -Name Microsoft.WinGet.Client -Force -AllowClobber -Repository PSGallery -ErrorAction SilentlyContinue *>&1 | Out-Null } catch { }
Write-Host "<WRITE-LOG = ""*Installing WinGet...*"">"
try { Repair-WinGetPackageManager -AllUsers -Force -Latest *>&1 | Out-Null } catch { }
} catch {
$errorHandled = Handle-Error $_
if ($null -ne $errorHandled) { throw $errorHandled }
}
Add-ToEnvironmentPath -PathToAdd "%LOCALAPPDATA%\Microsoft\WindowsApps" -Scope 'User'
}
if (($osVersion.Type -eq "Server" -and ($osVersion.NumericVersion -eq 2019)) -or $AlternateInstallMethod -or $RunAsSystem) {
try {
$winget_dependencies_path = New-TemporaryFile2
$winget_dependencies_url = Get-WingetDownloadUrl -Match 'DesktopAppInstaller_Dependencies.zip'
Write-Host "<WRITE-LOG = ""*Downloading WinGet dependencies...*"">"
Invoke-WebRequest -Uri $winget_dependencies_url -OutFile $winget_dependencies_path
Add-Type -AssemblyName System.IO.Compression.FileSystem
$zip = [System.IO.Compression.ZipFile]::OpenRead($winget_dependencies_path)
$matchingEntries = $zip.Entries | Where-Object { $_.FullName -match ".*$arch.appx" }
if ($matchingEntries) {
$matchingEntries | ForEach-Object {
$destPath = Join-Path ([System.IO.Path]::GetTempPath()) $_.Name
[System.IO.Compression.ZipFileExtensions]::ExtractToFile($_, $destPath, $true)
if ($_.Name -like '*.VCLibs.140.00.UWPDesktop*.appx') { $VCLibs_Path = $destPath }
if ($_.Name -like '*.UI.Xaml.2.8*.appx') { $UIXaml_Path = $destPath }
}
$zip.Dispose()
} else {
Write-Error "Dependency not found."
}
Write-Output "Installing VCLibs.140.00.UWPDesktop..."
Install-LibIfRequired -Lib_Name 'VCLibs.140.00.UWPDesktop' -Lib_Path $VCLibs_Path
Write-Output ""
Write-Output "Installing UI.Xaml.2.8..."
Install-LibIfRequired -Lib_Name 'UI.Xaml.2.8' -Lib_Path $UIXaml_Path
TryRemove $winget_dependencies_path
TryRemove $VCLibs_Path
TryRemove $UIXaml_Path
} catch {
$errorHandled = Handle-Error $_
if ($null -ne $errorHandled) { throw $errorHandled }
}
try {
$winget_license_path = New-TemporaryFile2
$winget_license_url = Get-WingetDownloadUrl -Match "License1.xml"
Write-Host "<WRITE-LOG = ""*Downloading winget license...*"">"
Invoke-WebRequest -Uri $winget_license_url -OutFile $winget_license_path
$winget_path = New-TemporaryFile2
$winget_url = Get-WingetDownloadUrl -Match 'Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle'
Write-Host "<WRITE-LOG = ""*Downloading WinGet...*"">"
Invoke-WebRequest -Uri $winget_url -OutFile $winget_path
Write-Host "<WRITE-LOG = ""*Installing WinGet...*"">"
Add-AppxProvisionedPackage -Online -PackagePath $winget_path -LicensePath $winget_license_path | Out-Null
TryRemove $winget_path
TryRemove $winget_license_path
} catch {
$errorHandled = Handle-Error $_
if ($null -ne $errorHandled) { throw $errorHandled }
}
if (!(Test-VCRedistInstalled)) {
$VCppRedistributable_Url = "https://aka.ms/vs/17/release/vc_redist.${arch}.exe"
$VCppRedistributable_Path = New-TemporaryFile2
Write-Output "Downloading Visual C++ Redistributable..."
Invoke-WebRequest -Uri $VCppRedistributable_Url -OutFile $VCppRedistributable_Path
$VCppRedistributableExe_Path = $VCppRedistributable_Path + ".exe"
Rename-Item -Path $VCppRedistributable_Path -NewName $VCppRedistributableExe_Path
Write-Output "Installing Visual C++ Redistributable..."
Start-Process -FilePath $VCppRedistributableExe_Path -ArgumentList "/install", "/quiet", "/norestart" -Wait
TryRemove $VCppRedistributableExe_Path
} else {
Write-Output "Visual C++ Redistributable is already installed."
}
Write-Host "<WRITE-LOG = ""*Fixing permissions for WinGet folder...*"">"
$WinGetFolderPath = (Get-ChildItem -Path ([System.IO.Path]::Combine($env:ProgramFiles, 'WindowsApps')) -Filter "Microsoft.DesktopAppInstaller_*_${arch}__8wekyb3d8bbwe" | Sort-Object Name | Select-Object -Last 1).FullName
if ($null -ne $WinGetFolderPath) {
Set-PathPermissions -FolderPath $WinGetFolderPath
Add-ToEnvironmentPath -PathToAdd $WinGetFolderPath -Scope 'System'
} else {
Write-Warning "winget folder path not found."
}
}
Write-Host "<WRITE-LOG = ""*Registering WinGet...*"">"
try {
if ($osVersion.NumericVersion -ne 2019 -and $RunAsSystem -eq $false) {
# First try the family name registration
try {
Add-AppxPackage -RegisterByFamilyName -MainPackage Microsoft.DesktopAppInstaller_8wekyb3d8bbwe -ErrorAction Stop
} catch {
Write-Host "<WRITE-LOG = ""*Family name registration failed, trying alternative method...*"">"
# Find the actual package path and register it directly
$packagePath = Get-ChildItem -Path "$env:ProgramFiles\WindowsApps" -Directory -Filter "Microsoft.DesktopAppInstaller_*_*__8wekyb3d8bbwe" |
Sort-Object Name -Descending |
Select-Object -First 1 -ExpandProperty FullName
if ($packagePath) {
$manifestPath = Join-Path $packagePath "AppxManifest.xml"
if (Test-Path $manifestPath) {
Write-Host "<WRITE-LOG = ""*Registering package from: $packagePath*"">"
Add-AppxPackage -Register -DisableDevelopmentMode -RegisterPath $manifestPath -ErrorAction Stop
} else {
throw "Manifest not found at $manifestPath"
}
} else {
throw "Could not find WinGet package installation directory"
}
}
}
# Verify registration was successful
$registered = Get-AppxPackage -Name "Microsoft.DesktopAppInstaller" -ErrorAction SilentlyContinue
if ($registered) {
Write-Host "<WRITE-LOG = ""*WinGet registered successfully.*"">"
} else {
Write-Warning "WinGet package may not be properly registered"
}
} catch {
Write-Warning "Failed to register WinGet: $($_.Exception.Message)"
# Try one more method - repair using winget module if available
try {
Write-Host "<WRITE-LOG = ""*Attempting repair via Repair-WinGetPackageManager...*"">"
Import-Module Microsoft.WinGet.Client -ErrorAction SilentlyContinue
Repair-WinGetPackageManager -AllUsers -ErrorAction SilentlyContinue
} catch {
# Silently continue if this also fails
}
}
Write-Host "<WRITE-LOG = ""*WinGet installed.*"">"
Write-Host "<WRITE-LOG = ""*Checking if WinGet is working..*"">"
Start-Sleep -Seconds 3
if (Get-WingetStatus -eq $true) {
Write-Host "<WRITE-LOG = ""*WinGet is working.*"">"
if ($RunAsSystem) {
Write-Output "Restart may be required under SYSTEM context."
}
} else {
if (Get-WingetStatus -ne $true) {
Write-Warning "WinGet command not detected. Wait 1 minute or restart computer."
}
}
ExitWithDelay 0
} catch {
Write-Warning "See troubleshooting guide: https://github.com/asheroto/winget-install#troubleshooting"
Write-Warning "Check for updates: $PowerShellGalleryName -CheckForUpdate"
if ($_.Exception.Message -notmatch '0x80073D02') {
if ($Debug) { Write-Warning "Line number : $($_.InvocationInfo.ScriptLineNumber)" }
Write-Warning "Error: $($_.Exception.Message)`n"
}
ExitWithDelay 1
}Run it across your fleet
This script runs as-is on a single host. Paste it into ServerEngine to schedule it, run it on a whole server group in parallel, and keep the credentials out of the file — see the scripts documentation and the credential store.
More in ServerEngine Platform
Write to the ServerEngine Run Log from PowerShell
2026-08-17Pass Data Between Runbook Steps in PowerShell
2026-08-17Read Data from a Previous Runbook Step in PowerShell
2026-08-17Pass Parameters into a PowerShell Script from an API
2026-08-17Reboot a Server and Resume the Runbook
2026-08-17Configure WinRM over HTTPS with a Self-Signed Certificate
2026-08-17Ready when you are.
Try ServerEngine free for 7 days.