winget-cli
winget-cli copied to clipboard
Receive `Specified method is not supported.` for multiple module cmdlets under SYSTEM context.
Brief description of your issue
It's been exciting to see 1.6.3133.0 of the PowerShell module, its really starting to come together.
While the main cmdlets like Get-WinGetPackage
, Install-WinGetPackage
and Uninstall-WinGetPackage
are working well, other ones that I require such as Get-WinGetVersion
and Repair-WinGetPackageManager
are not, and they're crucial as during a Windows Autopilot sequence, I need to ensure an appropriate version of WinGet is available vs. whatever the system ships with.
Steps to reproduce
- Open PowerShell 7.x as SYSTEM
- Call
Get-WinGetVersion
and observe error occurs.
Expected behavior
C:\Windows\System32>pwsh.exe -ExecutionPolicy Bypass -MTA PowerShell 7.4.0 PS C:\Windows\System32> whoami nt authority\system PS C:\Windows\System32> Get-WinGetVersion v1.6.3133 PS C:\Windows\System32>
Actual behavior
C:\Windows\System32>pwsh.exe -ExecutionPolicy Bypass -MTA PowerShell 7.4.0 PS C:\Windows\System32> whoami nt authority\system PS C:\Windows\System32> Get-WinGetVersion Get-WinGetVersion: Specified method is not supported. PS C:\Windows\System32>
Environment
Windows Package Manager v1.6.3133
Copyright (c) Microsoft Corporation. All rights reserved.
Windows: Windows.Desktop v10.0.22621.2715
System Architecture: X64
Winget Directories
------------------------------------------------------------------------------------------------------
Logs %TEMP%\WinGet\defaultState
User Settings %LOCALAPPDATA%\Microsoft\WinGet\Settings\defaultState\settings.json
Portable Links Directory (User) %LOCALAPPDATA%\Microsoft\WinGet\Links
Portable Links Directory (Machine) C:\Program Files\WinGet\Links
Portable Package Root (User) %LOCALAPPDATA%\Microsoft\WinGet\Packages
Portable Package Root C:\Program Files\WinGet\Packages
Portable Package Root (x86) C:\Program Files (x86)\WinGet\Packages
Installer Downloads %USERPROFILE%\Downloads
Links
---------------------------------------------------------------------------
Privacy Statement https://aka.ms/winget-privacy
License Agreement https://aka.ms/winget-license
Third Party Notices https://aka.ms/winget-3rdPartyNotice
Homepage https://aka.ms/winget
Windows Store Terms https://www.microsoft.com/en-us/storedocs/terms-of-sale
Admin Setting State
--------------------------------------------------
LocalManifestFiles Disabled
BypassCertificatePinningForMicrosoftStore Disabled
InstallerHashOverride Disabled
LocalArchiveMalwareScanOverride Disabled
- Related to https://github.com/microsoft/winget-cli/pull/3816
Was something missed in the PR?
+1 on this. Given the instability/inconsistency I've experienced across our fleet when leveraging WinGet as SYSTEM, cmdlets like Get-WinGetVersion and Repair-WinGetPackageManager are important for supporting successful deployments.
@mjr4077au - Is this still occurring with the 1.7.10651 release of the modules?
Unfortunately so, for both Windows PowerShell and PowerShell 7:
The repair command is essential because Windows images often ship with ludicrously out of date WinGet versions.
Windows PowerShell support is very inconsistent as well. Take Get-WinGetPackage
, under SYSTEM it throws saying Windows PowerShell is not supported, however the cmdlet works fine under non-SYSTEM contexts:
Thanks for confirming
Has there been any development or movement on this issue? We're now relying on our private WinGet source to be available under the SYSTEM context and are unable to configure said source using Add-WinGetSource
as the same Specified method is not supported
error is thrown (behavior observed in version 1.7.11132 of Microsoft.WinGet.Client PS Module), and of course the winget cli
is completely unavailable under the SYSTEM context.
Is there any alternative way we could go about configuring WinGet sources under the SYSTEM context without relying on a currently-broken Add-WinGetSource
?
I'm currently using WinGet via the CLI while running as SYSTEM presently, it's just a cumbersome (albeit reliable) solution due to all the text parsing I have to do from the app's stdout, etc, when there's a shiny module I should be able to use.
I'm currently using WinGet via the CLI while running as SYSTEM presently, it's just a cumbersome (albeit reliable) solution due to all the text parsing I have to do from the app's stdout, etc, when there's a shiny module I should be able to use.
How exactly are you accomplishing this?
I can't provide my code as its considered proprietary to our company, and it depends on our own logging module and other internal code but the main guts to get things going, updated, working, and a valid path to winget.exe
is:
#---------------------------------------------------------------------------
#
# Installs the latest Visual Studio Runtime dependency.
#
#---------------------------------------------------------------------------
Microsoft.PowerShell.Management\Set-Item -LiteralPath Function:Install-VisualStudioRuntimeDependency -Options Constant -Value {
# Set required variables for install operation.
$pkgArch = @('x86','x64')[[System.Environment]::Is64BitProcess]
$pkgName = "Microsoft Visual C++ 2015-2022 Redistributable ($pkgArch)"
$uriPath = "https://aka.ms/vs/17/release/vc_redist.$pkgArch.exe"
TMLSTL.Logging\Write-LogEntry -Message "Preparing $pkgName dependency, please wait..."
# Define arguments for installation.
$spParams = @{
FilePath = "$Env:TEMP\$(Microsoft.PowerShell.Utility\Get-Random).exe"
ArgumentList = "/install", "/quiet", "/norestart", "/log $(TMLSTL.Logging\Out-LogFilePath -Identifier MSVCRT)"
}
# Download and extract installer.
TMLSTL.Logging\Write-LogEntry -Message "Downloading $pkgName, please wait..."
TMLSTL.Utilities\Invoke-CommandWithRetries -Command Microsoft.PowerShell.Utility\Invoke-WebRequest -UseBasicParsing -Uri $uriPath -OutFile $spParams.FilePath -Verbose 4>&1 | TMLSTL.Logging\Send-VerboseRecordsToLog
# Invoke installer.
TMLSTL.Logging\Write-LogEntry -Message "Installing $pkgName, please wait..."
TMLSTL.Logging\Update-ExitCode -Value (Microsoft.PowerShell.Management\Start-Process @spParams -Wait -PassThru).ExitCode
}
#---------------------------------------------------------------------------
#
# Pre-provisions the latest WinGet binaries.
#
#---------------------------------------------------------------------------
Microsoft.PowerShell.Management\Set-Item -LiteralPath Function:Install-DesktopAppInstallerDependency -Options Constant -Value {
# Update WinGet to the latest version. Don't rely in 3rd party store API services for this.
# https://learn.microsoft.com/en-us/windows/package-manager/winget/#install-winget-on-windows-sandbox
TMLSTL.Logging\Write-LogEntry -Message "Updating $(($pkgName = "Microsoft.DesktopAppInstaller")) dependency, please wait..."
# Define installation file info.
$packages = @(
@{
Name = 'C++ Desktop Bridge Runtime dependency'
Uri = ($uri = [System.Uri]'https://aka.ms/Microsoft.VCLibs.x64.14.00.Desktop.appx')
FilePath = "$($env:TEMP)\$($uri.Segments[-1])"
}
@{
Name = 'Windows UI Library dependency'
Uri = ($uri = [System.Uri]'https://github.com/microsoft/microsoft-ui-xaml/releases/download/v2.8.6/Microsoft.UI.Xaml.2.8.x64.appx')
FilePath = "$($env:TEMP)\$($uri.Segments[-1])"
}
@{
Name = 'latest WinGet msixbundle'
Uri = ($uri = TMLSTL.Utilities\Get-RedirectedUri -Uri 'https://aka.ms/getwinget')
FilePath = "$($env:TEMP)\$($uri.Segments[-1])"
}
)
# Download all packages.
foreach ($package in $packages)
{
TMLSTL.Logging\Write-LogEntry -Message "Downloading $($package.Name), please wait..."
TMLSTL.Utilities\Invoke-CommandWithRetries -Command Microsoft.PowerShell.Utility\Invoke-WebRequest -UseBasicParsing -Uri $package.Uri -OutFile $package.FilePath -Verbose 4>&1 | TMLSTL.Logging\Send-VerboseRecordsToLog
}
# Pre-provision package in the system.
$aappParams = @{
Online = $true
SkipLicense = $true
PackagePath = $packages[(-1)].FilePath
DependencyPackagePath = $packages[(0)..($packages.Count-2)].FilePath
LogPath = TMLSTL.Logging\Out-LogFilePath -Identifier Dism
}
TMLSTL.Logging\Write-LogEntry -Message "Pre-provisioning $pkgName $($packages[-1].Uri.Segments[-2].Trim('/')), please wait..."
Dism\Add-AppxProvisionedPackage @aappParams
}
#---------------------------------------------------------------------------
#
# Gets the correct, fully-qualified path to winget.exe.
#
#---------------------------------------------------------------------------
Microsoft.PowerShell.Management\Set-Item -LiteralPath Function:Out-WinGetPath -Options Constant -Value {
# Get the path to WinGet, with special handling if we're running as SYSTEM or not.
$wingetAppx = Appx\Get-AppxPackage -Name Microsoft.DesktopAppInstaller -AllUsers:$systemUser
$wingetPath = "$($wingetAppx | Microsoft.PowerShell.Utility\Sort-Object -Property Version | Microsoft.PowerShell.Utility\Select-Object -ExpandProperty InstallLocation -Last 1)\winget.exe"
$wingetProv = $null
# Test whether we have any output from WinGet.exe. If this is null, it typically means the appropriate MSVC++ runtime is not installed.
if (!($wingetOutput = & $wingetPath))
{
# We can only reliably update if we're elevated.
if (!(TMLSTL.Utilities\Test-ElevatedSession))
{
throw "The installed version of WinGet was unable to run. Please ensure the latest Visual Studio 2015-2022 Runtime is installed and try again."
}
# Install the missing dependency.
Install-VisualStudioRuntimeDependency
# Re-check the output, ensuring it's not null.
if (!($wingetOutput = & $wingetPath))
{
throw "The installed version of WinGet was unable to run. This is possibly related to the Visual Studio 2015-2022 Runtime."
}
}
# Ensure winget.exe is above the minimum version.
if ([System.Version]($wingetVer = ($wingetOutput | Microsoft.PowerShell.Utility\Select-Object -First 1) -replace '^.+\sv') -lt $wingetMinimum)
{
# We can only reliably update if we're elevated.
if ($wingetProv -or !(TMLSTL.Utilities\Test-ElevatedSession))
{
throw "The installed WinGet version of $wingetVer is less than $wingetMinimum. Please update Microsoft.DesktopAppInstaller and try again."
}
# Install the missing dependency and reset variables.
$wingetProv = Install-DesktopAppInstallerDependency
$wingetAppx = Appx\Get-AppxPackage -Name Microsoft.DesktopAppInstaller -AllUsers:$systemUser
$wingetPath = "$($wingetAppx | Microsoft.PowerShell.Utility\Sort-Object -Property Version | Microsoft.PowerShell.Utility\Select-Object -ExpandProperty InstallLocation -Last 1)\winget.exe"
# Ensure winget.exe is above the minimum version.
if ([System.Version]($wingetVer = (($wingetOutput = & $wingetPath) | Microsoft.PowerShell.Utility\Select-Object -First 1) -replace '^.+\sv') -lt $wingetMinimum)
{
throw "The installed WinGet version of $wingetVer is less than $wingetMinimum. Please check the DISM pre-provisioning logs and try again."
}
# Reset WinGet sources after updating. Helps with a corner-case issue discovered.
TMLSTL.Logging\Write-LogEntry -Message "Resetting all WinGet sources following update, please wait..."
if (!($wgSrcRes = & $wingetPath source reset --force 2>&1).Equals('Resetting all sources...Done'))
{
TMLSTL.Logging\Write-LogEntry -Message "An issue occurred while resetting WinGet sources: $($wgSrcRes.TrimEnd('.')). Continuing with operation." -Warning
}
}
# Return tested path to the caller.
TMLSTL.Logging\Write-LogEntry -Message "Using WinGet path: $wingetPath"
return $wingetPath
}
Just modified the code to make it run under SYSTEM context.
Unfortunately there are some compatibility issues with Windows PowerShell, so the module can only run in PowerShell Core under SYSTEM context. Besides, the user-scope packages and MSIX/APPX installers won't work.
That's awesome! Will you be submitting a PR for that? Interesting that there's still Windows PowerShell 5.1 issues as it does work alright outside of the SYSTEM context from what I've seen: https://github.com/microsoft/winget-cli/issues/3935#issuecomment-1981996325
Related changes are in https://github.com/SpecterShell/winget-cli/commit/8c024e4dbbed54216cd69632c068b7316c5837e4 and the build artifact is available in https://github.com/SpecterShell/Dumplings/actions/runs/9094089001. To use it,
- ~~Get a portable copy of WinGet by using this script: https://github.com/SpecterShell/Dumplings/blob/main/Utilities/InstallWinGetPortable.ps1. After downloading, copy the files to somewhere, say
C:\WinGet
.~~ - Download the module files and import it manually
- ~~Set the environmental variable
$Env:CUSTOMWINGET='C:\WinGet'
in PowerShell~~ - Now it should work.
EDIT: Weird. The winget.exe in C:\Program Files\WindowsApps
didn't work when I was making these changes, but it worked again when I tried it just now. Probably you just need to specify $Env:CUSTOMWINGET = 'C:\Program Files\WindowsApps\Microsoft.DesktopAppInstaller_1.23.1133.0_x64__8wekyb3d8bbwe\'
.
Will you be submitting a PR for that?
Probably not. This is more like a hack as it just simply removes the limitations of running WinGet in SYSTEM context, but didn't address any issues behind like the Windows PowerShell compatibility issues and how to use the module without using another copy of WinGet.
Just saw this amongst your diff:
if (Utilities.ExecutingAsSystem)
{
throw new NotSupportedException();
}
I guess I'll keep using my own solution for now as its working well, but hopefully this situation gets rectified as you've demonstrated there's no technical reason for it not to work and support is required in the ConfigMgr/Intune space.