forked from microsoft/msquic
-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Move AZP Setup to Docs (microsoft#1665)
- Loading branch information
Showing
1 changed file
with
263 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,263 @@ | ||
# Azure Pipelines Machine Setup | ||
|
||
The following are a set of instructions to set up an Azure Pipeline test machine for running the latest Windows builds on private/custom hardware. Both VMs and HW are supported/allowed. | ||
|
||
## Windows OS Install | ||
|
||
- Install the latest Windows Server Datacenter (desktop) SKU, ideally from the RS_PRERELEASE branch if possible, since symbols persist the longest for that branch. | ||
- Log in as Administrator. | ||
- Make sure to activate it. If necessary grab a product key from the internal website. | ||
|
||
## Machine Setup | ||
|
||
- Copy `sfpcopy.exe` into C:\Windows\System32 | ||
- Disable Windows Defender | ||
- Install the latest PowerShell: `iex "& { $(irm https://aka.ms/install-powershell.ps1) } -UseMSI"` | ||
- Download and install VS build tools: | ||
- https://visualstudio.microsoft.com/thank-you-downloading-visual-studio/?sku=BuildTools&rel=16 | ||
- Specifically make sure **C++ Build Tools** is installed | ||
- Enable the kernel debugger: | ||
``` | ||
bcdedit /dbgsettings NET HOSTIP:192.168.1.160 PORT:50000 /noumex | ||
bcdedit -deletevalue {dbgsettings} hostip | ||
bcdedit /debug on | ||
``` | ||
- Start windbg on debug server machine to connect with autogenerated key from above. | ||
- **Reboot** | ||
|
||
## Agent Setup | ||
|
||
- Download the agent: https://vstsagentpackage.azureedge.net/agent/2.172.2/vsts-agent-win-x64-2.172.2.zip | ||
- Unzip the contents to `C:\a` | ||
- Run `config.cmd` | ||
- Connect to `https://dev.azure.com/ms` | ||
- Use the PAT (ping me to ask for it) | ||
- Add to `MsQuic-Win-Latest` pool | ||
- Use `w` for the work folder name | ||
- Run it as a service, using the default account | ||
- Open 'Services' and find the Azure Pipelines service that was created | ||
- Change the service to run a Local System | ||
- Then stop and restart it | ||
- Change the service to run as Administrator | ||
- Then stop and restart it | ||
|
||
## Script for preparing VMs for use in the AZP pool | ||
``` | ||
param ( | ||
[Parameter(Mandatory = $true)] | ||
[ValidateSet("prepareseed", "create", "config", "delete", "launchdebug")] | ||
[string]$Mode, | ||
[Parameter(Mandatory = $false)] | ||
[string]$SeedVhdLocation = 'c:\SeedVHDs', | ||
[Parameter(Mandatory = $false)] | ||
[string]$SeedVhd = 'seed.vhdx', | ||
[Parameter(Mandatory = $false)] | ||
[string]$VhdLocation = 'c:\users\public\documents\Hyper-V\Virtual hard disks', | ||
[Parameter(Mandatory = $false)] | ||
[long]$VhdSize = 40GB, | ||
[Parameter(Mandatory = $false)] | ||
[string]$UnattendLocation = "$($PSScriptRoot)", | ||
[Parameter(Mandatory = $false)] | ||
[string]$PAT = '', | ||
[Parameter(Mandatory = $false)] | ||
[long]$VmCores = 4, | ||
[Parameter(Mandatory = $false)] | ||
[long]$MaximumVmMemory = 4096, | ||
[Parameter(Mandatory = $false)] | ||
[long]$VmsToProcess = 14, | ||
[Parameter(Mandatory = $false)] | ||
[long]$VmNumberStart = 1, | ||
[Parameter(Mandatory = $false)] | ||
[string]$VmNamePrefix = "AZP", | ||
[Parameter(Mandatory = $false)] | ||
[string]$VmPassword = "Very!SecurePassword2", | ||
[Parameter(Mandatory = $false)] | ||
[string]$AgentPool = 'MsQuic-Win-Latest', | ||
[Parameter(Mandatory = $false)] | ||
[string]$AgentUrl = 'https://dev.azure.com/ms', | ||
[Parameter(Mandatory = $false)] | ||
[long]$DebugPortBase = 50000 | ||
) | ||
$ProgressPreference = 'SilentlyContinue' | ||
$AzpDebugKey = "something.very.very.secret" | ||
function ExecuteScriptWithMountedVhd($vhd, $scriptblock) | ||
{ | ||
$vhdname = (Split-Path $vhd -Leaf).substring(0,8) | ||
$vhdmountdir = "$($Env:Temp)\vhdmount\$vhdname" | ||
if (Test-Path $vhdmountdir) { | ||
throw "VHD mount path already exists." | ||
} | ||
mkdir $vhdmountdir > $null | ||
dism.exe /mount-image /ImageFile:$vhd /index:1 /mountdir:$vhdmountdir | ||
& $scriptblock | ||
dism.exe /unmount-image /mountdir:$vhdmountdir /commit | ||
Remove-Item -Path $vhdmountdir -Force > $null | ||
} | ||
function AddUnattendFile($vhd, $unattendfile) | ||
{ | ||
ExecuteScriptWithMountedVhd $vhd { | ||
dism.exe /image:$vhdmountdir /apply-unattend:$unattendfile | ||
Copy-Item $unattendfile $vhdmountdir | ||
} | ||
} | ||
function CreateVM($VmName, $VmNumber) | ||
{ | ||
$VhdExtension = $SeedVhd.split('.')[-1] | ||
$VhdPath = "$(Join-Path $VhdLocation $VmName).$($VhdExtension)" | ||
if (-not (Test-Path $VhdPath)) { | ||
New-VHD -Path $VhdPath -ParentPath (Join-Path $SeedVhdLocation $SeedVhd) -Differencing | ||
} | ||
$VMGeneration = 1 | ||
if ($VhdExtension.Contains("vhdx")) { | ||
$VmGeneration = 2 | ||
} | ||
New-Vm -Name $VmName -VHDPath $VhdPath -Generation $VMGeneration -SwitchName "ExternalSwitch" | ||
Set-VMProcessor -VMName $VmName -Count $VmCores | ||
Set-VMMemory -VMName $VmName -DynamicMemoryEnabled $true -MinimumBytes (512 * 1024 * 1024) -StartupBytes (1024 *1024 * 1024) -MaximumBytes ($MaximumVmMemory * 1024 * 1024) | ||
if ($VMGeneration -eq 2) { | ||
Set-VMFirmware -VMName $VmName -FirstBootDevice (Get-VMHardDiskDrive -VMName $VmName) -EnableSecureBoot Off | ||
} | ||
Start-VM $VmName | ||
# Wait for VM to start - never gets to "Healthy" | ||
# while ((Get-VM -Name $VmName).HeartBeat -ne 'OkApplicationsHealthy') { | ||
# Write-Host "VM state is: $((Get-VM -Name $VmName).HeartBeat) Sleeping 5 seconds..." | ||
# Start-Sleep -Seconds 5 | ||
# } | ||
} | ||
function ConfigureVM($VmName, $VmNumber) | ||
{ | ||
$block = { | ||
param($Port, $HostIP, $VmName, $Token, $DebugKey, $Password, $PoolName, $URL) | ||
Set-MpPreference -DisableRealtimeMonitoring $true | ||
Copy-Item c:\sfpcopy.exe c:\Windows\System32 | ||
Invoke-Expression "& { $(Invoke-RestMethod https://aka.ms/install-powershell.ps1) } -UseMSI" | ||
bcdedit.exe /dbgsettings NET HOSTIPV6:$HostIP PORT:$Port KEY:$DebugKey /noumex | ||
bcdedit.exe /debug on | ||
# Install VS build tools | ||
c:\vs_buildtools.exe --add Microsoft.VisualStudio.Workload.MSBuildTools --add Microsoft.VisualStudio.Workload.VCTools --IncludeRecommended -q --force --wait | ||
# Add agent to pool | ||
c:\a\config.cmd --unattended --URL "$($URL)" --auth pat --token "$($Token)" --pool "$($PoolName)" --agent "$($VmName)" --replace --work "c:\a\w" --runAsService | ||
# Enable services to run as Administrator | ||
secedit.exe /export /cfg "$($Env:Temp)\secconfig.cfg" | ||
(Get-Content "$($Env:Temp)\secconfig.cfg") -replace 'SeServiceLogonRight = (?<SIDs>.*)', 'SeServiceLogonRight = Administrator,$1' | Set-Content "$($Env:Temp)\secconfig.cfg" | ||
secedit.exe /configure /db c:\windows\security\local.sdb /cfg "$($Env:Temp)\secconfig.cfg" /areas USER_RIGHTS | ||
# Set AZP service to run as Administrator | ||
#$cred = New-Object System.Management.Automation.PSCredential ('Administrator', (ConvertTo-SecureString $Password -AsPlainText -Force)) | ||
#& "C:\Program Files\Powershell\7\pwsh.exe" -Command Set-Service -Name "vsts*" -Credential (New-Object System.Management.Automation.PSCredential ('Administrator', (ConvertTo-SecureString $Password -AsPlainText -Force))) | ||
#Get-Service vsts* | Restart-Service | ||
$ServiceName = (get-service vsts*).name | ||
$WmiObject = Get-WMIObject Win32_Service -filter "name='$ServiceName'" | ||
$StopStatus = $WmiObject.StopService() | ||
If ($StopStatus.ReturnValue -eq "0") { | ||
Write-host "The service '$ServiceName' Stopped successfully" | ||
} | ||
$ChangeStatus = $WmiObject.change($null,$null,$null,$null,$null,$null,'.\Administrator',$Password,$null,$null,$null) | ||
If ($ChangeStatus.ReturnValue -eq "0") { | ||
Write-host "Set User Name sucessfully for the service '$ServiceName'" | ||
} | ||
Start-Sleep 5 | ||
$StartStatus = $WmiObject.StartService() | ||
If ($StartStatus.ReturnValue -eq "0") { | ||
Write-host "The service '$ServiceName' Started successfully" | ||
} | ||
# Visual studio installer doesn't respect the --wait parameter, so we can't automatically reboot | ||
} | ||
$DebugPort = $DebugPortBase + $VmNumber | ||
$HostIP = (get-netipaddress -AddressFamily IPv6 -AddressState Preferred -InterfaceAlias "vEthernet (ExternalSwitch)" -ValidLifetime ([TimeSpan]::MaxValue)).IPAddress.Split('%')[0] | ||
$password = ConvertTo-SecureString $VmPassword -AsPlainText -Force | ||
$credential = New-Object System.Management.Automation.PSCredential ('Administrator', $password) | ||
#start up WinDbgX | ||
windbgx.exe -y c:\symbols -k net:port=$DebugPort,key=$AzpDebugKey | ||
#Configure VM | ||
Invoke-Command -VmName $VmName -Credential $credential -ScriptBlock $block -ArgumentList $DebugPort,$HostIP,$VmName,$PAT, $AzpDebugKey,$VmPassword,$AgentPool,$AgentUrl | ||
Write-Host "Finished setting up $VmName" | ||
} | ||
function DeleteVM($VmName) | ||
{ | ||
if ((Get-VM -Name $VmName).State -eq 'Running') { | ||
$block = { | ||
param($Token) | ||
C:\a\config.cmd remove --unattended --auth pat --token "$($Token)" | ||
} | ||
$password = ConvertTo-SecureString $VmPassword -AsPlainText -Force | ||
$credential = New-Object System.Management.Automation.PSCredential ('Administrator', $password) | ||
Invoke-Command -VmName $VmName -Credential $credential -ScriptBlock $block -ArgumentList $PAT | ||
# Turn off running VM | ||
Stop-VM -Name $VmName -TurnOff -Force | ||
} | ||
# Remove VHDs (and snapshot VHDs) before the VM | ||
Remove-Item -Path "$(Join-Path $VhdLocation $VmName)*" -Force | ||
Remove-VM -Name $VmName -Force | ||
} | ||
# | ||
# Actually run the script | ||
# | ||
if ($Mode -eq "prepareseed") { | ||
$Vhd = Join-Path $SeedVhdLocation $SeedVhd | ||
if ((Get-VHD $Vhd).Size -lt $VhdSize) { | ||
Resize-VHD -Path $Vhd -SizeBytes $VhdSize | ||
} | ||
AddUnattendFile $Vhd "$($UnattendLocation)\unattend.xml" | ||
ExecuteScriptWithMountedVhd $Vhd { | ||
Invoke-WebRequest -Uri "https://vstsagentpackage.azureedge.net/agent/2.172.2/vsts-agent-win-x64-2.172.2.zip" -OutFile "$($vhdmountdir)\vsts-agent-win-x64-2.172.2.zip" | ||
Expand-Archive -Path "$($vhdmountdir)\vsts-agent-win-x64-2.172.2.zip" -DestinationPath "$($vhdmountdir)\a" -Force | ||
Copy-Item "vs_buildtools.exe" "$($vhdmountdir)\vs_buildtools.exe" | ||
Copy-Item "sfpcopy.exe" "$($vhdmountdir)\sfpcopy.exe" | ||
} | ||
} else { | ||
for ($i = $VmNumberStart; $i -le $VmsToProcess; $i++) { | ||
if ($Mode -eq "create") { | ||
CreateVM "$($VmNamePrefix)-$($i)" $i | ||
} elseif ($Mode -eq "config") { | ||
ConfigureVM "$($VmNamePrefix)-$($i)" $i | ||
} elseif ($Mode -eq "delete") { | ||
$VmName = "$($VmNamePrefix)-$($i)" | ||
DeleteVm $VmName | ||
} elseif ($Mode -eq "launchdebug") { | ||
$DebugPort = $DebugPortBase + $i | ||
windbgx.exe -y c:\symbols -k net:port=$DebugPort,key=$AzpDebugKey | ||
} | ||
} | ||
} | ||
``` |