529 lines
22 KiB
PowerShell
529 lines
22 KiB
PowerShell
<#
|
|
### step 1
|
|
gather specs
|
|
provision virtual machine on hypervisor
|
|
|
|
final result:
|
|
cpu configured, with hot-add
|
|
memory configured, with hot-add
|
|
disks 1, 2, and 3 attached with correct sizing
|
|
network connected
|
|
virtual machine powered on
|
|
|
|
update SCTASK Step 1 completed
|
|
|
|
### step 2 - customize Windows Guest OS
|
|
wait for SCTASK Step 1 completed message
|
|
configure
|
|
time zone, mount points, page file, etc
|
|
|
|
update SCTASK Step 2 completed
|
|
|
|
### step 3 - administration
|
|
wait for SCTASK Step 2 completed message
|
|
domain join
|
|
nd.gov at a minimum
|
|
install sccm
|
|
regardless if domain joined
|
|
|
|
update SCTASK Step 3 completed
|
|
|
|
### step 4 - validation
|
|
|
|
|
|
confirm all agents are installed
|
|
disks are present and formatted
|
|
|
|
#>
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
A short one-line action-based description, e.g. 'Tests if a function is valid'
|
|
.DESCRIPTION
|
|
A longer description of the function, its purpose, common use cases, etc.
|
|
.NOTES
|
|
Information or caveats about the function e.g. 'This function is not supported in Linux'
|
|
.LINK
|
|
Specify a URI to a help page, this will show when Get-Help -Online is used.
|
|
.EXAMPLE
|
|
$NewITDWindowsVmVMwareParams = @{
|
|
ComputerName = 'itdzmtest300.nd.gov';
|
|
CPU = 2;
|
|
MemoryGB = 8;
|
|
DiskOsGB = 50;
|
|
DiskSwapGB = 9;
|
|
DiskDataGB = 20;
|
|
Subnet = '10.11.12.0/23';
|
|
OS = 'Windows Server 2022 Datacenter';
|
|
Environment = "Test";
|
|
Datacenter = "Bismarck";
|
|
AppName = "ITD-POC-zmeier";
|
|
StartupPriority = 4;
|
|
LicensingRestrictions = "No Licensing Restrictions";
|
|
Credential = $PrvCred;
|
|
}
|
|
|
|
New-ITDWindowsVmVMware @NewITDWindowsVmVMwareParams
|
|
#>
|
|
|
|
function New-ITDWindowsVmVMwareStep1 {
|
|
[CmdletBinding()]
|
|
param (
|
|
[string]
|
|
$FQDN,
|
|
|
|
[int]
|
|
$CPU,
|
|
|
|
[int]
|
|
$MemoryGB,
|
|
|
|
[int]
|
|
$DiskOsGB,
|
|
|
|
[int]
|
|
$DiskSwapGB,
|
|
|
|
[int]
|
|
$DiskDataGB,
|
|
|
|
[string]
|
|
$Subnet,
|
|
|
|
[string]
|
|
$OS,
|
|
|
|
[string]
|
|
$VMEnvironment,
|
|
|
|
[string]
|
|
$Datacenter,
|
|
|
|
[string]
|
|
$AppName,
|
|
|
|
[int]
|
|
$StartupPriority,
|
|
|
|
[string]
|
|
$LicensingRestrictions,
|
|
|
|
[PSCredential]
|
|
$Credential
|
|
|
|
)
|
|
|
|
begin {
|
|
|
|
}
|
|
|
|
process {
|
|
$FQDN = $FQDN.ToLower()
|
|
$HostName = $FQDN.split('.')[0]
|
|
|
|
If ($VMEnvironment -eq "Development") {
|
|
$VMEnvironment = "Test"
|
|
}
|
|
|
|
Write-Verbose -Message "Prepare Credentials and Connections"
|
|
$RadiusCred = New-Object System.Management.Automation.PSCredential($Credential.username.split('\')[1], ($Credential.Password))
|
|
|
|
Write-Verbose -Message "Infoblox: Find DNS pre-existing record, or create one"
|
|
Write-Verbose -Message "FQDN: $FQDN" -Verbose
|
|
Write-Verbose -Message "Hostname: $Hostname" -Verbose
|
|
|
|
Clear-DnsClientCache
|
|
$InfobloxVlanMetadata = Get-ITDIbVlan -CIDR $Subnet -Credential $RadiusCred
|
|
$Cidr = ($InfobloxVlanMetadata.AssignedTo | Out-String).TrimEnd()
|
|
[Net.IpAddress]$NetworkId = $Cidr.split('/')[0]
|
|
#######
|
|
####### Remove 10.10.10.10 references when DNS sync is fixed
|
|
#######
|
|
[Net.IPAddress]$IpAddress = (Resolve-DnsName -Name $FQDN -ErrorAction SilentlyContinue -Server 10.10.10.10).IPAddress
|
|
$SubnetMaskInt = $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 = $Subnet.Split('.')
|
|
[Net.IPAddress]$DefaultGateway = ($IPSplit[0] + '.' + $IPSplit[1] + '.' + $IPSplit[2] + '.' + (($CIDR.split('/')[0].split('.')[-1] -as [int]) + 1) )
|
|
|
|
If ($null -ne $IpAddress) {
|
|
If (($IpAddress.Address -band $SubnetMask.Address) -eq ($NetworkId.Address -band $SubnetMask.Address)) {
|
|
Write-Verbose -Message "DNS record already exists, CIDR Block match"
|
|
}
|
|
Else {
|
|
Write-Error "DNS record already exists, but does not match CIDR Block"
|
|
Break
|
|
}
|
|
}
|
|
Else {
|
|
Write-Verbose -Message "Pre-existing IP address not found, creating new DNS record."
|
|
try {
|
|
New-ITDIbDNSRecordNextAvailableIP -Hostname $FQDN -CIDR $CIDR -Credential $RadiusCred
|
|
Start-Sleep -Seconds 5
|
|
Write-Verbose -Message ("FQDN is " + $FQDN)
|
|
}
|
|
catch {
|
|
|
|
}
|
|
|
|
|
|
|
|
#######
|
|
####### Review this code after DNS problems resolved - 2024/09/24 zm
|
|
#######
|
|
####### [Net.IPAddress]$IpAddress = (Resolve-DnsName -Name $FQDN -ErrorAction Stop -Server 10.10.10.10).IPAddress
|
|
|
|
[Net.IPAddress]$IpAddress = (Get-ITDIbDNSRecord -Hostname $FQDN -Credential $RadiusCred).IPv4Address
|
|
|
|
If ((Test-NetConnection -ComputerName $IpAddress.IPAddressToString).PingSucceeded) {
|
|
Write-Error "IP Address already in use." -ErrorAction Stop
|
|
}
|
|
}
|
|
|
|
Write-Verbose -Message "Passwordstate: If local administrator password does not exist in vault, create it."
|
|
If ($FQDN -like "itdcnd*") {
|
|
$PasswordStateList = "Peoplesoft Share PW"
|
|
}
|
|
Else {
|
|
$PasswordStateList = "CSRC"
|
|
}
|
|
|
|
$GuestVMLocalCredential = Get-ITDPassword -Title $FQDN -UserName itdadmin -Credential $Credential
|
|
If ($null -eq $GuestVMLocalCredential) {
|
|
Write-Verbose -Message "Passwordstate: Local admin password record does not exist, creating new credentials"
|
|
$GuestVMLocalCredential = New-ITDPassword -Title $FQDN -UserName itdadmin -Description 'Local Administrator' -PasswordList $PasswordStateList -Credential $Credential
|
|
}
|
|
Else {
|
|
Write-Verbose -Message "Passwordstate: Local admin password record already exists, use those credentials"
|
|
}
|
|
$GuestCredentialAB = New-Object System.Management.Automation.PSCredential ('itdadmin', ($GuestVMLocalCredential.GetNetworkCredential().Password | ConvertTo-SecureString -AsPlainText -Force))
|
|
$GuestCredentialBB = New-Object System.Management.Automation.PSCredential ('Administrator', ($GuestVMLocalCredential.GetNetworkCredential().Password | ConvertTo-SecureString -AsPlainText -Force))
|
|
|
|
Write-Verbose -Message "Decide VMware Cluster and Licensing"
|
|
switch ($LicensingRestrictions) {
|
|
"No Licensing Restrictions" { $ClusterRoot = "WINDOWS" }
|
|
"Microsoft SharePoint Server" { $ClusterRoot = "WINDOWS" }
|
|
"Microsoft SharePoint Server (Academic)" { $ClusterRoot = "WINDOWS" }
|
|
"Microsoft SQL Developer" { $ClusterRoot = "WINDOWS" }
|
|
"Microsoft SQL MSDN" { $ClusterRoot = "WINDOWS" }
|
|
"Microsoft SQL Standard" { $ClusterRoot = "WINDOWS" }
|
|
"Microsoft SQL Standard (Academic)" { $ClusterRoot = "WINDOWS" }
|
|
"Microsoft SQL Standard (Vendor Provided)" { $ClusterRoot = "WINDOWS" }
|
|
"Microsoft SQL Enterprise" { $ClusterRoot = "SQLe" }
|
|
"Microsoft SQL Enterprise (Academic)" { $ClusterRoot = "SQLa" }
|
|
"IBM Websphere" { $ClusterRoot = "WAS" }
|
|
"Powerschool" { $ClusterRoot = "PS" }
|
|
"Pexip" { $ClusterRoot = "TEL" }
|
|
}
|
|
|
|
Write-Verbose -Message "Decide Datacenter"
|
|
switch ($Datacenter) {
|
|
"Bismarck" { $ClusterInt = 1 }
|
|
"Mandan" { $ClusterInt = 2 }
|
|
}
|
|
|
|
$Cluster = $ClusterRoot + $ClusterInt
|
|
Write-Verbose -Message "VMware Cluster is $Cluster, gathering metadata for $Cluster"
|
|
|
|
switch ($Cluster) {
|
|
"WINDOWS1" {
|
|
$ViServer = 'itdvmvc1.nd.gov'
|
|
$ComputeCluster = Get-Cluster WINDOWS1
|
|
$VirtualSwitch = Get-VDSwitch -Name "dvSwitch-PDC-Data-Server"
|
|
|
|
If ($LicensingRestrictions -like "*SQL*") {
|
|
$DatastoreCluster = Get-DatastoreCluster -Name "WINDOWS1_FS92_SQL"
|
|
$DiskStorageFormat = 'EagerZeroedThick'
|
|
}
|
|
Else {
|
|
$DatastoreCluster = Get-DatastoreCluster -Name "WINDOWS1_FS92_Gen"
|
|
$DiskStorageFormat = 'Thin'
|
|
}
|
|
}
|
|
"WINDOWS2" {
|
|
$ViServer = 'itdvmvc2.nd.gov'
|
|
$ComputeCluster = Get-Cluster WINDOWS2
|
|
$VirtualSwitch = Get-VDSwitch -Name "dvSwitch-SDC-Data-Server"
|
|
$DiskStorageFormat = 'Thin'
|
|
If ($LicensingRestrictions -like "*SQL*") {
|
|
$DatastoreCluster = Get-DatastoreCluster -Name "WINDOWS2_FS92_SQL"
|
|
$DiskStorageFormat = 'EagerZeroedThick'
|
|
}
|
|
Else {
|
|
$DatastoreCluster = Get-DatastoreCluster -Name "WINDOWS2_FS92_Gen"
|
|
$DiskStorageFormat = 'Thin'
|
|
}
|
|
}
|
|
"SQLa1" {
|
|
$ViServer = 'itdvmvc1.nd.gov'
|
|
$ComputeCluster = Get-Cluster SQLa1
|
|
$VirtualSwitch = Get-VDSwitch -Name "dvSwitch-PDC-Data-Server"
|
|
$DiskStorageFormat = 'EagerZeroedThick'
|
|
$DatastoreCluster = Get-DatastoreCluster -Name "SQLa1_FS92_Gen"
|
|
}
|
|
"SQLa2" {
|
|
$ViServer = 'itdvmvc2.nd.gov'
|
|
$ComputeCluster = Get-Cluster SQLa2
|
|
$VirtualSwitch = Get-VDSwitch -Name "dvSwitch-SDC-Data-Server"
|
|
$DiskStorageFormat = 'EagerZeroedThick'
|
|
$DatastoreCluster = Get-DatastoreCluster -Name "SQLa2_FS92_Gen"
|
|
}
|
|
"SQLe1" {
|
|
$ViServer = 'itdvmvc1.nd.gov'
|
|
$ComputeCluster = Get-Cluster SQLe1
|
|
$VirtualSwitch = Get-VDSwitch -Name "dvSwitch-PDC-Data-Server"
|
|
$DiskStorageFormat = 'EagerZeroedThick'
|
|
$DatastoreCluster = Get-DatastoreCluster -Name "SQLe1_FS92_Gen"
|
|
}
|
|
"SQLe2" {
|
|
$ViServer = 'itdvmvc2.nd.gov'
|
|
$ComputeCluster = Get-Cluster SQLe2
|
|
$VirtualSwitch = Get-VDSwitch -Name "dvSwitch-SDC-Data-Server"
|
|
$DiskStorageFormat = 'EagerZeroedThick'
|
|
$DatastoreCluster = Get-DatastoreCluster -Name "SQLe2_FS92_Gen"
|
|
}
|
|
"WAS1" {
|
|
$ViServer = 'itdvmvc1.nd.gov'
|
|
$ComputeCluster = Get-Cluster WAS1
|
|
$VirtualSwitch = Get-VDSwitch -Name "dvSwitch-PDC-Data-Server"
|
|
$DiskStorageFormat = 'Thin'
|
|
$DatastoreCluster = Get-DatastoreCluster -Name "WAS1_FS92_Gen"
|
|
}
|
|
"WAS2" {
|
|
$ViServer = 'itdvmvc2.nd.gov'
|
|
$ComputeCluster = Get-Cluster WAS2
|
|
$VirtualSwitch = Get-VDSwitch -Name "dvSwitch-SDC-Data-Server"
|
|
$DiskStorageFormat = 'Thin'
|
|
$DatastoreCluster = Get-DatastoreCluster -Name "WAS2_FS92_Gen"
|
|
}
|
|
"PS1" {
|
|
$ViServer = 'itdvmvc1.nd.gov'
|
|
$ComputeCluster = Get-Cluster PS1
|
|
$VirtualSwitch = Get-VDSwitch -Name "dvSwitch-PDC-Data-Server"
|
|
$DiskStorageFormat = 'Thin'
|
|
$DatastoreCluster = Get-DatastoreCluster -Name "PS1_FS92_Gen"
|
|
}
|
|
"PS2" {
|
|
$ViServer = 'itdvmvc2.nd.gov'
|
|
$ComputeCluster = Get-Cluster PS2
|
|
$VirtualSwitch = Get-VDSwitch -Name "dvSwitch-SDC-Data-Server"
|
|
$DiskStorageFormat = 'Thin'
|
|
$DatastoreCluster = Get-DatastoreCluster -Name "PS2_FS92_Gen"
|
|
}
|
|
"TEL1" {
|
|
$ViServer = 'itdvmvc1.nd.gov'
|
|
$ComputeCluster = Get-Cluster TEL1
|
|
$VirtualSwitch = Get-VDSwitch -Name "dvSwitch-PDC-TEL1-Data"
|
|
$DiskStorageFormat = 'Thin'
|
|
$DatastoreCluster = Get-DatastoreCluster -Name "TEL1_FS92_Gen"
|
|
}
|
|
"TEL2" {
|
|
$ViServer = 'itdvmvc2.nd.gov'
|
|
$ComputeCluster = Get-Cluster TEL2
|
|
$VirtualSwitch = Get-VDSwitch -Name "dvSwitch-PDC-TEL2-Data"
|
|
$DiskStorageFormat = 'Thin'
|
|
$DatastoreCluster = Get-DatastoreCluster -Name "TEL2_FS92_Gen"
|
|
}
|
|
Default {
|
|
Write-Error "Cluster not found" -ErrorAction Stop
|
|
}
|
|
}
|
|
|
|
Write-Verbose -Message "Validate entered disk sizes"
|
|
Write-Verbose -Message "DiskOsGB is $DiskOsGB. Validating its not a stupid number." -Verbose
|
|
switch ($DiskOsGB) {
|
|
{ $_ -lt 50 } {
|
|
Write-Verbose -Message "DiskOsGB is 0 or below. Since an OS Disk is required, defaulting to 50GB" -Verbose
|
|
$DiskOsGB = 50
|
|
}
|
|
}
|
|
|
|
Write-Verbose -Message "DiskSwapGB is $DiskSwapGB. Validating its not a stupid number." -Verbose
|
|
switch ($DiskSwapGB) {
|
|
{ $_ -le 0 } {
|
|
Write-Verbose -Message "DiskSwapGB is zero or below. Since an Swap Disk is required, defaulting to `$Memory + 1GB." -Verbose
|
|
$DiskSwapGB = ($MemoryGB + 1)
|
|
}
|
|
}
|
|
|
|
Write-Verbose -Message "DiskDataGB is $DiskDataGB. Validating its not a stupid number." -Verbose
|
|
switch ($DiskDataGB) {
|
|
{ $_ -le 0 } {
|
|
Write-Verbose -Message "DiskDataGB is 0. Since an Data Disk is optional, data disk will not be created." -Verbose
|
|
$DiskDataGB = 0
|
|
}
|
|
{ $_ -gt 500 } {
|
|
Write-Verbose -Message "DiskDataGB is 500GB or more. DiskDataGB will be set to the maximum of 500GB." -Verbose
|
|
$DiskDataGB = 500
|
|
}
|
|
}
|
|
|
|
Write-Verbose -Message "Determine Datastore / Datastore Cluster"
|
|
$DiskTotal = $DiskOsGB + $DiskSwapGB + $DiskDataGB
|
|
If ($DatastoreCluster) {
|
|
}
|
|
Else {
|
|
$DatastoreCluster = Get-DatastoreCluster | Where-Object Name -Like ("*" + $ComputeCluster + "*")
|
|
}
|
|
$ClusterDatastoreWithHighestFreeSpaceGB = ($DatastoreCluster | Get-Datastore | Sort-Object FreeSpaceGB -Descending | Select-Object -First 1)
|
|
If ($ClusterDatastoreWithHighestFreeSpaceGB.FreeSpaceGB -gt $DiskTotal) {
|
|
Write-Warning ("VM DiskTotal " + $DiskTotal + "GB, will fit on " + $ClusterDatastoreWithHighestFreeSpaceGB.Name + " (" + [math]::round($ClusterDatastoreWithHighestFreeSpaceGB.FreeSpaceGB, 0) + "GB free)")
|
|
}
|
|
else {
|
|
Write-Warning ("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 = $ComputeCluster | Get-Datacenter | Get-Folder -Name "_New Builds"
|
|
|
|
Write-Verbose -Message "Determine VMware VM Template for OS: $OS"
|
|
switch ($OS) {
|
|
"Windows Server 2012R2 Standard" { $Template = "Windows Server 2012R2 Standard" }
|
|
"Windows Server 2016 Standard" { $Template = "Windows Server 2016 Standard" }
|
|
"Windows Server 2019" { $Template = "Windows Server 2019 Standard 1809.19" }
|
|
"Windows Server 2019 Standard" { $Template = "Windows Server 2019 Standard 1809.19" }
|
|
"Windows Server 2019 Datacenter" { $Template = "Windows Server 2019 Standard 1809.19" }
|
|
"Windows Server 2022" { $Template = "Windows Server 2022 Standard 2108.21" }
|
|
"Windows Server 2022 Datacenter" { $Template = "Windows Server 2022 Standard 2108.21" }
|
|
"Windows Server 2025" { $Template = "Windows Server 2025 Standard 24H2.6" }
|
|
Default { Write-Error "Invalid template option: $OS" -ErrorAction Stop }
|
|
}
|
|
|
|
Write-Verbose -Message "Determine VMware Port Group"
|
|
$PortGroupsAvailable = Get-VDPortgroup -Server $ViServer -VDSwitch $VirtualSwitch
|
|
$PortGroup = $PortGroupsAvailable | Where-Object Name -Like ("dvPG_*" + $NetworkId.IPAddressToString + "_" + $SubnetMaskInt)
|
|
If (!($PortGroup)) {
|
|
Write-Error "Virtual port group not found" -ErrorAction Stop
|
|
Stop
|
|
}
|
|
If (@($PortGroup).count -gt 1) {
|
|
Write-Error "Multiple port groups found" -ErrorAction Stop
|
|
Stop
|
|
}
|
|
|
|
Write-Verbose -Message "Configure Guest OS Customization Spec"
|
|
$NewOSSpecName = ("AutoBuild-$Hostname-" + (Get-Date -UFormat "%Y%m%d%H%M%S"))
|
|
Write-Warning "NewOSSpecName = $NewOSSpecName"
|
|
|
|
Get-OSCustomizationSpec -Name 'Windows (Auto)' -Server $ViServer | New-OSCustomizationSpec -Name $NewOSSpecName -Type Persistent -Server $ViServer
|
|
|
|
Get-OSCustomizationSpec -Name $NewOSSpecName -Server $ViServer | `
|
|
Set-OSCustomizationSpec `
|
|
-NamingScheme fixed `
|
|
-NamingPrefix $Hostname `
|
|
-AdminPassword $GuestCredentialBB.GetNetworkCredential().Password
|
|
|
|
Get-OSCustomizationSpec -Name $NewOSSpecName -Server $ViServer | `
|
|
Get-OSCustomizationNicMapping | `
|
|
Set-OSCustomizationNicMapping `
|
|
-IpMode UseStaticIP `
|
|
-IpAddress $IpAddress.IPAddressToString `
|
|
-SubnetMask $SubnetMask.IPAddressToString `
|
|
-DefaultGateway $DefaultGateway.IPAddressToString `
|
|
-Dns "10.2.7.40", "10.10.10.10"
|
|
|
|
$OSSpec = Get-OSCustomizationSpec -Name $NewOSSpecName -Server $ViServer
|
|
|
|
Set-Location C:\Temp
|
|
$NewVMParams = @{
|
|
Name = $FQDN;
|
|
ResourcePool = $ComputeCluster.Name;
|
|
Datastore = $DatastoreCluster;
|
|
DiskStorageFormat = $DiskStorageFormat;
|
|
Location = $FolderLocation;
|
|
# Removed when using Content Library
|
|
#Template = $Template;
|
|
#OSCustomizationSpec = $OSSpec
|
|
}
|
|
|
|
Get-ContentLibraryItem -Name $Template -Server $ViServer | New-VM @NewVMParams
|
|
$VM = Get-VM -Name $FQDN
|
|
$VM | Set-VM -OSCustomizationSpec $OSSpec -Confirm:$false
|
|
|
|
Write-Verbose -Message "Set vCenter Tags on VM"
|
|
New-TagAssignment -Entity (Get-VM $FQDN -Server $VIServer) -Tag (Get-Tag -Server $ViServer -Category AppName -Name $AppName) -Server $VIServer
|
|
New-TagAssignment -Entity (Get-VM $FQDN -Server $VIServer) -Tag (Get-Tag -Server $ViServer -Category DTAP -Name $VMEnvironment) -Server $VIServer
|
|
New-TagAssignment -Entity (Get-VM $FQDN -Server $VIServer) -Tag (Get-Tag -Server $ViServer -Category LicensingRestrictions -Name $LicensingRestrictions) -Server $VIServer
|
|
New-TagAssignment -Entity (Get-VM $FQDN -Server $VIServer) -Tag (Get-Tag -Server $ViServer -Category StartupPriority -Name $StartupPriority) -Server $VIServer
|
|
|
|
|
|
# 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 $CPU -MemoryGB $MemoryGB -Confirm:$false
|
|
$VM | Get-NetworkAdapter | Set-NetworkAdapter -Portgroup $PortGroup -Confirm:$false
|
|
|
|
|
|
|
|
Write-Verbose -Message "Config and Update 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"
|
|
|
|
Write-Verbose -Message "Update Disk 1"
|
|
$VMDisk1 = $VM | Get-HardDisk | Where-Object Name -EQ "Hard disk 1"
|
|
If ($VMDisk1.CapacityGB -lt $DiskOsGB) {
|
|
Set-HardDisk -HardDisk $VMDisk1 -CapacityGB $DiskOsGB -Confirm:$false
|
|
}
|
|
|
|
Write-Verbose -Message "Config Disk 2"
|
|
If (!$VMDisk2) {
|
|
$VM | New-HardDisk `
|
|
-CapacityGB ($MemoryGB + 1) `
|
|
-StorageFormat Thin `
|
|
-DiskType Flat `
|
|
-Persistence Persistent
|
|
}
|
|
$VMDisk2 = $VM | Get-HardDisk | Where-Object Name -EQ "Hard disk 2"
|
|
If ($VMDisk2.CapacityGB -lt $DiskSwapGB) {
|
|
Set-HardDisk -HardDisk $VMDisk2 -CapacityGB $DiskSwapGB -Confirm:$false
|
|
}
|
|
|
|
Write-Verbose -Message "Config Disk 3"
|
|
If ($DiskDataGB -gt 0) {
|
|
Write-Verbose -Message "$DiskDataGB greater than zero"
|
|
If (!$VMDisk3) {
|
|
$VM | New-HardDisk `
|
|
-CapacityGB $DiskDataGB `
|
|
-StorageFormat Thin `
|
|
-DiskType Flat `
|
|
-Persistence Persistent
|
|
}
|
|
$VMDisk3 = $VM | Get-HardDisk | Where-Object Name -EQ "Hard disk 3"
|
|
If ($VMDisk3.CapacityGB -lt $DiskDataGB) {
|
|
Set-HardDisk -HardDisk $VMDisk3 -CapacityGB $DiskDataGB -Confirm:$false
|
|
}
|
|
}
|
|
|
|
Write-Verbose -Message "Set VMware Tools Upgrade Policy to UpgradeAtPowerCycle"
|
|
$VMView = $VM | Get-View
|
|
$vmConfigSpec = New-Object VMware.Vim.VirtualMachineConfigSpec
|
|
$vmConfigSpec.Tools = New-Object VMware.Vim.ToolsConfigInfo
|
|
$vmConfigSpec.Tools.ToolsUpgradePolicy = "UpgradeAtPowerCycle"
|
|
$VMView.ReconfigVM($vmConfigSpec)
|
|
|
|
Write-Verbose -Message "Power On VM"
|
|
$VM | Start-VM
|
|
|
|
Write-Verbose -Message "[$FQDN]:Step 1 End"
|
|
}
|
|
|
|
end {
|
|
|
|
}
|
|
} |