Skip to content

Commit

Permalink
scripts: Add Windows guest preparation, cleanup and cloning scripts
Browse files Browse the repository at this point in the history
Signed-off-by: Tu Dinh <[email protected]>
  • Loading branch information
Tu Dinh committed Jan 16, 2025
1 parent a9c0582 commit e904ca2
Show file tree
Hide file tree
Showing 6 changed files with 227 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ __pycache__
*/__pycache__
data.py
vm_data.py
/scripts/guests/windows/id_rsa.pub
78 changes: 78 additions & 0 deletions scripts/guests/windows/install-autotest.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#Requires -RunAsAdministrator

[CmdletBinding()]
param (
[Parameter()]
[switch]$NoNetReporting,
[Parameter()]
[switch]$Cleanup
)

$ErrorActionPreference = "Stop"

if (!(Test-Path "$PSScriptRoot\id_rsa.pub")) {
throw "Cannot find id_rsa.pub for SSH configuration"
}

# Sometimes enabling updates will disrupt installation and rebooting.
# This is a temporary measure at most, but Microsoft makes disabling updates really difficult...
Write-Output "Disabling updates"
Set-ItemProperty -Path HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU -Name AUOptions -Type DWord -Value 2 -Force
Stop-Service wuauserv
Set-Service wuauserv -StartupType Disabled

Write-Output "Installing SSH"
$SSHDownloadPath = "$env:TEMP\OpenSSH-Win64-v9.8.1.0.msi"
Invoke-WebRequest -UseBasicParsing -Uri "https://github.com/PowerShell/Win32-OpenSSH/releases/download/v9.8.1.0p1-Preview/OpenSSH-Win64-v9.8.1.0.msi" -OutFile $SSHDownloadPath
$exitCode = (Start-Process -Wait msiexec.exe -ArgumentList "/i", $SSHDownloadPath, "/passive", "/norestart" -PassThru).ExitCode
if ($exitCode -ne 0) {
throw
}
Remove-Item -Force $SSHDownloadPath -ErrorAction SilentlyContinue
Copy-Item "$PSScriptRoot\id_rsa.pub" "$env:ProgramData\ssh\administrators_authorized_keys" -Force
icacls.exe "$env:ProgramData\ssh\administrators_authorized_keys" /inheritance:r /grant "Administrators:F" /grant "SYSTEM:F"
if ($LASTEXITCODE -ne 0) {
throw
}
New-NetFirewallRule -Action Allow -Program "$env:ProgramFiles\OpenSSH\sshd.exe" -Direction Inbound -Protocol TCP -LocalPort 22 -DisplayName sshd

Write-Output "Installing Git Bash"
$GitDownloadPath = "$env:TEMP\Git-2.47.1-64-bit.exe"
Invoke-WebRequest -UseBasicParsing -Uri "https://github.com/git-for-windows/git/releases/download/v2.47.1.windows.1/Git-2.47.1-64-bit.exe" -OutFile $GitDownloadPath
$exitCode = (Start-Process -Wait $GitDownloadPath -ArgumentList "/silent" -PassThru).ExitCode
if ($exitCode -ne 0) {
throw
}
Remove-Item -Force $GitDownloadPath -ErrorAction SilentlyContinue
Set-ItemProperty -Path "HKLM:\SOFTWARE\OpenSSH" -Name DefaultShell -Type String -Value "$env:ProgramFiles\Git\bin\bash.exe" -Force

if (!$NoNetReporting) {
Write-Output "Installing network reporting script"
Copy-Item "$PSScriptRoot\netreport.ps1" "$env:SystemDrive\" -Force
$action = New-ScheduledTaskAction -Execute "powershell.exe" -Argument "-executionpolicy bypass $env:SystemDrive\netreport.ps1"
$trigger = New-ScheduledTaskTrigger -AtStartup
$principal = New-ScheduledTaskPrincipal -UserId "NT AUTHORITY\SYSTEM" -RunLevel Highest
$task = New-ScheduledTask -Action $action -Trigger $trigger -Principal $principal
Register-ScheduledTask -InputObject $task -TaskName "XCP-ng Test Network Report"
}

if ($Cleanup) {
Read-Host -Prompt "Unplug Internet, run Disk Cleanup and continue"

Write-Output "Cleaning up component store"
dism.exe /Online /Cleanup-Image /StartComponentCleanup /ResetBase

Write-Output "Cleaning up SoftwareDistribution"
Stop-Service wuauserv, BITS -ErrorAction SilentlyContinue
Remove-Item -Recurse -Force -ErrorAction SilentlyContinue "$env:windir\SoftwareDistribution\Download\*"

Write-Output "Cleaning up Defender signatures"
& "$env:ProgramFiles\Windows Defender\MpCmdRun.exe" -RemoveDefinitions -All

Write-Output "Optimizing system drive"
defrag.exe $env:SystemDrive /O
}

Write-Output "Resealing"
Stop-Process -Name sysprep -ErrorAction SilentlyContinue
& "$env:windir\System32\Sysprep\sysprep.exe" /generalize /oobe /shutdown /unattend:$PSScriptRoot\unattend.xml
52 changes: 52 additions & 0 deletions scripts/guests/windows/install-drivers.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
[CmdletBinding()]
param (
[Parameter(Mandatory, ParameterSetName = "Drivers")]
[string]$DriverPath,
[Parameter(Mandatory, ParameterSetName = "Msi")]
[string]$MsiPath,
[Parameter()]
[switch]$Shutdown
)

$ErrorActionPreference = "Stop"

$signature = @'
[DllImport("Cfgmgr32.dll")]
public static extern uint CMP_WaitNoPendingInstallEvents(uint dwTimeout);
public const uint INFINITE = 0xFFFFFFFF;
public const uint WAIT_OBJECT_0 = 0;
public const uint WAIT_TIMEOUT = 258;
public const uint WAIT_FAILED = 0xFFFFFFFF;
'@

$nativeMethods = Add-Type -MemberDefinition $signature -Name NativeMethods -Namespace XenTools -PassThru

if ($DriverPath) {
foreach ($driver in @("xenbus", "xeniface", "xenvbd", "xenvif", "xennet")) {
$infPath = (Resolve-Path "$DriverPath\$driver\x64\$driver.inf").Path
Write-Output "Attempting install $infPath"
pnputil.exe /add-driver $infPath /install
if ($LASTEXITCODE -ne 0) {
throw "pnputil.exe $LASTEXITCODE"
}
}
}
elseif ($MsiPath) {
$resolvedMsiPath = (Resolve-Path $MsiPath).Path
Write-Output "Attempting install $resolvedMsiPath"
$msiexecProcess = Start-Process -Wait -PassThru msiexec.exe -ArgumentList "/i", "$resolvedMsiPath", "/l*", "C:\other-install.log", "/passive", "/norestart"
if ($msiexecProcess.ExitCode -ne 0 -and $msiexecProcess.ExitCode -ne 1641 -and $msiexecProcess.ExitCode -ne 3010) {
throw "msiexec.exe $($msiexecProcess.ExitCode)"
}
# Some installers like XCP-ng 8.2 don't install their drivers using MSI but through their own service (XenInstall).
# Leave some time for the installation service to do its thing.
Start-Sleep -Seconds 15
}
Write-Output "Waiting for install events"
$nativeMethods::CMP_WaitNoPendingInstallEvents($nativeMethods::INFINITE)

if ($Shutdown) {
Write-Output "Shutting down"
Start-Sleep -Seconds 5
Stop-Computer -Force
}
21 changes: 21 additions & 0 deletions scripts/guests/windows/netreport.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
do {
Start-Sleep -Seconds 2
$Adapter = Get-NetAdapter -Physical | Where-Object Status -eq Up | Select-Object -First 1
} while (!$Adapter)

$Address = Get-NetIPAddress -AddressFamily IPv4 -InterfaceIndex $Adapter.InterfaceIndex
# write the full `r`n sequence so that grep could catch it as a full line
$ReportString = "~xcp-ng-tests~$($Adapter.MacAddress)=$($Address.IPv4Address)~end~`r`n"

$Port = [System.IO.Ports.SerialPort]::new("COM1")
try {
$Port.Open()
for ($i = 0; $i -lt 300; $i++) {
$Port.Write($ReportString)
Start-Sleep -Seconds 1
}
$Port.Close()
}
finally {
$Port.Dispose()
}
29 changes: 29 additions & 0 deletions scripts/guests/windows/unattend.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<unattend xmlns="urn:schemas-microsoft-com:unattend">
<settings pass="oobeSystem">
<component name="Microsoft-Windows-International-Core" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<InputLocale>0409:00000409</InputLocale>
<SystemLocale>en-US</SystemLocale>
<UILanguage>en-US</UILanguage>
<UserLocale>en-US</UserLocale>
</component>
<component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<UserAccounts>
<LocalAccounts>
<LocalAccount wcm:action="add">
<Group>Administrators</Group>
<Name>root</Name>
</LocalAccount>
</LocalAccounts>
</UserAccounts>
<OOBE>
<HideEULAPage>true</HideEULAPage>
<HideLocalAccountScreen>true</HideLocalAccountScreen>
<HideOEMRegistrationScreen>true</HideOEMRegistrationScreen>
<HideOnlineAccountScreens>true</HideOnlineAccountScreens>
<HideWirelessSetupInOOBE>true</HideWirelessSetupInOOBE>
<ProtectYourPC>3</ProtectYourPC>
</OOBE>
</component>
</settings>
</unattend>
46 changes: 46 additions & 0 deletions scripts/guests/windows/win-diskclone.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#!/bin/bash
set -eu

src=$1
dst=$2

if [ "$(blockdev --getsz $src)" != "$(blockdev --getsz $dst)" ]
then
echo "Disks are not the same size!"
exit 1
fi

if (sfdisk -d $dst > /dev/null)
then
echo "Destination contains partition table! Stopping"
exit 1
fi

echo "Cloning partition table"
sfdisk -d $src | sfdisk $dst

echo "Cloning non-data partitions"
for srcpart in $(sfdisk -d $src |
grep start= |
grep -v type=EBD0A0A2-B9E5-4433-87C0-68B6B72699C7 |
cut -d ':' -f 1)
do
dstpart=${srcpart/"$src"/"$dst"}
echo "Cloning $srcpart to $dstpart"
pv $srcpart > $dstpart
done

echo "Cloning data partitions"
for srcpart in $(sfdisk -d $src |
grep type=EBD0A0A2-B9E5-4433-87C0-68B6B72699C7 |
cut -d ':' -f 1)
do
dstpart=${srcpart/"$src"/"$dst"}
echo "Deleting pagefiles"
mkdir -p /mnt/$srcpart &&
mount $srcpart /mnt/$srcpart &&
find /mnt/$srcpart -maxdepth 1 -iname pagefile.sys -or -iname hiberfil.sys -or -iname swapfile.sys -delete
umount /mnt/$srcpart
echo "Cloning $srcpart to $dstpart"
ntfsclone -O $dstpart $srcpart
done

0 comments on commit e904ca2

Please sign in to comment.