Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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