aboutsummaryrefslogtreecommitdiff
path: root/vcpkg/scripts/azure-pipelines/windows
diff options
context:
space:
mode:
Diffstat (limited to 'vcpkg/scripts/azure-pipelines/windows')
-rw-r--r--vcpkg/scripts/azure-pipelines/windows/azure-pipelines.yml133
-rw-r--r--vcpkg/scripts/azure-pipelines/windows/bootstrap-from-source.cmd8
-rw-r--r--vcpkg/scripts/azure-pipelines/windows/create-image.ps1287
-rw-r--r--vcpkg/scripts/azure-pipelines/windows/deploy-azcopy.ps121
-rw-r--r--vcpkg/scripts/azure-pipelines/windows/deploy-azure-cli.ps120
-rw-r--r--vcpkg/scripts/azure-pipelines/windows/deploy-cuda.ps167
-rw-r--r--vcpkg/scripts/azure-pipelines/windows/deploy-cudnn.ps126
-rw-r--r--vcpkg/scripts/azure-pipelines/windows/deploy-install-disk.ps164
-rw-r--r--vcpkg/scripts/azure-pipelines/windows/deploy-inteloneapi.ps166
-rw-r--r--vcpkg/scripts/azure-pipelines/windows/deploy-mpi.ps120
-rw-r--r--vcpkg/scripts/azure-pipelines/windows/deploy-pwsh.ps120
-rw-r--r--vcpkg/scripts/azure-pipelines/windows/deploy-settings.txt20
-rw-r--r--vcpkg/scripts/azure-pipelines/windows/deploy-tlssettings.ps1738
-rw-r--r--vcpkg/scripts/azure-pipelines/windows/deploy-visual-studio.ps142
-rw-r--r--vcpkg/scripts/azure-pipelines/windows/disk-space.ps135
-rw-r--r--vcpkg/scripts/azure-pipelines/windows/provision-entire-image.ps121
-rw-r--r--vcpkg/scripts/azure-pipelines/windows/sysprep.ps119
-rw-r--r--vcpkg/scripts/azure-pipelines/windows/utility-prefix.ps1156
-rw-r--r--vcpkg/scripts/azure-pipelines/windows/validate-version-files.ps129
19 files changed, 1792 insertions, 0 deletions
diff --git a/vcpkg/scripts/azure-pipelines/windows/azure-pipelines.yml b/vcpkg/scripts/azure-pipelines/windows/azure-pipelines.yml
new file mode 100644
index 0000000..0efe34d
--- /dev/null
+++ b/vcpkg/scripts/azure-pipelines/windows/azure-pipelines.yml
@@ -0,0 +1,133 @@
+# Copyright (c) Microsoft Corporation.
+# SPDX-License-Identifier: MIT
+#
+
+parameters:
+ - name: vcpkgToolSha
+ displayName: 'Custom SHA of vcpkg-tool to use rather than bootstrap'
+ type: string
+ default: 'use default'
+ - name: jobName
+ type: string
+ default: 'x86_windows'
+ - name: tripletPattern
+ displayName: 'Enable the triplets which contain this substring'
+ type: string
+ default: ''
+
+jobs:
+- job: ${{ parameters.jobName }}
+ condition: and(succeeded(), contains('^${{ replace(parameters.jobName, '_', '-') }}$', '${{ parameters.tripletPattern }}'))
+ pool:
+ name: PrWin-WUS
+ demands: ImageVersionOverride -equals 2025.10.17
+ timeoutInMinutes: 2880 # 2 days
+ variables:
+ - name: WORKING_ROOT
+ value: D:\
+ - name: VCPKG_DOWNLOADS
+ value: D:\downloads
+ - name: DiffFile
+ value: $(Build.ArtifactStagingDirectory)\format.diff
+ - name: ExtraChecksTriplet
+ value: x86-windows
+ steps:
+ - script: .\bootstrap-vcpkg.bat
+ displayName: 'Bootstrap vcpkg'
+ condition: eq('use default', '${{ parameters.vcpkgToolSha }}')
+ - script: .\scripts\azure-pipelines\windows\bootstrap-from-source.cmd ${{ parameters.vcpkgToolSha }}
+ displayName: "Build vcpkg with CMake"
+ condition: ne('use default', '${{ parameters.vcpkgToolSha }}')
+ - script: |
+ .\vcpkg.exe format-manifest --all
+ .\vcpkg.exe format-feature-baseline scripts\ci.baseline.txt
+ .\vcpkg.exe format-feature-baseline scripts\ci.feature.baseline.txt
+ displayName: 'Format Manifests and Baselines'
+ condition: eq('${{ replace(parameters.jobName, '_', '-') }}', '${{ variables.ExtraChecksTriplet }}')
+ - task: PowerShell@2
+ displayName: 'Create Diff'
+ condition: eq('${{ replace(parameters.jobName, '_', '-') }}', '${{ variables.ExtraChecksTriplet }}')
+ inputs:
+ filePath: scripts/azure-pipelines/Create-PRDiff.ps1
+ arguments: "-DiffFile '$(DiffFile)'"
+ pwsh: true
+ - task: PublishPipelineArtifact@1
+ displayName: 'Publish Format and Documentation Diff'
+ condition: and(eq('${{ replace(parameters.jobName, '_', '-') }}', '${{ variables.ExtraChecksTriplet }}'), failed())
+ inputs:
+ targetPath: '$(DiffFile)'
+ artifact: 'format.diff'
+ - task: AzureCLI@2
+ displayName: '*** Test Modified Ports'
+ inputs:
+ azureSubscription: 'vcpkg-pr-fleet-wus'
+ scriptType: 'pscore'
+ scriptLocation: 'inlineScript'
+ inlineScript: |
+ $current = Get-Date -AsUtc
+ $endDate = $current.AddDays(2)
+ $end = Get-Date -Date $endDate -UFormat '+%Y-%m-%dT%H:%MZ'
+ $assetSas = az storage container generate-sas --name cache --account-name vcpkgassetcachewus --as-user --auth-mode login --https-only --permissions rcl --expiry $end -o tsv | Out-String
+ $assetSas = $assetSas.Trim()
+ $binarySas = az storage container generate-sas --name cache --account-name vcpkgbinarycachewus --as-user --auth-mode login --https-only --permissions rclw --expiry $end -o tsv | Out-String
+ $binarySas = $binarySas.Trim()
+ # Persist the binary SAS as a secret pipeline variable for the owners-db step
+ Write-Host "##vso[task.setvariable variable=BCACHE_SAS_TOKEN;issecret=true]$binarySas"
+ $env:X_VCPKG_ASSET_SOURCES = "x-azurl,https://vcpkgassetcachewus.blob.core.windows.net/cache,$assetSas,readwrite"
+ & scripts/azure-pipelines/test-modified-ports.ps1 -Triplet ${{ replace(parameters.jobName, '_', '-') }} -BuildReason $(Build.Reason) -BinarySourceStub "x-azcopy-sas,https://vcpkgbinarycachewus.blob.core.windows.net/cache,$binarySas" -WorkingRoot $env:WORKING_ROOT -ArtifactStagingDirectory $(Build.ArtifactStagingDirectory)
+ - task: PowerShell@2
+ displayName: 'Validate version files'
+ condition: eq('${{ replace(parameters.jobName, '_', '-') }}', '${{ variables.ExtraChecksTriplet }}')
+ inputs:
+ filePath: 'scripts/azure-pipelines/windows/validate-version-files.ps1'
+ pwsh: true
+ - task: PublishPipelineArtifact@1
+ displayName: "Publish Artifact: failure logs for ${{ replace(parameters.jobName, '_', '-') }}"
+ inputs:
+ targetPath: '$(Build.ArtifactStagingDirectory)\failure-logs'
+ artifact: "failure logs for ${{ replace(parameters.jobName, '_', '-') }}"
+ condition: ne(variables['FAILURE_LOGS_EMPTY'], 'True')
+ - task: PublishPipelineArtifact@1
+ displayName: "Publish Artifact: azcopy logs for ${{ replace(parameters.jobName, '_', '-') }}"
+ inputs:
+ targetPath: '$(WORKING_ROOT)/azcopy-logs'
+ artifactName: "z azcopy logs for ${{ replace(parameters.jobName, '_', '-') }}"
+ condition: ne(variables['AZCOPY_LOGS_EMPTY'], 'True')
+ - task: UseNode@1
+ displayName: 'Ensure Node.js is available'
+ condition: always()
+ inputs:
+ version: '22.x'
+ - task: PowerShell@2
+ displayName: 'Build a file list for all packages'
+ condition: always()
+ inputs:
+ targetType: inline
+ script: |
+ cd scripts/azure-pipelines/owners-db
+ npm ci -s
+ if ($env:BUILD_REASON -eq 'PullRequest') {
+ Write-Host 'Running file_script_from_cache for PR'
+ $blob = "https://vcpkgbinarycachewus.blob.core.windows.net/cache?$env:BCACHE_SAS_TOKEN"
+ npx --yes ts-node ./file_script_from_cache.ts --pr-hashes "$env:BUILD_ARTIFACTSTAGINGDIRECTORY/pr-hashes.json" --blob-base-url "$blob" --target-branch "origin/master" --out-dir ../../list_files
+ } else {
+ Write-Host 'Running file_script for CI'
+ npx --yes ts-node ./file_script.ts --info-dir D:\installed\vcpkg\info\ --out-dir ../../list_files
+ }
+ pwsh: true
+ env:
+ BCACHE_SAS_TOKEN: $(BCACHE_SAS_TOKEN)
+ - task: PublishPipelineArtifact@1
+ displayName: "Publish Artifact: file lists for ${{ replace(parameters.jobName, '_', '-') }}"
+ condition: always()
+ inputs:
+ targetPath: scripts/list_files
+ artifact: "file lists for ${{ replace(parameters.jobName, '_', '-') }}"
+ - task: PublishTestResults@2
+ displayName: 'Publish Test Results'
+ condition: ne(variables['XML_RESULTS_FILE'], '')
+ inputs:
+ testRunTitle: ${{ replace(parameters.jobName, '_', '-') }}
+ testResultsFormat: xUnit
+ testResultsFiles: $(XML_RESULTS_FILE)
+ platform: ${{ replace(parameters.jobName, '_', '-') }}
diff --git a/vcpkg/scripts/azure-pipelines/windows/bootstrap-from-source.cmd b/vcpkg/scripts/azure-pipelines/windows/bootstrap-from-source.cmd
new file mode 100644
index 0000000..73a03ff
--- /dev/null
+++ b/vcpkg/scripts/azure-pipelines/windows/bootstrap-from-source.cmd
@@ -0,0 +1,8 @@
+call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\Tools\VsDevCmd.bat" -arch=x86 -host_arch=x86
+git clone --depth 1 https://github.com/microsoft/vcpkg-tool vcpkg-tool
+git -C vcpkg-tool fetch --depth 1 origin %1
+git -C vcpkg-tool switch -d FETCH_HEAD
+rmdir /s /q build.x86.release > nul 2> nul
+cmake.exe -G Ninja -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=OFF -DVCPKG_DEVELOPMENT_WARNINGS=OFF -DVCPKG_WARNINGS_AS_ERRORS=OFF -DVCPKG_BUILD_FUZZING=OFF -DVCPKG_BUILD_TLS12_DOWNLOADER=OFF -B build.x86.release -S vcpkg-tool
+ninja.exe -C build.x86.release
+move build.x86.release\vcpkg.exe vcpkg.exe
diff --git a/vcpkg/scripts/azure-pipelines/windows/create-image.ps1 b/vcpkg/scripts/azure-pipelines/windows/create-image.ps1
new file mode 100644
index 0000000..d4e02b2
--- /dev/null
+++ b/vcpkg/scripts/azure-pipelines/windows/create-image.ps1
@@ -0,0 +1,287 @@
+# Copyright (c) Microsoft Corporation.
+# SPDX-License-Identifier: MIT
+#
+
+<#
+.SYNOPSIS
+Creates a Windows virtual machine image, set up for vcpkg's CI.
+
+.DESCRIPTION
+create-image.ps1 creates an Azure Windows VM image, set up for vcpkg's CI system.
+
+This script assumes you have installed Azure tools into PowerShell by following the instructions
+at https://docs.microsoft.com/en-us/powershell/azure/install-az-ps?view=azps-3.6.1
+or are running from Azure Cloud Shell.
+#>
+
+$Location = 'westus3'
+$DatePrefixComponent = Get-Date -Format 'yyyy-MM-dd'
+$Prefix = "Win-$DatePrefixComponent"
+$GalleryImageVersion = $DatePrefixComponent.Replace('-','.')
+$VMSize = 'Standard_D8ads_v5'
+$ProtoVMName = 'PROTOTYPE'
+$WindowsServerSku = '2025-datacenter-azure-edition'
+$ErrorActionPreference = 'Stop'
+
+$ProgressActivity = 'Creating Windows Image'
+$TotalProgress = 18
+$CurrentProgress = 1
+
+# Assigning this to another variable helps when running the commands in this script manually for
+# debugging
+$Root = $PSScriptRoot
+
+<#
+.SYNOPSIS
+Generates a random password.
+
+.DESCRIPTION
+New-Password generates a password, randomly, of length $Length, containing
+only alphanumeric characters, underscore, and dash.
+
+.PARAMETER Length
+The length of the returned password.
+#>
+function New-Password {
+ Param ([int] $Length = 32)
+ $alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-"
+ if ($alphabet.Length -ne 64) {
+ throw 'Bad alphabet length'
+ }
+
+ $result = New-Object SecureString
+ for ($idx = 0; $idx -lt $Length; $idx++) {
+ $result.AppendChar($alphabet[(Get-SecureRandom -Maximum $alphabet.Length)])
+ }
+
+ return $result
+}
+
+<#
+.SYNOPSIS
+Waits for the shutdown of the specified resource.
+
+.DESCRIPTION
+Wait-Shutdown takes a VM, and checks if there's a 'PowerState/stopped'
+code; if there is, it returns. If there isn't, it waits ten seconds and
+tries again.
+
+.PARAMETER ResourceGroupName
+The name of the resource group to look up the VM in.
+
+.PARAMETER Name
+The name of the virtual machine to wait on.
+#>
+function Wait-Shutdown {
+ [CmdletBinding()]
+ Param([string]$ResourceGroupName, [string]$Name)
+
+ Write-Host "Waiting for $Name to stop..."
+ while ($true) {
+ $Vm = Get-AzVM -ResourceGroupName $ResourceGroupName -Name $Name -Status
+ $highestStatus = $Vm.Statuses.Count
+ for ($idx = 0; $idx -lt $highestStatus; $idx++) {
+ if ($Vm.Statuses[$idx].Code -eq 'PowerState/stopped') {
+ return
+ }
+ }
+
+ Write-Host "... not stopped yet, sleeping for 10 seconds"
+ Start-Sleep -Seconds 10
+ }
+}
+
+
+$AdminPW = New-Password
+$Credential = New-Object System.Management.Automation.PSCredential ("AdminUser", $AdminPW)
+
+$VirtualNetwork = Get-AzVirtualNetwork -ResourceGroupName 'vcpkg-image-minting' -Name 'vcpkg-image-minting-wus3'
+$Subnet = $VirtualNetwork.Subnets | Where-Object -Property 'Name' -EQ -Value 'image-minting' | Select-Object -First 1
+
+####################################################################################################
+Write-Progress `
+ -Activity $ProgressActivity `
+ -Status 'Creating prototype VM' `
+ -PercentComplete (100 / $TotalProgress * $CurrentProgress++)
+
+$NicName = $Prefix + 'NIC'
+$Nic = New-AzNetworkInterface `
+ -Name $NicName `
+ -ResourceGroupName 'vcpkg-image-minting' `
+ -Location $Location `
+ -Subnet $Subnet `
+ -EnableAcceleratedNetworking
+
+$VM = New-AzVMConfig -Name $ProtoVMName -VMSize $VMSize -SecurityType TrustedLaunch -IdentityType SystemAssigned
+$VM = Set-AzVMOperatingSystem `
+ -VM $VM `
+ -Windows `
+ -ComputerName $ProtoVMName `
+ -Credential $Credential `
+ -ProvisionVMAgent
+
+$VM = Add-AzVMNetworkInterface -VM $VM -Id $Nic.Id
+$VM = Set-AzVMOSDisk -VM $VM -StorageAccountType 'Premium_LRS' -CreateOption 'FromImage'
+$VM = Set-AzVMSourceImage `
+ -VM $VM `
+ -PublisherName 'MicrosoftWindowsServer' `
+ -Offer 'WindowsServer' `
+ -Skus $WindowsServerSku `
+ -Version latest
+
+$VM = Set-AzVMBootDiagnostic -VM $VM -Disable
+New-AzVm `
+ -ResourceGroupName 'vcpkg-image-minting' `
+ -Location $Location `
+ -VM $VM
+
+$VMCreated = Get-AzVM -ResourceGroupName 'vcpkg-image-minting' -Name $ProtoVMName
+$VMCreatedOsDisk = $VMCreated.StorageProfile.OsDisk.Name
+
+####################################################################################################
+Write-Progress `
+ -Activity $ProgressActivity `
+ -Status 'Minting token for vcpkg-image-minting storage account' `
+ -PercentComplete (100 / $TotalProgress * $CurrentProgress++)
+
+$VcpkgImageMintingAccount = Get-AzStorageAccount -ResourceGroupName 'vcpkg-image-minting' -Name 'vcpkgimageminting'
+
+$AssetStorageContext = New-AzStorageContext -StorageAccountName 'vcpkgimageminting' -UseConnectedAccount
+$StartTime = Get-Date
+$ExpiryTime = $StartTime.AddHours(4)
+$AssetsSas = New-AzStorageContainerSASToken -Name 'assets' -Permission r -StartTime $StartTime -ExpiryTime $ExpiryTime -Context $AssetStorageContext
+
+####################################################################################################
+function Invoke-ScriptWithPrefix {
+ param(
+ [string]$ScriptName,
+ [switch]$SkipSas
+ )
+
+ Write-Progress `
+ -Activity $ProgressActivity `
+ -Status "Running provisioning script $ScriptName in VM" `
+ -PercentComplete (100 / $TotalProgress * $CurrentProgress++)
+
+ $UtilityPrefixContent = Get-Content "$Root\utility-prefix.ps1" -Encoding utf8NoBOM -Raw
+
+ $tempScriptFilename = "$env:TEMP\temp-script.txt"
+ try {
+ $script = Get-Content "$Root\$ScriptName" -Encoding utf8NoBOM -Raw
+$replacement = @"
+if (Test-Path "`$PSScriptRoot/utility-prefix.ps1") {
+ . "`$PSScriptRoot/utility-prefix.ps1"
+}
+"@
+ $script = $script.Replace($replacement, $UtilityPrefixContent);
+ Set-Content -Path $tempScriptFilename -Value $script -Encoding utf8NoBOM
+
+ $parameter = $null
+ if (-not $SkipSas) {
+ $parameter = @{SasToken = "`"$AssetsSas`"";}
+ }
+
+ $InvokeResult = Invoke-AzVMRunCommand `
+ -ResourceGroupName 'vcpkg-image-minting' `
+ -VMName $ProtoVMName `
+ -CommandId 'RunPowerShellScript' `
+ -ScriptPath $tempScriptFilename `
+ -Parameter $parameter
+
+ Write-Host "$ScriptName output: $($InvokeResult.value.Message)"
+ } finally {
+ Remove-Item $tempScriptFilename -Force
+ }
+}
+
+####################################################################################################
+Invoke-ScriptWithPrefix -ScriptName 'deploy-tlssettings.ps1' -SkipSas
+Write-Host 'Waiting 1 minute for VM to reboot...'
+Start-Sleep -Seconds 60
+
+####################################################################################################
+Invoke-ScriptWithPrefix -ScriptName 'deploy-visual-studio.ps1'
+
+####################################################################################################
+Invoke-ScriptWithPrefix -ScriptName 'deploy-mpi.ps1'
+
+####################################################################################################
+Invoke-ScriptWithPrefix -ScriptName 'deploy-cuda.ps1'
+
+####################################################################################################
+Invoke-ScriptWithPrefix -ScriptName 'deploy-cudnn.ps1'
+
+####################################################################################################
+Invoke-ScriptWithPrefix -ScriptName 'deploy-inteloneapi.ps1'
+
+####################################################################################################
+Invoke-ScriptWithPrefix -ScriptName 'deploy-pwsh.ps1'
+
+####################################################################################################
+Invoke-ScriptWithPrefix -ScriptName 'deploy-azure-cli.ps1'
+
+####################################################################################################
+Invoke-ScriptWithPrefix -ScriptName 'deploy-azcopy.ps1'
+
+####################################################################################################
+Invoke-ScriptWithPrefix -ScriptName 'deploy-settings.txt' -SkipSas
+Restart-AzVM -ResourceGroupName 'vcpkg-image-minting' -Name $ProtoVMName
+
+####################################################################################################
+Invoke-ScriptWithPrefix -ScriptName 'sysprep.ps1'
+
+####################################################################################################
+Write-Progress `
+ -Activity $ProgressActivity `
+ -Status 'Waiting for VM to shut down' `
+ -PercentComplete (100 / $TotalProgress * $CurrentProgress++)
+
+Wait-Shutdown -ResourceGroupName 'vcpkg-image-minting' -Name $ProtoVMName
+
+####################################################################################################
+Write-Progress `
+ -Activity $ProgressActivity `
+ -Status 'Converting VM to Image' `
+ -PercentComplete (100 / $TotalProgress * $CurrentProgress++)
+
+Stop-AzVM `
+ -ResourceGroupName 'vcpkg-image-minting' `
+ -Name $ProtoVMName `
+ -Force
+
+Set-AzVM `
+ -ResourceGroupName 'vcpkg-image-minting' `
+ -Name $ProtoVMName `
+ -Generalized
+
+$westus3Location = @{Name = 'West US 3';}
+$westusLocation = @{Name = 'West US';}
+
+New-AzGalleryImageVersion `
+ -ResourceGroupName 'vcpkg-image-minting' `
+ -GalleryName 'vcpkg_gallery_wus3' `
+ -GalleryImageDefinitionName 'PrWinWus3-TrustedLaunch' `
+ -Name $GalleryImageVersion `
+ -Location $Location `
+ -SourceImageVMId $VMCreated.ID `
+ -ReplicaCount 1 `
+ -StorageAccountType 'Premium_LRS' `
+ -PublishingProfileExcludeFromLatest `
+ -TargetRegion @($westus3Location, $westusLocation)
+
+####################################################################################################
+Write-Progress `
+ -Activity $ProgressActivity `
+ -Status 'Deleting unused temporary resources' `
+ -PercentComplete (100 / $TotalProgress * $CurrentProgress++)
+
+Remove-AzVM -Id $VMCreated.ID -Force
+Remove-AzDisk -ResourceGroupName 'vcpkg-image-minting' -Name $VMCreatedOsDisk -Force
+Remove-AzNetworkInterface -ResourceGroupName 'vcpkg-image-minting' -Name $NicName -Force
+
+####################################################################################################
+Write-Progress -Activity $ProgressActivity -Completed
+Write-Host "Generated Image: $GalleryImageVersion"
+Write-Host 'Finished!'
+
+$AdminPW.Dispose()
diff --git a/vcpkg/scripts/azure-pipelines/windows/deploy-azcopy.ps1 b/vcpkg/scripts/azure-pipelines/windows/deploy-azcopy.ps1
new file mode 100644
index 0000000..3c9ec68
--- /dev/null
+++ b/vcpkg/scripts/azure-pipelines/windows/deploy-azcopy.ps1
@@ -0,0 +1,21 @@
+# Copyright (c) Microsoft Corporation.
+# SPDX-License-Identifier: MIT
+
+param([string]$SasToken)
+
+if (Test-Path "$PSScriptRoot/utility-prefix.ps1") {
+ . "$PSScriptRoot/utility-prefix.ps1"
+}
+
+[string]$AzCopyUrl
+if ([string]::IsNullOrEmpty($SasToken)) {
+ Write-Host 'Downloading from the Internet'
+ $AzCopyUrl = 'https://github.com/Azure/azure-storage-azcopy/releases/download/v10.30.1/azcopy_windows_amd64_10.30.1.zip'
+} else {
+ Write-Host 'Downloading from vcpkgimageminting using SAS token'
+ $SasToken = $SasToken.Replace('"', '')
+ $AzCopyUrl = "https://vcpkgimageminting.blob.core.windows.net/assets/azcopy_windows_amd64_10.30.1.zip?$SasToken"
+}
+
+mkdir -Force "C:\AzCopy10"
+DownloadAndUnzip -Name 'azcopy' -Url $AzCopyUrl -Destination "C:\AzCopy10"
diff --git a/vcpkg/scripts/azure-pipelines/windows/deploy-azure-cli.ps1 b/vcpkg/scripts/azure-pipelines/windows/deploy-azure-cli.ps1
new file mode 100644
index 0000000..19e5207
--- /dev/null
+++ b/vcpkg/scripts/azure-pipelines/windows/deploy-azure-cli.ps1
@@ -0,0 +1,20 @@
+# Copyright (c) Microsoft Corporation.
+# SPDX-License-Identifier: MIT
+
+param([string]$SasToken)
+
+if (Test-Path "$PSScriptRoot/utility-prefix.ps1") {
+ . "$PSScriptRoot/utility-prefix.ps1"
+}
+
+[string]$AzCliUrl
+if ([string]::IsNullOrEmpty($SasToken)) {
+ Write-Host 'Downloading from the Internet'
+ $AzCliUrl = 'https://azcliprod.blob.core.windows.net/msi/azure-cli-2.78.0-x64.msi'
+} else {
+ Write-Host 'Downloading from vcpkgimageminting using SAS token'
+ $SasToken = $SasToken.Replace('"', '')
+ $AzCliUrl = "https://vcpkgimageminting.blob.core.windows.net/assets/azure-cli-2.78.0-x64.msi?$SasToken"
+}
+
+DownloadAndInstall -Url $AzCliUrl -Name 'Azure CLI' -Args @('/quiet', '/norestart')
diff --git a/vcpkg/scripts/azure-pipelines/windows/deploy-cuda.ps1 b/vcpkg/scripts/azure-pipelines/windows/deploy-cuda.ps1
new file mode 100644
index 0000000..4903b23
--- /dev/null
+++ b/vcpkg/scripts/azure-pipelines/windows/deploy-cuda.ps1
@@ -0,0 +1,67 @@
+# Copyright (c) Microsoft Corporation.
+# SPDX-License-Identifier: MIT
+
+param([string]$SasToken)
+
+if (Test-Path "$PSScriptRoot/utility-prefix.ps1") {
+ . "$PSScriptRoot/utility-prefix.ps1"
+}
+
+[string]$CudaUrl
+if ([string]::IsNullOrEmpty($SasToken)) {
+ Write-Host 'Downloading from the Internet'
+ $CudaUrl = 'https://developer.download.nvidia.com/compute/cuda/12.9.1/local_installers/cuda_12.9.1_576.57_windows.exe'
+} else {
+ Write-Host 'Downloading from vcpkgimageminting using SAS token'
+ $SasToken = $SasToken.Replace('"', '')
+ $CudaUrl = "https://vcpkgimageminting.blob.core.windows.net/assets/cuda_12.9.1_576.57_windows.exe?$SasToken"
+}
+
+# https://docs.nvidia.com/cuda/cuda-installation-guide-microsoft-windows/index.html
+# Intentionally omitted:
+# demo_suite_12.9
+# documentation_12.9
+# nsight_compute_12.9
+# nsight_systems_12.9
+# nsight_vse_12.9
+# nvvm_samples_12.9
+# visual_studio_integration_12.9
+# visual_profiler_12.9
+# Display.Driver
+DownloadAndInstall -Name 'CUDA' -Url $CudaUrl -Args @(
+ '-s',
+ 'cublas_12.9',
+ 'cublas_dev_12.9',
+ 'cuda_profiler_api_12.9',
+ 'cudart_12.9',
+ 'cufft_12.9',
+ 'cufft_dev_12.9',
+ 'cuobjdump_12.9',
+ 'cupti_12.9',
+ 'curand_12.9',
+ 'curand_dev_12.9',
+ 'cusolver_12.9',
+ 'cusolver_dev_12.9',
+ 'cusparse_12.9',
+ 'cusparse_dev_12.9',
+ 'cuxxfilt_12.9',
+ 'npp_12.9',
+ 'npp_dev_12.9',
+ 'nvcc_12.9',
+ 'nvdisasm_12.9',
+ 'nvfatbin_12.9',
+ 'nvjitlink_12.9',
+ 'nvjpeg_12.9',
+ 'nvjpeg_dev_12.9',
+ 'nvml_dev_12.9',
+ 'nvprof_12.9',
+ 'nvprune_12.9',
+ 'nvrtc_12.9',
+ 'nvrtc_dev_12.9',
+ 'nvtx_12.9',
+ 'occupancy_calculator_12.9',
+ 'opencl_12.9',
+ 'sanitizer_12.9',
+ 'thrust_12.9',
+ '-n'
+)
diff --git a/vcpkg/scripts/azure-pipelines/windows/deploy-cudnn.ps1 b/vcpkg/scripts/azure-pipelines/windows/deploy-cudnn.ps1
new file mode 100644
index 0000000..9b20660
--- /dev/null
+++ b/vcpkg/scripts/azure-pipelines/windows/deploy-cudnn.ps1
@@ -0,0 +1,26 @@
+# Copyright (c) Microsoft Corporation.
+# SPDX-License-Identifier: MIT
+
+param([string]$SasToken)
+
+if (Test-Path "$PSScriptRoot/utility-prefix.ps1") {
+ . "$PSScriptRoot/utility-prefix.ps1"
+}
+
+[string]$CudnnUrl
+if ([string]::IsNullOrEmpty($SasToken)) {
+ Write-Host 'Downloading from the Internet'
+ $CudnnUrl = 'https://developer.download.nvidia.com/compute/cudnn/redist/cudnn/windows-x86_64/cudnn-windows-x86_64-9.10.2.21_cuda12-archive.zip'
+} else {
+ Write-Host 'Downloading from vcpkgimageminting using SAS token'
+ $SasToken = $SasToken.Replace('"', '')
+ $CudnnUrl = "https://vcpkgimageminting.blob.core.windows.net/assets/cudnn-windows-x86_64-9.10.2.21_cuda12-archive.zip?$SasToken"
+}
+
+DownloadAndUnzip -Name 'CUDNN' -Url $CudnnUrl -Destination "$env:ProgramFiles\NVIDIA GPU Computing Toolkit\CUDA\v12.9"
+
+if (Test-Path "$env:ProgramFiles\NVIDIA GPU Computing Toolkit\CUDA\v12.9\include\cudnn.h") {
+ Write-Host 'cudnn appears correctly installed'
+} else {
+ Write-Error 'cudnn appears broken!'
+}
diff --git a/vcpkg/scripts/azure-pipelines/windows/deploy-install-disk.ps1 b/vcpkg/scripts/azure-pipelines/windows/deploy-install-disk.ps1
new file mode 100644
index 0000000..c981900
--- /dev/null
+++ b/vcpkg/scripts/azure-pipelines/windows/deploy-install-disk.ps1
@@ -0,0 +1,64 @@
+# Copyright (c) Microsoft Corporation.
+# SPDX-License-Identifier: MIT
+
+param([string]$SasToken)
+
+if (Test-Path "$PSScriptRoot/utility-prefix.ps1") {
+ . "$PSScriptRoot/utility-prefix.ps1"
+}
+
+<#
+.SYNOPSIS
+Partitions a new physical disk.
+.DESCRIPTION
+Takes the disk $DiskNumber, turns it on, then partitions it for use with label
+$Label and drive letter $Letter.
+.PARAMETER DiskNumber
+The number of the disk to set up.
+.PARAMETER Letter
+The drive letter at which to mount the disk.
+.PARAMETER Label
+The label to give the disk.
+#>
+Function New-PhysicalDisk {
+Param(
+ [int]$DiskNumber,
+ [string]$Letter,
+ [string]$Label
+)
+ if ($Letter.Length -ne 1) {
+ throw "Bad drive letter $Letter, expected only one letter. (Did you accidentally add a : ?)"
+ }
+
+ try {
+ Write-Host "Attempting to online physical disk $DiskNumber"
+ [string]$diskpartScriptPath = Get-TempFilePath -Extension 'txt'
+ [string]$diskpartScriptContent =
+ "SELECT DISK $DiskNumber`r`n" +
+ "ONLINE DISK`r`n"
+
+ Write-Host "Writing diskpart script to $diskpartScriptPath with content:"
+ Write-Host $diskpartScriptContent
+ Set-Content -Path $diskpartScriptPath -Value $diskpartScriptContent
+ Write-Host 'Invoking DISKPART...'
+ & diskpart.exe /s $diskpartScriptPath
+
+ Write-Host "Provisioning physical disk $DiskNumber as drive $Letter"
+ [string]$diskpartScriptContent =
+ "SELECT DISK $DiskNumber`r`n" +
+ "ATTRIBUTES DISK CLEAR READONLY`r`n" +
+ "CREATE PARTITION PRIMARY`r`n" +
+ "FORMAT FS=NTFS LABEL=`"$Label`" QUICK`r`n" +
+ "ASSIGN LETTER=$Letter`r`n"
+ Write-Host "Writing diskpart script to $diskpartScriptPath with content:"
+ Write-Host $diskpartScriptContent
+ Set-Content -Path $diskpartScriptPath -Value $diskpartScriptContent
+ Write-Host 'Invoking DISKPART...'
+ & diskpart.exe /s $diskpartScriptPath
+ }
+ catch {
+ Write-Error "Failed to provision physical disk $DiskNumber as drive $Letter! $($_.Exception.Message)"
+ }
+}
+
+New-PhysicalDisk -DiskNumber 1 -Letter 'E' -Label 'install disk'
diff --git a/vcpkg/scripts/azure-pipelines/windows/deploy-inteloneapi.ps1 b/vcpkg/scripts/azure-pipelines/windows/deploy-inteloneapi.ps1
new file mode 100644
index 0000000..6b99d9f
--- /dev/null
+++ b/vcpkg/scripts/azure-pipelines/windows/deploy-inteloneapi.ps1
@@ -0,0 +1,66 @@
+# Copyright (c) Microsoft Corporation.
+# SPDX-License-Identifier: MIT
+
+param([string]$SasToken)
+
+if (Test-Path "$PSScriptRoot/utility-prefix.ps1") {
+ . "$PSScriptRoot/utility-prefix.ps1"
+}
+
+
+[string]$oneAPIBaseUrl
+if ([string]::IsNullOrEmpty($SasToken)) {
+ Write-Host 'Downloading from the Internet'
+ $oneAPIBaseUrl = 'https://registrationcenter-download.intel.com/akdlm/IRC_NAS/3bbdaf75-6728-492e-a18c-be654dae9ee2/intel-oneapi-hpc-toolkit-2025.2.0.576_offline.exe'
+} else {
+ Write-Host 'Downloading from vcpkgimageminting using SAS token'
+ $SasToken = $SasToken.Replace('"', '')
+ $oneAPIBaseUrl = "https://vcpkgimageminting.blob.core.windows.net/assets/intel-oneapi-hpc-toolkit-2025.2.0.576_offline.exe?$SasToken"
+}
+
+$oneAPIHPCComponents = 'intel.oneapi.win.ifort-compiler'
+
+$LocalName = 'intel-oneapi-hpc-toolkit-2025.2.0.576_offline.exe'
+
+try {
+ [bool]$doRemove = $false
+ [string]$LocalPath = Join-Path $PSScriptRoot $LocalName
+ if (Test-Path $LocalPath) {
+ Write-Host "Using local Intel oneAPI..."
+ } else {
+ Write-Host "Downloading Intel oneAPI..."
+ $tempPath = Get-TempFilePath
+ New-Item -ItemType Directory -Path $tempPath -Force
+ $LocalPath = Join-Path $tempPath $LocalName
+ curl.exe -L -o $LocalPath $oneAPIBaseUrl
+ $doRemove = $true
+ }
+
+ [string]$extractionPath = Get-TempFilePath
+ Write-Host 'Extracting Intel oneAPI...to folder: ' $extractionPath
+ $proc = Start-Process -FilePath $LocalPath -ArgumentList @('-s ', '-x', '-f', $extractionPath) -Wait -PassThru
+ $exitCode = $proc.ExitCode
+ if ($exitCode -eq 0) {
+ Write-Host 'Extraction successful!'
+ } else {
+ Write-Error "Extraction failed! Exited with $exitCode."
+ throw
+ }
+
+ Write-Host 'Install Intel oneAPI...from folder: ' $extractionPath
+ $proc = Start-Process -FilePath "$extractionPath/bootstrapper.exe" -ArgumentList @('-s ', '--action install', "--components=$oneAPIHPCComponents" , '--eula=accept', '-p=NEED_VS2017_INTEGRATION=0', '-p=NEED_VS2019_INTEGRATION=0', '-p=NEED_VS2022_INTEGRATION=0', '--log-dir=.') -Wait -PassThru
+ $exitCode = $proc.ExitCode
+ if ($exitCode -eq 0) {
+ Write-Host 'Installation successful!'
+ } elseif ($exitCode -eq 3010) {
+ Write-Host 'Installation successful! Exited with 3010 (ERROR_SUCCESS_REBOOT_REQUIRED).'
+ } else {
+ Write-Error "Installation failed! Exited with $exitCode."
+ }
+
+ if ($doRemove) {
+ Remove-Item -Path $LocalPath -Force
+ }
+} catch {
+ Write-Error "Installation failed! Exception: $($_.Exception.Message)"
+}
diff --git a/vcpkg/scripts/azure-pipelines/windows/deploy-mpi.ps1 b/vcpkg/scripts/azure-pipelines/windows/deploy-mpi.ps1
new file mode 100644
index 0000000..5f66bdb
--- /dev/null
+++ b/vcpkg/scripts/azure-pipelines/windows/deploy-mpi.ps1
@@ -0,0 +1,20 @@
+# Copyright (c) Microsoft Corporation.
+# SPDX-License-Identifier: MIT
+
+param([string]$SasToken)
+
+if (Test-Path "$PSScriptRoot/utility-prefix.ps1") {
+ . "$PSScriptRoot/utility-prefix.ps1"
+}
+
+[string]$MpiUrl
+if ([string]::IsNullOrEmpty($SasToken)) {
+ Write-Host 'Downloading from the Internet'
+ $MpiUrl = 'https://download.microsoft.com/download/a/5/2/a5207ca5-1203-491a-8fb8-906fd68ae623/msmpisetup.exe'
+} else {
+ Write-Host 'Downloading from vcpkgimageminting using SAS token'
+ $SasToken = $SasToken.Replace('"', '')
+ $MpiUrl = "https://vcpkgimageminting.blob.core.windows.net/assets/msmpisetup.exe?$SasToken"
+}
+
+DownloadAndInstall -Name 'MSMPI' -Url $MpiUrl -Args @('-force', '-unattend')
diff --git a/vcpkg/scripts/azure-pipelines/windows/deploy-pwsh.ps1 b/vcpkg/scripts/azure-pipelines/windows/deploy-pwsh.ps1
new file mode 100644
index 0000000..94b05e3
--- /dev/null
+++ b/vcpkg/scripts/azure-pipelines/windows/deploy-pwsh.ps1
@@ -0,0 +1,20 @@
+# Copyright (c) Microsoft Corporation.
+# SPDX-License-Identifier: MIT
+
+param([string]$SasToken)
+
+if (Test-Path "$PSScriptRoot/utility-prefix.ps1") {
+ . "$PSScriptRoot/utility-prefix.ps1"
+}
+
+[string]$PwshUrl
+if ([string]::IsNullOrEmpty($SasToken)) {
+ Write-Host 'Downloading from the Internet'
+ $PwshUrl = 'https://github.com/PowerShell/PowerShell/releases/download/v7.5.3/PowerShell-7.5.3-win-x64.msi'
+} else {
+ Write-Host 'Downloading from vcpkgimageminting using SAS token'
+ $SasToken = $SasToken.Replace('"', '')
+ $PwshUrl = "https://vcpkgimageminting.blob.core.windows.net/assets/PowerShell-7.5.3-win-x64.msi?$SasToken"
+}
+
+DownloadAndInstall -Url $PwshUrl -Name 'PowerShell Core' -Args @('/quiet', '/norestart')
diff --git a/vcpkg/scripts/azure-pipelines/windows/deploy-settings.txt b/vcpkg/scripts/azure-pipelines/windows/deploy-settings.txt
new file mode 100644
index 0000000..102aafe
--- /dev/null
+++ b/vcpkg/scripts/azure-pipelines/windows/deploy-settings.txt
@@ -0,0 +1,20 @@
+# Copyright (c) Microsoft Corporation.
+# SPDX-License-Identifier: MIT
+
+$ErrorActionPreference = 'Stop'
+$ProgressPreference = 'SilentlyContinue'
+
+$av = Get-Command Add-MPPreference -ErrorAction SilentlyContinue
+if ($null -eq $av) {
+ Write-Host 'AntiVirus not installed, skipping exclusions.'
+} else {
+ Write-Host 'Configuring AntiVirus exclusions...'
+ Add-MpPreference -ExclusionPath C:\agent
+ Add-MPPreference -ExclusionPath D:\
+ Add-MPPreference -ExclusionPath E:\
+ Add-MPPreference -ExclusionProcess ninja.exe
+ Add-MPPreference -ExclusionProcess clang-cl.exe
+ Add-MPPreference -ExclusionProcess cl.exe
+ Add-MPPreference -ExclusionProcess link.exe
+ Add-MPPreference -ExclusionProcess python.exe
+}
diff --git a/vcpkg/scripts/azure-pipelines/windows/deploy-tlssettings.ps1 b/vcpkg/scripts/azure-pipelines/windows/deploy-tlssettings.ps1
new file mode 100644
index 0000000..94e3732
--- /dev/null
+++ b/vcpkg/scripts/azure-pipelines/windows/deploy-tlssettings.ps1
@@ -0,0 +1,738 @@
+#***************************************************************************************************************
+# This script supports the TLS 1.2 everywhere project
+# It does the following:
+# * By default it disables TLS 1.O, TLS 1.1, SSLv2, SSLv3 and Enables TLS1.2
+# * The CipherSuite order is set to the SDL approved version.
+# * The FIPS MinEncryptionLevel is set to 3.
+# * RC4 is disabled
+# * A log with a transcript of all actions taken is generated
+#***************************************************************************************************************
+
+#************************************************ SCRIPT USAGE ************************************************
+# .\TLSSettings.ps1
+# -SetCipherOrder : Excellence/Min-Bar, default(Excellence), use B to set Min-Bar. (Min-Bar ordering prefers ciphers with smaller key sizes to improve performance over security)
+# -RebootIfRequired : $true/$false, default($true), use $false to disable auto-reboot (Settings won't take effect until a reboot is completed)
+# -EnableOlderTlsVersions : $true/$false, default($false), use $true to explicitly Enable TLS1.0, TLS1.1
+#***************************************************************************************************************
+
+#***************************TEAM CAN DETERMINE WHAT CIPHER SUITE ORDER IS CHOSEN ******************************
+# Option B provides the min-bar configuration (small trade-off: performance over security)
+# Syntax: .\TLSSettings.ps1 -SetCipherOrder B
+# if no option is supplied, you will get the opportunity for excellence cipher order (small trade-off: security over performance)
+# Syntax: .\TLSSettings.ps1
+#***************************************************************************************************************
+
+param (
+ [string]$SetCipherOrder = " ",
+ [bool]$RebootIfRequired = $true,
+ [bool]$EnableOlderTlsVersions = $false
+)
+
+#******************* FUNCTION THAT ACTUALLY UPDATES KEYS; WILL RETURN REBOOT FLAG IF CHANGES ***********************
+Function Set-CryptoSetting {
+ param (
+ $regKeyName,
+ $value,
+ $valuedata,
+ $valuetype
+ )
+
+ $restart = $false
+
+ # Check for existence of registry key, and create if it does not exist
+ If (!(Test-Path -Path $regKeyName)) {
+ New-Item $regKeyName | Out-Null
+ }
+
+
+ # Get data of registry value, or null if it does not exist
+ $val = (Get-ItemProperty -Path $regKeyName -Name $value -ErrorAction SilentlyContinue).$value
+
+
+ If ($val -eq $null) {
+ # Value does not exist - create and set to desired value
+ New-ItemProperty -Path $regKeyName -Name $value -Value $valuedata -PropertyType $valuetype | Out-Null
+ $restart = $true
+ }
+ Else {
+ # Value does exist - if not equal to desired value, change it
+ If ($val -ne $valuedata) {
+ Set-ItemProperty -Path $regKeyName -Name $value -Value $valuedata
+ $restart = $true
+ }
+ }
+
+
+ $restart
+}
+#***************************************************************************************************************
+
+
+#******************* FUNCTION THAT DISABLES RC4 ***********************
+Function DisableRC4 {
+
+ $restart = $false
+ $subkeys = Get-Item -Path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL"
+ $ciphers = $subkeys.OpenSubKey("Ciphers", $true)
+
+ Write-Log -Message "----- Checking the status of RC4 -----" -Logfile $logLocation -Severity Information
+
+ $RC4 = $false
+ if ($ciphers.SubKeyCount -eq 0) {
+ $k1 = $ciphers.CreateSubKey("RC4 128/128")
+ $k1.SetValue("Enabled", 0, [Microsoft.Win32.RegistryValueKind]::DWord)
+ $restart = $true
+ $k2 = $ciphers.CreateSubKey("RC4 64/128")
+ $k2.SetValue("Enabled", 0, [Microsoft.Win32.RegistryValueKind]::DWord)
+ $k3 = $ciphers.CreateSubKey("RC4 56/128")
+ $k3.SetValue("Enabled", 0, [Microsoft.Win32.RegistryValueKind]::DWord)
+ $k4 = $ciphers.CreateSubKey("RC4 40/128")
+ $k4.SetValue("Enabled", 0, [Microsoft.Win32.RegistryValueKind]::DWord)
+
+ Write-Log -Message "RC4 was disabled " -Logfile $logLocation -Severity Information
+ $RC4 = $true
+ }
+
+ If ($RC4 -ne $true) {
+ Write-Log -Message "There was no change for RC4 " -Logfile $logLocation -Severity Information
+ }
+
+ $restart
+}
+#***************************************************************************************************************
+
+#******************* FUNCTION CHECKS FOR PROBLEMATIC FIPS SETTING AND FIXES IT ***********************
+Function Test-RegistryValueForFipsSettings {
+
+ $restart = $false
+
+ $fipsPath = @(
+ "HKLM:\System\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp",
+ "HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services",
+ "HKLM:\System\CurrentControlSet\Control\Terminal Server\DefaultUserConfiguration"
+ )
+
+ $fipsValue = "MinEncryptionLevel"
+
+
+ foreach ($path in $fipsPath) {
+
+ Write-Log -Message "Checking to see if $($path)\$fipsValue exists" -Logfile $logLocation -Severity Information
+
+ $ErrorActionPreference = "stop"
+ Try {
+
+ $result = Get-ItemProperty -Path $path | Select-Object -ExpandProperty $fipsValue
+ if ($result -eq 4) {
+ set-itemproperty -Path $path -Name $fipsValue -value 3
+ Write-Log -Message "Regkey $($path)\$fipsValue was changed from value $result to a value of 3" -Logfile $logLocation -Severity Information
+ $restart = $true
+ }
+ else {
+ Write-Log -Message "Regkey $($path)\$fipsValue left at value $result" -Logfile $logLocation -Severity Information
+ }
+
+ }
+ Catch [System.Management.Automation.ItemNotFoundException] {
+
+ Write-Log -Message "Reg path $path was not found" -Logfile $logLocation -Severity Information
+ }
+ Catch [System.Management.Automation.PSArgumentException] {
+
+ Write-Log -Message "Regkey $($path)\$fipsValue was not found" -Logfile $logLocation -Severity Information
+ }
+ Catch {
+ Write-Log -Message "Error of type $($Error[0].Exception.GetType().FullName) trying to get $($path)\$fipsValue" -Logfile $logLocation -Severity Information
+ }
+ Finally {$ErrorActionPreference = "Continue"
+ }
+ }
+ $restart
+}
+#***************************************************************************************************************
+
+#********************************** FUNCTION THAT CREATE LOG DIRECTORY IF IT DOES NOT EXIST *******************************
+function CreateLogDirectory {
+
+ $TARGETDIR = "$env:HOMEDRIVE\Logs"
+ if ( -Not (Test-Path -Path $TARGETDIR ) ) {
+ New-Item -ItemType directory -Path $TARGETDIR | Out-Null
+ }
+
+ $TARGETDIR = $TARGETDIR + "\" + "TLSSettingsLogFile.csv"
+
+ return $TARGETDIR
+}
+#***************************************************************************************************************
+
+
+#********************************** FUNCTION THAT LOGS WHAT THE SCRIPT IS DOING *******************************
+function Write-Log {
+ [CmdletBinding()]
+ param(
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [string]$Message,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [string]$LogFile,
+
+ [Parameter()]
+ [ValidateNotNullOrEmpty()]
+ [ValidateSet('Information', 'Warning', 'Error')]
+ [string]$Severity = 'Information'
+ )
+
+
+ [pscustomobject]@{
+ Time = (Get-Date -f g)
+ Message = $Message
+ Severity = $Severity
+ } | ConvertTo-Csv -NoTypeInformation | Select-Object -Skip 1 | Out-File -Append -FilePath $LogFile
+}
+
+#********************************TLS CipherSuite Settings *******************************************
+
+# CipherSuites for windows OS < 10
+function Get-BaseCipherSuitesOlderWindows()
+{
+ param
+ (
+ [Parameter(Mandatory=$true, Position=0)][bool] $isExcellenceOrder
+ )
+ $cipherorder = @()
+
+ if ($isExcellenceOrder -eq $true)
+ {
+ $cipherorder += "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384_P384"
+ $cipherorder += "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256_P256"
+ $cipherorder += "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384_P384"
+ $cipherorder += "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256_P256"
+ $cipherorder += "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P384"
+ $cipherorder += "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256"
+ }
+ else
+ {
+ $cipherorder += "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256_P256"
+ $cipherorder += "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384_P384"
+ $cipherorder += "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256_P256"
+ $cipherorder += "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384_P384"
+ $cipherorder += "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256"
+ $cipherorder += "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P384"
+ }
+
+ # Add additional ciphers when EnableOlderTlsVersions flag is set to true
+ if ($EnableOlderTlsVersions)
+ {
+ $cipherorder += "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA_P256"
+ $cipherorder += "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA_P256"
+ $cipherorder += "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA_P256"
+ $cipherorder += "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA_P256"
+ $cipherorder += "TLS_RSA_WITH_AES_256_GCM_SHA384"
+ $cipherorder += "TLS_RSA_WITH_AES_128_GCM_SHA256"
+ $cipherorder += "TLS_RSA_WITH_AES_256_CBC_SHA256"
+ $cipherorder += "TLS_RSA_WITH_AES_128_CBC_SHA256"
+ $cipherorder += "TLS_RSA_WITH_AES_256_CBC_SHA"
+ $cipherorder += "TLS_RSA_WITH_AES_128_CBC_SHA"
+ }
+ return $cipherorder
+}
+
+# Ciphersuites needed for backwards compatibility with Firefox, Chrome
+# Server 2012 R2 doesn't support TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
+# Both firefox and chrome negotiate ECDHE_RSA_AES_256_CBC_SHA1, Edge negotiates ECDHE_RSA_AES_256_CBC_SHA384
+function Get-BrowserCompatCipherSuitesOlderWindows()
+{
+ param
+ (
+ [Parameter(Mandatory=$true, Position=0)][bool] $isExcellenceOrder
+ )
+ $cipherorder = @()
+
+ if ($isExcellenceOrder -eq $true)
+ {
+ $cipherorder += "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA_P384" # (uses SHA-1)
+ $cipherorder += "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA_P256" # (uses SHA-1)
+ }
+ else
+ {
+ $cipherorder += "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA_P256" # (uses SHA-1)
+ $cipherorder += "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA_P384" # (uses SHA-1)
+ }
+ return $cipherorder
+}
+
+# Ciphersuites for OS versions windows 10 and above
+function Get-BaseCipherSuitesWin10Above()
+{
+ param
+ (
+ [Parameter(Mandatory=$true, Position=0)][bool] $isExcellenceOrder
+ )
+
+ $cipherorder = @()
+
+ if ($isExcellenceOrder -eq $true)
+ {
+
+ $cipherorder += "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"
+ $cipherorder += "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"
+ $cipherorder += "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"
+ $cipherorder += "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
+ $cipherorder += "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384"
+ $cipherorder += "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256"
+ $cipherorder += "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384"
+ $cipherorder += "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256"
+ }
+ else
+ {
+ $cipherorder += "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"
+ $cipherorder += "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"
+ $cipherorder += "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
+ $cipherorder += "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"
+ $cipherorder += "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256"
+ $cipherorder += "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384"
+ $cipherorder += "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256"
+ $cipherorder += "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384"
+ }
+ # Add additional ciphers when EnableOlderTlsVersions flag is set to true
+ if ($EnableOlderTlsVersions)
+ {
+ $cipherorder += "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA_P256"
+ $cipherorder += "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA_P256"
+ $cipherorder += "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA_P256"
+ $cipherorder += "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA_P256"
+ $cipherorder += "TLS_RSA_WITH_AES_256_GCM_SHA384"
+ $cipherorder += "TLS_RSA_WITH_AES_128_GCM_SHA256"
+ $cipherorder += "TLS_RSA_WITH_AES_256_CBC_SHA256"
+ $cipherorder += "TLS_RSA_WITH_AES_128_CBC_SHA256"
+ $cipherorder += "TLS_RSA_WITH_AES_256_CBC_SHA"
+ $cipherorder += "TLS_RSA_WITH_AES_128_CBC_SHA"
+ }
+
+ return $cipherorder
+}
+
+
+#******************************* TLS Version Settings ****************************************************
+
+function Get-RegKeyPathForTls12()
+{
+ $regKeyPath = @(
+ "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2",
+ "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Client",
+ "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Server"
+ )
+ return $regKeyPath
+}
+
+function Get-RegKeyPathForTls11()
+{
+ $regKeyPath = @(
+ "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.1",
+ "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.1\Client",
+ "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.1\Server"
+ )
+ return $regKeyPath
+}
+
+function Get-RegKeypathForTls10()
+{
+ $regKeyPath = @(
+ "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.0",
+ "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.0\Client",
+ "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.0\Server"
+ )
+ return $regKeyPath
+}
+
+function Get-RegKeyPathForSsl30()
+{
+ $regKeyPath = @(
+ "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 3.0",
+ "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 3.0\Client",
+ "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 3.0\Server"
+ )
+ return $regKeyPath
+}
+
+function Get-RegKeyPathForSsl20()
+{
+ $regKeyPath = @(
+ "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 2.0",
+ "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 2.0\Client",
+ "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 2.0\Server"
+ )
+ return $regKeyPath
+}
+
+#Initialize reboot value to false
+$reboot = $false
+
+#*****************************Create the logfile if not does not exist***************************************
+$logLocation = CreateLogDirectory
+
+
+#Start writing to the logs
+Write-Log -Message "========== Start of logging for a script execution ==========" -Logfile $logLocation -Severity Information
+
+$registryPathGoodGuys = @()
+$registryPathBadGuys = @()
+
+# we enable TLS 1.2 and disable SSL 2.0, 3.0 in any case
+$registryPathGoodGuys += Get-RegKeyPathForTls12
+
+$registryPathBadGuys += Get-RegKeyPathForSsl20
+$registryPathBadGuys += Get-RegKeyPathForSsl30
+
+# add TLS 1.0/1.1 to good/bad depending on user's preference
+# default is adding TLS 1.0/1.1 to bad
+if ($EnableOlderTlsVersions)
+{
+ $registryPathGoodGuys += Get-RegKeypathForTls10
+ $registryPathGoodGuys += Get-RegKeyPathForTls11
+ Write-Log -Message "Enabling TLS1.2, TLS1.1, TLS1.0. Disabling SSL3.0, SSL2.0" -Logfile $logLocation -Severity Information
+}
+else
+{
+ $registryPathBadGuys += Get-RegKeypathForTls10
+ $registryPathBadGuys += Get-RegKeyPathForTls11
+ Write-Log -Message "Enabling TLS1.2. Disabling TLS1.1, TLS1.0, SSL3.0, SSL2.0" -Logfile $logLocation -Severity Information
+}
+
+
+Write-Log -Message "Check which registry keys exist already and which registry keys need to be created." -Logfile $logLocation -Severity Information
+
+#******************* CREATE THE REGISTRY KEYS IF THEY DON'T EXIST********************************
+# Check for existence of GoodGuy registry keys, and create if they do not exist
+For ($i = 0; $i -lt $registryPathGoodGuys.Length; $i = $i + 1) {
+
+ Write-Log -Message "Checking for existing of key: $($registryPathGoodGuys[$i]) " -Logfile $logLocation -Severity Information
+ If (!(Test-Path -Path $registryPathGoodGuys[$i])) {
+ New-Item $registryPathGoodGuys[$i] | Out-Null
+ Write-Log -Message "Creating key: $($registryPathGoodGuys[$i]) " -Logfile $logLocation -Severity Information
+ }
+}
+
+# Check for existence of BadGuy registry keys, and create if they do not exist
+For ($i = 0; $i -lt $registryPathBadGuys.Length; $i = $i + 1) {
+
+ Write-Log -Message "Checking for existing of key: $($registryPathBadGuys[$i]) " -Logfile $logLocation -Severity Information
+ If (!(Test-Path -Path $registryPathBadGuys[$i])) {
+ Write-Log -Message "Creating key: $($registryPathBadGuys[$i]) " -Logfile $logLocation -Severity Information
+ New-Item $registryPathBadGuys[$i] | Out-Null
+ }
+}
+
+#******************* EXPLICITLY DISABLE SSLV2, SSLV3, TLS10 AND TLS11 ********************************
+For ($i = 0; $i -lt $registryPathBadGuys.Length; $i = $i + 1) {
+
+ if ($registryPathBadGuys[$i].Contains("Client") -Or $registryPathBadGuys[$i].Contains("Server")) {
+
+ Write-Log -Message "Disabling this key: $($registryPathBadGuys[$i]) " -Logfile $logLocation -Severity Information
+ $result = Set-CryptoSetting $registryPathBadGuys[$i].ToString() Enabled 0 DWord
+ $result = Set-CryptoSetting $registryPathBadGuys[$i].ToString() DisabledByDefault 1 DWord
+ $reboot = $reboot -or $result
+ }
+}
+
+#********************************* EXPLICITLY Enable TLS12 ****************************************
+For ($i = 0; $i -lt $registryPathGoodGuys.Length; $i = $i + 1) {
+
+ if ($registryPathGoodGuys[$i].Contains("Client") -Or $registryPathGoodGuys[$i].Contains("Server")) {
+
+ Write-Log -Message "Enabling this key: $($registryPathGoodGuys[$i]) " -Logfile $logLocation -Severity Information
+ $result = Set-CryptoSetting $registryPathGoodGuys[$i].ToString() Enabled 1 DWord
+ $result = Set-CryptoSetting $registryPathGoodGuys[$i].ToString() DisabledByDefault 0 DWord
+ $reboot = $reboot -or $result
+ }
+}
+
+#************************************** Disable RC4 ************************************************
+$result = DisableRC4
+$reboot = $reboot -or $result
+
+
+#************************************** Set Cipher Suite Order **************************************
+Write-Log -Message "----- starting ciphersuite order calculation -----" -Logfile $logLocation -Severity Information
+$configureExcellenceOrder = $true
+if ($SetCipherOrder.ToUpper() -eq "B")
+{
+ $configureExcellenceOrder = $false
+ Write-Host "The min bar cipher suite order was chosen."
+ Write-Log -Message "The min bar cipher suite order was chosen." -Logfile $logLocation -Severity Information
+}
+else
+{
+ Write-Host "The opportunity for excellence cipher suite order was chosen."
+ Write-Log -Message "The opportunity for excellence cipher suite order was chosen." -Logfile $logLocation -Severity Information
+}
+$cipherlist = @()
+
+if ([Environment]::OSVersion.Version.Major -lt 10)
+{
+ $cipherlist += Get-BaseCipherSuitesOlderWindows -isExcellenceOrder $configureExcellenceOrder
+ $cipherlist += Get-BrowserCompatCipherSuitesOlderWindows -isExcellenceOrder $configureExcellenceOrder
+}
+else
+{
+ $cipherlist += Get-BaseCipherSuitesWin10Above -isExcellenceOrder $configureExcellenceOrder
+}
+$cipherorder = [System.String]::Join(",", $cipherlist)
+ Write-Host "Appropriate ciphersuite order : $cipherorder"
+ Write-Log -Message "Appropriate ciphersuite order : $cipherorder" -Logfile $logLocation -Severity Information
+
+$CipherSuiteRegKey = "HKLM:\SOFTWARE\Policies\Microsoft\Cryptography\Configuration\SSL\00010002"
+
+if (!(Test-Path -Path $CipherSuiteRegKey))
+{
+ New-Item $CipherSuiteRegKey | Out-Null
+ $reboot = $True
+ Write-Log -Message "Creating key: $($CipherSuiteRegKey) " -Logfile $logLocation -Severity Information
+}
+
+$val = (Get-Item -Path $CipherSuiteRegKey -ErrorAction SilentlyContinue).GetValue("Functions", $null)
+Write-Log -Message "Previous cipher suite value: $val " -Logfile $logLocation -Severity Information
+Write-Log -Message "New cipher suite value : $cipherorder " -Logfile $logLocation -Severity Information
+
+if ($val -ne $cipherorder)
+{
+ Write-Log -Message "Cipher suite order needs to be updated. " -Logfile $logLocation -Severity Information
+ Write-Host "The original cipher suite order needs to be updated", `n, $val
+ Set-ItemProperty -Path $CipherSuiteRegKey -Name Functions -Value $cipherorder
+ Write-Log -Message "Cipher suite value was updated. " -Logfile $logLocation -Severity Information
+ $reboot = $True
+}
+else
+{
+ Write-Log -Message "Cipher suite order does not need to be updated. " -Logfile $logLocation -Severity Information
+ Write-Log -Message "Cipher suite value was not updated as there was no change. " -Logfile $logLocation -Severity Information
+}
+
+#****************************** CHECK THE FIPS SETTING WHICH IMPACTS RDP'S ALLOWED CIPHERS **************************
+#Check for FipsSettings
+Write-Log -Message "Checking to see if reg keys exist and if MinEncryptionLevel is set to 4" -Logfile $logLocation -Severity Information
+$result = Test-RegistryValueForFipsSettings
+$reboot = $reboot -or $result
+
+
+#************************************** REBOOT **************************************
+
+if ($RebootIfRequired)
+{
+ Write-Log -Message "You set the RebootIfRequired flag to true. If changes are made, the system will reboot " -Logfile $logLocation -Severity Information
+ # If any settings were changed, reboot
+ If ($reboot)
+ {
+ Write-Log -Message "Rebooting now... " -Logfile $logLocation -Severity Information
+ Write-Log -Message "Using this command: shutdown.exe /r /t 5 /c ""Crypto settings changed"" /f /d p:2:4 " -Logfile $logLocation -Severity Information
+ Write-Host "Rebooting now..."
+ shutdown.exe /r /t 5 /c "Crypto settings changed" /f /d p:2:4
+ }
+ Else
+ {
+ Write-Host "Nothing get updated."
+ Write-Log -Message "Nothing get updated. " -Logfile $logLocation -Severity Information
+ }
+}
+else
+{
+
+ Write-Log -Message "You set the RebootIfRequired flag to false. If changes are made, the system will NOT reboot " -Logfile $logLocation -Severity Information
+ Write-Log -Message "No changes will take effect until a reboot has been completed. " -Logfile $logLocation -Severity Information
+ Write-Log -Message "Script does not include a reboot by design" -Logfile $logLocation -Severity Information
+}
+Write-Log -Message "========== End of logging for a script execution ==========" -Logfile $logLocation -Severity Information
+# SIG # Begin signature block
+# MIIjhgYJKoZIhvcNAQcCoIIjdzCCI3MCAQExDzANBglghkgBZQMEAgEFADB5Bgor
+# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
+# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCAHtlEJwNffjnOP
+# Sr2t1yq5EfE0ll4GozyZt3UXO9BXKKCCDYEwggX/MIID56ADAgECAhMzAAABh3IX
+# chVZQMcJAAAAAAGHMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD
+# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
+# b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p
+# bmcgUENBIDIwMTEwHhcNMjAwMzA0MTgzOTQ3WhcNMjEwMzAzMTgzOTQ3WjB0MQsw
+# CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u
+# ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy
+# b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
+# AQDOt8kLc7P3T7MKIhouYHewMFmnq8Ayu7FOhZCQabVwBp2VS4WyB2Qe4TQBT8aB
+# znANDEPjHKNdPT8Xz5cNali6XHefS8i/WXtF0vSsP8NEv6mBHuA2p1fw2wB/F0dH
+# sJ3GfZ5c0sPJjklsiYqPw59xJ54kM91IOgiO2OUzjNAljPibjCWfH7UzQ1TPHc4d
+# weils8GEIrbBRb7IWwiObL12jWT4Yh71NQgvJ9Fn6+UhD9x2uk3dLj84vwt1NuFQ
+# itKJxIV0fVsRNR3abQVOLqpDugbr0SzNL6o8xzOHL5OXiGGwg6ekiXA1/2XXY7yV
+# Fc39tledDtZjSjNbex1zzwSXAgMBAAGjggF+MIIBejAfBgNVHSUEGDAWBgorBgEE
+# AYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQUhov4ZyO96axkJdMjpzu2zVXOJcsw
+# UAYDVR0RBEkwR6RFMEMxKTAnBgNVBAsTIE1pY3Jvc29mdCBPcGVyYXRpb25zIFB1
+# ZXJ0byBSaWNvMRYwFAYDVQQFEw0yMzAwMTIrNDU4Mzg1MB8GA1UdIwQYMBaAFEhu
+# ZOVQBdOCqhc3NyK1bajKdQKVMFQGA1UdHwRNMEswSaBHoEWGQ2h0dHA6Ly93d3cu
+# bWljcm9zb2Z0LmNvbS9wa2lvcHMvY3JsL01pY0NvZFNpZ1BDQTIwMTFfMjAxMS0w
+# Ny0wOC5jcmwwYQYIKwYBBQUHAQEEVTBTMFEGCCsGAQUFBzAChkVodHRwOi8vd3d3
+# Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NlcnRzL01pY0NvZFNpZ1BDQTIwMTFfMjAx
+# MS0wNy0wOC5jcnQwDAYDVR0TAQH/BAIwADANBgkqhkiG9w0BAQsFAAOCAgEAixmy
+# S6E6vprWD9KFNIB9G5zyMuIjZAOuUJ1EK/Vlg6Fb3ZHXjjUwATKIcXbFuFC6Wr4K
+# NrU4DY/sBVqmab5AC/je3bpUpjtxpEyqUqtPc30wEg/rO9vmKmqKoLPT37svc2NV
+# BmGNl+85qO4fV/w7Cx7J0Bbqk19KcRNdjt6eKoTnTPHBHlVHQIHZpMxacbFOAkJr
+# qAVkYZdz7ikNXTxV+GRb36tC4ByMNxE2DF7vFdvaiZP0CVZ5ByJ2gAhXMdK9+usx
+# zVk913qKde1OAuWdv+rndqkAIm8fUlRnr4saSCg7cIbUwCCf116wUJ7EuJDg0vHe
+# yhnCeHnBbyH3RZkHEi2ofmfgnFISJZDdMAeVZGVOh20Jp50XBzqokpPzeZ6zc1/g
+# yILNyiVgE+RPkjnUQshd1f1PMgn3tns2Cz7bJiVUaqEO3n9qRFgy5JuLae6UweGf
+# AeOo3dgLZxikKzYs3hDMaEtJq8IP71cX7QXe6lnMmXU/Hdfz2p897Zd+kU+vZvKI
+# 3cwLfuVQgK2RZ2z+Kc3K3dRPz2rXycK5XCuRZmvGab/WbrZiC7wJQapgBodltMI5
+# GMdFrBg9IeF7/rP4EqVQXeKtevTlZXjpuNhhjuR+2DMt/dWufjXpiW91bo3aH6Ea
+# jOALXmoxgltCp1K7hrS6gmsvj94cLRf50QQ4U8Qwggd6MIIFYqADAgECAgphDpDS
+# AAAAAAADMA0GCSqGSIb3DQEBCwUAMIGIMQswCQYDVQQGEwJVUzETMBEGA1UECBMK
+# V2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0
+# IENvcnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3NvZnQgUm9vdCBDZXJ0aWZpY2F0
+# ZSBBdXRob3JpdHkgMjAxMTAeFw0xMTA3MDgyMDU5MDlaFw0yNjA3MDgyMTA5MDla
+# MH4xCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdS
+# ZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMT
+# H01pY3Jvc29mdCBDb2RlIFNpZ25pbmcgUENBIDIwMTEwggIiMA0GCSqGSIb3DQEB
+# AQUAA4ICDwAwggIKAoICAQCr8PpyEBwurdhuqoIQTTS68rZYIZ9CGypr6VpQqrgG
+# OBoESbp/wwwe3TdrxhLYC/A4wpkGsMg51QEUMULTiQ15ZId+lGAkbK+eSZzpaF7S
+# 35tTsgosw6/ZqSuuegmv15ZZymAaBelmdugyUiYSL+erCFDPs0S3XdjELgN1q2jz
+# y23zOlyhFvRGuuA4ZKxuZDV4pqBjDy3TQJP4494HDdVceaVJKecNvqATd76UPe/7
+# 4ytaEB9NViiienLgEjq3SV7Y7e1DkYPZe7J7hhvZPrGMXeiJT4Qa8qEvWeSQOy2u
+# M1jFtz7+MtOzAz2xsq+SOH7SnYAs9U5WkSE1JcM5bmR/U7qcD60ZI4TL9LoDho33
+# X/DQUr+MlIe8wCF0JV8YKLbMJyg4JZg5SjbPfLGSrhwjp6lm7GEfauEoSZ1fiOIl
+# XdMhSz5SxLVXPyQD8NF6Wy/VI+NwXQ9RRnez+ADhvKwCgl/bwBWzvRvUVUvnOaEP
+# 6SNJvBi4RHxF5MHDcnrgcuck379GmcXvwhxX24ON7E1JMKerjt/sW5+v/N2wZuLB
+# l4F77dbtS+dJKacTKKanfWeA5opieF+yL4TXV5xcv3coKPHtbcMojyyPQDdPweGF
+# RInECUzF1KVDL3SV9274eCBYLBNdYJWaPk8zhNqwiBfenk70lrC8RqBsmNLg1oiM
+# CwIDAQABo4IB7TCCAekwEAYJKwYBBAGCNxUBBAMCAQAwHQYDVR0OBBYEFEhuZOVQ
+# BdOCqhc3NyK1bajKdQKVMBkGCSsGAQQBgjcUAgQMHgoAUwB1AGIAQwBBMAsGA1Ud
+# DwQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFHItOgIxkEO5FAVO
+# 4eqnxzHRI4k0MFoGA1UdHwRTMFEwT6BNoEuGSWh0dHA6Ly9jcmwubWljcm9zb2Z0
+# LmNvbS9wa2kvY3JsL3Byb2R1Y3RzL01pY1Jvb0NlckF1dDIwMTFfMjAxMV8wM18y
+# Mi5jcmwwXgYIKwYBBQUHAQEEUjBQME4GCCsGAQUFBzAChkJodHRwOi8vd3d3Lm1p
+# Y3Jvc29mdC5jb20vcGtpL2NlcnRzL01pY1Jvb0NlckF1dDIwMTFfMjAxMV8wM18y
+# Mi5jcnQwgZ8GA1UdIASBlzCBlDCBkQYJKwYBBAGCNy4DMIGDMD8GCCsGAQUFBwIB
+# FjNodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2RvY3MvcHJpbWFyeWNw
+# cy5odG0wQAYIKwYBBQUHAgIwNB4yIB0ATABlAGcAYQBsAF8AcABvAGwAaQBjAHkA
+# XwBzAHQAYQB0AGUAbQBlAG4AdAAuIB0wDQYJKoZIhvcNAQELBQADggIBAGfyhqWY
+# 4FR5Gi7T2HRnIpsLlhHhY5KZQpZ90nkMkMFlXy4sPvjDctFtg/6+P+gKyju/R6mj
+# 82nbY78iNaWXXWWEkH2LRlBV2AySfNIaSxzzPEKLUtCw/WvjPgcuKZvmPRul1LUd
+# d5Q54ulkyUQ9eHoj8xN9ppB0g430yyYCRirCihC7pKkFDJvtaPpoLpWgKj8qa1hJ
+# Yx8JaW5amJbkg/TAj/NGK978O9C9Ne9uJa7lryft0N3zDq+ZKJeYTQ49C/IIidYf
+# wzIY4vDFLc5bnrRJOQrGCsLGra7lstnbFYhRRVg4MnEnGn+x9Cf43iw6IGmYslmJ
+# aG5vp7d0w0AFBqYBKig+gj8TTWYLwLNN9eGPfxxvFX1Fp3blQCplo8NdUmKGwx1j
+# NpeG39rz+PIWoZon4c2ll9DuXWNB41sHnIc+BncG0QaxdR8UvmFhtfDcxhsEvt9B
+# xw4o7t5lL+yX9qFcltgA1qFGvVnzl6UJS0gQmYAf0AApxbGbpT9Fdx41xtKiop96
+# eiL6SJUfq/tHI4D1nvi/a7dLl+LrdXga7Oo3mXkYS//WsyNodeav+vyL6wuA6mk7
+# r/ww7QRMjt/fdW1jkT3RnVZOT7+AVyKheBEyIXrvQQqxP/uozKRdwaGIm1dxVk5I
+# RcBCyZt2WwqASGv9eZ/BvW1taslScxMNelDNMYIVWzCCFVcCAQEwgZUwfjELMAkG
+# A1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQx
+# HjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEoMCYGA1UEAxMfTWljcm9z
+# b2Z0IENvZGUgU2lnbmluZyBQQ0EgMjAxMQITMwAAAYdyF3IVWUDHCQAAAAABhzAN
+# BglghkgBZQMEAgEFAKCBrjAZBgkqhkiG9w0BCQMxDAYKKwYBBAGCNwIBBDAcBgor
+# BgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAvBgkqhkiG9w0BCQQxIgQgOQvu7NUq
+# wmve+qCoalj/s9HX5Hz9/zYISdJyOFTC4FIwQgYKKwYBBAGCNwIBDDE0MDKgFIAS
+# AE0AaQBjAHIAbwBzAG8AZgB0oRqAGGh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbTAN
+# BgkqhkiG9w0BAQEFAASCAQAHbtGz0AChe0qMPM3c7iU8BQCfJklePUlAlhwFSuCx
+# careoloxao+ZtS+dQRlrxLu/ZSqtmJHNsyRoWzsHdOs65pwUYhV3svzaXd7pJwkc
+# nbDXedLBbNuQrQrrL2xbGtzT3U+EwgpJ1TTEYwHgqkTFogIelGa2sjD5N+4Vvalq
+# t+vxaYrWwkTtsm0qczLKGRUjJqCjARjviE1xsOvs4zwbpXx/bEs/6M7U9tR+w/DS
+# nDY/5KAKYET0DCVDhmsMmzJi3xXdBr4sAz0484AAB0CIRVgPCgdgr8E0NQUESJzm
+# xm3K4bMAgTMWRiGTL4MRYSuMIn09sbfYXP9hjXLvTV4YoYIS5TCCEuEGCisGAQQB
+# gjcDAwExghLRMIISzQYJKoZIhvcNAQcCoIISvjCCEroCAQMxDzANBglghkgBZQME
+# AgEFADCCAVEGCyqGSIb3DQEJEAEEoIIBQASCATwwggE4AgEBBgorBgEEAYRZCgMB
+# MDEwDQYJYIZIAWUDBAIBBQAEIJBynrmlQmGS0UNGTk53HVKEc4aHvNdYrs5eCcHM
+# puc5AgZfEgElnvMYEzIwMjAwNzI0MTgwNDM3Ljg3NlowBIACAfSggdCkgc0wgcox
+# CzAJBgNVBAYTAlVTMQswCQYDVQQIEwJXQTEQMA4GA1UEBxMHUmVkbW9uZDEeMBwG
+# A1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMS0wKwYDVQQLEyRNaWNyb3NvZnQg
+# SXJlbGFuZCBPcGVyYXRpb25zIExpbWl0ZWQxJjAkBgNVBAsTHVRoYWxlcyBUU1Mg
+# RVNOOkUwNDEtNEJFRS1GQTdFMSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFt
+# cCBzZXJ2aWNloIIOPDCCBPEwggPZoAMCAQICEzMAAAEHfjdomIdaN9YAAAAAAQcw
+# DQYJKoZIhvcNAQELBQAwfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0
+# b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3Jh
+# dGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIwMTAwHhcN
+# MTkxMDA4MTczODM1WhcNMjEwMTAzMTczODM1WjCByjELMAkGA1UEBhMCVVMxCzAJ
+# BgNVBAgTAldBMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQg
+# Q29ycG9yYXRpb24xLTArBgNVBAsTJE1pY3Jvc29mdCBJcmVsYW5kIE9wZXJhdGlv
+# bnMgTGltaXRlZDEmMCQGA1UECxMdVGhhbGVzIFRTUyBFU046RTA0MS00QkVFLUZB
+# N0UxJTAjBgNVBAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIHNlcnZpY2UwggEiMA0G
+# CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDUuqOUlbaeWirgwbCwhhNIOqTshpo+
+# QdSYxAt9JnkeulQFeKrQ6rOSECXxwgOjL/TNMIXtkig1MaifFON6si/Ri+AsV8Gu
+# rQp4fylJzLDMFdJcGSpV3CGRdpDb0au8kNQLmnZuxLxAL91R7//3mH2QDQI20w3G
+# 06s+Xv8+js9wQksXAfclXX1TJoBIx1Pi1FGqCnY3KlW81+Plhz0T4yStm1MgnqH4
+# RKYyPdcempCYC/BI04Ph2EJL+uQQfAfYdbf9vGqpKYjsuktnWr5uowD3H5At+x3l
+# YH5rz4JCleKjeLpB/j74H7VZ0I5eTEbls9e2lEKaUzb9o0wjnjDc+t4BAgMBAAGj
+# ggEbMIIBFzAdBgNVHQ4EFgQUNOHjlxlIJXMcP9n/0ogYdX8p6HcwHwYDVR0jBBgw
+# FoAU1WM6XIoxkPNDe3xGG8UzaFqFbVUwVgYDVR0fBE8wTTBLoEmgR4ZFaHR0cDov
+# L2NybC5taWNyb3NvZnQuY29tL3BraS9jcmwvcHJvZHVjdHMvTWljVGltU3RhUENB
+# XzIwMTAtMDctMDEuY3JsMFoGCCsGAQUFBwEBBE4wTDBKBggrBgEFBQcwAoY+aHR0
+# cDovL3d3dy5taWNyb3NvZnQuY29tL3BraS9jZXJ0cy9NaWNUaW1TdGFQQ0FfMjAx
+# MC0wNy0wMS5jcnQwDAYDVR0TAQH/BAIwADATBgNVHSUEDDAKBggrBgEFBQcDCDAN
+# BgkqhkiG9w0BAQsFAAOCAQEAGN3/7XWSzHGKjk444w+2q1D3k7Bh/ZahUvWHFJ6E
+# UKU5vLzEGsdsgJSvWXHZDRrpf5rcUGQyjnlo1hAY1mDteNKFushS6bedxcxPHJje
+# lVZ9N2/e5+/7zLu18YjnKw5bFu7dWqYBMI3J0FOr56XJOJ1KTtMiJhpxuib+FWy+
+# pyhVVgHGTUHuUdbE09dY9WxuRsbpb4DdWAWNrPDB6VAOO50QfEj+0tW+zF6h3RhB
+# TI0ilj0+AzgXE+6DyJ7/br6aVvCEvNRJzE6akJnMyn/kzmC32LxvRZWKEwWDR0Fn
+# zeXj5ynSStZ6iifTBP7gqiDsidguxh+BFX7HxhN1eHf7jTCCBnEwggRZoAMCAQIC
+# CmEJgSoAAAAAAAIwDQYJKoZIhvcNAQELBQAwgYgxCzAJBgNVBAYTAlVTMRMwEQYD
+# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
+# b3NvZnQgQ29ycG9yYXRpb24xMjAwBgNVBAMTKU1pY3Jvc29mdCBSb290IENlcnRp
+# ZmljYXRlIEF1dGhvcml0eSAyMDEwMB4XDTEwMDcwMTIxMzY1NVoXDTI1MDcwMTIx
+# NDY1NVowfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNV
+# BAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQG
+# A1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIwMTAwggEiMA0GCSqGSIb3
+# DQEBAQUAA4IBDwAwggEKAoIBAQCpHQ28dxGKOiDs/BOX9fp/aZRrdFQQ1aUKAIKF
+# ++18aEssX8XD5WHCdrc+Zitb8BVTJwQxH0EbGpUdzgkTjnxhMFmxMEQP8WCIhFRD
+# DNdNuDgIs0Ldk6zWczBXJoKjRQ3Q6vVHgc2/JGAyWGBG8lhHhjKEHnRhZ5FfgVSx
+# z5NMksHEpl3RYRNuKMYa+YaAu99h/EbBJx0kZxJyGiGKr0tkiVBisV39dx898Fd1
+# rL2KQk1AUdEPnAY+Z3/1ZsADlkR+79BL/W7lmsqxqPJ6Kgox8NpOBpG2iAg16Hgc
+# sOmZzTznL0S6p/TcZL2kAcEgCZN4zfy8wMlEXV4WnAEFTyJNAgMBAAGjggHmMIIB
+# 4jAQBgkrBgEEAYI3FQEEAwIBADAdBgNVHQ4EFgQU1WM6XIoxkPNDe3xGG8UzaFqF
+# bVUwGQYJKwYBBAGCNxQCBAweCgBTAHUAYgBDAEEwCwYDVR0PBAQDAgGGMA8GA1Ud
+# EwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAU1fZWy4/oolxiaNE9lJBb186aGMQwVgYD
+# VR0fBE8wTTBLoEmgR4ZFaHR0cDovL2NybC5taWNyb3NvZnQuY29tL3BraS9jcmwv
+# cHJvZHVjdHMvTWljUm9vQ2VyQXV0XzIwMTAtMDYtMjMuY3JsMFoGCCsGAQUFBwEB
+# BE4wTDBKBggrBgEFBQcwAoY+aHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraS9j
+# ZXJ0cy9NaWNSb29DZXJBdXRfMjAxMC0wNi0yMy5jcnQwgaAGA1UdIAEB/wSBlTCB
+# kjCBjwYJKwYBBAGCNy4DMIGBMD0GCCsGAQUFBwIBFjFodHRwOi8vd3d3Lm1pY3Jv
+# c29mdC5jb20vUEtJL2RvY3MvQ1BTL2RlZmF1bHQuaHRtMEAGCCsGAQUFBwICMDQe
+# MiAdAEwAZQBnAGEAbABfAFAAbwBsAGkAYwB5AF8AUwB0AGEAdABlAG0AZQBuAHQA
+# LiAdMA0GCSqGSIb3DQEBCwUAA4ICAQAH5ohRDeLG4Jg/gXEDPZ2joSFvs+umzPUx
+# vs8F4qn++ldtGTCzwsVmyWrf9efweL3HqJ4l4/m87WtUVwgrUYJEEvu5U4zM9GAS
+# inbMQEBBm9xcF/9c+V4XNZgkVkt070IQyK+/f8Z/8jd9Wj8c8pl5SpFSAK84Dxf1
+# L3mBZdmptWvkx872ynoAb0swRCQiPM/tA6WWj1kpvLb9BOFwnzJKJ/1Vry/+tuWO
+# M7tiX5rbV0Dp8c6ZZpCM/2pif93FSguRJuI57BlKcWOdeyFtw5yjojz6f32WapB4
+# pm3S4Zz5Hfw42JT0xqUKloakvZ4argRCg7i1gJsiOCC1JeVk7Pf0v35jWSUPei45
+# V3aicaoGig+JFrphpxHLmtgOR5qAxdDNp9DvfYPw4TtxCd9ddJgiCGHasFAeb73x
+# 4QDf5zEHpJM692VHeOj4qEir995yfmFrb3epgcunCaw5u+zGy9iCtHLNHfS4hQEe
+# gPsbiSpUObJb2sgNVZl6h3M7COaYLeqN4DMuEin1wC9UJyH3yKxO2ii4sanblrKn
+# QqLJzxlBTeCG+SqaoxFmMNO7dDJL32N79ZmKLxvHIa9Zta7cRDyXUHHXodLFVeNp
+# 3lfB0d4wwP3M5k37Db9dT+mdHhk4L7zPWAUu7w2gUDXa7wknHNWzfjUeCLraNtvT
+# X4/edIhJEqGCAs4wggI3AgEBMIH4oYHQpIHNMIHKMQswCQYDVQQGEwJVUzELMAkG
+# A1UECBMCV0ExEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBD
+# b3Jwb3JhdGlvbjEtMCsGA1UECxMkTWljcm9zb2Z0IElyZWxhbmQgT3BlcmF0aW9u
+# cyBMaW1pdGVkMSYwJAYDVQQLEx1UaGFsZXMgVFNTIEVTTjpFMDQxLTRCRUUtRkE3
+# RTElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAgc2VydmljZaIjCgEBMAcG
+# BSsOAwIaAxUAwwu+tfgG3rC7RZrxuFO2CmZSfPiggYMwgYCkfjB8MQswCQYDVQQG
+# EwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwG
+# A1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQg
+# VGltZS1TdGFtcCBQQ0EgMjAxMDANBgkqhkiG9w0BAQUFAAIFAOLFEVUwIhgPMjAy
+# MDA3MjQxNTUwNDVaGA8yMDIwMDcyNTE1NTA0NVowdzA9BgorBgEEAYRZCgQBMS8w
+# LTAKAgUA4sURVQIBADAKAgEAAgIa9QIB/zAHAgEAAgIR9DAKAgUA4sZi1QIBADA2
+# BgorBgEEAYRZCgQCMSgwJjAMBgorBgEEAYRZCgMCoAowCAIBAAIDB6EgoQowCAIB
+# AAIDAYagMA0GCSqGSIb3DQEBBQUAA4GBADwvhE9bln801RR+oEXjtPJXTqtYMakR
+# ymItUlO2HRorDqEv2SJR/V/kQjcsqS6ig54bOiKs0Il2fW/s/pi+x1ydJMpOyhM7
+# zzqm3acQ9kbYHIDoPWVT/Rq2Oo33Dq380zXENcc0hpLAKF3Cu06SbbNbqu+A/wbI
+# z5IClz6kU8kiMYIDDTCCAwkCAQEwgZMwfDELMAkGA1UEBhMCVVMxEzARBgNVBAgT
+# Cldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29m
+# dCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENB
+# IDIwMTACEzMAAAEHfjdomIdaN9YAAAAAAQcwDQYJYIZIAWUDBAIBBQCgggFKMBoG
+# CSqGSIb3DQEJAzENBgsqhkiG9w0BCRABBDAvBgkqhkiG9w0BCQQxIgQg6+NCew+c
+# OhYIOzhUKofOF7MxtgOvSMWQCMCIWlTFNMgwgfoGCyqGSIb3DQEJEAIvMYHqMIHn
+# MIHkMIG9BCBBYvCj4pFkwhumagATn0gLh9fdDNzImQkKNeOtRj/LHjCBmDCBgKR+
+# MHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdS
+# ZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMT
+# HU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwAhMzAAABB343aJiHWjfWAAAA
+# AAEHMCIEIGIH6vLdbEFNnxTxBhtIN7CtmhcKy/9m6/xoAA3LHzXUMA0GCSqGSIb3
+# DQEBCwUABIIBAKGg3zNulscnGBDlD6Q/U6yLQ5dN3gF9UrprgACiQ1gs/DexU7oC
+# hjNZxBnH5RTA/7q9TFf2a1rBydHWVnqXuuQQJ0HuskdpXahxR4y1jboDdGwr7F08
+# v/gmPeeUik28Je72QZp5m/R0O61/kMQaDpLO9iPH0Z9iMGfqJonFPDeY4VX8Da2n
+# cPY7mrv6YAI+ydZ+mUdBp2yjas7+/N8MntcNtAO0HpWFXQTAmb77RrSssfeZphRA
+# mBD+gLx5C3q4uSmuOqaQxUaF0y8FeuetHp0bw2sfce6GlMXJwzTpC6HvXnaVtMy0
+# pgzd/KPHW7EgSvmRVKmvwiQGiZBoRG/Gcg8=
+# SIG # End signature block
diff --git a/vcpkg/scripts/azure-pipelines/windows/deploy-visual-studio.ps1 b/vcpkg/scripts/azure-pipelines/windows/deploy-visual-studio.ps1
new file mode 100644
index 0000000..b741bb8
--- /dev/null
+++ b/vcpkg/scripts/azure-pipelines/windows/deploy-visual-studio.ps1
@@ -0,0 +1,42 @@
+# Copyright (c) Microsoft Corporation.
+# SPDX-License-Identifier: MIT
+
+param([string]$SasToken)
+
+if (Test-Path "$PSScriptRoot/utility-prefix.ps1") {
+ . "$PSScriptRoot/utility-prefix.ps1"
+}
+
+# See https://learn.microsoft.com/visualstudio/releases/2022/release-history
+# 17.14.17
+$VisualStudioBootstrapperUrl = 'https://download.visualstudio.microsoft.com/download/pr/5967a899-96aa-47e2-a7c5-1b7192f292ee/74cdb7178d623f27d405946de1860f7ee67acba537a9e43ce4b2d2ee87bd75b4/vs_Enterprise.exe'
+$Workloads = @(
+ 'Microsoft.VisualStudio.Workload.NativeDesktop',
+ 'Microsoft.VisualStudio.Workload.Universal',
+ 'Microsoft.VisualStudio.Component.UWP.VC.ARM64',
+ 'Microsoft.VisualStudio.Component.VC.Tools.x86.x64',
+ 'Microsoft.VisualStudio.Component.VC.Tools.ARM64',
+ 'Microsoft.VisualStudio.Component.VC.ASAN',
+ 'Microsoft.VisualStudio.Component.VC.ATL',
+ 'Microsoft.VisualStudio.Component.VC.ATLMFC',
+ 'Microsoft.VisualStudio.Component.VC.ATL.ARM64',
+ 'Microsoft.VisualStudio.Component.VC.MFC.ARM64',
+ 'Microsoft.VisualStudio.Component.Windows11SDK.26100',
+ 'Microsoft.VisualStudio.Component.Windows10SDK.19041', # As of 2024-11-15, CMake explicitly needs a Windows 10 SDK for Store
+ # These .NET parts are needed for easyhook, openni2
+ 'Microsoft.Net.Component.4.8.SDK',
+ 'Microsoft.Net.Component.4.7.2.TargetingPack',
+ 'Microsoft.Component.NetFX.Native',
+ 'Microsoft.VisualStudio.Component.VC.Llvm.ClangToolset',
+ 'Microsoft.VisualStudio.Component.VC.Llvm.Clang',
+ 'Microsoft.VisualStudio.ComponentGroup.UWP.VC.BuildTools',
+ 'Microsoft.VisualStudio.Component.VC.CMake.Project'
+)
+
+$vsArgs = @('--quiet', '--norestart', '--wait', '--nocache')
+foreach ($workload in $Workloads) {
+ $vsArgs += '--add'
+ $vsArgs += $workload
+}
+
+DownloadAndInstall -Name 'Visual Studio' -Url $VisualStudioBootstrapperUrl -Args $vsArgs
diff --git a/vcpkg/scripts/azure-pipelines/windows/disk-space.ps1 b/vcpkg/scripts/azure-pipelines/windows/disk-space.ps1
new file mode 100644
index 0000000..b3b4086
--- /dev/null
+++ b/vcpkg/scripts/azure-pipelines/windows/disk-space.ps1
@@ -0,0 +1,35 @@
+# Copyright (c) Microsoft Corporation.
+# SPDX-License-Identifier: MIT
+#
+
+<#
+.SYNOPSIS
+Prints total and free disk space for each disk on the system
+#>
+
+Function Format-Size {
+ [CmdletBinding()]
+ Param([long]$Size)
+
+ if ($Size -lt 1024) {
+ $Size = [int]$Size
+ return "$Size B"
+ }
+
+ $Size = $Size / 1024
+ if ($Size -lt 1024) {
+ $Size = [int]$Size
+ return "$Size KiB"
+ }
+
+ $Size = $Size / 1024
+ if ($Size -lt 1024) {
+ $Size = [int]$Size
+ return "$Size MiB"
+ }
+
+ $Size = [int]($Size / 1024)
+ return "$Size GiB"
+}
+
+Get-CimInstance -ClassName Win32_LogicalDisk | Format-Table -Property @{Label="Disk"; Expression={ $_.DeviceID }},@{Label="Label"; Expression={ $_.VolumeName }},@{Label="Size"; Expression={ Format-Size($_.Size) }},@{Label="Free Space"; Expression={ Format-Size($_.FreeSpace) }}
diff --git a/vcpkg/scripts/azure-pipelines/windows/provision-entire-image.ps1 b/vcpkg/scripts/azure-pipelines/windows/provision-entire-image.ps1
new file mode 100644
index 0000000..7adc13f
--- /dev/null
+++ b/vcpkg/scripts/azure-pipelines/windows/provision-entire-image.ps1
@@ -0,0 +1,21 @@
+# Copyright (c) Microsoft Corporation.
+# SPDX-License-Identifier: MIT
+
+# This script runs all the scripts we run on Azure machines to deploy prerequisites,
+# and assumes it is being run as an admin user.
+
+. "$PSScriptRoot\deploy-tlssettings.ps1" -RebootIfRequired 0
+. "$PSScriptRoot\deploy-visual-studio.ps1"
+. "$PSScriptRoot\deploy-mpi.ps1"
+. "$PSScriptRoot\deploy-cuda.ps1"
+. "$PSScriptRoot\deploy-cudnn.ps1"
+. "$PSScriptRoot\deploy-inteloneapi.ps1"
+. "$PSScriptRoot\deploy-pwsh.ps1"
+. "$PSScriptRoot\deploy-azure-cli.ps1"
+. "$PSScriptRoot\deploy-azcopy.ps1"
+try {
+ Copy-Item "$PSScriptRoot\deploy-settings.txt" "$PSScriptRoot\deploy-settings.ps1"
+ . "$PSScriptRoot\deploy-settings.ps1"
+} finally {
+ Remove-Item "$PSScriptRoot\deploy-settings.ps1"
+}
diff --git a/vcpkg/scripts/azure-pipelines/windows/sysprep.ps1 b/vcpkg/scripts/azure-pipelines/windows/sysprep.ps1
new file mode 100644
index 0000000..2af2ae9
--- /dev/null
+++ b/vcpkg/scripts/azure-pipelines/windows/sysprep.ps1
@@ -0,0 +1,19 @@
+# Copyright (c) Microsoft Corporation.
+# SPDX-License-Identifier: MIT
+#
+
+param([string]$SasToken)
+
+<#
+.SYNOPSIS
+Prepares the virtual machine for imaging.
+
+.DESCRIPTION
+Runs the `sysprep` utility to prepare the system for imaging.
+See https://docs.microsoft.com/en-us/windows-hardware/manufacture/desktop/sysprep--system-preparation--overview
+for more information.
+#>
+
+$ErrorActionPreference = 'Stop'
+Write-Host 'Running sysprep'
+& C:\Windows\system32\sysprep\sysprep.exe /oobe /generalize /mode:vm /shutdown
diff --git a/vcpkg/scripts/azure-pipelines/windows/utility-prefix.ps1 b/vcpkg/scripts/azure-pipelines/windows/utility-prefix.ps1
new file mode 100644
index 0000000..2e0b0f0
--- /dev/null
+++ b/vcpkg/scripts/azure-pipelines/windows/utility-prefix.ps1
@@ -0,0 +1,156 @@
+# Copyright (c) Microsoft Corporation.
+# SPDX-License-Identifier: MIT
+
+<#
+.SYNOPSIS
+Gets a random file path in the temp directory.
+
+.DESCRIPTION
+Get-TempFilePath takes an extension, and returns a path with a random
+filename component in the temporary directory with that extension.
+
+.PARAMETER Extension
+The extension to use for the path.
+#>
+Function Get-TempFilePath {
+ Param(
+ [String]$Extension
+ )
+
+ $tempPath = [System.IO.Path]::GetTempPath()
+ $tempName = [System.IO.Path]::GetRandomFileName()
+ if (-not [String]::IsNullOrWhiteSpace($Extension)) {
+ $tempName = $tempName + '.' + $Extension
+ }
+ return Join-Path $tempPath $tempName
+}
+
+<#
+.SYNOPSIS
+Download and install a component.
+
+.DESCRIPTION
+DownloadAndInstall downloads an executable from the given URL, and runs it with the given command-line arguments.
+
+.PARAMETER Name
+The name of the component, to be displayed in logging messages.
+
+.PARAMETER Url
+The URL of the installer.
+
+.PARAMETER Args
+The command-line arguments to pass to the installer.
+#>
+Function DownloadAndInstall {
+ [CmdletBinding(PositionalBinding=$false)]
+ Param(
+ [Parameter(Mandatory)][String]$Name,
+ [Parameter(Mandatory)][String]$Url,
+ [Parameter(Mandatory)][String[]]$Args,
+ [String]$LocalName = $null
+ )
+
+ try {
+ if ([string]::IsNullOrWhiteSpace($LocalName)) {
+ $LocalName = [uri]::new($Url).Segments[-1]
+ }
+
+ [bool]$doRemove = $false
+ [string]$LocalPath = Join-Path $PSScriptRoot $LocalName
+ if (Test-Path $LocalPath) {
+ Write-Host "Using local $Name..."
+ } else {
+ Write-Host "Downloading $Name..."
+ $tempPath = Get-TempFilePath
+ New-Item -ItemType Directory -Path $tempPath -Force | Out-Null
+ $LocalPath = Join-Path $tempPath $LocalName
+ curl.exe --fail -L -o $LocalPath $Url
+ if (-Not $?) {
+ Write-Error 'Download failed!'
+ }
+ $doRemove = $true
+ }
+
+ Write-Host "Installing $Name..."
+ $proc = Start-Process -FilePath $LocalPath -ArgumentList $Args -Wait -PassThru
+ $exitCode = $proc.ExitCode
+
+ if ($exitCode -eq 0) {
+ Write-Host 'Installation successful!'
+ } elseif ($exitCode -eq 3010) {
+ Write-Host 'Installation successful! Exited with 3010 (ERROR_SUCCESS_REBOOT_REQUIRED).'
+ } else {
+ Write-Error "Installation failed! Exited with $exitCode."
+ }
+
+ if ($doRemove) {
+ Remove-Item -Path $LocalPath -Force
+ }
+ } catch {
+ Write-Error "Installation failed! Exception: $($_.Exception.Message)"
+ }
+}
+
+<#
+.SYNOPSIS
+Download and install a zip file component.
+
+.DESCRIPTION
+DownloadAndUnzip downloads a zip from the given URL, and extracts it to the indicated path.
+
+.PARAMETER Name
+The name of the component, to be displayed in logging messages.
+
+.PARAMETER Url
+The URL of the zip to download.
+
+.PARAMETER Destination
+The location to which the zip should be extracted
+#>
+Function DownloadAndUnzip {
+ [CmdletBinding(PositionalBinding=$false)]
+ Param(
+ [Parameter(Mandatory)][String]$Name,
+ [Parameter(Mandatory)][String]$Url,
+ [Parameter(Mandatory)][String]$Destination
+ )
+
+ try {
+ $fileName = [uri]::new($Url).Segments[-1]
+ if ([string]::IsNullOrWhiteSpace($LocalName)) {
+ $LocalName = $fileName
+ }
+
+ [string]$zipPath
+ [bool]$doRemove = $false
+ [string]$LocalPath = Join-Path $PSScriptRoot $LocalName
+ if (Test-Path $LocalPath) {
+ Write-Host "Using local $Name..."
+ $zipPath = $LocalPath
+ } else {
+ $tempPath = Get-TempFilePath
+ New-Item -ItemType Directory -Path $tempPath -Force | Out-Null
+ $zipPath = Join-Path $tempPath $LocalName
+ Write-Host "Downloading $Name ( $Url -> $zipPath )..."
+ curl.exe --fail -L -o $zipPath $Url
+ if (-Not $?) {
+ Write-Error 'Download failed!'
+ }
+ $doRemove = $true
+ }
+
+ Write-Host "Installing $Name to $Destination..."
+ & tar.exe -xvf $zipPath --strip 1 --directory $Destination
+ if ($LASTEXITCODE -eq 0) {
+ Write-Host 'Installation successful!'
+ } else {
+ Write-Error "Installation failed! Exited with $LASTEXITCODE."
+ }
+
+ if ($doRemove) {
+ Remove-Item -Path $zipPath -Force
+ }
+ } catch {
+ Write-Error "Installation failed! Exception: $($_.Exception.Message)"
+ }
+}
diff --git a/vcpkg/scripts/azure-pipelines/windows/validate-version-files.ps1 b/vcpkg/scripts/azure-pipelines/windows/validate-version-files.ps1
new file mode 100644
index 0000000..32b9ba7
--- /dev/null
+++ b/vcpkg/scripts/azure-pipelines/windows/validate-version-files.ps1
@@ -0,0 +1,29 @@
+./vcpkg.exe --feature-flags=versions x-ci-verify-versions --verbose |
+ForEach-Object -Begin {
+ $long_error = ''
+} -Process {
+ if ($long_error -ne '' -and $_ -match '^$|^ ') {
+ # Extend multi-line message
+ $long_error = -join($long_error, "%0D%0A", $_ -replace '^ ','' `
+ -replace '(git add) [^ ]*\\ports\\([^ ]*)', '$1 ports/$2' )
+ } else {
+ if ($long_error -ne '') {
+ # Flush multi-line message
+ $long_error
+ $long_error = ''
+ }
+ if ($_ -match '^Error: ') {
+ # Start multi-line message
+ $long_error = $_ -replace '^Error: ', '##vso[task.logissue type=error]' `
+ -replace '(^##vso[^\]]*)](.*) [^ ]*\\versions\\(.-)\\(.*.json)(.*)', '$1;sourcepath=versions/$3/$4;linenumber=2]$2 version/$3/$4$5'
+ } else {
+ # Normal line
+ $_
+ }
+ }
+} -End {
+ if ($long_error -ne '') {
+ # Flush multi-line message
+ $long_error
+ }
+}