########################################################## #Create Hyper-V Lab using PowerShell # # # # https://www.pesk.co.uk/docs/CreateYourHyper-VLab # # # #Copyright 2016-2022, Solomon Evans # ########################################################## Clear $Cred1 = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList 'Administrator',('Pa55w.rd' | ConvertTo-SecureString -AsPlainText -Force) $Cred2 = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList 'ADATUM\Administrator',('Pa55w.rd' | ConvertTo-SecureString -AsPlainText -Force) $wshell = New-Object -ComObject Wscript.Shell $msgBoxIn = [System.Windows.MessageBox]::Show('This script will try to create the Hyper-V lab environment for you. Do you want to continue?','CRHVL v1.2 (c)2022 PSIUK - All Rights Reserved.','YesNoCancel','Question') | Out-Null switch ($msgBoxIn) { 'Yes' { $os = Get-WmiObject -Class Win32_OperatingSystem | Select -Property Caption # $os2 = systeminfo /fo csv | ConvertFrom-Csv | select 'OS Name', 'OS Configuration' | Format-List If ($os.Caption -Like "*Windows Server*") { Install-WindowsFeature "Hyper-V-Tools","Hyper-V-PowerShell" -ErrorAction SilentlyContinue } If ($os.Caption -Like "*Windows 1*") { Enable-WindowsOptionalFeature -Online -FeatureName "Microsoft-Hyper-V" –All -ErrorAction SilentlyContinue } [System.Reflection.Assembly]::LoadWithPartialName('Microsoft.VisualBasic') | Out-Null $drv = [Microsoft.VisualBasic.Interaction]::InputBox('Enter the drive letter to create the labs into. For example, to install into the D drive, enter D:\','Drive selection.') New-Item -ItemType Directory -Path $drv -Name ISOs $msgBoxDownloadISOs = [System.Windows.MessageBox]::Show('Do you want to download the Windows Server (2019 or 2022) Datacenter and Windows 10 (or 11) Enterprise Evaluation ISOs?','Download Server and Client ISOs?','YesNo','Question') switch ($msgBoxDownloadISOs) { 'Yes' { $download = [Microsoft.VisualBasic.Interaction]::InputBox('Enter 10 or 11 for Windows 10 or 11 Enterprise; 19 or 22 for Windows Server 2019 or 2022 Datacenter Evaluation ISOs.','Which ISO would you like to download?','11','750','200') | Out-Null If ($download -eq '10') { Invoke-WebRequest -UseBasicParsing -URI https://software-download.microsoft.com/download/sg/444969d5-f34g-4e03-ac9d-1f9786c69161/19044.1288.211006-0501.21h2_release_svc_refresh_CLIENTENTERPRISEEVAL_OEMRET_x64FRE_en-gb.iso -Method GET -OutFile C:\ISOs\Win10EntEval.iso } ElseIf ($download -eq '11') { Invoke-WebRequest -UseBasicParsing -URI https://software-download.microsoft.com/download/sg/888969d5-f34g-4e03-ac9d-1f9786c66749/22000.318.211104-1236.co_release_svc_refresh_CLIENTENTERPRISEEVAL_OEMRET_x64FRE_en-gb.iso -Method GET -OutFile C:\ISOs\Win11EntEval.iso } ElseIf ($download -eq '19') { Invoke-WebRequest -UseBasicParsing -URI https://software-download.microsoft.com/download/pr/17763.737.190906-2324.rs5_release_svc_refresh_SERVER_EVAL_x64FRE_en-us_1.iso -Method GET -OutFile C:\ISOs\WS2019Eval.iso } ElseIf ($download -eq '22') { Invoke-WebRequest -UseBasicParsing -URI https://software-download.microsoft.com/download/sg/20348.169.210806-2348.fe_release_svc_refresh_SERVER_EVAL_x64FRE_en-us.iso -Method GET -OutFile C:\ISOs\WS2022Eval.iso } } 'No' { $wshell.Popup("Make sure you have the ISOs in the right locations or the creation of the labs will fail stupendously...You lose a life. Wait 10 seconds...",10,"Download Aborted! Continuing...",0x30) | Out-Null } } $wshell.Popup("Download of the ISOs is now complete. We shall now continue creating the lab in 10 seconds...",10,"Download Complete! Continuing...",0x40) | Out-Null Clear $wshell.Popup("Creating Virtual Switches...",2,"New-VMSwitch...",0x40) | Out-Null New-VMSwitch -SwitchName 'Private Network' -SwitchType Private New-VMSwitch -SwitchName 'Private Network 2' -SwitchType Private $vmsw1 = Get-VMSwitch -Name 'Private Network' | Select -ExpandProperty Name | Out-Null $vmsw2 = Get-VMSwitch -Name 'Private Network 2' | Select -ExpandProperty Name | Out-Null If ($vmsw1 -eq 'Private Network') { $wshell.Popup("Virtual Switch '$vmsw1' created successfully.",2,"-Private Network- switch...",0x40) | Out-Null } Else { $wshell.Popup("The 'Private Network' virtual Switch creation failed. Make sure you create this switch manually in Hyper-V Manager otherwise the lab creation will fail.",0,"-Private Network- switch...",16) | Out-Null } If ($vmsw2 -eq 'Private Network 2') { $wshell.Popup("Virtual Switch '$vmsw2' created successfully.",2,"-Private Network 2- switch...",0x40) | Out-Null } Else { $wshell.Popup("The 'Private Network 2' virtual Switch creation failed. Make sure you create this switch manually in Hyper-V Manager otherwise the lab creation will fail.",0,"-Private Network 2- switch...",16) | Out-Null } Clear $wshell.Popup("Creating Virtual Machines LON-DC1, LON-SVR1 and LON-CL1...",4,"New-VM...",0x40) $ISOPath = Get-Item -Path 'C:\ISOs\WS*.ISO' | Select -Property Name $ISOPath2 = Get-Item -Path 'C:\ISOs\Win1*.ISO' | Select -Property Name Set-Location C:\ New-Item -ItemType Directory -Name 'HVVM' -ErrorAction SilentlyContinue $Path = "C:\HVVM\" New-VM -Name 'LON-DC1' -Path ($Path+'LON-DC1') -MemoryStartupBytes 2GB -NewVHDPath ($Path + 'LON-DC1\Virtual Disks\LON-DC1.vhdx') -NewVHDSizeBytes 30GB -SwitchName 'Private Network' -Generation 1 New-VM -Name 'LON-SVR1' -Path ($Path + 'LON-SVR1') -MemoryStartupBytes 2GB -NewVHDPath ($Path + 'LON-SVR1\Virtual Disks\LON-SVR1.vhdx') -NewVHDSizeBytes 30GB -SwitchName 'Private Network' -Generation 1 New-VM -Name 'LON-CL1' -Path ($Path + 'LON-CL1') -MemoryStartupBytes 2GB -NewVHDPath ($Path + 'LON-CL1\Virtual Disks\LON-CL1.vhdx') -NewVHDSizeBytes 20GB -SwitchName 'Private Network' -Generation 1 $msgBoxAddVMs = [System.Windows.MessageBox]::Show('Would you like to create the additional Virtual Machines LON-SVR2, LON-SVR3, LON-SVR4 and LON-CA1?','Create additional VMs','YesNo','Question') If ($msgBoxAddVMs -eq "Yes") { $wshell.Popup("Doing it...",2,"Doing it...",0x40) New-VM -Name LON-SVR2 -Path $Path + "LON-SVR2" -MemoryStartupBytes 2GB -NewVHDPath $Path + “LON-SVR2\Virtual Disks\LON-SVR2.vhdx” -NewVHDSizeBytes 30GB -SwitchName “Private Network” -Generation 1 New-VM -Name LON-SVR3 -Path $Path + "LON-SVR3" -MemoryStartupBytes 1GB -NewVHDPath $Path + “LON-SVR3\Virtual Disks\LON-SVR3.vhdx” -NewVHDSizeBytes 30GB -SwitchName “Private Network 2” -Generation 1 New-VM -Name LON-SVR4 -Path $Path + "LON-SVR4" -MemoryStartupBytes 1GB -NewVHDPath $Path + “LON-SVR4\Virtual Disks\LON-SVR4.vhdx” -NewVHDSizeBytes 30GB -SwitchName “Private Network 2” -Generation 1 New-VM -Name LON-CA1 -Path $Path + "LON-CA1" -MemoryStartupBytes 1GB -NewVHDPath $Path + “LON-CA1\Virtual Disks\LON-CA1.vhdx” -NewVHDSizeBytes 30GB -SwitchName “Private Network” -Generation 1 } $wshell.Popup("Creating second hard drives for LON-DC1, LON-SVR1 and LON-SVR2.",3,"Additional drives.",0x40) New-VHD -Path $Path + “LON-DC1\Virtual Disks\LON-DC1-AllFiles.vhdx" -SizeBytes 10GB -Fixed New-VHD -Path $Path + “LON-SVR1\Virtual Disks\LON-SVR1-AllFiles.vhdx" -SizeBytes 10GB -Fixed New-VHD -Path $Path + “LON-SVR2\Virtual Disks\LON-SVR2-AllFiles.vhdx" -SizeBytes 10GB -Fixed $wshell.Popup("Configuring Processors and adding cores.",3,"Adding processor cores.",0x40) Invoke-Command -VMName LON-DC1,LON-SVR1,LON-SVR2,LON-CL1 -Credential $Cred1 -ScriptBlock {Set-VMProcessor -Count 4} -ErrorAction SilentlyContinue Invoke-Command -VMName LON-SVR3,LON-SVR4,LON-CA1 -Credential $Cred1 -ScriptBlock {Set-VMProcessor -Count 2} -ErrorAction SilentlyContinue $wshell.Popup("Configure Virtual Machines to start from the installation DVD (.iso)",3,"Adding DVD.",0x40) Invoke-Command -VMName LON-DC1,LON-SVR1,LON-SVR2,LON-SVR3,LON-SVR4,LON-CA1 -Credential $Cred1 -ScriptBlock {Add-VMDVDDrive -Path "$ISOPath2.FullName"} -ErrorAction SilentlyContinue Invoke-Command -VMName LON-CL1 -Credential $Cred1 -ScriptBlock {Add-VMDVDDrive -VMName LON-CL1 -Path "$ISOPath.FullName"} -ErrorAction SilentlyContinue Clear $wshell.Popup("Start Virtual Machines and install Windows.",2,"Start VMs.",0x40) Start-VM -Name 'LON-DC1','LON-SVR1','LON-CL1' While((Get-VM -Name 'LON-DC1','LON-SVR1','LON-CL1').HeartBeat -ne 'OkApplicationsHealthy') { Start-Sleep -Seconds 1 $wshell.Popup("Waiting for Virtual Machines to stabilise.",2,"Starting DC1, SVR1 and CL1 VMs.",0x40) | Out-Null } $wshell.Popup("Changing the computer names.",3,"Change computer names.",0x40) Invoke-Command -VMName LON-DC1 -Credential $Cred1 -ScriptBlock {Rename-Computer -NewName LON-DC1 -Force -Restart} Invoke-Command -VMName LON-SVR1 -Credential $Cred1 -ScriptBlock {Rename-Computer -NewName LON-SVR1 -Force -Restart} Invoke-Command -VMName LON-CL1 -Credential $Cred1 -ScriptBlock {Rename-Computer -NewName LON-CL1 -Force -Restart} $wshell.Popup("Setting IP address infomation.",1,"Setting IP address for LON-DC1",0x40) Clear-Variable -Name IfIndex $IfIndex = Invoke-Command -VMName LON-DC1 -Credential $Cred1 -ScriptBlock {Get-NetAdapter | Select -ExpandProperty IfIndex} | Select -First 1 Invoke-Command -VMName LON-DC1 -Credential $Cred1 -ScriptBlock {Set-NetIPAddress -InterfaceIndex $ifindex -IPAddress 172.16.0.10 -PrefixLength 24} $wshell.Popup("Setting IP address infomation.",1,"Setting IP address for LON-SVR1",0x40) Clear-Variable -Name IfIndex $IfIndex = Invoke-Command -VMName LON-SVR1 -Credential $Cred1 -ScriptBlock {Get-NetAdapter | Select -ExpandProperty IfIndex} | Select -First 1 Invoke-Command -VMName LON-SVR1 -Credential $Cred1 -ScriptBlock {Set-NetIPAddress -InterfaceIndex $ifindex -IPAddress 172.16.0.21 -PrefixLength 24} $wshell.Popup("Setting IP address infomation.",1,"Setting IP address for LON-CL1",0x40) Clear-Variable -Name IfIndex $IfIndex = Invoke-Command -VMName LON-CL1 -Credential $Cred1 -ScriptBlock {Get-NetAdapter | Select -ExpandProperty IfIndex} | Select -First 1 Invoke-Command -VMName LON-CL1 -Credential $Cred1 -ScriptBlock {Set-NetIPAddress -InterfaceIndex $ifindex -IPAddress 172.16.0.50 -PrefixLength 24} $SVR2 = [System.IO.File]::Exists("$Path\LON-SVR2.vhdx") If ($SVR2 -eq $True) { $wshell.Popup("Starting LON-SVR2.",1,"Start LON-SVR2",0x40) Start-VM -Name LON-SVR2 While((Get-VM -Name 'LON-SVR2').HeartBeat -ne 'OkApplicationsHealthy') { Start-Sleep -Seconds 1 $wshell.Popup("Waiting for LON-SVR2 to stabilise.",2,"Starting SVR2 VM.",0x40) | Out-Null } Invoke-Command -VMName LON-SVR2 -Credential $Cred1 -ScriptBlock{Rename-Computer -NewName LON-SVR2 -LocalCredential Administrator -Force -Restart} $wshell.Popup("Setting IP address infomation.",1,"Setting IP address for LON-SVR2",0x40) Clear-Variable -Name IfIndex $IfIndex = Invoke-Command -VMName LON-SVR2 -Credential $Cred1 -ScriptBlock {Get-NetAdapter | Select -ExpandProperty IfIndex} | Select -First 1 Invoke-Command -VMName LON-SVR2 -Credential $Cred1 -ScriptBlock {Set-NetIPAddress -InterfaceIndex $ifindex -IPAddress 172.16.0.22 -PrefixLength 24} } $SVR3 = [System.IO.File]::Exists("$Path\LON-SVR3.vhdx") If ($SVR3 -eq $True) { $wshell.Popup("Starting LON-SVR3.",1,"Start LON-SVR3",0x40) Start-VM -Name LON-SVR3 While((Get-VM -Name 'LON-SVR3').HeartBeat -ne 'OkApplicationsHealthy') { Start-Sleep -Seconds 1 $wshell.Popup("Waiting for LON-SVR3 to stabilise.",2,"Starting SVR3 VM.",0x40) | Out-Null } Invoke-Command -VMName LON-SVR3 -Credential $Cred1 -ScriptBlock{Rename-Computer -NewName LON-SVR3 -LocalCredential Administrator -Force -Restart} $wshell.Popup("Setting IP address infomation.",1,"Setting IP address for LON-SVR3",0x40) Clear-Variable -Name IfIndex $IfIndex = Invoke-Command -VMName LON-SVR3 -Credential $Cred1 -ScriptBlock {Get-NetAdapter | Select -ExpandProperty IfIndex} | Select -First 1 Invoke-Command -VMName LON-SVR3 -Credential $Cred1 -ScriptBlock {Set-NetIPAddress -InterfaceIndex $ifindex -IPAddress 172.16.0.23 -PrefixLength 24} } $SVR4 = [System.IO.File]::Exists("$Path\LON-SVR4.vhdx") If ($SVR4 -eq $True) { $wshell.Popup("Starting LON-SVR4.",1,"Start LON-SVR4",0x40) Start-VM -Name LON-SVR4 While((Get-VM -Name 'LON-SVR4').HeartBeat -ne 'OkApplicationsHealthy') { Start-Sleep -Seconds 1 $wshell.Popup("Waiting for LON-SVR4 to stabilise.",2,"Starting SVR4 VM.",0x40) | Out-Null } Invoke-Command -VMName LON-SVR4 -Credential $Cred1 -ScriptBlock{Rename-Computer -NewName LON-SVR4 -LocalCredential Administrator -Force -Restart} $wshell.Popup("Setting IP address infomation.",1,"Setting IP address for LON-SVR4",0x40) Clear-Variable -Name IfIndex $IfIndex = Invoke-Command -VMName LON-SVR4 -Credential $Cred1 -ScriptBlock {Get-NetAdapter | Select -ExpandProperty IfIndex} | Select -First 1 Invoke-Command -VMName LON-SVR4 -Credential $Cred1 -ScriptBlock {Set-NetIPAddress -InterfaceIndex $ifindex -IPAddress 172.16.0.24 -PrefixLength 24} } $CA1 = [System.IO.File]::Exists("$Path\LON-CA1.vhdx") If ($CA1 -eq $True) { $wshell.Popup("Starting LON-CA1.",1,"Start LON-CA1",0x40) Start-VM -Name LON-CA1 While((Get-VM -Name 'LON-CA1').HeartBeat -ne 'OkApplicationsHealthy') { Start-Sleep -Seconds 1 $wshell.Popup("Waiting for LON-CA1 to stabilise.",2,"Starting CA1 VM.",0x40) | Out-Null } Invoke-Command -VMName LON-CA1 -Credential $Cred1 -ScriptBlock{Rename-Computer -NewName LON-CA1 -LocalCredential Administrator -Force -Restart} $wshell.Popup("Setting IP address infomation.",1,"Setting IP address for LON-CA1",0x40) Clear-Variable -Name IfIndex $IfIndex = Invoke-Command -VMName LON-CA1 -Credential $Cred1 -ScriptBlock {Get-NetAdapter | Select -ExpandProperty IfIndex} | Select -First 1 Invoke-Command -VMName LON-CA1 -Credential $Cred1 -ScriptBlock {Set-NetIPAddress -InterfaceIndex $ifindex -IPAddress 172.16.0.25 -PrefixLength 24} } Clear $wshell.Popup("Now about to set up the Adatum Forest and Adatum.com domain.",3,"Creating Forest and Domain",0x40) Invoke-Command -VMName 'LON-DC1' -Credential $Cred1 -ScriptBlock {Install-WindowsFeature AD-Domain-Services,DNS,DHCP -IncludeAllSubFeature -IncludeManagementTools} Invoke-Command -VMName 'LON-DC1' -Credential $Cred1 -ScriptBlock {Install-Module ADDSDeployment } Invoke-Command -VMName 'LON-DC1' -Credential $Cred1 -ScriptBlock {Install-ADDSForest -CreateDNSDelegation:$false -DatabasePath C:\Windows\NTDS -DomainMode Win2012R2 -DomainName Adatum.com -DomainNetbiosName ADATUM -ForestMode Win2012R2 -LogPath C:\Windows\NTDS -NoRebootOnCompletion:$false -SysvolPath C:\Windows\SYSVOL -SafeModeAdministratorPassword (ConvertTo-SecureString "Pa55w.rd" -AsPlainText -Force) -SkipPreChecks -Force:$true $wshell.Popup("Creating optional DNS Resource records",3,"DNS Resource Records",0x40) Invoke-Command -VMName 'LON-DC1' -Credential $Cred2 -ScriptBlock {Add-DNSServerResourceRecordA -Name adfs -ZoneName adatum.com -IPv4Address 172.16.0.10 -TimeToLive 01:00:00} Invoke-Command -VMName 'LON-DC1' -Credential $Cred2 -ScriptBlock {Add-DNSServerResourceRecordCNAME -Name crl -HostNameAlias lon-dc1.adatum.com -ZoneName adatum.com} Invoke-Command -VMName 'LON-DC1' -Credential $Cred2 -ScriptBlock {Add-DNSServerResourceRecordCNAME -Name EnterpriseRegistration -HostNameAlias lon-svr1.adatum.com -ZoneName adatum.com} $wshell.Popup("Authorizing the DHCP Server, creating the DHCP Scope and setting DHCP Scope Options.",3,"DHCP Configuration",0x40) Invoke-Command -VMName 'LON-DC1' -Credential $Cred2 -ScriptBlock {Add-DHCPServerInDC} Invoke-Command -VMName 'LON-DC1' -Credential $Cred2 -ScriptBlock {Add-DHCPServerv4Scope -StartRange 172.16.0.160 -EndRange 172.16.0.190 -SubnetMask 255.255.0.0 -Name Adatum -Type Both} Invoke-Command -VMName 'LON-DC1' -Credential $Cred2 -ScriptBlock {Set-DHCPServerv4OptionValue -ScopeID 172.16.0.0 -DNSDomain Adatum.com -DNSServer 172.16.0.10 -Router 172.16.0.1} $wshell.Popup("Configuration Complete. The server will restart in 30 seconds...",30,"Configuration complete.",0x30) Invoke-Command -VMName 'LON-DC1' -Credential $Cred2 -ScriptBlock {Restart-Computer -Force} While((Get-VM -Name 'LON-DC1').HeartBeat -ne 'OkApplicationsHealthy') { Start-Sleep -Seconds 2 $wshell.Popup("Waiting for LON-DC1 to fully stabilise. Please wait... This may take a while.",2,"Starting DC1 VM.",0x40) | Out-Null } $Health = (Get-VM -Name 'LON-DC1').HeartBeat If ($Health -eq 'OkApplicationsHealthy') { $wshell.Popup("LON-DC1 is now up and fully stabilised. Now continuing to add computers to the domain. Once all the VMs are restarted the lab will be complete.",6,"DC1 VM Status Healthy!",0x40) | Out-Null } Add-Computer -Computername 'LON-SVR1','LON-CL1' -DomainName Adatum.com –Credential $Cred2 -Restart –Force Add-Computer -Computername 'LON-SVR2','LON-SVR3','LON-SVR4' -DomainName Adatum.com –Credential $Cred2 -Restart –Force Clear [System.Windows.MessageBox]::Show('Enjoy your newly minted lab. Review any errors and correct them before starting any activities. Use the form on the ''Contact Us'' section of the website for any feedback.','Lab creation complete.') | Out-Null 'No' { Exit } 'Cancel' { Exit } } }