aboutsummaryrefslogtreecommitdiff
path: root/vcpkg/scripts/azure-pipelines
diff options
context:
space:
mode:
authorEthan Morgan <ethan@gweithio.com>2026-02-14 16:44:06 +0000
committerEthan Morgan <ethan@gweithio.com>2026-02-14 16:44:06 +0000
commit54409423f767d8b1cf30cb7d0efca6b4ca138823 (patch)
treed915ac7828703ce4b963efdd9728a1777ba18c1e /vcpkg/scripts/azure-pipelines
move to own git serverHEADmaster
Diffstat (limited to 'vcpkg/scripts/azure-pipelines')
-rw-r--r--vcpkg/scripts/azure-pipelines/Create-PRDiff.ps120
-rw-r--r--vcpkg/scripts/azure-pipelines/android/Dockerfile108
-rw-r--r--vcpkg/scripts/azure-pipelines/android/azure-pipelines.yml147
-rw-r--r--vcpkg/scripts/azure-pipelines/azure-pipelines.yml105
-rwxr-xr-xvcpkg/scripts/azure-pipelines/bootstrap-from-source.sh10
-rw-r--r--vcpkg/scripts/azure-pipelines/create-docker-images.ps171
-rw-r--r--vcpkg/scripts/azure-pipelines/example-ubuntu-provision-for-docker.sh20
-rw-r--r--vcpkg/scripts/azure-pipelines/linux/Dockerfile10
-rw-r--r--vcpkg/scripts/azure-pipelines/linux/azure-pipelines.yml147
-rwxr-xr-xvcpkg/scripts/azure-pipelines/linux/provision-image.sh178
-rw-r--r--vcpkg/scripts/azure-pipelines/osx/README.md300
-rw-r--r--vcpkg/scripts/azure-pipelines/osx/azure-pipelines.yml109
-rw-r--r--vcpkg/scripts/azure-pipelines/osx/register-guest.sh23
-rw-r--r--vcpkg/scripts/azure-pipelines/osx/setup-box.sh26
-rw-r--r--vcpkg/scripts/azure-pipelines/osx/setup-guest.sh21
-rw-r--r--vcpkg/scripts/azure-pipelines/osx/start-parallels-vm.zsh47
-rw-r--r--vcpkg/scripts/azure-pipelines/osx/stop-delete-all-vms.zsh17
-rw-r--r--vcpkg/scripts/azure-pipelines/owners-db/README.md96
-rw-r--r--vcpkg/scripts/azure-pipelines/owners-db/file_script.ts93
-rw-r--r--vcpkg/scripts/azure-pipelines/owners-db/file_script_from_cache.ts184
-rw-r--r--vcpkg/scripts/azure-pipelines/owners-db/package-lock.json219
-rw-r--r--vcpkg/scripts/azure-pipelines/owners-db/package.json19
-rw-r--r--vcpkg/scripts/azure-pipelines/patch-tuesday-checklist.md27
-rwxr-xr-xvcpkg/scripts/azure-pipelines/test-modified-ports.ps1279
-rw-r--r--vcpkg/scripts/azure-pipelines/windows-unstable/README.md4
-rw-r--r--vcpkg/scripts/azure-pipelines/windows-unstable/azure-pipelines.yml81
-rw-r--r--vcpkg/scripts/azure-pipelines/windows-unstable/rearrange-msvc-drop-layout.ps175
-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
46 files changed, 4228 insertions, 0 deletions
diff --git a/vcpkg/scripts/azure-pipelines/Create-PRDiff.ps1 b/vcpkg/scripts/azure-pipelines/Create-PRDiff.ps1
new file mode 100644
index 0000000..5991180
--- /dev/null
+++ b/vcpkg/scripts/azure-pipelines/Create-PRDiff.ps1
@@ -0,0 +1,20 @@
+[CmdletBinding(PositionalBinding=$False)]
+Param(
+ [Parameter(Mandatory=$True)]
+ [String]$DiffFile
+)
+
+Start-Process -FilePath 'git' -ArgumentList 'diff' `
+ -NoNewWindow -Wait `
+ -RedirectStandardOutput $DiffFile
+if (0 -ne (Get-Item -LiteralPath $DiffFile).Length)
+{
+ $msg = @(
+ 'The formatting of the files in the repo were not what we expected,',
+ 'or the documentation was not regenerated.',
+ 'Please access the diff from format.diff in the build artifacts,'
+ 'and apply the patch with `git apply`'
+ )
+ Write-Error ($msg -join "`n")
+ throw
+} \ No newline at end of file
diff --git a/vcpkg/scripts/azure-pipelines/android/Dockerfile b/vcpkg/scripts/azure-pipelines/android/Dockerfile
new file mode 100644
index 0000000..03144ab
--- /dev/null
+++ b/vcpkg/scripts/azure-pipelines/android/Dockerfile
@@ -0,0 +1,108 @@
+# syntax=docker/dockerfile:1.4
+# DisableDockerDetector "Used to build the container deployed to Azure Container Registry"
+FROM ubuntu:noble-20251001
+
+ADD https://packages.microsoft.com/config/ubuntu/24.04/packages-microsoft-prod.deb /packages-microsoft-prod.deb
+ADD https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.14+7/OpenJDK17U-jdk_x64_linux_hotspot_17.0.14_7.tar.gz /OpenJDK17U-jdk_x64_linux_hotspot_17.0.14_7.tar.gz
+ADD https://dl.google.com/android/repository/commandlinetools-linux-10406996_latest.zip /sdk-commandlinetools-linux-10406996_latest.zip
+ADD https://dl.google.com/android/repository/build-tools_r34-linux.zip /build-tools_r34-linux.zip
+ADD https://dl.google.com/android/repository/platform-34-ext7_r03.zip /platform-34-ext7_r03.zip
+ADD https://dl.google.com/android/repository/platform-tools_r35.0.1-linux.zip /platform-tools_r35.0.1-linux.zip
+ADD https://dl.google.com/android/repository/android-ndk-r28c-linux.zip /android-ndk-r28c-linux.zip
+
+# Add apt packages
+
+## vcpkg prerequisites
+ENV APT_PACKAGES="git curl zip unzip tar"
+
+## Common build prereqs
+ENV APT_PACKAGES="$APT_PACKAGES g++ vim pkg-config cmake ca-certificates"
+
+ENV APT_PACKAGES="$APT_PACKAGES autoconf nasm bison flex build-essential libtool libtool-bin libltdl-dev gettext automake autoconf-archive"
+
+## Python related
+ENV APT_PACKAGES="$APT_PACKAGES python3-setuptools python3-pip python3-venv python3-mako python3-jinja2"
+
+## at-spi2-atk
+ENV APT_PACKAGES="$APT_PACKAGES libxtst-dev"
+
+## freeglut
+ENV APT_PACKAGES="$APT_PACKAGES libxi-dev libgl1-mesa-dev libglu1-mesa-dev mesa-common-dev libxrandr-dev libxxf86vm-dev"
+
+# glfw3
+ENV APT_PACKAGES="$APT_PACKAGES libxinerama-dev libxcursor-dev"
+
+# qt5-base
+ENV APT_PACKAGES="$APT_PACKAGES libxext-dev libxfixes-dev libxrender-dev \
+ libxcb1-dev libx11-xcb-dev libxcb-glx0-dev libxcb-util0-dev \
+ libxkbcommon-dev libxcb-keysyms1-dev \
+ libxcb-image0-dev libxcb-shm0-dev libxcb-icccm4-dev libxcb-sync-dev \
+ libxcb-xfixes0-dev libxcb-shape0-dev libxcb-randr0-dev \
+ libxcb-render-util0-dev libxcb-xinerama0-dev libxcb-xkb-dev libxcb-xinput-dev \
+ libxcb-cursor-dev libxkbcommon-x11-dev libsm6 libsm-dev"
+
+## PowerShell
+ENV APT_PACKAGES="$APT_PACKAGES powershell azcopy"
+
+# The BUILD_DATE argument forces cache invalidation so we get updated apt dependencies
+ARG BUILD_DATE
+RUN echo "Build date: ${BUILD_DATE}"
+
+RUN <<END_OF_SCRIPT bash
+set -e
+
+export DEBIAN_FRONTEND=noninteractive
+
+# Apt prereqs itself
+apt-get -y update
+apt-get -y --no-install-recommends install ca-certificates
+
+# Add apt repos
+
+## PowerShell
+dpkg -i packages-microsoft-prod.deb
+rm -f packages-microsoft-prod.deb
+
+# Run apt things
+apt-get -y update
+apt-get -y dist-upgrade
+
+apt-get -y --no-install-recommends install $APT_PACKAGES
+
+# OpenJDK
+tar xzf OpenJDK17U-jdk_x64_linux_hotspot_17.0.14_7.tar.gz
+rm OpenJDK17U-jdk_x64_linux_hotspot_17.0.14_7.tar.gz
+
+# Android SDK
+unzip -q sdk-commandlinetools-linux-10406996_latest.zip -d android-sdk
+rm sdk-commandlinetools-linux-10406996_latest.zip
+
+unzip -q build-tools_r34-linux.zip -d android-sdk/build-tools
+mv android-sdk/build-tools/android-14 android-sdk/build-tools/34.0.0
+rm build-tools_r34-linux.zip
+
+unzip -q platform-34-ext7_r03.zip -d android-sdk/platforms
+rm platform-34-ext7_r03.zip
+find android-sdk/platforms -type d -exec chmod o+rx '{}' ';'
+find android-sdk/platforms -type f -exec chmod o+r '{}' ';'
+
+unzip -q platform-tools_r35.0.1-linux.zip -d android-sdk
+rm platform-tools_r35.0.1-linux.zip
+
+# JRE for sdk setup
+export JAVA_HOME=/jdk-17.0.14+7
+yes | /android-sdk/cmdline-tools/bin/sdkmanager --sdk_root=/android-sdk --licenses
+
+# Android NDK
+unzip -q /android-ndk-r28c-linux.zip
+rm -f android-ndk-r28c-linux.zip
+
+END_OF_SCRIPT
+
+ENV JAVA_HOME /jdk-17.0.14+7
+
+ENV ANDROID_HOME /android-sdk
+
+ENV ANDROID_NDK_HOME /android-ndk-r28c
+
+WORKDIR /vcpkg
diff --git a/vcpkg/scripts/azure-pipelines/android/azure-pipelines.yml b/vcpkg/scripts/azure-pipelines/android/azure-pipelines.yml
new file mode 100644
index 0000000..7cc5656
--- /dev/null
+++ b/vcpkg/scripts/azure-pipelines/android/azure-pipelines.yml
@@ -0,0 +1,147 @@
+# 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
+ - 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: PrAzureLinux3Docker
+ timeoutInMinutes: 1440 # 1 day
+ variables:
+ - name: WORKING_ROOT
+ value: /mnt/vcpkg-ci
+ - name: VCPKG_DOWNLOADS
+ value: /mnt/vcpkg-ci/downloads
+ - name: ANDROID_NDK_HOME
+ value: /android-ndk-r28c
+ - name: ANDROID_DOCKER_IMAGE
+ value: 'vcpkgandroidwus.azurecr.io/vcpkg-android:2025-10-16'
+ - name: LINUX_DOCKER_IMAGE
+ value: 'vcpkgandroidwus.azurecr.io/vcpkg-linux:2025-10-16'
+ steps:
+ # Note: /mnt is the Azure machines' temporary disk.
+ - bash: |
+ sudo mkdir /home/agent -m=777
+ sudo chown `id -u` /home/agent
+ sudo mkdir ${{ variables.WORKING_ROOT }} -m=777
+ sudo rm -rf ${{ variables.WORKING_ROOT }}/failure-logs
+ sudo mkdir ${{ variables.WORKING_ROOT }}/failure-logs -m=777
+ sudo mkdir ${{ variables.VCPKG_DOWNLOADS }} -m=777
+ # Move the docker layers to the temp disk.
+ sudo mkdir -p /etc/docker
+ echo '{"data-root": "/mnt/docker"}' | sudo tee /etc/docker/daemon.json
+ sudo systemctl restart docker
+ exit 0
+ displayName: 'Create working directories'
+ - bash: ./bootstrap-vcpkg.sh -skipDependencyChecks
+ displayName: 'Bootstrap vcpkg'
+ condition: eq('use default', '${{ parameters.vcpkgToolSha }}')
+ - task: AzureCLI@2
+ displayName: 'Build vcpkg with CMake'
+ condition: ne('use default', '${{ parameters.vcpkgToolSha }}')
+ inputs:
+ azureSubscription: 'vcpkg-pr-fleet-wus'
+ scriptType: bash
+ scriptLocation: 'inlineScript'
+ inlineScript: |
+ # This is a second pull but the vcpkgToolSha setting is used rarely.
+ USER=$(id --user)
+ az acr login --name vcpkgandroidwus
+ docker pull ${{ variables.LINUX_DOCKER_IMAGE }}
+ docker run --init -i --rm \
+ -a stderr \
+ -a stdout \
+ --user $USER \
+ --mount type=bind,source=$(Build.Repository.LocalPath),target=/vcpkg \
+ --workdir /vcpkg \
+ ${{ variables.LINUX_DOCKER_IMAGE }} \
+ /vcpkg/scripts/azure-pipelines/bootstrap-from-source.sh ${{ parameters.vcpkgToolSha }}
+ - task: AzureCLI@2
+ displayName: '*** Test Modified Ports'
+ inputs:
+ azureSubscription: 'vcpkg-pr-fleet-wus'
+ scriptType: bash
+ scriptLocation: 'inlineScript' # Be very very careful that the exit code from the last pwsh is reported correctly
+ inlineScript: |
+ end=`date -u -d "2 days" '+%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`
+ binarySas=`az storage container generate-sas --name cache --account-name vcpkgbinarycachewus --as-user --auth-mode login --https-only --permissions rclw --expiry $end -o tsv`
+ echo Minting SAS tokens valid through $end
+ echo "##vso[task.setvariable variable=BCACHE_SAS_TOKEN;issecret=true]$binarySas"
+ USER=$(id --user)
+ az acr login --name vcpkgandroidwus
+ docker pull ${{ variables.ANDROID_DOCKER_IMAGE }}
+ docker run --init -i --rm \
+ -a stderr \
+ -a stdout \
+ --user $USER \
+ --mount type=bind,source=$(Build.Repository.LocalPath),target=/vcpkg \
+ --mount type=bind,source=$(WORKING_ROOT)/failure-logs,target=/vcpkg/failure-logs \
+ --mount type=bind,source=/mnt/vcpkg-ci,target=/mnt/vcpkg-ci \
+ --env X_VCPKG_ASSET_SOURCES="x-azurl,https://vcpkgassetcachewus.blob.core.windows.net/cache,$assetSas,readwrite" \
+ --env ANDROID_NDK_HOME="${{ variables.ANDROID_NDK_HOME }}" \
+ --workdir /vcpkg \
+ ${{ variables.ANDROID_DOCKER_IMAGE }} \
+ pwsh \
+ -File 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 ${{ variables.WORKING_ROOT }}
+ - task: PublishPipelineArtifact@1
+ displayName: "Publish Artifact: failure logs for ${{ replace(parameters.jobName, '_', '-') }}"
+ inputs:
+ targetPath: '$(WORKING_ROOT)/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'
+ - bash: |
+ cd scripts/azure-pipelines/owners-db && npm ci || true
+ if [ "$(Build.Reason)" = "PullRequest" ]; then
+ echo "Running file_script_from_cache for PR"
+ npx --yes ts-node ./file_script_from_cache.ts --pr-hashes "$(Build.Repository.LocalPath)/pr-hashes.json" --blob-base-url "https://vcpkgbinarycachewus.blob.core.windows.net/cache?${BCACHE_SAS_TOKEN}" --target-branch "origin/master" --out-dir ../../list_files
+ else
+ echo "Running file_script for CI"
+ npx --yes ts-node ./file_script.ts --info-dir /mnt/vcpkg-ci/installed/vcpkg/info/ --out-dir ../../list_files
+ fi
+ displayName: 'Build a file list for all packages'
+ condition: always()
+ 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/azure-pipelines.yml b/vcpkg/scripts/azure-pipelines/azure-pipelines.yml
new file mode 100644
index 0000000..d4ea9e5
--- /dev/null
+++ b/vcpkg/scripts/azure-pipelines/azure-pipelines.yml
@@ -0,0 +1,105 @@
+# 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: tripletPattern
+ displayName: 'Enable triplets which contain this substring (^ matches begin, $ matches end)'
+ type: string
+ default: '^'
+
+jobs:
+- template: windows/azure-pipelines.yml
+ parameters:
+ jobName: x86_windows
+ vcpkgToolSha: ${{ parameters.vcpkgToolSha }}
+ tripletPattern: ${{ parameters.tripletPattern }}
+
+- template: windows/azure-pipelines.yml
+ parameters:
+ jobName: x64_windows
+ vcpkgToolSha: ${{ parameters.vcpkgToolSha }}
+ tripletPattern: ${{ parameters.tripletPattern }}
+
+- template: windows/azure-pipelines.yml
+ parameters:
+ jobName: x64_windows_release
+ vcpkgToolSha: ${{ parameters.vcpkgToolSha }}
+ tripletPattern: ${{ parameters.tripletPattern }}
+
+- template: windows/azure-pipelines.yml
+ parameters:
+ jobName: x64_windows_static
+ vcpkgToolSha: ${{ parameters.vcpkgToolSha }}
+ tripletPattern: ${{ parameters.tripletPattern }}
+
+- template: windows/azure-pipelines.yml
+ parameters:
+ jobName: x64_windows_static_md
+ vcpkgToolSha: ${{ parameters.vcpkgToolSha }}
+ tripletPattern: ${{ parameters.tripletPattern }}
+
+- template: windows/azure-pipelines.yml
+ parameters:
+ jobName: x64_uwp
+ vcpkgToolSha: ${{ parameters.vcpkgToolSha }}
+ tripletPattern: ${{ parameters.tripletPattern }}
+
+- template: windows/azure-pipelines.yml
+ parameters:
+ jobName: arm64_windows
+ vcpkgToolSha: ${{ parameters.vcpkgToolSha }}
+ tripletPattern: ${{ parameters.tripletPattern }}
+
+- template: windows/azure-pipelines.yml
+ parameters:
+ jobName: arm64_windows_static_md
+ vcpkgToolSha: ${{ parameters.vcpkgToolSha }}
+ tripletPattern: ${{ parameters.tripletPattern }}
+
+- template: windows/azure-pipelines.yml
+ parameters:
+ jobName: arm64_uwp
+ vcpkgToolSha: ${{ parameters.vcpkgToolSha }}
+ tripletPattern: ${{ parameters.tripletPattern }}
+
+- template: osx/azure-pipelines.yml
+ parameters:
+ jobName: x64_osx
+ poolName: 'PrOsx-2025-09-11'
+ vcpkgToolSha: ${{ parameters.vcpkgToolSha }}
+ tripletPattern: ${{ parameters.tripletPattern }}
+
+- template: osx/azure-pipelines.yml
+ parameters:
+ jobName: arm64_osx
+ poolName: 'PrOsx-2025-09-11-arm64'
+ vcpkgToolSha: ${{ parameters.vcpkgToolSha }}
+ tripletPattern: ${{ parameters.tripletPattern }}
+
+- template: linux/azure-pipelines.yml
+ parameters:
+ jobName: x64_linux
+ vcpkgToolSha: ${{ parameters.vcpkgToolSha }}
+ tripletPattern: ${{ parameters.tripletPattern }}
+
+- template: android/azure-pipelines.yml
+ parameters:
+ jobName: arm_neon_android
+ vcpkgToolSha: ${{ parameters.vcpkgToolSha }}
+ tripletPattern: ${{ parameters.tripletPattern }}
+
+- template: android/azure-pipelines.yml
+ parameters:
+ jobName: x64_android
+ vcpkgToolSha: ${{ parameters.vcpkgToolSha }}
+ tripletPattern: ${{ parameters.tripletPattern }}
+
+- template: android/azure-pipelines.yml
+ parameters:
+ jobName: arm64_android
+ vcpkgToolSha: ${{ parameters.vcpkgToolSha }}
+ tripletPattern: ${{ parameters.tripletPattern }}
diff --git a/vcpkg/scripts/azure-pipelines/bootstrap-from-source.sh b/vcpkg/scripts/azure-pipelines/bootstrap-from-source.sh
new file mode 100755
index 0000000..d9ee04f
--- /dev/null
+++ b/vcpkg/scripts/azure-pipelines/bootstrap-from-source.sh
@@ -0,0 +1,10 @@
+#!/bin/sh
+set -e
+
+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
+rm -rf build.x64.release
+cmake -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.x64.release -S vcpkg-tool
+ninja -C build.x64.release
+mv build.x64.release/vcpkg vcpkg
diff --git a/vcpkg/scripts/azure-pipelines/create-docker-images.ps1 b/vcpkg/scripts/azure-pipelines/create-docker-images.ps1
new file mode 100644
index 0000000..9f465bf
--- /dev/null
+++ b/vcpkg/scripts/azure-pipelines/create-docker-images.ps1
@@ -0,0 +1,71 @@
+# Create Docker images for vcpkg
+
+[CmdletBinding()]
+param(
+ [switch]$OnlyAndroid,
+ [switch]$OnlyLinux,
+ [switch]$NoLogout
+)
+
+if ($OnlyAndroid -and $OnlyLinux) {
+ Write-Error "At most one of {-OnlyAndroid, -OnlyLinux} may be set"
+ return 1
+}
+
+if ($OnlyAndroid) {
+ Write-Host "Only building Android"
+ $BuildAndroid = $true
+ $BuildLinux = $false
+} elseif ($OnlyLinux) {
+ Write-Host "Only building Linux"
+ $BuildAndroid = $false
+ $BuildLinux = $true
+} else {
+ $BuildAndroid = $true
+ $BuildLinux = $true
+}
+
+function Build-Image {
+ param(
+ $AcrRegistry,
+ [string]$Location,
+ [string]$ImageName,
+ [string]$Date
+ )
+
+ Push-Location $Location
+ try {
+ $remote = [string]::Format('{0}/{1}:{2}', $AcrRegistry.LoginServer, $ImageName, $Date)
+ docker build . -t $remote --build-arg BUILD_DATE=$Date
+ docker push $remote
+ Write-Host "Remote: $remote"
+ } finally {
+ Pop-Location
+ }
+}
+
+$Date = (Get-Date -Format 'yyyy-MM-dd')
+$ResourceGroupName = "PrAnd-WUS"
+$ContainerRegistryName = "vcpkgandroidwus"
+$ErrorActionPreference = 'Stop'
+
+$registry = Get-AzContainerRegistry -ResourceGroupName $ResourceGroupName -Name $ContainerRegistryName
+Connect-AzContainerRegistry -Name $registry.Name
+
+if ($BuildAndroid) {
+ Build-Image -AcrRegistry $registry `
+ -Location "$PSScriptRoot/android" `
+ -ImageName "vcpkg-android" `
+ -Date $Date
+}
+
+if ($BuildLinux) {
+ Build-Image -AcrRegistry $registry `
+ -Location "$PSScriptRoot/linux" `
+ -ImageName "vcpkg-linux" `
+ -Date $Date
+}
+
+if (-not $NoLogout) {
+ docker logout $registry.LoginServer
+}
diff --git a/vcpkg/scripts/azure-pipelines/example-ubuntu-provision-for-docker.sh b/vcpkg/scripts/azure-pipelines/example-ubuntu-provision-for-docker.sh
new file mode 100644
index 0000000..ada5445
--- /dev/null
+++ b/vcpkg/scripts/azure-pipelines/example-ubuntu-provision-for-docker.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+# Copyright (c) Microsoft Corporation.
+# SPDX-License-Identifier: MIT
+#
+# This script is to set up the machine for the Docker host.
+
+# This script is no longer used by official vcpkg testing due to an internal compliance effort
+# requiring use of CBL-Mariner. It's still intended to be more or less identical to how the lab
+# actually works though; everything meaningful is inside the Docker image; see Dockerfile
+
+export DEBIAN_FRONTEND=noninteractive
+
+## Docker
+apt-get -y --no-install-recommends install ca-certificates gnupg lsb-release
+mkdir -p /etc/apt/keyrings
+curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
+echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
+ $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
+apt-get update
+apt-get -y --no-install-recommends install docker-ce docker-ce-cli
diff --git a/vcpkg/scripts/azure-pipelines/linux/Dockerfile b/vcpkg/scripts/azure-pipelines/linux/Dockerfile
new file mode 100644
index 0000000..c07392b
--- /dev/null
+++ b/vcpkg/scripts/azure-pipelines/linux/Dockerfile
@@ -0,0 +1,10 @@
+# syntax=docker/dockerfile:1.4
+# DisableDockerDetector "Used to build the container deployed to Azure Container Registry"
+FROM ubuntu:noble-20251001
+ADD provision-image.sh /provision-image.sh
+RUN apt-get update && \
+ apt-get install --no-install-recommends -y curl gnupg ca-certificates
+# The BUILD_DATE argument forces cache invalidation so we get updated apt dependencies
+ARG BUILD_DATE
+RUN echo "Build date: ${BUILD_DATE}"
+RUN chmod +x /provision-image.sh && /provision-image.sh
diff --git a/vcpkg/scripts/azure-pipelines/linux/azure-pipelines.yml b/vcpkg/scripts/azure-pipelines/linux/azure-pipelines.yml
new file mode 100644
index 0000000..0da2b03
--- /dev/null
+++ b/vcpkg/scripts/azure-pipelines/linux/azure-pipelines.yml
@@ -0,0 +1,147 @@
+# 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: 'x64_linux'
+ - 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: PrAzureLinux3Docker
+ timeoutInMinutes: 1440 # 1 day
+ variables:
+ - name: WORKING_ROOT
+ value: /mnt/vcpkg-ci
+ - name: VCPKG_DOWNLOADS
+ value: /mnt/vcpkg-ci/downloads
+ - name: LINUX_DOCKER_IMAGE
+ value: 'vcpkgandroidwus.azurecr.io/vcpkg-linux:2025-10-16'
+ steps:
+ # Note: /mnt is the Azure machines' temporary disk.
+ - bash: |
+ sudo mkdir /home/agent -m=777
+ sudo chown `id -u` /home/agent
+ sudo mkdir ${{ variables.WORKING_ROOT }} -m=777
+ sudo rm -rf ${{ variables.WORKING_ROOT }}/failure-logs
+ sudo mkdir ${{ variables.WORKING_ROOT }}/failure-logs -m=777
+ sudo mkdir ${{ variables.VCPKG_DOWNLOADS }} -m=777
+ # Move the docker layers to the temp disk.
+ sudo mkdir -p /etc/docker
+ echo '{"data-root": "/mnt/docker"}' | sudo tee /etc/docker/daemon.json
+ sudo systemctl restart docker
+ exit 0
+ displayName: 'Create working directories'
+ - bash: ./bootstrap-vcpkg.sh -skipDependencyChecks
+ displayName: 'Bootstrap vcpkg'
+ condition: eq('use default', '${{ parameters.vcpkgToolSha }}')
+ - task: AzureCLI@2
+ displayName: 'Build vcpkg with CMake'
+ condition: ne('use default', '${{ parameters.vcpkgToolSha }}')
+ inputs:
+ azureSubscription: 'vcpkg-pr-fleet-wus'
+ scriptType: bash
+ scriptLocation: 'inlineScript'
+ inlineScript: |
+ # This is a second pull but the vcpkgToolSha setting is used rarely.
+ USER=$(id --user)
+ az acr login --name vcpkgandroidwus
+ docker pull ${{ variables.LINUX_DOCKER_IMAGE }}
+ docker run --init -i --rm \
+ -a stderr \
+ -a stdout \
+ --user $USER \
+ --mount type=bind,source=$(Build.Repository.LocalPath),target=/vcpkg \
+ --workdir /vcpkg \
+ ${{ variables.LINUX_DOCKER_IMAGE }} \
+ /vcpkg/scripts/azure-pipelines/bootstrap-from-source.sh ${{ parameters.vcpkgToolSha }}
+ - task: AzureCLI@2
+ displayName: '*** Test Modified Ports'
+ inputs:
+ azureSubscription: 'vcpkg-pr-fleet-wus'
+ scriptType: bash
+ scriptLocation: 'inlineScript' # Be very very careful that the exit code from the last pwsh is reported correctly
+ inlineScript: |
+ end=`date -u -d "2 days" '+%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`
+ binarySas=`az storage container generate-sas --name cache --account-name vcpkgbinarycachewus --as-user --auth-mode login --https-only --permissions rclw --expiry $end -o tsv`
+ echo Minting SAS tokens valid through $end
+ # Persist the binary SAS as a secret pipeline variable for the owners-db step
+ echo "##vso[task.setvariable variable=BCACHE_SAS_TOKEN;issecret=true]$binarySas"
+ USER=$(id --user)
+ az acr login --name vcpkgandroidwus
+ docker pull ${{ variables.LINUX_DOCKER_IMAGE }}
+ docker run --init -i --rm \
+ -a stderr \
+ -a stdout \
+ --user $USER \
+ --mount type=bind,source=$(Build.Repository.LocalPath),target=/vcpkg \
+ --mount type=bind,source=$(WORKING_ROOT)/failure-logs,target=/vcpkg/failure-logs \
+ --mount type=bind,source=/mnt/vcpkg-ci,target=/mnt/vcpkg-ci \
+ --env X_VCPKG_ASSET_SOURCES="x-azurl,https://vcpkgassetcachewus.blob.core.windows.net/cache,$assetSas,readwrite" \
+ --workdir /vcpkg \
+ ${{ variables.LINUX_DOCKER_IMAGE }} \
+ pwsh \
+ -File 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 ${{ variables.WORKING_ROOT }}
+ - task: PublishPipelineArtifact@1
+ displayName: "Publish Artifact: failure logs for ${{ replace(parameters.jobName, '_', '-') }}"
+ inputs:
+ targetPath: '$(WORKING_ROOT)/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'
+ - bash: |
+ cd scripts/azure-pipelines/owners-db && npm ci || true
+ # Construct the blob base url using the secret SAS token set earlier
+ blob="https://vcpkgbinarycachewus.blob.core.windows.net/cache?${BCACHE_SAS_TOKEN}"
+ if [ "$(Build.Reason)" = "PullRequest" ]; then
+ echo "Running file_script_from_cache for PR"
+ npx --yes ts-node ./file_script_from_cache.ts --pr-hashes "$(Build.Repository.LocalPath)/pr-hashes.json" --blob-base-url "$blob" --target-branch "origin/master" --out-dir ../../list_files
+ else
+ echo "Running file_script for CI"
+ npx --yes ts-node ./file_script.ts --info-dir /mnt/vcpkg-ci/installed/vcpkg/info/ --out-dir ../../list_files
+ fi
+ displayName: 'Build a file list for all packages'
+ condition: always()
+ 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, '_', '-') }}
+ configuration: static
diff --git a/vcpkg/scripts/azure-pipelines/linux/provision-image.sh b/vcpkg/scripts/azure-pipelines/linux/provision-image.sh
new file mode 100755
index 0000000..62daced
--- /dev/null
+++ b/vcpkg/scripts/azure-pipelines/linux/provision-image.sh
@@ -0,0 +1,178 @@
+#!/bin/bash
+# Copyright (c) Microsoft Corporation.
+# SPDX-License-Identifier: MIT
+#
+
+export DEBIAN_FRONTEND=noninteractive
+
+# Add apt repos
+
+# Detect Ubuntu VERSION_ID from /etc/os-release (e.g., "24.04") and format to "2404"
+UBUNTU_VERSION_ID=$(. /etc/os-release && echo "$VERSION_ID")
+NVIDIA_REPO_VERSION=$(echo "$UBUNTU_VERSION_ID" | sed 's/\.//')
+
+# Apt dependencies; needed for add-apt-repository and curl downloads to work
+apt-get -y update
+apt-get --no-install-recommends -y install ca-certificates curl apt-transport-https lsb-release gnupg software-properties-common
+
+## CUDA
+curl -L -o /etc/apt/preferences.d/cuda-repository-pin-600 "https://developer.download.nvidia.com/compute/cuda/repos/ubuntu${NVIDIA_REPO_VERSION}/x86_64/cuda-ubuntu${NVIDIA_REPO_VERSION}.pin"
+apt-key adv --fetch-keys "https://developer.download.nvidia.com/compute/cuda/repos/ubuntu${NVIDIA_REPO_VERSION}/x86_64/3bf863cc.pub"
+add-apt-repository "deb https://developer.download.nvidia.com/compute/cuda/repos/ubuntu${NVIDIA_REPO_VERSION}/x86_64/ /"
+
+## PowerShell
+curl -L -o packages-microsoft-prod.deb https://packages.microsoft.com/config/ubuntu/${UBUNTU_VERSION_ID}/packages-microsoft-prod.deb
+dpkg -i packages-microsoft-prod.deb
+rm -f packages-microsoft-prod.deb
+add-apt-repository universe
+
+## Azure CLI
+mkdir -p /etc/apt/keyrings
+curl -sLS https://packages.microsoft.com/keys/microsoft.asc |
+ gpg --dearmor |
+ tee /etc/apt/keyrings/microsoft.gpg > /dev/null
+chmod go+r /etc/apt/keyrings/microsoft.gpg
+
+AZ_DIST=$(lsb_release -cs)
+echo "deb [arch=`dpkg --print-architecture` signed-by=/etc/apt/keyrings/microsoft.gpg] https://packages.microsoft.com/repos/azure-cli/ $AZ_DIST main" |
+ tee /etc/apt/sources.list.d/azure-cli.list
+
+apt-get -y update
+apt-get -y upgrade
+
+# Add apt packages
+
+## vcpkg prerequisites
+APT_PACKAGES="git curl zip unzip tar"
+
+## essentials
+APT_PACKAGES="$APT_PACKAGES \
+ autoconf autoconf-archive \
+ autopoint \
+ build-essential \
+ cmake \
+ gcc g++ gfortran \
+ libnuma1 libnuma-dev \
+ libtool libtool-bin libltdl-dev \
+ libudev-dev \
+"
+
+## vcpkg_find_acquire_program
+APT_PACKAGES="$APT_PACKAGES \
+ bison libbison-dev \
+ flex \
+ gperf \
+ nasm \
+ ninja-build \
+ pkg-config \
+ python3 \
+ ruby-full \
+ swig \
+ yasm \
+"
+
+## mesa and X essentials
+APT_PACKAGES="$APT_PACKAGES \
+ mesa-common-dev libgl1-mesa-dev libglu1-mesa-dev libgles2-mesa-dev \
+ libx11-dev \
+ libxaw7-dev \
+ libxcursor-dev \
+ libxi-dev \
+ libxinerama-dev \
+ libxkbcommon-x11-dev \
+ libxrandr-dev \
+ libxt-dev \
+ libxxf86vm-dev \
+ xutils-dev \
+"
+
+## required by qt5-base
+APT_PACKAGES="$APT_PACKAGES libxext-dev libxfixes-dev libxrender-dev \
+ libxcb1-dev libx11-xcb-dev libxcb-glx0-dev libxcb-util0-dev"
+
+## required by qt5-base for qt5-x11extras
+APT_PACKAGES="$APT_PACKAGES libxkbcommon-dev libxcb-keysyms1-dev \
+ libxcb-image0-dev libxcb-shm0-dev libxcb-icccm4-dev libxcb-sync-dev \
+ libxcb-xfixes0-dev libxcb-shape0-dev libxcb-randr0-dev \
+ libxcb-render-util0-dev libxcb-xinerama0-dev libxcb-xkb-dev libxcb-xinput-dev"
+
+## required by xcb feature in qtbase
+APT_PACKAGES="$APT_PACKAGES libxcb-cursor-dev"
+
+## required by libhdfs3
+APT_PACKAGES="$APT_PACKAGES libkrb5-dev"
+
+## required by kf5windowsystem
+APT_PACKAGES="$APT_PACKAGES libxcb-res0-dev"
+
+## required by kf5globalaccel
+APT_PACKAGES="$APT_PACKAGES libxcb-keysyms1-dev libxcb-xkb-dev libxcb-record0-dev"
+
+## required by mesa
+APT_PACKAGES="$APT_PACKAGES python3-setuptools python3-mako libxcb-dri3-dev libxcb-present-dev"
+
+## required by some packages to install additional python packages
+APT_PACKAGES="$APT_PACKAGES python3-pip python3-venv python3-jinja2"
+
+## required by qtwebengine
+APT_PACKAGES="$APT_PACKAGES nodejs"
+
+## required by qtwayland
+APT_PACKAGES="$APT_PACKAGES libwayland-dev"
+
+## required by all GN projects
+APT_PACKAGES="$APT_PACKAGES python-is-python3"
+
+## required by libctl
+APT_PACKAGES="$APT_PACKAGES guile-2.2-dev"
+
+## required by gtk
+APT_PACKAGES="$APT_PACKAGES libxdamage-dev libselinux1-dev"
+
+## required by at-spi2-atk
+APT_PACKAGES="$APT_PACKAGES libxtst-dev"
+
+## required by boringssl
+APT_PACKAGES="$APT_PACKAGES golang-go"
+
+## required by libdecor and mesa
+APT_PACKAGES="$APT_PACKAGES wayland-protocols"
+
+## required by robotraconteur
+APT_PACKAGES="$APT_PACKAGES libbluetooth-dev"
+
+## required by libmysql
+APT_PACKAGES="$APT_PACKAGES libtirpc-dev"
+
+## CUDA
+# The intent is to install everything that does not require an actual GPU, driver, or GUI.
+# Intentionally omitted: cuda-demo-suite-12-9 cuda-documentation-12-9 cuda-driver-*
+# cuda-gdb-12-9 cuda-gdb-src-12-9 cuda-nsight-* cuda-nvdisasm
+# cuda-nvprof cuda-nvprune cuda-profiler-api* cuda-sandbox-*
+# cuda-visual-tools-12-9 nvidia-gds-12-9 cuda-nvvp-12-9
+# cuda-toolkit-12-9 cuda-tools-12-9 cuda-command-line-tools-12-9
+# cuda-runtime-12-9
+# All libraries for which there is a -dev suffix included here
+# cudnn9-jit-cuda-12-9 : Depends: libcudnn9-jit-dev-cuda-12 (= 9.12.0.46-1) but it is not installable
+APT_PACKAGES="$APT_PACKAGES cuda-cccl-12-9 cuda-compat-12-9 cuda-compiler-12-9 cuda-crt-12-9 \
+ cuda-cudart-dev-12-9 cuda-cuobjdump-12-9 cuda-cupti-dev-12-9 cuda-cuxxfilt-12-9 \
+ cuda-driver-dev-12-9 cuda-libraries-dev-12-9 cuda-minimal-build-12-9 cuda-nvcc-12-9 \
+ cuda-nvml-dev-12-9 cuda-nvrtc-dev-12-9 cuda-nvtx-12-9 cuda-nvvm-12-9 cuda-opencl-dev-12-9 \
+ cuda-sanitizer-12-9 cuda-toolkit-12-9-config-common cudnn9-cuda-12-9 gds-tools-12-9 \
+ libcublas-12-9 libcudnn9-dev-cuda-12 libcufft-dev-12-9 libcurand-dev-12-9 libcusolver-dev-12-9 \
+ libcusparse-dev-12-9 libnccl-dev libnpp-dev-12-9 libnvfatbin-dev-12-9 libnvjitlink-dev-12-9 \
+ libnvjpeg-dev-12-9"
+
+## PowerShell + Azure
+APT_PACKAGES="$APT_PACKAGES powershell azcopy azure-cli"
+
+## Additionally required/installed by Azure DevOps Scale Set Agents, skip on WSL
+if [[ $(grep microsoft /proc/version) ]]; then
+echo "Skipping install of ADO prerequisites on WSL."
+else
+APT_PACKAGES="$APT_PACKAGES libkrb5-3 zlib1g libicu70 debsums liblttng-ust1"
+fi
+
+apt-get --no-install-recommends -y install $APT_PACKAGES
+
+az --version
diff --git a/vcpkg/scripts/azure-pipelines/osx/README.md b/vcpkg/scripts/azure-pipelines/osx/README.md
new file mode 100644
index 0000000..7164f23
--- /dev/null
+++ b/vcpkg/scripts/azure-pipelines/osx/README.md
@@ -0,0 +1,300 @@
+# `vcpkg-eg-mac` VMs
+
+This is the checklist for what the vcpkg team does when updating the macOS machines in the pool.
+
+## Creating new base images
+
+### Prerequisites
+
+- [ ] A Parallels license for amd64 or [macosvm](https://github.com/s-u/macosvm) allow-listed
+ by macOS for arm64. Note that the directory 'Parallels' is still used when using `macosvm`
+ just so that scripts know where to find the VM and friends.
+- [ ] An Xcode .xip - you can get this from Apple's developer website,
+ although you'll need to sign in first: <https://developer.apple.com/downloads>
+ If you are doing this from a local macos box, you can skip to the "update the macos host" step.
+- [ ] An Xcode Command Line Tools installer
+
+### Instructions (AMD64)
+
+- [ ] Go to https://dev.azure.com/vcpkg/public/_settings/agentqueues , pick the current osx queue,
+ and delete one of the agents that are idle.
+- [ ] Go to that machine in the KVM. (Passwords are stored as secrets in the CPP_GITHUB\vcpkg\vcpkgmm-passwords key vault)
+- [ ] Open the Parallels Control Center, and delete the active VM.
+- [ ] Update the macos host
+- [ ] Update or install parallels
+- [ ] Download the macOS installer from the app store. See https://support.apple.com/en-us/102662
+ Note: This portion of the instructions is that which breaks most often depending on what Parallels and macOS are doing.
+ You might need to use `softwareupdate --fetch-full-installer --full-installer-version 15.6.1` and point Parallels
+ at that resulting installer in 'Applications' instead.
+- [ ] Run parallels, and select that installer you just downloaded. Name the VM "vcpkg-osx-<DATE>", for example "vcpkg-osx-2025-09-11".
+- [ ] When creating the VM, customize the hardware to the following:
+ * 12 processors
+ * 24000 MB of memory
+ * 350 GB disk
+ * Disable sound output
+ * Disable microphone
+ * Do not share mac camera
+- [ ] Install MacOS like you would on real hardware.
+ * Set up as new
+ * Apple ID: 'Set Up Later' / Skip
+ * Account name: vcpkg
+ * A very similar password :)
+ * Don't enable Location Services
+ * Share crashes with app developers
+ * Don't enable Ask Siri
+- [ ] Install Parallels Tools
+- [ ] Restart the VM
+- [ ] Set the desktop wallpaper to a fixed color from Settings -> Wallpaper . (This makes the KVM a lot easier to use :) )
+- [ ] Disable automatic updates in the VM: Settings -> General -> Automatic Updates -> Disable them all
+- [ ] Enable remote login in System Settings -> General -> Sharing -> Remote Login
+- [ ] Update the Azure Agent URI in setup-box.sh to the current version. You can find this by going to the agent pool, selecting "New agent", picking macOS, and copying the link. For example https://download.agent.dev.azure.com/agent/4.261.0/vsts-agent-osx-x64-4.261.0.tar.gz
+- [ ] In the guest, set the vcpkg user to be able to use sudo without a password. From a dev machine:
+ ```sh
+ scp path/to/Xcode.xip vcpkg@HOSTMACHINE:/Users/vcpkg/Xcode.xip
+ ssh vcpkg@HOSTMACHINE
+ rm ~/.ssh/known_hosts
+ export GUEST_IP=`prlctl list --full | sed -nr 's/^.*running *([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}).*/\1/p'`
+ export SSH_COOKIE=vcpkg@$GUEST_IP
+ scp Xcode.xip $SSH_COOKIE:/Users/vcpkg/Xcode.xip
+ ssh $SSH_COOKIE # and then enter the password here
+ printf 'vcpkg\tALL=(ALL)\tNOPASSWD:\tALL\n' | sudo tee -a '/etc/sudoers.d/vcpkg'
+ sudo chmod 0440 '/etc/sudoers.d/vcpkg'
+ sudo mdutil -ad
+ xip --expand Xcode.xip
+ sudo mv Xcode.app /Applications/Xcode.app
+ rm Xcode.xip
+ exit
+ ```
+- [ ] Open Xcode from Applications in the guest GUI. Accept the EULA.
+- [ ] Update the Azure Agent URI in setup-box.sh to the current version. You can find this by going to the agent pool, selecting "New agent", picking macOS, and copying the link. For example https://download.agent.dev.azure.com/agent/4.261.0/vsts-agent-osx-x64-4.261.0.tar.gz
+- [ ] Copy setup-box.sh and the xcode installer renamed to 'clt.dmg' to the host. For example from a dev workstation:
+ ```sh
+ scp ./setup-guest.sh vcpkg@HOSTMACHINE:/Users/vcpkg
+ scp ./setup-box.sh vcpkg@HOSTMACHINE:/Users/vcpkg
+ scp path/to/console/tools.dmg vcpkg@HOSTMACHINE:/Users/vcpkg/clt.dmg
+ ssh vcpkg@HOSTMACHINE
+ chmod +x setup-guest.sh
+ ./setup-guest.sh
+ rm setup-guest.sh
+ rm setup-box.sh
+ rm clt.dmg
+ exit
+ ```
+- [ ] Shut down the VM cleanly.
+- [ ] Ensure that there is no host system specific 'hardware' like macOS install .isos attached.
+- [ ] Set the VM 'Isolated'
+- [ ] Boot and then cleanly shut down the VM.
+- [ ] In Parallels control center, right click the VM and select "Prepare for Transfer"
+- [ ] In Parallels control center, right click the VM and remove it, but "Keep Files"
+- [ ] Copy the packaged VM to Azure Storage, with something like:
+ ```sh
+ ssh vcpkg@HOSTMACHINE
+ brew install azcopy
+ azcopy copy ~/Parallels/vcpkg-osx-2025-09-11.pvmp "https://vcpkgimageminting.blob.core.windows.net/pvms?<SAS>"
+ azcopy copy ~/Parallels/vcpkg-osx-2025-09-11.sha256.txt "https://vcpkgimageminting.blob.core.windows.net/pvms?<SAS>"
+ exit
+ ```
+- [ ] Go to https://dev.azure.com/vcpkg/public/_settings/agentqueues and create a new self hosted Agent pool named `PrOsx-YYYY-MM-DD` based on the current date. Grant microsoft.vcpkg.ci and microsoft.vcpkg.pr access.
+- [ ] Remove the macOS installer from Applications
+- [ ] Follow the "Deploying images" steps below for each machine in the fleet.
+
+### Instructions (ARM64)
+
+- [ ] Go to https://dev.azure.com/vcpkg/public/_settings/agentqueues , pick the current osx queue,
+ and delete one of the agents that are idle.
+- [ ] Go to that machine in the KVM. (Passwords are stored as secrets in the CPP_GITHUB\vcpkg\vcpkgmm-passwords key vault)
+- [ ] Update the macos host
+- [ ] (Once only) install `macosvm` to `~` (this tarball is also backed up in our `vcpkg-image-minting` storage account). For example from a dev workstation:
+ ```sh
+ ssh vcpkg@HOSTMACHINE
+ curl -L -o macosvm-0.2-1-arm64-darwin21.tar.gz https://github.com/s-u/macosvm/releases/download/0.2-1/macosvm-0.2-1-arm64-darwin21.tar.gz
+ tar xvf macosvm-0.2-1-arm64-darwin21.tar.gz
+ rm macosvm-0.2-1-arm64-darwin21.tar.gz
+ exit
+ ```
+- [ ] Download the matching `.ipsw` for the macOS copy to install. See https://mrmacintosh.com/apple-silicon-m1-full-macos-restore-ipsw-firmware-files-database/ ; links there to find the .ipsw. Example: https://updates.cdn-apple.com/2025SummerFCS/fullrestores/093-10809/CFD6DD38-DAF0-40DA-854F-31AAD1294C6F/UniversalMac_15.6.1_24G90_Restore.ipsw
+- [ ] Determine the VM name using the form "vcpkg-osx-<date>-arm64", for example "vcpkg-osx-2025-09-11-arm64".
+- [ ] Open a terminal and run the following commands to create the VM with vcpkg-osx-2025-09-11-arm64 and UniversalMac_15.6.1_24G90_Restore.ipsw replaced as appropriate. This must be run in the KVM as it uses a GUI:
+ ```sh
+ mkdir -p ~/Parallels/vcpkg-osx-2025-09-11-arm64
+ cd ~/Parallels/vcpkg-osx-2025-09-11-arm64
+ ~/macosvm --disk disk.img,size=500g --aux aux.img -c 8 -r 12g --restore ~/UniversalMac_15.6.1_24G90_Restore.ipsw ./vm.json
+ ~/macosvm -g ./vm.json
+ ```
+- [ ] Follow prompts as you would on real hardware.
+ * Set up as new.
+ * Account name: vcpkg
+ * A very similar password
+ * Do not allow computer account password to be reset with your Apple Account.
+ * Apple ID: 'Set Up Later' / Skip
+ * No location services
+ * Yes send crash reports
+ * Set up screen time later
+ * Only download updates automatically
+- [ ] Set the desktop wallpaper to a fixed color from Settings -> Wallpaper . (This makes the KVM a lot easier to use :) )
+- [ ] Disable automatic updates in the VM: Settings -> General -> Automatic Updates -> Disable them all
+- [ ] Enable remote login in the VM: Settings -> General -> Sharing -> Remote Login
+- [ ] Set the vcpkg user to be able to use sudo without a password, and install Xcode. For example from a dev workstation:
+ ```sh
+ scp path/to/Xcode.xip vcpkg@HOSTMACHINE:/Users/vcpkg/Xcode.xip
+ ssh vcpkg@HOSTMACHINE
+ rm ~/.ssh/known_hosts
+ scp Xcode.xip vcpkg@vcpkgs-Virtual-Machine.local:/Users/vcpkg/Xcode.xip
+ ssh vcpkg@vcpkgs-Virtual-Machine.local
+ printf 'vcpkg\tALL=(ALL)\tNOPASSWD:\tALL\n' | sudo tee -a '/etc/sudoers.d/vcpkg'
+ sudo chmod 0440 '/etc/sudoers.d/vcpkg'
+ sudo mdutil -ad
+ xip --expand Xcode.xip
+ sudo mv Xcode.app /Applications/Xcode.app
+ rm Xcode.xip
+ exit
+ ```
+- [ ] Open Xcode from Applications in the guest GUI. Uncheck the "code completion model" and accept the EULA.
+- [ ] Update the Azure Agent URI in setup-box.sh to the current version. You can find this by going to the agent pool, selecting "New agent", picking macOS, and copying the link. For example https://download.agent.dev.azure.com/agent/4.261.0/vsts-agent-osx-arm64-4.261.0.tar.gz
+- [ ] Copy setup-box.sh and the xcode installer renamed to 'clt.dmg' to the host. For example from a dev workstation:
+ ```sh
+ scp ./setup-guest.sh vcpkg@HOSTMACHINE:/Users/vcpkg
+ scp ./setup-box.sh vcpkg@HOSTMACHINE:/Users/vcpkg
+ scp path/to/console/tools.dmg vcpkg@HOSTMACHINE:/Users/vcpkg/clt.dmg
+ ssh vcpkg@HOSTMACHINE
+ chmod +x setup-guest.sh
+ ./setup-guest.sh
+ rm setup-guest.sh
+ rm setup-box.sh
+ rm clt.dmg
+ exit
+ ```
+- [ ] Shut down the VM cleanly.
+- [ ] Mint a SAS token to vcpkgimageminting/pvms with read, add, create, write, and list permissions.
+- [ ] Package the VM into a tarball. For example from a dev workstation:
+ ```sh
+ ssh vcpkg@HOSTMACHINE
+ cd ~/Parallels
+ aa archive -d vcpkg-osx-<date>-arm64 -o vcpkg-osx-<date>-arm64.aar -enable-holes
+ brew install azcopy
+ azcopy copy vcpkg-osx-<date>-arm64.aar "https://vcpkgimageminting.blob.core.windows.net/pvms?<SAS>"
+ exit
+ ```
+- [ ] Go to https://dev.azure.com/vcpkg/public/_settings/agentqueues and create a new self hosted Agent pool named `PrOsx-YYYY-MM-DD-arm64` based on the current date. Grant microsoft.vcpkg.ci and microsoft.vcpkg.pr access.
+- [ ] Follow the "Deploying images" steps below for each machine in the fleet.
+
+## Deploying images
+
+### Running the VM (AMD64)
+
+Run these steps on each machine to add to the fleet. Skip steps that were done implicitly above if this machine was used to build a box.
+
+- [ ] If this machine was used before, delete it from the pool of which it is a member from https://dev.azure.com/vcpkg/public/_settings/agentqueues
+- [ ] Log in to the machine using the KVM.
+- [ ] Check for software updates in macOS system settings
+- [ ] Check for software updates in Parallels' UI
+- [ ] Mint a SAS token URI to the box to use from the Azure portal if you don't already have one, and download the VM. (Recommend running this via SSH from domain joined machine due to containing SAS tokens). From a developer machine:
+ ```sh
+ ssh vcpkg@HOSTMACHINE
+ brew install azcopy
+ cd ~/Parallels
+ azcopy copy "https://vcpkgimageminting.blob.core.windows.net/pvms/vcpkg-osx-<DATE>.pvmp?<SAS>" .
+ azcopy copy "https://vcpkgimageminting.blob.core.windows.net/pvms/vcpkg-osx-<DATE>.sha256.txt?<SAS>" .
+ exit
+ ```
+- [ ] Open the .pvmp in Parallels, and unpack it.
+- [ ] Open the 'Configure' screen for the VM, and under Options -> Startup and Shutdown, set the following:
+ * Custom
+ * Start Automatically: When Mac Starts
+ * Startup View: Headless
+ * On VM Shutdown: Close Window (this one should already be set)
+ * On Mac Shutdown: Shut Down
+ * On Window Close: Keep Running in the Background
+- [ ] Under 'More Options':
+ * Time: Do not sync
+ * Uncheck 'Update Parallels Tools automatically'
+- [ ] Close and restart Parallels Desktop. The VM should start automatically. If it does not, start it.
+- [ ] [grab a PAT][] if you don't already have one
+- [ ] Copy the guest deploy script to the host, and run it with a first parameter of your PAT. From a developer machine:
+ ```sh
+ scp register-guest.sh vcpkg@HOSTMACHINE:/Users/vcpkg/register-guest.sh
+ ssh vcpkg@HOSTMACHINE
+ rm .ssh/known_hosts
+ chmod +x register-guest.sh
+ ./register-guest.sh PAT GOES HERE
+ rm register-guest.sh
+ ```
+- [ ] In the VM, open a terminal on the host and run:
+ ```
+ ssh -i ~/Parallels/*/id_guest vcpkg@`prlctl list --full | sed -nr 's/^.*running *([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}).*/\1/p'`
+ ~/myagent/run.sh
+ ```
+- [ ] Check that the machine shows up in the pool.
+- [ ] Lock the screen on the host.
+- [ ] Update the "vcpkg Macs" spreadsheet line for the machine with the new pool.
+
+[grab a PAT]: #getting-an-azure-pipelines-pat
+
+### Running the VM (ARM64)
+
+Run these steps on each machine to add to the fleet. Skip steps that were done implicitly above if this machine was used to build a box.
+
+- [ ] If this machine was used before, delete it from the pool of which it is a member from https://dev.azure.com/vcpkg/public/_settings/agentqueues
+- [ ] Log in to the machine using the KVM.
+- [ ] Check for software updates in macOS system settings
+- [ ] (Once only) install `macosvm` to `~` (this tarball is also backed up in our `vcpkg-image-minting` storage account). From a developer machine:
+ ```sh
+ ssh vcpkg@HOSTMACHINE
+ curl -L -o macosvm-0.2-1-arm64-darwin21.tar.gz https://github.com/s-u/macosvm/releases/download/0.2-1/macosvm-0.2-1-arm64-darwin21.tar.gz
+ tar xvf macosvm-0.2-1-arm64-darwin21.tar.gz
+ rm macosvm-0.2-1-arm64-darwin21.tar.gz
+ exit
+ ```
+- [ ] Skip if this is the image building machine. Mint a SAS token URI to the box to use from the Azure portal if you don't already have one, and download the VM. (Recommend running this via SSH from domain joined machine due to containing SAS tokens). From a developer machine:
+ ```sh
+ ssh vcpkg@HOSTMACHINE
+ brew install azcopy
+ mkdir -p ~/Parallels
+ cd ~/Parallels
+ azcopy copy "https://vcpkgimageminting.blob.core.windows.net/pvms/vcpkg-osx-<DATE>-arm64.aar?<SAS>" vcpkg-osx-<DATE>-arm64.aar
+ aa extract -d vcpkg-osx-<DATE>-arm64 -i ./vcpkg-osx-<DATE>-arm64.aar -enable-holes
+ exit
+ ```
+- [ ] Open a separate terminal window on the host and start the VM by running:
+ ```sh
+ cd ~/Parallels/vcpkg-osx-<DATE>-arm64
+ ~/macosvm ./vm.json
+ ```
+- [ ] [grab a PAT][] if you don't already have one
+- [ ] Copy the guest deploy script to the host, and run it with a first parameter of your PAT. From a developer machine:
+ ```sh
+ scp register-guest.sh vcpkg@HOSTMACHINE:/Users/vcpkg/register-guest.sh
+ ssh vcpkg@HOSTMACHINE
+ rm .ssh/known_hosts
+ chmod +x register-guest.sh
+ ./register-guest.sh PAT GOES HERE
+ rm register-guest.sh
+ ```
+- [ ] That will cleanly shut down the VM. In the KVM's terminal, relaunch the VM in ephemeral mode with:
+ ```sh
+ ~/macosvm --ephemeral ./vm.json
+ ```
+- [ ] Open a terminal window on the host and run the agent
+ ```sh
+ ssh -i ~/Parallels/*/id_guest vcpkg@vcpkgs-Virtual-Machine.local
+ ~/myagent/run.sh
+ ```
+- [ ] Check that the machine shows up in the pool, and lock the vcpkg user on the host.
+- [ ] Lock the screen on the host.
+- [ ] Update the "vcpkg Macs" spreadsheet line for the machine with the new pool.
+
+[grab a PAT]: #getting-an-azure-pipelines-pat
+
+## Getting an Azure Pipelines PAT
+
+Personal Access Tokens are an important part of this process,
+and they are fairly easy to generate.
+On ADO, under the correct project (in vcpkg's case, "vcpkg"),
+click on the "User Settings" icon, then go to "Personal access tokens".
+It is the icon to the left of your user icon, in the top right corner.
+
+Then, create a new token, give it a name, make sure it expires quickly,
+and give it a custom defined scope that includes the
+"Agent pools: Read & manage" permission (you'll need to "Show all scopes"
+to access this).
+You can now copy this token and use it to allow machines to join.
diff --git a/vcpkg/scripts/azure-pipelines/osx/azure-pipelines.yml b/vcpkg/scripts/azure-pipelines/osx/azure-pipelines.yml
new file mode 100644
index 0000000..db31a00
--- /dev/null
+++ b/vcpkg/scripts/azure-pipelines/osx/azure-pipelines.yml
@@ -0,0 +1,109 @@
+# 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: 'x64_osx'
+ - name: poolName
+ type: string
+ - 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: ${{ parameters.poolName }}
+ workspace:
+ clean: resources
+ timeoutInMinutes: 2880 # 2 days
+ variables:
+ - name: WORKING_ROOT
+ value: /Users/vcpkg/Data
+ - name: VCPKG_DOWNLOADS
+ value: /Users/vcpkg/Data/downloads
+ steps:
+ - bash: |
+ sudo mdutil -ad || 0
+ sudo mkdir ${{ variables.VCPKG_DOWNLOADS }} || 0
+ sudo chmod 777 ${{ variables.VCPKG_DOWNLOADS }} || 0
+ exit 0
+ displayName: 'Create ${{ variables.VCPKG_DOWNLOADS }}'
+ - bash: ./bootstrap-vcpkg.sh
+ displayName: 'Bootstrap vcpkg'
+ condition: eq('use default', '${{ parameters.vcpkgToolSha }}')
+ - bash: ./scripts/azure-pipelines/bootstrap-from-source.sh ${{ parameters.vcpkgToolSha }}
+ displayName: "Build vcpkg with CMake"
+ condition: ne('use default', '${{ parameters.vcpkgToolSha }}')
+ - 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: 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'
+ inputs:
+ version: '22.x'
+ - bash: |
+ cd scripts/azure-pipelines/owners-db && npm ci || true
+ # Construct the blob base url using the secret SAS token set earlier
+ blob="https://vcpkgbinarycachewus.blob.core.windows.net/cache?${BCACHE_SAS_TOKEN}"
+ if [ "$(Build.Reason)" = "PullRequest" ]; then
+ echo "Running file_script_from_cache for PR"
+ npx --yes ts-node ./file_script_from_cache.ts --pr-hashes "$(Build.ArtifactStagingDirectory)/pr-hashes.json" --blob-base-url "$blob" --target-branch "origin/master" --out-dir ../../list_files
+ else
+ echo "Running file_script for CI"
+ npx --yes ts-node ./file_script.ts --info-dir /Users/vcpkg/Data/installed/vcpkg/info/ --out-dir ../../list_files
+ fi
+ displayName: 'Build a file list for all packages'
+ condition: always()
+ 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, '_', '-') }}
+ configuration: static
diff --git a/vcpkg/scripts/azure-pipelines/osx/register-guest.sh b/vcpkg/scripts/azure-pipelines/osx/register-guest.sh
new file mode 100644
index 0000000..f714e45
--- /dev/null
+++ b/vcpkg/scripts/azure-pipelines/osx/register-guest.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+if [ -z "$1" ]; then
+ echo "PAT missing"
+ exit 1
+fi
+export AGENT=$(hostname | sed -nr 's/([^.]+).*/\1/p' | tr '[:lower:]' '[:upper:]')
+echo "THIS IS AGENT: $AGENT"
+if [ `uname -m` = 'arm64' ]; then
+export POOL=`echo ~/Parallels/*/ | sed -nr 's/\/Users\/vcpkg\/Parallels\/vcpkg-osx-([0-9]{4}-[0-9]{2}-[0-9]{2})-arm64\/$/PrOsx-\1-arm64/p'`
+# on arm64, DNS works
+export SSH_COOKIE=vcpkg@vcpkgs-Virtual-Machine.local
+else
+export POOL=`echo ~/Parallels/*.pvm | sed -nr 's/\/Users\/vcpkg\/Parallels\/vcpkg-osx-([0-9]{4}-[0-9]{2}-[0-9]{2})\.pvm/PrOsx-\1/p'`
+# on amd64, DNS does not work, but luckily for us prlctl does know the IP
+export GUEST_IP=`prlctl list --full | sed -nr 's/^.*running *([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}).*/\1/p'`
+export SSH_COOKIE=vcpkg@$GUEST_IP
+fi
+echo "POOL: $POOL"
+echo "SSH_COOKIE: $SSH_COOKIE"
+ssh $SSH_COOKIE -o "StrictHostKeyChecking=no" -i ~/Parallels/*/id_guest "~/myagent/config.sh --unattended --url https://dev.azure.com/vcpkg --work ~/Data/work --auth pat --token $1 --pool $POOL --agent $AGENT --replace --acceptTeeEula"
+if [ `uname -m` = 'arm64' ]; then
+ ssh $SSH_COOKIE -o "StrictHostKeyChecking=no" -i ~/Parallels/*/id_guest "sudo shutdown -h now"
+fi
diff --git a/vcpkg/scripts/azure-pipelines/osx/setup-box.sh b/vcpkg/scripts/azure-pipelines/osx/setup-box.sh
new file mode 100644
index 0000000..0dd81e7
--- /dev/null
+++ b/vcpkg/scripts/azure-pipelines/osx/setup-box.sh
@@ -0,0 +1,26 @@
+#!/bin/sh
+
+hdiutil attach clt.dmg -mountpoint /Volumes/setup-installer
+sudo installer -pkg "/Volumes/setup-installer/Command Line Tools.pkg" -target /
+hdiutil detach /Volumes/setup-installer
+rm clt.dmg
+sudo xcode-select -s /Applications/Xcode.app
+/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
+if [ `uname -m` = 'arm64' ]; then
+ (echo; echo 'eval "$(/opt/homebrew/bin/brew shellenv)"') >> /Users/vcpkg/.zprofile
+ eval "$(/opt/homebrew/bin/brew shellenv)"
+else
+ (echo; echo 'eval "$(/usr/local/bin/brew shellenv)"') >> /Users/vcpkg/.zprofile
+ eval "$(/usr/local/bin/brew shellenv)"
+fi
+brew install autoconf-archive autoconf automake azcopy azure-cli bison cmake gettext gfortran gnu-sed gperf gtk-doc libtool meson mono nasm ninja pkg-config powershell python-setuptools texinfo yasm
+mkdir ~/Data
+if [ `uname -m` = 'arm64' ]; then
+curl -s -o ~/Downloads/azure-agent.tar.gz https://download.agent.dev.azure.com/agent/4.261.0/vsts-agent-osx-arm64-4.261.0.tar.gz
+else
+curl -s -o ~/Downloads/azure-agent.tar.gz https://download.agent.dev.azure.com/agent/4.261.0/vsts-agent-osx-x64-4.261.0.tar.gz
+fi
+mkdir ~/myagent
+tar xf ~/Downloads/azure-agent.tar.gz -C ~/myagent
+rm ~/Downloads/azure-agent.tar.gz
+rm setup-box.sh
diff --git a/vcpkg/scripts/azure-pipelines/osx/setup-guest.sh b/vcpkg/scripts/azure-pipelines/osx/setup-guest.sh
new file mode 100644
index 0000000..8efd97d
--- /dev/null
+++ b/vcpkg/scripts/azure-pipelines/osx/setup-guest.sh
@@ -0,0 +1,21 @@
+#!/bin/sh
+export VM_DIRECTORY=`ls ~/Parallels | grep vcpkg-osx`
+export SSH_KEY="$HOME/Parallels/$VM_DIRECTORY/id_guest"
+export SSH_PUBLIC_KEY="$SSH_KEY.pub"
+ssh-keygen -P '' -f "$SSH_KEY"
+if [ `uname -m` = 'arm64' ]; then
+# on arm64, prlctl does not know the IP address, but luckily for us DNS works
+export SSH_COOKIE=vcpkg@vcpkgs-Virtual-Machine.local
+else
+# on amd64, DNS does not work, but luckily for us prlctl does know the IP
+export GUEST_IP=`prlctl list --full | sed -nr 's/^.*running *([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}).*/\1/p'`
+export SSH_COOKIE=vcpkg@$GUEST_IP
+fi
+echo Type 'vcpkg' and press enter
+ssh-copy-id -i "$SSH_PUBLIC_KEY" $SSH_COOKIE
+echo Keys deployed
+ssh $SSH_COOKIE -i "$SSH_KEY" echo hello from \`hostname\`
+scp -i "$SSH_KEY" ./clt.dmg $SSH_COOKIE:/Users/vcpkg/clt.dmg
+scp -i "$SSH_KEY" ./setup-box.sh $SSH_COOKIE:/Users/vcpkg/setup-box.sh
+ssh $SSH_COOKIE -i "$SSH_KEY" chmod +x /Users/vcpkg/setup-box.sh
+ssh $SSH_COOKIE -i "$SSH_KEY" /Users/vcpkg/setup-box.sh
diff --git a/vcpkg/scripts/azure-pipelines/osx/start-parallels-vm.zsh b/vcpkg/scripts/azure-pipelines/osx/start-parallels-vm.zsh
new file mode 100644
index 0000000..5e60b2a
--- /dev/null
+++ b/vcpkg/scripts/azure-pipelines/osx/start-parallels-vm.zsh
@@ -0,0 +1,47 @@
+#!/usr/bin/env zsh
+
+set -e # Exit on any error
+
+# Find the .pvmp file
+PVMP_FILE=$(find ~/Parallels -name "*.pvmp" -type f | head -1)
+if [[ -z "$PVMP_FILE" ]]; then
+ echo "Error: No .pvmp file found in ~/Parallels"
+ exit 1
+fi
+
+echo "Found PVMP file: $PVMP_FILE"
+
+# Attach the PVMP file
+echo "Registering PVMP file..."
+/usr/local/bin/prlctl register "$PVMP_FILE"
+
+VM_NAME=$(/usr/local/bin/prlctl list --all --output name --no-header | head -1)
+
+if [[ -z "$VM_NAME" ]]; then
+ echo "Error: Failed to register PVMP file or extract VM ID"
+ exit 1
+fi
+
+echo "VM registered with ID: $VM_NAME"
+
+# Unpack the VM
+echo "Unpacking VM..."
+/usr/local/bin/prlctl unpack "$VM_NAME"
+
+# Configure startup and shutdown settings
+echo "Configuring VM startup and shutdown settings..."
+/usr/local/bin/prlctl set "$VM_NAME" --startup-view headless
+/usr/local/bin/prlctl set "$VM_NAME" --autostart start-host
+/usr/local/bin/prlctl set "$VM_NAME" --autostop shutdown
+/usr/local/bin/prlctl set "$VM_NAME" --on-shutdown close
+/usr/local/bin/prlctl set "$VM_NAME" --on-window-close keep-running
+
+echo "VM startup and shutdown settings configured successfully"
+
+# Display current VM configuration for verification
+echo "Current VM configuration:"
+/usr/local/bin/prlctl list "$VM_NAME" --info | grep -E "(Autostart|Autostop|Startup view|On shutdown|On window close)"
+
+echo "Parallels VM setup completed successfully!"
+echo "VM ID: $VM_NAME"
+
diff --git a/vcpkg/scripts/azure-pipelines/osx/stop-delete-all-vms.zsh b/vcpkg/scripts/azure-pipelines/osx/stop-delete-all-vms.zsh
new file mode 100644
index 0000000..1eb6fef
--- /dev/null
+++ b/vcpkg/scripts/azure-pipelines/osx/stop-delete-all-vms.zsh
@@ -0,0 +1,17 @@
+#!/usr/bin/env zsh
+
+vm_name=$(/usr/local/bin/prlctl list --all --output name --no-header 2>/dev/null | head -1)
+if [[ -z "$vm_name" ]]; then
+ echo "No VM found on the system."
+ exit 0
+fi
+
+echo "Found VM: $vm_name"
+
+# Stop the VM if it's running
+echo "Stopping VM..."
+/usr/local/bin/prlctl stop "$vm_name" --kill 2>/dev/null || echo "VM was already stopped or failed to stop"
+
+# Delete the VM
+echo "Deleting VM..."
+/usr/local/bin/prlctl delete "$vm_name" \ No newline at end of file
diff --git a/vcpkg/scripts/azure-pipelines/owners-db/README.md b/vcpkg/scripts/azure-pipelines/owners-db/README.md
new file mode 100644
index 0000000..023058e
--- /dev/null
+++ b/vcpkg/scripts/azure-pipelines/owners-db/README.md
@@ -0,0 +1,96 @@
+Owners DB helpers
+=================
+
+Summary
+-------
+This directory contains two small Node.js CLI helpers used by the Azure Pipelines owners-db step to build two plain-text database files used by downstream tooling:
+
+- `file_script.ts` — builds databases from a local `info` directory (used in CI runs where vcpkg is installed locally).
+- `file_script_from_cache.ts` — builds databases by downloading package ZIPs from a binary cache (used in PR runs that can consult prebuilt artifacts).
+
+Both scripts produce the same output file formats described below:
+
+- `VCPKGDatabase.txt` — a newline-separated list of entries of the form `port:triplet:/path/inside/package`.
+- `VCPKGHeadersDatabase.txt` — a newline-separated list of entries of the form `port:triplet:relative/header/path`
+
+These files are emitted to `--out-dir` (default `scripts/list_files`).
+
+Usage
+-----
+
+file_script.ts (local info-dir mode)
+
+```text
+file_script.ts --info-dir <path-to-info-dir> [--out-dir <path>]
+```
+
+Behavior and input format:
+
+- `--info-dir <path>` should point at a directory containing vcpkg-generated `.list` files (the same layout created by `vcpkg` under `installed/<triplet>/vcpkg/info/`).
+- Each file in that directory is expected to follow the filename convention used by vcpkg info files. The script parses the filename by splitting on underscores and constructs a package identifier using the first and third components:
+
+ <package>_<...>_<triplet>.list --> package id = `<package>:<triplet>`
+
+- Each `.list` file is plain text with one relative file path per line. Lines that are empty, or which end in `/` are ignored. If a line contains any prefix before a `/`, the script strips the prefix and uses only the path starting at the first `/`.
+
+Examples of lines processed from `.list` files:
+
+- `share/zlib/include/zlib.h` -> entry `zlib:x64-windows:/share/zlib/include/zlib.h`
+- `someprefix/share/zlib/include/zlib.h` -> same as above (prefix before first `/` is dropped)
+
+file_script_from_cache.ts (PR cache mode)
+
+```text
+file_script_from_cache.ts --pr-hashes <pr-hashes.json> --blob-base-url <blob-base-url> [--target-branch <branch>] [--out-dir <path>]
+```
+
+Required inputs:
+
+- `--pr-hashes <pr-hashes.json>` is a JSON file produced by the vcpkg tooling that lists changed ports and their ABIs. The script expects a top-level JSON array of objects where each object contains at least the following fields:
+
+ {
+ "name": "<port-name>",
+ "triplet": "<triplet>",
+ "state": "<state>",
+ "abi": "<sha>"
+ }
+
+ Important: in this script the `abi` field is expected to be the 64-hex SHA string used to name the ZIP blob in the binary cache (the script validates `abi` against `/^[a-f0-9]{64}$/`).
+
+- `--blob-base-url <blob-base-url>` should be a URL that points to a binary cache container and include any required SAS token (for example: `https://<account>.blob.core.windows.net/cache?<sas>`). The script will insert `/<sha>.zip` into that base URL to download the package ZIP for each port/abi pair and then enumerate files inside each ZIP.
+
+Output file formats
+-------------------
+
+Both scripts write two files into the chosen `--out-dir` (default `scripts/list_files`):
+
+- `VCPKGDatabase.txt`
+ - Each line has the form: `<port>:<triplet>:<filepath>`
+ - `<filepath>` begins with a leading `/` when sourced from `.list` files or ZIP entries; it is the path inside the package (for example `/share/zlib/include/zlib.h`).
+
+- `VCPKGHeadersDatabase.txt`
+ - Each line has the form: `<port>:<triplet>:<relative/header/path>`
+ - Only files whose path starts with `/include/` are recorded here and the `/include/` prefix is removed from the path. For example, an entry for `/include/zlib.h` will produce `zlib:x64-windows:zlib.h`.
+
+Exit codes and errors
+---------------------
+
+- Both scripts print an error and exit non-zero on fatal problems (invalid arguments, invalid `pr-hashes.json`, or failed git diff in the cache variant).
+- `file_script_from_cache.ts` will attempt to download each expected ZIP; failures to download or process a single package are reported as warnings and the script continues — missing entries will simply be absent from the output.
+
+Examples
+--------
+
+Local info-dir:
+
+```sh
+npx ts-node ./file_script.ts --info-dir /mnt/vcpkg-ci/installed/vcpkg/info --out-dir ./scripts/list_files
+```
+
+PR cache mode (pipeline example using `BCACHE_SAS_TOKEN` set as a secret variable):
+
+```sh
+# pipeline constructs the URL from the secret token and passes it to the script
+blob="https://vcpkgbinarycachewus.blob.core.windows.net/cache?${BCACHE_SAS_TOKEN}"
+npx --yes ts-node ./file_script_from_cache.ts --pr-hashes /path/to/pr-hashes.json --blob-base-url "$blob" --target-branch origin/master --out-dir ./scripts/list_files
+```
diff --git a/vcpkg/scripts/azure-pipelines/owners-db/file_script.ts b/vcpkg/scripts/azure-pipelines/owners-db/file_script.ts
new file mode 100644
index 0000000..abb79dc
--- /dev/null
+++ b/vcpkg/scripts/azure-pipelines/owners-db/file_script.ts
@@ -0,0 +1,93 @@
+#!/usr/bin/env node
+import * as fs from "fs";
+import * as path from "path";
+
+const include_subpath = "/include/";
+
+function getFiles(dirPath: string): string[] {
+ const files = fs.readdirSync(dirPath);
+ return files.filter((f) => !f.startsWith("."));
+}
+
+function genAllFileStrings(
+ dirPath: string,
+ files: string[],
+ headersStream: fs.WriteStream,
+ outputStream: fs.WriteStream
+) {
+ for (const file of files) {
+ const components = file.split("_");
+ const pkg = components[0] + ":" + components[2].replace(".list", "");
+ const content = fs.readFileSync(path.join(dirPath, file), "utf8");
+ const lines = content.split(/\r?\n/);
+ for (const raw of lines) {
+ if (!raw) continue;
+ const line = raw.trim();
+ if (line.length === 0) continue;
+ if (line.endsWith("/")) continue;
+ // Remove the leading triplet directory
+ const idx = line.indexOf("/");
+ const filepath = idx >= 0 ? line.substring(idx) : line;
+ outputStream.write(pkg + ":" + filepath + "\n");
+ if (filepath.startsWith(include_subpath)) {
+ headersStream.write(pkg + ":" + filepath.substring(include_subpath.length) + "\n");
+ }
+ }
+ }
+}
+
+function usage() {
+ console.error("Usage: file_script.ts --info-dir <path-to-info-dir> [--out-dir <path>]");
+}
+
+function parseArgs(argv: string[]) {
+ let infoDir: string | undefined;
+ let outDir = "scripts/list_files";
+ for (let i = 0; i < argv.length; i++) {
+ const a = argv[i];
+ if (a === "--info-dir") {
+ i++;
+ infoDir = argv[i];
+ } else if (a === "--out-dir") {
+ i++;
+ outDir = argv[i];
+ } else if (a.startsWith("--")) {
+ console.error(`Unknown argument: ${a}`);
+ usage();
+ process.exit(2);
+ } else {
+ console.error(`Unexpected positional argument: ${a}`);
+ usage();
+ process.exit(2);
+ }
+ }
+ if (!infoDir) {
+ console.error("info-dir is required");
+ usage();
+ process.exit(2);
+ }
+ return { infoDir, outDir };
+}
+
+function main() {
+ const { infoDir: dir, outDir } = parseArgs(process.argv.slice(2));
+ try {
+ fs.mkdirSync(outDir, { recursive: true });
+ } catch {
+ // ignore
+ }
+
+ const headersPath = path.join(outDir, "VCPKGHeadersDatabase.txt");
+ const dbPath = path.join(outDir, "VCPKGDatabase.txt");
+ const headers = fs.createWriteStream(headersPath, { encoding: "utf8" });
+ const output = fs.createWriteStream(dbPath, { encoding: "utf8" });
+ try {
+ const files = getFiles(dir);
+ genAllFileStrings(dir, files, headers, output);
+ } finally {
+ headers.end();
+ output.end();
+ }
+}
+
+main();
diff --git a/vcpkg/scripts/azure-pipelines/owners-db/file_script_from_cache.ts b/vcpkg/scripts/azure-pipelines/owners-db/file_script_from_cache.ts
new file mode 100644
index 0000000..7b91c1f
--- /dev/null
+++ b/vcpkg/scripts/azure-pipelines/owners-db/file_script_from_cache.ts
@@ -0,0 +1,184 @@
+#!/usr/bin/env node
+import * as fs from "fs";
+import * as path from "path";
+import * as https from "https";
+import AdmZip from "adm-zip";
+import { execSync } from "child_process";
+
+const keyword = "/include/";
+
+function writeOutputLines(outDir: string, dbLines: string[], headerLines: string[]) {
+ fs.mkdirSync(outDir, { recursive: true });
+ fs.writeFileSync(path.join(outDir, "VCPKGDatabase.txt"), dbLines.join("\n") + (dbLines.length ? "\n" : ""));
+ fs.writeFileSync(path.join(outDir, "VCPKGHeadersDatabase.txt"), headerLines.join("\n") + (headerLines.length ? "\n" : ""));
+}
+
+function listZipFiles(buffer: Buffer, pkgName: string, dbLines: string[], headerLines: string[]) {
+ const zip = new AdmZip(buffer);
+ const entries = zip.getEntries();
+ for (const e of entries) {
+ if (e.isDirectory) continue;
+ const entryName = "/" + e.entryName.replace(/\\/g, "/");
+ if (entryName === "/BUILD_INFO" || entryName === "/CONTROL") continue;
+ dbLines.push(`${pkgName}:${entryName}`);
+ if (entryName.startsWith(keyword)) {
+ headerLines.push(`${pkgName}:${entryName.substring(keyword.length)}`);
+ }
+ }
+}
+
+function downloadUrlToBuffer(url: string): Promise<Buffer> {
+ return new Promise((resolve, reject) => {
+ https.get(url, (res) => {
+ if (res.statusCode && res.statusCode >= 400) {
+ reject(new Error(`HTTP ${res.statusCode} while fetching ${url}`));
+ return;
+ }
+ const chunks: Buffer[] = [];
+ res.on("data", (c) => chunks.push(c));
+ res.on("end", () => resolve(Buffer.concat(chunks)));
+ }).on("error", reject);
+ });
+}
+
+function usage() {
+ console.error("Usage: file_script_from_cache.ts --pr-hashes <pr-hashes.json> --blob-base-url <blob-base-url> [--target-branch <branch>] [--out-dir <path>]");
+ console.error("blob-base-url should include SAS token (e.g. https://<account>.blob.core.windows.net/<container>/?<sas>)");
+}
+
+function parseArgs(argv: string[]) {
+ // supports: --pr-hashes <path> --blob-base-url <url> [--target-branch <branch>] [--out-dir <path>]
+ // legacy: positional: <pr-hashes> <blob-base-url> [target-branch]
+ let prHashesPath: string | undefined;
+ let blobBaseUrl: string | undefined;
+ let targetBranch = "master";
+ let outDir = "scripts/list_files";
+ for (let i = 0; i < argv.length; i++) {
+ const a = argv[i];
+ if (a === "--pr-hashes") {
+ i++;
+ prHashesPath = argv[i];
+ } else if (a === "--blob-base-url") {
+ i++;
+ blobBaseUrl = argv[i];
+ } else if (a === "--target-branch") {
+ i++;
+ targetBranch = argv[i];
+ } else if (a === "--out-dir") {
+ i++;
+ outDir = argv[i];
+ } else if (a.startsWith("--")) {
+ console.error(`Unknown argument: ${a}`);
+ usage();
+ process.exit(2);
+ } else if (!prHashesPath) {
+ prHashesPath = a;
+ } else if (!blobBaseUrl) {
+ blobBaseUrl = a.replace(/[\/\\]+$/g, "");
+ } else if (targetBranch === "master") {
+ targetBranch = a;
+ } else {
+ console.error(`Unexpected positional argument: ${a}`);
+ usage();
+ process.exit(2);
+ }
+ }
+ if (!prHashesPath || !blobBaseUrl) {
+ usage();
+ process.exit(2);
+ }
+ return { prHashesPath, blobBaseUrl, targetBranch, outDir };
+}
+
+async function main() {
+ const { prHashesPath, blobBaseUrl, targetBranch, outDir } = parseArgs(process.argv.slice(2));
+
+ const prHashes = JSON.parse(fs.readFileSync(prHashesPath, "utf8")) as Array<{ name: string; triplet: string; state: string; abi: string }>;
+ // Expect vcpkg-tool produced format: array of objects
+ // [ { "name": "zlib", "triplet": "x64-windows", "state": "pass", "abi": "zlib:x64-windows:<sha>" }, ... ]
+ if (!Array.isArray(prHashes)) {
+ console.error(
+ `Invalid pr-hashes.json format: expected a top-level JSON array (vcpkg-tool output).`
+ );
+ process.exit(2);
+ }
+
+ const dbLines: string[] = [];
+ const headerLines: string[] = [];
+
+ // Determine list of ports to process from git-diff (only folders under ports/ that changed)
+ let changedPorts: string[] = [];
+ try {
+ const mergebase = execSync(`git merge-base ${targetBranch} HEAD`, { encoding: "utf8" }).trim();
+ // Find repository root by locating .vcpkg-root in or above cwd
+ function findRepoRoot(): string {
+ let dir = process.cwd();
+ while (true) {
+ if (fs.existsSync(path.join(dir, ".vcpkg-root"))) return dir;
+ const parent = path.dirname(dir);
+ if (parent === dir) break;
+ dir = parent;
+ }
+ throw new Error("Could not find .vcpkg-root in or above current working directory");
+ }
+
+ const repoRoot = findRepoRoot();
+ const diffOut = execSync(`git diff --name-only ${mergebase}...HEAD -- ports/`, { encoding: "utf8", cwd: repoRoot });
+ const files = diffOut.split(/\r?\n/).filter((l) => l.length > 0);
+ const set = new Set<string>();
+ for (const f of files) {
+ const m = f.match(/^ports\/([^\/]+)/);
+ if (m) set.add(m[1]);
+ }
+ changedPorts = Array.from(set);
+ if (changedPorts.length === 0) {
+ console.log(`git diff found no changed ports under ports/ for range ${mergebase}...HEAD; exiting.`);
+ writeOutputLines(outDir, dbLines, headerLines);
+ return;
+ }
+ } catch (e) {
+ console.error(`git diff failed (${e}); this is fatal in PR cache mode.`);
+ process.exit(2);
+ }
+
+ for (const port of changedPorts) {
+ for (const item of prHashes) {
+ if (item.name !== port) continue;
+ // Validate sha format
+ const sha1Regex = /^[a-f0-9]{64}$/;
+ if (!sha1Regex.test(item.abi)) {
+ throw new Error(`Invalid SHA format in pr-hashes.json for port ${port}: ${item.abi}`);
+ }
+ const abi = item.abi;
+ // blob named <sha>.zip
+ // Ensure we append the ABI path before the SAS query string, i.e.:
+ // https://.../<container>/<sha>.zip?<sas>
+ let blobUrl: string;
+ try {
+ const u = new URL(blobBaseUrl);
+ const sas = u.search; // includes leading '?' or empty
+ // build base path without query and without trailing slash
+ const baseNoQuery = `${u.origin}${u.pathname.replace(/[\/\\]+$/g, "")}`;
+ blobUrl = sas ? `${baseNoQuery}/${abi}.zip${sas}` : `${baseNoQuery}/${abi}.zip`;
+ } catch (e) {
+ console.error(`Invalid blob base URL provided: ${blobBaseUrl} -- ${e}`);
+ process.exit(2);
+ }
+ console.log(`Downloading ${blobUrl} for port ${port}...`);
+ try {
+ const buf = await downloadUrlToBuffer(blobUrl);
+ listZipFiles(buf, `${port}:${item.triplet}`, dbLines, headerLines);
+ } catch (err) {
+ console.warn(`Failed to download or process blob for ${port}: ${err}`);
+ }
+ }
+ }
+
+ writeOutputLines(outDir, dbLines, headerLines);
+ console.log(`Wrote ${path.join(outDir, "VCPKGDatabase.txt")} and ${path.join(outDir, "VCPKGHeadersDatabase.txt")}`);
+}
+
+await main().catch((e) => {
+ console.error("Error in script:", e);
+ process.exit(1);
+});
diff --git a/vcpkg/scripts/azure-pipelines/owners-db/package-lock.json b/vcpkg/scripts/azure-pipelines/owners-db/package-lock.json
new file mode 100644
index 0000000..78139ee
--- /dev/null
+++ b/vcpkg/scripts/azure-pipelines/owners-db/package-lock.json
@@ -0,0 +1,219 @@
+{
+ "name": "owners-db",
+ "version": "1.0.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "owners-db",
+ "version": "1.0.0",
+ "license": "MIT",
+ "dependencies": {
+ "adm-zip": "^0.5.9",
+ "ts-node": "^10.9.1",
+ "typescript": "^4.9.5"
+ },
+ "devDependencies": {
+ "@types/adm-zip": "^0.5.7"
+ },
+ "engines": {
+ "node": ">=14"
+ }
+ },
+ "node_modules/@cspotcode/source-map-support": {
+ "version": "0.8.1",
+ "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
+ "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==",
+ "dependencies": {
+ "@jridgewell/trace-mapping": "0.3.9"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@jridgewell/resolve-uri": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
+ "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@jridgewell/sourcemap-codec": {
+ "version": "1.5.5",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
+ "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="
+ },
+ "node_modules/@jridgewell/trace-mapping": {
+ "version": "0.3.9",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz",
+ "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
+ "dependencies": {
+ "@jridgewell/resolve-uri": "^3.0.3",
+ "@jridgewell/sourcemap-codec": "^1.4.10"
+ }
+ },
+ "node_modules/@tsconfig/node10": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz",
+ "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw=="
+ },
+ "node_modules/@tsconfig/node12": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz",
+ "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag=="
+ },
+ "node_modules/@tsconfig/node14": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz",
+ "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow=="
+ },
+ "node_modules/@tsconfig/node16": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz",
+ "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA=="
+ },
+ "node_modules/@types/adm-zip": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/@types/adm-zip/-/adm-zip-0.5.7.tgz",
+ "integrity": "sha512-DNEs/QvmyRLurdQPChqq0Md4zGvPwHerAJYWk9l2jCbD1VPpnzRJorOdiq4zsw09NFbYnhfsoEhWtxIzXpn2yw==",
+ "dev": true,
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/node": {
+ "version": "24.5.2",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-24.5.2.tgz",
+ "integrity": "sha512-FYxk1I7wPv3K2XBaoyH2cTnocQEu8AOZ60hPbsyukMPLv5/5qr7V1i8PLHdl6Zf87I+xZXFvPCXYjiTFq+YSDQ==",
+ "dependencies": {
+ "undici-types": "~7.12.0"
+ }
+ },
+ "node_modules/acorn": {
+ "version": "8.15.0",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
+ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
+ "bin": {
+ "acorn": "bin/acorn"
+ },
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/acorn-walk": {
+ "version": "8.3.4",
+ "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz",
+ "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==",
+ "dependencies": {
+ "acorn": "^8.11.0"
+ },
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/adm-zip": {
+ "version": "0.5.16",
+ "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.16.tgz",
+ "integrity": "sha512-TGw5yVi4saajsSEgz25grObGHEUaDrniwvA2qwSC060KfqGPdglhvPMA2lPIoxs3PQIItj2iag35fONcQqgUaQ==",
+ "engines": {
+ "node": ">=12.0"
+ }
+ },
+ "node_modules/arg": {
+ "version": "4.1.3",
+ "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
+ "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA=="
+ },
+ "node_modules/create-require": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
+ "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ=="
+ },
+ "node_modules/diff": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
+ "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
+ "engines": {
+ "node": ">=0.3.1"
+ }
+ },
+ "node_modules/make-error": {
+ "version": "1.3.6",
+ "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
+ "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw=="
+ },
+ "node_modules/ts-node": {
+ "version": "10.9.2",
+ "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz",
+ "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==",
+ "dependencies": {
+ "@cspotcode/source-map-support": "^0.8.0",
+ "@tsconfig/node10": "^1.0.7",
+ "@tsconfig/node12": "^1.0.7",
+ "@tsconfig/node14": "^1.0.0",
+ "@tsconfig/node16": "^1.0.2",
+ "acorn": "^8.4.1",
+ "acorn-walk": "^8.1.1",
+ "arg": "^4.1.0",
+ "create-require": "^1.1.0",
+ "diff": "^4.0.1",
+ "make-error": "^1.1.1",
+ "v8-compile-cache-lib": "^3.0.1",
+ "yn": "3.1.1"
+ },
+ "bin": {
+ "ts-node": "dist/bin.js",
+ "ts-node-cwd": "dist/bin-cwd.js",
+ "ts-node-esm": "dist/bin-esm.js",
+ "ts-node-script": "dist/bin-script.js",
+ "ts-node-transpile-only": "dist/bin-transpile.js",
+ "ts-script": "dist/bin-script-deprecated.js"
+ },
+ "peerDependencies": {
+ "@swc/core": ">=1.2.50",
+ "@swc/wasm": ">=1.2.50",
+ "@types/node": "*",
+ "typescript": ">=2.7"
+ },
+ "peerDependenciesMeta": {
+ "@swc/core": {
+ "optional": true
+ },
+ "@swc/wasm": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/typescript": {
+ "version": "4.9.5",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz",
+ "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==",
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=4.2.0"
+ }
+ },
+ "node_modules/undici-types": {
+ "version": "7.12.0",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.12.0.tgz",
+ "integrity": "sha512-goOacqME2GYyOZZfb5Lgtu+1IDmAlAEu5xnD3+xTzS10hT0vzpf0SPjkXwAw9Jm+4n/mQGDP3LO8CPbYROeBfQ=="
+ },
+ "node_modules/v8-compile-cache-lib": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
+ "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg=="
+ },
+ "node_modules/yn": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
+ "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
+ "engines": {
+ "node": ">=6"
+ }
+ }
+ }
+}
diff --git a/vcpkg/scripts/azure-pipelines/owners-db/package.json b/vcpkg/scripts/azure-pipelines/owners-db/package.json
new file mode 100644
index 0000000..abfeda0
--- /dev/null
+++ b/vcpkg/scripts/azure-pipelines/owners-db/package.json
@@ -0,0 +1,19 @@
+{
+ "name": "owners-db",
+ "version": "1.0.0",
+ "description": "Utility to generate VCPKG file lists (TypeScript)",
+ "private": true,
+ "type": "module",
+ "license": "MIT",
+ "engines": {
+ "node": ">=22"
+ },
+ "dependencies": {
+ "adm-zip": "^0.5.9",
+ "ts-node": "^10.9.1",
+ "typescript": "^4.9.5"
+ },
+ "devDependencies": {
+ "@types/adm-zip": "^0.5.7"
+ }
+}
diff --git a/vcpkg/scripts/azure-pipelines/patch-tuesday-checklist.md b/vcpkg/scripts/azure-pipelines/patch-tuesday-checklist.md
new file mode 100644
index 0000000..c87618c
--- /dev/null
+++ b/vcpkg/scripts/azure-pipelines/patch-tuesday-checklist.md
@@ -0,0 +1,27 @@
+## First time machine setup:
+* [ ] Install Azure PowerShell: https://docs.microsoft.com/en-us/powershell/azure/install-az-ps
+* [ ] Run `Connect-AzAccount -Subscription CPP_GITHUB`
+* [ ] Install Docker
+
+## Each Patch Tuesday:
+* [ ] Check for depends:vm-update PRs and make relevant changes if possible.
+* [ ] Check for Service 360 alerts (possibly at https://aka.ms/s360 ?) against the service named
+ "C++ VCPKG Validation" about vulnerable software we are installing in the VMs and update that.
+ (Most often PowerShell needs to be updated)
+* [ ] Check for any other software for the Windows images we wish to update and make the edits to do
+ so in `scripts/azure-pipelines/windows`
+* [ ] Check for any updates possible to `vcpkg-tools.json`. Note that PowerShell currently uses the
+ 7.2.x series due to customer reported problems on older Windows with 7.3.x and later.
+* [ ] Update the first line of android/Dockerfile with the current 'noble' image according to
+ https://hub.docker.com/_/ubuntu
+* [ ] Update the first line of linux/Dockerfile with the current 'jammy' image according to
+ https://hub.docker.com/_/ubuntu
+* [ ] Run create-docker-images.ps1
+* [ ] Update android/azure-pipelines.yml and linux/azure-pipelines.yml to point to the new docker
+ images
+* [ ] Run windows/create-image.ps1
+* [ ] Submit PR with those changes and merge it.
+* [ ] In the Azure portal, mark the newly created image as the 'latest' one.
+* [ ] Mint a new macOS base box. (See instructions in `scripts/azure-pipelines/osx/README.md`)
+* [ ] Deploy the new base box to all hosts.
+* [ ] Update the software on the CTI's machine #1 to match.
diff --git a/vcpkg/scripts/azure-pipelines/test-modified-ports.ps1 b/vcpkg/scripts/azure-pipelines/test-modified-ports.ps1
new file mode 100755
index 0000000..49070e5
--- /dev/null
+++ b/vcpkg/scripts/azure-pipelines/test-modified-ports.ps1
@@ -0,0 +1,279 @@
+# Copyright (c) Microsoft Corporation.
+# SPDX-License-Identifier: MIT
+#
+
+<#
+.SYNOPSIS
+Runs the 'Test Modified Ports' part of the vcpkg CI system for all platforms.
+
+.PARAMETER Triplet
+The triplet to test.
+
+.PARAMETER WorkingRoot
+The location used as scratch space for 'installed', 'packages', and 'buildtrees' vcpkg directories.
+
+.PARAMETER ArtifactStagingDirectory
+The Azure Pipelines artifacts directory. If not supplied, defaults to the current directory.
+
+.PARAMETER ArchivesRoot
+Equivalent to '-BinarySourceStub "files,$ArchivesRoot"'
+
+.PARAMETER BinarySourceStub
+The type and parameters of the binary source. Shared across runs of this script. If
+this parameter is not set, binary caching will not be used. Example: "files,W:\"
+
+.PARAMETER BuildReason
+The reason Azure Pipelines is running this script. For invocations caused by `PullRequest`,
+modified ports are identified by changed hashes with regard to git HEAD~1 (subject to NoParentHashes),
+and ports marked as failing in the CI baseline (or which depend on such ports) are skipped.
+If BinarySourceStub is set and this parameter is set to a non-empty value other than `PullRequest`,
+binary caching will be in write-only mode.
+
+.PARAMETER NoParentHashes
+Indicates to not use parent hashes even for pull requests.
+
+.PARAMETER AllowUnexpectedPassing
+Indicates that 'Passing, remove from fail list' results should not be emitted as failures. (For example, this is used
+when using vcpkg to test a prerelease MSVC++ compiler)
+
+.Parameter KnownFailuresAbiLog
+If present, the path to a file containing a list of known ABI failing ABI hashes, typically generated
+by the `vcpkg x-check-features` command.
+#>
+
+[CmdletBinding(DefaultParameterSetName="ArchivesRoot")]
+Param(
+ [Parameter(Mandatory = $true)]
+ [ValidateNotNullOrEmpty()]
+ [string]$Triplet,
+ [Parameter(Mandatory = $true)]
+ [ValidateNotNullOrEmpty()]
+ $WorkingRoot,
+ [ValidateNotNullOrEmpty()]
+ $ArtifactStagingDirectory = '.',
+ [Parameter(ParameterSetName='ArchivesRoot')]
+ $ArchivesRoot = $null,
+ [Parameter(ParameterSetName='BinarySourceStub')]
+ $BinarySourceStub = $null,
+ [String]$BuildReason = $null,
+ [switch]$NoParentHashes = $false,
+ [switch]$AllowUnexpectedPassing = $false
+)
+
+function Add-ToolchainToTestCMake {
+ # The vcpkg.cmake toolchain file is not part of ABI hashing,
+ # but changes must trigger at least some testing.
+ Copy-Item "scripts/buildsystems/vcpkg.cmake" -Destination "scripts/test_ports/cmake"
+ Copy-Item "scripts/buildsystems/vcpkg.cmake" -Destination "scripts/test_ports/cmake-user"
+}
+
+if (-Not ((Test-Path "triplets/$Triplet.cmake") -or (Test-Path "triplets/community/$Triplet.cmake"))) {
+ Write-Error "Incorrect triplet '$Triplet', please supply a valid triplet."
+ exit 1
+}
+
+if ((-Not [string]::IsNullOrWhiteSpace($ArchivesRoot))) {
+ if ((-Not [string]::IsNullOrWhiteSpace($BinarySourceStub))) {
+ Write-Error "Only one binary caching setting may be used."
+ exit 1
+ }
+
+ $BinarySourceStub = "files,$ArchivesRoot"
+}
+
+$buildtreesRoot = Join-Path $WorkingRoot 'b'
+$installRoot = Join-Path $WorkingRoot 'installed'
+$packagesRoot = Join-Path $WorkingRoot 'p'
+
+$env:AZCOPY_LOG_LOCATION = Join-Path $WorkingRoot 'azcopy-logs'
+$env:AZCOPY_JOB_PLAN_LOCATION = Join-Path $WorkingRoot 'azcopy-plans'
+if ($Triplet -eq 'x64-osx') {
+ $env:AZCOPY_BUFFER_GB = 2
+ $env:AZCOPY_CONCURRENCY_VALUE = 8
+}
+if (!(Test-Path $env:AZCOPY_LOG_LOCATION))
+{
+ New-Item -ItemType Directory -Path $env:AZCOPY_LOG_LOCATION | Out-Null
+}
+Write-Host "AzCopy logs location: $env:AZCOPY_LOG_LOCATION"
+Write-Host "##vso[task.setvariable variable=AZCOPY_LOGS_EMPTY]$true"
+
+$commonArgs = @(
+ "--x-buildtrees-root=$buildtreesRoot",
+ "--x-install-root=$installRoot",
+ "--x-packages-root=$packagesRoot",
+ "--overlay-ports=scripts/test_ports"
+)
+
+$testFeatures = $false
+$cachingArgs = @()
+$skipFailuresArgs = @()
+if ([string]::IsNullOrWhiteSpace($BinarySourceStub)) {
+ $cachingArgs = @('--binarysource', 'clear')
+} else {
+ $cachingArgs = @()
+ $binaryCachingMode = 'readwrite'
+ if ([string]::IsNullOrWhiteSpace($BuildReason)) {
+ Write-Host 'Build reason not specified, defaulting to using binary caching in read write mode.'
+ }
+ elseif ($BuildReason -eq 'PullRequest') {
+ Write-Host 'Build reason was Pull Request, using binary caching in read write mode, testing features, skipping failures.'
+ $skipFailuresArgs = @('--skip-failures')
+ $testFeatures = $true
+ }
+ else {
+ Write-Host "Build reason was $BuildReason, using binary caching in write only mode."
+ $binaryCachingMode = 'write'
+ }
+
+ $cachingArgs += "--binarysource=clear;$BinarySourceStub,$binaryCachingMode"
+}
+
+if ($IsWindows) {
+ $vcpkgExe = './vcpkg.exe'
+} else {
+ $vcpkgExe = './vcpkg'
+}
+
+if ($Triplet -eq 'x64-windows-release') {
+ $tripletArg = "--host-triplet=$Triplet"
+} else {
+ $tripletArg = "--triplet=$Triplet"
+}
+
+$failureLogs = Join-Path $ArtifactStagingDirectory 'failure-logs'
+$failureLogsArg = "--failure-logs=$failureLogs"
+$knownFailuresFromArgs = @()
+if ($testFeatures) {
+ & $vcpkgExe x-ci-clean @commonArgs
+ $lastLastExitCode = $LASTEXITCODE
+ if ($lastLastExitCode -ne 0)
+ {
+ Write-Error "vcpkg x-ci-clean failed. This is usually an infrastructure problem; trying again may help."
+ exit $lastLastExitCode
+ }
+
+ $ciFeatureBaselineFile = "$PSScriptRoot/../ci.feature.baseline.txt"
+ $ciFeatureBaselineArg = "--ci-feature-baseline=$ciFeatureBaselineFile"
+ $knownFailingAbisFile = Join-Path $ArtifactStagingDirectory 'failing-abi-log.txt'
+ $failingAbiLogArg = "--failing-abi-log=$knownFailingAbisFile"
+ & $vcpkgExe x-test-features --for-merge-with origin/master $tripletArg $failureLogsArg $ciBaselineArg $failingAbiLogArg $ciFeatureBaselineArg @commonArgs @cachingArgs
+ $lastLastExitCode = $LASTEXITCODE
+ $azcopyLogsEmpty = ((Get-ChildItem $env:AZCOPY_LOG_LOCATION).Count -eq 0)
+ Write-Host "##vso[task.setvariable variable=AZCOPY_LOGS_EMPTY]$azcopyLogsEmpty"
+ if ($lastLastExitCode -ne 0)
+ {
+ Write-Host "##vso[task.setvariable variable=FAILURE_LOGS_EMPTY]$false"
+ Write-Host "##vso[task.logissue type=error]vcpkg feature testing failed; this is usually a bug in one of the features in the port(s) edited in this pull request. See https://github.com/microsoft/vcpkg/discussions/31357 for how to access AZP failure logs."
+ exit $lastLastExitCode
+ }
+
+ $knownFailuresFromArgs += "--known-failures-from=$knownFailingAbisFile"
+}
+
+$ciBaselineFile = "$PSScriptRoot/../ci.baseline.txt"
+$ciBaselineArg = "--ci-baseline=$ciBaselineFile"
+$toolMetadataFile = "$PSScriptRoot/../vcpkg-tool-metadata.txt"
+
+& $vcpkgExe x-ci-clean @commonArgs
+$lastLastExitCode = $LASTEXITCODE
+if ($lastLastExitCode -ne 0)
+{
+ Write-Error "vcpkg x-ci-clean failed. This is usually an infrastructure problem; trying again may help."
+ exit $lastLastExitCode
+}
+
+if ($IsMacOS)
+{
+ Write-Host "macOS disk space report:"
+ & df -h | Where-Object { $_ -match "Avail|/System/Volumes/Data$" }
+ & du -sh $WorkingRoot
+}
+
+$parentHashesArgs = @()
+if (($BuildReason -eq 'PullRequest') -and -not $NoParentHashes)
+{
+ $headBaseline = Get-Content $ciBaselineFile -Raw
+ $headTool = Get-Content $toolMetadataFile -Raw
+
+ Write-Host "Comparing with HEAD~1"
+ & git revert -n -m 1 HEAD | Out-Null
+ $lastLastExitCode = $LASTEXITCODE
+ if ($lastLastExitCode -ne 0)
+ {
+ Write-Error "git revert -n -m 1 HEAD failed"
+ exit $lastLastExitCode
+ }
+
+ $parentBaseline = Get-Content $ciBaselineFile -Raw
+ $parentTool = Get-Content $toolMetadataFile -Raw
+ if (($parentBaseline -eq $headBaseline) -and ($parentTool -eq $headTool))
+ {
+ Write-Host "CI baseline unchanged, determining parent hashes"
+ $parentHashesFile = Join-Path $ArtifactStagingDirectory 'parent-hashes.json'
+ $parentHashesArgs += "--parent-hashes=$parentHashesFile"
+ Add-ToolchainToTestCMake
+ & $vcpkgExe ci $tripletArg --dry-run $ciBaselineArg @commonArgs --no-binarycaching "--output-hashes=$parentHashesFile"
+ $lastLastExitCode = $LASTEXITCODE
+ if ($lastLastExitCode -ne 0)
+ {
+ Write-Error "Generating parent hashes failed; this is usually an infrastructure problem with vcpkg"
+ exit $lastLastExitCode
+ }
+ }
+ else
+ {
+ Write-Host "Tool or baseline modified, not using parent hashes"
+ }
+
+ Write-Host "Running CI for HEAD"
+ & git reset --hard HEAD
+ $lastLastExitCode = $LASTEXITCODE
+ if ($lastLastExitCode -ne 0)
+ {
+ Write-Error "git reset --hard HEAD failed"
+ exit $lastLastExitCode
+ }
+}
+
+$allowUnexpectedPassingArgs = @()
+if ($AllowUnexpectedPassing) {
+ $allowUnexpectedPassingArgs = @('--allow-unexpected-passing')
+}
+
+Add-ToolchainToTestCMake
+$xunitFile = Join-Path $ArtifactStagingDirectory "$Triplet-results.xml"
+$xunitArg = "--x-xunit=$xunitFile"
+$prHashesFile = Join-Path $ArtifactStagingDirectory "pr-hashes.json"
+& $vcpkgExe ci `
+ $tripletArg `
+ $failureLogsArg `
+ "--output-hashes=$prHashesFile" `
+ $xunitArg `
+ $ciBaselineArg `
+ @commonArgs `
+ @cachingArgs `
+ @parentHashesArgs `
+ @skipFailuresArgs `
+ @knownFailuresFromArgs `
+ @allowUnexpectedPassingArgs
+$lastLastExitCode = $LASTEXITCODE
+$failureLogsEmpty = (-Not (Test-Path $failureLogs) -Or ((Get-ChildItem $failureLogs).Count -eq 0))
+Write-Host "##vso[task.setvariable variable=FAILURE_LOGS_EMPTY]$failureLogsEmpty"
+$azcopyLogsEmpty = ((Get-ChildItem $env:AZCOPY_LOG_LOCATION).Count -eq 0)
+Write-Host "##vso[task.setvariable variable=AZCOPY_LOGS_EMPTY]$azcopyLogsEmpty"
+Write-Host "##vso[task.setvariable variable=XML_RESULTS_FILE]$xunitFile"
+
+if ($lastLastExitCode -ne 0)
+{
+ if (-Not $failureLogsEmpty)
+ {
+ Write-Host "##vso[task.logissue type=error]vcpkg ci testing failed; this is usually a bug in a port. See https://github.com/microsoft/vcpkg/discussions/31357 for how to access AZP failure logs."
+ }
+ else
+ {
+ Write-Host "##vso[task.logissue type=error]vcpkg ci testing failed, but no build failure logs were created for this error."
+ }
+}
+
+exit $lastLastExitCode
diff --git a/vcpkg/scripts/azure-pipelines/windows-unstable/README.md b/vcpkg/scripts/azure-pipelines/windows-unstable/README.md
new file mode 100644
index 0000000..5dc58f5
--- /dev/null
+++ b/vcpkg/scripts/azure-pipelines/windows-unstable/README.md
@@ -0,0 +1,4 @@
+The "unstable" build is used internally by Microsoft to test prerelease versions
+of our C++ compiler; not seeing results from these build definitions in the
+GitHub portal is normal as these builds depend on acquisition of private
+compiler bits that aren't yet shipping.
diff --git a/vcpkg/scripts/azure-pipelines/windows-unstable/azure-pipelines.yml b/vcpkg/scripts/azure-pipelines/windows-unstable/azure-pipelines.yml
new file mode 100644
index 0000000..21a9d92
--- /dev/null
+++ b/vcpkg/scripts/azure-pipelines/windows-unstable/azure-pipelines.yml
@@ -0,0 +1,81 @@
+# Copyright (c) Microsoft Corporation.
+# SPDX-License-Identifier: MIT
+#
+
+jobs:
+- job: x64_windows
+ pool:
+ name: vcpkg-testing-msvc
+ demands: ImageVersionOverride -equals 2025.10.17
+ timeoutInMinutes: 2880 # 2 days
+ variables:
+ - name: WORKING_ROOT
+ value: D:\
+ - name: VCPKG_DOWNLOADS
+ value: D:\downloads
+ - name: Codeql.Enabled
+ value: false
+ steps:
+ - task: DownloadBuildArtifacts@0
+ displayName: 'Download DropBuildNumber if not specified'
+ inputs:
+ buildType: specific
+ project: '0bdbc590-a062-4c3f-b0f6-9383f67865ee'
+ pipeline: 16549
+ buildVersionToDownload: latestFromBranch
+ branchName: 'refs/heads/$(MSVCBranchName)'
+ artifactName: BuildNumber
+ downloadPath: 'D:\msvc-drops'
+ condition: eq(variables['DropBuildNumber'], '')
+ - task: PowerShell@2
+ displayName: 'Set DropBuildNumber if not specified'
+ inputs:
+ targetType: inline
+ script: |
+ $DropBuildNumber = Get-Content -Path D:\msvc-drops\BuildNumber\Build.BuildNumber.txt
+ Write-Host "##vso[task.setvariable variable=DropBuildNumber]$DropBuildNumber"
+ Write-Host "Build Number set to: $DropBuildNumber"
+ pwsh: true
+ condition: eq(variables['DropBuildNumber'], '')
+ - task: ms-vscs-artifact.build-tasks.artifactDropDownloadTask-1.artifactDropDownloadTask@0
+ displayName: 'Download msvc x86 ret'
+ inputs:
+ dropServiceURI: 'https://devdiv.artifacts.visualstudio.com/DefaultCollection'
+ buildNumber: 'msvc/builds/$(DropBuildNumber)/x86ret'
+ destinationPath: 'D:\msvc-drops\$(DropBuildNumber)\binaries.x86ret'
+ - task: ms-vscs-artifact.build-tasks.artifactDropDownloadTask-1.artifactDropDownloadTask@0
+ displayName: 'Download msvc amd64 ret'
+ inputs:
+ dropServiceURI: 'https://devdiv.artifacts.visualstudio.com/DefaultCollection'
+ buildNumber: 'msvc/builds/$(DropBuildNumber)/amd64ret'
+ destinationPath: 'D:\msvc-drops\$(DropBuildNumber)\binaries.amd64ret'
+ - task: PowerShell@2
+ displayName: 'Rearrange MSVC Drop Layout'
+ inputs:
+ targetType: filePath
+ filePath: 'scripts/azure-pipelines/windows-unstable/rearrange-msvc-drop-layout.ps1'
+ arguments: '-DropRoot "D:\msvc-drops\$(DropBuildNumber)" -BuildType ret'
+ pwsh: true
+ - script: .\bootstrap-vcpkg.bat
+ displayName: 'Bootstrap vcpkg'
+ - task: AzureCLI@2
+ displayName: '*** Test Modified Ports'
+ inputs:
+ azureSubscription: 'vcpkg-pr-fleet-wus'
+ scriptType: 'pscore'
+ failOnStandardError: true
+ 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 r --expiry $end -o tsv | Out-String
+ $assetSas = $assetSas.Trim()
+ $env:X_VCPKG_ASSET_SOURCES = "x-azurl,https://vcpkgassetcachewus.blob.core.windows.net/cache,$assetSas,read"
+ & scripts/azure-pipelines/test-modified-ports.ps1 -Triplet x64-windows -BuildReason $(Build.Reason) -WorkingRoot $env:WORKING_ROOT -ArtifactStagingDirectory $(Build.ArtifactStagingDirectory) -AllowUnexpectedPassing
+ - task: PublishPipelineArtifact@1
+ displayName: "Publish Artifact: failure logs for x64-windows"
+ inputs:
+ targetPath: '$(Build.ArtifactStagingDirectory)\failure-logs'
+ artifact: "failure logs for x64-windows"
+ condition: ne(variables['FAILURE_LOGS_EMPTY'], 'True')
diff --git a/vcpkg/scripts/azure-pipelines/windows-unstable/rearrange-msvc-drop-layout.ps1 b/vcpkg/scripts/azure-pipelines/windows-unstable/rearrange-msvc-drop-layout.ps1
new file mode 100644
index 0000000..5369253
--- /dev/null
+++ b/vcpkg/scripts/azure-pipelines/windows-unstable/rearrange-msvc-drop-layout.ps1
@@ -0,0 +1,75 @@
+# Copyright (c) Microsoft Corporation.
+# SPDX-License-Identifier: MIT
+#
+<#
+.SYNOPSIS
+Moves files from an MSVC compiler drop to the locations where they are installed in a Visual Studio installation.
+
+.PARAMETER DropRoot
+The location where the MSVC compiler drop has been downloaded.
+
+.PARAMETER BuildType
+The MSVC drop build type set with /p:_BuildType when MSVC was built. Defaults to 'ret'.
+
+#>
+[CmdletBinding()]
+param(
+ [Parameter(Mandatory = $true)][string]$DropRoot,
+ [Parameter(Mandatory = $false)][ValidateSet('ret', 'chk')][string]$BuildType = 'ret'
+)
+
+Set-StrictMode -Version Latest
+
+$MSVCRoot = "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC"
+
+$ErrorActionPreference = "Stop"
+
+$tempRoot = "$DropRoot\readytodeploy"
+
+New-Item -ItemType Directory -Path $tempRoot | Out-Null
+
+Write-Host "Rearranging x86$BuildType"
+New-Item -ItemType Directory -Path "$tempRoot\bin\HostX86" | Out-Null
+Move-Item "$DropRoot\binaries.x86$BuildType\bin\i386" "$tempRoot\bin\HostX86\x86"
+Move-Item "$DropRoot\binaries.x86$BuildType\bin\x86_amd64" "$tempRoot\bin\HostX86\x64"
+Move-Item "$DropRoot\binaries.x86$BuildType\bin\x86_arm" "$tempRoot\bin\HostX86\arm"
+
+Write-Host "Rearranging amd64$BuildType"
+New-Item -ItemType Directory -Path "$tempRoot\bin\HostX64" | Out-Null
+Move-Item "$DropRoot\binaries.amd64$BuildType\bin\amd64" "$tempRoot\bin\HostX64\x64"
+Move-Item "$DropRoot\binaries.amd64$BuildType\bin\amd64_x86" "$tempRoot\bin\HostX64\x86"
+Move-Item "$DropRoot\binaries.amd64$BuildType\bin\amd64_arm" "$tempRoot\bin\HostX64\arm"
+
+# Only copy files and directories that already exist in the VS installation.
+Write-Host "Rearranging inc, lib"
+New-Item -ItemType Directory -Path "$tempRoot\lib" | Out-Null
+Move-Item "$DropRoot\binaries.x86$BuildType\inc" "$tempRoot\include"
+Move-Item "$DropRoot\binaries.x86$BuildType\lib\i386" "$tempRoot\lib\x86"
+Move-Item "$DropRoot\binaries.amd64$BuildType\lib\amd64" "$tempRoot\lib\x64"
+
+Write-Host "Rearranging atlmfc"
+New-Item -ItemType Directory -Path "$tempRoot\atlmfc" | Out-Null
+New-Item -ItemType Directory -Path "$tempRoot\atlmfc\lib" | Out-Null
+Move-Item "$DropRoot\binaries.x86$BuildType\atlmfc\include" "$tempRoot\atlmfc\include"
+Move-Item "$DropRoot\binaries.x86$BuildType\atlmfc\lib\i386" "$tempRoot\atlmfc\lib\x86"
+Move-Item "$DropRoot\binaries.amd64$BuildType\atlmfc\lib\amd64" "$tempRoot\atlmfc\lib\x64"
+
+[string[]]$toolsets = Get-ChildItem -Path $MSVCRoot -Directory | Sort-Object -Descending
+if ($toolsets.Length -eq 0) {
+ throw "Could not find Visual Studio toolset!"
+}
+
+Write-Host "Found toolsets:`n$($toolsets -join `"`n`")`n"
+$selectedToolset = $toolsets[0]
+Write-Host "Using toolset: $selectedToolset"
+for ($idx = 1; $idx -lt $toolsets.Length; $idx++) {
+ $badToolset = $toolsets[$idx]
+ Write-Host "Deleting toolset: $badToolset"
+ Remove-Item $badToolset -Recurse -Force
+}
+
+Write-Host "Deploying $tempRoot => $selectedToolset"
+Copy-Item "$tempRoot\*" $selectedToolset -Recurse -Force
+Write-Host "Deleting $DropRoot..."
+Remove-Item $DropRoot -Recurse -Force
+Write-Host "Done!"
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
+ }
+}