src/private/Invoke-WinGet.ps1
# Builds a command optimized for a package provider and sends to winget.exe function Invoke-WinGet { [CmdletBinding()] param ( [Parameter(Mandatory=$true, ParameterSetName='Search')] [switch] $Search, [Parameter(Mandatory=$true, ParameterSetName='Install')] [switch] $Install, [Parameter(Mandatory=$true, ParameterSetName='Uninstall')] [switch] $Uninstall, [Parameter(Mandatory=$true, ParameterSetName='SourceList')] [switch] $SourceList, [Parameter(Mandatory=$true, ParameterSetName='SourceAdd')] [switch] $SourceAdd, [Parameter(Mandatory=$true, ParameterSetName='SourceRemove')] [switch] $SourceRemove, [Parameter(Mandatory=$true, ParameterSetName='SourceUpdate')] [switch] $SourceUpdate, [Parameter(ParameterSetName='Search')] [Parameter(Mandatory=$true, ParameterSetName='Install')] [Parameter(Mandatory=$true, ParameterSetName='Uninstall')] [string] $Package, [Parameter(ParameterSetName='Search')] [Parameter(Mandatory=$true, ParameterSetName='Install')] [Parameter(Mandatory=$true, ParameterSetName='Uninstall')] [string] $Version, [Parameter(ParameterSetName='Search')] [Parameter(ParameterSetName='Install')] [Parameter(Mandatory=$true, ParameterSetName='SourceAdd')] [Parameter(Mandatory=$true, ParameterSetName='SourceRemove')] [Parameter(ParameterSetName='SourceUpdate')] [string] $SourceName = $script:PackageSourceName, [Parameter(Mandatory=$true, ParameterSetName='SourceAdd')] [string] $SourceLocation, [string] $AdditionalArgs = (Get-AdditionalArguments) ) # Split on the first hyphen of each option/switch $argSplitRegex = '(?:^|\s)-' # Installation parameters/arguments can interfere with non-installation commands (ex: search) and should be filtered out $argParamFilterRegex = '\w*(?:param|arg)\w*' # ParamGlobal Flag $paramGlobalRegex = '\w*-(?:p.+global)\w*' # ArgGlobal Flag $argGlobalRegex = '\w*-(?:(a|i).+global)\w*' # Just parameters $paramFilterRegex = '\w*(?:param)\w*' # Just parameters $argFilterRegex = '\w*(?:arg)\w*' $WinGetExePath = Get-WinGetPath if ($WinGetExePath) { Write-Debug ("WinGet already installed") } else { $WinGetExePath = Install-WinGetBinaries } # Source Management if ($SourceList -or $SourceAdd -or $SourceRemove -or $SourceUpdate) { $cmdString = 'source ' if ($SourceAdd) { $cmdString += "add --name $SourceName --arg $SourceLocation " } elseif ($SourceRemove) { $cmdString += "remove --name $SourceName " } elseif ($SourceUpdate) { $cmdString += "update " if ($SourceName) { $cmdString += "--name $SourceName " } } elseif ($SourceList) { $cmdString += 'list ' } } else { # Package Management if ($Install) { $cmdString = "install --id $Package " # Accept all prompts and dont show installation progress percentage - the excess output from WinGet.exe will slow down PowerShell $AdditionalArgs += ' --silent ' } elseif ($Search) { $cmdString = 'search ' if ($Package) { $cmdString += "$Package " } } # Uninstall not currently supported # Finish constructing package management command string if ($Version) { $cmdString += "--version $Version " } $cmdString += "--source $SourceName " } # Joins the constructed and user-provided arguments together to be soon split as a single array of options passed to WinGet.exe $cmdString += $AdditionalArgs Write-Debug ("Calling $WinGetExePath $cmdString") $cmdString = $cmdString.Split(' ') # Save the output to a variable so we can inspect the exit code before submitting the output to the pipeline $output = (& $WinGetExePath $cmdString) if ($LASTEXITCODE -ne 0) { ThrowError -ExceptionName 'System.OperationCanceledException' ` -ExceptionMessage $($output | Out-String) ` -ErrorID 'JobFailure' ` -ErrorCategory InvalidOperation ` -ExceptionObject $output } else { if ($Install) { $swid = @{ FastPackageReference = $Package+"#"+$Version+"#"+$SourceName Name = $Package Version = $Version versionScheme = "MultiPartNumeric" FromTrustedSource = $true Source = $SourceName } New-SoftwareIdentity @swid } elseif ($Search) { $swidArgs = @{ Source = $SourceName IdIndex = $output[1].IndexOf('Id') VersionIndex = $output[1].IndexOf('Version') MatchedIndex = $output[1].IndexOf('Matched') } # Search returns an extra line of whitespace to skip $output | Select-Object -Skip 3 | ConvertTo-SoftwareIdentity @swidArgs } elseif ($SourceList) { $ArgIndex = $output[0].IndexOf('Arg') # Skip the header lines and convert the rest $output | Select-Object -Skip 2 | ForEach-Object { $packageSource = @{ Name = $_.Substring(0,$ArgIndex-1).Trim() Location = $_.Substring($ArgIndex).Trim() Trusted = $True Registered = $true } New-PackageSource @packageSource } } else { $output } } } |