Skip to content

Commit

Permalink
Merge 32cff18 into a725dab
Browse files Browse the repository at this point in the history
  • Loading branch information
ader1990 committed Aug 28, 2019
2 parents a725dab + 32cff18 commit a5d912c
Show file tree
Hide file tree
Showing 3 changed files with 245 additions and 42 deletions.
43 changes: 42 additions & 1 deletion Tests/WinImageBuilder.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ Describe "Test Resize-VHDImage" {
}
Mock Get-Volume -Verifiable -ModuleName $moduleName { return @{"DriveLetter" = "F"} }
Mock Optimize-Volume -Verifiable -ModuleName $moduleName { return }
Mock Get-PartitionSupportedSize -Verifiable -ModuleName $moduleName { return @{"SizeMin" = 100} }
Mock Get-PartitionSupportedSize -Verifiable -ModuleName $moduleName { return @{"SizeMin" = 100; "SizeMax" = 1000} }
Mock Resize-Partition -Verifiable -ModuleName $moduleName { return 0 }
Mock Resize-VHD -Verifiable -ModuleName $moduleName { return 0 }
Mock Dismount-VHD -Verifiable -ModuleName $moduleName { return 0 }
Expand All @@ -177,6 +177,47 @@ Describe "Test Resize-VHDImage" {
}
}

Describe "Test Resize-VHDImage with binary search" {
function Get-VHD { }
function Mount-VHD { }
function Resize-VHD { }
function Dismount-VHD { }
Mock Write-Host -Verifiable -ModuleName $moduleName { return 0 }
Mock Get-VHD -Verifiable -ModuleName $moduleName { return @{"Size" = 100; "MinimumSize" = 10} }
Mock Mount-VHD -Verifiable -ModuleName $moduleName {
$b = New-Object System.Management.Automation.PSObject
$b | Add-Member -MemberType NoteProperty -Name "Number" -Value 1 -Force
return $b
}
Mock Get-Disk -Verifiable -ModuleName $moduleName {
$b = New-Object System.Management.Automation.PSObject
$b | Add-Member -MemberType NoteProperty -Name "DiskId" -Value 1 -Force
return $b
}
Mock Get-Partition -Verifiable -ModuleName $moduleName {
$b = New-Object System.Management.Automation.PSObject
$b | Add-Member -MemberType NoteProperty -Name "DriveLetter" -Value "L" -Force
$b | Add-Member -MemberType NoteProperty -Name "Size" -Value 90 -Force
return $b
}
Mock Get-Volume -Verifiable -ModuleName $moduleName { return @{"DriveLetter" = "F"} }
Mock Optimize-Volume -Verifiable -ModuleName $moduleName { return }
Mock Get-PartitionSupportedSize -Verifiable -ModuleName $moduleName { return @{"SizeMin" = 10GB; "SizeMax" = 1000GB} }
Mock Resize-Partition -Verifiable -ModuleName $moduleName { throw "Failure to resize" }
Mock Resize-VHD -Verifiable -ModuleName $moduleName { return 0 }
Mock Dismount-VHD -Verifiable -ModuleName $moduleName { return 0 }
Mock Start-Sleep -Verifiable -ModuleName $moduleName { return }

It "Should resize a vhd image" {
Resize-VHDImage -VirtualDiskPath "fakePath" `
-FreeSpace 100 | Should -Contain 0
}

It "should run all mocked commands" {
Assert-MockCalled -Times 10 -CommandName "Resize-Partition" -ModuleName $moduleName
}
}


Describe "Test New-WindowsOnlineImage" {
function Optimize-VHD { }
Expand Down
119 changes: 97 additions & 22 deletions UnattendResources/Logon.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ $ErrorActionPreference = "Stop"
$resourcesDir = "$ENV:SystemDrive\UnattendResources"
$configIniPath = "$resourcesDir\config.ini"
$customScriptsDir = "$resourcesDir\CustomScripts"
$logFile = "$resourcesDir\image-generation-log.txt"

function Set-PersistDrivers {
Param(
Expand Down Expand Up @@ -30,6 +31,7 @@ function Set-PersistDrivers {
}
}
$xml.Save($Path)
Write-Log "Drivers" "PersistDrivers was set to ${Persist} in the unattend.xml"
}

function Set-UnattendEnableSwap {
Expand Down Expand Up @@ -66,13 +68,15 @@ function Set-UnattendEnableSwap {
}
}
$xml.Save($Path)
Write-Log "Swap(1)" "Was enabled in the unattend.xml"
}

function Optimize-SparseImage {
$zapfree = "$resourcesDir\zapfree.exe"
if ( Test-Path $zapfree ) {
Write-Host "Optimizing for sparse image..."
& $zapfree -z $ENV:SystemDrive
Write-Log "ZapFree" "Image was zeroed succesfully"
} else {
Write-Debug "No zapfree. Image not optimized."
}
Expand All @@ -87,6 +91,7 @@ function Clean-UpdateResources {
# Cleanup
Remove-Item -Recurse -Force $resourcesDir
Remove-Item -Force "$ENV:SystemDrive\Unattend.xml"
Write-Log "Cleanup(1)" "Image was cleaned up succesfully"

}

Expand All @@ -105,6 +110,7 @@ function Clean-WindowsUpdates {
if ($LASTEXITCODE) {
throw "Dism.exe clean failed"
}
Write-Log "Cleanup" "Updates were cleaned up succesfully"
}
}

Expand All @@ -115,14 +121,16 @@ function Run-Defragment {
if ($LASTEXITCODE) {
throw "Defrag.exe failed"
}
Write-Log "Defragment" "Image was defragemented succesfully"
}

function Release-IP {
$HOST.UI.RawUI.WindowTitle = "Releasing IP..."
ipconfig.exe /release
if ($LASTEXITCODE) {
throw "IPconfig release failed"
}
throw "IPconfig release failed"
}
Write-Log "Ipconfig" "IPs were released succesfully"
}

function Install-WindowsUpdates {
Expand Down Expand Up @@ -150,10 +158,12 @@ function Install-WindowsUpdates {
# to be retrieved on a changed system state and be applied correctly.
Install-WindowsUpdate -Updates $updates[0..$maximumUpdates]
} finally {
Write-Log "Updates(${availableUpdatesNumber})" "Available updates were installed succesfully. Rebooting..."
Restart-Computer -Force
exit 0
}
}
Write-Log "Updates" "All available updates were installed succesfully"
}

function ExecRetry($command, $maxRetryCount=4, $retryInterval=4) {
Expand Down Expand Up @@ -191,6 +201,7 @@ function Disable-Swap {
if ($pageFileSetting) {
$pageFileSetting.Delete()
}
Write-Log "Swap" "Swap was disabled succesfully"
}

function License-Windows {
Expand All @@ -215,10 +226,12 @@ function License-Windows {
if ($licenseWindows) {
$licensingOutput = cscript.exe "$env:windir\system32\slmgr.vbs" /ipk $ProductKey
if ($lastExitCode) {
Write-Log "License" "Error: Windows could not be licensed"
throw $licensingOutput
} else {
Write-Host "Windows has been succesfully licensed."
}
Write-Log "License" "Windows was licensed succesfully"
} else {
Write-Host "Windows will not be licensed."
}
Expand Down Expand Up @@ -261,8 +274,10 @@ function Enable-AdministratorAccount {
& cmd.exe /c "net.exe user $username """
# Note(atira): net.exe can set an empty password only if it is run from cmd.exe
if ($LASTEXITCODE) {
Write-Log "Administrator" "Error: Account could not be enabled"
throw "Resetting $username password failed."
}
Write-Log "Administrator" "Account was enabled succesfully"
}

function Is-WindowsClient {
Expand All @@ -281,24 +296,25 @@ function Run-CustomScript {
if (Test-Path $fullScriptFilePath) {
Write-Host "Executing script $fullScriptFilePath"
& $fullScriptFilePath
if ($LastExitCode -eq 1004) {
# exit this script
exit 0
}
if ($LastExitCode -eq 1005) {
# exit this script and reboot
shutdown -r -t 0 -f
exit 0
}
if ($LastExitCode -eq 1006) {
# exit this script and shutdown
shutdown -s -t 0 -f
exit 0
}
if ($LastExitCode -eq 1) {
throw "Script $ScriptFileName executed unsuccessfuly"
}

if ($LastExitCode -eq 1004) {
# exit this script
exit 0
}
if ($LastExitCode -eq 1005) {
# exit this script and reboot
shutdown -r -t 0 -f
exit 0
}
if ($LastExitCode -eq 1006) {
# exit this script and shutdown
shutdown -s -t 0 -f
exit 0
}
if ($LastExitCode -eq 1) {
Write-Log "CustomScripts(${ScriptFileName})" "${ScriptFileName} failed to run"
throw "Script $ScriptFileName executed unsuccessfuly"
}
Write-Log "CustomScripts(${ScriptFileName})" "${ScriptFileName} executed succesfully"
}
}

Expand All @@ -310,12 +326,58 @@ function Install-VMwareTools {
}
$p = Start-Process -FilePath $vmwareToolsPath -ArgumentList $vmwareToolsInstallArgs -Wait -verb runAS
if ($p.ExitCode) {
Write-Log "VMwareTools" "Error: Tools could not be installed"
throw "VMware tools setup failed"
}
Write-Log "VMwareTools" "Tools installed succesfully"
}

function Write-HostLog {
<#
.SYNOPSIS
Uses KVP to communicate to the Hyper-V host the status of the various stages
of the imaging generation. This feature works only if the VM where this script
runs is spawned on Hyper-V and the 'Data Exchange' (aka Key Value Pair Exchange)
is enabled for the instance. On KVM / ESXi / baremetal, this method is NOOP.
#>
Param($Stage = "Default",
$StageLog
)

$KVPOutgoingRegistryKey = "HKLM://SOFTWARE/Microsoft/Virtual Machine/Auto"
if ($Stage -and $StageLog -and (Test-Path $KVPOutgoingRegistryKey)) {
Set-ItemProperty $KVPOutgoingRegistryKey -Name "ImageGenerationLog-${Stage}" `
-Value $StageLog -ErrorAction SilentlyContinue
}
}

function Write-Log {
<#
.SYNOPSIS
Writes timestamped logs to the console, to the log file and via KVP if on Hyper-V platform.
#>
Param($Stage = "Default",
$StageLog
)

$logMessage = "{0} - {1}: {2}" -f @((Get-Date), $Stage, $StageLog)
Write-Host $logMessage
Add-Content -Value $logMessage -Path $logFile -Force -Encoding Ascii -ErrorAction SilentlyContinue
Write-HostLog $Stage $StageLog
}

function Reset-AutoLogon {
param($AutoLogonPassword)

$autologonUser = $env:UserName
$winLogonRegistryPath = "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon"
Set-ItemProperty $winLogonRegistryPath "AutoAdminLogon" -Value 1 -Type String -Force
Set-ItemProperty $winLogonRegistryPath "DefaultUsername" -Value $autologonUser -Type String -Force
Set-ItemProperty $winLogonRegistryPath "DefaultPassword" -Value $autologonPassword -Type String -Force
}

try
{
try {
Write-Log "StatusInitial" "Automated instance configuration started..."
Import-Module "$resourcesDir\ini.psm1"
$installUpdates = Get-IniFileValue -Path $configIniPath -Section "updates" -Key "install_updates" -Default $false -AsBoolean
$persistDrivers = Get-IniFileValue -Path $configIniPath -Section "sysprep" -Key "persist_drivers_install" -Default $true -AsBoolean
Expand Down Expand Up @@ -344,6 +406,15 @@ try
try {
$useIpv6EUI64 = Get-IniFileValue -Path $configIniPath -Key "enable_ipv6_eui64"
} catch {}
try {
$autologonPassword = Get-IniFileValue -Path $configIniPath -Section "vm" -Key "administrator_password"
} catch {}

if ([System.Environment]::OSVersion.Version.Major -eq 10 -and `
[System.Environment]::OSVersion.Version.Minor -eq 0 -and `
((Get-WindowsEdition -Online).Edition -like '*Enterprise*')) {
Reset-AutoLogon -AutoLogonPassword $autologonPassword
}

if ($productKey) {
License-Windows $productKey
Expand Down Expand Up @@ -395,6 +466,7 @@ try

$p = Start-Process -Wait -PassThru -FilePath msiexec -ArgumentList $msiexecArgumentList
if ($p.ExitCode -ne 0) {
Write-Log "Cloudbase-Init" "Failed to install cloudbase-init"
throw "Installing $CloudbaseInitMsiPath failed. Log: $CloudbaseInitMsiLog"
}

Expand All @@ -405,6 +477,7 @@ try

$Host.UI.RawUI.WindowTitle = "Running SetSetupComplete..."
& "${cloudbaseInitInstallDir}\bin\SetSetupComplete.cmd"
Write-Log "Cloudbase-Init" "Installed succesfully"
Run-CustomScript "RunAfterCloudbaseInitInstall.ps1"

Run-Defragment
Expand Down Expand Up @@ -445,8 +518,10 @@ try
Run-CustomScript "RunBeforeSysprep.ps1"
Optimize-SparseImage
& "$ENV:SystemRoot\System32\Sysprep\Sysprep.exe" `/generalize `/oobe `/shutdown `/unattend:"$unattendedXmlPath"
Write-Log "Sysprep" "Sysprep initiated succesfully"
Run-CustomScript "RunAfterSysprep.ps1"
Clean-UpdateResources
Write-Log "StatusFinal" "Waiting for sysprep to stop machine..."
} catch {
$host.ui.WriteErrorLine($_.Exception.ToString())
$x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
Expand Down
Loading

0 comments on commit a5d912c

Please sign in to comment.