Skip to content

Commit 0a58141

Browse files
authored
Merge pull request #616 from microsoft/dev
added few options to support ZTP
2 parents bfe9289 + db18377 commit 0a58141

File tree

2 files changed

+122
-62
lines changed

2 files changed

+122
-62
lines changed

Scripts/3_Deploy.ps1

Lines changed: 110 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -408,22 +408,34 @@ If (-not $isAdmin) {
408408
)
409409
WriteInfoHighlighted "Creating VM $($VMConfig.VMName)"
410410
WriteInfo "`t Looking for Parent Disk"
411-
$serverparent = Get-ChildItem "$PSScriptRoot\ParentDisks\" -Recurse | Where-Object Name -eq $VMConfig.ParentVHD
412-
413-
if ($serverparent -eq $null) {
414-
WriteErrorAndExit "Server parent disk $($VMConfig.ParentVHD) not found."
411+
if ($VMConfig.ParentVHD){
412+
$serverparent = Get-ChildItem "$PSScriptRoot\ParentDisks\" -Recurse | Where-Object Name -eq $VMConfig.ParentVHD
413+
if ($serverparent -eq $null) {
414+
WriteErrorAndExit "Server parent disk $($VMConfig.ParentVHD) not found."
415+
}else{
416+
WriteInfo "`t`t Server parent disk $($serverparent.Name) found"
417+
}
415418
}else{
416-
WriteInfo "`t`t Server parent disk $($serverparent.Name) found"
419+
WriteInfo "`t`t Server parent disk not specified. VHD will be created"
417420
}
418421

419422
$VMname=$Labconfig.Prefix+$VMConfig.VMName
423+
420424
if ($serverparent.Extension -eq ".vhdx"){
421425
$vhdpath="$LabFolder\VMs\$VMname\Virtual Hard Disks\$VMname.vhdx"
422426
}elseif($serverparent.Extension -eq ".vhd"){
423427
$vhdpath="$LabFolder\VMs\$VMname\Virtual Hard Disks\$VMname.vhd"
428+
}else{
429+
$vhdpath="$LabFolder\VMs\$VMname\Virtual Hard Disks\$VMname.vhdx"
430+
}
431+
432+
if ($serverparent){
433+
WriteInfo "`t Creating OS VHD from parent disk $($VMConfig.ParentVHD)"
434+
New-VHD -ParentPath $serverparent.fullname -Path $vhdpath
435+
}else{
436+
WriteInfo "`t Creating blank OS VHD"
437+
New-VHD -Path $vhdpath -SizeBytes 127GB
424438
}
425-
WriteInfo "`t Creating OS VHD"
426-
New-VHD -ParentPath $serverparent.fullname -Path $vhdpath
427439

428440
if ($VMConfig.VMVersion){
429441
$VMTemp = New-VM -Path "$LabFolder\VMs" -Name $VMname -Generation 2 -MemoryStartupBytes $VMConfig.MemoryStartupBytes -SwitchName $SwitchName -VHDPath $vhdPath -Version $VMConfig.VMVersion
@@ -443,7 +455,14 @@ If (-not $isAdmin) {
443455
if ($VMTemp.AutomaticCheckpointsEnabled -eq $True){
444456
$VMTemp | Set-VM -AutomaticCheckpointsEnabled $False
445457
}
446-
$VMTemp | Set-VMFirmware -EnableSecureBoot Off
458+
459+
if ($VMConfig.SecureBoot -eq "Linux"){
460+
WriteInfo "`t Configuring Secure Boot to Linux"
461+
$VMTemp | Set-VMFirmware -SecureBootTemplateId ([guid]'272e7447-90a4-4563-a4b9-8e4ab00526ce')
462+
}else{
463+
WriteInfo "`t Disabling Secure Boot"
464+
$VMTemp | Set-VMFirmware -EnableSecureBoot Off
465+
}
447466

448467
# only Debian Buster supports Secure Boot
449468
#$vm | Set-VMFirmware -EnableSecureBoot On -SecureBootTemplateId "272e7447-90a4-4563-a4b9-8e4ab00526ce" # -SecureBootTemplate MicrosoftUEFICertificateAuthority
@@ -534,26 +553,37 @@ If (-not $isAdmin) {
534553
)
535554
WriteInfoHighlighted "Creating VM $($VMConfig.VMName)"
536555
WriteInfo "`t Looking for Parent Disk"
537-
$serverparent=Get-ChildItem "$PSScriptRoot\ParentDisks\" -Recurse | Where-Object Name -eq $VMConfig.ParentVHD
538-
539-
if ($serverparent -eq $null){
540-
WriteErrorAndExit "Server parent disk $($VMConfig.ParentVHD) not found."
556+
if ($VMConfig.ParentVHD){
557+
$serverparent = Get-ChildItem "$PSScriptRoot\ParentDisks\" -Recurse | Where-Object Name -eq $VMConfig.ParentVHD
558+
if ($serverparent -eq $null) {
559+
WriteErrorAndExit "Server parent disk $($VMConfig.ParentVHD) not found."
560+
}else{
561+
WriteInfo "`t`t Server parent disk $($serverparent.Name) found"
562+
}
541563
}else{
542-
WriteInfo "`t`t Server parent disk $($serverparent.Name) found"
564+
WriteInfo "`t`t Server parent disk not specified. VHD will be created"
543565
}
544566

545567
$VMname=$Labconfig.Prefix+$VMConfig.VMName
568+
546569
if ($serverparent.Extension -eq ".vhdx"){
547570
$vhdpath="$LabFolder\VMs\$VMname\Virtual Hard Disks\$VMname.vhdx"
548571
}elseif($serverparent.Extension -eq ".vhd"){
549572
$vhdpath="$LabFolder\VMs\$VMname\Virtual Hard Disks\$VMname.vhd"
573+
}else{
574+
$vhdpath="$LabFolder\VMs\$VMname\Virtual Hard Disks\$VMname.vhdx"
550575
}
551-
WriteInfoHighlighted "`t Creating OS VHD"
552-
New-VHD -ParentPath $serverparent.fullname -Path $vhdpath
553576

554-
#Get VM Version
555-
[System.Version]$BuildVersion=(Get-WindowsImage -ImagePath $VHDPath -Index 1).Version
556-
WriteInfo "`t VM Version is $($BuildVersion.Build).$($BuildVersion.Revision)"
577+
if ($serverparent){
578+
WriteInfo "`t Creating OS VHD from parent disk $($VMConfig.ParentVHD)"
579+
New-VHD -ParentPath $serverparent.fullname -Path $vhdpath
580+
#Get VM Version
581+
[System.Version]$BuildVersion=(Get-WindowsImage -ImagePath $VHDPath -Index 1).Version
582+
WriteInfo "`t VM Version is $($BuildVersion.Build).$($BuildVersion.Revision)"
583+
}else{
584+
WriteInfo "`t Creating blank OS VHD"
585+
New-VHD -Path $vhdpath -SizeBytes 127GB
586+
}
557587

558588
WriteInfo "`t Creating VM"
559589
if ($VMConfig.VMVersion){
@@ -662,6 +692,15 @@ If (-not $isAdmin) {
662692
}
663693
}
664694

695+
#configure secure boot
696+
if ($VMConfig.SecureBoot -eq "Linux"){
697+
WriteInfo "`t Configuring Secure Boot to Linux"
698+
$VMTemp | Set-VMFirmware -SecureBootTemplateId ([guid]'272e7447-90a4-4563-a4b9-8e4ab00526ce')
699+
}elseif ($VMConfig.SecureBoot -eq "Disabled"){
700+
WriteInfo "`t Disabling Secure Boot"
701+
$VMTemp | Set-VMFirmware -EnableSecureBoot Off
702+
}
703+
665704
#set MemoryMinimumBytes
666705
if ($VMConfig.MemoryMinimumBytes -ne $null){
667706
WriteInfo "`t Configuring MemoryMinimumBytes to $($VMConfig.MemoryMinimumBytes/1MB)MB"
@@ -770,50 +809,52 @@ If (-not $isAdmin) {
770809
WriteInfo "`t`t Subnet ID is 0 with NativeVLAN 0. AllowedVlanIDList is $($LabConfig.AllowedVLANs)"
771810
$VMTemp | Set-VMNetworkAdapterVlan -VMNetworkAdapterName "Management*" -Trunk -NativeVlanId 0 -AllowedVlanIdList "$AllowedVLANs"
772811

773-
#Create Unattend file
774-
if ($VMConfig.Unattend -eq "NoDjoin" -or $VMConfig.SkipDjoin){
775-
WriteInfo "`t Skipping Djoin"
776-
if ($VMConfig.AdditionalLocalAdmin){
777-
WriteInfo "`t Additional Local Admin $($VMConfig.AdditionalLocalAdmin) will be added"
778-
$AdditionalLocalAccountXML=AdditionalLocalAccountXML -AdditionalAdminName $VMConfig.AdditionalLocalAdmin -AdminPassword $LabConfig.AdminPassword
779-
$unattendfile=CreateUnattendFileNoDjoin -ComputerName $Name -AdminPassword $LabConfig.AdminPassword -RunSynchronous $RunSynchronous -AdditionalAccount $AdditionalLocalAccountXML -TimeZone $TimeZone
780-
}else{
781-
$unattendfile=CreateUnattendFileNoDjoin -ComputerName $Name -AdminPassword $LabConfig.AdminPassword -RunSynchronous $RunSynchronous -TimeZone $TimeZone
812+
if ($serverparent){
813+
#Create Unattend file if there was server parent disk. If not, blank was created and it does not make sense to create answer file
814+
if ($VMConfig.Unattend -eq "NoDjoin" -or $VMConfig.SkipDjoin){
815+
WriteInfo "`t Skipping Djoin"
816+
if ($VMConfig.AdditionalLocalAdmin){
817+
WriteInfo "`t Additional Local Admin $($VMConfig.AdditionalLocalAdmin) will be added"
818+
$AdditionalLocalAccountXML=AdditionalLocalAccountXML -AdditionalAdminName $VMConfig.AdditionalLocalAdmin -AdminPassword $LabConfig.AdminPassword
819+
$unattendfile=CreateUnattendFileNoDjoin -ComputerName $Name -AdminPassword $LabConfig.AdminPassword -RunSynchronous $RunSynchronous -AdditionalAccount $AdditionalLocalAccountXML -TimeZone $TimeZone
820+
}else{
821+
$unattendfile=CreateUnattendFileNoDjoin -ComputerName $Name -AdminPassword $LabConfig.AdminPassword -RunSynchronous $RunSynchronous -TimeZone $TimeZone
822+
}
823+
}elseif($VMConfig.Win2012Djoin -or $VMConfig.Unattend -eq "DjoinCred"){
824+
WriteInfoHighlighted "`t Creating Unattend with win2012-ish domain join"
825+
$unattendfile=CreateUnattendFileWin2012 -ComputerName $Name -AdminPassword $LabConfig.AdminPassword -DomainName $Labconfig.DomainName -RunSynchronous $RunSynchronous -TimeZone $TimeZone
826+
827+
}elseif($VMConfig.Unattend -eq "DjoinBlob" -or -not ($VMConfig.Unattend)){
828+
WriteInfoHighlighted "`t Creating Unattend with djoin blob"
829+
$path="c:\$vmname.txt"
830+
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
831+
$blob=Invoke-Command -VMGuid $DC.id -Credential $cred -ScriptBlock {param($path); get-content $path} -ArgumentList $path
832+
Invoke-Command -VMGuid $DC.id -Credential $cred -ScriptBlock {param($path); Remove-Item $path} -ArgumentList $path
833+
$unattendfile=CreateUnattendFileBlob -Blob $blob.Substring(0,$blob.Length-1) -AdminPassword $LabConfig.AdminPassword -RunSynchronous $RunSynchronous -TimeZone $TimeZone
834+
}elseif($VMConfig.Unattend -eq "None"){
835+
$unattendFile=$Null
782836
}
783-
}elseif($VMConfig.Win2012Djoin -or $VMConfig.Unattend -eq "DjoinCred"){
784-
WriteInfoHighlighted "`t Creating Unattend with win2012-ish domain join"
785-
$unattendfile=CreateUnattendFileWin2012 -ComputerName $Name -AdminPassword $LabConfig.AdminPassword -DomainName $Labconfig.DomainName -RunSynchronous $RunSynchronous -TimeZone $TimeZone
786-
787-
}elseif($VMConfig.Unattend -eq "DjoinBlob" -or -not ($VMConfig.Unattend)){
788-
WriteInfoHighlighted "`t Creating Unattend with djoin blob"
789-
$path="c:\$vmname.txt"
790-
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
791-
$blob=Invoke-Command -VMGuid $DC.id -Credential $cred -ScriptBlock {param($path); get-content $path} -ArgumentList $path
792-
Invoke-Command -VMGuid $DC.id -Credential $cred -ScriptBlock {param($path); Remove-Item $path} -ArgumentList $path
793-
$unattendfile=CreateUnattendFileBlob -Blob $blob.Substring(0,$blob.Length-1) -AdminPassword $LabConfig.AdminPassword -RunSynchronous $RunSynchronous -TimeZone $TimeZone
794-
}elseif($VMConfig.Unattend -eq "None"){
795-
$unattendFile=$Null
796-
}
797-
798-
#adding unattend to VHD
799-
if ($unattendFile){
800-
WriteInfo "`t Adding unattend to VHD"
801-
Mount-WindowsImage -Path $mountdir -ImagePath $VHDPath -Index 1
802-
Use-WindowsUnattend -Path $mountdir -UnattendPath $unattendFile
803-
#&"$PSScriptRoot\Tools\dism\dism" /mount-image /imagefile:$vhdpath /index:1 /MountDir:$mountdir
804-
#&"$PSScriptRoot\Tools\dism\dism" /image:$mountdir /Apply-Unattend:$unattendfile
805-
New-item -type directory "$mountdir\Windows\Panther" -ErrorAction Ignore
806-
Copy-Item $unattendfile "$mountdir\Windows\Panther\unattend.xml"
807-
}
808837

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

814-
if ($unattendFile){
815-
Dismount-WindowsImage -Path $mountdir -Save
816-
#&"$PSScriptRoot\Tools\dism\dism" /Unmount-Image /MountDir:$mountdir /Commit
849+
if ($VMConfig.DSCMode -eq 'Pull'){
850+
WriteInfo "`t Adding metaconfig.mof to VHD"
851+
Copy-Item "$PSScriptRoot\temp\dscconfig\$name.meta.mof" -Destination "$mountdir\Windows\system32\Configuration\metaconfig.mof"
852+
}
853+
854+
if ($unattendFile){
855+
Dismount-WindowsImage -Path $mountdir -Save
856+
#&"$PSScriptRoot\Tools\dism\dism" /Unmount-Image /MountDir:$mountdir /Commit
857+
}
817858
}
818859

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

867+
#add ISO
868+
if ($VMConfig.AttachISO){
869+
if (-not ($VMTemp | Get-VMDvdDrive)){
870+
WriteInfoHighlighted "`t Adding ISO $($VMConfig.AttachISO)"
871+
$DVD=$VMTemp | Add-VMDvdDrive -Path "$PSScriptRoot\ParentDisks\$($VMConfig.AttachISO)" -Passthru
872+
$VMTemp | Set-VMFirmware -FirstBootDevice $DVD
873+
}
874+
}
875+
826876
# return info
827877
[PSCustomObject]@{
828878
OSDiskPath = $vhdpath
@@ -1668,9 +1718,8 @@ If (-not $isAdmin) {
16681718
'vm.configuration' = $VMConfig.Configuration
16691719
'vm.unattend' = $VMConfig.Unattend
16701720
}
1671-
if((Test-Path -Path $createdVm.OSDiskPath) -and $VMConfig.configuration -ne "Linux") {
1721+
if((Test-Path -Path $createdVm.OSDiskPath) -and ($VMConfig.configuration -ne "Linux") -and ($VMConfig.ParentVHD)) {
16721722
$osInfo = Get-WindowsImage -ImagePath $createdVm.OSDiskPath -Index 1
1673-
16741723
$properties.'vm.os.installationType' = $osInfo.InstallationType
16751724
$properties.'vm.os.editionId' = $osInfo.EditionId
16761725
$properties.'vm.os.version' = $osInfo.Version

Scripts/LabConfig.ps1

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ $LabConfig=@{AllowedVLANs="1-10,711-719" ; DomainAdminName='LabAdmin'; AdminPass
236236
VMSet (Mandatory for Shared and Replica configuration)
237237
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.
238238
239-
ParentVHD (Mandatory)
239+
ParentVHD (Optional. If Null, new VHDx will be created)
240240
'Win2016Core_G2.vhdx' - Windows Server 2016 Core
241241
'Win2016NanoHV_G2.vhdx' - Windows Server 2016 Nano with these packages: DSC, Failover Cluster, Guest, Storage, SCVMM
242242
'Win2016NanoHV_G2.vhdx' - Windows Server 2016 Nano with these packages: DSC, Failover Cluster, Guest, Storage, SCVMM, Compute, SCVMM Compute
@@ -346,6 +346,17 @@ $LabConfig=@{AllowedVLANs="1-10,711-719" ; DomainAdminName='LabAdmin'; AdminPass
346346
Example VMVersion="10.0"
347347
default versions - Windows Server 2022 = 10.0, Widnows Server 2025 = 12.0
348348
https://learn.microsoft.com/en-us/windows-server/virtualization/hyper-v/deploy/Upgrade-virtual-machine-version-in-Hyper-V-on-Windows-or-Windows-Server
349+
350+
#AttachISO (optional)
351+
Example AttachISO="WindowsServer2025.iso"
352+
it will mount iso specified from Parent Disks
353+
354+
#SecureBoot (optional)
355+
Example Secureboot="Linux"
356+
enables/disables secure boot for VM
357+
possible values: windows,linux,disabled
358+
Default: windows for windows machines, disabled for linux VMs
359+
349360
#>
350361
#endregion
351362

0 commit comments

Comments
 (0)