AWS.Tools.Installer.psm1
$script:AWSToolsSignatureSubject = 'CN="Amazon.com, Inc.", O="Amazon.com, Inc.", L=Seattle, S=Washington, C=US' $script:AWSToolsTempRepoName = 'AWSToolsTemp' $script:CurrentMinAWSToolsInstallerVersion = '0.0.0.0' $script:ExpectedModuleCompanyName = 'aws-dotnet-sdk-team' function Get-CleanVersion { Param( [Parameter(ValueFromPipelineByPropertyName, ValueFromPipeline, Mandatory, Position = 0)] [AllowNull()] [System.Version] $Version ) Process { if ($null -eq $Version) { $Version } else { $major = $Version.Major $minor = $Version.Minor $build = $Version.Build $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 } [System.Version]::new($major, $minor, $build, $revision) } } } function Get-AWSToolsModule { Param( [Parameter()] [Switch] $SkipIfInvalidSignature ) Process { $awsToolsModules = Get-Module AWS.Tools.* -ListAvailable if ($awsToolsModules -and ($PSVersionTable.PSVersion.Major -lt 6 -or $IsWindows)) { $awsToolsModules = $awsToolsModules | Where-Object { $signature = Get-AuthenticodeSignature $_.Path ($signature.Status -eq 'Valid' -or $SkipIfInvalidSignature) -and $signature.SignerCertificate.Subject -eq $script:AWSToolsSignatureSubject } } $awsToolsModules | 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)] [System.Version] $MinimumVersion, ## Specifies exact version number of the module to uninstall. [Parameter(ValueFromPipelineByPropertyName)] [System.Version] $RequiredVersion, ## Specifies the maximum version of the modules to uninstall. [Parameter(ValueFromPipelineByPropertyName)] [System.Version] $MaximumVersion, ## Specifies that you want to uninstall all of the other available versions of AWS Tools except this one. [Parameter(ValueFromPipelineByPropertyName)] [System.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" $awsToolsModules = Get-AWSToolsModule if ($MinimumVersion) { $awsToolsModules = $awsToolsModules | Where-Object { $_.Version -ge $MinimumVersion } } if ($MaximumVersion) { $awsToolsModules = $awsToolsModules | Where-Object { $_.Version -le $MaximumVersion } } if ($RequiredVersion) { $awsToolsModules = $awsToolsModules | Where-Object { $_.Version -eq $RequiredVersion } } if ($ExceptVersion) { $awsToolsModules = $awsToolsModules | Where-Object { $_.Version -ne $ExceptVersion } } $versions = $awsToolsModules | Group-Object Version if ($awsToolsModules -and ($Force -or $WhatIfPreference -or $PSCmdlet.ShouldProcess("AWS Tools version $([System.String]::Join(', ', $versions.Name))"))) { $ConfirmPreference = 'None' $versions | ForEach-Object { Write-Host "Uninstalling AWS.Tools version $($_.Name)" $versionModules = $_.Group while ($versionModules) { $dependencies = $versionModules.RequiredModules | Sort-Object -Unique if ($dependencies) { $removableModules = $versionModules | Where-Object { -not $dependencies.Name.Contains($_.Name) } } else { $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' } Uninstall-Module @uninstallModuleParams } } $versionModules = $versionModules | Where-Object { -not $removableModules.Name.Contains($_.Name) } } } } } End { Write-Verbose "[$($MyInvocation.MyCommand)] End" } } function Get-AvailableModuleVersion { Param( ## Specifies names of the AWS.Tools modules to retrieve the version for. [Parameter(ValueFromPipelineByPropertyName, ValueFromPipeline, Mandatory)] [string[]] $Name, ## Specifies exact version number of the module to install. [Parameter(ValueFromPipelineByPropertyName)] [System.Version] $RequiredVersion, ## Specifies the maximum version of the modules to install. [Parameter(ValueFromPipelineByPropertyName)] [System.Version] $MaximumVersion, ## 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 Force=$Force" } Process { $proxyParams = @{ } if ($Proxy) { $proxyParams['Proxy'] = $Proxy } if ($ProxyCredential) { $proxyParams['ProxyCredential'] = $ProxyCredential } $findModuleParams = @{ RequiredVersion = $versionToInstall MaximumVersion = $MaximumVersion Repository = 'PSGallery' ErrorAction = 'Stop' } $savedModules = $Name | ForEach-Object { Find-Module -Name $_ @findModuleParams @proxyParams } $versionToInstall = $savedModules.Version | Sort-Object -Unique if ($versionToInstall.Count -gt 1) { Write-Verbose "[$($MyInvocation.MyCommand)] Found multiple modules versions: $([System.String]::Join(', ', $versionToInstall)).)" $versionToInstall = [System.Version[]]$versionToInstall | Measure-Object -Minimum | Select-Object -Expand Minimum $findModuleParams = @{ RequiredVersion = $versionToInstall Repository = 'PSGallery' ErrorAction = 'Stop' } $savedModules = $Name | ForEach-Object { Find-Module -Name $_ @findModuleParams @proxyParams } } $versionToInstall } End { Write-Verbose "[$($MyInvocation.MyCommand)] End" } } function Save-AWSToolsModule { [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Low')] Param( ## Specifies name of the AWS.Tools module to save. [Parameter(ValueFromPipelineByPropertyName, ValueFromPipeline, Mandatory)] [string] $Name, ## Specifies directory the module should be saved to. [Parameter(ValueFromPipelineByPropertyName, Mandatory)] [string] $TemporaryRepoDirectory, ## Specifies exact version number of the module to install. [Parameter(ValueFromPipelineByPropertyName, Mandatory)] [System.Version] $RequiredVersion, ## Specifies which modules are already available either installed or in the temporary repository. [Parameter(ValueFromPipelineByPropertyName, Mandatory)] [AllowEmptyCollection()] [System.Collections.Generic.HashSet[string]] $SavedModules, ## 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 Write-Verbose "[$($MyInvocation.MyCommand)] ConfirmPreference=$ConfirmPreference WhatIfPreference=$WhatIfPreference VerbosePreference=$VerbosePreference Force=$Force" } Process { $ErrorActionPreference = 'Stop' if ($SavedModules.Add($Name.ToLower())) { $proxyParams = @{ } if ($Proxy) { $proxyParams['Proxy'] = $Proxy } if ($ProxyCredential) { $proxyParams['ProxyCredential'] = $ProxyCredential } $findModuleParams = @{ Name = $Name RequiredVersion = $versionToInstall Repository = 'PSGallery' ErrorAction = 'Stop' } $moduleInfo = Find-Module @findModuleParams @proxyParams if ($moduleInfo.CompanyName -ne $script:ExpectedModuleCompanyName) { throw "Error validating CompanyName for $($moduleInfo.Name)" } $nupkgFilePath = Join-Path $TemporaryRepoDirectory "$($moduleInfo.Name).$($moduleInfo.Version).nupkg" Write-Verbose "[$($MyInvocation.MyCommand)] Downloading module $($moduleInfo.Name) to $TemporaryRepoDirectory" $webRequestParams = @{ Uri = "https://www.powershellgallery.com/api/v2/package/$($moduleInfo.Name)/$($moduleInfo.Version)" OutFile = $nupkgFilePath } if ($PSVersionTable.PSVersion.Major -le 5) { $webRequestParams['UseBasicParsing'] = $true } Invoke-WebRequest @webRequestParams @proxyParams Write-Verbose "[$($MyInvocation.MyCommand)] Validating module manifest" try { Add-Type -AssemblyName System.IO.Compression.FileSystem -ErrorAction Stop $zipArchive = [System.IO.Compression.ZipFile]::OpenRead($nupkgFilePath) $entry = $zipArchive.GetEntry("$($moduleInfo.Name).psd1") $entryStream = $entry.Open() $temporaryManifestFilePath = Join-Path ([System.IO.Path]::GetTempPath()) "$([System.IO.Path]::GetRandomFileName()).psd1" $manifestFileStream = [System.IO.File]::OpenWrite($temporaryManifestFilePath) $entryStream.CopyTo($manifestFileStream) $manifestFileStream.Close(); if ($awsToolsModules -and ($PSVersionTable.PSVersion.Major -lt 6 -or $IsWindows)) { $manifestSignature = Get-AuthenticodeSignature $temporaryManifestFilePath if ($manifestSignature.Status -eq 'Valid' -and $manifestSignature.SignerCertificate.Subject -eq $script:AWSToolsSignatureSubject) { Write-Verbose "[$($MyInvocation.MyCommand)] Manifest signature correctly validated" } else { Write-Host $temporaryManifestFilePath Write-Host $manifestSignature.Status Write-Host $manifestSignature.SignerCertificate.Subject throw "Error validating manifest signature for $($moduleInfo.Name)" } } else { Write-Verbose "[$($MyInvocation.MyCommand)] Authenticode signature can only be vefied on Windows, skipping" } $manifestData = Import-PowerShellDataFile $temporaryManifestFilePath if ($manifestData.PrivateData.MinAWSToolsInstallerVersion) { $minVersion = Get-CleanVersion $manifestData.PrivateData.MinAWSToolsInstallerVersion if ($minVersion -gt $script:CurrentMinAWSToolsInstallerVersion) { throw "$($moduleInfo.Name) version $RequiredVersion requires at least AWS.Tools.Installer version $minVersion. Run 'Update-Module AWS.Tools.Installer -Force'." } } $saveAWSToolsModuleParams = @{ RequiredVersion = $RequiredVersion TemporaryRepoDirectory = $TemporaryRepoDirectory SavedModules = $SavedModules } $manifestData.RequiredModules | ForEach-Object { Write-Verbose "[$($MyInvocation.MyCommand)] Found dependency $($_.ModuleName)" Save-AWSToolsModule -Name $_.ModuleName @saveAWSToolsModuleParams @proxyParams | Out-Null } #Returning the property capitalized module name. $moduleInfo.Name } finally { if ($manifestFileStream) { $manifestFileStream.Dispose() } if ($entryStream) { $entryStream.Dispose() } if ($zipArchive) { $zipArchive.Dispose() } if ($temporaryManifestFilePath) { Remove-Item $temporaryManifestFilePath } } } } 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)] [System.Version] $RequiredVersion, ## Specifies the maximum version of the modules to install. [Parameter(ValueFromPipelineByPropertyName)] [System.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, ## 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" } Process { $ErrorActionPreference = 'Stop' $Name = $Name | ForEach-Object { if ($_.Contains('.')) { $_ } else { "AWS.Tools.$_" } } if (($Name -like 'AWS.Tools.*' | Sort-Object -Unique).Count -ne $Name.Count) { throw "The Name parameter must contain only AWS.Tools modules without duplicates." } if ($Name -eq 'AWS.Tools.Installer') { throw "AWS.Tools.Installer cannot be used to install AWS.Tools.Installer. Use Update-Module instead." } if ($RequiredVersion) { $versionToInstall = $RequiredVersion } else { $versionToInstall = Get-AvailableModuleVersion -Name $Name -MaximumVersion $MaximumVersion -Proxy $Proxy -ProxyCredential $ProxyCredential Write-Verbose "[$($MyInvocation.MyCommand)] Installing AWS Tools version $versionToInstall" } if (-not $SkipUpdate) { Write-Verbose "[$($MyInvocation.MyCommand)] Searching installed modules" $awsToolsModules = Get-AWSToolsModule -SkipIfInvalidSignature if ($awsToolsModules) { Write-Verbose "[$($MyInvocation.MyCommand)] Merging existing modules into the list of modules to install" $Name = ($Name + ($awsToolsModules | Select-Object -Expand Name)) | Sort-Object -Unique } } $Name = $Name | Where-Object { -not (Get-Module $_ -ListAvailable | Where-Object { $_.Version -eq $versionToInstall }) } if ($Name) { if ($Force -or $WhatIfPreference -or $PSCmdlet.ShouldProcess("AWS Tools version $versionToInstall")) { $ConfirmPreference = 'None' $temporaryRepoDirectory = Join-Path ([System.IO.Path]::GetTempPath()) ([System.IO.Path]::GetRandomFileName()) Write-Verbose "[$($MyInvocation.MyCommand)] Create folder for temporary repository $temporaryRepoDirectory" New-Item -ItemType Directory -Path $temporaryRepoDirectory -WhatIf:$false | Out-Null try { if (-not $WhatIfPreference) { Unregister-PSRepository -Name $script:AWSToolsTempRepoName -ErrorAction 'SilentlyContinue' Write-Verbose "[$($MyInvocation.MyCommand)] Registering temporary repository $script:AWSToolsTempRepoName" Register-PSRepository -Name $script:AWSToolsTempRepoName -SourceLocation $temporaryRepoDirectory -ErrorAction 'Stop' Set-PSRepository -Name $script:AWSToolsTempRepoName -InstallationPolicy Trusted } $savedModules = New-Object System.Collections.Generic.HashSet[string] $modulesToInstall = @() Write-Verbose "[$($MyInvocation.MyCommand)] Downloading modules to temporary repository" $saveAWSToolsModuleParams = @{ RequiredVersion = $versionToInstall TemporaryRepoDirectory = $temporaryRepoDirectory SavedModules = $savedModules Proxy = $Proxy ProxyCredential = $ProxyCredential Confirm = $false WhatIf = $false } $Name | ForEach-Object { if (Get-Module $_ -ListAvailable | Where-Object { $_.Version -eq $versionToInstall } ) { Write-Verbose "[$($MyInvocation.MyCommand)] Skipping installation of $_ because already installed" } else { $modulesToInstall += Save-AWSToolsModule -Name $_ @saveAWSToolsModuleParams } } Write-Verbose "[$($MyInvocation.MyCommand)] Installing modules" $installModuleParams = @{ RequiredVersion = $versionToInstall Scope = $Scope Repository = $script:AWSToolsTempRepoName AllowClobber = $AllowClobber Confirm = $false ErrorAction = 'Stop' } $modulesToInstall | ForEach-Object { if (-not $WhatIfPreference) { Write-Host "Installing module $_ version $versionToInstall" Install-Module -Name $_ @installModuleParams } else { Write-Host "What if: Installing module $_ version $versionToInstall" } } Write-Verbose "[$($MyInvocation.MyCommand)] Modules install complete" } finally { if (-not $WhatIfPreference) { Write-Verbose "[$($MyInvocation.MyCommand)] Unregistering temporary repository $script:AWSToolsTempRepoName" Unregister-PSRepository -Name $script:AWSToolsTempRepoName -ErrorAction 'Continue' } Write-Verbose "[$($MyInvocation.MyCommand)] Delete repository folder $temporaryRepoDirectory" Remove-Item -Path $temporaryRepoDirectory -Recurse -WhatIf:$false } } } else { Write-Verbose "[$($MyInvocation.MyCommand)] All modules are up to date" } if ($CleanUp) { Uninstall-AWSToolsModule -ExceptVersion $versionToInstall } } 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)] [System.Version] $RequiredVersion, ## Specifies the maximum version of the modules to update to. [Parameter(ValueFromPipelineByPropertyName)] [System.Version] $MaximumVersion, ## Specifies that, after a successful install, all other versions of the AWS Tools modules should be uninstalled. [Parameter(ValueFromPipelineByPropertyName)] [Switch] $CleanUp, #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" $awsToolsModules = Get-AWSToolsModule -SkipIfInvalidSignature $awsToolsModulesNames = $awsToolsModules | Select-Object -Expand Name | Sort-Object -Unique if ($awsToolsModulesNames) { Write-Verbose "[$($MyInvocation.MyCommand)] Found modules $([System.String]::Join(', ', $awsToolsModulesNames))" if ($RequiredVersion) { $versionToInstall = $RequiredVersion } else { $getAvailableModuleVersionParams = @{ Name = $awsToolsModulesNames MaximumVersion = $MaximumVersion Proxy = $Proxy ProxyCredential = $ProxyCredential } $versionToInstall = Get-AvailableModuleVersion @getAvailableModuleVersionParams Write-Host "Installing AWS Tools version $versionToInstall" } $installAWSToolsModuleParams = @{ Name = $awsToolsModulesNames RequiredVersion = $versionToInstall Scope = $Scope AllowClobber = $AllowClobber CleanUp = $CleanUp Force = $Force SkipUpdate = $true Proxy = $Proxy ProxyCredential = $ProxyCredential } Install-AWSToolsModule @installAWSToolsModuleParams } } End { Write-Verbose "[$($MyInvocation.MyCommand)] End" } } # SIG # Begin signature block # MIIcUAYJKoZIhvcNAQcCoIIcQTCCHD0CAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCAXJWRmmzsKJVJC # S9BpLOEpi7zjo18Q8AGyn/nZlBDXl6CCF0cwggS5MIIDoaADAgECAhArd4OFAE9M # ppHAfzWQwHt/MA0GCSqGSIb3DQEBCwUAMIGEMQswCQYDVQQGEwJVUzEdMBsGA1UE # ChMUU3ltYW50ZWMgQ29ycG9yYXRpb24xHzAdBgNVBAsTFlN5bWFudGVjIFRydXN0 # IE5ldHdvcmsxNTAzBgNVBAMTLFN5bWFudGVjIENsYXNzIDMgU0hBMjU2IENvZGUg # U2lnbmluZyBDQSAtIEcyMB4XDTE3MDcxMDAwMDAwMFoXDTIwMDcxMDIzNTk1OVow # ajELMAkGA1UEBhMCVVMxEzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1Nl # YXR0bGUxGTAXBgNVBAoMEEFtYXpvbi5jb20sIEluYy4xGTAXBgNVBAMMEEFtYXpv # bi5jb20sIEluYy4wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC18TJW # m2/aGpvb+TP2CZMg49X/5bjDAgPxWlAs7bqDyZnRYJork4rLmejpeJu+2BhRjZeK # OirT4XveddBsdL1/TR+FKp8BXEsrm0wcR4yT6mNHJ9yCgC1YBNG91bZ75kRIT+46 # chbC7eNI5703wi8ejxe2KvvOERppBTaFStVJuAHab69dvFma8qE3s7wbqPdQ5eTI # +Xm0bXp8cObS+vj+hf3N2pfDNWM8ITva3kbowGoCW0rKzpf7fBGtBOKnOCCSL0yC # AOwLlFkslemVyrT1/HTDjOTKCro016HxOPddA4cefvr2ZhGlRZQQHg7wMdG7TpZX # ueQ6LoS9UxlzCYHFAgMBAAGjggE+MIIBOjAJBgNVHRMEAjAAMA4GA1UdDwEB/wQE # AwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzBhBgNVHSAEWjBYMFYGBmeBDAEEATBM # MCMGCCsGAQUFBwIBFhdodHRwczovL2Quc3ltY2IuY29tL2NwczAlBggrBgEFBQcC # AjAZDBdodHRwczovL2Quc3ltY2IuY29tL3JwYTAfBgNVHSMEGDAWgBTUwAYiSes5 # S92T4lyhuEd2CXIDWDArBgNVHR8EJDAiMCCgHqAchhpodHRwOi8vcmIuc3ltY2Iu # Y29tL3JiLmNybDBXBggrBgEFBQcBAQRLMEkwHwYIKwYBBQUHMAGGE2h0dHA6Ly9y # Yi5zeW1jZC5jb20wJgYIKwYBBQUHMAKGGmh0dHA6Ly9yYi5zeW1jYi5jb20vcmIu # Y3J0MA0GCSqGSIb3DQEBCwUAA4IBAQC+C4TcK44ph2QQK/1f65jOR23DtSBC3y9a # bzRHdo4qxmcAW5ot69os7GJfzgVsA5lh1IT4+aMuGYA4GTcF6iTSOMgFSRwP8urI # N2BprsWuMJsQ7+Flo3PBRN3dU6idOlFKOfuRxgIHRn47t2yRan6XTNhfiWl84DrD # NjSTnk4c72Gzu0hiwQB9OTsf8CQP3Shb3ZzcAOmeUB01TFoJU34PfJpKlKQZeQIi # W5WdPPr1G/0cAHgejDHtdNYcSqIWfoGeYgCxUg1IFpp1VmPlqb/de8QKONzPDK6/ # 5hulSGqGgpRmEkwGGJiQeOB51GxYZRCPq3hN3UJ6N0A+hYzj7yspMIIFRzCCBC+g # AwIBAgIQfBs1NUrn23TnQV8RacprqDANBgkqhkiG9w0BAQsFADCBvTELMAkGA1UE # BhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2ln # biBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwOCBWZXJpU2lnbiwgSW5j # LiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MTgwNgYDVQQDEy9WZXJpU2lnbiBV # bml2ZXJzYWwgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0xNDA3MjIw # MDAwMDBaFw0yNDA3MjEyMzU5NTlaMIGEMQswCQYDVQQGEwJVUzEdMBsGA1UEChMU # U3ltYW50ZWMgQ29ycG9yYXRpb24xHzAdBgNVBAsTFlN5bWFudGVjIFRydXN0IE5l # dHdvcmsxNTAzBgNVBAMTLFN5bWFudGVjIENsYXNzIDMgU0hBMjU2IENvZGUgU2ln # bmluZyBDQSAtIEcyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA15VD # 1NzfZ645+1KktiYxBHDpt45bKro3aTWVj7vAMOeG2HO73+vRdj+KVo7rLUvwVxhO # sY2lM9MLdSPVankn3aPT9w6HZbXerRzx9TW0IlGvIqHBXUuQf8BZTqudeakC1x5J # sTtNh/7CeKu/71KunK8I2TnlmlE+aV8wEE5xY2xY4fAgMxsPdL5byxLh24zEgJRy # u/ZFmp7BJQv7oxye2KYJcHHswEdMj33D3hnOPu4Eco4X0//wsgUyGUzTsByf/qV4 # IEJwQbAmjG8AyDoAEUF6QbCnipEEoJl49He082Aq5mxQBLcUYP8NUfSoi4T+Idpc # Xn31KXlPsER0b21y/wIDAQABo4IBeDCCAXQwLgYIKwYBBQUHAQEEIjAgMB4GCCsG # AQUFBzABhhJodHRwOi8vcy5zeW1jZC5jb20wEgYDVR0TAQH/BAgwBgEB/wIBADBm # BgNVHSAEXzBdMFsGC2CGSAGG+EUBBxcDMEwwIwYIKwYBBQUHAgEWF2h0dHBzOi8v # ZC5zeW1jYi5jb20vY3BzMCUGCCsGAQUFBwICMBkaF2h0dHBzOi8vZC5zeW1jYi5j # b20vcnBhMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9zLnN5bWNiLmNvbS91bml2 # ZXJzYWwtcm9vdC5jcmwwEwYDVR0lBAwwCgYIKwYBBQUHAwMwDgYDVR0PAQH/BAQD # AgEGMCkGA1UdEQQiMCCkHjAcMRowGAYDVQQDExFTeW1hbnRlY1BLSS0xLTcyNDAd # BgNVHQ4EFgQU1MAGIknrOUvdk+JcobhHdglyA1gwHwYDVR0jBBgwFoAUtnf6aUhH # n1MS1cLqBzJ2B9GXBxkwDQYJKoZIhvcNAQELBQADggEBAH/ryqfqi3ZC6z6OIFQw # 47e53PpIPhbHD0WVEM0nhqNm8wLtcfiqwlWXkXCD+VJ+Umk8yfHglEaAGLuh1KRW # pvMdAJHVhvNIh+DLxDRoIF60y/kF7ZyvcFMnueg+flGgaXGL3FHtgDolMp9Er25D # KNMhdbuX2IuLjP6pBEYEhfcVnEsRjcQsF/7Vbn+a4laS8ZazrS359N/aiZnOsjhE # wPdHe8olufoqaDObUHLeqJ/UzSwLNL2LMHhA4I2OJxuQbxq+CBWBXesv4lHnUR7J # eCnnHmW/OO8BSgEJJA4WxBR5wUE3NNA9kVKUneFo7wjw4mmcZ26QCxqTcdQmAsPA # WiMwggZqMIIFUqADAgECAhADAZoCOv9YsWvW1ermF/BmMA0GCSqGSIb3DQEBBQUA # MGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsT # EHd3dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lDZXJ0IEFzc3VyZWQgSUQg # Q0EtMTAeFw0xNDEwMjIwMDAwMDBaFw0yNDEwMjIwMDAwMDBaMEcxCzAJBgNVBAYT # AlVTMREwDwYDVQQKEwhEaWdpQ2VydDElMCMGA1UEAxMcRGlnaUNlcnQgVGltZXN0 # YW1wIFJlc3BvbmRlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKNk # Xfx8s+CCNeDg9sYq5kl1O8xu4FOpnx9kWeZ8a39rjJ1V+JLjntVaY1sCSVDZg85v # Zu7dy4XpX6X51Id0iEQ7Gcnl9ZGfxhQ5rCTqqEsskYnMXij0ZLZQt/USs3OWCmej # vmGfrvP9Enh1DqZbFP1FI46GRFV9GIYFjFWHeUhG98oOjafeTl/iqLYtWQJhiGFy # GGi5uHzu5uc0LzF3gTAfuzYBje8n4/ea8EwxZI3j6/oZh6h+z+yMDDZbesF6uHjH # yQYuRhDIjegEYNu8c3T6Ttj+qkDxss5wRoPp2kChWTrZFQlXmVYwk/PJYczQCMxr # 7GJCkawCwO+k8IkRj3cCAwEAAaOCAzUwggMxMA4GA1UdDwEB/wQEAwIHgDAMBgNV # HRMBAf8EAjAAMBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMIMIIBvwYDVR0gBIIBtjCC # AbIwggGhBglghkgBhv1sBwEwggGSMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5k # aWdpY2VydC5jb20vQ1BTMIIBZAYIKwYBBQUHAgIwggFWHoIBUgBBAG4AeQAgAHUA # cwBlACAAbwBmACAAdABoAGkAcwAgAEMAZQByAHQAaQBmAGkAYwBhAHQAZQAgAGMA # bwBuAHMAdABpAHQAdQB0AGUAcwAgAGEAYwBjAGUAcAB0AGEAbgBjAGUAIABvAGYA # IAB0AGgAZQAgAEQAaQBnAGkAQwBlAHIAdAAgAEMAUAAvAEMAUABTACAAYQBuAGQA # IAB0AGgAZQAgAFIAZQBsAHkAaQBuAGcAIABQAGEAcgB0AHkAIABBAGcAcgBlAGUA # bQBlAG4AdAAgAHcAaABpAGMAaAAgAGwAaQBtAGkAdAAgAGwAaQBhAGIAaQBsAGkA # dAB5ACAAYQBuAGQAIABhAHIAZQAgAGkAbgBjAG8AcgBwAG8AcgBhAHQAZQBkACAA # aABlAHIAZQBpAG4AIABiAHkAIAByAGUAZgBlAHIAZQBuAGMAZQAuMAsGCWCGSAGG # /WwDFTAfBgNVHSMEGDAWgBQVABIrE5iymQftHt+ivlcNK2cCzTAdBgNVHQ4EFgQU # YVpNJLZJMp1KKnkag0v0HonByn0wfQYDVR0fBHYwdDA4oDagNIYyaHR0cDovL2Ny # bDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEQ0EtMS5jcmwwOKA2oDSG # Mmh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRENBLTEu # Y3JsMHcGCCsGAQUFBwEBBGswaTAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGln # aWNlcnQuY29tMEEGCCsGAQUFBzAChjVodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5j # b20vRGlnaUNlcnRBc3N1cmVkSURDQS0xLmNydDANBgkqhkiG9w0BAQUFAAOCAQEA # nSV+GzNNsiaBXJuGziMgD4CH5Yj//7HUaiwx7ToXGXEXzakbvFoWOQCd42yE5FpA # +94GAYw3+puxnSR+/iCkV61bt5qwYCbqaVchXTQvH3Gwg5QZBWs1kBCge5fH9j/n # 4hFBpr1i2fAnPTgdKG86Ugnw7HBi02JLsOBzppLA044x2C/jbRcTBu7kA7YUq/OP # Q6dxnSHdFMoVXZJB2vkPgdGZdA0mxA5/G7X1oPHGdwYoFenYk+VVFvC7Cqsc21xI # J2bIo4sKHOWV2q7ELlmgYd3a822iYemKC23sEhi991VUQAOSK2vCUcIKSK+w1G7g # 9BQKOhvjjz3Kr2qNe9zYRDCCBs0wggW1oAMCAQICEAb9+QOWA63qAArrPye7uhsw # DQYJKoZIhvcNAQEFBQAwZTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0 # IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTEkMCIGA1UEAxMbRGlnaUNl # cnQgQXNzdXJlZCBJRCBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTIxMTExMDAw # MDAwMFowYjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcG # A1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTEhMB8GA1UEAxMYRGlnaUNlcnQgQXNzdXJl # ZCBJRCBDQS0xMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6IItmfnK # wkKVpYBzQHDSnlZUXKnE0kEGj8kz/E1FkVyBn+0snPgWWd+etSQVwpi5tHdJ3InE # Ctqvy15r7a2wcTHrzzpADEZNk+yLejYIA6sMNP4YSYL+x8cxSIB8HqIPkg5QycaH # 6zY/2DDD/6b3+6LNb3Mj/qxWBZDwMiEWicZwiPkFl32jx0PdAug7Pe2xQaPtP77b # lUjE7h6z8rwMK5nQxl0SQoHhg26Ccz8mSxSQrllmCsSNvtLOBq6thG9IhJtPQLnx # TPKvmPv2zkBdXPao8S+v7Iki8msYZbHBc63X8djPHgp0XEK4aH631XcKJ1Z8D2Kk # PzIUYJX9BwSiCQIDAQABo4IDejCCA3YwDgYDVR0PAQH/BAQDAgGGMDsGA1UdJQQ0 # MDIGCCsGAQUFBwMBBggrBgEFBQcDAgYIKwYBBQUHAwMGCCsGAQUFBwMEBggrBgEF # BQcDCDCCAdIGA1UdIASCAckwggHFMIIBtAYKYIZIAYb9bAABBDCCAaQwOgYIKwYB # BQUHAgEWLmh0dHA6Ly93d3cuZGlnaWNlcnQuY29tL3NzbC1jcHMtcmVwb3NpdG9y # eS5odG0wggFkBggrBgEFBQcCAjCCAVYeggFSAEEAbgB5ACAAdQBzAGUAIABvAGYA # IAB0AGgAaQBzACAAQwBlAHIAdABpAGYAaQBjAGEAdABlACAAYwBvAG4AcwB0AGkA # dAB1AHQAZQBzACAAYQBjAGMAZQBwAHQAYQBuAGMAZQAgAG8AZgAgAHQAaABlACAA # RABpAGcAaQBDAGUAcgB0ACAAQwBQAC8AQwBQAFMAIABhAG4AZAAgAHQAaABlACAA # UgBlAGwAeQBpAG4AZwAgAFAAYQByAHQAeQAgAEEAZwByAGUAZQBtAGUAbgB0ACAA # dwBoAGkAYwBoACAAbABpAG0AaQB0ACAAbABpAGEAYgBpAGwAaQB0AHkAIABhAG4A # ZAAgAGEAcgBlACAAaQBuAGMAbwByAHAAbwByAGEAdABlAGQAIABoAGUAcgBlAGkA # bgAgAGIAeQAgAHIAZQBmAGUAcgBlAG4AYwBlAC4wCwYJYIZIAYb9bAMVMBIGA1Ud # EwEB/wQIMAYBAf8CAQAweQYIKwYBBQUHAQEEbTBrMCQGCCsGAQUFBzABhhhodHRw # Oi8vb2NzcC5kaWdpY2VydC5jb20wQwYIKwYBBQUHMAKGN2h0dHA6Ly9jYWNlcnRz # LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcnQwgYEGA1Ud # HwR6MHgwOqA4oDaGNGh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFz # c3VyZWRJRFJvb3RDQS5jcmwwOqA4oDaGNGh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNv # bS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcmwwHQYDVR0OBBYEFBUAEisTmLKZ # B+0e36K+Vw0rZwLNMB8GA1UdIwQYMBaAFEXroq/0ksuCMS1Ri6enIZ3zbcgPMA0G # CSqGSIb3DQEBBQUAA4IBAQBGUD7Jtygkpzgdtlspr1LPUukxR6tWXHvVDQtBs+/s # dR90OPKyXGGinJXDUOSCuSPRujqGcq04eKx1XRcXNHJHhZRW0eu7NoR3zCSl8wQZ # Vann4+erYs37iy2QwsDStZS9Xk+xBdIOPRqpFFumhjFiqKgz5Js5p8T1zh14dpQl # c+Qqq8+cdkvtX8JLFuRLcEwAiR78xXm8TBJX/l/hHrwCXaj++wc4Tw3GXZG5D2dF # zdaD7eeSDY2xaYxP+1ngIw/Sqq4AfO6cQg7PkdcntxbuD8O9fAqg7iwIVYUiuOsY # Gk38KiGtSTGDR5V3cdyxG0tLHBCcdxTBnU8vWpUIKRAmMYIEXzCCBFsCAQEwgZkw # gYQxCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRTeW1hbnRlYyBDb3Jwb3JhdGlvbjEf # MB0GA1UECxMWU3ltYW50ZWMgVHJ1c3QgTmV0d29yazE1MDMGA1UEAxMsU3ltYW50 # ZWMgQ2xhc3MgMyBTSEEyNTYgQ29kZSBTaWduaW5nIENBIC0gRzICECt3g4UAT0ym # kcB/NZDAe38wDQYJYIZIAWUDBAIBBQCggYQwGAYKKwYBBAGCNwIBDDEKMAigAoAA # oQKAADAZBgkqhkiG9w0BCQMxDAYKKwYBBAGCNwIBBDAcBgorBgEEAYI3AgELMQ4w # DAYKKwYBBAGCNwIBFTAvBgkqhkiG9w0BCQQxIgQgNClPJSP+CdtlkkRccUT9c1iP # ykogQGP8wepAQ6h7Fc0wDQYJKoZIhvcNAQEBBQAEggEAsYRD3LzMTXlgZAMVlAdY # gtL4ItINweigW/tM/RnPiObzShtPUUBEvgHhIISGSl/gtBidRmDGsTxDuN1cQlm5 # WaoRwgv/8uB71Gs5eMbYSfMNvWzgAunEDPdiK2+Fxx1kE0gkd0V+6VHl7mbCoCHe # p6VZ8MqYbZoN+CT6SbH3mc+J8Gju/eKwYGeuLJtnl1VjwTAg6igHGzYcGMjiLm8r # GFacOWoYfhUpZ0hM+VQF8RHhjBZOC8ERK0/vAR+Lmqwev/yrxbNvTfA/Q/OlpoYC # nBe/8+bSW1fQiBjtG7n3b0tlLR2f16M16z0LiTf4l9EA7clnjIWSqQoS89axCigh # xKGCAg8wggILBgkqhkiG9w0BCQYxggH8MIIB+AIBATB2MGIxCzAJBgNVBAYTAlVT # MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j # b20xITAfBgNVBAMTGERpZ2lDZXJ0IEFzc3VyZWQgSUQgQ0EtMQIQAwGaAjr/WLFr # 1tXq5hfwZjAJBgUrDgMCGgUAoF0wGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAc # BgkqhkiG9w0BCQUxDxcNMTkxMTI1MDcwOTI5WjAjBgkqhkiG9w0BCQQxFgQUeZvM # K9xz+Ns6nc6g4aUcgj5t544wDQYJKoZIhvcNAQEBBQAEggEAoTD6Jv0J35dQigcZ # 1Q5DPm04BUv23A3MUUxpT7PyUxRBP5hc1HXr8c/r0WjXLu8ck6JGRdn9zuZBGaW+ # s5QM9HiWYM/1/WfJCAkaI+3pJ9rWYOQoNuc794SIPXK4IbxH4mS6vD4+/LQjeUoq # vu7EIQd/PfHAifxJLUNUKUvzrg+PUZJOftZKR3NkAD+7w6VbxenLjlvvOLcXGp15 # QpLSx9WRkr4aBgejC5zzBPT+uGiu00RMckAvdD+V/3Ix6Y7DIx5CL3FWwFlslPHo # ex/Bi5eAg5inY94WMJEFkmByG8/2nA7BwYr5K5lrNZMPtzTD2mu9beEPrEiOqaDL # oBWCUQ== # SIG # End signature block |