AWS.Tools.Installer.psm1
using namespace System using namespace System.Collections.Generic using namespace System.IO using namespace System.IO.Compression using namespace System.Management.Automation using namespace System.Net using namespace System.Net.Http using namespace System.Threading.Tasks Microsoft.PowerShell.Core\Set-StrictMode -Version 3 $script:AWSToolsSignatureAmazonSubject = 'CN="Amazon.com, Inc.", O="Amazon.com, Inc.", L=Seattle, S=Washington, C=US' $script:AWSToolsSignatureAwsSubject = 'CN="Amazon Web Services, Inc.", OU=AWS, O="Amazon Web Services, Inc.", L=Seattle, S=Washington, C=US' $script:AWSToolsTempRepoName = 'AWSToolsTemp' $script:CurrentMinAWSToolsInstallerVersion = '0.0.0.0' $script:ExpectedModuleCompanyName = 'aws-dotnet-sdk-team' $script:MaxModulesToFindIndividually = 3 $script:ParallelDownloaderClassCode = @" using System; using System.IO; using System.Net.Http; using System.Threading; using System.Threading.Tasks; public class ParallelDownloader { private readonly HttpClient Client; private readonly CancellationTokenSource CancellationTokenSource = new CancellationTokenSource(); public ParallelDownloader(HttpClient client) { Client = client; } public async Task DownloadToFile(string uri, string filePath) { using (var httpResponseMessage = await Client.GetAsync(uri, CancellationTokenSource.Token)) using (var stream = await httpResponseMessage.EnsureSuccessStatusCode().Content.ReadAsStreamAsync()) using (var fileStream = new FileStream(filePath, FileMode.Create)) { await stream.CopyToAsync(fileStream, 81920, CancellationTokenSource.Token); } } public void Cancel() { CancellationTokenSource.Cancel(); } } "@ function Get-CleanVersion { Param( [Parameter(ValueFromPipelineByPropertyName, ValueFromPipeline, Mandatory, Position = 0)] [AllowNull()] [Version] $Version ) Process { if ($null -eq $Version) { $Version } else { [int]$major = $Version.Major [int]$minor = $Version.Minor [int]$build = $Version.Build [int]$revision = $Version.Revision #PowerShell modules version numbers can have missing fields, that would create problems with #matching and sorting versions. Replacing missing fields with 0s if ($major -lt 0) { $major = 0 } if ($minor -lt 0) { $minor = 0 } if ($build -lt 0) { $build = 0 } if ($revision -lt 0) { $revision = 0 } [Version]::new($major, $minor, $build, $revision) } } } function Get-AWSToolsModule { Param( [Parameter()] [Switch] $SkipIfInvalidSignature ) Process { [PSModuleInfo[]]$installedAwsToolsModules = Microsoft.PowerShell.Core\Get-Module -Name 'AWS.Tools.*' -ListAvailable -Verbose:$false if ($installedAwsToolsModules -and ($PSVersionTable.PSVersion.Major -lt 6 -or $IsWindows)) { $installedAwsToolsModules = $installedAwsToolsModules | Where-Object { [Signature]$signature = Microsoft.PowerShell.Security\Get-AuthenticodeSignature -FilePath $_.Path ($signature.Status -eq 'Valid' -or $SkipIfInvalidSignature) -and ($signature.SignerCertificate.Subject -eq $script:AWSToolsSignatureAmazonSubject -or $signature.SignerCertificate.Subject -eq $script:AWSToolsSignatureAwsSubject) } } $installedAwsToolsModules | Where-Object { $_.Name -ne 'AWS.Tools.Installer' } } } <# .Synopsis Uninstalls all currently installed AWS.Tools modules. .Description This cmdlet uses Uninstall-Module to uninstall all currently installed AWS.Tools modules. .Notes .Example Uninstall-AWSToolsModule -ExceptVersion 4.0.0.0 This example uninstalls all versions of all AWS.Tools modules except for version 4.0.0.0. #> function Uninstall-AWSToolsModule { [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'High')] Param( ## Specifies the minimum version of the modules to uninstall. [Parameter(ValueFromPipelineByPropertyName)] [Version] $MinimumVersion, ## Specifies exact version number of the module to uninstall. [Parameter(ValueFromPipelineByPropertyName)] [Version] $RequiredVersion, ## Specifies the maximum version of the modules to uninstall. [Parameter(ValueFromPipelineByPropertyName)] [Version] $MaximumVersion, ## Specifies that you want to uninstall all of the other available versions of AWS Tools except this one. [Parameter(ValueFromPipelineByPropertyName)] [Version] $ExceptVersion, ## Forces Uninstall-AWSToolsModule to run without asking for user confirmation [Parameter(ValueFromPipelineByPropertyName)] [Switch] $Force ) Begin { $MinimumVersion = Get-CleanVersion $MinimumVersion $RequiredVersion = Get-CleanVersion $RequiredVersion $MaximumVersion = Get-CleanVersion $MaximumVersion $ExceptVersion = Get-CleanVersion $ExceptVersion Write-Verbose "[$($MyInvocation.MyCommand)] ConfirmPreference=$ConfirmPreference WhatIfPreference=$WhatIfPreference VerbosePreference=$VerbosePreference Force=$Force" } Process { $ErrorActionPreference = 'Stop' Write-Verbose "[$($MyInvocation.MyCommand)] Searching installed modules" [PSModuleInfo[]]$InstalledAwsToolsModules = Get-AWSToolsModule if ($MinimumVersion) { $InstalledAwsToolsModules = $InstalledAwsToolsModules | Where-Object { $_.Version -ge $MinimumVersion } } if ($MaximumVersion) { $InstalledAwsToolsModules = $InstalledAwsToolsModules | Where-Object { $_.Version -le $MaximumVersion } } if ($RequiredVersion) { $InstalledAwsToolsModules = $InstalledAwsToolsModules | Where-Object { $_.Version -eq $RequiredVersion } } if ($ExceptVersion) { $InstalledAwsToolsModules = $InstalledAwsToolsModules | Where-Object { $_.Version -ne $ExceptVersion } } $versions = $InstalledAwsToolsModules | Group-Object Version if ($versions -and ($Force -or $WhatIfPreference -or $PSCmdlet.ShouldProcess("AWS Tools version $([string]::Join(', ', $versions.Name))"))) { $ConfirmPreference = 'None' $versions | ForEach-Object { Write-Host "Uninstalling AWS.Tools version $($_.Name)" [PSModuleInfo[]]$versionModules = $_.Group while ($versionModules) { [string[]]$dependencyNames = $versionModules | Select-Object -ExpandProperty RequiredModules | Select-Object -ExpandProperty Name | Sort-Object -Unique if ($dependencyNames) { [PSModuleInfo[]]$removableModules = $versionModules | Where-Object { -not $dependencyNames.Contains($_.Name) } } else { [PSModuleInfo[]]$removableModules = $versionModules } if (-not $removableModules) { Write-Error "Remaining modules for version $($_.Name) cannot be removed" break } $removableModules | ForEach-Object { if ($WhatIfPreference) { Write-Host "What if: Uninstalling module $($_.Name)" } else { Write-Host "Uninstalling module $($_.Name)" #We need to use -Force to work around https://github.com/PowerShell/PowerShellGet/issues/542 $uninstallModuleParams = @{ Name = $_.Name RequiredVersion = $_.Version Force = $true Confirm = $false ErrorAction = 'Continue' } PowerShellGet\Uninstall-Module @uninstallModuleParams } } $versionModules = $versionModules | Where-Object { $_.Name -notin ($removableModules | Select-Object -ExpandProperty Name) } } } } } End { Write-Verbose "[$($MyInvocation.MyCommand)] End" } } function Find-AWSToolsModule { Param( ## Specifies a proxy server for the request, rather than connecting directly to an internet resource. [Parameter(ValueFromPipelineByPropertyName, ValueFromPipeline, Mandatory, Position = 0)] [string[]] $Name, ## Specifies a proxy server for the request, rather than connecting directly to an internet resource. [Parameter(ValueFromPipelineByPropertyName)] [Uri] $Proxy, ## Specifies a user account that has permission to use the proxy server specified by the Proxy parameter. [Parameter(ValueFromPipelineByPropertyName)] [PSCredential] $ProxyCredential ) Begin { $RequiredVersion = Get-CleanVersion $RequiredVersion $MaximumVersion = Get-CleanVersion $MaximumVersion Write-Verbose "[$($MyInvocation.MyCommand)] ConfirmPreference=$ConfirmPreference WhatIfPreference=$WhatIfPreference VerbosePreference=$VerbosePreference Name=($Name)" } Process { $proxyParams = @{ } if ($Proxy) { $proxyParams['Proxy'] = $Proxy } if ($ProxyCredential) { $proxyParams['ProxyCredential'] = $ProxyCredential } [PSObject[]]$availableModules = @() [string[]]$missingModules = $Name #'Find-Module AWS.Tools.*' is only slightly slower than Find-Module for a single module if ($Name.Count -gt $script:MaxModulesToFindIndividually) { $availableModules += PowerShellGet\Find-Module -Name 'AWS.Tools.*' -Repository 'PSGallery' @proxyParams -ErrorAction 'Stop' | Where-Object { $_.Name -in $Name -and $_.CompanyName -ceq $script:ExpectedModuleCompanyName } $missingModules = $Name | Where-Object { $_ -notin ($availableModules | Select-Object -ExpandProperty Name) } if ($missingModules) { Write-Verbose "[$($MyInvocation.MyCommand)] Retrying Find-Module on ($missingModules)" } } if ($missingModules) { #'Find-Module AWS.Tools.*' doesn't always return all modules, so we have to retry missing ones $missingModules | ForEach-Object { $availableModules += PowerShellGet\Find-Module -Name $_ -Repository 'PSGallery' @proxyParams -ErrorAction 'Ignore' | Where-Object { $_.Name -in $Name -and $_.CompanyName -ceq $script:ExpectedModuleCompanyName } } $missingModules = $Name | Where-Object { $_ -notin ($availableModules | Select-Object -ExpandProperty Name) } if ($missingModules) { throw "Could not find AWS.Tools module on PSGallery: $([string]::Join(', ', $missingModules))." } } $availableModules } End { Write-Verbose "[$($MyInvocation.MyCommand)] End" } } function Get-AWSToolsModuleDependenciesAndValidate { Param( ## Path of the manifest file to validate [Parameter(ValueFromPipelineByPropertyName, Mandatory)] [string] $Path, ## Name of the module to validate [Parameter(ValueFromPipelineByPropertyName, Mandatory)] [string] $Name ) Begin { Write-Verbose "[$($MyInvocation.MyCommand)] ConfirmPreference=$ConfirmPreference WhatIfPreference=$WhatIfPreference VerbosePreference=$VerbosePreference Name=$Name Path=$Path" } Process { $ErrorActionPreference = 'Stop' Add-Type -AssemblyName System.IO.Compression.FileSystem -ErrorAction Stop Add-Type -AssemblyName System.IO.Compression -ErrorAction Stop [Stream]$manifestFileStream = $null [Stream]$entryStream = $null [ZipArchive]$zipArchive = $null [string]$temporaryManifestFilePath = $null try { $zipArchive = [ZipFile]::OpenRead($Path) [ZipArchiveEntry]$entry = $zipArchive.GetEntry("$($Name).psd1") $entryStream = $entry.Open() $temporaryManifestFilePath = Join-Path ([Path]::GetTempPath()) "$([Path]::GetRandomFileName()).psd1" $manifestFileStream = [File]::OpenWrite($temporaryManifestFilePath) $entryStream.CopyTo($manifestFileStream) $manifestFileStream.Close(); if ($PSVersionTable.PSVersion.Major -lt 6 -or $IsWindows) { [Signature]$manifestSignature = Microsoft.PowerShell.Security\Get-AuthenticodeSignature -FilePath $temporaryManifestFilePath if ($manifestSignature.Status -eq 'Valid' -and ($manifestSignature.SignerCertificate.Subject -eq $script:AWSToolsSignatureAmazonSubject -or $manifestSignature.SignerCertificate.Subject -eq $script:AWSToolsSignatureAwsSubject)) { Write-Verbose "[$($MyInvocation.MyCommand)] Manifest signature correctly validated" } else { throw "Error validating manifest signature for $($Name)" } } else { Write-Verbose "[$($MyInvocation.MyCommand)] Authenticode signature can only be verified on Windows, skipping" } [PSObject]$manifestData = Microsoft.PowerShell.Utility\Import-PowerShellDataFile $temporaryManifestFilePath if ($manifestData.PrivateData.ContainsKey('MinAWSToolsInstallerVersion')) { [Version]$minVersion = Get-CleanVersion $manifestData.PrivateData.MinAWSToolsInstallerVersion if ($minVersion -gt $script:CurrentMinAWSToolsInstallerVersion) { throw "$Name version $($manifestData.ModuleVersion) requires at least AWS.Tools.Installer version $minVersion. Run 'Update-Module AWS.Tools.Installer'." } } $manifestData.RequiredModules | ForEach-Object { Write-Verbose "[$($MyInvocation.MyCommand)] Found dependency $($_.ModuleName)" $_.ModuleName } } finally { if ($manifestFileStream) { $manifestFileStream.Dispose() } if ($entryStream) { $entryStream.Dispose() } if ($zipArchive) { $zipArchive.Dispose() } if ($temporaryManifestFilePath) { Microsoft.PowerShell.Management\Remove-Item -Path $temporaryManifestFilePath -WhatIf:$false } } } End { Write-Verbose "[$($MyInvocation.MyCommand)] End" } } <# .Synopsis Install AWS.Tools modules. .Description This cmdlet uses Install-Module to install AWS.Tools modules. Unless -SkipUpdate is specified, this cmdlet also updates all other currently installed AWS.Tools modules to the version being installed. .Notes This cmdlet uses the PSRepository named PSGallery as source. Use 'Get-PSRepository -Name PSGallery' for information on the PSRepository used by Update-AWSToolsModule. This cmdlet downloads all modules from https://www.powershellgallery.com/api/v2/package/ and considers it a trusted source. .Example Install-AWSToolsModule EC2,S3 -RequiredVersion 4.0.0.0 This example installs version 4.0.0.0 of AWS.Tools.EC2, AWS.Tools.S3 and their dependencies. #> function Install-AWSToolsModule { [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'High')] Param( ## Specifies names of the AWS.Tools modules to install. ## The names can be listed either with or without the "AWS.Tools." prefix (i.e. "AWS.Tools.Common" or simply "Common"). [Parameter(ValueFromPipelineByPropertyName, ValueFromPipeline, Mandatory, Position = 0)] [string[]] $Name, ## Specifies exact version number of the module to install. [Parameter(ValueFromPipelineByPropertyName, Position = 1)] [Version] $RequiredVersion, ## Specifies the minimum version of the modules to install. [Parameter(ValueFromPipelineByPropertyName)] [Version] $MinimumVersion, ## Specifies the maximum version of the modules to install. [Parameter(ValueFromPipelineByPropertyName)] [Version] $MaximumVersion, ## Specifies that, after a successful install, all other versions of the AWS Tools modules should be uninstalled. [Parameter(ValueFromPipelineByPropertyName)] [Switch] $CleanUp, ## Install-AWSToolsModule by default also updates all currently installed AWS.Tools modules. -SkipUpdate disables the update. [Parameter(ValueFromPipelineByPropertyName)] [Switch] $SkipUpdate, ## Allows skipping the publisher validation check. [Parameter(ValueFromPipelineByPropertyName)] [Switch] $SkipPublisherCheck, ## Specifies the installation scope of the module. The acceptable values for this parameter are AllUsers and CurrentUser. ## The AllUsers scope installs modules in a location that is accessible to all users of the computer: ## $env:ProgramFiles\PowerShell\Modules ## The CurrentUser installs modules in a location that is accessible only to the current user of the computer: ## $home\Documents\PowerShell\Modules ## When no Scope is defined, the default is CurrentUser. [Parameter(ValueFromPipelineByPropertyName)] [ValidateSet('CurrentUser', 'AllUsers')] [string] $Scope = 'CurrentUser', ## Overrides warning messages about installation conflicts about existing commands on a computer. [Parameter(ValueFromPipelineByPropertyName)] [Switch] $AllowClobber, ## Specifies a proxy server for the request, rather than connecting directly to an internet resource. [Parameter(ValueFromPipelineByPropertyName)] [Uri] $Proxy, ## Specifies a user account that has permission to use the proxy server specified by the Proxy parameter. [Parameter(ValueFromPipelineByPropertyName)] [PSCredential] $ProxyCredential, ## Forces an install of each specified module without a prompt to request confirmation [Parameter(ValueFromPipelineByPropertyName)] [Switch] $Force ) Begin { $RequiredVersion = Get-CleanVersion $RequiredVersion $MaximumVersion = Get-CleanVersion $MaximumVersion Write-Verbose "[$($MyInvocation.MyCommand)] ConfirmPreference=$ConfirmPreference WhatIfPreference=$WhatIfPreference VerbosePreference=$VerbosePreference Force=$Force Name=($Name) RequiredVersion=$RequiredVersion SkipUpdate=$SkipUpdate CleanUp=$CleanUp" } Process { $ErrorActionPreference = 'Stop' $Name = $Name | ForEach-Object { if ($_.Contains('.')) { $_ } else { "AWS.Tools.$_" } } | Sort-Object -Unique if ($Name -notlike 'AWS.Tools.*') { throw "The Name parameter must contain only AWS.Tools modules." } if ($Name -eq 'AWS.Tools.Installer') { throw "AWS.Tools.Installer cannot be used to install AWS.Tools.Installer. Use Update-Module instead." } [PSObject[]]$availableModulesToInstall = Find-AWSToolsModule -Name $Name -Proxy $Proxy -ProxyCredential $ProxyCredential [Version]$availableVersion = [Version[]]$availableModulesToInstall.Version | Measure-Object -Minimum | Select-Object -Expand Minimum if ($MinimumVersion -and $MinimumVersion -gt $availableVersion) { throw "The maximum version available is $availableVersion." } if ($RequiredVersion -and $RequiredVersion -gt $availableVersion) { throw "The maximum version available is $availableVersion." } if ($MinimumVersion -and $RequiredVersion -and $MinimumVersion -gt $RequiredVersion) { throw 'Parameter MinimumVersion is greater than RequiredVersion.' } if ($MaximumVersion -and $RequiredVersion -and $MaximumVersion -lt $RequiredVersion) { throw 'Parameter MaximumVersion is less than RequiredVersion.' } if ($MaximumVersion -and -not $RequiredVersion -and $MaximumVersion -lt $availableVersion) { $RequiredVersion = Find-Module -Name 'AWS.Tools.Common' -MaximumVersion $MaximumVersion | Select-Object -Expand Version } if (-not $RequiredVersion) { $RequiredVersion = $availableVersion } Write-Verbose "[$($MyInvocation.MyCommand)] Installing AWS Tools version $RequiredVersion" [string[]]$modulesToInstall = $availableModulesToInstall.Name if (-not $SkipUpdate) { Write-Verbose "[$($MyInvocation.MyCommand)] Searching installed modules" [PSModuleInfo[]]$installedAwsToolsModules = Get-AWSToolsModule -SkipIfInvalidSignature if ($installedAwsToolsModules) { $modulesToInstall = ($modulesToInstall + ($installedAwsToolsModules | Select-Object -Expand Name)) | Sort-Object -Unique Write-Verbose "[$($MyInvocation.MyCommand)] Merging existing modules into the list of modules to install: ($modulesToInstall)" } } $modulesToInstall = $modulesToInstall | Where-Object { -not (Get-Module $_ -ListAvailable -Verbose:$false | Where-Object { $_.Version -eq $RequiredVersion }) } Write-Verbose "[$($MyInvocation.MyCommand)] Removing already installed modules from the. Final list of modules to install: ($modulesToInstall)" if ($modulesToInstall) { if ($Force -or $WhatIfPreference -or $PSCmdlet.ShouldProcess("AWS Tools version $RequiredVersion")) { $ConfirmPreference = 'None' [string]$temporaryRepoDirectory = Join-Path ([Path]::GetTempPath()) ([Path]::GetRandomFileName()) Write-Verbose "[$($MyInvocation.MyCommand)] Create folder for temporary repository $temporaryRepoDirectory" Microsoft.PowerShell.Management\New-Item -ItemType Directory -Path $temporaryRepoDirectory -WhatIf:$false | Out-Null try { if (-not $WhatIfPreference) { PowerShellGet\Unregister-PSRepository -Name $script:AWSToolsTempRepoName -ErrorAction 'SilentlyContinue' Write-Verbose "[$($MyInvocation.MyCommand)] Registering temporary repository $script:AWSToolsTempRepoName" PowerShellGet\Register-PSRepository -Name $script:AWSToolsTempRepoName -SourceLocation $temporaryRepoDirectory -ErrorAction 'Stop' PowerShellGet\Set-PSRepository -Name $script:AWSToolsTempRepoName -InstallationPolicy Trusted } Add-Type -AssemblyName System.Net.Http -ErrorAction Stop [HttpClient]$httpClient = $null [HttpClientHandler]$httpClientHandler = $null [List[PSCustomObject]]$tasks = @() Write-Verbose "[$($MyInvocation.MyCommand)] Downloading modules to temporary repository" try { $httpClientHandler = [HttpClientHandler]::new() if ($Proxy) { $httpClientHandler.Proxy = [WebProxy]::new($Proxy) if ($ProxyCredential) { $httpClientHandler.Proxy.Credentials = $ProxyCredential.GetNetworkCredential() } } $httpClient = [HttpClient]::new($httpClientHandler); Add-Type $script:ParallelDownloaderClassCode -ReferencedAssemblies System.Net.Http,System.Threading.Tasks [ParallelDownloader]$parallelDownloader = [ParallelDownloader]::new($httpClient) [string[]]$modulesToDownload = $modulesToInstall [HashSet[string]]$savedModules = New-Object -TypeName System.Collections.Generic.HashSet[string] Write-Verbose "[$($MyInvocation.MyCommand)] Downloading modules ($modulesToDownload)" while ($modulesToDownload) { [string[]]$dependencies = @() $tasks = $modulesToDownload | Where-Object { $savedModules.Add($_) } | ForEach-Object { [string]$nupkgFilePath = Join-Path $temporaryRepoDirectory "$_.$($RequiredVersion).nupkg" Write-Verbose "[$($MyInvocation.MyCommand)] Downloading module $_ to $TemporaryRepoDirectory" [PSCustomObject]@{ Task = $parallelDownloader.DownloadToFile("https://www.powershellgallery.com/api/v2/package/$_/$RequiredVersion", $nupkgFilePath) ModuleName = $_ Path = $nupkgFilePath } } while ($tasks) { [int]$taskIndex = [Task]::WaitAny($tasks.Task) [PSObject]$task = $tasks[$taskIndex] $tasks.RemoveAt($taskIndex) if ($task.Task.IsCompleted) { $dependencies += Get-AWSToolsModuleDependenciesAndValidate -Path $task.Path -Name $task.ModuleName } else { throw "Error downloading $($task.ModuleName): $($task.Task.Exception)" } } $modulesToDownload = $dependencies | Sort-Object -Unique } } finally { if ($tasks) { Write-Verbose "[$($MyInvocation.MyCommand)] Cancelling $($tasks.Count) tasks" $parallelDownloader.Cancel() try { [Task]::WaitAll($tasks.Task) } catch { } } if ($httpClient) { $httpClient.Dispose() } if ($httpClientHandler) { $httpClientHandler.Dispose() } } Write-Verbose "[$($MyInvocation.MyCommand)] Installing modules ($modulesToInstall)" $installModuleParams = @{ RequiredVersion = $RequiredVersion Scope = $Scope Repository = $script:AWSToolsTempRepoName AllowClobber = $AllowClobber Confirm = $false ErrorAction = 'Stop' SkipPublisherCheck = $SkipPublisherCheck } $modulesToInstall | ForEach-Object { if (-not $WhatIfPreference) { Write-Host "Installing module $_ version $RequiredVersion" PowerShellGet\Install-Module -Name $_ @installModuleParams } else { Write-Host "What if: Installing module $_ version $RequiredVersion" } } Write-Verbose "[$($MyInvocation.MyCommand)] Modules install complete" } finally { if (-not $WhatIfPreference) { Write-Verbose "[$($MyInvocation.MyCommand)] Unregistering temporary repository $script:AWSToolsTempRepoName" PowerShellGet\Unregister-PSRepository -Name $script:AWSToolsTempRepoName -ErrorAction 'Continue' } Write-Verbose "[$($MyInvocation.MyCommand)] Delete repository folder $temporaryRepoDirectory" Microsoft.PowerShell.Management\Remove-Item -Path $temporaryRepoDirectory -Recurse -WhatIf:$false } } } else { Write-Verbose "[$($MyInvocation.MyCommand)] All modules are up to date" } if ($CleanUp) { Uninstall-AWSToolsModule -ExceptVersion $RequiredVersion } } End { Write-Verbose "[$($MyInvocation.MyCommand)] End" } } <# .Synopsis Updates all currently installed AWS.Tools modules. .Description This cmdlet uses Install-Module to update all AWS.Tools modules. .Notes This cmdlet uses the PSRepository named PSGallery as source. Use 'Get-PSRepository -Name PSGallery' for information on the PSRepository used by Update-AWSToolsModule. This cmdlet downloads all modules from https://www.powershellgallery.com/api/v2/package/ and considers it a trusted source. .Example Update-AWSToolsModule -CleanUp This example updates all installed AWS.Tools modules to the latest version available on the PSGallery and uninstalls all other versions. #> function Update-AWSToolsModule { [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'High')] Param( ## Specifies the exact version of the modules to update to. [Parameter(ValueFromPipelineByPropertyName, Position = 0)] [Version] $RequiredVersion, ## Specifies the maximum version of the modules to update to. [Parameter(ValueFromPipelineByPropertyName)] [Version] $MaximumVersion, ## Specifies that, after a successful install, all other versions of the AWS Tools modules should be uninstalled. [Parameter(ValueFromPipelineByPropertyName)] [Switch] $CleanUp, ## Allows skipping the publisher validation check. [Parameter(ValueFromPipelineByPropertyName)] [Switch] $SkipPublisherCheck, #Specifies the installation scope of the module. The acceptable values for this parameter are AllUsers and CurrentUser. #The AllUsers scope installs modules in a location that is accessible to all users of the computer: # $env:ProgramFiles\PowerShell\Modules #The CurrentUser installs modules in a location that is accessible only to the current user of the computer: # $home\Documents\PowerShell\Modules #When no Scope is defined, the default is CurrentUser. [Parameter(ValueFromPipelineByPropertyName)] [ValidateSet('CurrentUser', 'AllUsers')] [string] $Scope = 'CurrentUser', #Overrides warning messages about installation conflicts about existing commands on a computer. [Parameter(ValueFromPipelineByPropertyName)] [Switch] $AllowClobber, #Specifies a proxy server for the request, rather than connecting directly to an internet resource. [Parameter(ValueFromPipelineByPropertyName)] [Uri] $Proxy, ## Specifies a user account that has permission to use the proxy server specified by the Proxy parameter. [Parameter(ValueFromPipelineByPropertyName)] [PSCredential] $ProxyCredential, ## Forces an update of each specified module without a prompt to request confirmation [Parameter(ValueFromPipelineByPropertyName)] [Switch] $Force ) Begin { $RequiredVersion = Get-CleanVersion $RequiredVersion $MaximumVersion = Get-CleanVersion $MaximumVersion Write-Verbose "[$($MyInvocation.MyCommand)] ConfirmPreference=$ConfirmPreference WhatIfPreference=$WhatIfPreference VerbosePreference=$VerbosePreference Force=$Force" } Process { $ErrorActionPreference = 'Stop' Write-Verbose "[$($MyInvocation.MyCommand)] Searching installed modules" [PSModuleInfo[]]$installedAwsToolsModules = Get-AWSToolsModule -SkipIfInvalidSignature [string[]]$installedAwsToolsModuleNames = $installedAwsToolsModules | Select-Object -Expand Name | Sort-Object -Unique if ($installedAwsToolsModuleNames) { Write-Verbose "[$($MyInvocation.MyCommand)] Found modules ($installedAwsToolsModuleNames)" $installAWSToolsModuleParams = @{ Name = $installedAwsToolsModuleNames RequiredVersion = $RequiredVersion MaximumVersion = $MaximumVersion Scope = $Scope AllowClobber = $AllowClobber CleanUp = $CleanUp Force = $Force SkipUpdate = $true Proxy = $Proxy ProxyCredential = $ProxyCredential SkipPublisherCheck = $SkipPublisherCheck } Install-AWSToolsModule @installAWSToolsModuleParams } } End { Write-Verbose "[$($MyInvocation.MyCommand)] End" } } # SIG # Begin signature block # MIIcLQYJKoZIhvcNAQcCoIIcHjCCHBoCAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCB44GFGaTvPemL6 # oqYx+xofBZh6GmxDFumy8Rsfn7xem6CCCoYwggUwMIIEGKADAgECAhAECRgbX9W7 # ZnVTQ7VvlVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQK # EwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNV # BAMTG0RpZ2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBa # Fw0yODEwMjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2Vy # dCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lD # ZXJ0IFNIQTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3 # DQEBAQUAA4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/l # qJ3bMtdx6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fT # eyOU5JEjlpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqH # CN8M9eJNYBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+ # bMt+dDk2DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLo # LFH3c7y9hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIB # yTASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAK # BggrBgEFBQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9v # Y3NwLmRpZ2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGln # aWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHow # eDA6oDigNoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJl # ZElEUm9vdENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0Rp # Z2lDZXJ0QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwA # AgQwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAK # BghghkgBhv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0j # BBgwFoAUReuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7s # DVoks/Mi0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGS # dQ9RtG6ljlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6 # r7VRwo0kriTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo # +MUSaJ/PQMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qz # sIzV6Q3d9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHq # aGxEMrJmoecYpJpkUe8wggVOMIIENqADAgECAhALTIJyAKtH3xTtbI8ZUVgmMA0G # CSqGSIb3DQEBCwUAMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJ # bmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0 # IFNIQTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwHhcNMjAwNjIyMDAwMDAw # WhcNMjEwNjMwMTIwMDAwWjCBijELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hp # bmd0b24xEDAOBgNVBAcTB1NlYXR0bGUxIjAgBgNVBAoTGUFtYXpvbiBXZWIgU2Vy # dmljZXMsIEluYy4xDDAKBgNVBAsTA0FXUzEiMCAGA1UEAxMZQW1hem9uIFdlYiBT # ZXJ2aWNlcywgSW5jLjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALmr # sFGrSta/FARlw23GEH+EpVCu0ejJBCgyuE2cX1ArId8rh8M6Q9/R8mlash12LDk6 # Zhfl0418bvsGqxp4V7x1PBwM9LqHwv+v9SRNJkIIRE9XQW5XLubMLDSZbqz4ysK4 # BeNXx8fg3DPIhzRYnNVAsINj43T95kW21Mje7pe8nABgUF+ihOyarccQ/+eUYHbf # vNKEn7jVwVElzKc0zlYB2xwn6NC75FunB9ah9bK1eiKyDIVq0lQfW07yW4ReAIci # 7Lmk/NLK6p+WX18tevZyOZvTp2JWCMrjQpi4Z6zNcgPVlQH/Fw9pOH88AoRNspJq # M4cTQ9nZuVO1YP37uh8CAwEAAaOCAcUwggHBMB8GA1UdIwQYMBaAFFrEuXsqCqOl # 6nEDwGD5LfZldQ5YMB0GA1UdDgQWBBRslc5x8VXQyhHcfVS3bCh5Tu1ZcTAOBgNV # HQ8BAf8EBAMCB4AwEwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYDVR0fBHAwbjA1oDOg # MYYvaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5j # cmwwNaAzoDGGL2h0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQt # Y3MtZzEuY3JsMEwGA1UdIARFMEMwNwYJYIZIAYb9bAMBMCowKAYIKwYBBQUHAgEW # HGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQQBMIGEBggrBgEF # BQcBAQR4MHYwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBO # BggrBgEFBQcwAoZCaHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # U0hBMkFzc3VyZWRJRENvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJ # KoZIhvcNAQELBQADggEBAIyDXLu8ZDZqNX5ET8VHvAu/9V6yXI+HNMeUOJO4/az7 # 5HmJmja6SpmfLZC3g+WbNgF4roHwMNsIdb7dbdTGedxef49HJe5Ut5iV5vQ8DuKn # PA7ezZV93Y5XDEiboX3sys5/k+7B1ZcP1jkObnfzQs7QXLAa3C/+kPtNmsXmTFOg # DzRBmkr1Z/LXGTxgoWNQVZKNm2HA6ePRLPGBIXw7DUTnHtr9+4Fqxadck6fn5izz # PUMOliRngw8XKTIRgBODRInHJZN9GRZI11emCP25LdHwLySxdHBTKsaslToKRAnd # hrQhoc1FDAV6wKBOQoEKRZd75GIijtMCFaih+sVRCNAxghD9MIIQ+QIBATCBhjBy # MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 # d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQg # SUQgQ29kZSBTaWduaW5nIENBAhALTIJyAKtH3xTtbI8ZUVgmMA0GCWCGSAFlAwQC # AQUAoHwwEAYKKwYBBAGCNwIBDDECMAAwGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcC # AQQwHAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIE # IOC1sOwP6I7wkxXoWmuorh57CGA6XaXQOhqRLJCLUs19MA0GCSqGSIb3DQEBAQUA # BIIBAGb8Vp6Z3jHzJCmyDvNlAhkj0Q43RaxaHwRhHXqWu09iSzlK5IkU+hUiJkiA # dENrum9NGrdPosNK+E57XHgfxfAVoyKJLJuUOSQ370zc88G/BeLZKjwAEzLkehbG # 0XMkRoMtY3O8siphTmM7Xd0r6dwks4d2OJEMKOHSLIlcwFa4mC4DSt2EL5FGXo2x # XtVowyGC6Zw6tQCmVVQx27lF58npyE7Y5geFXmHK+U7Jl89CMW3TkuV95G2bN4mw # xYwoxgXWits/XAOyVQQroc2SG+z8ldIuHy4QfA9fD+3++94edHQEcvG27/ngObhB # ZzPj7TSR5rcYM4OU7I4D8d4OE7Ohgg7JMIIOxQYKKwYBBAGCNwMDATGCDrUwgg6x # BgkqhkiG9w0BBwKggg6iMIIOngIBAzEPMA0GCWCGSAFlAwQCAQUAMHgGCyqGSIb3 # DQEJEAEEoGkEZzBlAgEBBglghkgBhv1sBwEwMTANBglghkgBZQMEAgEFAAQgH+Cr # e9T3YddS3O1Hkvcz0FSCiHXqM0NfgKUeqHrJkRsCEQDU/2AZCwr3pjyId0d4jrAE # GA8yMDIwMDgxOTA3MjcxMVqgggu7MIIGgjCCBWqgAwIBAgIQBM0/hWiudsYbsP5x # YMynbTANBgkqhkiG9w0BAQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGln # aUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhE # aWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgVGltZXN0YW1waW5nIENBMB4XDTE5MTAw # MTAwMDAwMFoXDTMwMTAxNzAwMDAwMFowTDELMAkGA1UEBhMCVVMxFzAVBgNVBAoT # DkRpZ2lDZXJ0LCBJbmMuMSQwIgYDVQQDExtUSU1FU1RBTVAtU0hBMjU2LTIwMTkt # MTAtMTUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDpZDWc+qmYZWQb # 5BfcuCk2zGcJWIVNMODJ/+U7PBEoUK8HMeJdCRjC9omMaQgEI+B3LZ0V5bjooWqO # /9Su0noW7/hBtR05dcHPL6esRX6UbawDAZk8Yj5+ev1FlzG0+rfZQj6nVZvfWk9Y # AqgyaSITvouCLcaYq2ubtMnyZREMdA2y8AiWdMToskiioRSl+PrhiXBEO43v+6T0 # w7m9FCzrDCgnJYCrEEsWEmALaSKMTs3G1bJlWSHgfCwSjXAOj4rK4NPXszl3UNBC # LC56zpxnejh3VED/T5UEINTryM6HFAj+HYDd0OcreOq/H3DG7kIWUzZFm1MZSWKd # egKblRSjAgMBAAGjggM4MIIDNDAOBgNVHQ8BAf8EBAMCB4AwDAYDVR0TAQH/BAIw # ADAWBgNVHSUBAf8EDDAKBggrBgEFBQcDCDCCAb8GA1UdIASCAbYwggGyMIIBoQYJ # YIZIAYb9bAcBMIIBkjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQu # Y29tL0NQUzCCAWQGCCsGAQUFBwICMIIBVh6CAVIAQQBuAHkAIAB1AHMAZQAgAG8A # ZgAgAHQAaABpAHMAIABDAGUAcgB0AGkAZgBpAGMAYQB0AGUAIABjAG8AbgBzAHQA # aQB0AHUAdABlAHMAIABhAGMAYwBlAHAAdABhAG4AYwBlACAAbwBmACAAdABoAGUA # IABEAGkAZwBpAEMAZQByAHQAIABDAFAALwBDAFAAUwAgAGEAbgBkACAAdABoAGUA # IABSAGUAbAB5AGkAbgBnACAAUABhAHIAdAB5ACAAQQBnAHIAZQBlAG0AZQBuAHQA # IAB3AGgAaQBjAGgAIABsAGkAbQBpAHQAIABsAGkAYQBiAGkAbABpAHQAeQAgAGEA # bgBkACAAYQByAGUAIABpAG4AYwBvAHIAcABvAHIAYQB0AGUAZAAgAGgAZQByAGUA # aQBuACAAYgB5ACAAcgBlAGYAZQByAGUAbgBjAGUALjALBglghkgBhv1sAxUwHwYD # VR0jBBgwFoAU9LbhIB3+Ka7S5GGlsqIlssgXNW4wHQYDVR0OBBYEFFZTD8HGB6dN # 19huV3KAUEzk7J7BMHEGA1UdHwRqMGgwMqAwoC6GLGh0dHA6Ly9jcmwzLmRpZ2lj # ZXJ0LmNvbS9zaGEyLWFzc3VyZWQtdHMuY3JsMDKgMKAuhixodHRwOi8vY3JsNC5k # aWdpY2VydC5jb20vc2hhMi1hc3N1cmVkLXRzLmNybDCBhQYIKwYBBQUHAQEEeTB3 # MCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wTwYIKwYBBQUH # MAKGQ2h0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFNIQTJBc3N1 # cmVkSURUaW1lc3RhbXBpbmdDQS5jcnQwDQYJKoZIhvcNAQELBQADggEBAC6DoUQF # SgTjuTJS+tmB8Bq7+AmNI7k92JKh5kYcSi9uejxjbjcXoxq/WCOyQ5yUg045CbAs # 6Mfh4szty3lrzt4jAUftlVSB4IB7ErGvAoapOnNq/vifwY3RIYzkKYLDigtgAAKd # H0fEn7QKaFN/WhCm+CLm+FOSMV/YgoMtbRNCroPBEE6kJPRHnN4PInJ3XH9P6TmY # K1eSRNfvbpPZQ8cEM2NRN1aeRwQRw6NYVCHY4o5W10k/V/wKnyNee/SUjd2dGrvf # eiqm0kWmVQyP9kyK8pbPiUbcMbKRkKNfMzBgVfX8azCsoe3kR04znmdqKLVNwu1b # l4L4y6kIbFMJtPcwggUxMIIEGaADAgECAhAKoSXW1jIbfkHkBdo2l8IVMA0GCSqG # SIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0RpZ2lDZXJ0IEFz # c3VyZWQgSUQgUm9vdCBDQTAeFw0xNjAxMDcxMjAwMDBaFw0zMTAxMDcxMjAwMDBa # MHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsT # EHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNIQTIgQXNzdXJl # ZCBJRCBUaW1lc3RhbXBpbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK # AoIBAQC90DLuS82Pf92puoKZxTlUKFe2I0rEDgdFM1EQfdD5fU1ofue2oPSNs4jk # l79jIZCYvxO8V9PD4X4I1moUADj3Lh477sym9jJZ/l9lP+Cb6+NGRwYaVX4LJ37A # ovWg4N4iPw7/fpX786O6Ij4YrBHk8JkDbTuFfAnT7l3ImgtU46gJcWvgzyIQD3XP # cXJOCq3fQDpct1HhoXkUxk0kIzBdvOw8YGqsLwfM/fDqR9mIUF79Zm5WYScpiYRR # 5oLnRlD9lCosp+R1PrqYD4R/nzEU1q3V8mTLex4F0IQZchfxFwbvPc3WTe8GQv2i # UypPhR3EHTyvz9qsEPXdrKzpVv+TAgMBAAGjggHOMIIByjAdBgNVHQ4EFgQU9Lbh # IB3+Ka7S5GGlsqIlssgXNW4wHwYDVR0jBBgwFoAUReuir/SSy4IxLVGLp6chnfNt # yA8wEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwEwYDVR0lBAww # CgYIKwYBBQUHAwgweQYIKwYBBQUHAQEEbTBrMCQGCCsGAQUFBzABhhhodHRwOi8v # b2NzcC5kaWdpY2VydC5jb20wQwYIKwYBBQUHMAKGN2h0dHA6Ly9jYWNlcnRzLmRp # Z2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcnQwgYEGA1UdHwR6 # MHgwOqA4oDaGNGh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3Vy # ZWRJRFJvb3RDQS5jcmwwOqA4oDaGNGh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9E # aWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcmwwUAYDVR0gBEkwRzA4BgpghkgBhv1s # AAIEMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMw # CwYJYIZIAYb9bAcBMA0GCSqGSIb3DQEBCwUAA4IBAQBxlRLpUYdWac3v3dp8qmN6 # s3jPBjdAhO9LhL/KzwMC/cWnww4gQiyvd/MrHwwhWiq3BTQdaq6Z+CeiZr8JqmDf # dqQ6kw/4stHYfBli6F6CJR7Euhx7LCHi1lssFDVDBGiy23UC4HLHmNY8ZOUfSBAY # X4k4YU1iRiSHY4yRUiyvKYnleB/WCxSlgNcSR3CzddWThZN+tpJn+1Nhiaj1a5bA # 9FhpDXzIAbG5KHW3mWOFIoxhynmUfln8jA/jb7UBJrZspe6HUSHkWGCbugwtK22i # xH67xCUrRwIIfEmuE7bhfEJCKMYYVs9BNLZmXbZ0e/VWMyIvIjayS6JKldj1po5S # MYICTTCCAkkCAQEwgYYwcjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0 # IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTExMC8GA1UEAxMoRGlnaUNl # cnQgU0hBMiBBc3N1cmVkIElEIFRpbWVzdGFtcGluZyBDQQIQBM0/hWiudsYbsP5x # YMynbTANBglghkgBZQMEAgEFAKCBmDAaBgkqhkiG9w0BCQMxDQYLKoZIhvcNAQkQ # AQQwHAYJKoZIhvcNAQkFMQ8XDTIwMDgxOTA3MjcxMVowKwYLKoZIhvcNAQkQAgwx # HDAaMBgwFgQUAyW9UF7aljAtwi9PoB5MKL4oNMUwLwYJKoZIhvcNAQkEMSIEINb9 # xTajgtwEfPyfutu2r0QStxLuye1vIg7MRxvnG/VgMA0GCSqGSIb3DQEBAQUABIIB # ABj1vnNjUZNHx5s1zePxtyzIHir09s1XE1V2SJJzT+PkS115iHpmh0olzc/IOTQe # bWtEuZDTb0yDo0Ln043acYjh3v1uBml4bSmQtm+7e/BKONkHTitawEDdVQDUEl+T # 9Yy6K/pnWR/W2Kzc1THkYjtcy/8UzuniONJQxBpjRgaKIzZxniQ5nhpTzz3E0+nK # skZdHG8c7yiTAMQUDo+ReYrSHk81SYxsiOh/h9CBTaN9Iq99wL/9U+Gah8LbD+fO # bLm6NjLI3xCyRtTvTX0Sdkb9p268bOYMiZMqhpoygXc1cvSSIhbPqeFGcYdaBwKb # CYvi+4RiA/W1L4iryiAp59M= # SIG # End signature block |