| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866 |
- #
- # Add-AppxDevPackage.ps1 is a PowerShell script designed to install app
- # packages created by Visual Studio for developers. To run this script from
- # Explorer, right-click on its icon and choose "Run with PowerShell".
- #
- # Visual Studio supplies this script in the folder generated with its
- # "Prepare Package" command. The same folder will also contain the app
- # package (a .appx file), the signing certificate (a .cer file), and a
- # "Dependencies" subfolder containing all the framework packages used by the
- # app.
- #
- # This script simplifies installing these packages by automating the
- # following functions:
- # 1. Find the app package and signing certificate in the script directory
- # 2. Prompt the user to acquire a developer license and to install the
- # certificate if necessary
- # 3. Find dependency packages that are applicable to the operating system's
- # CPU architecture
- # 4. Install the package along with all applicable dependencies
- #
- # All command line parameters are reserved for use internally by the script.
- # Users should launch this script from Explorer.
- #
-
- # .Link
- # http://go.microsoft.com/fwlink/?LinkId=243053
-
- param(
- [switch]$Force = $false,
- [switch]$GetDeveloperLicense = $false,
- [switch]$SkipLoggingTelemetry = $false,
- [string]$CertificatePath = $null
- )
-
- $ErrorActionPreference = "Stop"
-
- # The language resources for this script are placed in the
- # "Add-AppDevPackage.resources" subfolder alongside the script. Since the
- # current working directory might not be the directory that contains the
- # script, we need to create the full path of the resources directory to
- # pass into Import-LocalizedData
- $ScriptPath = $null
- try
- {
- $ScriptPath = (Get-Variable MyInvocation).Value.MyCommand.Path
- $ScriptDir = Split-Path -Parent $ScriptPath
- }
- catch {}
-
- if (!$ScriptPath)
- {
- PrintMessageAndExit $UiStrings.ErrorNoScriptPath $ErrorCodes.NoScriptPath
- }
-
- $LocalizedResourcePath = Join-Path $ScriptDir "Add-AppDevPackage.resources"
- Import-LocalizedData -BindingVariable UiStrings -BaseDirectory $LocalizedResourcePath
-
- $ErrorCodes = Data {
- ConvertFrom-StringData @'
- Success = 0
- NoScriptPath = 1
- NoPackageFound = 2
- ManyPackagesFound = 3
- NoCertificateFound = 4
- ManyCertificatesFound = 5
- BadCertificate = 6
- PackageUnsigned = 7
- CertificateMismatch = 8
- ForceElevate = 9
- LaunchAdminFailed = 10
- GetDeveloperLicenseFailed = 11
- InstallCertificateFailed = 12
- AddPackageFailed = 13
- ForceDeveloperLicense = 14
- CertUtilInstallFailed = 17
- CertIsCA = 18
- BannedEKU = 19
- NoBasicConstraints = 20
- NoCodeSigningEku = 21
- InstallCertificateCancelled = 22
- BannedKeyUsage = 23
- ExpiredCertificate = 24
- '@
- }
-
- $IMAGE_FILE_MACHINE_i386 = 0x014c
- $IMAGE_FILE_MACHINE_AMD64 = 0x8664
- $IMAGE_FILE_MACHINE_ARM64 = 0xAA64
- $IMAGE_FILE_MACHINE_ARM = 0x01c0
- $IMAGE_FILE_MACHINE_THUMB = 0x01c2
- $IMAGE_FILE_MACHINE_ARMNT = 0x01c4
-
- # First try to use IsWow64Process2 to determine the OS architecture
- try
- {
- $IsWow64Process2_MethodDefinition = @"
- [DllImport("kernel32.dll", SetLastError = true)]
- public static extern bool IsWow64Process2(IntPtr process, out ushort processMachine, out ushort nativeMachine);
- "@
-
- $Kernel32 = Add-Type -MemberDefinition $IsWow64Process2_MethodDefinition -Name "Kernel32" -Namespace "Win32" -PassThru
-
- $Proc = Get-Process -id $pid
- $processMachine = New-Object uint16
- $nativeMachine = New-Object uint16
-
- $Res = $Kernel32::IsWow64Process2($Proc.Handle, [ref] $processMachine, [ref] $nativeMachine)
- if ($Res -eq $True)
- {
- switch ($nativeMachine)
- {
- $IMAGE_FILE_MACHINE_i386 { $ProcessorArchitecture = "x86" }
- $IMAGE_FILE_MACHINE_AMD64 { $ProcessorArchitecture = "amd64" }
- $IMAGE_FILE_MACHINE_ARM64 { $ProcessorArchitecture = "arm64" }
- $IMAGE_FILE_MACHINE_ARM { $ProcessorArchitecture = "arm" }
- $IMAGE_FILE_MACHINE_THUMB { $ProcessorArchitecture = "arm" }
- $IMAGE_FILE_MACHINE_ARMNT { $ProcessorArchitecture = "arm" }
- }
- }
- }
- catch
- {
- # Ignore exception and fall back to using environment variables to determine the OS architecture
- }
-
- if ($null -eq $ProcessorArchitecture)
- {
- $ProcessorArchitecture = $Env:Processor_Architecture
-
- # Getting $Env:Processor_Architecture on arm64 machines will return x86. So check if the environment
- # variable "ProgramFiles(Arm)" is also set, if it is we know the actual processor architecture is arm64.
- # The value will also be x86 on amd64 machines when running the x86 version of PowerShell.
- if ($ProcessorArchitecture -eq "x86")
- {
- if ($null -ne ${Env:ProgramFiles(Arm)})
- {
- $ProcessorArchitecture = "arm64"
- }
- elseif ($null -ne ${Env:ProgramFiles(x86)})
- {
- $ProcessorArchitecture = "amd64"
- }
- }
- }
-
- function PrintMessageAndExit($ErrorMessage, $ReturnCode)
- {
- Write-Host $ErrorMessage
- try
- {
- # Log telemetry data regarding the use of the script if possible.
- # There are three ways that this can be disabled:
- # 1. If the "TelemetryDependencies" folder isn't present. This can be excluded at build time by setting the MSBuild property AppxLogTelemetryFromSideloadingScript to false
- # 2. If the SkipLoggingTelemetry switch is passed to this script.
- # 3. If Visual Studio telemetry is disabled via the registry.
- $TelemetryAssembliesFolder = (Join-Path $PSScriptRoot "TelemetryDependencies")
- if (!$SkipLoggingTelemetry -And (Test-Path $TelemetryAssembliesFolder))
- {
- $job = Start-Job -FilePath (Join-Path $TelemetryAssembliesFolder "LogSideloadingTelemetry.ps1") -ArgumentList $TelemetryAssembliesFolder, "VS/DesignTools/SideLoadingScript/AddAppDevPackage", $ReturnCode, $ProcessorArchitecture
- Wait-Job -Job $job -Timeout 60 | Out-Null
- }
- }
- catch
- {
- # Ignore telemetry errors
- }
-
- if (!$Force)
- {
- Pause
- }
-
- exit $ReturnCode
- }
-
- #
- # Warns the user about installing certificates, and presents a Yes/No prompt
- # to confirm the action. The default is set to No.
- #
- function ConfirmCertificateInstall
- {
- $Answer = $host.UI.PromptForChoice(
- "",
- $UiStrings.WarningInstallCert,
- [System.Management.Automation.Host.ChoiceDescription[]]@($UiStrings.PromptYesString, $UiStrings.PromptNoString),
- 1)
-
- return $Answer -eq 0
- }
-
- #
- # Validates whether a file is a valid certificate using CertUtil.
- # This needs to be done before calling Get-PfxCertificate on the file, otherwise
- # the user will get a cryptic "Password: " prompt for invalid certs.
- #
- function ValidateCertificateFormat($FilePath)
- {
- # certutil -verify prints a lot of text that we don't need, so it's redirected to $null here
- certutil.exe -verify $FilePath > $null
- if ($LastExitCode -lt 0)
- {
- PrintMessageAndExit ($UiStrings.ErrorBadCertificate -f $FilePath, $LastExitCode) $ErrorCodes.BadCertificate
- }
-
- # Check if certificate is expired
- $cert = Get-PfxCertificate $FilePath
- if (($cert.NotBefore -gt (Get-Date)) -or ($cert.NotAfter -lt (Get-Date)))
- {
- PrintMessageAndExit ($UiStrings.ErrorExpiredCertificate -f $FilePath) $ErrorCodes.ExpiredCertificate
- }
- }
-
- #
- # Verify that the developer certificate meets the following restrictions:
- # - The certificate must contain a Basic Constraints extension, and its
- # Certificate Authority (CA) property must be false.
- # - The certificate's Key Usage extension must be either absent, or set to
- # only DigitalSignature.
- # - The certificate must contain an Extended Key Usage (EKU) extension with
- # Code Signing usage.
- # - The certificate must NOT contain any other EKU except Code Signing and
- # Lifetime Signing.
- #
- # These restrictions are enforced to decrease security risks that arise from
- # trusting digital certificates.
- #
- function CheckCertificateRestrictions
- {
- Set-Variable -Name BasicConstraintsExtensionOid -Value "2.5.29.19" -Option Constant
- Set-Variable -Name KeyUsageExtensionOid -Value "2.5.29.15" -Option Constant
- Set-Variable -Name EkuExtensionOid -Value "2.5.29.37" -Option Constant
- Set-Variable -Name CodeSigningEkuOid -Value "1.3.6.1.5.5.7.3.3" -Option Constant
- Set-Variable -Name LifetimeSigningEkuOid -Value "1.3.6.1.4.1.311.10.3.13" -Option Constant
- Set-Variable -Name UwpSigningEkuOid -Value "1.3.6.1.4.1.311.84.3.1" -Option Constant
- Set-Variable -Name DisposableSigningEkuOid -Value "1.3.6.1.4.1.311.84.3.2" -Option Constant
-
- $CertificateExtensions = (Get-PfxCertificate $CertificatePath).Extensions
- $HasBasicConstraints = $false
- $HasCodeSigningEku = $false
-
- foreach ($Extension in $CertificateExtensions)
- {
- # Certificate must contain the Basic Constraints extension
- if ($Extension.oid.value -eq $BasicConstraintsExtensionOid)
- {
- # CA property must be false
- if ($Extension.CertificateAuthority)
- {
- PrintMessageAndExit $UiStrings.ErrorCertIsCA $ErrorCodes.CertIsCA
- }
- $HasBasicConstraints = $true
- }
-
- # If key usage is present, it must be set to digital signature
- elseif ($Extension.oid.value -eq $KeyUsageExtensionOid)
- {
- if ($Extension.KeyUsages -ne "DigitalSignature")
- {
- PrintMessageAndExit ($UiStrings.ErrorBannedKeyUsage -f $Extension.KeyUsages) $ErrorCodes.BannedKeyUsage
- }
- }
-
- elseif ($Extension.oid.value -eq $EkuExtensionOid)
- {
- # Certificate must contain the Code Signing EKU
- $EKUs = $Extension.EnhancedKeyUsages.Value
- if ($EKUs -contains $CodeSigningEkuOid)
- {
- $HasCodeSigningEKU = $True
- }
-
- # EKUs other than code signing and lifetime signing are not allowed
- foreach ($EKU in $EKUs)
- {
- if ($EKU -ne $CodeSigningEkuOid -and $EKU -ne $LifetimeSigningEkuOid -and $EKU -ne $UwpSigningEkuOid -and $EKU -ne $DisposableSigningEkuOid)
- {
- PrintMessageAndExit ($UiStrings.ErrorBannedEKU -f $EKU) $ErrorCodes.BannedEKU
- }
- }
- }
- }
-
- if (!$HasBasicConstraints)
- {
- PrintMessageAndExit $UiStrings.ErrorNoBasicConstraints $ErrorCodes.NoBasicConstraints
- }
- if (!$HasCodeSigningEKU)
- {
- PrintMessageAndExit $UiStrings.ErrorNoCodeSigningEku $ErrorCodes.NoCodeSigningEku
- }
- }
-
- #
- # Performs operations that require administrative privileges:
- # - Prompt the user to obtain a developer license
- # - Install the developer certificate (if -Force is not specified, also prompts the user to confirm)
- #
- function DoElevatedOperations
- {
- if ($GetDeveloperLicense)
- {
- Write-Host $UiStrings.GettingDeveloperLicense
-
- if ($Force)
- {
- PrintMessageAndExit $UiStrings.ErrorForceDeveloperLicense $ErrorCodes.ForceDeveloperLicense
- }
- try
- {
- Show-WindowsDeveloperLicenseRegistration
- }
- catch
- {
- $Error[0] # Dump details about the last error
- PrintMessageAndExit $UiStrings.ErrorGetDeveloperLicenseFailed $ErrorCodes.GetDeveloperLicenseFailed
- }
- }
-
- if ($CertificatePath)
- {
- Write-Host $UiStrings.InstallingCertificate
-
- # Make sure certificate format is valid and usage constraints are followed
- ValidateCertificateFormat $CertificatePath
- CheckCertificateRestrictions
-
- # If -Force is not specified, warn the user and get consent
- if ($Force -or (ConfirmCertificateInstall))
- {
- # Add cert to store
- certutil.exe -addstore TrustedPeople $CertificatePath
- if ($LastExitCode -lt 0)
- {
- PrintMessageAndExit ($UiStrings.ErrorCertUtilInstallFailed -f $LastExitCode) $ErrorCodes.CertUtilInstallFailed
- }
- }
- else
- {
- PrintMessageAndExit $UiStrings.ErrorInstallCertificateCancelled $ErrorCodes.InstallCertificateCancelled
- }
- }
- }
-
- #
- # Checks whether the machine is missing a valid developer license.
- #
- function CheckIfNeedDeveloperLicense
- {
- $Result = $true
- try
- {
- $Result = (Get-WindowsDeveloperLicense | Where-Object { $_.IsValid } | Measure-Object).Count -eq 0
- }
- catch {}
-
- return $Result
- }
-
- #
- # Launches an elevated process running the current script to perform tasks
- # that require administrative privileges. This function waits until the
- # elevated process terminates, and checks whether those tasks were successful.
- #
- function LaunchElevated
- {
- # Set up command line arguments to the elevated process
- $RelaunchArgs = '-ExecutionPolicy Unrestricted -file "' + $ScriptPath + '"'
-
- if ($Force)
- {
- $RelaunchArgs += ' -Force'
- }
- if ($NeedDeveloperLicense)
- {
- $RelaunchArgs += ' -GetDeveloperLicense'
- }
- if ($SkipLoggingTelemetry)
- {
- $RelaunchArgs += ' -SkipLoggingTelemetry'
- }
- if ($NeedInstallCertificate)
- {
- $RelaunchArgs += ' -CertificatePath "' + $DeveloperCertificatePath.FullName + '"'
- }
-
- # Launch the process and wait for it to finish
- try
- {
- $PowerShellExePath = (Get-Process -Id $PID).Path
- $AdminProcess = Start-Process $PowerShellExePath -Verb RunAs -ArgumentList $RelaunchArgs -PassThru
- }
- catch
- {
- $Error[0] # Dump details about the last error
- PrintMessageAndExit $UiStrings.ErrorLaunchAdminFailed $ErrorCodes.LaunchAdminFailed
- }
-
- while (!($AdminProcess.HasExited))
- {
- Start-Sleep -Seconds 2
- }
-
- # Check if all elevated operations were successful
- if ($NeedDeveloperLicense)
- {
- if (CheckIfNeedDeveloperLicense)
- {
- PrintMessageAndExit $UiStrings.ErrorGetDeveloperLicenseFailed $ErrorCodes.GetDeveloperLicenseFailed
- }
- else
- {
- Write-Host $UiStrings.AcquireLicenseSuccessful
- }
- }
- if ($NeedInstallCertificate)
- {
- $Signature = Get-AuthenticodeSignature $DeveloperPackagePath -Verbose
- if ($Signature.Status -ne "Valid")
- {
- PrintMessageAndExit ($UiStrings.ErrorInstallCertificateFailed -f $Signature.Status) $ErrorCodes.InstallCertificateFailed
- }
- else
- {
- Write-Host $UiStrings.InstallCertificateSuccessful
- }
- }
- }
-
- #
- # Finds all applicable dependency packages according to OS architecture, and
- # installs the developer package with its dependencies. The expected layout
- # of dependencies is:
- #
- # <current dir>
- # \Dependencies
- # <Architecture neutral dependencies>.appx\.msix
- # \x86
- # <x86 dependencies>.appx\.msix
- # \x64
- # <x64 dependencies>.appx\.msix
- # \arm
- # <arm dependencies>.appx\.msix
- # \arm64
- # <arm64 dependencies>.appx\.msix
- #
- function InstallPackageWithDependencies
- {
- $DependencyPackagesDir = (Join-Path $ScriptDir "Dependencies")
- $DependencyPackages = @()
- if (Test-Path $DependencyPackagesDir)
- {
- # Get architecture-neutral dependencies
- $DependencyPackages += Get-ChildItem (Join-Path $DependencyPackagesDir "*.appx") | Where-Object { $_.Mode -NotMatch "d" }
- $DependencyPackages += Get-ChildItem (Join-Path $DependencyPackagesDir "*.msix") | Where-Object { $_.Mode -NotMatch "d" }
-
- # Get architecture-specific dependencies
- if (($ProcessorArchitecture -eq "x86" -or $ProcessorArchitecture -eq "amd64" -or $ProcessorArchitecture -eq "arm64") -and (Test-Path (Join-Path $DependencyPackagesDir "x86")))
- {
- $DependencyPackages += Get-ChildItem (Join-Path $DependencyPackagesDir "x86\*.appx") | Where-Object { $_.Mode -NotMatch "d" }
- $DependencyPackages += Get-ChildItem (Join-Path $DependencyPackagesDir "x86\*.msix") | Where-Object { $_.Mode -NotMatch "d" }
- }
- if (($ProcessorArchitecture -eq "amd64") -and (Test-Path (Join-Path $DependencyPackagesDir "x64")))
- {
- $DependencyPackages += Get-ChildItem (Join-Path $DependencyPackagesDir "x64\*.appx") | Where-Object { $_.Mode -NotMatch "d" }
- $DependencyPackages += Get-ChildItem (Join-Path $DependencyPackagesDir "x64\*.msix") | Where-Object { $_.Mode -NotMatch "d" }
- }
- if (($ProcessorArchitecture -eq "arm" -or $ProcessorArchitecture -eq "arm64") -and (Test-Path (Join-Path $DependencyPackagesDir "arm")))
- {
- $DependencyPackages += Get-ChildItem (Join-Path $DependencyPackagesDir "arm\*.appx") | Where-Object { $_.Mode -NotMatch "d" }
- $DependencyPackages += Get-ChildItem (Join-Path $DependencyPackagesDir "arm\*.msix") | Where-Object { $_.Mode -NotMatch "d" }
- }
- if (($ProcessorArchitecture -eq "arm64") -and (Test-Path (Join-Path $DependencyPackagesDir "arm64")))
- {
- $DependencyPackages += Get-ChildItem (Join-Path $DependencyPackagesDir "arm64\*.appx") | Where-Object { $_.Mode -NotMatch "d" }
- $DependencyPackages += Get-ChildItem (Join-Path $DependencyPackagesDir "arm64\*.msix") | Where-Object { $_.Mode -NotMatch "d" }
- }
- }
- Write-Host $UiStrings.InstallingPackage
-
- $AddPackageSucceeded = $False
- try
- {
- if ($DependencyPackages.FullName.Count -gt 0)
- {
- Write-Host $UiStrings.DependenciesFound
- $DependencyPackages.FullName
- Add-AppxPackage -Path $DeveloperPackagePath.FullName -DependencyPath $DependencyPackages.FullName -ForceApplicationShutdown
- }
- else
- {
- Add-AppxPackage -Path $DeveloperPackagePath.FullName -ForceApplicationShutdown
- }
- $AddPackageSucceeded = $?
- }
- catch
- {
- $Error[0] # Dump details about the last error
- }
-
- if (!$AddPackageSucceeded)
- {
- if ($NeedInstallCertificate)
- {
- PrintMessageAndExit $UiStrings.ErrorAddPackageFailedWithCert $ErrorCodes.AddPackageFailed
- }
- else
- {
- PrintMessageAndExit $UiStrings.ErrorAddPackageFailed $ErrorCodes.AddPackageFailed
- }
- }
- }
-
- #
- # Main script logic when the user launches the script without parameters.
- #
- function DoStandardOperations
- {
- # Check for an .appx or .msix file in the script directory
- $PackagePath = Get-ChildItem (Join-Path $ScriptDir "*.appx") | Where-Object { $_.Mode -NotMatch "d" }
- if ($PackagePath -eq $null)
- {
- $PackagePath = Get-ChildItem (Join-Path $ScriptDir "*.msix") | Where-Object { $_.Mode -NotMatch "d" }
- }
- $PackageCount = ($PackagePath | Measure-Object).Count
-
- # Check for an .appxbundle or .msixbundle file in the script directory
- $BundlePath = Get-ChildItem (Join-Path $ScriptDir "*.appxbundle") | Where-Object { $_.Mode -NotMatch "d" }
- if ($BundlePath -eq $null)
- {
- $BundlePath = Get-ChildItem (Join-Path $ScriptDir "*.msixbundle") | Where-Object { $_.Mode -NotMatch "d" }
- }
- $BundleCount = ($BundlePath | Measure-Object).Count
-
- # Check for an .eappx or .emsix file in the script directory
- $EncryptedPackagePath = Get-ChildItem (Join-Path $ScriptDir "*.eappx") | Where-Object { $_.Mode -NotMatch "d" }
- if ($EncryptedPackagePath -eq $null)
- {
- $EncryptedPackagePath = Get-ChildItem (Join-Path $ScriptDir "*.emsix") | Where-Object { $_.Mode -NotMatch "d" }
- }
- $EncryptedPackageCount = ($EncryptedPackagePath | Measure-Object).Count
-
- # Check for an .eappxbundle or .emsixbundle file in the script directory
- $EncryptedBundlePath = Get-ChildItem (Join-Path $ScriptDir "*.eappxbundle") | Where-Object { $_.Mode -NotMatch "d" }
- if ($EncryptedBundlePath -eq $null)
- {
- $EncryptedBundlePath = Get-ChildItem (Join-Path $ScriptDir "*.emsixbundle") | Where-Object { $_.Mode -NotMatch "d" }
- }
- $EncryptedBundleCount = ($EncryptedBundlePath | Measure-Object).Count
-
- $NumberOfPackages = $PackageCount + $EncryptedPackageCount
- $NumberOfBundles = $BundleCount + $EncryptedBundleCount
-
- # There must be at least one package or bundle
- if ($NumberOfPackages + $NumberOfBundles -lt 1)
- {
- PrintMessageAndExit $UiStrings.ErrorNoPackageFound $ErrorCodes.NoPackageFound
- }
- # We must have exactly one bundle OR no bundle and exactly one package
- elseif ($NumberOfBundles -gt 1 -or
- ($NumberOfBundles -eq 0 -and $NumberOfpackages -gt 1))
- {
- PrintMessageAndExit $UiStrings.ErrorManyPackagesFound $ErrorCodes.ManyPackagesFound
- }
-
- # First attempt to install a bundle or encrypted bundle. If neither exists, fall back to packages and then encrypted packages
- if ($BundleCount -eq 1)
- {
- $DeveloperPackagePath = $BundlePath
- Write-Host ($UiStrings.BundleFound -f $DeveloperPackagePath.FullName)
- }
- elseif ($EncryptedBundleCount -eq 1)
- {
- $DeveloperPackagePath = $EncryptedBundlePath
- Write-Host ($UiStrings.EncryptedBundleFound -f $DeveloperPackagePath.FullName)
- }
- elseif ($PackageCount -eq 1)
- {
- $DeveloperPackagePath = $PackagePath
- Write-Host ($UiStrings.PackageFound -f $DeveloperPackagePath.FullName)
- }
- elseif ($EncryptedPackageCount -eq 1)
- {
- $DeveloperPackagePath = $EncryptedPackagePath
- Write-Host ($UiStrings.EncryptedPackageFound -f $DeveloperPackagePath.FullName)
- }
-
- # The package must be signed
- $PackageSignature = Get-AuthenticodeSignature $DeveloperPackagePath
- $PackageCertificate = $PackageSignature.SignerCertificate
- if (!$PackageCertificate)
- {
- PrintMessageAndExit $UiStrings.ErrorPackageUnsigned $ErrorCodes.PackageUnsigned
- }
-
- # Test if the package signature is trusted. If not, the corresponding certificate
- # needs to be present in the current directory and needs to be installed.
- $NeedInstallCertificate = ($PackageSignature.Status -ne "Valid")
-
- if ($NeedInstallCertificate)
- {
- # List all .cer files in the script directory
- $DeveloperCertificatePath = Get-ChildItem (Join-Path $ScriptDir "*.cer") | Where-Object { $_.Mode -NotMatch "d" }
- $DeveloperCertificateCount = ($DeveloperCertificatePath | Measure-Object).Count
-
- # There must be exactly 1 certificate
- if ($DeveloperCertificateCount -lt 1)
- {
- PrintMessageAndExit $UiStrings.ErrorNoCertificateFound $ErrorCodes.NoCertificateFound
- }
- elseif ($DeveloperCertificateCount -gt 1)
- {
- PrintMessageAndExit $UiStrings.ErrorManyCertificatesFound $ErrorCodes.ManyCertificatesFound
- }
-
- Write-Host ($UiStrings.CertificateFound -f $DeveloperCertificatePath.FullName)
-
- # The .cer file must have the format of a valid certificate
- ValidateCertificateFormat $DeveloperCertificatePath
-
- # The package signature must match the certificate file
- if ($PackageCertificate -ne (Get-PfxCertificate $DeveloperCertificatePath))
- {
- PrintMessageAndExit $UiStrings.ErrorCertificateMismatch $ErrorCodes.CertificateMismatch
- }
- }
-
- $NeedDeveloperLicense = CheckIfNeedDeveloperLicense
-
- # Relaunch the script elevated with the necessary parameters if needed
- if ($NeedDeveloperLicense -or $NeedInstallCertificate)
- {
- Write-Host $UiStrings.ElevateActions
- if ($NeedDeveloperLicense)
- {
- Write-Host $UiStrings.ElevateActionDevLicense
- }
- if ($NeedInstallCertificate)
- {
- Write-Host $UiStrings.ElevateActionCertificate
- }
-
- $IsAlreadyElevated = ([Security.Principal.WindowsIdentity]::GetCurrent().Groups.Value -contains "S-1-5-32-544")
- if ($IsAlreadyElevated)
- {
- if ($Force -and $NeedDeveloperLicense)
- {
- PrintMessageAndExit $UiStrings.ErrorForceDeveloperLicense $ErrorCodes.ForceDeveloperLicense
- }
- if ($Force -and $NeedInstallCertificate)
- {
- Write-Warning $UiStrings.WarningInstallCert
- }
- }
- else
- {
- if ($Force)
- {
- PrintMessageAndExit $UiStrings.ErrorForceElevate $ErrorCodes.ForceElevate
- }
- else
- {
- Write-Host $UiStrings.ElevateActionsContinue
- Pause
- }
- }
-
- LaunchElevated
- }
-
- InstallPackageWithDependencies
- }
-
- #
- # Main script entry point
- #
- if ($GetDeveloperLicense -or $CertificatePath)
- {
- DoElevatedOperations
- }
- else
- {
- DoStandardOperations
- PrintMessageAndExit $UiStrings.Success $ErrorCodes.Success
- }
-
- # SIG # Begin signature block
- # MIIhdwYJKoZIhvcNAQcCoIIhaDCCIWQCAQExDzANBglghkgBZQMEAgEFADB5Bgor
- # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
- # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCAaovVnr86uRLc7
- # aU4MWMaEBdFBUDgUiMNw07NprqcvsqCCC3IwggT6MIID4qADAgECAhMzAAAD3o1W
- # glrxpKlnAAAAAAPeMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD
- # VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
- # b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p
- # bmcgUENBIDIwMTAwHhcNMjAxMjE1MjEyNDIwWhcNMjExMjAyMjEyNDIwWjB0MQsw
- # CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u
- # ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy
- # b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
- # AQCn8/DiSdIkSLNe/aikoxkWIAtCq9W+7+dbEXN/cZ4ZkeX/mn8MPRJVyt7FaE3k
- # bFofDl4GH5xZOQoOUhGh8mfq3sUq9RDZ6T1vFanVTeRq3iamvmjYHVgYq1MW9RdY
- # 1UaGH7OE2L0coGjp46azVnYJlj7I1BWMZXxYRSxGQttNi9g1lwXCGfGl+aTqWSfy
- # hRpMB/mpVC4IF8MYsHVYctYb1ex+3ZwDSmwsX/Y4sxtSpt18xX9Rso2fES8GGnQK
- # dBnMMdySgdp0E4ACWpa0iQDTBQMQVSTfrVFjyetviHoMejI+SgbkiPrEezGGvTiG
- # Ooc6+eWSEwYMy9sxw0GaCiVvAgMBAAGjggF5MIIBdTAfBgNVHSUEGDAWBgorBgEE
- # AYI3PQYBBggrBgEFBQcDAzAdBgNVHQ4EFgQUJOo70fFaruzlxG7u+R2Hd9N1TIkw
- # UAYDVR0RBEkwR6RFMEMxKTAnBgNVBAsTIE1pY3Jvc29mdCBPcGVyYXRpb25zIFB1
- # ZXJ0byBSaWNvMRYwFAYDVQQFEw0yMzA4NjUrNDYzMTMzMB8GA1UdIwQYMBaAFOb8
- # X3u7IgBY5HJOtfQhdCMy5u+sMFYGA1UdHwRPME0wS6BJoEeGRWh0dHA6Ly9jcmwu
- # bWljcm9zb2Z0LmNvbS9wa2kvY3JsL3Byb2R1Y3RzL01pY0NvZFNpZ1BDQV8yMDEw
- # LTA3LTA2LmNybDBaBggrBgEFBQcBAQROMEwwSgYIKwYBBQUHMAKGPmh0dHA6Ly93
- # d3cubWljcm9zb2Z0LmNvbS9wa2kvY2VydHMvTWljQ29kU2lnUENBXzIwMTAtMDct
- # MDYuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggEBADxf8A60TSfr
- # Xa5t5G1ExJ08OpjCi9RBsN8T+wkozcz1E0QfB8mxaE38u00S89z+HoCJ5/LCgMBY
- # VoTWAHtbG4PYT7rLcGzBuX8S+OIlBR2LtghZ5H6mCiblpD/3dMz2d2Z62/TCYAHp
- # 0iKlHa+EJ/KW7SPsvfUNxQ2IbolvXfQGuTyFV9HEN/NdfmWWg78vXVZ25TlM1HLj
- # uotGgyG7Td3b4cHQBZbO+XVZ/AITsfAB6TlqFzGCLINYyZ90EX0sAcm6mVvO2GDU
- # PiqJjKoh+0nO06ccETCeyMMRxt6oyJB+0UkldpKX4aZc18u0gNohHGx04bp9Jc6D
- # TuTh3ynE8hwwggZwMIIEWKADAgECAgphDFJMAAAAAAADMA0GCSqGSIb3DQEBCwUA
- # MIGIMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMH
- # UmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTIwMAYDVQQD
- # EylNaWNyb3NvZnQgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgMjAxMDAeFw0x
- # MDA3MDYyMDQwMTdaFw0yNTA3MDYyMDUwMTdaMH4xCzAJBgNVBAYTAlVTMRMwEQYD
- # VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
- # b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p
- # bmcgUENBIDIwMTAwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDpDmRQ
- # eWe1xOP9CQBMnpSs91Zo6kTYz8VYT6mldnxtRbrTOZK0pB75+WWC5BfSj/1EnAjo
- # ZZPOLFWEv30I4y4rqEErGLeiS25JTGsVB97R0sKJHnGUzbV/S7SvCNjMiNZrF5Q6
- # k84mP+zm/jSYV9UdXUn2siou1YW7WT/4kLQrg3TKK7M7RuPwRknBF2ZUyRy9HcRV
- # Yldy+Ge5JSA03l2mpZVeqyiAzdWynuUDtWPTshTIwciKJgpZfwfs/w7tgBI1TBKm
- # vlJb9aba4IsLSHfWhUfVELnG6Krui2otBVxgxrQqW5wjHF9F4xoUHm83yxkzgGqJ
- # TaNqZmN4k9Uwz5UfAgMBAAGjggHjMIIB3zAQBgkrBgEEAYI3FQEEAwIBADAdBgNV
- # HQ4EFgQU5vxfe7siAFjkck619CF0IzLm76wwGQYJKwYBBAGCNxQCBAweCgBTAHUA
- # YgBDAEEwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAU
- # 1fZWy4/oolxiaNE9lJBb186aGMQwVgYDVR0fBE8wTTBLoEmgR4ZFaHR0cDovL2Ny
- # bC5taWNyb3NvZnQuY29tL3BraS9jcmwvcHJvZHVjdHMvTWljUm9vQ2VyQXV0XzIw
- # MTAtMDYtMjMuY3JsMFoGCCsGAQUFBwEBBE4wTDBKBggrBgEFBQcwAoY+aHR0cDov
- # L3d3dy5taWNyb3NvZnQuY29tL3BraS9jZXJ0cy9NaWNSb29DZXJBdXRfMjAxMC0w
- # Ni0yMy5jcnQwgZ0GA1UdIASBlTCBkjCBjwYJKwYBBAGCNy4DMIGBMD0GCCsGAQUF
- # BwIBFjFodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vUEtJL2RvY3MvQ1BTL2RlZmF1
- # bHQuaHRtMEAGCCsGAQUFBwICMDQeMiAdAEwAZQBnAGEAbABfAFAAbwBsAGkAYwB5
- # AF8AUwB0AGEAdABlAG0AZQBuAHQALiAdMA0GCSqGSIb3DQEBCwUAA4ICAQAadO9X
- # Tyl7xBaFeLhQ0yL8CZ2sgpf4NP8qLJeVEuXkv8+/k8jjNKnbgbjcHgC+0jVvr+V/
- # eZV35QLU8evYzU4eG2GiwlojGvCMqGJRRWcI4z88HpP4MIUXyDlAptcOsyEp5aWh
- # aYwik8x0mOehR0PyU6zADzBpf/7SJSBtb2HT3wfV2XIALGmGdj1R26Y5SMk3YW0H
- # 3VMZy6fWYcK/4oOrD+Brm5XWfShRsIlKUaSabMi3H0oaDmmp19zBftFJcKq2rbty
- # R2MX+qbWoqaG7KgQRJtjtrJpiQbHRoZ6GD/oxR0h1Xv5AiMtxUHLvx1MyBbvsZx/
- # /CJLSYpuFeOmf3Zb0VN5kYWd1dLbPXM18zyuVLJSR2rAqhOV0o4R2plnXjKM+zeF
- # 0dx1hZyHxlpXhcK/3Q2PjJst67TuzyfTtV5p+qQWBAGnJGdzz01Ptt4FVpd69+lS
- # TfR3BU+FxtgL8Y7tQgnRDXbjI1Z4IiY2vsqxjG6qHeSF2kczYo+kyZEzX3EeQK+Y
- # Zcki6EIhJYocLWDZN4lBiSoWD9dhPJRoYFLv1keZoIBA7hWBdz6c4FMYGlAdOJWb
- # HmYzEyc5F3iHNs5Ow1+y9T1HU7bg5dsLYT0q15IszjdaPkBCMaQfEAjCVpy/JF1R
- # Ap1qedIX09rBlI4HeyVxRKsGaubUxt8jmpZ1xTGCFVswghVXAgEBMIGVMH4xCzAJ
- # BgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25k
- # MR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jv
- # c29mdCBDb2RlIFNpZ25pbmcgUENBIDIwMTACEzMAAAPejVaCWvGkqWcAAAAAA94w
- # DQYJYIZIAWUDBAIBBQCgga4wGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYK
- # KwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIEopdEf3
- # vaw+bknrxifr7wCqVwSSQ1Hlz/MHRULiG6hkMEIGCisGAQQBgjcCAQwxNDAyoBSA
- # EgBNAGkAYwByAG8AcwBvAGYAdKEagBhodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20w
- # DQYJKoZIhvcNAQEBBQAEggEAoc95H28Otz04OMSpqyJEI/GOQC1Mb/J5ZbWNlpwL
- # SpWn/LabLVovn/C/4KWJqIC+6973dDNa0vNC4/OFtxPHqYCJa/hE9CglCe27w5K0
- # OhkbjqC6tgExbEnEoaDgm2PXUk/4tfbPlJh6Y1VKqN3VR993zQsZ2XFAEhXQH4wQ
- # mzAjtjK39ybg6jvMyB27jSftZEkEXiY5mBRulKXbi3N9D4HoYcIy+JkWjNtOCs0C
- # FouKQvMWbGnSdCD4J+1812BhJgwkRV/Mv6SyvpDaGqsDStM6IGP9qzP8fycMa2T4
- # HphTGOVATk5daOVXhzCUYBMJGN1uc1vBRnM24+GrZyDh6aGCEuUwghLhBgorBgEE
- # AYI3AwMBMYIS0TCCEs0GCSqGSIb3DQEHAqCCEr4wghK6AgEDMQ8wDQYJYIZIAWUD
- # BAIBBQAwggFRBgsqhkiG9w0BCRABBKCCAUAEggE8MIIBOAIBAQYKKwYBBAGEWQoD
- # ATAxMA0GCWCGSAFlAwQCAQUABCA0G+7FTsJDPTYWwZ08h1B7VPplzC/1k7Py6r3M
- # VtxDaAIGYD0KIhcoGBMyMDIxMDMwMjE5NTEyOC44NTRaMASAAgH0oIHQpIHNMIHK
- # MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVk
- # bW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSUwIwYDVQQLExxN
- # aWNyb3NvZnQgQW1lcmljYSBPcGVyYXRpb25zMSYwJAYDVQQLEx1UaGFsZXMgVFNT
- # IEVTTjpFNUE2LUUyN0MtNTkyRTElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3Rh
- # bXAgU2VydmljZaCCDjwwggTxMIID2aADAgECAhMzAAABR52P8ebeMYNZAAAAAAFH
- # MA0GCSqGSIb3DQEBCwUAMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5n
- # dG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9y
- # YXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwMB4X
- # DTIwMTExMjE4MjU1NVoXDTIyMDIxMTE4MjU1NVowgcoxCzAJBgNVBAYTAlVTMRMw
- # EQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVN
- # aWNyb3NvZnQgQ29ycG9yYXRpb24xJTAjBgNVBAsTHE1pY3Jvc29mdCBBbWVyaWNh
- # IE9wZXJhdGlvbnMxJjAkBgNVBAsTHVRoYWxlcyBUU1MgRVNOOkU1QTYtRTI3Qy01
- # OTJFMSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2aWNlMIIBIjAN
- # BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArQUDTOl99ihZPwSfGGqa38xLei49
- # +BvlS484HxIDhklXdTLu5wqYStCuKMj68yLYDUYweIFIiquhs4MXQx4GT4ExL5ue
- # 87GrHMhq8m1pH91Va/G6n9jyIBr8CgzRIFXMoLBG7lsF8/S4ujOwDqA+EwfH5eAE
- # 5vi+2+PpWA1DCWDC86YiczO+OWtFx4q4lGjqWFn5MDvR8+rn/pNh6u8hsoLh/J2j
- # yzJ2H5mCLdj1wMFlbxuDA+GG41wVWdeLnoe2JamUzLmt5/ZE9QmQ7B78/qOfJ7KG
- # pl0cERTm+yw41VfvnGSGSztvbrIiNB+/bW930r4fbVO0AuwoqzQgWGoDSQIDAQAB
- # o4IBGzCCARcwHQYDVR0OBBYEFLT43G/eZKGGVxsvQz8TePXUgrC6MB8GA1UdIwQY
- # MBaAFNVjOlyKMZDzQ3t8RhvFM2hahW1VMFYGA1UdHwRPME0wS6BJoEeGRWh0dHA6
- # Ly9jcmwubWljcm9zb2Z0LmNvbS9wa2kvY3JsL3Byb2R1Y3RzL01pY1RpbVN0YVBD
- # QV8yMDEwLTA3LTAxLmNybDBaBggrBgEFBQcBAQROMEwwSgYIKwYBBQUHMAKGPmh0
- # dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2kvY2VydHMvTWljVGltU3RhUENBXzIw
- # MTAtMDctMDEuY3J0MAwGA1UdEwEB/wQCMAAwEwYDVR0lBAwwCgYIKwYBBQUHAwgw
- # DQYJKoZIhvcNAQELBQADggEBAFDEDso1fnmtpBLV6g9HDnw9mdjxVCMuZC5BlOd0
- # QxnH4ZcyEfUJU4GS6kxIYCy7gksuo3Jmvpz4O3uV4NaKgmXGSUcLUT80tRevzOmE
- # d+R926zdJmlZz65q0PdZJH7Dag07blg4gCAX5DRIAqUGQm+DldxzLuS/Hmc4OXVG
- # ie1xPiwbqYSUixSbWm8WLeH5AkMZ0w9s+dGN9mbl4jZhRYmu6lavt2HN5pltNvvy
- # lh/D9Rz4qGyRvHKxmIEhJMbZFFxnaLrcBllvPCkfUUXDP+Bii6rdjkPAFhEG+7IY
- # DPKcTb7t9E8Xo0QKWuFgHzgHo0xuPiswZuu141WdiJVwD5IwggZxMIIEWaADAgEC
- # AgphCYEqAAAAAAACMA0GCSqGSIb3DQEBCwUAMIGIMQswCQYDVQQGEwJVUzETMBEG
- # A1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWlj
- # cm9zb2Z0IENvcnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3NvZnQgUm9vdCBDZXJ0
- # aWZpY2F0ZSBBdXRob3JpdHkgMjAxMDAeFw0xMDA3MDEyMTM2NTVaFw0yNTA3MDEy
- # MTQ2NTVaMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYD
- # VQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAk
- # BgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwMIIBIjANBgkqhkiG
- # 9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqR0NvHcRijog7PwTl/X6f2mUa3RUENWlCgCC
- # hfvtfGhLLF/Fw+Vhwna3PmYrW/AVUycEMR9BGxqVHc4JE458YTBZsTBED/FgiIRU
- # QwzXTbg4CLNC3ZOs1nMwVyaCo0UN0Or1R4HNvyRgMlhgRvJYR4YyhB50YWeRX4FU
- # sc+TTJLBxKZd0WETbijGGvmGgLvfYfxGwScdJGcSchohiq9LZIlQYrFd/XcfPfBX
- # day9ikJNQFHRD5wGPmd/9WbAA5ZEfu/QS/1u5ZrKsajyeioKMfDaTgaRtogINeh4
- # HLDpmc085y9Euqf03GS9pAHBIAmTeM38vMDJRF1eFpwBBU8iTQIDAQABo4IB5jCC
- # AeIwEAYJKwYBBAGCNxUBBAMCAQAwHQYDVR0OBBYEFNVjOlyKMZDzQ3t8RhvFM2ha
- # hW1VMBkGCSsGAQQBgjcUAgQMHgoAUwB1AGIAQwBBMAsGA1UdDwQEAwIBhjAPBgNV
- # HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNX2VsuP6KJcYmjRPZSQW9fOmhjEMFYG
- # A1UdHwRPME0wS6BJoEeGRWh0dHA6Ly9jcmwubWljcm9zb2Z0LmNvbS9wa2kvY3Js
- # L3Byb2R1Y3RzL01pY1Jvb0NlckF1dF8yMDEwLTA2LTIzLmNybDBaBggrBgEFBQcB
- # AQROMEwwSgYIKwYBBQUHMAKGPmh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2kv
- # Y2VydHMvTWljUm9vQ2VyQXV0XzIwMTAtMDYtMjMuY3J0MIGgBgNVHSABAf8EgZUw
- # gZIwgY8GCSsGAQQBgjcuAzCBgTA9BggrBgEFBQcCARYxaHR0cDovL3d3dy5taWNy
- # b3NvZnQuY29tL1BLSS9kb2NzL0NQUy9kZWZhdWx0Lmh0bTBABggrBgEFBQcCAjA0
- # HjIgHQBMAGUAZwBhAGwAXwBQAG8AbABpAGMAeQBfAFMAdABhAHQAZQBtAGUAbgB0
- # AC4gHTANBgkqhkiG9w0BAQsFAAOCAgEAB+aIUQ3ixuCYP4FxAz2do6Ehb7Prpsz1
- # Mb7PBeKp/vpXbRkws8LFZslq3/Xn8Hi9x6ieJeP5vO1rVFcIK1GCRBL7uVOMzPRg
- # Eop2zEBAQZvcXBf/XPleFzWYJFZLdO9CEMivv3/Gf/I3fVo/HPKZeUqRUgCvOA8X
- # 9S95gWXZqbVr5MfO9sp6AG9LMEQkIjzP7QOllo9ZKby2/QThcJ8ySif9Va8v/rbl
- # jjO7Yl+a21dA6fHOmWaQjP9qYn/dxUoLkSbiOewZSnFjnXshbcOco6I8+n99lmqQ
- # eKZt0uGc+R38ONiU9MalCpaGpL2eGq4EQoO4tYCbIjggtSXlZOz39L9+Y1klD3ou
- # OVd2onGqBooPiRa6YacRy5rYDkeagMXQzafQ732D8OE7cQnfXXSYIghh2rBQHm+9
- # 8eEA3+cxB6STOvdlR3jo+KhIq/fecn5ha293qYHLpwmsObvsxsvYgrRyzR30uIUB
- # HoD7G4kqVDmyW9rIDVWZeodzOwjmmC3qjeAzLhIp9cAvVCch98isTtoouLGp25ay
- # p0Kiyc8ZQU3ghvkqmqMRZjDTu3QyS99je/WZii8bxyGvWbWu3EQ8l1Bx16HSxVXj
- # ad5XwdHeMMD9zOZN+w2/XU/pnR4ZOC+8z1gFLu8NoFA12u8JJxzVs341Hgi62jbb
- # 01+P3nSISRKhggLOMIICNwIBATCB+KGB0KSBzTCByjELMAkGA1UEBhMCVVMxEzAR
- # BgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1p
- # Y3Jvc29mdCBDb3Jwb3JhdGlvbjElMCMGA1UECxMcTWljcm9zb2Z0IEFtZXJpY2Eg
- # T3BlcmF0aW9uczEmMCQGA1UECxMdVGhhbGVzIFRTUyBFU046RTVBNi1FMjdDLTU5
- # MkUxJTAjBgNVBAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNlcnZpY2WiIwoBATAH
- # BgUrDgMCGgMVAKunwbRBDaHDQEjKi9N8xiUtMGXdoIGDMIGApH4wfDELMAkGA1UE
- # BhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAc
- # BgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0
- # IFRpbWUtU3RhbXAgUENBIDIwMTAwDQYJKoZIhvcNAQEFBQACBQDj6NoOMCIYDzIw
- # MjEwMzAyMjMzNjQ2WhgPMjAyMTAzMDMyMzM2NDZaMHcwPQYKKwYBBAGEWQoEATEv
- # MC0wCgIFAOPo2g4CAQAwCgIBAAICF1UCAf8wBwIBAAICEgEwCgIFAOPqK44CAQAw
- # NgYKKwYBBAGEWQoEAjEoMCYwDAYKKwYBBAGEWQoDAqAKMAgCAQACAwehIKEKMAgC
- # AQACAwGGoDANBgkqhkiG9w0BAQUFAAOBgQDGpf2DDaMchKYVl+vO/Gecar2AYuJq
- # G2SKTV2+crmfibf0vmGSf3Kmr+q16ig+tSUazXh8Atkb2L/08PqOqr19m9pPHd2O
- # KOa6pnhgqkyEb73Yj0YCXbdBNE9bo9kf6N1ybOqFlIdFlX3Ud5USLBGHYFylcyX8
- # LmrODdH9s26VsDGCAw0wggMJAgEBMIGTMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQI
- # EwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3Nv
- # ZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBD
- # QSAyMDEwAhMzAAABR52P8ebeMYNZAAAAAAFHMA0GCWCGSAFlAwQCAQUAoIIBSjAa
- # BgkqhkiG9w0BCQMxDQYLKoZIhvcNAQkQAQQwLwYJKoZIhvcNAQkEMSIEIP9OL2YM
- # L4toKb9r93wQS2ENt2Vv1I0tSd082TGWx9V6MIH6BgsqhkiG9w0BCRACLzGB6jCB
- # 5zCB5DCBvQQge9s8EgOUz7oGyImTv9h9Ya4rAFSLcMw7HG9FqooY6YUwgZgwgYCk
- # fjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMH
- # UmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQD
- # Ex1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMAITMwAAAUedj/Hm3jGDWQAA
- # AAABRzAiBCCEG4IGoiAdWd8laB+jIRYGwbyCd2sa5shagO05EtZMujANBgkqhkiG
- # 9w0BAQsFAASCAQA//5WeIMBNt8Sz9yeypy4tIm7zZxOcBMqtb4gFCeFhD/cGNNeV
- # Tmtg9Ulk8OGotezlN/X0g6ZpckZ21v7FGFRWpq0L3Wuzuk+xS+jfbTrxhQHh5+kK
- # oVAsGCaK9RHWuofD10w8uQzVJQMQR0sF7CNYABArAJmoGiy5tLZnJaIDga898yAA
- # hS16psPTfK2eWKEfHb8W79a8Cgpz9cXl5Pri39STagnpUWWiIcDpXwRH18fq3ImN
- # nBnVGCDrzfJrSO8XSA9HeUCt7U5ZzPl+JkJA0yPyb9OUpmhIDyNlGpXoafkq5vkS
- # +aa46CK+MKPkohYUejAtWlyGRcwBfPKxjDDq
- # SIG # End signature block
|