Skip to content

Commit

Permalink
added few options to support ZTP
Browse files Browse the repository at this point in the history
  • Loading branch information
jaromirk committed Jan 20, 2025
1 parent 2a36189 commit db18377
Show file tree
Hide file tree
Showing 2 changed files with 122 additions and 62 deletions.
171 changes: 110 additions & 61 deletions Scripts/3_Deploy.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -408,22 +408,34 @@ If (-not $isAdmin) {
)
WriteInfoHighlighted "Creating VM $($VMConfig.VMName)"
WriteInfo "`t Looking for Parent Disk"
$serverparent = Get-ChildItem "$PSScriptRoot\ParentDisks\" -Recurse | Where-Object Name -eq $VMConfig.ParentVHD

if ($serverparent -eq $null) {
WriteErrorAndExit "Server parent disk $($VMConfig.ParentVHD) not found."
if ($VMConfig.ParentVHD){
$serverparent = Get-ChildItem "$PSScriptRoot\ParentDisks\" -Recurse | Where-Object Name -eq $VMConfig.ParentVHD
if ($serverparent -eq $null) {
WriteErrorAndExit "Server parent disk $($VMConfig.ParentVHD) not found."
}else{
WriteInfo "`t`t Server parent disk $($serverparent.Name) found"
}
}else{
WriteInfo "`t`t Server parent disk $($serverparent.Name) found"
WriteInfo "`t`t Server parent disk not specified. VHD will be created"
}

$VMname=$Labconfig.Prefix+$VMConfig.VMName

if ($serverparent.Extension -eq ".vhdx"){
$vhdpath="$LabFolder\VMs\$VMname\Virtual Hard Disks\$VMname.vhdx"
}elseif($serverparent.Extension -eq ".vhd"){
$vhdpath="$LabFolder\VMs\$VMname\Virtual Hard Disks\$VMname.vhd"
}else{
$vhdpath="$LabFolder\VMs\$VMname\Virtual Hard Disks\$VMname.vhdx"
}

if ($serverparent){
WriteInfo "`t Creating OS VHD from parent disk $($VMConfig.ParentVHD)"
New-VHD -ParentPath $serverparent.fullname -Path $vhdpath
}else{
WriteInfo "`t Creating blank OS VHD"
New-VHD -Path $vhdpath -SizeBytes 127GB
}
WriteInfo "`t Creating OS VHD"
New-VHD -ParentPath $serverparent.fullname -Path $vhdpath

if ($VMConfig.VMVersion){
$VMTemp = New-VM -Path "$LabFolder\VMs" -Name $VMname -Generation 2 -MemoryStartupBytes $VMConfig.MemoryStartupBytes -SwitchName $SwitchName -VHDPath $vhdPath -Version $VMConfig.VMVersion
Expand All @@ -443,7 +455,14 @@ If (-not $isAdmin) {
if ($VMTemp.AutomaticCheckpointsEnabled -eq $True){
$VMTemp | Set-VM -AutomaticCheckpointsEnabled $False
}
$VMTemp | Set-VMFirmware -EnableSecureBoot Off

if ($VMConfig.SecureBoot -eq "Linux"){
WriteInfo "`t Configuring Secure Boot to Linux"
$VMTemp | Set-VMFirmware -SecureBootTemplateId ([guid]'272e7447-90a4-4563-a4b9-8e4ab00526ce')
}else{
WriteInfo "`t Disabling Secure Boot"
$VMTemp | Set-VMFirmware -EnableSecureBoot Off
}

# only Debian Buster supports Secure Boot
#$vm | Set-VMFirmware -EnableSecureBoot On -SecureBootTemplateId "272e7447-90a4-4563-a4b9-8e4ab00526ce" # -SecureBootTemplate MicrosoftUEFICertificateAuthority
Expand Down Expand Up @@ -534,26 +553,37 @@ If (-not $isAdmin) {
)
WriteInfoHighlighted "Creating VM $($VMConfig.VMName)"
WriteInfo "`t Looking for Parent Disk"
$serverparent=Get-ChildItem "$PSScriptRoot\ParentDisks\" -Recurse | Where-Object Name -eq $VMConfig.ParentVHD

if ($serverparent -eq $null){
WriteErrorAndExit "Server parent disk $($VMConfig.ParentVHD) not found."
if ($VMConfig.ParentVHD){
$serverparent = Get-ChildItem "$PSScriptRoot\ParentDisks\" -Recurse | Where-Object Name -eq $VMConfig.ParentVHD
if ($serverparent -eq $null) {
WriteErrorAndExit "Server parent disk $($VMConfig.ParentVHD) not found."
}else{
WriteInfo "`t`t Server parent disk $($serverparent.Name) found"
}
}else{
WriteInfo "`t`t Server parent disk $($serverparent.Name) found"
WriteInfo "`t`t Server parent disk not specified. VHD will be created"
}

$VMname=$Labconfig.Prefix+$VMConfig.VMName

if ($serverparent.Extension -eq ".vhdx"){
$vhdpath="$LabFolder\VMs\$VMname\Virtual Hard Disks\$VMname.vhdx"
}elseif($serverparent.Extension -eq ".vhd"){
$vhdpath="$LabFolder\VMs\$VMname\Virtual Hard Disks\$VMname.vhd"
}else{
$vhdpath="$LabFolder\VMs\$VMname\Virtual Hard Disks\$VMname.vhdx"
}
WriteInfoHighlighted "`t Creating OS VHD"
New-VHD -ParentPath $serverparent.fullname -Path $vhdpath

#Get VM Version
[System.Version]$BuildVersion=(Get-WindowsImage -ImagePath $VHDPath -Index 1).Version
WriteInfo "`t VM Version is $($BuildVersion.Build).$($BuildVersion.Revision)"
if ($serverparent){
WriteInfo "`t Creating OS VHD from parent disk $($VMConfig.ParentVHD)"
New-VHD -ParentPath $serverparent.fullname -Path $vhdpath
#Get VM Version
[System.Version]$BuildVersion=(Get-WindowsImage -ImagePath $VHDPath -Index 1).Version
WriteInfo "`t VM Version is $($BuildVersion.Build).$($BuildVersion.Revision)"
}else{
WriteInfo "`t Creating blank OS VHD"
New-VHD -Path $vhdpath -SizeBytes 127GB
}

WriteInfo "`t Creating VM"
if ($VMConfig.VMVersion){
Expand Down Expand Up @@ -662,6 +692,15 @@ If (-not $isAdmin) {
}
}

#configure secure boot
if ($VMConfig.SecureBoot -eq "Linux"){
WriteInfo "`t Configuring Secure Boot to Linux"
$VMTemp | Set-VMFirmware -SecureBootTemplateId ([guid]'272e7447-90a4-4563-a4b9-8e4ab00526ce')
}elseif ($VMConfig.SecureBoot -eq "Disabled"){
WriteInfo "`t Disabling Secure Boot"
$VMTemp | Set-VMFirmware -EnableSecureBoot Off
}

#set MemoryMinimumBytes
if ($VMConfig.MemoryMinimumBytes -ne $null){
WriteInfo "`t Configuring MemoryMinimumBytes to $($VMConfig.MemoryMinimumBytes/1MB)MB"
Expand Down Expand Up @@ -770,50 +809,52 @@ If (-not $isAdmin) {
WriteInfo "`t`t Subnet ID is 0 with NativeVLAN 0. AllowedVlanIDList is $($LabConfig.AllowedVLANs)"
$VMTemp | Set-VMNetworkAdapterVlan -VMNetworkAdapterName "Management*" -Trunk -NativeVlanId 0 -AllowedVlanIdList "$AllowedVLANs"

#Create Unattend file
if ($VMConfig.Unattend -eq "NoDjoin" -or $VMConfig.SkipDjoin){
WriteInfo "`t Skipping Djoin"
if ($VMConfig.AdditionalLocalAdmin){
WriteInfo "`t Additional Local Admin $($VMConfig.AdditionalLocalAdmin) will be added"
$AdditionalLocalAccountXML=AdditionalLocalAccountXML -AdditionalAdminName $VMConfig.AdditionalLocalAdmin -AdminPassword $LabConfig.AdminPassword
$unattendfile=CreateUnattendFileNoDjoin -ComputerName $Name -AdminPassword $LabConfig.AdminPassword -RunSynchronous $RunSynchronous -AdditionalAccount $AdditionalLocalAccountXML -TimeZone $TimeZone
}else{
$unattendfile=CreateUnattendFileNoDjoin -ComputerName $Name -AdminPassword $LabConfig.AdminPassword -RunSynchronous $RunSynchronous -TimeZone $TimeZone
if ($serverparent){
#Create Unattend file if there was server parent disk. If not, blank was created and it does not make sense to create answer file
if ($VMConfig.Unattend -eq "NoDjoin" -or $VMConfig.SkipDjoin){
WriteInfo "`t Skipping Djoin"
if ($VMConfig.AdditionalLocalAdmin){
WriteInfo "`t Additional Local Admin $($VMConfig.AdditionalLocalAdmin) will be added"
$AdditionalLocalAccountXML=AdditionalLocalAccountXML -AdditionalAdminName $VMConfig.AdditionalLocalAdmin -AdminPassword $LabConfig.AdminPassword
$unattendfile=CreateUnattendFileNoDjoin -ComputerName $Name -AdminPassword $LabConfig.AdminPassword -RunSynchronous $RunSynchronous -AdditionalAccount $AdditionalLocalAccountXML -TimeZone $TimeZone
}else{
$unattendfile=CreateUnattendFileNoDjoin -ComputerName $Name -AdminPassword $LabConfig.AdminPassword -RunSynchronous $RunSynchronous -TimeZone $TimeZone
}
}elseif($VMConfig.Win2012Djoin -or $VMConfig.Unattend -eq "DjoinCred"){
WriteInfoHighlighted "`t Creating Unattend with win2012-ish domain join"
$unattendfile=CreateUnattendFileWin2012 -ComputerName $Name -AdminPassword $LabConfig.AdminPassword -DomainName $Labconfig.DomainName -RunSynchronous $RunSynchronous -TimeZone $TimeZone

}elseif($VMConfig.Unattend -eq "DjoinBlob" -or -not ($VMConfig.Unattend)){
WriteInfoHighlighted "`t Creating Unattend with djoin blob"
$path="c:\$vmname.txt"
Invoke-Command -VMGuid $DC.id -Credential $cred -ScriptBlock {param($Name,$path,$Labconfig); djoin.exe /provision /domain $labconfig.DomainNetbiosName /machine $Name /savefile $path /machineou "OU=$($Labconfig.DefaultOUName),$($Labconfig.DN)"} -ArgumentList $Name,$path,$Labconfig
$blob=Invoke-Command -VMGuid $DC.id -Credential $cred -ScriptBlock {param($path); get-content $path} -ArgumentList $path
Invoke-Command -VMGuid $DC.id -Credential $cred -ScriptBlock {param($path); Remove-Item $path} -ArgumentList $path
$unattendfile=CreateUnattendFileBlob -Blob $blob.Substring(0,$blob.Length-1) -AdminPassword $LabConfig.AdminPassword -RunSynchronous $RunSynchronous -TimeZone $TimeZone
}elseif($VMConfig.Unattend -eq "None"){
$unattendFile=$Null
}
}elseif($VMConfig.Win2012Djoin -or $VMConfig.Unattend -eq "DjoinCred"){
WriteInfoHighlighted "`t Creating Unattend with win2012-ish domain join"
$unattendfile=CreateUnattendFileWin2012 -ComputerName $Name -AdminPassword $LabConfig.AdminPassword -DomainName $Labconfig.DomainName -RunSynchronous $RunSynchronous -TimeZone $TimeZone

}elseif($VMConfig.Unattend -eq "DjoinBlob" -or -not ($VMConfig.Unattend)){
WriteInfoHighlighted "`t Creating Unattend with djoin blob"
$path="c:\$vmname.txt"
Invoke-Command -VMGuid $DC.id -Credential $cred -ScriptBlock {param($Name,$path,$Labconfig); djoin.exe /provision /domain $labconfig.DomainNetbiosName /machine $Name /savefile $path /machineou "OU=$($Labconfig.DefaultOUName),$($Labconfig.DN)"} -ArgumentList $Name,$path,$Labconfig
$blob=Invoke-Command -VMGuid $DC.id -Credential $cred -ScriptBlock {param($path); get-content $path} -ArgumentList $path
Invoke-Command -VMGuid $DC.id -Credential $cred -ScriptBlock {param($path); Remove-Item $path} -ArgumentList $path
$unattendfile=CreateUnattendFileBlob -Blob $blob.Substring(0,$blob.Length-1) -AdminPassword $LabConfig.AdminPassword -RunSynchronous $RunSynchronous -TimeZone $TimeZone
}elseif($VMConfig.Unattend -eq "None"){
$unattendFile=$Null
}

#adding unattend to VHD
if ($unattendFile){
WriteInfo "`t Adding unattend to VHD"
Mount-WindowsImage -Path $mountdir -ImagePath $VHDPath -Index 1
Use-WindowsUnattend -Path $mountdir -UnattendPath $unattendFile
#&"$PSScriptRoot\Tools\dism\dism" /mount-image /imagefile:$vhdpath /index:1 /MountDir:$mountdir
#&"$PSScriptRoot\Tools\dism\dism" /image:$mountdir /Apply-Unattend:$unattendfile
New-item -type directory "$mountdir\Windows\Panther" -ErrorAction Ignore
Copy-Item $unattendfile "$mountdir\Windows\Panther\unattend.xml"
}

if ($VMConfig.DSCMode -eq 'Pull'){
WriteInfo "`t Adding metaconfig.mof to VHD"
Copy-Item "$PSScriptRoot\temp\dscconfig\$name.meta.mof" -Destination "$mountdir\Windows\system32\Configuration\metaconfig.mof"
}
#adding unattend to VHD
if ($unattendFile){
WriteInfo "`t Adding unattend to VHD"
Mount-WindowsImage -Path $mountdir -ImagePath $VHDPath -Index 1
Use-WindowsUnattend -Path $mountdir -UnattendPath $unattendFile
#&"$PSScriptRoot\Tools\dism\dism" /mount-image /imagefile:$vhdpath /index:1 /MountDir:$mountdir
#&"$PSScriptRoot\Tools\dism\dism" /image:$mountdir /Apply-Unattend:$unattendfile
New-item -type directory "$mountdir\Windows\Panther" -ErrorAction Ignore
Copy-Item $unattendfile "$mountdir\Windows\Panther\unattend.xml"
}

if ($unattendFile){
Dismount-WindowsImage -Path $mountdir -Save
#&"$PSScriptRoot\Tools\dism\dism" /Unmount-Image /MountDir:$mountdir /Commit
if ($VMConfig.DSCMode -eq 'Pull'){
WriteInfo "`t Adding metaconfig.mof to VHD"
Copy-Item "$PSScriptRoot\temp\dscconfig\$name.meta.mof" -Destination "$mountdir\Windows\system32\Configuration\metaconfig.mof"
}

if ($unattendFile){
Dismount-WindowsImage -Path $mountdir -Save
#&"$PSScriptRoot\Tools\dism\dism" /Unmount-Image /MountDir:$mountdir /Commit
}
}

#add toolsdisk
Expand All @@ -823,6 +864,15 @@ If (-not $isAdmin) {
$VMTemp | Add-VMHardDiskDrive -Path $vhd.Path
}

#add ISO
if ($VMConfig.AttachISO){
if (-not ($VMTemp | Get-VMDvdDrive)){
WriteInfoHighlighted "`t Adding ISO $($VMConfig.AttachISO)"
$DVD=$VMTemp | Add-VMDvdDrive -Path "$PSScriptRoot\ParentDisks\$($VMConfig.AttachISO)" -Passthru
$VMTemp | Set-VMFirmware -FirstBootDevice $DVD
}
}

# return info
[PSCustomObject]@{
OSDiskPath = $vhdpath
Expand Down Expand Up @@ -1668,9 +1718,8 @@ If (-not $isAdmin) {
'vm.configuration' = $VMConfig.Configuration
'vm.unattend' = $VMConfig.Unattend
}
if((Test-Path -Path $createdVm.OSDiskPath) -and $VMConfig.configuration -ne "Linux") {
if((Test-Path -Path $createdVm.OSDiskPath) -and ($VMConfig.configuration -ne "Linux") -and ($VMConfig.ParentVHD)) {
$osInfo = Get-WindowsImage -ImagePath $createdVm.OSDiskPath -Index 1

$properties.'vm.os.installationType' = $osInfo.InstallationType
$properties.'vm.os.editionId' = $osInfo.EditionId
$properties.'vm.os.version' = $osInfo.Version
Expand Down
13 changes: 12 additions & 1 deletion Scripts/LabConfig.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ $LabConfig=@{AllowedVLANs="1-10,711-719" ; DomainAdminName='LabAdmin'; AdminPass
VMSet (Mandatory for Shared and Replica configuration)
This is unique name for your set of VMs. You need to specify it for Spaces and Replica scenario, so script will connect shared disks to the same VMSet.
ParentVHD (Mandatory)
ParentVHD (Optional. If Null, new VHDx will be created)
'Win2016Core_G2.vhdx' - Windows Server 2016 Core
'Win2016NanoHV_G2.vhdx' - Windows Server 2016 Nano with these packages: DSC, Failover Cluster, Guest, Storage, SCVMM
'Win2016NanoHV_G2.vhdx' - Windows Server 2016 Nano with these packages: DSC, Failover Cluster, Guest, Storage, SCVMM, Compute, SCVMM Compute
Expand Down Expand Up @@ -346,6 +346,17 @@ $LabConfig=@{AllowedVLANs="1-10,711-719" ; DomainAdminName='LabAdmin'; AdminPass
Example VMVersion="10.0"
default versions - Windows Server 2022 = 10.0, Widnows Server 2025 = 12.0
https://learn.microsoft.com/en-us/windows-server/virtualization/hyper-v/deploy/Upgrade-virtual-machine-version-in-Hyper-V-on-Windows-or-Windows-Server
#AttachISO (optional)
Example AttachISO="WindowsServer2025.iso"
it will mount iso specified from Parent Disks
#SecureBoot (optional)
Example Secureboot="Linux"
enables/disables secure boot for VM
possible values: windows,linux,disabled
Default: windows for windows machines, disabled for linux VMs
#>
#endregion

Expand Down

0 comments on commit db18377

Please sign in to comment.