Skip to content

Instantly share code, notes, and snippets.

@machv
Last active April 21, 2022 07:54
Show Gist options
  • Save machv/1a5c6fa3f28b884412034c6554718971 to your computer and use it in GitHub Desktop.
Save machv/1a5c6fa3f28b884412034c6554718971 to your computer and use it in GitHub Desktop.
vm ps
$vmRootDir = "D:\Virtual Machines"
$LibraryPath = "C:\Data\Parent Disks"
$vSwitchName = "VM"
$MountDir = "C:\Data\MountDir" #cannot be CSV
$ServerName = ""hv01
$VMs = @()
$VMs += @{
VMName = "VM01"
MemoryStartupBytes = 512MB
DynamicMemory = $true
NumberOfCPUs = 2
AdminPassword = "LS1setup!"
OUPath = "OU=Servers,DC=contoso,DC=com"
ImageName = "Win2019_G2.vhdx"
}
#region Provision
foreach ($VM in $VMs){
#Copy VHD to destination
Invoke-Command -ComputerName $ServerName -ScriptBlock {
New-Item -Path "$using:vmRootDir\$($using:VM.VMName)\Virtual Hard Disks\" -ItemType Directory -Force
Copy-Item -Path "$using:LibraryPath\$($using:VM.ImageName)" -Destination "$using:vmRootDir\$($using:VM.VMName)\Virtual Hard Disks\$($using:VM.VMName).vhdx"
}
#Create Answer File
$djointemp=New-TemporaryFile
& djoin.exe /provision /domain $env:USERDOMAIN /machine $VM.VMName /savefile $djointemp.fullname /machineou $VM.Oupath
#extract blob blob from temp file
$Blob=get-content $djointemp
$Blob=$blob.Substring(0,$blob.Length-1)
#remove temp file
$djointemp | Remove-Item
#Generate Unattend file
$unattend = @"
<?xml version='1.0' encoding='utf-8'?>
<unattend xmlns="urn:schemas-microsoft-com:unattend" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<settings pass="offlineServicing">
<component name="Microsoft-Windows-UnattendedJoin" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
<OfflineIdentification>
<Provisioning>
<AccountData>$Blob</AccountData>
</Provisioning>
</OfflineIdentification>
</component>
</settings>
<settings pass="oobeSystem">
<component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
<UserAccounts>
<AdministratorPassword>
<Value>$($VM.AdminPassword)</Value>
<PlainText>true</PlainText>
</AdministratorPassword>
</UserAccounts>
<OOBE>
<HideEULAPage>true</HideEULAPage>
<SkipMachineOOBE>true</SkipMachineOOBE>
<SkipUserOOBE>true</SkipUserOOBE>
</OOBE>
</component>
</settings>
<settings pass="specialize">
<component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
<RegisteredOwner>Owner</RegisteredOwner>
<RegisteredOrganization>Organization</RegisteredOrganization>
</component>
<component name="Microsoft-Windows-Deployment" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
</component>
</settings>
</unattend>
"@
#Mount VHD and Apply answer file
Invoke-Command -ComputerName $ServerName -ScriptBlock {
New-Item -Path "$using:Mountdir" -ItemType Directory -Force
Mount-WindowsImage -Path "$using:Mountdir" -ImagePath "$using:CSVPath\$($using:VM.VMName)\Virtual Hard Disks\$($using:VM.VMName).vhdx" -Index 1
New-item -type directory "$using:Mountdir\Windows\Panther"
Set-Content -Value $using:unattend -Path "$using:Mountdir\Windows\Panther\Unattend.xml"
Use-WindowsUnattend -Path "$using:Mountdir" -UnattendPath "$using:Mountdir\Windows\Panther\Unattend.xml"
Dismount-WindowsImage -Path "$using:Mountdir" -Save
Remove-Item -Path "$using:Mountdir"
}
#Create VM
Invoke-Command -ComputerName ($ClusterNodes | Get-Random) -ScriptBlock {
Function Set-VMNetworkConfiguration {
#source:http://www.ravichaganti.com/blog/?p=2766 with some changes
#example use: Get-VMNetworkAdapter -VMName Demo-VM-1 -Name iSCSINet | Set-VMNetworkConfiguration -IPAddress 192.168.100.1 00 -Subnet 255.255.0.0 -DNSServer 192.168.100.101 -DefaultGateway 192.168.100.1
[CmdletBinding()]
Param (
[Parameter(Mandatory=$true,
Position=1,
ParameterSetName='DHCP',
ValueFromPipeline=$true)]
[Parameter(Mandatory=$true,
Position=0,
ParameterSetName='Static',
ValueFromPipeline=$true)]
[Microsoft.HyperV.PowerShell.VMNetworkAdapter]$NetworkAdapter,
[Parameter(Mandatory=$true,
Position=1,
ParameterSetName='Static')]
[String[]]$IPAddress=@(),
[Parameter(Mandatory=$false,
Position=2,
ParameterSetName='Static')]
[String[]]$Subnet=@(),
[Parameter(Mandatory=$false,
Position=3,
ParameterSetName='Static')]
[String[]]$DefaultGateway = @(),
[Parameter(Mandatory=$false,
Position=4,
ParameterSetName='Static')]
[String[]]$DNSServer = @(),
[Parameter(Mandatory=$false,
Position=0,
ParameterSetName='DHCP')]
[Switch]$Dhcp
)
$VM = Get-WmiObject -Namespace 'root\virtualization\v2' -Class 'Msvm_ComputerSystem' | Where-Object { $_.ElementName -eq $NetworkAdapter.VMName }
$VMSettings = $vm.GetRelated('Msvm_VirtualSystemSettingData') | Where-Object { $_.VirtualSystemType -eq 'Microsoft:Hyper-V:System:Realized' }
$VMNetAdapters = $VMSettings.GetRelated('Msvm_SyntheticEthernetPortSettingData')
$NetworkSettings = @()
foreach ($NetAdapter in $VMNetAdapters) {
if ($NetAdapter.elementname -eq $NetworkAdapter.name) {
$NetworkSettings = $NetworkSettings + $NetAdapter.GetRelated("Msvm_GuestNetworkAdapterConfiguration")
}
}
$NetworkSettings[0].IPAddresses = $IPAddress
$NetworkSettings[0].Subnets = $Subnet
$NetworkSettings[0].DefaultGateways = $DefaultGateway
$NetworkSettings[0].DNSServers = $DNSServer
$NetworkSettings[0].ProtocolIFType = 4096
if ($dhcp) {
$NetworkSettings[0].DHCPEnabled = $true
} else {
$NetworkSettings[0].DHCPEnabled = $false
}
$Service = Get-WmiObject -Class "Msvm_VirtualSystemManagementService" -Namespace "root\virtualization\v2"
$setIP = $Service.SetGuestNetworkAdapterConfiguration($VM, $NetworkSettings[0].GetText(1))
if ($setip.ReturnValue -eq 4096) {
$job=[WMI]$setip.job
while ($job.JobState -eq 3 -or $job.JobState -eq 4) {
start-sleep 1
$job=[WMI]$setip.job
}
if ($job.JobState -eq 7) {
Write-Host "`t Success"
}else {
$job.GetError()
}
}elseif($setip.ReturnValue -eq 0) {
Write-Host "`t Success"
}
}
$VM=$using:vm
$VMTemp=New-VM -Name $VM.VMName -MemoryStartupBytes $VM.MemoryStartupBytes -Generation 2 -Path "$Using:CSVPath" -VHDPath "$Using:CSVPath\$($VM.VMName)\Virtual Hard Disks\$($VM.VMName).vhdx" -SwitchName $Using:vSwitchName
$VMTemp | Set-VMProcessor -Count $VM.NumberOfCPUs
if ($VM.DynamicMemory){
$VMTemp | Set-VM -DynamicMemory
}
if ($VM.IPAddress){
$VMTemp | Get-VMNetworkAdapter | Set-VMNetworkConfiguration -IPAddress $VM.IPAddress -Subnet $VM.Subnet -DefaultGateway $VM.DefaultGateway -DNSServer $VM.DNSServer
}
if ($VM.VLAN){
$VMTemp | Get-VMNetworkAdapter | Set-VMNetworkAdapterVlan -VlanId $VM.VLAN -Access
}
$VMTemp | Start-VM
}
}
#endregion
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment