Crossplatform App der Caritas (Versuch).
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

Add-AppDevPackage.ps1 37KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866
  1. #
  2. # Add-AppxDevPackage.ps1 is a PowerShell script designed to install app
  3. # packages created by Visual Studio for developers. To run this script from
  4. # Explorer, right-click on its icon and choose "Run with PowerShell".
  5. #
  6. # Visual Studio supplies this script in the folder generated with its
  7. # "Prepare Package" command. The same folder will also contain the app
  8. # package (a .appx file), the signing certificate (a .cer file), and a
  9. # "Dependencies" subfolder containing all the framework packages used by the
  10. # app.
  11. #
  12. # This script simplifies installing these packages by automating the
  13. # following functions:
  14. # 1. Find the app package and signing certificate in the script directory
  15. # 2. Prompt the user to acquire a developer license and to install the
  16. # certificate if necessary
  17. # 3. Find dependency packages that are applicable to the operating system's
  18. # CPU architecture
  19. # 4. Install the package along with all applicable dependencies
  20. #
  21. # All command line parameters are reserved for use internally by the script.
  22. # Users should launch this script from Explorer.
  23. #
  24. # .Link
  25. # http://go.microsoft.com/fwlink/?LinkId=243053
  26. param(
  27. [switch]$Force = $false,
  28. [switch]$GetDeveloperLicense = $false,
  29. [switch]$SkipLoggingTelemetry = $false,
  30. [string]$CertificatePath = $null
  31. )
  32. $ErrorActionPreference = "Stop"
  33. # The language resources for this script are placed in the
  34. # "Add-AppDevPackage.resources" subfolder alongside the script. Since the
  35. # current working directory might not be the directory that contains the
  36. # script, we need to create the full path of the resources directory to
  37. # pass into Import-LocalizedData
  38. $ScriptPath = $null
  39. try
  40. {
  41. $ScriptPath = (Get-Variable MyInvocation).Value.MyCommand.Path
  42. $ScriptDir = Split-Path -Parent $ScriptPath
  43. }
  44. catch {}
  45. if (!$ScriptPath)
  46. {
  47. PrintMessageAndExit $UiStrings.ErrorNoScriptPath $ErrorCodes.NoScriptPath
  48. }
  49. $LocalizedResourcePath = Join-Path $ScriptDir "Add-AppDevPackage.resources"
  50. Import-LocalizedData -BindingVariable UiStrings -BaseDirectory $LocalizedResourcePath
  51. $ErrorCodes = Data {
  52. ConvertFrom-StringData @'
  53. Success = 0
  54. NoScriptPath = 1
  55. NoPackageFound = 2
  56. ManyPackagesFound = 3
  57. NoCertificateFound = 4
  58. ManyCertificatesFound = 5
  59. BadCertificate = 6
  60. PackageUnsigned = 7
  61. CertificateMismatch = 8
  62. ForceElevate = 9
  63. LaunchAdminFailed = 10
  64. GetDeveloperLicenseFailed = 11
  65. InstallCertificateFailed = 12
  66. AddPackageFailed = 13
  67. ForceDeveloperLicense = 14
  68. CertUtilInstallFailed = 17
  69. CertIsCA = 18
  70. BannedEKU = 19
  71. NoBasicConstraints = 20
  72. NoCodeSigningEku = 21
  73. InstallCertificateCancelled = 22
  74. BannedKeyUsage = 23
  75. ExpiredCertificate = 24
  76. '@
  77. }
  78. $IMAGE_FILE_MACHINE_i386 = 0x014c
  79. $IMAGE_FILE_MACHINE_AMD64 = 0x8664
  80. $IMAGE_FILE_MACHINE_ARM64 = 0xAA64
  81. $IMAGE_FILE_MACHINE_ARM = 0x01c0
  82. $IMAGE_FILE_MACHINE_THUMB = 0x01c2
  83. $IMAGE_FILE_MACHINE_ARMNT = 0x01c4
  84. # First try to use IsWow64Process2 to determine the OS architecture
  85. try
  86. {
  87. $IsWow64Process2_MethodDefinition = @"
  88. [DllImport("kernel32.dll", SetLastError = true)]
  89. public static extern bool IsWow64Process2(IntPtr process, out ushort processMachine, out ushort nativeMachine);
  90. "@
  91. $Kernel32 = Add-Type -MemberDefinition $IsWow64Process2_MethodDefinition -Name "Kernel32" -Namespace "Win32" -PassThru
  92. $Proc = Get-Process -id $pid
  93. $processMachine = New-Object uint16
  94. $nativeMachine = New-Object uint16
  95. $Res = $Kernel32::IsWow64Process2($Proc.Handle, [ref] $processMachine, [ref] $nativeMachine)
  96. if ($Res -eq $True)
  97. {
  98. switch ($nativeMachine)
  99. {
  100. $IMAGE_FILE_MACHINE_i386 { $ProcessorArchitecture = "x86" }
  101. $IMAGE_FILE_MACHINE_AMD64 { $ProcessorArchitecture = "amd64" }
  102. $IMAGE_FILE_MACHINE_ARM64 { $ProcessorArchitecture = "arm64" }
  103. $IMAGE_FILE_MACHINE_ARM { $ProcessorArchitecture = "arm" }
  104. $IMAGE_FILE_MACHINE_THUMB { $ProcessorArchitecture = "arm" }
  105. $IMAGE_FILE_MACHINE_ARMNT { $ProcessorArchitecture = "arm" }
  106. }
  107. }
  108. }
  109. catch
  110. {
  111. # Ignore exception and fall back to using environment variables to determine the OS architecture
  112. }
  113. if ($null -eq $ProcessorArchitecture)
  114. {
  115. $ProcessorArchitecture = $Env:Processor_Architecture
  116. # Getting $Env:Processor_Architecture on arm64 machines will return x86. So check if the environment
  117. # variable "ProgramFiles(Arm)" is also set, if it is we know the actual processor architecture is arm64.
  118. # The value will also be x86 on amd64 machines when running the x86 version of PowerShell.
  119. if ($ProcessorArchitecture -eq "x86")
  120. {
  121. if ($null -ne ${Env:ProgramFiles(Arm)})
  122. {
  123. $ProcessorArchitecture = "arm64"
  124. }
  125. elseif ($null -ne ${Env:ProgramFiles(x86)})
  126. {
  127. $ProcessorArchitecture = "amd64"
  128. }
  129. }
  130. }
  131. function PrintMessageAndExit($ErrorMessage, $ReturnCode)
  132. {
  133. Write-Host $ErrorMessage
  134. try
  135. {
  136. # Log telemetry data regarding the use of the script if possible.
  137. # There are three ways that this can be disabled:
  138. # 1. If the "TelemetryDependencies" folder isn't present. This can be excluded at build time by setting the MSBuild property AppxLogTelemetryFromSideloadingScript to false
  139. # 2. If the SkipLoggingTelemetry switch is passed to this script.
  140. # 3. If Visual Studio telemetry is disabled via the registry.
  141. $TelemetryAssembliesFolder = (Join-Path $PSScriptRoot "TelemetryDependencies")
  142. if (!$SkipLoggingTelemetry -And (Test-Path $TelemetryAssembliesFolder))
  143. {
  144. $job = Start-Job -FilePath (Join-Path $TelemetryAssembliesFolder "LogSideloadingTelemetry.ps1") -ArgumentList $TelemetryAssembliesFolder, "VS/DesignTools/SideLoadingScript/AddAppDevPackage", $ReturnCode, $ProcessorArchitecture
  145. Wait-Job -Job $job -Timeout 60 | Out-Null
  146. }
  147. }
  148. catch
  149. {
  150. # Ignore telemetry errors
  151. }
  152. if (!$Force)
  153. {
  154. Pause
  155. }
  156. exit $ReturnCode
  157. }
  158. #
  159. # Warns the user about installing certificates, and presents a Yes/No prompt
  160. # to confirm the action. The default is set to No.
  161. #
  162. function ConfirmCertificateInstall
  163. {
  164. $Answer = $host.UI.PromptForChoice(
  165. "",
  166. $UiStrings.WarningInstallCert,
  167. [System.Management.Automation.Host.ChoiceDescription[]]@($UiStrings.PromptYesString, $UiStrings.PromptNoString),
  168. 1)
  169. return $Answer -eq 0
  170. }
  171. #
  172. # Validates whether a file is a valid certificate using CertUtil.
  173. # This needs to be done before calling Get-PfxCertificate on the file, otherwise
  174. # the user will get a cryptic "Password: " prompt for invalid certs.
  175. #
  176. function ValidateCertificateFormat($FilePath)
  177. {
  178. # certutil -verify prints a lot of text that we don't need, so it's redirected to $null here
  179. certutil.exe -verify $FilePath > $null
  180. if ($LastExitCode -lt 0)
  181. {
  182. PrintMessageAndExit ($UiStrings.ErrorBadCertificate -f $FilePath, $LastExitCode) $ErrorCodes.BadCertificate
  183. }
  184. # Check if certificate is expired
  185. $cert = Get-PfxCertificate $FilePath
  186. if (($cert.NotBefore -gt (Get-Date)) -or ($cert.NotAfter -lt (Get-Date)))
  187. {
  188. PrintMessageAndExit ($UiStrings.ErrorExpiredCertificate -f $FilePath) $ErrorCodes.ExpiredCertificate
  189. }
  190. }
  191. #
  192. # Verify that the developer certificate meets the following restrictions:
  193. # - The certificate must contain a Basic Constraints extension, and its
  194. # Certificate Authority (CA) property must be false.
  195. # - The certificate's Key Usage extension must be either absent, or set to
  196. # only DigitalSignature.
  197. # - The certificate must contain an Extended Key Usage (EKU) extension with
  198. # Code Signing usage.
  199. # - The certificate must NOT contain any other EKU except Code Signing and
  200. # Lifetime Signing.
  201. #
  202. # These restrictions are enforced to decrease security risks that arise from
  203. # trusting digital certificates.
  204. #
  205. function CheckCertificateRestrictions
  206. {
  207. Set-Variable -Name BasicConstraintsExtensionOid -Value "2.5.29.19" -Option Constant
  208. Set-Variable -Name KeyUsageExtensionOid -Value "2.5.29.15" -Option Constant
  209. Set-Variable -Name EkuExtensionOid -Value "2.5.29.37" -Option Constant
  210. Set-Variable -Name CodeSigningEkuOid -Value "1.3.6.1.5.5.7.3.3" -Option Constant
  211. Set-Variable -Name LifetimeSigningEkuOid -Value "1.3.6.1.4.1.311.10.3.13" -Option Constant
  212. Set-Variable -Name UwpSigningEkuOid -Value "1.3.6.1.4.1.311.84.3.1" -Option Constant
  213. Set-Variable -Name DisposableSigningEkuOid -Value "1.3.6.1.4.1.311.84.3.2" -Option Constant
  214. $CertificateExtensions = (Get-PfxCertificate $CertificatePath).Extensions
  215. $HasBasicConstraints = $false
  216. $HasCodeSigningEku = $false
  217. foreach ($Extension in $CertificateExtensions)
  218. {
  219. # Certificate must contain the Basic Constraints extension
  220. if ($Extension.oid.value -eq $BasicConstraintsExtensionOid)
  221. {
  222. # CA property must be false
  223. if ($Extension.CertificateAuthority)
  224. {
  225. PrintMessageAndExit $UiStrings.ErrorCertIsCA $ErrorCodes.CertIsCA
  226. }
  227. $HasBasicConstraints = $true
  228. }
  229. # If key usage is present, it must be set to digital signature
  230. elseif ($Extension.oid.value -eq $KeyUsageExtensionOid)
  231. {
  232. if ($Extension.KeyUsages -ne "DigitalSignature")
  233. {
  234. PrintMessageAndExit ($UiStrings.ErrorBannedKeyUsage -f $Extension.KeyUsages) $ErrorCodes.BannedKeyUsage
  235. }
  236. }
  237. elseif ($Extension.oid.value -eq $EkuExtensionOid)
  238. {
  239. # Certificate must contain the Code Signing EKU
  240. $EKUs = $Extension.EnhancedKeyUsages.Value
  241. if ($EKUs -contains $CodeSigningEkuOid)
  242. {
  243. $HasCodeSigningEKU = $True
  244. }
  245. # EKUs other than code signing and lifetime signing are not allowed
  246. foreach ($EKU in $EKUs)
  247. {
  248. if ($EKU -ne $CodeSigningEkuOid -and $EKU -ne $LifetimeSigningEkuOid -and $EKU -ne $UwpSigningEkuOid -and $EKU -ne $DisposableSigningEkuOid)
  249. {
  250. PrintMessageAndExit ($UiStrings.ErrorBannedEKU -f $EKU) $ErrorCodes.BannedEKU
  251. }
  252. }
  253. }
  254. }
  255. if (!$HasBasicConstraints)
  256. {
  257. PrintMessageAndExit $UiStrings.ErrorNoBasicConstraints $ErrorCodes.NoBasicConstraints
  258. }
  259. if (!$HasCodeSigningEKU)
  260. {
  261. PrintMessageAndExit $UiStrings.ErrorNoCodeSigningEku $ErrorCodes.NoCodeSigningEku
  262. }
  263. }
  264. #
  265. # Performs operations that require administrative privileges:
  266. # - Prompt the user to obtain a developer license
  267. # - Install the developer certificate (if -Force is not specified, also prompts the user to confirm)
  268. #
  269. function DoElevatedOperations
  270. {
  271. if ($GetDeveloperLicense)
  272. {
  273. Write-Host $UiStrings.GettingDeveloperLicense
  274. if ($Force)
  275. {
  276. PrintMessageAndExit $UiStrings.ErrorForceDeveloperLicense $ErrorCodes.ForceDeveloperLicense
  277. }
  278. try
  279. {
  280. Show-WindowsDeveloperLicenseRegistration
  281. }
  282. catch
  283. {
  284. $Error[0] # Dump details about the last error
  285. PrintMessageAndExit $UiStrings.ErrorGetDeveloperLicenseFailed $ErrorCodes.GetDeveloperLicenseFailed
  286. }
  287. }
  288. if ($CertificatePath)
  289. {
  290. Write-Host $UiStrings.InstallingCertificate
  291. # Make sure certificate format is valid and usage constraints are followed
  292. ValidateCertificateFormat $CertificatePath
  293. CheckCertificateRestrictions
  294. # If -Force is not specified, warn the user and get consent
  295. if ($Force -or (ConfirmCertificateInstall))
  296. {
  297. # Add cert to store
  298. certutil.exe -addstore TrustedPeople $CertificatePath
  299. if ($LastExitCode -lt 0)
  300. {
  301. PrintMessageAndExit ($UiStrings.ErrorCertUtilInstallFailed -f $LastExitCode) $ErrorCodes.CertUtilInstallFailed
  302. }
  303. }
  304. else
  305. {
  306. PrintMessageAndExit $UiStrings.ErrorInstallCertificateCancelled $ErrorCodes.InstallCertificateCancelled
  307. }
  308. }
  309. }
  310. #
  311. # Checks whether the machine is missing a valid developer license.
  312. #
  313. function CheckIfNeedDeveloperLicense
  314. {
  315. $Result = $true
  316. try
  317. {
  318. $Result = (Get-WindowsDeveloperLicense | Where-Object { $_.IsValid } | Measure-Object).Count -eq 0
  319. }
  320. catch {}
  321. return $Result
  322. }
  323. #
  324. # Launches an elevated process running the current script to perform tasks
  325. # that require administrative privileges. This function waits until the
  326. # elevated process terminates, and checks whether those tasks were successful.
  327. #
  328. function LaunchElevated
  329. {
  330. # Set up command line arguments to the elevated process
  331. $RelaunchArgs = '-ExecutionPolicy Unrestricted -file "' + $ScriptPath + '"'
  332. if ($Force)
  333. {
  334. $RelaunchArgs += ' -Force'
  335. }
  336. if ($NeedDeveloperLicense)
  337. {
  338. $RelaunchArgs += ' -GetDeveloperLicense'
  339. }
  340. if ($SkipLoggingTelemetry)
  341. {
  342. $RelaunchArgs += ' -SkipLoggingTelemetry'
  343. }
  344. if ($NeedInstallCertificate)
  345. {
  346. $RelaunchArgs += ' -CertificatePath "' + $DeveloperCertificatePath.FullName + '"'
  347. }
  348. # Launch the process and wait for it to finish
  349. try
  350. {
  351. $PowerShellExePath = (Get-Process -Id $PID).Path
  352. $AdminProcess = Start-Process $PowerShellExePath -Verb RunAs -ArgumentList $RelaunchArgs -PassThru
  353. }
  354. catch
  355. {
  356. $Error[0] # Dump details about the last error
  357. PrintMessageAndExit $UiStrings.ErrorLaunchAdminFailed $ErrorCodes.LaunchAdminFailed
  358. }
  359. while (!($AdminProcess.HasExited))
  360. {
  361. Start-Sleep -Seconds 2
  362. }
  363. # Check if all elevated operations were successful
  364. if ($NeedDeveloperLicense)
  365. {
  366. if (CheckIfNeedDeveloperLicense)
  367. {
  368. PrintMessageAndExit $UiStrings.ErrorGetDeveloperLicenseFailed $ErrorCodes.GetDeveloperLicenseFailed
  369. }
  370. else
  371. {
  372. Write-Host $UiStrings.AcquireLicenseSuccessful
  373. }
  374. }
  375. if ($NeedInstallCertificate)
  376. {
  377. $Signature = Get-AuthenticodeSignature $DeveloperPackagePath -Verbose
  378. if ($Signature.Status -ne "Valid")
  379. {
  380. PrintMessageAndExit ($UiStrings.ErrorInstallCertificateFailed -f $Signature.Status) $ErrorCodes.InstallCertificateFailed
  381. }
  382. else
  383. {
  384. Write-Host $UiStrings.InstallCertificateSuccessful
  385. }
  386. }
  387. }
  388. #
  389. # Finds all applicable dependency packages according to OS architecture, and
  390. # installs the developer package with its dependencies. The expected layout
  391. # of dependencies is:
  392. #
  393. # <current dir>
  394. # \Dependencies
  395. # <Architecture neutral dependencies>.appx\.msix
  396. # \x86
  397. # <x86 dependencies>.appx\.msix
  398. # \x64
  399. # <x64 dependencies>.appx\.msix
  400. # \arm
  401. # <arm dependencies>.appx\.msix
  402. # \arm64
  403. # <arm64 dependencies>.appx\.msix
  404. #
  405. function InstallPackageWithDependencies
  406. {
  407. $DependencyPackagesDir = (Join-Path $ScriptDir "Dependencies")
  408. $DependencyPackages = @()
  409. if (Test-Path $DependencyPackagesDir)
  410. {
  411. # Get architecture-neutral dependencies
  412. $DependencyPackages += Get-ChildItem (Join-Path $DependencyPackagesDir "*.appx") | Where-Object { $_.Mode -NotMatch "d" }
  413. $DependencyPackages += Get-ChildItem (Join-Path $DependencyPackagesDir "*.msix") | Where-Object { $_.Mode -NotMatch "d" }
  414. # Get architecture-specific dependencies
  415. if (($ProcessorArchitecture -eq "x86" -or $ProcessorArchitecture -eq "amd64" -or $ProcessorArchitecture -eq "arm64") -and (Test-Path (Join-Path $DependencyPackagesDir "x86")))
  416. {
  417. $DependencyPackages += Get-ChildItem (Join-Path $DependencyPackagesDir "x86\*.appx") | Where-Object { $_.Mode -NotMatch "d" }
  418. $DependencyPackages += Get-ChildItem (Join-Path $DependencyPackagesDir "x86\*.msix") | Where-Object { $_.Mode -NotMatch "d" }
  419. }
  420. if (($ProcessorArchitecture -eq "amd64") -and (Test-Path (Join-Path $DependencyPackagesDir "x64")))
  421. {
  422. $DependencyPackages += Get-ChildItem (Join-Path $DependencyPackagesDir "x64\*.appx") | Where-Object { $_.Mode -NotMatch "d" }
  423. $DependencyPackages += Get-ChildItem (Join-Path $DependencyPackagesDir "x64\*.msix") | Where-Object { $_.Mode -NotMatch "d" }
  424. }
  425. if (($ProcessorArchitecture -eq "arm" -or $ProcessorArchitecture -eq "arm64") -and (Test-Path (Join-Path $DependencyPackagesDir "arm")))
  426. {
  427. $DependencyPackages += Get-ChildItem (Join-Path $DependencyPackagesDir "arm\*.appx") | Where-Object { $_.Mode -NotMatch "d" }
  428. $DependencyPackages += Get-ChildItem (Join-Path $DependencyPackagesDir "arm\*.msix") | Where-Object { $_.Mode -NotMatch "d" }
  429. }
  430. if (($ProcessorArchitecture -eq "arm64") -and (Test-Path (Join-Path $DependencyPackagesDir "arm64")))
  431. {
  432. $DependencyPackages += Get-ChildItem (Join-Path $DependencyPackagesDir "arm64\*.appx") | Where-Object { $_.Mode -NotMatch "d" }
  433. $DependencyPackages += Get-ChildItem (Join-Path $DependencyPackagesDir "arm64\*.msix") | Where-Object { $_.Mode -NotMatch "d" }
  434. }
  435. }
  436. Write-Host $UiStrings.InstallingPackage
  437. $AddPackageSucceeded = $False
  438. try
  439. {
  440. if ($DependencyPackages.FullName.Count -gt 0)
  441. {
  442. Write-Host $UiStrings.DependenciesFound
  443. $DependencyPackages.FullName
  444. Add-AppxPackage -Path $DeveloperPackagePath.FullName -DependencyPath $DependencyPackages.FullName -ForceApplicationShutdown
  445. }
  446. else
  447. {
  448. Add-AppxPackage -Path $DeveloperPackagePath.FullName -ForceApplicationShutdown
  449. }
  450. $AddPackageSucceeded = $?
  451. }
  452. catch
  453. {
  454. $Error[0] # Dump details about the last error
  455. }
  456. if (!$AddPackageSucceeded)
  457. {
  458. if ($NeedInstallCertificate)
  459. {
  460. PrintMessageAndExit $UiStrings.ErrorAddPackageFailedWithCert $ErrorCodes.AddPackageFailed
  461. }
  462. else
  463. {
  464. PrintMessageAndExit $UiStrings.ErrorAddPackageFailed $ErrorCodes.AddPackageFailed
  465. }
  466. }
  467. }
  468. #
  469. # Main script logic when the user launches the script without parameters.
  470. #
  471. function DoStandardOperations
  472. {
  473. # Check for an .appx or .msix file in the script directory
  474. $PackagePath = Get-ChildItem (Join-Path $ScriptDir "*.appx") | Where-Object { $_.Mode -NotMatch "d" }
  475. if ($PackagePath -eq $null)
  476. {
  477. $PackagePath = Get-ChildItem (Join-Path $ScriptDir "*.msix") | Where-Object { $_.Mode -NotMatch "d" }
  478. }
  479. $PackageCount = ($PackagePath | Measure-Object).Count
  480. # Check for an .appxbundle or .msixbundle file in the script directory
  481. $BundlePath = Get-ChildItem (Join-Path $ScriptDir "*.appxbundle") | Where-Object { $_.Mode -NotMatch "d" }
  482. if ($BundlePath -eq $null)
  483. {
  484. $BundlePath = Get-ChildItem (Join-Path $ScriptDir "*.msixbundle") | Where-Object { $_.Mode -NotMatch "d" }
  485. }
  486. $BundleCount = ($BundlePath | Measure-Object).Count
  487. # Check for an .eappx or .emsix file in the script directory
  488. $EncryptedPackagePath = Get-ChildItem (Join-Path $ScriptDir "*.eappx") | Where-Object { $_.Mode -NotMatch "d" }
  489. if ($EncryptedPackagePath -eq $null)
  490. {
  491. $EncryptedPackagePath = Get-ChildItem (Join-Path $ScriptDir "*.emsix") | Where-Object { $_.Mode -NotMatch "d" }
  492. }
  493. $EncryptedPackageCount = ($EncryptedPackagePath | Measure-Object).Count
  494. # Check for an .eappxbundle or .emsixbundle file in the script directory
  495. $EncryptedBundlePath = Get-ChildItem (Join-Path $ScriptDir "*.eappxbundle") | Where-Object { $_.Mode -NotMatch "d" }
  496. if ($EncryptedBundlePath -eq $null)
  497. {
  498. $EncryptedBundlePath = Get-ChildItem (Join-Path $ScriptDir "*.emsixbundle") | Where-Object { $_.Mode -NotMatch "d" }
  499. }
  500. $EncryptedBundleCount = ($EncryptedBundlePath | Measure-Object).Count
  501. $NumberOfPackages = $PackageCount + $EncryptedPackageCount
  502. $NumberOfBundles = $BundleCount + $EncryptedBundleCount
  503. # There must be at least one package or bundle
  504. if ($NumberOfPackages + $NumberOfBundles -lt 1)
  505. {
  506. PrintMessageAndExit $UiStrings.ErrorNoPackageFound $ErrorCodes.NoPackageFound
  507. }
  508. # We must have exactly one bundle OR no bundle and exactly one package
  509. elseif ($NumberOfBundles -gt 1 -or
  510. ($NumberOfBundles -eq 0 -and $NumberOfpackages -gt 1))
  511. {
  512. PrintMessageAndExit $UiStrings.ErrorManyPackagesFound $ErrorCodes.ManyPackagesFound
  513. }
  514. # First attempt to install a bundle or encrypted bundle. If neither exists, fall back to packages and then encrypted packages
  515. if ($BundleCount -eq 1)
  516. {
  517. $DeveloperPackagePath = $BundlePath
  518. Write-Host ($UiStrings.BundleFound -f $DeveloperPackagePath.FullName)
  519. }
  520. elseif ($EncryptedBundleCount -eq 1)
  521. {
  522. $DeveloperPackagePath = $EncryptedBundlePath
  523. Write-Host ($UiStrings.EncryptedBundleFound -f $DeveloperPackagePath.FullName)
  524. }
  525. elseif ($PackageCount -eq 1)
  526. {
  527. $DeveloperPackagePath = $PackagePath
  528. Write-Host ($UiStrings.PackageFound -f $DeveloperPackagePath.FullName)
  529. }
  530. elseif ($EncryptedPackageCount -eq 1)
  531. {
  532. $DeveloperPackagePath = $EncryptedPackagePath
  533. Write-Host ($UiStrings.EncryptedPackageFound -f $DeveloperPackagePath.FullName)
  534. }
  535. # The package must be signed
  536. $PackageSignature = Get-AuthenticodeSignature $DeveloperPackagePath
  537. $PackageCertificate = $PackageSignature.SignerCertificate
  538. if (!$PackageCertificate)
  539. {
  540. PrintMessageAndExit $UiStrings.ErrorPackageUnsigned $ErrorCodes.PackageUnsigned
  541. }
  542. # Test if the package signature is trusted. If not, the corresponding certificate
  543. # needs to be present in the current directory and needs to be installed.
  544. $NeedInstallCertificate = ($PackageSignature.Status -ne "Valid")
  545. if ($NeedInstallCertificate)
  546. {
  547. # List all .cer files in the script directory
  548. $DeveloperCertificatePath = Get-ChildItem (Join-Path $ScriptDir "*.cer") | Where-Object { $_.Mode -NotMatch "d" }
  549. $DeveloperCertificateCount = ($DeveloperCertificatePath | Measure-Object).Count
  550. # There must be exactly 1 certificate
  551. if ($DeveloperCertificateCount -lt 1)
  552. {
  553. PrintMessageAndExit $UiStrings.ErrorNoCertificateFound $ErrorCodes.NoCertificateFound
  554. }
  555. elseif ($DeveloperCertificateCount -gt 1)
  556. {
  557. PrintMessageAndExit $UiStrings.ErrorManyCertificatesFound $ErrorCodes.ManyCertificatesFound
  558. }
  559. Write-Host ($UiStrings.CertificateFound -f $DeveloperCertificatePath.FullName)
  560. # The .cer file must have the format of a valid certificate
  561. ValidateCertificateFormat $DeveloperCertificatePath
  562. # The package signature must match the certificate file
  563. if ($PackageCertificate -ne (Get-PfxCertificate $DeveloperCertificatePath))
  564. {
  565. PrintMessageAndExit $UiStrings.ErrorCertificateMismatch $ErrorCodes.CertificateMismatch
  566. }
  567. }
  568. $NeedDeveloperLicense = CheckIfNeedDeveloperLicense
  569. # Relaunch the script elevated with the necessary parameters if needed
  570. if ($NeedDeveloperLicense -or $NeedInstallCertificate)
  571. {
  572. Write-Host $UiStrings.ElevateActions
  573. if ($NeedDeveloperLicense)
  574. {
  575. Write-Host $UiStrings.ElevateActionDevLicense
  576. }
  577. if ($NeedInstallCertificate)
  578. {
  579. Write-Host $UiStrings.ElevateActionCertificate
  580. }
  581. $IsAlreadyElevated = ([Security.Principal.WindowsIdentity]::GetCurrent().Groups.Value -contains "S-1-5-32-544")
  582. if ($IsAlreadyElevated)
  583. {
  584. if ($Force -and $NeedDeveloperLicense)
  585. {
  586. PrintMessageAndExit $UiStrings.ErrorForceDeveloperLicense $ErrorCodes.ForceDeveloperLicense
  587. }
  588. if ($Force -and $NeedInstallCertificate)
  589. {
  590. Write-Warning $UiStrings.WarningInstallCert
  591. }
  592. }
  593. else
  594. {
  595. if ($Force)
  596. {
  597. PrintMessageAndExit $UiStrings.ErrorForceElevate $ErrorCodes.ForceElevate
  598. }
  599. else
  600. {
  601. Write-Host $UiStrings.ElevateActionsContinue
  602. Pause
  603. }
  604. }
  605. LaunchElevated
  606. }
  607. InstallPackageWithDependencies
  608. }
  609. #
  610. # Main script entry point
  611. #
  612. if ($GetDeveloperLicense -or $CertificatePath)
  613. {
  614. DoElevatedOperations
  615. }
  616. else
  617. {
  618. DoStandardOperations
  619. PrintMessageAndExit $UiStrings.Success $ErrorCodes.Success
  620. }
  621. # SIG # Begin signature block
  622. # MIIhdwYJKoZIhvcNAQcCoIIhaDCCIWQCAQExDzANBglghkgBZQMEAgEFADB5Bgor
  623. # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
  624. # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCAaovVnr86uRLc7
  625. # aU4MWMaEBdFBUDgUiMNw07NprqcvsqCCC3IwggT6MIID4qADAgECAhMzAAAD3o1W
  626. # glrxpKlnAAAAAAPeMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD
  627. # VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
  628. # b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p
  629. # bmcgUENBIDIwMTAwHhcNMjAxMjE1MjEyNDIwWhcNMjExMjAyMjEyNDIwWjB0MQsw
  630. # CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u
  631. # ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy
  632. # b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
  633. # AQCn8/DiSdIkSLNe/aikoxkWIAtCq9W+7+dbEXN/cZ4ZkeX/mn8MPRJVyt7FaE3k
  634. # bFofDl4GH5xZOQoOUhGh8mfq3sUq9RDZ6T1vFanVTeRq3iamvmjYHVgYq1MW9RdY
  635. # 1UaGH7OE2L0coGjp46azVnYJlj7I1BWMZXxYRSxGQttNi9g1lwXCGfGl+aTqWSfy
  636. # hRpMB/mpVC4IF8MYsHVYctYb1ex+3ZwDSmwsX/Y4sxtSpt18xX9Rso2fES8GGnQK
  637. # dBnMMdySgdp0E4ACWpa0iQDTBQMQVSTfrVFjyetviHoMejI+SgbkiPrEezGGvTiG
  638. # Ooc6+eWSEwYMy9sxw0GaCiVvAgMBAAGjggF5MIIBdTAfBgNVHSUEGDAWBgorBgEE
  639. # AYI3PQYBBggrBgEFBQcDAzAdBgNVHQ4EFgQUJOo70fFaruzlxG7u+R2Hd9N1TIkw
  640. # UAYDVR0RBEkwR6RFMEMxKTAnBgNVBAsTIE1pY3Jvc29mdCBPcGVyYXRpb25zIFB1
  641. # ZXJ0byBSaWNvMRYwFAYDVQQFEw0yMzA4NjUrNDYzMTMzMB8GA1UdIwQYMBaAFOb8
  642. # X3u7IgBY5HJOtfQhdCMy5u+sMFYGA1UdHwRPME0wS6BJoEeGRWh0dHA6Ly9jcmwu
  643. # bWljcm9zb2Z0LmNvbS9wa2kvY3JsL3Byb2R1Y3RzL01pY0NvZFNpZ1BDQV8yMDEw
  644. # LTA3LTA2LmNybDBaBggrBgEFBQcBAQROMEwwSgYIKwYBBQUHMAKGPmh0dHA6Ly93
  645. # d3cubWljcm9zb2Z0LmNvbS9wa2kvY2VydHMvTWljQ29kU2lnUENBXzIwMTAtMDct
  646. # MDYuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggEBADxf8A60TSfr
  647. # Xa5t5G1ExJ08OpjCi9RBsN8T+wkozcz1E0QfB8mxaE38u00S89z+HoCJ5/LCgMBY
  648. # VoTWAHtbG4PYT7rLcGzBuX8S+OIlBR2LtghZ5H6mCiblpD/3dMz2d2Z62/TCYAHp
  649. # 0iKlHa+EJ/KW7SPsvfUNxQ2IbolvXfQGuTyFV9HEN/NdfmWWg78vXVZ25TlM1HLj
  650. # uotGgyG7Td3b4cHQBZbO+XVZ/AITsfAB6TlqFzGCLINYyZ90EX0sAcm6mVvO2GDU
  651. # PiqJjKoh+0nO06ccETCeyMMRxt6oyJB+0UkldpKX4aZc18u0gNohHGx04bp9Jc6D
  652. # TuTh3ynE8hwwggZwMIIEWKADAgECAgphDFJMAAAAAAADMA0GCSqGSIb3DQEBCwUA
  653. # MIGIMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMH
  654. # UmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTIwMAYDVQQD
  655. # EylNaWNyb3NvZnQgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgMjAxMDAeFw0x
  656. # MDA3MDYyMDQwMTdaFw0yNTA3MDYyMDUwMTdaMH4xCzAJBgNVBAYTAlVTMRMwEQYD
  657. # VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
  658. # b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p
  659. # bmcgUENBIDIwMTAwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDpDmRQ
  660. # eWe1xOP9CQBMnpSs91Zo6kTYz8VYT6mldnxtRbrTOZK0pB75+WWC5BfSj/1EnAjo
  661. # ZZPOLFWEv30I4y4rqEErGLeiS25JTGsVB97R0sKJHnGUzbV/S7SvCNjMiNZrF5Q6
  662. # k84mP+zm/jSYV9UdXUn2siou1YW7WT/4kLQrg3TKK7M7RuPwRknBF2ZUyRy9HcRV
  663. # Yldy+Ge5JSA03l2mpZVeqyiAzdWynuUDtWPTshTIwciKJgpZfwfs/w7tgBI1TBKm
  664. # vlJb9aba4IsLSHfWhUfVELnG6Krui2otBVxgxrQqW5wjHF9F4xoUHm83yxkzgGqJ
  665. # TaNqZmN4k9Uwz5UfAgMBAAGjggHjMIIB3zAQBgkrBgEEAYI3FQEEAwIBADAdBgNV
  666. # HQ4EFgQU5vxfe7siAFjkck619CF0IzLm76wwGQYJKwYBBAGCNxQCBAweCgBTAHUA
  667. # YgBDAEEwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAU
  668. # 1fZWy4/oolxiaNE9lJBb186aGMQwVgYDVR0fBE8wTTBLoEmgR4ZFaHR0cDovL2Ny
  669. # bC5taWNyb3NvZnQuY29tL3BraS9jcmwvcHJvZHVjdHMvTWljUm9vQ2VyQXV0XzIw
  670. # MTAtMDYtMjMuY3JsMFoGCCsGAQUFBwEBBE4wTDBKBggrBgEFBQcwAoY+aHR0cDov
  671. # L3d3dy5taWNyb3NvZnQuY29tL3BraS9jZXJ0cy9NaWNSb29DZXJBdXRfMjAxMC0w
  672. # Ni0yMy5jcnQwgZ0GA1UdIASBlTCBkjCBjwYJKwYBBAGCNy4DMIGBMD0GCCsGAQUF
  673. # BwIBFjFodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vUEtJL2RvY3MvQ1BTL2RlZmF1
  674. # bHQuaHRtMEAGCCsGAQUFBwICMDQeMiAdAEwAZQBnAGEAbABfAFAAbwBsAGkAYwB5
  675. # AF8AUwB0AGEAdABlAG0AZQBuAHQALiAdMA0GCSqGSIb3DQEBCwUAA4ICAQAadO9X
  676. # Tyl7xBaFeLhQ0yL8CZ2sgpf4NP8qLJeVEuXkv8+/k8jjNKnbgbjcHgC+0jVvr+V/
  677. # eZV35QLU8evYzU4eG2GiwlojGvCMqGJRRWcI4z88HpP4MIUXyDlAptcOsyEp5aWh
  678. # aYwik8x0mOehR0PyU6zADzBpf/7SJSBtb2HT3wfV2XIALGmGdj1R26Y5SMk3YW0H
  679. # 3VMZy6fWYcK/4oOrD+Brm5XWfShRsIlKUaSabMi3H0oaDmmp19zBftFJcKq2rbty
  680. # R2MX+qbWoqaG7KgQRJtjtrJpiQbHRoZ6GD/oxR0h1Xv5AiMtxUHLvx1MyBbvsZx/
  681. # /CJLSYpuFeOmf3Zb0VN5kYWd1dLbPXM18zyuVLJSR2rAqhOV0o4R2plnXjKM+zeF
  682. # 0dx1hZyHxlpXhcK/3Q2PjJst67TuzyfTtV5p+qQWBAGnJGdzz01Ptt4FVpd69+lS
  683. # TfR3BU+FxtgL8Y7tQgnRDXbjI1Z4IiY2vsqxjG6qHeSF2kczYo+kyZEzX3EeQK+Y
  684. # Zcki6EIhJYocLWDZN4lBiSoWD9dhPJRoYFLv1keZoIBA7hWBdz6c4FMYGlAdOJWb
  685. # HmYzEyc5F3iHNs5Ow1+y9T1HU7bg5dsLYT0q15IszjdaPkBCMaQfEAjCVpy/JF1R
  686. # Ap1qedIX09rBlI4HeyVxRKsGaubUxt8jmpZ1xTGCFVswghVXAgEBMIGVMH4xCzAJ
  687. # BgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25k
  688. # MR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jv
  689. # c29mdCBDb2RlIFNpZ25pbmcgUENBIDIwMTACEzMAAAPejVaCWvGkqWcAAAAAA94w
  690. # DQYJYIZIAWUDBAIBBQCgga4wGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYK
  691. # KwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIEopdEf3
  692. # vaw+bknrxifr7wCqVwSSQ1Hlz/MHRULiG6hkMEIGCisGAQQBgjcCAQwxNDAyoBSA
  693. # EgBNAGkAYwByAG8AcwBvAGYAdKEagBhodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20w
  694. # DQYJKoZIhvcNAQEBBQAEggEAoc95H28Otz04OMSpqyJEI/GOQC1Mb/J5ZbWNlpwL
  695. # SpWn/LabLVovn/C/4KWJqIC+6973dDNa0vNC4/OFtxPHqYCJa/hE9CglCe27w5K0
  696. # OhkbjqC6tgExbEnEoaDgm2PXUk/4tfbPlJh6Y1VKqN3VR993zQsZ2XFAEhXQH4wQ
  697. # mzAjtjK39ybg6jvMyB27jSftZEkEXiY5mBRulKXbi3N9D4HoYcIy+JkWjNtOCs0C
  698. # FouKQvMWbGnSdCD4J+1812BhJgwkRV/Mv6SyvpDaGqsDStM6IGP9qzP8fycMa2T4
  699. # HphTGOVATk5daOVXhzCUYBMJGN1uc1vBRnM24+GrZyDh6aGCEuUwghLhBgorBgEE
  700. # AYI3AwMBMYIS0TCCEs0GCSqGSIb3DQEHAqCCEr4wghK6AgEDMQ8wDQYJYIZIAWUD
  701. # BAIBBQAwggFRBgsqhkiG9w0BCRABBKCCAUAEggE8MIIBOAIBAQYKKwYBBAGEWQoD
  702. # ATAxMA0GCWCGSAFlAwQCAQUABCA0G+7FTsJDPTYWwZ08h1B7VPplzC/1k7Py6r3M
  703. # VtxDaAIGYD0KIhcoGBMyMDIxMDMwMjE5NTEyOC44NTRaMASAAgH0oIHQpIHNMIHK
  704. # MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVk
  705. # bW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSUwIwYDVQQLExxN
  706. # aWNyb3NvZnQgQW1lcmljYSBPcGVyYXRpb25zMSYwJAYDVQQLEx1UaGFsZXMgVFNT
  707. # IEVTTjpFNUE2LUUyN0MtNTkyRTElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3Rh
  708. # bXAgU2VydmljZaCCDjwwggTxMIID2aADAgECAhMzAAABR52P8ebeMYNZAAAAAAFH
  709. # MA0GCSqGSIb3DQEBCwUAMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5n
  710. # dG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9y
  711. # YXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwMB4X
  712. # DTIwMTExMjE4MjU1NVoXDTIyMDIxMTE4MjU1NVowgcoxCzAJBgNVBAYTAlVTMRMw
  713. # EQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVN
  714. # aWNyb3NvZnQgQ29ycG9yYXRpb24xJTAjBgNVBAsTHE1pY3Jvc29mdCBBbWVyaWNh
  715. # IE9wZXJhdGlvbnMxJjAkBgNVBAsTHVRoYWxlcyBUU1MgRVNOOkU1QTYtRTI3Qy01
  716. # OTJFMSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2aWNlMIIBIjAN
  717. # BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArQUDTOl99ihZPwSfGGqa38xLei49
  718. # +BvlS484HxIDhklXdTLu5wqYStCuKMj68yLYDUYweIFIiquhs4MXQx4GT4ExL5ue
  719. # 87GrHMhq8m1pH91Va/G6n9jyIBr8CgzRIFXMoLBG7lsF8/S4ujOwDqA+EwfH5eAE
  720. # 5vi+2+PpWA1DCWDC86YiczO+OWtFx4q4lGjqWFn5MDvR8+rn/pNh6u8hsoLh/J2j
  721. # yzJ2H5mCLdj1wMFlbxuDA+GG41wVWdeLnoe2JamUzLmt5/ZE9QmQ7B78/qOfJ7KG
  722. # pl0cERTm+yw41VfvnGSGSztvbrIiNB+/bW930r4fbVO0AuwoqzQgWGoDSQIDAQAB
  723. # o4IBGzCCARcwHQYDVR0OBBYEFLT43G/eZKGGVxsvQz8TePXUgrC6MB8GA1UdIwQY
  724. # MBaAFNVjOlyKMZDzQ3t8RhvFM2hahW1VMFYGA1UdHwRPME0wS6BJoEeGRWh0dHA6
  725. # Ly9jcmwubWljcm9zb2Z0LmNvbS9wa2kvY3JsL3Byb2R1Y3RzL01pY1RpbVN0YVBD
  726. # QV8yMDEwLTA3LTAxLmNybDBaBggrBgEFBQcBAQROMEwwSgYIKwYBBQUHMAKGPmh0
  727. # dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2kvY2VydHMvTWljVGltU3RhUENBXzIw
  728. # MTAtMDctMDEuY3J0MAwGA1UdEwEB/wQCMAAwEwYDVR0lBAwwCgYIKwYBBQUHAwgw
  729. # DQYJKoZIhvcNAQELBQADggEBAFDEDso1fnmtpBLV6g9HDnw9mdjxVCMuZC5BlOd0
  730. # QxnH4ZcyEfUJU4GS6kxIYCy7gksuo3Jmvpz4O3uV4NaKgmXGSUcLUT80tRevzOmE
  731. # d+R926zdJmlZz65q0PdZJH7Dag07blg4gCAX5DRIAqUGQm+DldxzLuS/Hmc4OXVG
  732. # ie1xPiwbqYSUixSbWm8WLeH5AkMZ0w9s+dGN9mbl4jZhRYmu6lavt2HN5pltNvvy
  733. # lh/D9Rz4qGyRvHKxmIEhJMbZFFxnaLrcBllvPCkfUUXDP+Bii6rdjkPAFhEG+7IY
  734. # DPKcTb7t9E8Xo0QKWuFgHzgHo0xuPiswZuu141WdiJVwD5IwggZxMIIEWaADAgEC
  735. # AgphCYEqAAAAAAACMA0GCSqGSIb3DQEBCwUAMIGIMQswCQYDVQQGEwJVUzETMBEG
  736. # A1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWlj
  737. # cm9zb2Z0IENvcnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3NvZnQgUm9vdCBDZXJ0
  738. # aWZpY2F0ZSBBdXRob3JpdHkgMjAxMDAeFw0xMDA3MDEyMTM2NTVaFw0yNTA3MDEy
  739. # MTQ2NTVaMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYD
  740. # VQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAk
  741. # BgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwMIIBIjANBgkqhkiG
  742. # 9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqR0NvHcRijog7PwTl/X6f2mUa3RUENWlCgCC
  743. # hfvtfGhLLF/Fw+Vhwna3PmYrW/AVUycEMR9BGxqVHc4JE458YTBZsTBED/FgiIRU
  744. # QwzXTbg4CLNC3ZOs1nMwVyaCo0UN0Or1R4HNvyRgMlhgRvJYR4YyhB50YWeRX4FU
  745. # sc+TTJLBxKZd0WETbijGGvmGgLvfYfxGwScdJGcSchohiq9LZIlQYrFd/XcfPfBX
  746. # day9ikJNQFHRD5wGPmd/9WbAA5ZEfu/QS/1u5ZrKsajyeioKMfDaTgaRtogINeh4
  747. # HLDpmc085y9Euqf03GS9pAHBIAmTeM38vMDJRF1eFpwBBU8iTQIDAQABo4IB5jCC
  748. # AeIwEAYJKwYBBAGCNxUBBAMCAQAwHQYDVR0OBBYEFNVjOlyKMZDzQ3t8RhvFM2ha
  749. # hW1VMBkGCSsGAQQBgjcUAgQMHgoAUwB1AGIAQwBBMAsGA1UdDwQEAwIBhjAPBgNV
  750. # HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNX2VsuP6KJcYmjRPZSQW9fOmhjEMFYG
  751. # A1UdHwRPME0wS6BJoEeGRWh0dHA6Ly9jcmwubWljcm9zb2Z0LmNvbS9wa2kvY3Js
  752. # L3Byb2R1Y3RzL01pY1Jvb0NlckF1dF8yMDEwLTA2LTIzLmNybDBaBggrBgEFBQcB
  753. # AQROMEwwSgYIKwYBBQUHMAKGPmh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2kv
  754. # Y2VydHMvTWljUm9vQ2VyQXV0XzIwMTAtMDYtMjMuY3J0MIGgBgNVHSABAf8EgZUw
  755. # gZIwgY8GCSsGAQQBgjcuAzCBgTA9BggrBgEFBQcCARYxaHR0cDovL3d3dy5taWNy
  756. # b3NvZnQuY29tL1BLSS9kb2NzL0NQUy9kZWZhdWx0Lmh0bTBABggrBgEFBQcCAjA0
  757. # HjIgHQBMAGUAZwBhAGwAXwBQAG8AbABpAGMAeQBfAFMAdABhAHQAZQBtAGUAbgB0
  758. # AC4gHTANBgkqhkiG9w0BAQsFAAOCAgEAB+aIUQ3ixuCYP4FxAz2do6Ehb7Prpsz1
  759. # Mb7PBeKp/vpXbRkws8LFZslq3/Xn8Hi9x6ieJeP5vO1rVFcIK1GCRBL7uVOMzPRg
  760. # Eop2zEBAQZvcXBf/XPleFzWYJFZLdO9CEMivv3/Gf/I3fVo/HPKZeUqRUgCvOA8X
  761. # 9S95gWXZqbVr5MfO9sp6AG9LMEQkIjzP7QOllo9ZKby2/QThcJ8ySif9Va8v/rbl
  762. # jjO7Yl+a21dA6fHOmWaQjP9qYn/dxUoLkSbiOewZSnFjnXshbcOco6I8+n99lmqQ
  763. # eKZt0uGc+R38ONiU9MalCpaGpL2eGq4EQoO4tYCbIjggtSXlZOz39L9+Y1klD3ou
  764. # OVd2onGqBooPiRa6YacRy5rYDkeagMXQzafQ732D8OE7cQnfXXSYIghh2rBQHm+9
  765. # 8eEA3+cxB6STOvdlR3jo+KhIq/fecn5ha293qYHLpwmsObvsxsvYgrRyzR30uIUB
  766. # HoD7G4kqVDmyW9rIDVWZeodzOwjmmC3qjeAzLhIp9cAvVCch98isTtoouLGp25ay
  767. # p0Kiyc8ZQU3ghvkqmqMRZjDTu3QyS99je/WZii8bxyGvWbWu3EQ8l1Bx16HSxVXj
  768. # ad5XwdHeMMD9zOZN+w2/XU/pnR4ZOC+8z1gFLu8NoFA12u8JJxzVs341Hgi62jbb
  769. # 01+P3nSISRKhggLOMIICNwIBATCB+KGB0KSBzTCByjELMAkGA1UEBhMCVVMxEzAR
  770. # BgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1p
  771. # Y3Jvc29mdCBDb3Jwb3JhdGlvbjElMCMGA1UECxMcTWljcm9zb2Z0IEFtZXJpY2Eg
  772. # T3BlcmF0aW9uczEmMCQGA1UECxMdVGhhbGVzIFRTUyBFU046RTVBNi1FMjdDLTU5
  773. # MkUxJTAjBgNVBAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNlcnZpY2WiIwoBATAH
  774. # BgUrDgMCGgMVAKunwbRBDaHDQEjKi9N8xiUtMGXdoIGDMIGApH4wfDELMAkGA1UE
  775. # BhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAc
  776. # BgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0
  777. # IFRpbWUtU3RhbXAgUENBIDIwMTAwDQYJKoZIhvcNAQEFBQACBQDj6NoOMCIYDzIw
  778. # MjEwMzAyMjMzNjQ2WhgPMjAyMTAzMDMyMzM2NDZaMHcwPQYKKwYBBAGEWQoEATEv
  779. # MC0wCgIFAOPo2g4CAQAwCgIBAAICF1UCAf8wBwIBAAICEgEwCgIFAOPqK44CAQAw
  780. # NgYKKwYBBAGEWQoEAjEoMCYwDAYKKwYBBAGEWQoDAqAKMAgCAQACAwehIKEKMAgC
  781. # AQACAwGGoDANBgkqhkiG9w0BAQUFAAOBgQDGpf2DDaMchKYVl+vO/Gecar2AYuJq
  782. # G2SKTV2+crmfibf0vmGSf3Kmr+q16ig+tSUazXh8Atkb2L/08PqOqr19m9pPHd2O
  783. # KOa6pnhgqkyEb73Yj0YCXbdBNE9bo9kf6N1ybOqFlIdFlX3Ud5USLBGHYFylcyX8
  784. # LmrODdH9s26VsDGCAw0wggMJAgEBMIGTMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQI
  785. # EwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3Nv
  786. # ZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBD
  787. # QSAyMDEwAhMzAAABR52P8ebeMYNZAAAAAAFHMA0GCWCGSAFlAwQCAQUAoIIBSjAa
  788. # BgkqhkiG9w0BCQMxDQYLKoZIhvcNAQkQAQQwLwYJKoZIhvcNAQkEMSIEIP9OL2YM
  789. # L4toKb9r93wQS2ENt2Vv1I0tSd082TGWx9V6MIH6BgsqhkiG9w0BCRACLzGB6jCB
  790. # 5zCB5DCBvQQge9s8EgOUz7oGyImTv9h9Ya4rAFSLcMw7HG9FqooY6YUwgZgwgYCk
  791. # fjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMH
  792. # UmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQD
  793. # Ex1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMAITMwAAAUedj/Hm3jGDWQAA
  794. # AAABRzAiBCCEG4IGoiAdWd8laB+jIRYGwbyCd2sa5shagO05EtZMujANBgkqhkiG
  795. # 9w0BAQsFAASCAQA//5WeIMBNt8Sz9yeypy4tIm7zZxOcBMqtb4gFCeFhD/cGNNeV
  796. # Tmtg9Ulk8OGotezlN/X0g6ZpckZ21v7FGFRWpq0L3Wuzuk+xS+jfbTrxhQHh5+kK
  797. # oVAsGCaK9RHWuofD10w8uQzVJQMQR0sF7CNYABArAJmoGiy5tLZnJaIDga898yAA
  798. # hS16psPTfK2eWKEfHb8W79a8Cgpz9cXl5Pri39STagnpUWWiIcDpXwRH18fq3ImN
  799. # nBnVGCDrzfJrSO8XSA9HeUCt7U5ZzPl+JkJA0yPyb9OUpmhIDyNlGpXoafkq5vkS
  800. # +aa46CK+MKPkohYUejAtWlyGRcwBfPKxjDDq
  801. # SIG # End signature block