vcpkg/scripts/azure-pipelines/windows/create-image.ps1
Billy O'Neal 9cbab417e4
Patch Tuesday March 2024 (#37466)
This contains high priority active security things to adopt trusted
launch, and managed identity rather than SAS tokens when minting the
images, and 1ES Hosted Pools.

Some instructions are rough around the edges because I'm not sure
everything is repeatable yet while this is all in flux...
2024-03-18 13:26:24 -07:00

272 lines
10 KiB
PowerShell

# 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 = '2022-datacenter-azure-edition'
$ErrorActionPreference = 'Stop'
$ProgressActivity = 'Creating Windows Image'
$TotalProgress = 17
$CurrentProgress = 1
# Assigning this to another variable helps when running the commands in this script manually for
# debugging
$Root = $PSScriptRoot
Import-Module "$Root/../create-vmss-helpers.psm1" -DisableNameChecking -Force
$AdminPW = New-Password
$AdminPWSecure = ConvertTo-SecureString $AdminPW -AsPlainText -Force
$Credential = New-Object System.Management.Automation.PSCredential ("AdminUser", $AdminPWSecure)
$VirtualNetwork = Get-AzVirtualNetwork -ResourceGroupName 'vcpkg-image-minting' -Name 'vcpkg-image-mintingNetwork'
####################################################################################################
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 $VirtualNetwork.Subnets[0] `
-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 'Granting permissions to use vcpkg-image-minting storage account' `
-PercentComplete (100 / $TotalProgress * $CurrentProgress++)
$VcpkgImageMintingAccount = Get-AzStorageAccount -ResourceGroupName 'vcpkg-image-minting' -Name 'vcpkgimageminting'
# Grant 'Storage Blob Data Reader' (RoleDefinitionId 2a2b9908-6ea1-4ae2-8e65-a410df84e7d1) to the VM
New-AzRoleAssignment `
-Scope $VcpkgImageMintingAccount.ID `
-RoleDefinitionId '2a2b9908-6ea1-4ae2-8e65-a410df84e7d1' `
-ObjectId $VMCreated.Identity.PrincipalId
####################################################################################################
Write-Progress `
-Activity $ProgressActivity `
-Status 'Running provisioning script deploy-tlssettings.ps1 in VM' `
-PercentComplete (100 / $TotalProgress * $CurrentProgress++)
$ProvisionImageResult = Invoke-AzVMRunCommandWithRetries `
-ResourceGroupName 'vcpkg-image-minting' `
-VMName $ProtoVMName `
-CommandId 'RunPowerShellScript' `
-ScriptPath "$Root\deploy-tlssettings.ps1"
Write-Host "deploy-tlssettings.ps1 output: $($ProvisionImageResult.value.Message)"
Write-Host 'Waiting 1 minute for VM to reboot...'
Start-Sleep -Seconds 60
####################################################################################################
Write-Progress `
-Activity $ProgressActivity `
-Status 'Running provisioning script deploy-psexec.ps1 in VM' `
-PercentComplete (100 / $TotalProgress * $CurrentProgress++)
$DeployPsExecResult = Invoke-AzVMRunCommandWithRetries `
-ResourceGroupName 'vcpkg-image-minting' `
-VMName $ProtoVMName `
-CommandId 'RunPowerShellScript' `
-ScriptPath "$Root\deploy-psexec.ps1"
Write-Host "deploy-psexec.ps1 output: $($DeployPsExecResult.value.Message)"
####################################################################################################
function Invoke-ScriptWithPrefix {
param(
[string]$ScriptName,
[switch]$AddAdminPw
)
Write-Progress `
-Activity $ProgressActivity `
-Status "Running provisioning script $ScriptName in VM" `
-PercentComplete (100 / $TotalProgress * $CurrentProgress++)
$DropToAdminUserPrefix = Get-Content "$Root\drop-to-admin-user-prefix.ps1" -Encoding utf8NoBOM -Raw
$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
if ($AddAdminPw) {
$script = $script.Replace('# REPLACE WITH DROP-TO-ADMIN-USER-PREFIX.ps1', $DropToAdminUserPrefix)
}
$script = $script.Replace('# REPLACE WITH UTILITY-PREFIX.ps1', $UtilityPrefixContent);
Set-Content -Path $tempScriptFilename -Value $script -Encoding utf8NoBOM
$parameter = $null
if ($AddAdminPw) {
$parameter = @{AdminUserPassword = $AdminPW;}
}
$InvokeResult = Invoke-AzVMRunCommandWithRetries `
-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-azcopy.ps1'
####################################################################################################
Invoke-ScriptWithPrefix -ScriptName 'deploy-windows-sdks.ps1' -AddAdminPw
####################################################################################################
Invoke-ScriptWithPrefix -ScriptName 'deploy-visual-studio.ps1' -AddAdminPw
####################################################################################################
Invoke-ScriptWithPrefix -ScriptName 'deploy-mpi.ps1' -AddAdminPw
####################################################################################################
Invoke-ScriptWithPrefix -ScriptName 'deploy-cuda.ps1' -AddAdminPw
####################################################################################################
Invoke-ScriptWithPrefix -ScriptName 'deploy-inteloneapi.ps1' -AddAdminPw
####################################################################################################
Invoke-ScriptWithPrefix -ScriptName 'deploy-pwsh.ps1' -AddAdminPw
####################################################################################################
Write-Progress `
-Activity $ProgressActivity `
-Status 'Running provisioning script deploy-settings.txt (as a .ps1) in VM' `
-PercentComplete (100 / $TotalProgress * $CurrentProgress++)
$ProvisionImageResult = Invoke-AzVMRunCommandWithRetries `
-ResourceGroupName 'vcpkg-image-minting' `
-VMName $ProtoVMName `
-CommandId 'RunPowerShellScript' `
-ScriptPath "$Root\deploy-settings.txt"
Write-Host "deploy-settings.txt output: $($ProvisionImageResult.value.Message)"
Restart-AzVM -ResourceGroupName 'vcpkg-image-minting' -Name $ProtoVMName
####################################################################################################
Write-Progress `
-Activity $ProgressActivity `
-Status 'Running provisioning script sysprep.ps1 in VM' `
-PercentComplete (100 / $TotalProgress * $CurrentProgress++)
$SysprepResult = Invoke-AzVMRunCommandWithRetries `
-ResourceGroupName 'vcpkg-image-minting' `
-VMName $ProtoVMName `
-CommandId 'RunPowerShellScript' `
-ScriptPath "$Root\sysprep.ps1"
Write-Host "sysprep.ps1 output: $($SysprepResult.value.Message)"
####################################################################################################
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
New-AzGalleryImageVersion `
-ResourceGroupName 'vcpkg-image-minting' `
-GalleryName 'vcpkg_gallery_wus3' `
-GalleryImageDefinitionName 'PrWinWus3-TrustedLaunch' `
-Name $GalleryImageVersion `
-Location $Location `
-SourceImageId $VMCreated.ID `
-ReplicaCount 1 `
-StorageAccountType 'Premium_LRS' `
-PublishingProfileExcludeFromLatest
####################################################################################################
Write-Progress `
-Activity $ProgressActivity `
-Status 'Deleting unused temporary resources' `
-PercentComplete (100 / $TotalProgress * $CurrentProgress++)
Remove-AzRoleAssignment `
-Scope $VcpkgImageMintingAccount.ID `
-RoleDefinitionId '2a2b9908-6ea1-4ae2-8e65-a410df84e7d1' `
-ObjectId $VMCreated.Identity.PrincipalId
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!'