[CmdletBinding()] param ( [Parameter(Mandatory = $false)] [object] $WebhookData ) If ($WebhookData) { If ($WebhookData.RequestHeader.ITD -eq '6EE8DaFMbswirY38qPfewwT82G9Bdiv8p3SKEdisX88mfnFfiredy6uti4nJprecedegJkTGBHDV3alpineePkM5grainsE56xp3JmuffWjwL') { Write-Verbose "Header has required data" } Else { Write-Error "Header missing required data" exit; } $InputParams = (ConvertFrom-Json -InputObject $WebhookData.RequestBody) $FQDN = 'itdzmbuild01.nd.gov' # Get Credentials $SPCred = Get-AutomationPSCredential -Name 'SharePoint IaaS ReadWrite' $ADCred = Get-AutomationPSCredential -Name 'ITD IaaS Automation' $PSCred = Get-AutomationPSCredential -Name 'ITD IaaS Automation' $IBCred = New-Object System.Management.Automation.PSCredential ($ADCred.UserName.split('\')[1], $ADCred.Password) $VMCred = Get-AutomationPSCredential -Name 'VMware Auto' Clear-DnsClientCache $SharePointList = Get-ITDVMwareSharePointVMGuestListTst -Credential $SPCred $SPItem = $SharePointList | Where-Object Title -eq $FQDN $HostName = $FQDN.split('.')[0] # Infoblox [Net.IpAddress]$NetworkId = $SPItem.CIDR.split('/')[0] [Net.IPAddress]$IpAddress = (Resolve-DnsName -Name $FQDN -ErrorAction SilentlyContinue).IPAddress $SubnetMaskInt = $SPItem.Cidr.split('/')[1] $Int64 = ([convert]::ToInt64(('1' * $SubnetMaskInt + '0' * (32 - $SubnetMaskInt)), 2)) [Net.IPAddress]$SubnetMask = '{0}.{1}.{2}.{3}' -f ([math]::Truncate($Int64 / 16777216)).ToString(), ([math]::Truncate(($Int64 % 16777216) / 65536)).ToString(), ([math]::Truncate(($Int64 % 65536) / 256)).ToString(), ([math]::Truncate($Int64 % 256)).ToString() $IPSplit = $SPItem.Cidr.Split('.') [Net.IPAddress]$DefaultGateway = ($IPSplit[0] + '.' + $IPSplit[1] + '.' + $IPSplit[2] + '.' + (($SPItem.Cidr.split('/')[0].split('.')[-1] -as [int]) + 1) ) If (($IpAddress.Address -band $SubnetMask.Address) -eq ($NetworkId.Address -band $SubnetMask.Address)) { Write-Verbose "IP Address and CIDR Block match" } Else { Write-Error "DNS record already exists, and does not match CIDR Block" -ErrorAction Stop } If ($IpAddress) { If (($IpAddress.Address -band $SubnetMask.Address) -eq ($NetworkId.Address -band $SubnetMask.Address)) { Write-Warning "DNS record already exists, CIDR Block match" } else { Write-Error "DNS record already exists, and does not match CIDR Block" Break } } Else { New-ITDIbDNSRecordNextAvailableIP -HostName $SPItem.Title -CIDR $SPItem.CIDR -Credential $IBCred } If ((Test-NetConnection -ComputerName $IpAddress.IPAddressToString).PingSucceeded) { Write-Error "IP Address already in use." -ErrorAction Stop } # Active Directory If ($PSEdition -eq 'Core') { Import-Module ActiveDirectory -UseWindowsPowerShell } $Filter = ("{Name -eq '" + $SPItem.AppName + "'}") $OUAppName = Get-ADOrganizationalUnit -SearchBase "OU=Windows,OU=SERVERS,ou=COMPUTERS,ou=ITD,dc=nd,dc=gov" -Filter $Filter If (!($OUAppName)) { $OUAppName = Get-ADOrganizationalUnit -SearchBase "OU=Windows,OU=SERVERS,ou=COMPUTERS,ou=ITD,dc=nd,dc=gov" -Filter { Name -eq 'All-General' } } $ExistingADComputer = Get-ADComputer -Identity $Hostname -ErrorAction SilentlyContinue If ($ExistingADComputer) { If ($ExistingADComputer.DistinguishedName -like ("*" + $SPItem.AppName + "*") -or $ExistingADComputer.DistinguishedName -like "*All-General*") { Write-Warning "AD object already exists, OU path does match" } Else { Write-Error "AD object already exists, OU path mismatch" Exit Exit } } else { switch ($SPItem.Environment) { 'Test' { $OUAppNameEnv = Get-ADOrganizationalUnit -SearchBase $OUAppName.DistinguishedName -Filter * | Where-Object Name -like "*Test*" } 'Production' { $OUAppNameEnv = Get-ADOrganizationalUnit -SearchBase $OUAppName.DistinguishedName -Filter * | Where-Object Name -like "*Prod*" } } If ($OUAppNameEnv) { $OUFinal = $OUAppNameEnv } Else { $OUFinal = $OUAppName } New-ADComputer -Name $HostName.ToUpper() -Path $OUFinal -Credential $ADCred -Description ($SPItem | Select-Object AppName, Environment | ConvertTo-Json) } # Passwordstate $LocalCredential = New-ITDPassword -Title $FQDN -Username itdadmin -Description 'Local Administrator' -PasswordList CSRC -Credential $PrvCred $GuestCredentialBB = New-Object System.Management.Automation.PSCredential ('Administrator', ($LocalCredential.Password | ConvertTo-SecureString -AsPlainText -Force)) $GuestCredentialAB = New-Object System.Management.Automation.PSCredential ($LocalCredential.UserName, ($LocalCredential.Password | ConvertTo-SecureString -AsPlainText -Force)) # VMware If (Get-VM -Name $FQDN -ErrorAction SilentlyContinue) { Write-Error "Virtual machine with the name $FQDN already exists." -ErrorAction Stop Stop Stop } switch ($SPItem.Cluster) { "WINDOWS1" { $ViServer = 'itdvmvc1.nd.gov' $VirtualSwitch = Get-VDSwitch -Name "dvSwitch-PDC-Data" $DiskStorageFormat = 'Thin' } "WINDOWS2" { $ViServer = 'itdvmvc2.nd.gov' $VirtualSwitch = Get-VDSwitch -Name "dvSwitch-SDC-Data" $DiskStorageFormat = 'Thin' } "SQL1" { $ViServer = 'itdvmvc1.nd.gov' $VirtualSwitch = Get-VDSwitch -Name "dvSwitch-PDC-Data" $DiskStorageFormat = 'EagerZeroedThick' } "SQL2" { $ViServer = 'itdvmvc2.nd.gov' $VirtualSwitch = Get-VDSwitch -Name "dvSwitch-SDC-Data" $DiskStorageFormat = 'EagerZeroedThick' } "WAS1" { $ViServer = 'itdvmvc1.nd.gov' $VirtualSwitch = Get-VDSwitch -Name "dvSwitch-PDC-Data" $DiskStorageFormat = 'Thin' } "WAS2" { $ViServer = 'itdvmvc2.nd.gov' $VirtualSwitch = Get-VDSwitch -Name "dvSwitch-SDC-Data" $DiskStorageFormat = 'Thin' } "PS1" { $ViServer = 'itdvmvc1.nd.gov' $VirtualSwitch = Get-VDSwitch -Name "dvSwitch-PDC-PS1-Data" $DiskStorageFormat = 'Thin' } "PS2" { $ViServer = 'itdvmvc2.nd.gov' $VirtualSwitch = Get-VDSwitch -Name "dvSwitch-SDC-PS2-Data" $DiskStorageFormat = 'Thin' } "TEL1" { $ViServer = 'itdvmvc1.nd.gov' $VirtualSwitch = Get-VDSwitch -Name "dvSwitch-PDC-TEL1-Data" $DiskStorageFormat = 'Thin' } "TEL2" { $ViServer = 'itdvmvc2.nd.gov' $VirtualSwitch = Get-VDSwitch -Name "dvSwitch-PDC-TEL2-Data" $DiskStorageFormat = 'Thin' } "DCN1" { $ViServer = 'itdvmvc1.nd.gov' $VirtualSwitch = Get-VDSwitch -Name "dvSwitch-DCN-vMotion-Data" $DiskStorageFormat = 'Thin' } } # verify disk will fit $DiskTotal = $SPItem.Disk1 + $SPItem.Disk2 + $SPItem.Disk3 $DatastoreCluster = Get-DatastoreCluster | Where-Object Name -like ("*" + $SPItem.Cluster + "*") $ClusterDatastoreWithHighestFreeSpaceGB = ($DatastoreCluster | Get-Datastore | Sort-Object FreeSpaceGB -Descending | Select -First 1) If ($ClusterDatastoreWithHighestFreeSpaceGB.FreeSpaceGB -gt $DiskTotal) { Write-Verbose ("VM DiskTotal " + $DiskTotal + "GB, will fit on " + $ClusterDatastoreWithHighestFreeSpaceGB.Name + " (" + [math]::round($ClusterDatastoreWithHighestFreeSpaceGB.FreeSpaceGB, 0) + "GB free)") } else { Write-Verbose ("VM DiskTotal " + $DiskTotal + "GB, will not fit on " + $ClusterDatastoreWithHighestFreeSpaceGB.Name + " (" + [math]::round($ClusterDatastoreWithHighestFreeSpaceGB.FreeSpaceGB, 0) + "GB free)") Write-Error ("New VM " + $FQDN + " needs " + $DiskTotal + "GB of free space on a single datastore in the " + $DatastoreCluster.Name + " datastore cluster.") -ErrorAction Stop } $FolderLocation = Get-Folder -Server $ViServer -Name "_New Builds" switch ($SPItem.OS) { "Windows Server 2012R2 Standard (64-Bit)" { $Template = "Windows Server 2012R2 Standard" } "Windows Server 2016 Standard (64-Bit)" { $Template = "Windows Server 2016 Standard" } "Windows Server 2019 Standard (64-Bit)" { $Template = "Windows Server 2019 Standard" } Default {} } $PortGroupsAvailable = Get-VDPortGroup -Server $ViServer -VDSwitch $VirtualSwitch $PortGroup = $PortGroupsAvailable | Where-Object Name -eq ("dvPG_" + $SPItem.Vlan_Id + "_" + $NetworkId.IPAddressToString + "_" + $SubnetMaskInt) If (!($PortGroup)) { Write-Error "Virtual port group not found" -ErrorAction Stop Stop } $NewOSSpecName = ("AutoBuild-$Hostname-" + (Get-Date -UFormat "%Y%m%d%H%M%S")) Get-OSCustomizationSpec -Name "Windows (Auto)" -Server $ViServer | New-OSCustomizationSpec -Name $NewOSSpecName -Type Persistent Get-OSCustomizationSpec -Name $NewOSSpecName | ` Set-OSCustomizationSpec ` -NamingScheme fixed ` -NamingPrefix $Hostname ` -AdminPassword $GuestCredentialBB.GetNetworkCredential().Password ` Get-OSCustomizationSpec -Name $NewOSSpecName | ` Get-OSCustomizationNicMapping | ` Set-OSCustomizationNicMapping ` -IpMode UseStaticIP ` -IpAddress $IpAddress.IPAddressToString ` -SubnetMask $SubnetMask.IPAddressToString ` -DefaultGateway $DefaultGateway.IPAddressToString ` -Dns "10.2.7.40", "10.2.5.40" $OSSpec = Get-OSCustomizationSpec -Name $NewOSSpecName $NewVMParams = @{ Name = $FQDN; ResourcePool = $SPItem.Cluster; Datastore = $DatastoreCluster; DiskStorageFormat = $DiskStorageFormat; Template = $Template; Location = $FolderLocation; OSCustomizationSpec = $OSSpec; } New-VM @NewVMParams #If (!($BuildError)) { $VM = Get-VM -Name $FQDN # Ensure CPU/Memory Hot-Add Enabled $vmView = $VM | Get-View $vmConfigSpec = New-Object VMware.Vim.VirtualMachineConfigSpec $vmOptValCPU = New-Object VMware.Vim.OptionValue $vmOptValMem = New-Object VMware.Vim.OptionValue $vmOptValCPU.Key = "vcpu.hotadd" $vmOptValMem.Key = "mem.hotadd" $vmOptValCPU.Value = "true" $vmOptValMem.Value = "true" $vmConfigSpec.ExtraConfig += $vmOptValCPU $vmConfigSpec.ExtraConfig += $vmOptValMem $vmView.ReconfigVM($vmConfigSpec) # Set CPU, Memory, Network $VM | Set-VM -NumCpu $SPItem.Processors -MemoryGB $SPItem.RAM -Confirm:$false $VM | Get-NetworkAdapter | Set-NetworkAdapter -Portgroup $PortGroup -Confirm:$false # Power On VM $VM | Start-VM # Wait for Customization to finish $VMStarted = $false $VMCustomizationStarted = $false $VMCustomizationResult = $false While ($VMStarted -eq $false -or $VMCustomizationStarted -eq $false -or $VMCustomizationResult -eq $false) { Write-Warning ("Customization wait loop started " + (Get-Date)) Write-Verbose "Current Status:" Write-Verbose ("VMStarted: " + $VMStarted) Write-Verbose ("VMCustomizationStarted: " + $VMCustomizationStarted) Write-Verbose ("VMCustomizationResult: " + $VMCustomizationResult) $GetVIEventRuntime = Measure-Command -Expression { $VMEvents = Get-VIEvent -Entity $VM -Server $ViServer -ErrorAction SilentlyContinue } Write-Verbose ("Get-VIEvent last run time: " + $GetVIEventRuntime.TotalSeconds + " seconds") If ($VMStarted -eq $false) { If (@($VMEvents | Where-Object { $_.GetType().Name -eq "VMStartingEvent" })) { $VMStarted = $true Write-Warning "[$FQDN]:Virtual machine started" } } If ($VMCustomizationStarted -eq $false) { If (@($VMEvents | Where-Object { $_.GetType().Name -eq "CustomizationStartedEvent" })) { $VMCustomizationStarted = $true Write-Warning "[$FQDN]:Virtual machine customization started" } } If ($VMCustomizationResult -eq $false) { If (@($VMEvents | Where-Object { $_.GetType().Name -eq "CustomizationFailed" })) { $VMCustomizationResult = $true Write-Error "[$FQDN]:Virtual machine customization failed" Exit Exit } If (@($VMEvents | Where-Object { $_.GetType().Name -eq "CustomizationSucceeded" })) { $VMCustomizationResult = $true Write-Warning "[$FQDN]:Virtual machine customization completed" } } } # Delete OS Customization Spec Get-OSCustomizationSpec -Name $NewOSSpecName | Remove-OSCustomizationSpec -Confirm:$false # Add/Expand Disks $VMDisk = $VM | Get-HardDisk $VMDisk1 = $VMDisk | Where-Object Name -EQ "Hard disk 1" $VMDisk2 = $VMDisk | Where-Object Name -EQ "Hard disk 2" $VMDisk3 = $VMDisk | Where-Object Name -EQ "Hard disk 3" If ($SPItem.Disk1) { If (!$VMDisk1) { $VM | New-HardDisk ` -CapacityGB $SPItem.Disk1 ` -StorageFormat Thin ` -DiskType Flat ` -Persistence Persistent } $VMDisk1 = $VMDisk | Where-Object Name -EQ "Hard disk 1" If ($VMDisk1.CapacityGB -lt $SPItem.Disk1) { Set-HardDisk -HardDisk $VMDisk1 -CapacityGB $SPItem.Disk1 -Confirm:$false } } If ($SPItem.Disk2) { If (!$VMDisk2) { $VM | New-HardDisk ` -CapacityGB $SPItem.Disk2 ` -StorageFormat Thin ` -DiskType Flat ` -Persistence Persistent } $VMDisk2 = $VMDisk | Where-Object Name -EQ "Hard disk 2" If ($VMDisk2.CapacityGB -lt $SPItem.Disk2) { Set-HardDisk -HardDisk $VMDisk2 -CapacityGB $SPItem.Disk2 -Confirm:$false } } If ($SPItem.Disk3) { If (!$VMDisk3) { $VM | New-HardDisk ` -CapacityGB $SPItem.Disk3 ` -StorageFormat Thin ` -DiskType Flat ` -Persistence Persistent } $VMDisk3 = $VMDisk | Where-Object Name -EQ "Hard disk 3" If ($VMDisk3.CapacityGB -lt $SPItem.Disk3) { Set-HardDisk -HardDisk $VMDisk3 -CapacityGB $SPItem.Disk3 -Confirm:$false } } # Run Guest OS code $InvokeVMScriptFunc = { } $VM | Invoke-VMScript -GuestCredential $GuestCredentialBB -ScriptText $InvokeVMScriptFunc #} } Else { Write-Error "Runbook must be started from webhook" }