AppxProvider.psm1
######################################################################################### # # Copyright (c) Microsoft Corporation. All rights reserved. # # Appx Provider Module # ######################################################################################### $script:ProviderName = "appx" $script:AppxPackageExtension = ".appx" $script:AppxManifestFile = "AppxManifest.xml" $script:AppxPkgZipFile = "AppxPkg.zip" $script:Architecture = "Architecture" $script:ResourceId = "ResourceId" $script:AppxPackageSources = $null $script:AppxLocalPath="$env:LOCALAPPDATA\Microsoft\Windows\PowerShell\AppxProvider" $script:AppxPackageSourcesFilePath = Microsoft.PowerShell.Management\Join-Path -Path $script:AppxLocalPath -ChildPath "AppxPackageSources.xml" $Script:ResponseUri = "ResponseUri" $Script:StatusCode = "StatusCode" # Wildcard pattern matching configuration. $script:wildcardOptions = [System.Management.Automation.WildcardOptions]::CultureInvariant -bor ` [System.Management.Automation.WildcardOptions]::IgnoreCase #Localized Data Microsoft.PowerShell.Utility\Import-LocalizedData LocalizedData -filename AppxProvider.Resource.psd1 function Find-AppxPackage { <# .ExternalHelp PSGet.psm1-help.xml #> [outputtype("PSCustomObject[]")] Param ( [Parameter(ValueFromPipelineByPropertyName=$true, Position=0)] [ValidateNotNullOrEmpty()] [string[]] $Name, [Parameter(ValueFromPipelineByPropertyName=$true)] [ValidateNotNull()] [Alias("Version")] [Version] $MinimumVersion, [Parameter(ValueFromPipelineByPropertyName=$true)] [ValidateNotNull()] [Version] $MaximumVersion, [Parameter(ValueFromPipelineByPropertyName=$true)] [ValidateNotNull()] [Version] $RequiredVersion, [Parameter(ValueFromPipelineByPropertyName=$true, Position=0)] [ValidateNotNullOrEmpty()] [string] $Architecture, [Parameter(ValueFromPipelineByPropertyName=$true, Position=0)] [ValidateNotNullOrEmpty()] [string] $ResourceId, [Parameter()] [ValidateNotNullOrEmpty()] [string[]] $Source ) Begin { } Process { $PSBoundParameters["ProviderName"] = $script:ProviderName PackageManagement\Find-Package @PSBoundParameters } } #region Appx Provider APIs Implementation function Get-PackageProviderName { return $script:ProviderName } function Initialize-Provider{ param( ) } function Get-DynamicOptions { param ( [Microsoft.PackageManagement.MetaProvider.PowerShell.OptionCategory] $category ) Write-Debug ($LocalizedData.ProviderApiDebugMessage -f ('Get-DynamicOptions')) switch($category) { Install { Write-Output -InputObject (New-DynamicOption -Category $category -Name Architecture -ExpectedType String -IsRequired $false) Write-Output -InputObject (New-DynamicOption -Category $category -Name ResourceId -ExpectedType String -IsRequired $false) } Package { Write-Output -InputObject (New-DynamicOption -Category $category -Name Architecture -ExpectedType String -IsRequired $false) Write-Output -InputObject (New-DynamicOption -Category $category -Name ResourceId -ExpectedType String -IsRequired $false) } } } function Find-Package { [CmdletBinding()] param ( [string[]] $names, [string] $requiredVersion, [string] $minimumVersion, [string] $maximumVersion ) Write-Debug ($LocalizedData.ProviderApiDebugMessage -f ('Find-Package')) $ResourceId = $null $Architecture = $null $Sources = @() $streamedResults = @() $namesParameterEmpty = (-not $names) -or (($names.Count -eq 1) -and ($names[0] -eq '')) Set-PackageSourcesVariable if($RequiredVersion -and $MinimumVersion) { ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $LocalizedData.VersionRangeAndRequiredVersionCannotBeSpecifiedTogether ` -ErrorId "VersionRangeAndRequiredVersionCannotBeSpecifiedTogether" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument } if($RequiredVersion -or $MinimumVersion) { if(-not $names -or $names.Count -ne 1 -or (Test-WildcardPattern -Name $names[0])) { ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $LocalizedData.VersionParametersAreAllowedOnlyWithSinglePackage ` -ErrorId "VersionParametersAreAllowedOnlyWithSinglePackage" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument } } $options = $request.Options if($options) { foreach( $o in $options.Keys ) { Write-Debug ( "OPTION: {0} => {1}" -f ($o, $options[$o]) ) } if($options.ContainsKey('Source')) { $SourceNames = $($options['Source']) Write-Verbose ($LocalizedData.SpecifiedSourceName -f ($SourceNames)) foreach($sourceName in $SourceNames) { if($script:AppxPackageSources.Contains($sourceName)) { $Sources += $script:AppxPackageSources[$sourceName] } else { $sourceByLocation = Get-SourceName -Location $sourceName if ($sourceByLocation -ne $null) { $Sources += $script:AppxPackageSources[$sourceByLocation] } else { $message = $LocalizedData.PackageSourceNotFound -f ($sourceName) ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId "PackageSourceNotFound" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument ` -ExceptionObject $sourceName } } } } else { Write-Verbose $LocalizedData.NoSourceNameIsSpecified $script:AppxPackageSources.Values | Microsoft.PowerShell.Core\ForEach-Object { $Sources += $_ } } if($options.ContainsKey($script:Architecture)) { $Architecture = $options[$script:Architecture] } if($options.ContainsKey($script:ResourceId)) { $ResourceId = $options[$script:ResourceId] } } foreach($source in $Sources) { $location = $source.SourceLocation if($request.IsCanceled) { return } if(-not(Test-Path $location)) { $message = $LocalizedData.PathNotFound -f ($Location) Write-Verbose $message continue } $packages = Get-AppxPackagesFromPath -path $location foreach($pkg in $packages) { if($request.IsCanceled) { return } $pkgName = $pkg.Name $pkgManifest = Get-PackageManfiestData -PackageFullPath $pkg.FullName if(-not $pkgManifest) { continue } # $pkgName has to match any of the supplied names, using PowerShell wildcards if(-not($namesParameterEmpty)) { if(-not(($names | Microsoft.PowerShell.Core\ForEach-Object { if ($pkgName -like $_){return $true; break} } -End {return $false}))) { continue } } # Version if($RequiredVersion) { if($RequiredVersion -ne $pkgManifest.Version) { continue } } if($Architecture) { $wildcardPattern = New-Object System.Management.Automation.WildcardPattern $Architecture, $script:wildcardOptions if(-not($wildcardPattern.IsMatch($pkgManifest.Architecture))) { continue } } if($ResourceId) { $wildcardPattern = New-Object System.Management.Automation.WildcardPattern $ResourceId, $script:wildcardOptions if(-not($wildcardPattern.IsMatch($pkgManifest.ResourceId))) { continue } } $sid = New-SoftwareIdentityPackageManifestData -PackageManifest $pkgManifest -Source $source.Name -pkgName $pkgName $fastPackageReference = $sid.fastPackageReference if($streamedResults -notcontains $fastPackageReference) { $streamedResults += $fastPackageReference Write-Output -InputObject $sid } } } } function Get-InstalledPackage { [CmdletBinding()] param ( [Parameter()] [string] $Name, [Parameter()] [string] $RequiredVersion, [Parameter()] [string] $MinimumVersion, [Parameter()] [string] $MaximumVersion ) Write-Debug -Message ($LocalizedData.ProviderApiDebugMessage -f ('Get-InstalledPackage')) $Architecture = $null $ResourceId = $null $options = $request.Options if($options) { if($options.ContainsKey($script:Architecture)) { $Architecture = $options[$script:Architecture] } if($options.ContainsKey($script:ResourceId)) { $ResourceId = $options[$script:ResourceId] } } $params = @{} if($Name) { $params.Add("Name", $Name) } $packages = Appx\Get-AppxPackage @params foreach($package in $packages) { if($RequiredVersion) { if($RequiredVersion -ne $package.Version) { continue } } else { if(-not((-not $MinimumVersion -or ($MinimumVersion -le $package.Version)) -and (-not $MaximumVersion -or ($MaximumVersion -ge $package.Version)))) { continue } } if($Architecture) { $wildcardPattern = New-Object System.Management.Automation.WildcardPattern $Architecture, $script:wildcardOptions if(-not($wildcardPattern.IsMatch($package.Architecture))) { continue } } if($ResourceId) { $wildcardPattern = New-Object System.Management.Automation.WildcardPattern $ResourceId,$script:wildcardOptions if(-not($wildcardPattern.IsMatch($package.ResourceId))) { continue } } $sid = New-SoftwareIdentityFromPackage -Package $package write-Output $sid } } function Install-Package { [CmdletBinding()] param ( [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [string] $fastPackageReference ) Write-Debug -Message ($LocalizedData.ProviderApiDebugMessage -f ('Install-Package')) Write-Debug -Message ($LocalizedData.FastPackageReference -f $fastPackageReference) Appx\Add-AppxPackage -Path $fastPackageReference } function UnInstall-Package { [CmdletBinding()] param ( [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [string] $fastPackageReference ) Write-Debug -Message ($LocalizedData.ProviderApiDebugMessage -f ('Uninstall-Package')) Write-Debug -Message ($LocalizedData.FastPackageReference -f $fastPackageReference) Appx\Remove-AppxPackage -Package $fastPackageReference } function Add-PackageSource { [CmdletBinding()] param ( [string] $Name, [string] $Location, [bool] $Trusted ) Write-Debug ($LocalizedData.ProviderApiDebugMessage -f ('Add-PackageSource')) Set-PackageSourcesVariable -Force if(-not (Microsoft.PowerShell.Management\Test-Path $Location) -and -not (Test-WebUri -uri $Location)) { $LocationUri = [Uri]$Location if($LocationUri.Scheme -eq 'file') { $message = $LocalizedData.PathNotFound -f ($Location) ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId "PathNotFound" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument ` -ExceptionObject $Location } else { $message = $LocalizedData.InvalidWebUri -f ($Location, "Location") ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId "InvalidWebUri" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument ` -ExceptionObject $Location } } if(Test-WildcardPattern $Name) { $message = $LocalizedData.PackageSourceNameContainsWildCards -f ($Name) ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId "PackageSourceNameContainsWildCards" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument ` -ExceptionObject $Name } $LocationString = Get-ValidPackageLocation -LocationString $Location -ParameterName "Location" # Check if Location is already registered with another Name $existingSourceName = Get-SourceName -Location $LocationString if($existingSourceName -and ($Name -ne $existingSourceName)) { $message = $LocalizedData.PackageSourceAlreadyRegistered -f ($existingSourceName, $Location, $Name) ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId "PackageSourceAlreadyRegistered" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument } # Check if Name is already registered if($script:AppxPackageSources.Contains($Name)) { $currentSourceObject = $script:AppxPackageSources[$Name] $null = $script:AppxPackageSources.Remove($Name) } # Add new package source $packageSource = Microsoft.PowerShell.Utility\New-Object PSCustomObject -Property ([ordered]@{ Name = $Name SourceLocation = $LocationString Trusted=$Trusted Registered= $true }) $script:AppxPackageSources.Add($Name, $packageSource) $message = $LocalizedData.SourceRegistered -f ($Name, $LocationString) Write-Verbose $message # Persist the package sources Save-PackageSources # return the package source object. Write-Output -InputObject (New-PackageSourceFromSource -Source $packageSource) } function Resolve-PackageSource { Write-Debug ($LocalizedData.ProviderApiDebugMessage -f ('Resolve-PackageSource')) Set-PackageSourcesVariable $SourceName = $request.PackageSources if(-not $SourceName) { $SourceName = "*" } foreach($src in $SourceName) { if($request.IsCanceled) { return } $wildcardPattern = New-Object System.Management.Automation.WildcardPattern $src,$script:wildcardOptions $sourceFound = $false $script:AppxPackageSources.GetEnumerator() | Microsoft.PowerShell.Core\Where-Object {$wildcardPattern.IsMatch($_.Key)} | Microsoft.PowerShell.Core\ForEach-Object { $source = $script:AppxPackageSources[$_.Key] $packageSource = New-PackageSourceFromSource -Source $source Write-Output -InputObject $packageSource $sourceFound = $true } if(-not $sourceFound) { $sourceName = Get-SourceName -Location $src if($sourceName) { $source = $script:AppxPackageSources[$sourceName] $packageSource = New-PackageSourceFromSource -Source $source Write-Output -InputObject $packageSource } elseif( -not (Test-WildcardPattern $src)) { $message = $LocalizedData.PackageSourceNotFound -f ($src) Write-Error -Message $message -ErrorId "PackageSourceNotFound" -Category InvalidOperation -TargetObject $src } } } } function Remove-PackageSource { param ( [string] $Name ) Write-Debug ($LocalizedData.ProviderApiDebugMessage -f ('Remove-PackageSource')) Set-PackageSourcesVariable -Force $SourcesToBeRemoved = @() foreach ($sourceName in $Name) { if($request.IsCanceled) { return } # Check if $Name contains any wildcards if(Test-WildcardPattern $sourceName) { $message = $LocalizedData.PackageSourceNameContainsWildCards -f ($sourceName) Write-Error -Message $message -ErrorId "PackageSourceNameContainsWildCards" -Category InvalidOperation -TargetObject $sourceName continue } # Check if the specified package source name is in the registered package sources if(-not $script:AppxPackageSources.Contains($sourceName)) { $message = $LocalizedData.PackageSourceNotFound -f ($sourceName) Write-Error -Message $message -ErrorId "PackageSourceNotFound" -Category InvalidOperation -TargetObject $sourceName continue } $SourcesToBeRemoved += $sourceName $message = $LocalizedData.PackageSourceUnregistered -f ($sourceName) Write-Verbose $message } # Remove the SourcesToBeRemoved $SourcesToBeRemoved | Microsoft.PowerShell.Core\ForEach-Object { $null = $script:AppxPackageSources.Remove($_) } # Persist the package sources Save-PackageSources } #endregion #region Common functions function Get-AppxPackagesFromPath { param ( [Parameter(Mandatory=$true)] $Path ) $filterAppxPackages = "*"+$script:AppxPackageExtension $packages = Get-ChildItem -path $Path -filter $filterAppxPackages return $packages } function ZipFileApisAvailable { $ZipFileApisAvailable = $false try { [System.IO.Compression.ZipFile] $ZipFileApisAvailable = $true } catch { } return $ZipFileApisAvailable } function Expand-ZIPFile($file, $destination) { try { if(-not(Test-Path $destination)) { New-Item -ItemType directory -Path $Destination } if(ZipFileApisAvailable) { [System.IO.Compression.ZipFile]::ExtractToDirectory($file, $destination) return true } else { Copy-Item -Path $file -Destination "$destination\$script:AppxPkgZipFile" -Force $shell = new-object -com shell.application $zip = $shell.NameSpace("$destination\$script:AppxPkgZipFile") foreach($item in $zip.items()) { if($item.Path -eq "$destination\$script:AppxPkgZipFile\$script:AppxManifestFile") { $shell.Namespace($destination).copyhere($item) } } return $true } } catch { return $false } } function Get-PackageManfiestData { param ( [Parameter(Mandatory=$true)] $PackageFullPath ) $guid = [System.Guid]::NewGuid().toString() $destination = "$env:TEMP\$guid" Expand-ZIPFile -file $PackageFullPath -destination $destination [xml] $packageManifest = Get-Content "$destination\$script:AppxManifestFile" -ErrorAction SilentlyContinue if($packageManifest) { $Identity = $packageManifest.Package.Identity $manifestData = new-object psobject -Property @{pkgName=$Identity.Name; Architecture=$Identity.ProcessorArchitecture; Publisher=$Identity.Publisher; Version=$Identity.Version; ResourceId=$Identity.resourceId; PackageFullName=$PackageFullPath} Remove-Item -Path "$env:TEMP\$guid" -Recurse -Force -ErrorAction SilentlyContinue return $manifestData } else { Write-Verbose ($LocalizedData.MetaDataExtractionFailed -f ($PackageFullPath) ) } return $null } function New-FastPackageReference { param ( [Parameter(Mandatory=$true)] [string] $PackageFullName ) return "$PackageFullName" } function New-SoftwareIdentityPackageManifestData { param ( [Parameter(Mandatory=$true)] $PackageManifest, [string] $Source, [Parameter(Mandatory=$true)] $pkgName ) $fastPackageReference = New-FastPackageReference -PackageFullName $PackageManifest.PackageFullName if(-not($Source)) { $Source = $Package.Publisher } $details = @{ Publisher = $PackageManifest.Publisher Architecture = $PackageManifest.Architecture ResourceId = $PackageManifest.ResourceId PackageFullName = $PackageManifest.PackageFullName PackageName = $PackageManifest.pkgName } $params = @{ FastPackageReference = $fastPackageReference; Name = $pkgName; Version = $PackageManifest.Version; versionScheme = "MultiPartNumeric"; Source = $source; Details = $details; } $sid = New-SoftwareIdentity @params return $sid } function New-SoftwareIdentityFromPackage { param ( [Parameter(Mandatory=$true)] $Package, [string] $Source ) $fastPackageReference = New-FastPackageReference -PackageFullName $Package.PackageFullName if(-not($Source)) { $Source = $Package.Publisher } $details = @{ Publisher = $Package.Publisher Architecture = $Package.Architecture ResourceId = $Package.ResourceId PackageFullName = $Package.PackageFullName } $params = @{ FastPackageReference = $fastPackageReference; Name = $Package.Name; Version = $Package.Version; versionScheme = "MultiPartNumeric"; Source = $source; Details = $details; } $sid = New-SoftwareIdentity @params return $sid } function Test-WebUri { [CmdletBinding()] [OutputType([bool])] Param ( [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [Uri] $uri ) return ($uri.AbsoluteURI -ne $null) -and ($uri.Scheme -match '[http|https]') } function Test-WildcardPattern { [CmdletBinding()] [OutputType([bool])] param( [Parameter(Mandatory=$true)] [ValidateNotNull()] $Name ) return [System.Management.Automation.WildcardPattern]::ContainsWildcardCharacters($Name) } function DeSerialize-PSObject { [CmdletBinding(PositionalBinding=$false)] Param ( [Parameter(Mandatory=$true)] $Path ) $filecontent = Microsoft.PowerShell.Management\Get-Content -Path $Path [System.Management.Automation.PSSerializer]::Deserialize($filecontent) } function Get-SourceName { [CmdletBinding()] [OutputType("string")] Param ( [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [string] $Location ) Set-PackageSourcesVariable foreach($source in $script:AppxPackageSources.Values) { if($source.SourceLocation -eq $Location) { return $source.Name } } } function WebRequestApisAvailable { $webRequestApiAvailable = $false try { [System.Net.WebRequest] $webRequestApiAvailable = $true } catch { } return $webRequestApiAvailable } function Ping-Endpoint { param ( [Parameter()] [ValidateNotNullOrEmpty()] [string[]] $Endpoint ) $results = @{} if(WebRequestApisAvailable) { $iss = [System.Management.Automation.Runspaces.InitialSessionState]::Create() $iss.types.clear() $iss.formats.clear() $iss.LanguageMode = "FullLanguage" $WebRequestcmd = @' try {{ $request = [System.Net.WebRequest]::Create("{0}") $request.Method = 'GET' $request.Timeout = 30000 $response = [System.Net.HttpWebResponse]$request.GetResponse() $response $response.Close() }} catch [System.Net.WebException] {{ "Error:System.Net.WebException" }} '@ -f $EndPoint $ps = [powershell]::Create($iss).AddScript($WebRequestcmd) $response = $ps.Invoke() $ps.dispose() if ($response -ne "Error:System.Net.WebException") { $results.Add($Script:ResponseUri,$response.ResponseUri.ToString()) $results.Add($Script:StatusCode,$response.StatusCode.value__) } } else { $response = $null try { $httpClient = New-Object 'System.Net.Http.HttpClient' $response = $httpclient.GetAsync($endpoint) } catch { } if ($response -ne $null -and $response.result -ne $null) { $results.Add($Script:ResponseUri,$response.Result.RequestMessage.RequestUri.AbsoluteUri.ToString()) $results.Add($Script:StatusCode,$response.result.StatusCode.value__) } } return $results } function Get-ValidPackageLocation { [CmdletBinding()] Param ( [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [string] $LocationString, [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [string] $ParameterName ) # Get the actual Uri from the Location if(-not (Microsoft.PowerShell.Management\Test-Path $LocationString)) { $results = Ping-Endpoint -Endpoint $LocationString if ($results.ContainsKey("Exception")) { $Exception = $results["Exception"] if($Exception) { $message = $LocalizedData.InvalidWebUri -f ($LocationString, $ParameterName) ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId "InvalidWebUri" ` -ExceptionObject $Exception ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument } } if ($results.ContainsKey("ResponseUri")) { $LocationString = $results["ResponseUri"] } } return $LocationString } function Set-PackageSourcesVariable { param([switch]$Force) if(-not $script:AppxPackageSources -or $Force) { if(Microsoft.PowerShell.Management\Test-Path $script:AppxPackageSourcesFilePath) { $script:AppxPackageSources = DeSerialize-PSObject -Path $script:AppxPackageSourcesFilePath } else { $script:AppxPackageSources = [ordered]@{} } } } function Save-PackageSources { if($script:AppxPackageSources) { if(-not (Microsoft.PowerShell.Management\Test-Path $script:AppxLocalPath)) { $null = Microsoft.PowerShell.Management\New-Item -Path $script:AppxLocalPath ` -ItemType Directory -Force ` -ErrorAction SilentlyContinue ` -WarningAction SilentlyContinue ` -Confirm:$false -WhatIf:$false } Microsoft.PowerShell.Utility\Out-File -FilePath $script:AppxPackageSourcesFilePath -Force -InputObject ([System.Management.Automation.PSSerializer]::Serialize($script:AppxPackageSources)) } } function New-PackageSourceFromSource { param ( [Parameter(Mandatory)] $Source ) # create a new package source $src = New-PackageSource -Name $Source.Name ` -Location $Source.SourceLocation ` -Trusted $Source.Trusted ` -Registered $Source.Registered ` Write-Verbose ( $LocalizedData.PackageSourceDetails -f ($src.Name, $src.Location, $src.IsTrusted, $src.IsRegistered) ) # return the package source object. Write-Output -InputObject $src } #endregion # Utility to throw an errorrecord function ThrowError { param ( [parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [System.Management.Automation.PSCmdlet] $CallerPSCmdlet, [parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [System.String] $ExceptionName, [parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [System.String] $ExceptionMessage, [System.Object] $ExceptionObject, [parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [System.String] $ErrorId, [parameter(Mandatory = $true)] [ValidateNotNull()] [System.Management.Automation.ErrorCategory] $ErrorCategory ) $exception = New-Object $ExceptionName $ExceptionMessage; $errorRecord = New-Object System.Management.Automation.ErrorRecord $exception, $ErrorId, $ErrorCategory, $ExceptionObject $CallerPSCmdlet.ThrowTerminatingError($errorRecord) } #endregion Export-ModuleMember -Function Find-AppxPackage , ` Find-Package, ` Install-Package, ` Uninstall-Package, ` Get-InstalledPackage, ` Remove-PackageSource, ` Resolve-PackageSource, ` Add-PackageSource, ` Get-DynamicOptions, ` Initialize-Provider, ` Get-PackageProviderName |