This commit is contained in:
Zack Meier
2026-04-15 15:45:50 -05:00
commit 1d304511b8
613 changed files with 140998 additions and 0 deletions
@@ -0,0 +1,109 @@
#$AllVMHosts = Get-Cluster AVAYA*,LINUX*,ODM*,ORACLE*,SQL*,SQL2-DR,TEL*,WAS*,WINDOWS* | Get-VMHost | Sort-object Name
$VMhostNames = @"
itdbisvm-av05.nd.gov
"@
$VMhostNames = ConvertTo-Array -MultiLineString $VMhostNames
$AllVMHosts = Get-VMHost $VMhostNames
$AllVMHosts = Get-Cluster WINDOWS2 | Get-VMHost
ForEach ($VMHost in $AllVMHosts) {
Clear-DnsClientCache
$VirtualSwitch = $null
$CohesityDNS = $null
$IpAddress = $null
$VMHostDNS = $VMHost.Name
$VirtualSwitch = $VMHost | Get-VirtualSwitch -Name "*Data*"
$PortGroup = $VirtualSwitch | Get-VirtualPortGroup | Where-Object Name -Like "dvPG_3534_10.2.170.0_24*"
$CohesityDNS = $VMHostDNS.split('.')[0] + 'co.nd.gov'
# does vmhost already have vmkernel in Cohesity range?
If ($VMHost | Get-VMHostNetworkAdapter -VMKernel | Where-Object IP -Like "10.2.170.*") {
Write-Warning "VMKernel already exists on $VMHostDNS"
}
Else {
$IpAddress = (Resolve-DnsName -Name $CohesityDNS).IpAddress
If ($IpAddress) {
New-VMHostNetworkAdapter -VMHost $VMHost `
-PortGroup $PortGroup `
-VirtualSwitch $VirtualSwitch `
-IP $IpAddress `
-SubnetMask 255.255.255.0 `
-ManagementTrafficEnabled $true `
-VMotionEnabled $false `
-VsanTrafficEnabled $false
}
else {
Write-Error "IpAddress null for $VMHostDNS"
}
}
}
<# Create DNS records
$AllVMHosts = @"
itdvmbismgmt01.nd.gov
itdvmbismgmt02.nd.gov
itdvmbisvapp01.nd.gov
itdvmbisvapp02.nd.gov
itdvmbiswas04.nd.gov
itdvmbiswas05.nd.gov
itdvmbisora02.nd.gov
itdvmbisora03.nd.gov
itdvmbissql09.nd.gov
itdvmbissql10.nd.gov
itdvmbissql11.nd.gov
itdvmbiswin07.nd.gov
itdvmbiswin08.nd.gov
itdvmbiswin09.nd.gov
itdvmbiswin10.nd.gov
itdvmbiswin11.nd.gov
itdvmbiswin12.nd.gov
itdvmbiswin13.nd.gov
itdvmbissql07.nd.gov
itdvmbissql08.nd.gov
itdvmmdnmgmt01.nd.gov
itdvmmdnvapp01.nd.gov
itdvmmdnsql07.nd.gov
itdvmmdnsql08.nd.gov
itdvmmdnsql09.nd.gov
itdvmmdnlin05.nd.gov
itdvmmdnora02.nd.gov
itdvmmdnmgmt02.nd.gov
itdvmmdnvapp02.nd.gov
itdvmmdnsql10.nd.gov
itdvmmdnsql11.nd.gov
itdvmmdnsql12.nd.gov
itdvmmdnlin03.nd.gov
itdvmmdnlin04.nd.gov
"@
$AllVMHosts = ConvertTo-Array -MultiLineString $AllVMHosts
#Get-Cluster WINDOWS2,WAS2,SQL2,SQL2-DR,TEL2,PS2,ORACLE2,ODM2,LINUX2,AVAYA2 | Get-VMHost
ForEach($VMHost in $AllVMhosts){
$CohesityDNS = $VMHost.split('.')[0] + 'co.nd.gov'
New-ITDIbDNSRecordNextAvailableIP -CIDR 10.2.170.0/24 -Credential $IbCred -Hostname $CohesityDNS
#$CohesityDNS
}
#>
# static routes
$AllVMHosts = Get-VMHost -Name itdmdnvm-av03.nd.gov
$result = [System.Collections.ArrayList]@()
ForEach ($VMHost in $AllVMHosts) {
$x = $null
$esxcli = Get-EsxCli -VMHost $VMHost -V2
$params = @{
network = '10.2.169.128/26'
gateway = '10.2.170.1'
}
$esxcli.network.ip.route.ipv4.add.Invoke($params)
$x = $esxcli.network.ip.route.ipv4.list.Invoke() | Where-Object {$_.Interface -eq 'vmk2' -and $_.Network -eq '10.2.169.128'}
$x | Add-Member -Name "Name" -MemberType NoteProperty -Value $VMHost.Name
$null = $result.Add($x)
}
@@ -0,0 +1,404 @@
#----------------------------------------------------------------------------------------------------------------------------------------------------
#vCenter Credentials
$creds = Get-Credential
Connect-VIServer itdvmvc1.nd.gov, itdvmvc2.nd.gov -Credential $creds
#----------------------------------------------------------------------------------------------------------------------------------------------------
#ConvertTo-Array
$VMs=@"
itdtaxtga1.nd.gov
itdtaxpfa1.nd.gov
itdtaxsga1.nd.gov
itdtaxsga2.nd.gov
itdtaxpga1.nd.gov
itdtaxpga2.nd.gov
itdtaxpga3.nd.gov
"@
$VMs=ConvertTo-Array -MultiLineString $VMs
#----------------------------------------------------------------------------------------------------------------------------------------------------
#Move VM to Datastore
$VMdatastore = 'VMWINDOWS1_143_A9K_R_SHRDPPLSFTST'
Get-VM $VMs | Get-HardDisk
Get-VM $VMs | Move-VM -DiskStorageFormat Thin -Datastore $VMdatastore
#----------------------------------------------------------------------------------------------------------------------------------------------------
#Copy Files to/from Remote Computer
#$fileloc = "C:\Users\delange\State of North Dakota\-Tm-ITD-Virtualization - Documents\VMware\Upgrades\ESXi\6.5.0Update3preGen9\VMware-ESXi-6.5.0-Update3-13932383-HPE-preGen9-650.U3.9.6.8.8-Jun2019.iso"
$fileloc = "C:\users\delange\Downloads\sql.zip"
#$fileloc = "O:\Backups\vp_grandforks\vp_grandforks.bak"
#$fileloc = "C:\temp3\AccelaSchool\*"
#$fileloc = "C:\temp\vp_bis_11252019.bak"
#$fileloc = "C:\ITD\vc-itdvmvc1.nd.gov-2020-01-14--19.33-53492.tgz"
#$fileloc = "D:\Upgrades\VMware\VMware-VCSA-all-6.5.0-14836121.iso"
#$fileloc = "F:\Support Bundles\vc-itdvmvc1.nd.gov-2020-01-07--19.02-29010.tgz"
#$destination = "D:\Upgrades\VMware\"
#$destination = "D:\delange"
#$destination = "C:\users\delange\Downloads\"
#$destination = "C:\inetpub\wwwroot\"
$destination = "D:\ITD\temp\"
#$servers = 'itdvmutil'
$servers = 'itdps-update.nd.gov'
#$servers = 'itdps-images.nd.gov'
#Copy to server
foreach ($server in $servers){
$s=New-PSSession $server -Credential $creds
Copy-Item $fileloc -ToSession $s -Destination $destination
}
#Copy from server
foreach ($server in $servers){
$s=New-PSSession $server -Credential $creds
Copy-Item $fileloc -FromSession $s -Destination $destination
}
#----------------------------------------------------------------------------------------------------------------------------------------------------
#Approve New VMs
Compare-ITDVMwareVMtoSharePoint -NewBuilds -OutVariable MatchSP | Format-Table
$MatchSP -Match $false | Sort-Object Name | Format-Table
$VMs=@"
itdohrcdbp1.nd.gov
itdohrcwebp1.nd.gov
"@
$VMs=ConvertTo-Array -MultiLineString $VMs
Approve-ITDVMwareVMNewBuild -ComputerName $VMs
#----------------------------------------------------------------------------------------------------------------------------------------------------
#Snapshots/Clones
#Get Current Snapshots
Get-VM | Get-Snapshot | Select-Object Name,VM | Sort-Object -Property Name | Format-Table -AutoSize #| clip.exe
#Take Snapshot
$SnapId = 2151..2156
New-ITDVMwareVMSnapshotTask -id $SnapId -vCenterCredential $creds
#Delete Snapshot from Scripted Task
$SnapId = 2186
Remove-ITDVMwareVMSnapshot -Id $SnapId -vCenterCredential $creds
#Delete Snapshot taken manually
$VM = 'bnd0704.nd.gov','itdscmt1.nd.gov'
Get-VM -Name $VM | Where-Object -Property PowerState -EQ PoweredOn | Get-Snapshot | Remove-Snapshot -Confirm:$false
#New Clone
$CloneId = 2149
New-ITDVMwareVMCloneTask -Id $CloneId -vCenterCredential $creds
#Delete Clone
$CloneId = 2117
Get-VM | Where-Object -Property Name -Like "*$CloneId*"
foreach ($Clone in $CloneId){
$DeleteClone = Get-VM | Where-Object -Property Name -Like "*$Clone*"
$DeleteClone | Remove-VM -DeleteFromDisk -Confirm:$false
}
#Snap entire vCenter environment at once
Get-VM itdvmpsc1*,itdvmvc1*,itdvmpsc2*,itdvmvc2* | New-Snapshot -Name "Converge External PSC"
Get-VM itdvmpsct1*,itdvmvct1*,itdvmpsct2*,itdvmvct2* | New-Snapshot -Name "PSCT2 Decommissioned"
#----------------------------------------------------------------------------------------------------------------------------------------------------
#Edit VMs
#Add CPU
$VMs = 'itdsql16p1.nd.gov'
$cpu = '4'
Get-VM $VMs
Set-VM $VMs -NumCpu $cpu -Confirm:$false
#Remove CPU
$VMs = 'bnd0557.nd.gov'
$cpu = '1'
Get-VM -Name $VMs | Shutdown-VMGuest -Confirm:$false
#Start-Sleep -Seconds 60
Get-VM -Name $VMs
Get-VM -Name $VMs | Set-VM -NumCPU $cpu -Confirm:$false
Start-VM $VMs -Confirm:$false
#Increase RAM
$VMs = 'itdcndhf16qps.nd.gov','itdcndhefqps.nd.gov'
$ram = '12'
Get-VM $VMs
Set-VM $VMs -MemoryGB $ram -Confirm:$false
#Remove RAM
$VMs = ''
$ram = ''
Get-VM $VMs | Shutdown-VMGuest -Confirm:$false
Start-Sleep -Seconds 60
Get-VM -Name $VMs | Set-VM -MemoryGB 16 -Confirm:$false
Start-VM $VMs -Confirm:$false
#Disconnect CDROM
$VMs = 'itdcndstrwt7.nd.gov'
foreach ($VM in $VMs){
Get-VM $VM | Get-CDDrive | Set-CDDrive -NoMedia -Confirm:$false
}
#Expand Disks
$VM = 'itdcndstvm04.nd.gov'
Get-VM | Where-Object -Property Name -Like "*$VM*"
Get-VM $VM | Get-HardDisk | Select-Object Name,CapacityGB,Filename
$harddisk = "Hard Disk 2"
$increasedisk = 3
$datastore = Get-VM $VM | Get-HardDisk | Where-Object -Property Name -EQ $harddisk | Get-Datastore
Get-Datastore $datastore | Select Name,FreeSpaceGB,CapacityGB
$newcap = (Get-VM $VM | Get-HardDisk | Where-Object -Property Name -EQ $harddisk).CapacityGB + $increasedisk
$newcap
Get-VM $VM | Get-HardDisk | Where-Object -Property Name -EQ $harddisk | Set-HardDisk -CapacityGB $newcap -Confirm:$false
#List NumCpu, MemoryGB, Total HardDiskSizeGB
$VMs = 'itd1xaes2','itdbiscmsvr','itdredskyaes','itdwfoaes4'
$datacenter = 'Primary Datacenter'
$harddisk = @{n="HardDiskSizeGB";e={(Get-HardDisk -VM $_ | Measure-Object -Sum CapacityGB).Sum}}
foreach ($VM in $VMs){
Get-Datacenter $datacenter | Get-VM | Where-Object -Property Name -Like "$VM*" | Select-Object -Property Name,NumCpu,MemoryGB,$harddisk
}
foreach ($VM in $VMs){
Get-VM | Where-Object -Property Name -Like "$VM*" | Get-HardDisk | Select-Object Name,CapacityGB,Filename | Sort-Object Filename -Descending
}
#----------------------------------------------------------------------------------------------------------------------------------------------------
#Port groups
#New distributed port group
$IP = '10.2.160.240/28' <#10.10.10.10/28#>
$VLANid = '3326' <#0001#>
New-ITDVMNetwork -CIDR $IP -VLAN $VLANid
#Remove distributed port group
$portgroup = 'dvPG_'
Get-VDPortgroup | Where-Object -Property Name -EQ $portgroup | Remove-VDPortGroup -Confirm:$false
#Manually add port group
$BismarckVDSwitch = 'dvSwitch3-PDC-AVAYA1-Data'
$MandanVDSwitch = 'dvSwitch3-SDC-AVAYA2-Data'
$PGName = 'dvPG3_2278_165.234.164.0_27'
$VlanId = '2278'
Get-VDSwitch -Name $BismarckVDSwitch | New-VDPortGroup -Name $PGName -NumPorts 1 -VlanId $VlanId
Get-VDSwitch -Name $BismarckVDSwitch | Get-VDPortGroup | Where-Object {$_.Name -like ("*" + "_" + $VlanId)} | Get-VDUplinkTeamingPolicy | Set-VDUplinkTeamingPolicy -FailoverDetectionPolicy BeaconProbing
Get-VDSwitch -Name $BismarckVDSwitch | Get-VDPortGroup | Where-Object {$_.Name -like ("*" + "_" + $VlanId)} | Get-VDPortgroupOverridePolicy | Set-VDPortgroupOverridePolicy -BlockOverrideAllowed $false -ResetPortConfigAtDisconnect $false
Get-VDSwitch -Name $MandanVDSwitch | New-VDPortGroup -Name $PGName -NumPorts 1 -VLANID $VlanId
Get-VDSwitch -Name $MandanVDSwitch | Get-VDPortGroup | Where-Object {$_.Name -like ("*" + "_" + $VlanId)} | Get-VDUplinkTeamingPolicy | Set-VDUplinkTeamingPolicy -FailoverDetectionPolicy BeaconProbing
Get-VDSwitch -Name $MandanVDSwitch | Get-VDPortGroup | Where-Object {$_.Name -like ("*" + "_" + $VlanId)} | Get-VDPortgroupOverridePolicy | Set-VDPortgroupOverridePolicy -BlockOverrideAllowed $false -ResetPortConfigAtDisconnect $false
#----------------------------------------------------------------------------------------------------------------------------------------------------
#Delete VMs
#Rename VMs for decommission
$VMs=@"
itdcndstfwp.nd.gov
itdcndstfsowp.nd.gov
itdcndstfwp1.nd.gov
itdcndstfapp1.nd.gov
itdcndstfwp2.nd.gov
itdcndstfapp2.nd.gov
"@
$VMs=ConvertTo-Array -MultiLineString $VMs
Remove-ITDVMWareVM -ComputerName $VMs | Select-Object -Property Name,PowerState
foreach ($VM in $VMs){
Get-VM | Where-Object -Property Name -Like "$VM*" | Select-Object -Property Name,PowerState
}
#Delete VM - FINAL DELETE
$deleteVM = foreach ($VM in $VMs){
Get-VM | Where-Object -Property Name -Like "$VM*delete*"
}
$deleteVM.Name
$deleteVM | Remove-VM -DeleteFromDisk -Confirm:$false
#----------------------------------------------------------------------------------------------------------------------------------------------------
#Replace VMs
$VMs = 'itdexchcasbis2.nd.gov','itdexchcasman2.nd.gov','itdcndhehb.nd.gov','itdcndheclnadd.nd.gov'
foreach ($VM in $VMs){
$VMold = Get-VM | Where-Object -Property Name -Like "$VM*" | Where-Object -Property PowerState -EQ PoweredOff
$VMnew = Get-VM | Where-Object -Property Name -Like "$VM*new*"
$VMtags = ($VMold | Get-TagAssignment).Tag | Sort-Object -Unique
foreach ($VMtag in $VMtags){
New-TagAssignment -Entity $VMnew -Tag $VMtag
}
Remove-ITDVMWareVM -ComputerName $VMold.Name
Set-VM -VM $VMnew -Name $VMold -Confirm:$false
}
foreach ($VM in $VMs){
Get-VM | Where-Object -Property Name -Like "$VM*" | Get-TagAssignment
}
#----------------------------------------------------------------------------------------------------------------------------------------------------
#Datastores
$Datastore = 'VMWINDOWS1_138_A9K_R_BNDFISERV'
#Rescan Host Cluster
Get-Cluster WINDOWS1 | Get-VMHost | Get-VMHostStorage -RescanAllHba -RescanVmfs
#Maintenance Mode
$Datastore = 'VMPS1_48_A9K_R','VMPS1_49_A9K_R','VMPS1_50_A9K_R','VMPS1_51_A9K_R','VMPS1_52_A9K_R','VMPS1_53_A9K_R'
Get-Datastore $Datastore | Set-Datastore -MaintenanceMode $true -EvacuateAutomatically
Get-Datastore $Datastore | Set-Datastore -MaintenanceMode $false
#Adding Datastores
$VMhost = 'itdbisvm-sql01.nd.gov'
#Get CanonicalName
Get-ScsiLun -VmHost $VMhost -LunType Disk | Select-Object CanonicalName,CapacityGB | Sort-Object CanonicalName
#Create Datastore
$Datastore = 'VMSQL1_119_A9K_TAX'
$CanonicalName = 'naa.6001738ccce06785000000000018ef24'
New-Datastore -VMHost $VMhost -Name $Datastore -Path $CanonicalName -VMFS -FileSystemVersion 6
#Removing Datastores
#Datastore Unmap
$Datastores = 'VMLINUX1_248_V5K_SECLOG','VMLINUX1_249_V5K_SECLOG','VMLINUX1_250_V5K_SECLOG','VMLINUX1_251_V5K_SECLOG'
#$Datastores = (Get-DatastoreCluster SQL1_A9K_General | Get-Datastore).Name
foreach ($Datastore in $Datastores){
Start-ITDVMwareDatastoreUnmap -Datastore $Datastores
}
#Expand Datastore
$Datastore = Get-Datastore 'VMTEL1_124_A9K_VBRICK'
$esxi = Get-View -Id ($Datastore.ExtensionData.Host | Select-Object -Last 1 | Select-Object -ExpandProperty Key)
$DatastoreSystem = Get-View -Id $esxi.ConfigManager.DatastoreSystem
$ExpandOptions = $DatastoreSystem.QueryVmfsDatastoreExpandOptions($Datastore.ExtensionData.MoRef)
$DatastoreSystem.ExpandVmfsDatastore($Datastore.ExtensionData.MoRef,$expandOptions.spec)
#Disable Storage I/O Control
$Datastores = 'VMWINDOWS1_90_A9K','VMWINDOWS1_91_A9K','VMWINDOWS1_92_A9K','VMSQL1_57_A9K','VMLINUX1_99_A9K_ELASTIC'
foreach ($Datastore in $Datastores){
Get-Datastore $Datastore | Set-Datastore -StorageIOControlEnabled $false
}
#Unmount/Detach
#Unmount/Detach
Remove-ITDVmwareDatastoreStep1 -LunId 90
#Step2 Storage Admin unmaps LUN from Host
#LUN cleanup (after storage unmap, should return empty)
Remove-ITDVMwareDatastoreStep3 -LunId 57
Remove-ITDVMwareDatastoreStep3 -LunId 90
Remove-ITDVMwareDatastoreStep3 -LunId 91
Remove-ITDVMwareDatastoreStep3 -LunId 92
Remove-ITDVMwareDatastoreStep3 -LunId 99
$Id = "_90_"
$Datastores = Get-Datastore | Where-Object Name -Like ("*_" + $Id + "_*")
ForEach ($Datastore in $Datastores) {
$SharePointRecord = $null
$DatastoreHosts = $Datastore | Get-VMHost
$VMHostCanonicalName = (Get-ScsiLun -VmHost ($DatastoreHosts | Select -First 1) | where-object RuntimeName -Like "*$Id*").CanonicalName
$SharePointRecord = ($SharePointList | Where-Object Title -eq $Datastore.Name)
If ($SharePointRecord.ExtentName -eq $VMHostCanonicalName) {
Write-Verbose ($Datastore.Name + " *** " + $VMHostCanonicalName + " *** CanonicalName accurate in SharePoint, continuing with unmount")
try {
Get-Datastore $Datastore #| Unmount-Datastore
$DatastoreHosts | Select-Object -First 1 | Remove-Datastore $Datastore -Confirm:$false -RunASync
$DatastoreRemovalSuccess += $Datastore.Name
}
catch {
$DatastoreRemovalFailure += $Datastore.Name
}
}
else {
Write-Error ($Datastore.Name + " *** " + " *** CanonicalName mismatch with SharePoint Record")
}
}
#----------------------------------------------------------------------------------------------------------------------------------------------------
#Clusters
#Get cluster that VM resides in
foreach ($VM in $VMs){
Get-VM $VM | Get-Datastore | Select-Object Name
}
#Get VMs with Resource Reservations
$Cluster = 'TEL1'
$VMs = Get-Cluster $Cluster | Get-VM
$VMs2 = Get-VM | Where-Object {$_.ExtensionData.ResourceConfig.MemoryAllocation.Reservation -ne "0" -or $_.ExtensionData.ResourceConfig.CpuAllocation.Reservation -ne "0"}
#----------------------------------------------------------------------------------------------------------------------------------------------------
#Tags
$VMs=@"
itdintrpmgrp1.nd.gov
"@
$VMs=ConvertTo-Array -MultiLineString $VMs
#Spectrum Protect for VE
$TagCat = "Backup Management (IBM Spectrum Protect)"
$TagName = "Included"
#RPO
$TagCat = "VR RPO"
$TagName = "ABR"
$TagName = "RPO 0:15"
$TagName = "RPO 0:30"
$TagName = "RPO 1:00"
$TagName = "RPO 2:00"
$TagName = "RPO 4:00"
$TagName = "RPO 8:00"
#VR Datastores
$TagCat = "VR Datastores"
$TagName = "VMAVAYA2_210_A9K_VR"
$TagName = "VMLINUX2_212_A9K_VR"
$TagName = "VMLINUX2_213_A9K_VR"
$TagName = "VMSQL2_218_A9K_VR"
$TagName = "VMTEL2_220_A9K_VR"
$TagName = "VMTEL2_221_A9K_VR"
$TagName = "VMWAS2_222_A9K_VR"
$TagName = "VMWAS2_223_A9K_VR"
$TagName = "VMWINDOWS2_224_A9K_VR"
$TagName = "VMWINDOWS2_225_A9K_VR"
$TagName = "VMWINDOWS2_226_A9K_VR"
#SRM Type
$TagCat = "SRM Type"
$TagName = "SRM Reserved"
$TagName = "SRM Repurposed Suspend"
$TagName = "SRM Repurposed"
#HA Host
$TagCat = "HA"
$TagName = "Dedicated HA Host"
#Assign Tag
foreach ($VM in $VMs){
$VM = Get-VM $VM | Where-Object -Property PowerState -EQ PoweredOn
$VIServer = $VM.Uid.split('@')[1].split(':')[0]
New-TagAssignment -Entity $VM -Tag (Get-Tag -Server $VIServer -Category $TagCat -Name $TagName) -Server $VIServer
}
foreach ($VMHost in $VMHosts){
$VMHost = Get-VMHost $VMHost
$VIServer = $VMHost.Uid.split('@')[1].split(':')[0]
New-TagAssignment -Entity $VMHost -Tag (Get-Tag -Server $VIServer -Category $TagCat -Name $TagName) -Server $VIServer
}
#----------------------------------------------------------------------------------------------------------------------------------------------------
#VMhosts
$VMhosts=@"
itdbisvm-av01.nd.gov
itdbisvm-av02.nd.gov
itdbisvm-av03.nd.gov
itdbisvm-av04.nd.gov
itdbisvm-av05.nd.gov
"@
$VMhosts=ConvertTo-Array -MultiLineString $VMhosts
#VMhosts by Cluster
$VMhosts = (Get-Cluster | Where-Object -Property Name -EQ WINDOWS1 | Get-VMHost | Sort-Object).Name
#Disable Lockdown Mode
foreach ($VMhost in $VMhosts){
(Get-VMHost $VMhost | Get-View).ExitLockdownMode()
}
#Enable Lockdown Mode
(Get-VMHost $VMhost | Get-View).EnterLockdownMode()
$VMhosts = Get-Datacenter | Where-Object -Property Uid -Like "*itdvmvc*" | Get-VMHost
(Get-VMHost $Vmhosts | Get-View).EnterLockdownMode()
foreach ($VMhost in $VMhosts){
(Get-VMHost $VMhost | Get-View).EnterLockdownMode()
}
#Enable SSH services
Get-VMHost $VMhost | Get-VMHostService | Where-Object {$_.Label -eq "SSH"} | Start-VMHostService
Get-VMHost $VMhost | Get-VMHostService | Where-Object {$_.Label -eq "ESXi Shell"} | Start-VMHostService
#Get Lockdown Status for all VMhosts
$VMhosts = Get-Datacenter | Where-Object -Property Uid -Like "*itdvmvc*" | Get-VMHost
$Lockdown = @{N="Lockdown";E={$_.Extensiondata.Config.adminDisabled}}
Get-VMHost $VMhosts | Select-Object Name,$Lockdown
#Disable Alarms
foreach ($VMhost in $VMhosts){
$disableHost = Get-VMhost $VMhost
$viServer = $disableHost.Uid.Split('@')[1].Split(':')[0]
$alarmMgr = Get-View AlarmManager -Server $viServer
$alarmEnabled = $disableHost.ExtensionData.AlarmActionsEnabled
if ($alarmEnabled -eq $true){
$alarmMgr.EnableAlarmActions($disableHost.ExtensionData.MoRef,$false)
}
$disableHost = $null
}
#Enable Alarms
foreach ($VMhost in $VMhosts){
$enableHost = Get-VMhost $VMhost
$viServer = $enableHost.Uid.Split('@')[1].Split(':')[0]
$alarmMgr = Get-View AlarmManager -Server $viServer
$alarmEnabled = $enableHost.ExtensionData.AlarmActionsEnabled
if ($alarmEnabled -eq $false){
$alarmMgr.EnableAlarmActions($enableHost.ExtensionData.MoRef,$true)
}
$enableHost = $null
}
#----------------------------------------------------------------------------------------------------------------------------------------------------
#Disk Space
$VMs=@"
itdcndhhpdb.nd.gov
itdcndhhpdbdr.nd.gov
itdcndhfpdb.nd.gov
itdcndhfpdbdr.nd.gov
"@
$VMs=ConvertTo-Array -MultiLineString $VMs
$export = 'C:\temp\usedspace.csv'
Get-VM $VMs | Select-Object Name,@{n="UsedSpaceGB"; e={[math]::round($_.UsedSpaceGB )}},@{n="ProvisionedSpaceGB"; e={[math]::round($_.ProvisionedSpaceGB )}} -OutVariable Avaya1 | Export-Csv $export
Get-VM $VMs | Select-Object Name,@{n="UsedSpaceGB"; e={[math]::round($_.UsedSpaceGB )}},@{n="ProvisionedSpaceGB"; e={[math]::round($_.ProvisionedSpaceGB )}} -OutVariable Avaya1 | Export-Csv $export -Append
Get-VM $VMs | Select-Object Name,@{n="UsedSpaceGB"; e={[math]::round($_.UsedSpaceGB )}},@{n="ProvisionedSpaceGB"; e={[math]::round($_.ProvisionedSpaceGB )}} -OutVariable Linux1 | Export-Csv $export -Append
Get-VM $VMs | Select-Object Name,@{n="UsedSpaceGB"; e={[math]::round($_.UsedSpaceGB )}},@{n="ProvisionedSpaceGB"; e={[math]::round($_.ProvisionedSpaceGB )}} -OutVariable ODM1 | Export-Csv $export -Append
Get-VM $VMs | Select-Object Name,@{n="UsedSpaceGB"; e={[math]::round($_.UsedSpaceGB )}},@{n="ProvisionedSpaceGB"; e={[math]::round($_.ProvisionedSpaceGB )}} -OutVariable PS1 | Export-Csv $export -Append
Get-VM $VMs | Select-Object Name,@{n="UsedSpaceGB"; e={[math]::round($_.UsedSpaceGB )}},@{n="ProvisionedSpaceGB"; e={[math]::round($_.ProvisionedSpaceGB )}} -OutVariable WAS1 | Export-Csv $export -Append
Get-VM $WindowsVMs | Select-Object Name,@{n="UsedSpaceGB"; e={[math]::round($_.UsedSpaceGB )}},@{n="ProvisionedSpaceGB"; e={[math]::round($_.ProvisionedSpaceGB )}} -OutVariable Windows1 | Export-Csv $export -Append
#----------------------------------------------------------------------------------------------------------------------------------------------------
$export = "C:\temp2\usedspace.csv"
Export-Csv -Path $export -InputObject $Avaya1
Get-VM $VMs | Select-Object @{n="Cluster"; e={($_ | Get-Cluster).Name}},Name,@{n="UsedSpaceGB"; e={[math]::round($_.UsedSpaceGB )}},@{n="ProvisionedSpaceGB"; e={[math]::round($_.ProvisionedSpaceGB )}} -OutVariable Avaya1 | Export-Csv $export
@@ -0,0 +1,97 @@
Start-Transcript C:\ITDSCRIPT\Logs\GetIPs.txt -Append
#Add-PSSnapin VMware.VimAutomation.Core
Set-PowerCLIConfiguration -DefaultVIServerMode multiple -Scope Session -Confirm:$false
#Connect
Connect-VIServer itdvmvc1.nd.gov, itdvmvc2.nd.gov
##Windows
#Output File
$OutFileWin = "c:\inetpub\wwwroot\Win.txt"
$Date = Get-Date -UFormat "%Y%m%d%H%M%S"
Get-Item -Path $OutFileWin | Copy-Item -Destination "D:\Backup\Win\$Date-Win.txt"
Remove-Item $OutFileWin
Start-Sleep -Seconds 5
#Get Powered On VM's
$vmwin = get-VM | Where-Object { $_.PowerState -eq "PoweredOn" `
-and ($_.GuestID -eq "windows7Guest" `
-or $_.GuestID -eq "windows7_64Guest" `
-or $_.GuestID -eq "windows7Server64Guest" `
-or $_.GuestID -eq "windows8_64Guest" `
-or $_.GuestID -eq "windows8Server64Guest" `
-or $_.GuestID -eq "windows9Server64Guest" `
-or $_.GuestID -eq "winLonghorn64Guest" `
-or $_.GuestID -eq "winLonghornGuest" `
-or $_.GuestID -eq "winNetStandardGuest" `
-or $_.GuestID -eq "winNetEnterpriseGuest" `
-or $_.GuestID -eq "windows9_64Guest") }
$vmviewwin = $vmwin | Get-View
$Outputwin = ""
#Loop through VM's, NIC's, and IP addresses.
Foreach ($v in $vmviewwin) {
Foreach ($nic in $v.Guest.Net) {
Foreach ($IP in $nic.IPAddress) {
If ($IP -notlike "fe80*" -and $IP -notlike "192.168.*" -and $IP -notlike "172.16*") {
$OutputWin += $IP + "`n"
}
}
}
}
#If ($Outputwin -ne "") {$OutputWin | Out-File $OutFileWin -Encoding utf8 -NoNewline}
If ($Outputwin -ne "") { $OutputWin | Out-File $OutFileWin -Encoding ASCII -NoNewline }
##Linux
#Output File
$OutFileLin = "c:\inetpub\wwwroot\Lin.txt"
$Date = Get-Date -UFormat "%Y%m%d%H%M%S"
Get-Item -Path $OutFileLin | Copy-Item -Destination "D:\Backup\Lin\$Date-Lin.txt"
Remove-Item $OutFileLin
Start-Sleep -Seconds 5
#Get Powered On VM's
$vmLin = get-VM | Where-Object { $_.PowerState -eq "PoweredOn" `
-and ($_.GuestID -eq "centos6_64Guest" `
-or $_.GuestID -eq "centos64Guest" `
-or $_.GuestID -eq "centos7_64Guest" `
-or $_.GuestID -eq "oracleLinux64Guest" `
-or $_.GuestID -eq "oracleLinux7_64Guest" `
-or $_.GuestID -eq "rhel4Guest" `
-or $_.GuestID -eq "rhel5Guest" `
-or $_.GuestID -eq "rhel5_64Guest" `
-or $_.GuestID -eq "rhel6Guest" `
-or $_.GuestID -eq "rhel6_64Guest" `
-or $_.GuestID -eq "rhel7_64Guest" `
-or $_.GuestID -eq "sles11_64Guest" `
-or $_.GuestID -eq "sles12_64Guest" `
-or $_.GuestID -eq "ubuntu64Guest") }
$vmviewlin = $vmLin | Get-View
$OutputLin = ""
#Loop through VM's, NIC's, and IP addresses.
Foreach ($v in $vmviewlin) {
Foreach ($nic in $v.Guest.Net) {
Foreach ($IP in $nic.IPAddress) {
If ($IP -notlike "fe80*" -and $IP -notlike "192.168.*" -and $IP -notlike "172.16*") {
$OutputLin += $IP + "`n"
}
}
}
}
#If ($OutputLin -ne "") {$OutputLin | Out-File $OutFileLin -Encoding utf8 -NoNewline}
If ($OutputLin -ne "") { $OutputLin | Out-File $OutFileLin -Encoding ASCII -NoNewline }
Stop-Transcript
@@ -0,0 +1,133 @@
Start-Transcript C:\itdscript\Logs\GetIPsAzureB.txt -Append
$VerbosePerfrence = "Continue"
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$OutputPath = "C:\inetpub\wwwroot"
$WindowsIPs = ""
$LinuxIPs = ""
$OutFileWin = $OutputPath + "\AzureWin.txt"
$OutFileLin = $OutputPath + "\AzureLin.txt"
Remove-Item $OutFileWin
Remove-Item $OutFileLin
$username="svcitdazurescript@nd.gov"
$usernameg="svcitdazurescript@ndstate.onmicrosoft.com"
#Read-Host -AsSecureString | ConvertFrom-SecureString | Out-File C:\Users\svcitdazurescript\AppData\Local\Microsoft\sac.bat
$password=Get-Content C:\Users\svcitdazurescript\AppData\Local\Microsoft\sac.bat | ConvertTo-SecureString
$passwordg=Get-Content C:\Users\svcitdazurescript\AppData\Local\Microsoft\sacg.bat | ConvertTo-SecureString
$AdminCred=New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $username,$password
$AdminCredg=New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $usernameg,$passwordg
Login-AzureRMAccount -Credential $AdminCred -Environment AzureCloud -Verbose
$Subscriptions = Get-AzureRMSubscription | Where-Object {$_.Name -ne "sandbox"}
foreach($subscription in $subscriptions)
{
Set-AzureRMContext -SubscriptionObject $subscription
$WindowsVMs = Get-AzureRMVM | Where-Object {$_.StorageProfile.osdisk.ostype -match "Windows"}
$LinuxVMs = Get-AzureRMVM | Where-Object {$_.StorageProfile.osdisk.ostype -match "Linux" -and $_.StorageProfile.ImageReference.Publisher -ne "infoblox" -and $_.StorageProfile.ImageReference.Publisher -ne "paloaltonetworks" -and $_.StorageProfile.ImageReference.Publisher -ne "juniper-networks"}
$nics = Get-AzureRMNetworkInterface | Where-Object {$_.VirtualMachine -NE $null}
foreach($vm in $WindowsVMs)
{
$vmnicinterfaces = $vm.Networkprofile.NetworkInterfaces.id
foreach($vmnicinterface in $vmnicinterfaces)
{
$nic = $nics | Where-Object {$_.Id -eq $vmnicinterface}
$privateip = $nic.IpConfigurations | Select PrivateIPAddress
If($privateip.count -gt 1)
{
foreach($private in $privateip)
{
$WindowsIPs += $private.privateIPAddress + "`n"
}
}
elseIf($privateip.privateIPAddress -ne $null)
{
$WindowsIPs += $privateip.privateIPAddress + "`n"
}
}
}
foreach($vm in $LinuxVMs)
{
$vmnicinterfaces = $vm.Networkprofile.NetworkInterfaces.id
foreach($vmnicinterface in $vmnicinterfaces)
{
$nic = $nics | Where-Object {$_.Id -eq $vmnicinterface}
$privateip = $nic.IpConfigurations | Select PrivateIPAddress
If($privateip.count -gt 1)
{
foreach($private in $privateip)
{
$LinuxIPs += $private.privateIPAddress + "`n"
}
}
elseif($privateip.privateIPAddress -ne $null)
{
$LinuxIps += $privateip.privateIPAddress + "`n"
}
}
}
}
Login-AzureRMAccount -EnvironmentName AzureUSGovernment -Credential $AdminCredg
$Subscriptions = Get-AzureRMSubscription | Where-Object {$_.Name -ne "sandbox"}
foreach($subscription in $subscriptions)
{
Set-AzureRMContext -SubscriptionObject $subscription
$WindowsVMs = Get-AzureRMVM | Where-Object {$_.StorageProfile.osdisk.ostype -match "Windows"}
$LinuxVMs = Get-AzureRMVM | Where-Object {$_.StorageProfile.osdisk.ostype -match "Linux" -and $_.StorageProfile.ImageReference.Publisher -ne "infoblox" -and $_.StorageProfile.ImageReference.Publisher -ne "paloaltonetworks" -and $_.StorageProfile.ImageReference.Publisher -ne "juniper-networks"}
$nics = Get-AzureRMNetworkInterface | Where-Object {$_.VirtualMachine -NE $null}
foreach($vm in $WindowsVMs)
{
$vmnicinterfaces = $vm.Networkprofile.NetworkInterfaces.id
foreach($vmnicinterface in $vmnicinterfaces)
{
$nic = $nics | Where-Object {$_.Id -eq $vmnicinterface}
$privateip = $nic.IpConfigurations | Select PrivateIPAddress
If($privateip.count -gt 1)
{
foreach($private in $privateip)
{
$WindowsIPs += $private.privateIPAddress + "`n"
}
}
elseIf($privateip.privateIPAddress -ne $null)
{
$WindowsIPs += $privateip.privateIPAddress + "`n"
}
}
}
foreach($vm in $LinuxVMs)
{
$vmnicinterfaces = $vm.Networkprofile.NetworkInterfaces.id
foreach($vmnicinterface in $vmnicinterfaces)
{
$nic = $nics | Where-Object {$_.Id -eq $vmnicinterface}
$privateip = $nic.IpConfigurations | Select PrivateIPAddress
If($privateip.count -gt 1)
{
foreach($private in $privateip)
{
$LinuxIPs += $private.privateIPAddress + "`n"
}
}
elseif($privateip.privateIPAddress -ne $null)
{
$LinuxIps += $privateip.privateIPAddress + "`n"
}
}
}
}
If ($WindowsIPs -ne "" -and $WindowsIPs.Length -gt 150) {$WindowsIPs | Out-File $OutFileWin -Encoding ASCII -NoNewline -Force}
If ($LinuxIPs -ne ""-and $LinuxIPs.Length -gt 150) {$LinuxIPs | Out-File $OutFileLin -Encoding ASCII -NoNewline -Force}
@@ -0,0 +1,89 @@
start-transcript D:\zm.log -force
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$OutputPath = "C:\inetpub\wwwroot"
$OutputBackupPath = "C:\inetpub\wwwroot\AzureBak\"
$CurrentDateTime = Get-Date -UFormat "%Y%m%d%H%M%S"
$BackupIPs = ""
$OutFileBak = $OutputPath + "\AzureBak.txt"
$OutFileBakBackup = $OutputBackupPath + "\AzureBak-$CurrentDateTime.txt"
Remove-Item $OutFileBak
$username="svcitdazurescript@nd.gov"
$usernameg="svcitdazurescript@ndstate.onmicrosoft.com"
#Read-Host -AsSecureString | ConvertFrom-SecureString | Out-File C:\Users\svcitdazurescript\AppData\Local\Microsoft\sac.bat
$password=Get-Content C:\Users\svcitdazurescript\AppData\Local\Microsoft\sac.bat | ConvertTo-SecureString
$passwordg=Get-Content C:\Users\svcitdazurescript\AppData\Local\Microsoft\sacg.bat | ConvertTo-SecureString
$AdminCred=New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $username,$password
$AdminCredg=New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $usernameg,$passwordg
Login-AzureRMAccount -Credential $AdminCred -Environment AzureCloud
$Subscriptions = Get-AzureRMSubscription | Where-Object {$_.Name -ne "sandbox"}
foreach($subscription in $subscriptions)
{
Set-AzureRMContext -SubscriptionObject $subscription
$BackupVMs = Get-AzureRMVM | Where-Object {$_.Tags["Backup"] -match "OS-BackupEnabled"}
$nics = Get-AzureRMNetworkInterface | Where-Object {$_.VirtualMachine -NE $null}
foreach($vm in $BackupVMs)
{
$vmnicinterfaces = $vm.Networkprofile.NetworkInterfaces.id
foreach($vmnicinterface in $vmnicinterfaces)
{
$nic = $nics | Where-Object {$_.Id -eq $vmnicinterface}
$privateip = $nic.IpConfigurations | Select PrivateIPAddress
If($privateip.count -gt 1)
{
foreach($private in $privateip)
{
$BackupIPs += $private.privateIPAddress + "`n"
}
}
elseIf($privateip.privateIPAddress -ne $null)
{
$BackupIPs += $privateip.privateIPAddress + "`n"
}
}
}
}
Login-AzureRMAccount -EnvironmentName AzureUSGovernment -Credential $AdminCredg
$Subscriptions = Get-AzureRMSubscription | Where-Object {$_.Name -ne "sandbox"}
foreach($subscription in $subscriptions)
{
Set-AzureRMContext -SubscriptionObject $subscription
$BackupVMs = Get-AzureRMVM | Where-Object {$_.Tags["Backup"] -match "OS-BackupEnabled"}
$nics = Get-AzureRMNetworkInterface | Where-Object {$_.VirtualMachine -NE $null}
foreach($vm in $BackupVMs)
{
$vmnicinterfaces = $vm.Networkprofile.NetworkInterfaces.id
foreach($vmnicinterface in $vmnicinterfaces)
{
$nic = $nics | Where-Object {$_.Id -eq $vmnicinterface}
$privateip = $nic.IpConfigurations | Select PrivateIPAddress
If($privateip.count -gt 1)
{
foreach($private in $privateip)
{
$BackupIPs += $private.privateIPAddress + "`n"
}
}
elseIf($privateip.privateIPAddress -ne $null)
{
$BackupIPs += $privateip.privateIPAddress + "`n"
}
}
}
}
If ($BackupIPs -ne "") {
$BackupIPs | Out-File $OutFileBak -Encoding ASCII -NoNewline -Force
$BackupUPs | Out-File $OutFileBakBackup -Encoding ascii -NoNewline -Force
}
@@ -0,0 +1,88 @@
$servers = @"
itdvmbisvdi05lo.nd.gov
itdvmbisvdi06lo.nd.gov
"@
$servers = ConvertTo-Array -MultiLineString $servers
# validate DNS is configured
ForEach($server in $servers){
Resolve-DnsName -Name $server
}
#ServerHardware.mpHostInfo.mpIpAddresses
# requires powershell 5.1 as of 2023/02/09
# Generate CSRs
ForEach ($server in $servers) {
$csr = $Null
$connection = Connect-HPEiLO $server -Credential $iLOCred -DisableCertificateAuthentication
$FQDN = $connection.Hostname
If($FQDN -notlike "itdvm*"){
$FQDN = ((Get-HPEiLOServerInfo -Connection $connection).ServerName.split('.')[0] + 'lo' + '.nd.gov')
}
$Hostname = $FQDN.split('.')[0]
Start-HPEiLOCertificateSigningRequest -Connection $connection -State "North Dakota" -Country "US" -City "Bismarck" -Organization "State of North Dakota" -OrganizationalUnit "NDIT" -CommonName $FQDN
do {
$csr = (Get-HPEiLOCertificateSigningRequest -Connection $connection -ErrorAction SilentlyContinue).CertificateSigningRequest.TrimEnd()
Write-Warning ((Get-Date).tostring() + " pausing for 5 seconds")
Start-Sleep -Seconds 5
} while ( $csr -eq $null )
$csr | Set-Content "D:\iLO\CSRs\$FQDN-csr.txt"
Disconnect-HPEiLO -Connection $connection
}
$CsrList = [System.Collections.ArrayList]@()
ForEach($server in $servers){
$obj=[PSCustomObject]@{
'Server' = $Server
'CSR' = (Get-Content "D:\iLO\CSRs\$server-csr.txt" -Raw);
}
$null = $CsrList.Add($obj)
}
$CsrList | group-object CSR
# If any appear with count not equal to 1, something is broken
ForEach ($server in $servers){
Write-Warning "$server csr to clipboard"
Get-Content "D:\iLO\CSRs\$server-csr.txt" | Set-Clipboard
Pause
}
ForEach ($server in $servers){
$certfile = $Null
$cert = $Null
$connection = Connect-HPEiLO $server -Credential $iloCred -DisableCertificateAuthentication
$FQDN = $connection.Hostname
If($FQDN -notlike "itdvm*"){
$FQDN = ((Get-HPEiLOServerInfo -Connection $connection).ServerName.split('.')[0] + 'lo' + '.nd.gov')
}
$Hostname = $FQDN.split('.')[0]
$certfile = ($hostname) + "_nd_gov_cert.cer"
$cert = (Get-Content "D:\iLO\Certs\$certfile" -Raw).Replace("`r`n", "`n").Trim()
Import-HPEiLOCertificate -Certificate $cert -Connection $connection -Verbose
Disconnect-HPEiLO -Connection $connection
}
# Refresh server hardware, in powershell 7
# Connect-OVMgmt
$OVServers = Get-OVServer | Sort-Object ServerName
Foreach($OVServer in $OVServers){
Write-Warning ("Start " + $OVServer.ServerName)
$OVServer | Update-OVServer -Async
Start-Sleep -Seconds 15
}
#######################
@@ -0,0 +1,19 @@
$VMHosts = Get-VMHost
#SSH Service Status
$SSHServiceStatus = $VMHosts | Get-VMHostService | Where-Object Key -eq "TSM-SSH" | select VMhost,Key,Label,Running
#Disable SSH
ForEach($item in ($SSHService | Where-Object Running -eq $true)){
Get-VMHost $item.VMHost | Get-VMHostService | Where-Object Key -eq "TSM-SSH" | Stop-VMHostService
}
#Lockdown status
$LockdownStatus = $VMHosts | Select Name,@{n='LockdownMode';e={$_.ExtensionData.Config.LockdownMode}}
#Enable Lockdown
ForEach($VMHost in ($LockdownStatus | Where-Object LockdownMode -eq "lockdownDisabled")){
(Get-VMHost $VMHost.Name | Get-View).EnterLockdownMode()
}
@@ -0,0 +1,102 @@
$VMHostNames=@"
itdvmbisps10.nd.gov
itdvmbisps11.nd.gov
itdvmbisps12.nd.gov
itdvmbisps13.nd.gov
itdvmbisps14.nd.gov
itdvmbisps15.nd.gov
itdvmbisps16.nd.gov
itdvmbisps17.nd.gov
itdvmbisps18.nd.gov
"@
$VMHostNames = ConvertTo-Array -MultiLineString $VMHostNames
<#$VMHostNames | ForEach-Object{
New-ITDVMwareHostScratchFolder -Site Bismarck $_.split('.')[0]
}
#>
foreach ($VMHostName in $VMHostNames){
$GetVMHost = Get-VMhost $VMHostName
$VMHostParent = $GetVMHost.Parent
$HostCluster = Get-Cluster $VMHostParent
$NewSpec = New-Object VMware.Vim.ClusterConfigSpec
$NewSpec.DasConfig = New-Object VMware.Vim.ClusterDasConfigInfo
$NewSpec.DasConfig.AdmissionControlPolicy = New-Object VMware.Vim.ClusterFailoverResourcesAdmissionControlPolicy
$NewSpec.DasConfig.AdmissionControlPolicy.AutoComputePercentages = $true
$HostCluster.ExtensionData.ReconfigureCluster($NewSpec,$true)
$VIServer = $GetVMHost.Uid.Split('@')[1].Split(':')[0]
$alarmMgr = Get-View AlarmManager -Server $VIServer
$alarmEnabled = $GetVMHost.ExtensionData.AlarmActionsEnabled
if ($alarmEnabled -eq $true){
$alarmMgr.EnableAlarmActions($GetVMHost.ExtensionData.MoRef,$false)
}
$VMs = $GetVMHost | Get-VM
#Disconnect CDROM and/or VMtools ISO
foreach ($VM in $VMs){
$GetVM = Get-VM $VM
$CDDrive = $GetVM | Get-CDDrive
if ($CDDrive | Where-Object {$_.IsoPath -Like "*vmware/isoimages*"}){
$GetVM | Dismount-Tools
#$CDDrive | Set-CDDrive -NoMedia -Confirm:$false
}
elseif ($CDDrive.HostDevice -Like "*drive*"){
$CDDrive | Set-CDDrive -NoMedia -Confirm:$false
}
}
$GetVMHost = $null
}
#Move Powered Off VMs
foreach ($VMHostName in $VMHostNames){
$VMHostDetails = Get-VMHost -Name $VMHostName
$VMHostParent = $VMHostDetails.Parent.Name
$VMHostMigrate = Get-Cluster $VMHostParent | Get-VMHost | Where-Object Name -NE $VMHostName | Select-Object -First 1
$VMsPoweredOff = Get-VMHost $VMHostName | Get-VM | Where-Object PowerState -EQ "PoweredOff"
Move-VM -VM $VMsPoweredOff -Destination $VMHostMigrate
}
#Enter Maintenance Mode
Set-VMHost -VMHost $VMHostNames -State "Maintenance" -RunAsync
#Monitor
Get-VMHost -Name $VMHostNames | Select-Object Name,ConnectionState,@{Name="VM.count";E={@($_ | Get-VM | Where-Object {$_.ExtensionData.Summary.Config.ManagedBy.Type -NE "placeholderVm"}).Count}} | sort-object Name
# shutdown
Get-VMHost -Name $VMHostnames | Stop-VMHost -Confirm:$false
#status
Get-VMHost -Name $VMHostnames
# OneView, Update Server Profile from Template
ForEach($VMHostName in $VMHostNames){
Get-OVServerProfile -Name $VMHostName.split('.')[0] | Update-OVServerProfile -Async -confirm:$false
}
# Power on
ForEach($VMHostName in $VMHostNames){
Get-OVServer -ServerName $VMHostName | Start-OVServer -Async
}
# Verify on and connected
Get-VMHost $VMHostNames
# attach new host profile
Get-VMHost -Name $VMHostnames | Set-VMHost -Profile "MDN 6.5.0 Synergy General 2203"
# Apply/Remediate Host Profile (invoke)
Get-VMHost -Name $VMHostnames | Invoke-VMHostProfile -confirm:$false -RunAsync
# manual check for dvswitch data-user
#Exit Maintenance Mode and Enable Alarms
Set-VMHost -VMHost $VMHostNames -State "Connected" -RunAsync
Start-Sleep -Seconds 60
foreach ($VMHostName in $VMHostNames){
$GetVMHost = Get-VMhost $VMHostName
$VIServer = $GetVMHost.Uid.Split('@')[1].Split(':')[0]
$alarmMgr = Get-View AlarmManager -Server $VIServer
$alarmEnabled = $GetVMHost.ExtensionData.AlarmActionsEnabled
if ($alarmEnabled -eq $false){
$alarmMgr.EnableAlarmActions($GetVMHost.ExtensionData.MoRef,$true)
}
$GetVMHost = $null
}
@@ -0,0 +1,136 @@
$sctasknum='SCTASK0123474'
$sctask = Get-ServiceNowRecord -Table 'Catalog Task' -ID $sctasknum -IncludeCustomVariable
$request_itemNum = $sctask.request_item.display_value
$TimeStampString = Get-Date -UFormat "%Y%m%d%H%M%S"
$CommentsToAdd=@"
$TimeStampString
Added disk
"@
Update-ServiceNowRecord -ID $sctask.number -Values @{comments = $CommentsToAdd} # enter comments into sctask
Update-ServiceNowRecord -ID $RitmNum -values @{comments = $CommentsToAdd}
If($CloseTask){
Update-ServiceNowRecord -Id $sctask.number -Values @{close_notes = $CommentsToAdd; state = "Closed Complete" }
}
Update-ServiceNowRecord -ID $sctask.number -Values @{short_description = "VMware VM change for $HostName"}
Update-ServiceNowRecord -ID $sctask.number -Values @{assigned_to = "Donald E. Lange"}
Update-ServiceNowRecord -ID $sctask.number -Values @{assigned_to = $assignTo.name}
# full auto cpu/memory
$SCTaskNum = 'SCTASK0123802'
$SCTask = Get-ServiceNowRecord -Table 'Catalog Task' -ID $SCTaskNum
$RitmNum = $SCTask.request_item.display_value
$RITM = Get-ServiceNowRecord -Table 'Requested Item' -ID $RitmNum -IncludeCustomVariable
[string]$HostName = ($RITM.CustomVariable | where-object Name -eq server_name).Value
[int]$CPU = ($RITM.CustomVariable | where-object Name -eq Processors).Value
[int]$MemoryGB = ($RITM.CustomVariable | where-object Name -eq MemoryGB).Value
[int]$Disk1 = ($RITM.CustomVariable | where-object Name -eq disk_1_os).Value
[int]$Disk2 = ($RITM.CustomVariable | where-object Name -eq disk_2_swap_disk).Value
[int]$Disk3 = ($RITM.CustomVariable | where-object Name -eq disk_3).Value
[int]$Disk4 = ($RITM.CustomVariable | where-object Name -eq disk_4).Value
[int]$Disk5 = ($RITM.CustomVariable | where-object Name -eq disk_5).Value
[int]$Disk6 = ($RITM.CustomVariable | where-object Name -eq disk_6).Value
[int]$Disk7 = ($RITM.CustomVariable | where-object Name -eq disk_7).Value
[int]$Disk8 = ($RITM.CustomVariable | where-object Name -eq disk_8).Value
[int]$Disk9 = ($RITM.CustomVariable | where-object Name -eq disk_9).Value
[int]$Disk10 = ($RITM.CustomVariable | where-object Name -eq disk_10).Value
[int]$Disk11 = ($RITM.CustomVariable | where-object Name -eq disk_11).Value
[int]$Disk12 = ($RITM.CustomVariable | where-object Name -eq disk_12).Value
[int]$Disk13 = ($RITM.CustomVariable | where-object Name -eq disk_13).Value
[int]$Disk14 = ($RITM.CustomVariable | where-object Name -eq disk_14).Value
[int]$Disk15 = ($RITM.CustomVariable | where-object Name -eq disk_15).Value
[int]$Disk16 = ($RITM.CustomVariable | where-object Name -eq disk_16).Value
$VM = Get-VM -Name $HostName* | Where-Object { $_.ExtensionData.summary.config.ManagedBy.Type -ne "placeholderVm" }
Write-Warning -Message ("VM: " + $VM.Name)
If($CPU -ne 0){
Write-Verbose -Message ($VM.Name + " attempt increasing CPU to " + $CPU)
try {
$VM | Set-VM -NumCpu $CPU
}
catch {
<#Do this if a terminating exception happens#>
}
}
If($MemoryGB -ne 0){
Write-Verbose -Message ($VM.Name + " attempt increasing MemoryGB to " + $CPU)
try {
$VM | Set-VM -MemoryGB $MemoryGB
}
catch{
}
}
If($Disk1){
$HardDisk = $VM | Get-HardDisk -Name "Hard disk 1"
$Datastore = $HardDisk | Get-Datastore
$HardDiskIncreaseGB = $Disk1 - $HardDisk.CapacityGB
$FreePercentBefore = ($Datastore.FreeSpaceGB) / $Datastore.CapacityGB
$FreePercentAfter = ($Datastore.FreeSpaceGB - $HardDiskIncreaseGB) / $Datastore.CapacityGB
If ($FreePercentAfter -gt 0.10){
Write-Warning -Message ("Hard disk 1: Increasing from " + $HardDisk.CapacityGB + "GB to " + $Disk1 + "GB")
#Write-Warning -Message ("Datastore " + $Datastore.Name + " free space will lower from " + [math]::round($FreePercentBefore,4)*100 + "% to " + [math]::round($FreePercentAfter,4)*100 + "%")
Write-Warning -Message ("Datastore " + $Datastore.Name + " free space will lower from " + [math]::round($FreePercentBefore,4) + " to " + [math]::round($FreePercentAfter,4) + "")
$VM | Get-HardDisk -Name "Hard disk 1" | Set-HardDisk -CapacityGB $Disk1 -Confirm:$false
}
Else{
Write-Error -Message ("Hard disk 1 failed. 20% free space is required for automated disk expansions. " + $Datastore.Name + " would be " + [math]::round($FreePercentAfter,4) + ".")
}
}
If($Disk2){
#$VM | Get-HardDisk -Name "Hard disk 2" | Set-HardDisk -CapacityGB $Disk2
}
If($Disk3){
#$VM | Get-HardDisk -Name "Hard disk 3" | Set-HardDisk -CapacityGB $Disk3
}
<#
If($Disk4){
$VM | Get-HardDisk -Name "Hard disk 4" | Set-HardDisk -CapacityGB $Disk4
}
If($Disk5){
$VM | Get-HardDisk -Name "Hard disk 5" | Set-HardDisk -CapacityGB $Disk5
}
If($Disk6){
$VM | Get-HardDisk -Name "Hard disk 6" | Set-HardDisk -CapacityGB $Disk6
}
If($Disk7){
$VM | Get-HardDisk -Name "Hard disk 7" | Set-HardDisk -CapacityGB $Disk7
}
If($Disk8){
$VM | Get-HardDisk -Name "Hard disk 8" | Set-HardDisk -CapacityGB $Disk8
}
If($Disk9){
$VM | Get-HardDisk -Name "Hard disk 9" | Set-HardDisk -CapacityGB $Disk9
}
If($Disk10){
$VM | Get-HardDisk -Name "Hard disk 10" | Set-HardDisk -CapacityGB $Disk10
}
If($Disk11){
$VM | Get-HardDisk -Name "Hard disk 10" | Set-HardDisk -CapacityGB $Disk11
}
If($Disk12){
$VM | Get-HardDisk -Name "Hard disk 10" | Set-HardDisk -CapacityGB $Disk12
}
If($Disk13){
$VM | Get-HardDisk -Name "Hard disk 10" | Set-HardDisk -CapacityGB $Disk13
}
If($Disk14){
$VM | Get-HardDisk -Name "Hard disk 10" | Set-HardDisk -CapacityGB $Disk14
}
If($Disk15){
$VM | Get-HardDisk -Name "Hard disk 10" | Set-HardDisk -CapacityGB $Disk15
}
If($Disk16){
$VM | Get-HardDisk -Name "Hard disk 10" | Set-HardDisk -CapacityGB $Disk16
}#>
@@ -0,0 +1,75 @@
<#
VM level:
VM Name
Storage provisioned per disk
Storage used per disk
Free capacity per disk
Disk Mode ( dependent persistent vs independent persistent )
Disk Type ( Thick, thin, lazy, eager, etc... )
Datastore
Replication Technology, if applicable
Datacenter
#>
$VMStorageList = [System.Collections.ArrayList]@()
$AllVMs = Get-VM | Where-Object { $_.ExtensionData.summary.config.ManagedBy.Type -ne "placeholderVm" }
ForEach($VM in $AllVMs){
$VmObj = [PSCustomObject]@{
VMName = $VM.Name;
UsedSpaceGB = $VM.UsedSpaceGB;
ProvisionedSpaceGB = $VM.ProvisionedSpaceGB;
Datastores = ($VM | Get-Datastore).Name
DatastoreCluster = ($VM | Get-DatastoreCluster).Name
Replication = switch ( ($VM | Get-TagAssignment -Category 'VR RPO').Tag.Name ){
{$_ -like "*ABR*"} {"ABR"}
{$_ -like "*:*"} {"VR"}
Default {$false}
}
Datacenter = ($VM | Get-Datacenter).Name
Disks = $VM | Get-HardDisk | Select-Object Name,CapacityGB,@{n='StorageFormat';e={$_.StorageFormat.ToString()}},@{n='Persistence';e={$_.Persistence.ToString()}}
}
$null = $VMStorageList.Add($VmObj)
}
$VMStorageList | ConvertTo-Json -Depth 5 | Out-File "C:\temp\VMs.json"
<#
Datastore:
Name
Capacity provisioned
Capacity used
Free capacity
Associated SAN device backing ( LUN Name )
Space Reclamation rate ( MB/s )
Datacenter
#>
$AllDatastores = Get-Datastore
$DatastoreList = [System.Collections.ArrayList]@()
ForEach($Datastore in $AllDatastores){
Write-Verbose -Message ("Start " + $Datastore.Name) -Verbose
#$Metadata = ($Datastore | Get-ScsiLun | Select-Object -First 1)
If ( $Datastore.ExtensionData.info.vmfs.UnmapBandwidthSpec.FixedValue){
# if reclamation rate is enabled at fixed rate, get that rate
$ReclamationRate = ("Enabled at fixed rate: " + $Datastore.ExtensionData.info.vmfs.UnmapBandwidthSpec.FixedValue + " MB/s")
} Else {
$ReclamationRate = "UnmapBandwidthSpec is null. Enabled at Low priority: Deleted or unmapped blocks are reclaimed on the LUN at low priority"
}
$DatastoreObj = [PSCustomObject]@{
Name = $Datastore.Name;
CapacityGB = $Datastore.CapacityGB;
UsedSpaceGB = ($Datastore.CapacityGB - $Datastore.FreeSpaceGB);
FreeSpaceGB = $Datastore.FreeSpaceGB;
CanonicalName = ($Datastore | Get-ScsiLun | Select-Object -First 1).CanonicalName;
SpaceReclamationRate = $ReclamationRate;
Datacenter = ($VMHostToUse | Get-Datacenter).Name
}
$null = $DatastoreList.Add($DatastoreObj)
}
$DatastoreList | ConvertTo-Json -Depth 5 | Out-File "C:\temp\Datastores.json"
@@ -0,0 +1,270 @@
<#
.SYNOPSIS
Daily HPE OneView enclosure and server inventory for PowerBI trending and lifecycle planning.
.DESCRIPTION
Iterates across all configured HPE OneView appliances, collecting enclosure and server
hardware metadata including compute capacity, power state, and server profile assignment.
Exports timestamped CSVs and inserts into SQL each run.
Append daily runs to build a historical dataset for PowerBI trend analysis and
physical hardware purchasing / lifecycle decisions.
Appliances processed:
itdoneviewp1.nd.gov - Rack servers only (no enclosures)
itdbissyncompp1.nd.gov - Synergy enclosures + servers
itdmdnsyncompp1.nd.gov - Synergy enclosures + servers
.NOTES
Run the following DDL once to create the destination tables:
DROP TABLE IF EXISTS [dbo].[VMware_Trends_Enclosure]
CREATE TABLE [dbo].[VMware_Trends_Enclosure] (
[ReportDate] DATETIME2 NOT NULL,
[ApplianceConnection] NVARCHAR(100) NULL,
[EnclosureName] NVARCHAR(255) NOT NULL,
[EnclosureModel] NVARCHAR(255) NULL,
[EnclosureSerialNumber] NVARCHAR(100) NULL,
[Status] NVARCHAR(50) NULL,
[DeviceBayCount] INT NULL
)
DROP TABLE IF EXISTS [dbo].[VMware_Trends_Server]
CREATE TABLE [dbo].[VMware_Trends_Server] (
[ReportDate] DATETIME2 NOT NULL,
[ApplianceConnection] NVARCHAR(100) NULL,
[EnclosureName] NVARCHAR(255) NULL,
[BayNumber] INT NULL,
[ServerHardwareName] NVARCHAR(255) NOT NULL,
[ServerName] NVARCHAR(255) NULL,
[ServerModel] NVARCHAR(255) NULL,
[ServerSerialNumber] NVARCHAR(100) NULL,
[Status] NVARCHAR(50) NULL,
[PowerState] NVARCHAR(50) NULL,
[ServerProfileName] NVARCHAR(255) NULL,
[ProcessorType] NVARCHAR(255) NULL,
[ProcessorCount] INT NULL,
[MemoryGB] DECIMAL(10,2) NULL,
[FormFactor] NVARCHAR(100) NULL
)
EnclosureName and BayNumber are NULL for rack-mounted servers not seated in an enclosure.
ServerName is the iLO/DNS hostname populated once a server profile is assigned.
#>
[CmdletBinding()]
param(
)
#region --- Setup ---------------------------------------------------------------
[string[]] $OVHostnames = @(
'itdoneviewp1.nd.gov',
'itdbissyncompp1.nd.gov',
'itdmdnsyncompp1.nd.gov'
)
[string] $OutputPath = 'C:\temp\OV_Trends\'
[string] $ServerInstance = 'itdintsql22p1.nd.gov\INTSQL22P1'
[string] $Database = 'ITD-Systems-Automation'
[string] $EnclosureTable = 'VMware_Trends_Enclosure'
[string] $ServerTable = 'VMware_Trends_Server'
[System.Management.Automation.PSCredential] $OVCredential = $PrvCred #$Secret:ndgov_svcitdvmhpe
[System.Management.Automation.PSCredential] $SqlCredential = $SqlCred #$Secret:sql_itdpsu1
$RunDate = Get-Date
$DateStamp = $RunDate.ToString('yyyyMMdd')
$Timestamp = $RunDate.ToString('yyyy-MM-dd')
if (-not (Test-Path -Path $OutputPath)) {
New-Item -ItemType Directory -Path $OutputPath | Out-Null
}
Start-Transcript -Path (Join-Path $OutputPath "OVServerInventory_$DateStamp.log") -Append
#endregion
#region --- Collect Data From All Appliances -----------------------------------
$AllEnclosureResults = [System.Collections.Generic.List[PSCustomObject]]::new()
$AllServerResults = [System.Collections.Generic.List[PSCustomObject]]::new()
foreach ($OVHostname in $OVHostnames) {
Write-Verbose "Connecting to HPE OneView: $OVHostname"
Connect-OVMgmt -Hostname $OVHostname -Credential $OVCredential -AuthLoginDomain nd.gov -LoginAcknowledge
#--- Enclosures ------------------------------------------------------------
Write-Verbose "[$OVHostname] Gathering enclosures..."
$Enclosures = Get-OVEnclosure
# Build URI map for server lookups (only populated if there are enclosures)
$EnclosureUriMap = @{}
foreach ($Enclosure in $Enclosures) {
$EnclosureUriMap[$Enclosure.uri] = $Enclosure.name
$AllEnclosureResults.Add([PSCustomObject]@{
ReportDate = $Timestamp
ApplianceConnection = $OVHostname
EnclosureName = $Enclosure.name
EnclosureModel = $Enclosure.model
EnclosureSerialNumber = $Enclosure.serialNumber
Status = $Enclosure.status
DeviceBayCount = ($Enclosure.deviceBays | Measure-Object).Count
})
}
#--- Servers ---------------------------------------------------------------
Write-Verbose "[$OVHostname] Gathering servers..."
$Servers = Get-OVServer | Where-Object { $_.serverName -like 'itdvm*' }
# Build profile URI map for this appliance
$ProfileUriMap = @{}
Get-OVServerProfile | ForEach-Object {
$ProfileUriMap[$_.uri] = $_.name
}
Write-Verbose "[$OVHostname] Processing $($Servers.Count) servers..."
foreach ($Server in $Servers) {
$EnclosureName = if ($Server.locationUri) {
$EnclosureUriMap[$Server.locationUri]
} else {
$null
}
$ProfileName = if ($Server.serverProfileUri) {
$ProfileUriMap[$Server.serverProfileUri]
} else {
$null
}
$MemoryGB = if ($null -ne $Server.memoryMb -and $Server.memoryMb -gt 0) {
[Math]::Round($Server.memoryMb / 1024, 2)
} else {
$null
}
$AllServerResults.Add([PSCustomObject]@{
ReportDate = $Timestamp
ApplianceConnection = $OVHostname
EnclosureName = $EnclosureName
BayNumber = if ($null -ne $Server.position) { [int]$Server.position } else { $null }
ServerHardwareName = $Server.name
ServerName = $Server.serverName
ServerModel = $Server.model
ServerSerialNumber = $Server.serialNumber
Status = $Server.status
PowerState = $Server.powerState
ServerProfileName = $ProfileName
ProcessorType = $Server.processorType
ProcessorCount = if ($null -ne $Server.processorCount) { [int]$Server.processorCount } else { $null }
MemoryGB = $MemoryGB
FormFactor = $Server.formFactor
})
}
Disconnect-OVMgmt
Write-Verbose "[$OVHostname] Disconnected."
}
#endregion
#region --- Export CSVs --------------------------------------------------------
$EnclosureCsv = Join-Path $OutputPath "OVEnclosures_$DateStamp.csv"
$ServerCsv = Join-Path $OutputPath "OVServers_$DateStamp.csv"
$AllEnclosureResults | Export-Csv -Path $EnclosureCsv -NoTypeInformation
$AllServerResults | Export-Csv -Path $ServerCsv -NoTypeInformation
Write-Verbose "Exported $($AllEnclosureResults.Count) enclosure records to: $EnclosureCsv"
Write-Verbose "Exported $($AllServerResults.Count) server records to: $ServerCsv"
#endregion
#region --- SQL Insert: Enclosures ---------------------------------------------
$EnclosureTable_DT = [System.Data.DataTable]::new()
$EnclosureColDefs = [ordered]@{
ReportDate = [datetime]
ApplianceConnection = [string]
EnclosureName = [string]
EnclosureModel = [string]
EnclosureSerialNumber = [string]
Status = [string]
DeviceBayCount = [int]
}
foreach ($Col in $EnclosureColDefs.GetEnumerator()) {
$Column = [System.Data.DataColumn]::new($Col.Key, $Col.Value)
$Column.AllowDBNull = $true
[void]$EnclosureTable_DT.Columns.Add($Column)
}
foreach ($Row in $AllEnclosureResults) {
$DataRow = $EnclosureTable_DT.NewRow()
foreach ($Col in $EnclosureColDefs.Keys) {
$Val = $Row.$Col
$DataRow[$Col] = if ($null -ne $Val) { $Val } else { [DBNull]::Value }
}
[void]$EnclosureTable_DT.Rows.Add($DataRow)
}
Write-SqlTableData -ServerInstance $ServerInstance -DatabaseName $Database -SchemaName 'dbo' `
-TableName $EnclosureTable -Credential $SqlCredential -InputData $EnclosureTable_DT
Write-Verbose "Inserted $($EnclosureTable_DT.Rows.Count) enclosure records into [$Database].[dbo].[$EnclosureTable]"
#endregion
#region --- SQL Insert: Servers ------------------------------------------------
$ServerTable_DT = [System.Data.DataTable]::new()
$ServerColDefs = [ordered]@{
ReportDate = [datetime]
ApplianceConnection = [string]
EnclosureName = [string]
BayNumber = [int]
ServerHardwareName = [string]
ServerName = [string]
ServerModel = [string]
ServerSerialNumber = [string]
Status = [string]
PowerState = [string]
ServerProfileName = [string]
ProcessorType = [string]
ProcessorCount = [int]
MemoryGB = [decimal]
FormFactor = [string]
}
foreach ($Col in $ServerColDefs.GetEnumerator()) {
$Column = [System.Data.DataColumn]::new($Col.Key, $Col.Value)
$Column.AllowDBNull = $true
[void]$ServerTable_DT.Columns.Add($Column)
}
foreach ($Row in $AllServerResults) {
$DataRow = $ServerTable_DT.NewRow()
foreach ($Col in $ServerColDefs.Keys) {
$Val = $Row.$Col
$DataRow[$Col] = if ($null -ne $Val) { $Val } else { [DBNull]::Value }
}
[void]$ServerTable_DT.Rows.Add($DataRow)
}
Write-SqlTableData -ServerInstance $ServerInstance -DatabaseName $Database -SchemaName 'dbo' `
-TableName $ServerTable -Credential $SqlCredential -InputData $ServerTable_DT
Write-Verbose "Inserted $($ServerTable_DT.Rows.Count) server records into [$Database].[dbo].[$ServerTable]"
#endregion
#region --- Cleanup ------------------------------------------------------------
Stop-Transcript
#endregion
@@ -0,0 +1,188 @@
<#
.SYNOPSIS
Daily VMware Cluster metadata report for PowerBI trending and capacity planning.
.DESCRIPTION
Collects cluster-level metadata from vCenter including DRS/HA configuration,
aggregate compute capacity, and effective resource availability.
Exports a timestamped CSV and inserts into SQL each run.
Append daily runs to build a historical dataset for PowerBI trend analysis.
.NOTES
Run the following DDL once to create the destination table:
DROP TABLE IF EXISTS [dbo].[VMware_Trends_Cluster]
CREATE TABLE [dbo].[VMware_Trends_Cluster] (
[ReportDate] DATETIME2 NOT NULL,
[ClusterName] NVARCHAR(255) NOT NULL,
[Datacenter] NVARCHAR(100) NULL,
[DrsEnabled] BIT NOT NULL,
[DrsMode] NVARCHAR(50) NULL,
[HaEnabled] BIT NOT NULL,
[HostCount] INT NULL,
[EffectiveHostCount] INT NULL,
[TotalCpuCores] INT NULL,
[TotalCpuMhz] INT NULL,
[EffectiveCpuMhz] INT NULL,
[TotalMemoryGB] DECIMAL(10,2) NULL,
[EffectiveMemoryGB] DECIMAL(10,2) NULL,
[UsedMemoryGB] DECIMAL(10,2) NULL,
[VMCount] INT NULL
)
TotalCpuMhz, EffectiveCpuMhz, TotalMemoryGB, and EffectiveMemoryGB come from
vCenter's cluster summary (real-time aggregate).
UsedMemoryGB is summed from each host's current MemoryUsageGB.
TotalCpuCores is summed from each host's hardware CpuInfo.
#>
[CmdletBinding()]
param(
)
#region --- Setup ---------------------------------------------------------------
[string] $OutputPath = 'C:\temp\VM_Trends\'
[string] $ServerInstance = 'itdintsql22p1.nd.gov\INTSQL22P1'
[string] $Database = 'ITD-Systems-Automation'
[string] $Table = 'VMware_Trends_Cluster'
[System.Management.Automation.PSCredential] $SqlCredential = $SqlCred #$Secret:sql_itdpsu1
$RunDate = Get-Date
$DateStamp = $RunDate.ToString('yyyyMMdd')
$Timestamp = $RunDate.ToString('yyyy-MM-dd')
if (-not (Test-Path -Path $OutputPath)) {
New-Item -ItemType Directory -Path $OutputPath | Out-Null
}
Start-Transcript -Path (Join-Path $OutputPath "ClusterMetadataReport_$DateStamp.log") -Append
#endregion
#region --- Build Cluster -> Datacenter Lookup ---------------------------------
Write-Verbose 'Building cluster-to-datacenter map...'
$ClusterDatacenterMap = @{}
Get-Datacenter | ForEach-Object {
$DatacenterName = $_.Name
Get-Cluster -Location $_ | ForEach-Object {
$ClusterDatacenterMap[$_.Name] = $DatacenterName
}
}
#endregion
#region --- Collect Cluster Data -----------------------------------------------
Write-Verbose 'Gathering clusters...'
$AllClusters = Get-Cluster
Write-Verbose "Processing $($AllClusters.Count) clusters..."
$Results = foreach ($Cluster in $AllClusters) {
$Summary = $Cluster.ExtensionData.Summary # reuse for all summary fields
#--- Aggregate host-level stats that vCenter summary does not expose
$ClusterHosts = Get-VMHost -Location $Cluster
$TotalCpuCores = ($ClusterHosts | ForEach-Object {
$_.ExtensionData.Hardware.CpuInfo.NumCpuCores
} | Measure-Object -Sum).Sum
$UsedMemoryGB = [Math]::Round(
($ClusterHosts | Measure-Object -Property MemoryUsageGB -Sum).Sum, 2
)
$VMCount = ($ClusterHosts | ForEach-Object {
($_.ExtensionData.Vm | Measure-Object).Count
} | Measure-Object -Sum).Sum
#--- Capacity from cluster summary
$TotalCpuMhz = $Summary.TotalCpu # MHz
$EffectiveCpuMhz = $Summary.EffectiveCpu # MHz
$TotalMemoryGB = [Math]::Round($Summary.TotalMemory / 1GB, 2) # bytes -> GB
$EffectiveMemGB = [Math]::Round($Summary.EffectiveMemory / 1KB, 2) # MB -> GB
[PSCustomObject]@{
ReportDate = $Timestamp
ClusterName = $Cluster.Name
Datacenter = $ClusterDatacenterMap[$Cluster.Name]
DrsEnabled = $Cluster.DrsEnabled
DrsMode = $Cluster.DrsAutomationLevel
HaEnabled = $Cluster.HAEnabled
HostCount = $Summary.NumHosts
EffectiveHostCount = $Summary.NumEffectiveHosts
TotalCpuCores = [int]$TotalCpuCores
TotalCpuMhz = $TotalCpuMhz
EffectiveCpuMhz = $EffectiveCpuMhz
TotalMemoryGB = $TotalMemoryGB
EffectiveMemoryGB = $EffectiveMemGB
UsedMemoryGB = $UsedMemoryGB
VMCount = [int]$VMCount
}
}
#endregion
#region --- Export CSV ---------------------------------------------------------
$OutputFile = Join-Path $OutputPath "ClusterMetadata_$DateStamp.csv"
$Results | Export-Csv -Path $OutputFile -NoTypeInformation
Write-Verbose "Exported $($Results.Count) cluster records to: $OutputFile"
#endregion
#region --- SQL Insert ---------------------------------------------------------
$DataTable = [System.Data.DataTable]::new()
$ColDefs = [ordered]@{
ReportDate = [datetime]
ClusterName = [string]
Datacenter = [string]
DrsEnabled = [bool]
DrsMode = [string]
HaEnabled = [bool]
HostCount = [int]
EffectiveHostCount = [int]
TotalCpuCores = [int]
TotalCpuMhz = [int]
EffectiveCpuMhz = [int]
TotalMemoryGB = [decimal]
EffectiveMemoryGB = [decimal]
UsedMemoryGB = [decimal]
VMCount = [int]
}
foreach ($Col in $ColDefs.GetEnumerator()) {
$Column = [System.Data.DataColumn]::new($Col.Key, $Col.Value)
$Column.AllowDBNull = $true
[void]$DataTable.Columns.Add($Column)
}
foreach ($Row in $Results) {
$DataRow = $DataTable.NewRow()
foreach ($Col in $ColDefs.Keys) {
$Val = $Row.$Col
$DataRow[$Col] = if ($null -ne $Val) { $Val } else { [DBNull]::Value }
}
[void]$DataTable.Rows.Add($DataRow)
}
$SqlParams = @{
ServerInstance = $ServerInstance
DatabaseName = $Database
SchemaName = 'dbo'
TableName = $Table
Credential = $SqlCredential
InputData = $DataTable
}
Write-SqlTableData @SqlParams
Write-Verbose "Inserted $($DataTable.Rows.Count) cluster records into [$Database].[dbo].[$Table]"
#endregion
#region --- Cleanup -------------------------------------------------------------
Stop-Transcript
#endregion
@@ -0,0 +1,212 @@
<#
.SYNOPSIS
Daily VMware Host metadata report for PowerBI trending and hardware capacity planning.
.DESCRIPTION
Collects ESXi host metadata from vCenter including hardware, compute capacity, and
version information. Exports a timestamped CSV and inserts into SQL each run.
Append daily runs to build a historical dataset for PowerBI trend analysis and
physical hardware purchasing / lifecycle decisions.
.NOTES
Run the following DDL once to create the destination table:
DROP TABLE IF EXISTS [dbo].[VMware_Trends_Host]
CREATE TABLE [dbo].[VMware_Trends_Host] (
[ReportDate] DATETIME2 NOT NULL,
[HostName] NVARCHAR(255) NOT NULL,
[Datacenter] NVARCHAR(100) NULL,
[Cluster] NVARCHAR(100) NULL,
[ConnectionState] NVARCHAR(50) NULL,
[PowerState] NVARCHAR(50) NULL,
[InMaintenanceMode] BIT NOT NULL,
[Model] NVARCHAR(255) NULL,
[ProcessorType] NVARCHAR(255) NULL,
[CpuSockets] INT NULL,
[CoresPerSocket] INT NULL,
[TotalCpuCores] INT NULL,
[CpuMhz] INT NULL,
[TotalCpuMhz] INT NULL,
[MemoryTotalGB] DECIMAL(10,2) NULL,
[MemoryUsageGB] DECIMAL(10,2) NULL,
[VMCount] INT NULL,
[EsxiVersion] NVARCHAR(50) NULL,
[EsxiBuild] NVARCHAR(50) NULL,
[UptimeDays] DECIMAL(10,2) NULL
)
MemoryUsageGB reflects real-time memory consumed by running VMs at the time of collection.
UptimeDays will be NULL for hosts that are powered off or disconnected.
#>
[CmdletBinding()]
param(
)
#region --- Setup ---------------------------------------------------------------
[string] $OutputPath = 'C:\temp\VM_Trends\'
[string] $ServerInstance = 'itdintsql22p1.nd.gov\INTSQL22P1'
[string] $Database = 'ITD-Systems-Automation'
[string] $Table = 'VMware_Trends_Host'
[System.Management.Automation.PSCredential] $SqlCredential = $SqlCred #$Secret:sql_itdpsu1
$RunDate = Get-Date
$DateStamp = $RunDate.ToString('yyyyMMdd')
$Timestamp = $RunDate.ToString('yyyy-MM-dd')
if (-not (Test-Path -Path $OutputPath)) {
New-Item -ItemType Directory -Path $OutputPath | Out-Null
}
Start-Transcript -Path (Join-Path $OutputPath "VMHostMetadataReport_$DateStamp.log") -Append
#endregion
#region --- Build VMHost -> Cluster/Datacenter Lookups (avoids per-host queries) -
Write-Verbose 'Building host-to-cluster and host-to-datacenter maps...'
$HostClusterMap = @{}
$HostDatacenterMap = @{}
Get-Datacenter | ForEach-Object {
$DatacenterName = $_.Name
Get-VMHost -Location $_ | ForEach-Object {
$HostDatacenterMap[$_.Name] = $DatacenterName
}
}
Get-Cluster | ForEach-Object {
$ClusterName = $_.Name
Get-VMHost -Location $_ | ForEach-Object {
$HostClusterMap[$_.Name] = $ClusterName
}
}
#endregion
#region --- Collect Host Data --------------------------------------------------
Write-Verbose 'Gathering hosts...'
$AllHosts = $HostDatacenterMap.Keys | ForEach-Object { Get-VMHost -Name $_ }
Write-Verbose "Processing $($AllHosts.Count) hosts..."
$Results = foreach ($VMHost in $AllHosts) {
$Ext = $VMHost.ExtensionData # single API object -- reuse for all fields
#--- CPU info from hardware summary
$CpuSockets = $Ext.Hardware.CpuInfo.NumCpuPackages
$TotalCpuCores = $Ext.Hardware.CpuInfo.NumCpuCores
$CoresPerSocket = if ($CpuSockets -gt 0) { [int]($TotalCpuCores / $CpuSockets) } else { $null }
$CpuMhz = $Ext.Hardware.CpuInfo.Hz / 1000000 # Hz -> MHz
$TotalCpuMhz = $Ext.Summary.Hardware.CpuMhz * $TotalCpuCores
#--- Memory
$MemoryTotalGB = [Math]::Round($VMHost.MemoryTotalGB, 2)
$MemoryUsageGB = [Math]::Round($VMHost.MemoryUsageGB, 2)
#--- VM count on this host right now
$VMCount = ($Ext.Vm | Measure-Object).Count
#--- Uptime (null when host is powered off / disconnected)
$UptimeDays = $null
$BootTime = $Ext.Runtime.BootTime
if ($null -ne $BootTime) {
$UptimeDays = [Math]::Round(($RunDate - $BootTime).TotalDays, 2)
}
[PSCustomObject]@{
ReportDate = $Timestamp
HostName = $VMHost.Name
Datacenter = $HostDatacenterMap[$VMHost.Name]
Cluster = $HostClusterMap[$VMHost.Name]
ConnectionState = $VMHost.ConnectionState
PowerState = $VMHost.PowerState
InMaintenanceMode = $VMHost.ExtensionData.Runtime.InMaintenanceMode
Model = $Ext.Hardware.SystemInfo.Model
ProcessorType = $VMHost.ProcessorType
CpuSockets = $CpuSockets
CoresPerSocket = $CoresPerSocket
TotalCpuCores = $TotalCpuCores
CpuMhz = [int]$CpuMhz
TotalCpuMhz = $TotalCpuMhz
MemoryTotalGB = $MemoryTotalGB
MemoryUsageGB = $MemoryUsageGB
VMCount = $VMCount
EsxiVersion = $VMHost.Version
EsxiBuild = $VMHost.Build
UptimeDays = $UptimeDays
}
}
#endregion
#region --- Export CSV ---------------------------------------------------------
$OutputFile = Join-Path $OutputPath "VMHostMetadata_$DateStamp.csv"
$Results | Export-Csv -Path $OutputFile -NoTypeInformation
Write-Verbose "Exported $($Results.Count) host records to: $OutputFile"
#endregion
#region --- SQL Insert ---------------------------------------------------------
$DataTable = [System.Data.DataTable]::new()
$ColDefs = [ordered]@{
ReportDate = [datetime]
HostName = [string]
Datacenter = [string]
Cluster = [string]
ConnectionState = [string]
PowerState = [string]
InMaintenanceMode = [bool]
Model = [string]
ProcessorType = [string]
CpuSockets = [int]
CoresPerSocket = [int]
TotalCpuCores = [int]
CpuMhz = [int]
TotalCpuMhz = [int]
MemoryTotalGB = [decimal]
MemoryUsageGB = [decimal]
VMCount = [int]
EsxiVersion = [string]
EsxiBuild = [string]
UptimeDays = [decimal]
}
foreach ($Col in $ColDefs.GetEnumerator()) {
$Column = [System.Data.DataColumn]::new($Col.Key, $Col.Value)
$Column.AllowDBNull = $true
[void]$DataTable.Columns.Add($Column)
}
foreach ($Row in $Results) {
$DataRow = $DataTable.NewRow()
foreach ($Col in $ColDefs.Keys) {
$Val = $Row.$Col
$DataRow[$Col] = if ($null -ne $Val) { $Val } else { [DBNull]::Value }
}
[void]$DataTable.Rows.Add($DataRow)
}
$SqlParams = @{
ServerInstance = $ServerInstance
DatabaseName = $Database
SchemaName = 'dbo'
TableName = $Table
Credential = $SqlCredential
InputData = $DataTable
}
Write-SqlTableData @SqlParams
Write-Verbose "Inserted $($DataTable.Rows.Count) host records into [$Database].[dbo].[$Table]"
#endregion
#region --- Cleanup -------------------------------------------------------------
Stop-Transcript
#endregion
@@ -0,0 +1,299 @@
<#
.SYNOPSIS
Daily VM metadata report for PowerBI trending and hardware capacity planning.
.DESCRIPTION
Collects VM metadata from vCenter including compute, storage, OS, and VMware Tools
information using only data available within vCenter (no direct guest connections).
Exports a timestamped CSV each run -- append daily runs to build a historical dataset
suitable for PowerBI trend analysis and physical hardware purchasing decisions.
.PARAMETER vCenterServers
One or more vCenter server hostnames. Defaults to itdvmvc1.nd.gov and itdvmvc2.nd.gov.
.PARAMETER DatacenterFilter
Wildcard filter applied to datacenter names. Defaults to 'Primary*'.
.PARAMETER OutputPath
Directory where CSV and log files are written.
Defaults to C:\ITDSCRIPT\Reports\VMMetadata.
.PARAMETER CredentialPath
Path to a saved PSCredential XML file for unattended/scheduled runs.
Create one interactively with:
Get-Credential | Export-Clixml -Path C:\ITDSCRIPT\Creds\vCenter.xml
When omitted the script prompts for credentials.
.EXAMPLE
# Interactive run
.\VMware-VMDailyMetadataReport.ps1
.EXAMPLE
# Scheduled / unattended run
.\VMware-VMDailyMetadataReport.ps1 -CredentialPath 'C:\ITDSCRIPT\Creds\vCenter.xml'
.NOTES
Run the following DDL once to create the destination table:
DROP TABLE IF EXISTS [dbo].[VMware_Trends_VM]
CREATE TABLE [dbo].[VMware_Trends_VM] (
[ReportDate] DATETIME2 NOT NULL,
[VMName] NVARCHAR(255) NOT NULL,
[Datacenter] NVARCHAR(100) NULL,
[Cluster] NVARCHAR(100) NULL,
[PowerState] NVARCHAR(50) NULL,
[IsSRMPlaceholder] BIT NOT NULL,
[StoragePlatform] NVARCHAR(100) NULL,
[GuestOS] NVARCHAR(255) NULL,
[vCPUs] INT NULL,
[MemoryGB] DECIMAL(10,2) NULL,
[ProvisionedSpaceGB] DECIMAL(12,2) NULL,
[UsedSpaceGB] DECIMAL(12,2) NULL,
[GuestDiskCapacityGB] DECIMAL(12,2) NULL,
[GuestDiskUsedGB] DECIMAL(12,2) NULL,
[ToolsRunningStatus] NVARCHAR(100) NULL,
[ToolsVersionStatus] NVARCHAR(100) NULL,
[ToolsVersion] NVARCHAR(50) NULL,
[Tag_DRProtection] NVARCHAR(100) NULL,
[Tag_AppName] NVARCHAR(255) NULL,
[Tag_VRDatastores] NVARCHAR(255) NULL,
[Tag_VRRPO] NVARCHAR(100) NULL,
[Tag_DTAP] NVARCHAR(50) NULL,
[Tag_StartupPriority] NVARCHAR(100) NULL,
[Tag_SRMRecoveryType] NVARCHAR(100) NULL,
[Tag_LicensingRestrictions] NVARCHAR(255) NULL
)
Guest OS disk capacity / used columns are NULL for powered-off VMs and SRM placeholders.
#>
[CmdletBinding()]
param(
)
#region --- Setup ---------------------------------------------------------------
[string] $OutputPath = 'C:\temp\VM_Trends\'
[string] $ServerInstance = 'itdintsql22p1.nd.gov\INTSQL22P1'
[string] $Database = 'ITD-Systems-Automation'
[string] $Table = 'VMware_Trends_VM'
[System.Management.Automation.PSCredential] $SqlCredential = $SqlCred #$Secret:sql_itdpsu1
[System.Management.Automation.PSCredential] $vCenterCredential = $PrvCred
$RunDate = Get-Date
$DateStamp = $RunDate.ToString('yyyyMMdd')
$Timestamp = $RunDate.ToString('yyyy-MM-dd')
if (-not (Test-Path -Path $OutputPath)) {
New-Item -ItemType Directory -Path $OutputPath | Out-Null
}
Start-Transcript -Path (Join-Path $OutputPath "VMMetadataReport_$DateStamp.log") -Append
#endregion
#region --- Build VMHost -> Cluster/Datacenter Lookups (avoids per-VM API calls) -
Write-Verbose 'Building host-to-cluster and host-to-datacenter maps...'
$HostClusterMap = @{}
$HostDatacenterMap = @{}
Get-Datacenter | ForEach-Object {
$DatacenterName = $_.Name
Get-VMHost -Location $_ | ForEach-Object {
$HostDatacenterMap[$_.Name] = $DatacenterName
}
}
Get-Cluster | ForEach-Object {
$ClusterName = $_.Name
Get-VMHost -Location $_ | ForEach-Object {
$HostClusterMap[$_.Name] = $ClusterName
}
}
#endregion
#region --- Collect VM Data -----------------------------------------------------
Write-Verbose "Gathering VMs"
# Include ALL VMs (SRM placeholders flagged via column, not excluded).
# vCLS agent VMs are excluded -- they are vSphere internal and not customer workloads.
$AllVMs = Get-VM | Where-Object { $_.Name -notlike 'vCLS*' }
#--- Pre-fetch all tag assignments in one API call (avoids per-VM Get-TagAssignment)
Write-Verbose 'Pre-fetching VM tag assignments...'
$TagLookup = @{}
Get-TagAssignment -Entity $AllVMs | ForEach-Object {
$VMId = $_.Entity.Id
$Cat = $_.Tag.Category.Name
$TagName = $_.Tag.Name
if (-not $TagLookup.ContainsKey($VMId)) { $TagLookup[$VMId] = @{} }
if ($TagLookup[$VMId].ContainsKey($Cat)) {
$TagLookup[$VMId][$Cat] += "; $TagName"
} else {
$TagLookup[$VMId][$Cat] = $TagName
}
}
Write-Verbose "Processing $($AllVMs.Count) VMs..."
$Results = foreach ($VM in $AllVMs) {
$Ext = $VM.ExtensionData # single API object -- reuse for all fields
#--- SRM placeholder detection
$IsSRMPlaceholder = $Ext.Summary.Config.ManagedBy.Type -eq 'placeholderVm'
#--- Cluster / Datacenter (null-safe: standalone hosts have no cluster entry)
$ClusterName = $HostClusterMap[$VM.VMHost.Name]
$DatacenterName = $HostDatacenterMap[$VM.VMHost.Name]
#--- Tag assignments (pre-fetched; null when category not assigned to this VM)
$VMTags = if ($TagLookup.ContainsKey($VM.Id)) { $TagLookup[$VM.Id] } else { @{} }
#--- Storage platform parsed from datastore name convention: VMCLUSTER_LUN_PLATFORM_Desc
# Segment 2 = storage platform identifier (e.g. FS92, A9K).
# Cluster grouping uses the compute Cluster column -- no need to re-derive it here.
$StoragePlatforms = foreach ($DSName in $Ext.Config.DatastoreUrl.Name) {
$Segments = $DSName -split '_'
if ($Segments.Count -ge 3) { $Segments[2] }
}
$StoragePlatform = ($StoragePlatforms | Sort-Object -Unique) -join '; '
#--- VMware Tools guest disk info
# Populated only when Tools is running; null otherwise.
$GuestDiskCapacityGB = $null
$GuestDiskUsedGB = $null
if ($Ext.Guest.Disk) {
$TotalCapBytes = ($Ext.Guest.Disk | Measure-Object -Property Capacity -Sum).Sum
$TotalFreeBytes = ($Ext.Guest.Disk | Measure-Object -Property FreeSpace -Sum).Sum
$GuestDiskCapacityGB = [Math]::Round($TotalCapBytes / 1GB, 2)
$GuestDiskUsedGB = [Math]::Round(($TotalCapBytes - $TotalFreeBytes) / 1GB, 2)
}
[PSCustomObject]@{
# --- Identity & grouping
ReportDate = $Timestamp # for PowerBI time-series/trend axis
VMName = $VM.Name
Datacenter = $DatacenterName
Cluster = $ClusterName
PowerState = $VM.PowerState
IsSRMPlaceholder = $IsSRMPlaceholder
StoragePlatform = $StoragePlatform
GuestOS = $Ext.Guest.GuestFullName
# --- Compute
vCPUs = $VM.NumCpu
MemoryGB = $VM.MemoryGB
# --- Datastore-level storage
# ProvisionedSpaceGB : maximum the VM could consume (thin disks counted at max size)
# UsedSpaceGB : bytes actually committed on datastores right now
ProvisionedSpaceGB = [Math]::Round($VM.ProvisionedSpaceGB, 2)
UsedSpaceGB = [Math]::Round($VM.UsedSpaceGB, 2)
# --- Guest OS-level storage (from VMware Tools; null when Tools not running)
# GuestDiskCapacityGB : sum of all volume capacities seen inside the guest
# GuestDiskUsedGB : sum of space consumed across those volumes
GuestDiskCapacityGB = $GuestDiskCapacityGB
GuestDiskUsedGB = $GuestDiskUsedGB
# --- VMware Tools
# ToolsRunningStatus : guestToolsRunning | guestToolsNotRunning | guestToolsExecutingScripts
# ToolsVersionStatus : guestToolsCurrent | guestToolsNeedUpgrade | guestToolsUnmanaged | guestToolsTooNew
# ToolsVersion : numeric build version string reported by vCenter
ToolsRunningStatus = $Ext.Guest.ToolsRunningStatus
ToolsVersionStatus = $Ext.Guest.ToolsVersionStatus
ToolsVersion = $Ext.Guest.ToolsVersion
# --- vCenter Tags
Tag_DRProtection = $VMTags['DR Protection']
Tag_AppName = $VMTags['AppName']
Tag_VRDatastores = $VMTags['VR Datastores']
Tag_VRRPO = $VMTags['VR RPO']
Tag_DTAP = $VMTags['DTAP']
Tag_StartupPriority = $VMTags['StartupPriority']
Tag_SRMRecoveryType = $VMTags['SRM Recovery Type']
Tag_LicensingRestrictions = $VMTags['LicensingRestrictions']
}
}
#endregion
<#region --- Export CSV ---------------------------------------------------------
$OutputFile = Join-Path $OutputPath "VMMetadata_$DateStamp.csv"
$Results | Export-Csv -Path $OutputFile -NoTypeInformation
Write-Verbose "Exported $($Results.Count) VM records to: $OutputFile"
#endregion
#>
#region --- SQL Insert ---------------------------------------------------------
# Build a typed DataTable so Write-SqlTableData knows each column's type
# even when nullable columns contain null values. Type inference from raw
# PSCustomObjects fails when the first row has a null in a numeric column.
$DataTable = [System.Data.DataTable]::new()
$ColDefs = [ordered]@{
ReportDate = [datetime]
VMName = [string]
Datacenter = [string]
Cluster = [string]
PowerState = [string]
IsSRMPlaceholder = [bool]
StoragePlatform = [string]
GuestOS = [string]
vCPUs = [int]
MemoryGB = [decimal]
ProvisionedSpaceGB = [decimal]
UsedSpaceGB = [decimal]
GuestDiskCapacityGB = [decimal]
GuestDiskUsedGB = [decimal]
ToolsRunningStatus = [string]
ToolsVersionStatus = [string]
ToolsVersion = [string]
Tag_DRProtection = [string]
Tag_AppName = [string]
Tag_VRDatastores = [string]
Tag_VRRPO = [string]
Tag_DTAP = [string]
Tag_StartupPriority = [string]
Tag_SRMRecoveryType = [string]
Tag_LicensingRestrictions = [string]
}
foreach ($Col in $ColDefs.GetEnumerator()) {
$Column = [System.Data.DataColumn]::new($Col.Key, $Col.Value)
$Column.AllowDBNull = $true
[void]$DataTable.Columns.Add($Column)
}
foreach ($Row in $Results) {
$DataRow = $DataTable.NewRow()
foreach ($Col in $ColDefs.Keys) {
$Val = $Row.$Col
$DataRow[$Col] = if ($null -ne $Val) { $Val } else { [DBNull]::Value }
}
[void]$DataTable.Rows.Add($DataRow)
}
$SqlParams = @{
ServerInstance = $ServerInstance
DatabaseName = $Database
SchemaName = 'dbo'
TableName = $Table
Credential = $SqlCredential
InputData = $DataTable
}
Write-SqlTableData @SqlParams
Write-Verbose "Inserted $($DataTable.Rows.Count) VM records into [$Database].[dbo].[$Table]"
#endregion
#region --- Cleanup -------------------------------------------------------------
Stop-Transcript
#endregion
@@ -0,0 +1,95 @@
$VMs = Get-VM | Where-Object { $_.ExtensionData.Summary.Config.ManagedBy.Type -ne "placeholderVm" }
$SettingName = @(
"tools.setInfo.sizeLimit",
"isolation.device.edit.disable",
"isolation.device.connectable.disable",
"isolation.tools.copy.disable",
"isolation.tools.dnd.disable",
"isolation.tools.setGUIOptions.enable",
"RemoteDisplay.vnc.enabled",
"isolation.tools.paste.disable",
"isolation.tools.diskShrink.disable",
"isolation.tools.diskWiper.disable",
"log.keepOld",
"log.rotateSize"
)
$Result = [System.Collections.ArrayList]@()
ForEach ($VM in $VMs) {
$GetAdvSetting = Get-AdvancedSetting -Entity $VM -Name $SettingName | select Entity, Name, Value
$obj = [PSCustomObject]@{
'Entity' = $VM.Name
"tools.setInfo.sizeLimit" = ($GetAdvSetting | Where-Object Name -EQ 'tools.setInfo.sizeLimit').Value
"isolation.device.edit.disable" = ($GetAdvSetting | Where-Object Name -EQ 'isolation.device.edit.disable').Value
"isolation.device.connectable.disable" = ($GetAdvSetting | Where-Object Name -EQ 'isolation.device.connectable.disable').Value
"isolation.tools.copy.disable" = ($GetAdvSetting | Where-Object Name -EQ 'isolation.tools.copy.disable').Value
"isolation.tools.dnd.disable" = ($GetAdvSetting | Where-Object Name -EQ 'isolation.tools.dnd.disable').Value
"isolation.tools.setGUIOptions.enable" = ($GetAdvSetting | Where-Object Name -EQ 'isolation.tools.setGUIOptions.enable').Value
"RemoteDisplay.vnc.enabled" = ($GetAdvSetting | Where-Object Name -EQ 'RemoteDisplay.vnc.enabled').Value
"isolation.tools.paste.disable" = ($GetAdvSetting | Where-Object Name -EQ 'isolation.tools.paste.disable').Value
"isolation.tools.diskShrink.disable" = ($GetAdvSetting | Where-Object Name -EQ 'isolation.tools.diskShrink.disable').Value
"isolation.tools.diskWiper.disable" = ($GetAdvSetting | Where-Object Name -EQ 'isolation.tools.diskWiper.disable').Value
"log.keepOld" = ($GetAdvSetting | Where-Object Name -EQ 'log.keepOld').Value
"log.rotateSize" = ($GetAdvSetting | Where-Object Name -EQ 'log.rotateSize').Value
}
$Result.Add($obj)
}
$Result
<# Blank Loop
ForEach-Object( ($Result | Where-Object { $_.Entity -notlike "vCLS*" -and $_.'' -ne "VALUE" }).Entity ) {
New-AdvancedSetting -Entity $VM -Name '' -Value TRUE -Confirm:$false -Force:$true
}
#>
# remediate VMs
ForEach ($VM in ($Result | Where-Object { $_.Entity -notlike "vCLS*" -and $_.'tools.setInfo.sizeLimit' -ne 1048576 }).Entity ) {
New-AdvancedSetting -Entity $VM -Name 'tools.setInfo.sizeLimit' -Value '1048576' -Confirm:$false -Force:$true
}
ForEach ($VM in ($Result | Where-Object { $_.Entity -notlike "vCLS*" -and $_.'isolation.device.edit.disable' -ne "TRUE" }).Entity ) {
New-AdvancedSetting -Entity $VM -Name 'isolation.device.edit.disable' -Value 'TRUE' -Confirm:$false -Force:$true
}
ForEach ($VM in ($Result | Where-Object { $_.Entity -notlike "vCLS*" -and $_.'isolation.device.connectable.disable' -ne "TRUE" }).Entity ) {
New-AdvancedSetting -Entity $VM -Name 'isolation.device.connectable.disable' -Value TRUE -Confirm:$false -Force:$true
}
ForEach ($VM in ($Result | Where-Object { $_.Entity -notlike "vCLS*" -and $_.'isolation.tools.copy.disable' -ne "TRUE" }).Entity ) {
New-AdvancedSetting -Entity $VM -Name 'isolation.tools.copy.disable' -Value 'TRUE' -Confirm:$false -Force:$true
}
ForEach ($VM in ($Result | Where-Object { $_.Entity -notlike "vCLS*" -and $_.'isolation.tools.dnd.disable' -ne "TRUE" }).Entity ) {
New-AdvancedSetting -Entity $VM -Name 'isolation.tools.dnd.disable' -Value 'TRUE' -Confirm:$false -Force:$true
}
ForEach ($VM in ($Result | Where-Object { $_.Entity -notlike "vCLS*" -and $_.'isolation.tools.setGUIOptions.enable' -ne "FALSE" }).Entity ) {
New-AdvancedSetting -Entity $VM -Name 'isolation.tools.setGUIOptions.enable' -Value 'FALSE' -Confirm:$false -Force:$true
}
ForEach ($VM in ($Result | Where-Object { $_.Entity -notlike "vCLS*" -and $_.'RemoteDisplay.vnc.enabled' -ne "FALSE" }).Entity ) {
New-AdvancedSetting -Entity $VM -Name 'RemoteDisplay.vnc.enabled' -Value 'FALSE' -Confirm:$false -Force:$true
}
ForEach ($VM in ($Result | Where-Object { $_.Entity -notlike "vCLS*" -and $_.'isolation.tools.paste.disable' -ne "TRUE" }).Entity ) {
New-AdvancedSetting -Entity $VM -Name 'isolation.tools.paste.disable' -Value 'TRUE' -Confirm:$false -Force:$true
}
ForEach ($VM in ($Result | Where-Object { $_.Entity -notlike "vCLS*" -and $_.'isolation.tools.diskShrink.disable' -ne "TRUE" }).Entity ) {
New-AdvancedSetting -Entity $VM -Name 'isolation.tools.diskShrink.disable' -Value 'TRUE' -Confirm:$false -Force:$true
}
ForEach ($VM in ($Result | Where-Object { $_.Entity -notlike "vCLS*" -and $_.'isolation.tools.diskWiper.disable' -ne "TRUE" }).Entity ) {
New-AdvancedSetting -Entity $VM -Name 'isolation.tools.diskWiper.disable' -Value 'TRUE' -Confirm:$false -Force:$true
}
ForEach ($VM in ($Result | Where-Object { $_.Entity -notlike "vCLS*" -and $_.'log.keepOld' -ne "10" }).Entity ) {
New-AdvancedSetting -Entity $VM -Name 'log.keepOld' -Value '10' -Confirm:$false -Force:$true
}
ForEach ($VM in ($Result | Where-Object { $_.Entity -notlike "vCLS*" -and $_.'log.rotateSize' -ne "1024000" }).Entity ) {
New-AdvancedSetting -Entity $VM -Name 'log.rotateSize' -Value '1024000' -Confirm:$false -Force:$true
}
@@ -0,0 +1,56 @@
$VMHostNames = @"
itdbisvm-gen05.nd.gov
"@
$VMHostNames = ConvertTo-Array -MultiLineString $VMHostNames
# set maintenance and disable alarms
Get-VMHost -Name $VMHostNames | Set-VMHost -State "Maintenance" -RunAsync
ForEach ($VMHostName in $VMHostNames) {
$GetVMHost = Get-VMHost -Name $VMHostname
$VIServer = $GetVMHost.Uid.Split('@')[1].Split(':')[0]
$alarmMgr = Get-View AlarmManager -Server $VIServer
$alarmEnabled = $GetVMHost.ExtensionData.AlarmActionsEnabled
if ($alarmEnabled -eq $true) {
$alarmMgr.EnableAlarmActions($GetVMHost.ExtensionData.MoRef, $false)
}
}
#Create Management Switch And Move Adapter
ForEach ($VMHostName in $VMHostNames) {
$vmnic0 = Get-VMHostNetworkAdapter -VMHost $VMHostName -Name "vmnic0"
$vmk0 = Get-VMHost $VMHostName | Get-VMHostNetworkAdapter -Name vmk0
New-VirtualSwitch -VMHost $VMHostName -Name "sSwitch-MGMT"
Get-VirtualSwitch -VMHost $VMHostName -Name "sSwitch-MGMT" | New-VirtualPortGroup -Name "sPG-MGMT"
$MGMTPG = Get-VirtualSwitch -VMHost $VMHostName -Name "sSwitch-MGMT" | Get-VirtualPortGroup -Name "sPG-MGMT"
$MGMTSwitch = Get-VirtualSwitch -VMHost $VMHostName -Name "sSwitch-MGMT"
Add-VirtualSwitchPhysicalNetworkAdapter -VMHostPhysicalNic $vmnic0 -VirtualSwitch $MGMTSwitch -Confirm:$false
Add-VirtualSwitchPhysicalNetworkAdapter -VMHostPhysicalNic $vmnic0 -VirtualSwitch $MGMTSwitch -VirtualNicPortgroup $MGMTPG -VMHostVirtualNic $vmk0 -Confirm:$false
}
# remove vmk1 and vmk2
ForEach ($VMHostName in $VMHostNames) {
Get-VMHost -Name $VMHostName | Get-VMHostNetworkAdapter -Name vmk1, vmk2 | Remove-VMHostNetworkAdapter -Confirm:$false
}
# remove distributed switches
$BackupVDSwitch = Get-VDSwitch -Name 'dvSwitch-SDC-Backup'
$DataVDSwitch = Get-VDSwitch -Name 'dvSwitch-SDC-Data-Server'
$vMotionVDSwitch = Get-VDSwitch -Name 'dvSwitch-SDC-VMotion'
$MgmtVDSwitch = Get-VDSwitch -Name 'dvSwitch-SDC-MGMT'
ForEach ($VMHostName in $VMHostNames) {
Remove-VDSwitchVMHost -VDSwitch $BackupVDSwitch -VMHost $VMHostName -Confirm:$false
Remove-VDSwitchVMHost -VDSwitch $DataVDSwitch -VMHost $VMHostName -Confirm:$false
Remove-VDSwitchVMHost -VDSwitch $vMotionVDSwitch -VMHost $VMHostName -Confirm:$false
Remove-VDSwitchVMHost -VDSwitch $MgmtVDSwitch -VMHost $VMHostName -Confirm:$false
}
# remove from inventory
ForEach ($VMHostName in $VMHostNames) {
Get-VMHost -Name $VMHostName | Remove-VMHost -Confirm:$false
}
# scrub DNS
# scrub Passwordstate
# scrub Active Directory
# send storage team request to remove SAN
# send cohesity team request to remove host mappings for backup vmkernels
@@ -0,0 +1,15 @@
$cluster = Get-Cluster
$hosti = $cluster | Get-VMHost
$report333 = foreach ($esxi in $hosti) {
Get-VMHosthba -VMHost $esxi -type FibreChannel | where{$_.STatus -eq 'online'} |
Select @{N="Host";E={$esxi.Name}},
@{N='HBA Node WWN';E={$wwn = "{0:X}" -f $_.NodeWorldWideName; (0..7 | %{$wwn.Substring($_*2,2)}) -join ':'}},
@{N='HBA Node WWP';E={$wwp = "{0:X}" -f $_.PortWorldWideName; (0..7 | %{$wwp.Substring($_*2,2)}) -join ':'}}
}
@@ -0,0 +1,188 @@
# VMhost Advanced Options -- see OneNote for documentation
# used to customize the first host of each model per datacenter (host profile will be extracted from this), run the entire code
# also used for customizations that made host profiles angry
# add to distributed switches first
# pre create the syslog folder for each host
# set the logdir datastore/path value using code below
# if this is not the first host per datacenter, stop after logdir value, host profile SHOULD do the rest
$VMHostName = 'itdvmmdntel08.nd.gov'
$VMHost = Get-VMHost -Name $VMHostName
$VMHostCluster = $VMHost | Get-Cluster
$VMHostDatacenter = $VMHost | Get-Datacenter
$EsxCli = Get-EsxCli -VMHost $VMHostName -V2
# set advanced settings
Get-VMHost -Name $VMHostName | Get-AdvancedSetting -Name UserVars.ESXiShellInteractiveTimeOut | Set-AdvancedSetting -Value 300 -Confirm:$false
Get-VMHost -Name $VMHostName | Get-AdvancedSetting -Name UserVars.ESXiShellTimeOut | Set-AdvancedSetting -Value 900 -Confirm:$false
Get-VMHost -Name $VMHostName | Get-AdvancedSetting -Name UserVars.DcuiTimeOut | Set-AdvancedSetting -Value 600 -Confirm:$false
Get-VMHost -Name $VMHostName | Get-AdvancedSetting -Name Config.HostAgent.plugins.solo.enableMob | Set-AdvancedSetting -Value false -Confirm:$false
Get-VMHost -Name $VMHostName | Get-AdvancedSetting -Name Config.HostAgent.plugins.hostsvc.esxAdminsGroupAutoAdd | Set-AdvancedSetting -Value false -Confirm:$false
Get-VMHost -Name $VMHostName | Get-AdvancedSetting -Name Config.HostAgent.plugins.hostsvc.esxAdminsGroup | Set-AdvancedSetting -Value "" -Confirm:$false
Get-VMHost -Name $VMHostName | Get-AdvancedSetting -Name Config.HostAgent.plugins.vimsvc.authValidateInterval | Set-AdvancedSetting -Value 90 -Confirm:$false
Get-VMHost -Name $VMHostName | Get-AdvancedSetting -Name Syslog.global.certificate.strictX509Compliance | Set-AdvancedSetting -Value true -Confirm:$false
Get-VMHost -Name $VMHostName | Get-AdvancedSetting -Name Syslog.global.logLevel | Set-AdvancedSetting -Value info -Confirm:$false
# scratch and syslog
switch ($VMHostDatacenter.Name) {
'Primary Datacenter' {
$ScratchPath = '/vmfs/volumes/5ef4c13d-6318953e-620e-6cc217314910/scratch'
$LogDirDatastore = 'VMALL1_006_FS92_SCRATCH'
}
'Secondary Datacenter' {
$ScratchPath = '/vmfs/volumes/5ef4be61-1084f19b-ca0a-6cc217314690/scratch'
$LogDirDatastore = 'VMALL2_007_FS92_SCRATCH'
}
'DCN Datacenter' {
$ScratchPath = '/vmfs/volumes/6463c3f5-1ffe01b3-3837-e0071befea78/scratch'
$LogDirDatastore = 'VMDCN1_40_V5K'
}
'Grand Forks Vantis' {
$ScratchPath = '[VMVNTS_040_V5K] syslog/itdvmgfvnts02'
$LogDirDatastore = 'VMVNTS_040_V5K'
}
'Test Primary Datacenter' {
$ScratchPath = '/vmfs/volumes/5f36e52c-93f96f5c-3c43-6cc2172ed4d0/scratch'
$LogDirDatastore = 'VMTEST_001_FS92_SCRATCH'
}
'Test Secondary Datacenter' {
$ScratchPath = '/vmfs/volumes/5f36e52c-93f96f5c-3c43-6cc2172ed4d0/scratch'
$LogDirDatastore = 'VMTEST_001_FS92_SCRATCH'
}
}
#Get-VMHost -Name $VMHostname | Get-AdvancedSetting -Name ScratchConfig.ConfiguredScratchLocation | Set-AdvancedSetting -Value ($ScratchPath + $VMhostName.split('.')[0]) -Confirm:$false
#Get-VMHost -Name $VMHostName | Get-AdvancedSetting -Name Syslog.global.logDir | Set-AdvancedSetting -Value "$LogDirDatastore] syslog" -Confirm:$false
#Get-VMHost -Name $VMHostName | Get-AdvancedSetting -Name Syslog.global.logDirUnique | Set-AdvancedSetting -Value true -Confirm:$false
# 2024 syslog values
$VMHostNameShort = $VMHostName.split('.')[0]
Get-VMHost -Name $VMHostName | Get-AdvancedSetting -Name Syslog.global.logDir | Set-AdvancedSetting -Value ("[$LogDirDatastore] syslog/$VMHostNameShort") -Confirm:$false
Get-VMHost -Name $VMHostName | Get-AdvancedSetting -Name Syslog.global.logDirUnique | Set-AdvancedSetting -Value false -Confirm:$false
Get-VMHost -Name $VMHostName | Get-AdvancedSetting -Name Syslog.global.logHost | Set-AdvancedSetting -Value "tcp://itdvmlogging1.nd.gov:514" -Confirm:$false
# Pub 1075 requirements, no longer included in host profile
Get-VMHost -Name $VMHostName | Get-AdvancedSetting -Name "Security.PasswordQualityControl" | Set-AdvancedSetting -Value "retry=3 min=disabled,disabled,disabled,disabled,14" -Confirm:$false
Get-VMHost -Name $VMHostName | Get-AdvancedSetting -Name "Security.AccountLockFailures" | Set-AdvancedSetting -Value "3" -Confirm:$false
Get-VMHost -Name $VMHostName | Get-AdvancedSetting -Name "Security.PasswordHistory" | Set-AdvancedSetting -Value "24" -Confirm:$false
# static routes for backups
switch ($VMHostDatacenter.Name) {
'Primary Datacenter' { $Environment = 'Production-General' }
'Secondary Datacenter' { $Environment = 'Production-General' }
'DCN Datacenter' { $Environment = 'Production-DCN' }
'Grand Forks Vantis' { $Environment = $null }
'Test Primary Datacenter' { $Environment = 'Sandbox' }
'Test Secondary Datacenter' { $Environment = 'Sandbox' }
}
switch ($Environment) {
'Production-General' {
$vmk0IP = (Resolve-DnsName -Name $VMHostName).IPAddress
$vmk1IP = '10.8.142.' + $vmk0IP.split('.')[3]
$vmk2IP = '10.2.170.' + $vmk0IP.split('.')[3]
}
}
switch ($VMHostDatacenter.Name) {
'Primary Datacenter' {
Get-VMHost -Name $VMHostname | New-VMHostNetworkAdapter -VirtualSwitch 'dvSwitch-PDC-VMotion' -PortGroup 'dvPG_PDC_VMotion' -IP $vmk1IP -SubnetMask 255.255.254.0 -VMotionEnabled $true
Get-VMHost -Name $VMHostname | New-VMHostNetworkAdapter -VirtualSwitch 'dvSwitch-PDC-Backup' -PortGroup 'dvPG_3534_10.2.170.0_24' -IP $vmk2IP -SubnetMask 255.255.255.0
}
'Secondary Datacenter' {
Get-VMHost -Name $VMHostname | New-VMHostNetworkAdapter -VirtualSwitch 'dvSwitch-SDC-VMotion' -PortGroup 'dvPG_SDC_VMotion' -IP $vmk1IP -SubnetMask 255.255.254.0 -VMotionEnabled $true
Get-VMHost -Name $VMHostname | New-VMHostNetworkAdapter -VirtualSwitch 'dvSwitch-SDC-Backup' -PortGroup 'dvPG_3534_10.2.170.0_24' -IP $vmk2IP -SubnetMask 255.255.255.0
}
'DCN Datacenter' {
}
'Grand Forks Vantis' {
}
}
# set vmkernel capabilities
Get-VMHostNetworkAdapter -VMHost $VMHostName -Name vmk0 | Set-VMHostNetworkAdapter -VSphereReplicationEnabled $true -VSphereReplicationNfcEnabled $true -Confirm:$false
Get-VMHostNetworkAdapter -VMHost $VMHostName -Name vmk1 | Set-VMHostNetworkAdapter -VMotionEnabled $true -Confirm:$false
Get-VMHostNetworkAdapter -VMHost $VMHostName -Name vmk2 | Set-VMHostNetworkAdapter -VSphereBackupNfcEnabled $true -Confirm:$false
# core dump - disable coredump file, enable network coredump
$CoreDumpArgs = $EsxCli.system.coredump.file.set.CreateArgs()
$CoreDumpArgs.enable = $false
$EsxCli.system.coredump.file.set.invoke($CoreDumpArgs)
$CoreDumpArgs = $EsxCli.system.coredump.network.set.CreateArgs()
$CoreDumpArgs.serverport = 6500
$CoreDumpArgs.interfacename = 'vmk0'
switch ($VMHostDatacenter.Name) {
'Primary Datacenter' { $CoreDumpArgs.serveripv4 = '10.8.145.25' }
'Secondary Datacenter' { $CoreDumpArgs.serveripv4 = '10.8.145.26' }
'DCN Datacenter' { $CoreDumpArgs.serveripv4 = '10.8.145.25' }
'Grand Forks Vantis' { $CoreDumpArgs.serveripv4 = '10.8.145.25' }
}
#$CoreDumpArgs.serveripv4 = '10.8.145.25'
$EsxCli.system.coredump.network.set.invoke($CoreDumpArgs)
$CoreDumpArgs = $EsxCli.system.coredump.network.set.CreateArgs()
$CoreDumpArgs.enable = $true
$EsxCli.system.coredump.network.set.invoke($CoreDumpArgs)
$EsxCli.system.coredump.network.get.invoke()
# ntp - set NTP server and set service to start/stop with host
Get-VMHost -Name $VMHostName | Add-VMHostNtpServer 10.2.7.40, 10.10.10.10
Get-VMHost -Name $VMHostName | Get-VMHostService | where { $_.Key -eq "ntpd" } | Set-VMHostService -Policy On
# static route for backups
$ParamsToAdd = @{
network = '10.2.169.0/24'
}
switch ($VMHostDatacenter.Name) {
'Primary Datacenter' { $ParamsToAdd.gateway = '10.2.170.1' }
'Secondary Datacenter' { $ParamsToAdd.gateway = '10.2.170.1' }
'DCN Datacenter' { $CoreDumpArgs.serveripv4 = '10.2.118.241' }
'Grand Forks Vantis' { $CoreDumpArgs.serveripv4 = '' }
}
$EsxCli.network.ip.route.ipv4.add.Invoke($ParamsToAdd)
<#$params = @{
network = '10.2.169.0/24' ## check subnet mask, should be /24 after collapsing the Cohesity subnets
gateway = '10.2.170.1' ## General 10.2.170.1, VDI 10.2.15.1, TEST 10.2.168.241 # DCN 10.2.118.241
} #>
#$x = $esxcli.network.ip.route.ipv4.list.Invoke() | Where-Object {$_.Interface -eq 'vmk2' -and $_.Network -eq '10.2.169.128'}
#$x | Add-Member -Name "Name" -MemberType NoteProperty -Value $VMHost.Name
#$null = $result.Add($x)
<## to remove static route
$paramsToRemove = @{
network = '10.2.169.0/24'
gateway = '10.2.170.1'
}
$EsxCli.network.ip.route.ipv4.remove.Invoke($paramsToRemove)
##>
# sshServer firewall
### 10.8.145.46 itdvmutilp3, 10.29.40.0/23 adminvpn
Get-VMHost -Name $VMHostName | Get-VMHostFirewallException -Name 'SSH Server' | Set-VMHostFirewallException -Enabled $true
$sshArgs = $EsxCli.network.firewall.ruleset.set.CreateArgs()
$sshArgs.enabled = $true
$sshArgs.allowedall = $false
$sshArgs.rulesetid = 'sshServer'
$EsxCli.network.firewall.ruleset.set.invoke($sshArgs)
$AllowedIpArgs = $EsxCli.network.firewall.ruleset.allowedip.add.CreateArgs()
$AllowedIpArgs.ipaddress = "10.8.145.46"
$AllowedIpArgs.rulesetid = 'sshServer'
$EsxCli.network.firewall.ruleset.allowedip.add.invoke($AllowedIpArgs)
$AllowedIpArgs = $EsxCli.network.firewall.ruleset.allowedip.add.CreateArgs()
$AllowedIpArgs.ipaddress = "10.29.40.0/23"
$AllowedIpArgs.rulesetid = 'sshServer'
$EsxCli.network.firewall.ruleset.allowedip.add.invoke($AllowedIpArgs)
(Get-VMHost -Name $VMHostName | Get-View).EnterLockdownMode()
<#ForEach($VMHostName in $VMHostNames){
write-warning $VMHostName
$EsxCli = Get-EsxCli -VMHost $VMHostName -V2
$esxcli.network.ip.route.ipv4.list.Invoke() | Where-Object {$_.Interface -eq 'vmk2' -and $_.Network -eq '10.2.169.128'}
}#>
@@ -0,0 +1,38 @@
$VMHostNames = @"
itdvmmdnwin11.nd.gov
itdvmmdnwin12.nd.gov
"@
$VMHostNames = ConvertTo-Array -MultiLineString $VMHostNames
ForEach ($VMHostName in $VMHostNames) {
$RootCred = $null
$RootCred = Get-ITDPassword -Title $VMHostName -UserName root -Credential $PrvCred
Disable-ITDVMwareVMHostFeature -Name $VMHostName -LockdownMode
$null = Connect-VIServer $VMHostName -Credential $RootCred
If (-not ($?)) {
Write-Warning ($VMHostName + " password failed")
}
else {
Disconnect-VIServer $VMHostName -Force -Confirm:$false
}
Enable-ITDVMwareVMHostFeature -Name $VMHostName -LockdownMode
}
$VMHostNames = @"
itdvmmdnwin11.nd.gov
itdvmmdnwin12.nd.gov
"@
$VMHostNames = ConvertTo-Array -MultiLineString $VMHostNames
$VmDefaultCred = Get-Secret VMDefault
ForEach($VMHostName in $VMHostNames){
Disable-ITDVMwareVMHostFeature -Name $VMHostName -LockdownMode
$VMHostCred = Get-ITDPassword -Title $VMHostName -UserName root -Credential $PrvCred
Connect-VIServer -Server $VMHostName -Credential $VmDefaultCred
Set-VMHostAccount -Server $VMHostName -UserAccount root -Password $VMHostCred.GetNetworkCredential().Password
Disconnect-VIServer -Server $VMHostname -Confirm:$false
Enable-ITDVMwareVMHostFeature -Name $VMHostName -LockdownMode
}
@@ -0,0 +1,3 @@
Get-VMHost | Select-Object Name,Model,MemoryTotalGB,ProcessorType,@{n='NumCpuPackages';e={$_.ExtensionData.Hardware.CpuInfo.NumCpuPackages}},@{n='CoresPerSocket';e={$_.ExtensionData.Hardware.CpuInfo.NumCpuCores / $_.ExtensionData.Hardware.CpuInfo.NumCpuPackages}},@{n='NumCpuCores';e={$_.ExtensionData.Hardware.CpuInfo.NumCpuCores}}
Get-Cluster | Where-Object {$_.Name -notlike "WINDOWS*" -or $_.Name -notlike "PS*" -or $_.Name -notlike "SQL*"} | Get-VM | Where-Object {$_.Guest.OSFullName -match "Windows"}
@@ -0,0 +1,363 @@
#----------------------------------------------------------------------------------------------------------------------------------------------------
$creds = Get-Credential
#Connect VC1
Connect-VIServer 'itdvmvc1.nd.gov' -Credential $creds
#Connect VC2
Connect-VIServer 'itdvmvc2.nd.gov' -Credential $creds
#Connect VCT1
Connect-VIServer 'itdvmvct1.nd.gov' -Credential $creds
#Connect VCT2
Connect-VIServer 'itdvmvct2.nd.gov' -Credential $creds
#Connect OneView
Connect-HPOVMgmt -Hostname 'itdoneviewp1.nd.gov' -Credential $creds -LoginAcknowledge
#----------------------------------------------------------------------------------------------------------------------------------------------------
#VMHosts to Patch
$VMHostNames = @"
itdvmmdnav04.nd.gov
itdvmmdnav05.nd.gov
"@
$VMHostNames = ConvertTo-Array -MultiLineString $VMHostNames
#----------------------------------------------------------------------------------------------------------------------------------------------------
#Disable Alarms and Disconnect CDROM
foreach ($VMHostName in $VMHostNames) {
$GetVMHost = Get-VMHost $VMHostName
#$VMHostParent = $GetVMHost.Parent
$HostCluster = Get-Cluster -VMHost $VMHostName
<#$NewSpec = New-Object VMware.Vim.ClusterConfigSpec
$NewSpec.DasConfig = New-Object VMware.Vim.ClusterDasConfigInfo
$NewSpec.DasConfig.AdmissionControlPolicy = New-Object VMware.Vim.ClusterFailoverResourcesAdmissionControlPolicy
$NewSpec.DasConfig.AdmissionControlPolicy.AutoComputePercentages = $true
$HostCluster.ExtensionData.ReconfigureCluster($NewSpec, $true)
#>
$VIServer = $GetVMHost.Uid.Split('@')[1].Split(':')[0]
$alarmMgr = Get-View AlarmManager -Server $VIServer
$alarmEnabled = $GetVMHost.ExtensionData.AlarmActionsEnabled
if ($alarmEnabled -eq $true) {
$alarmMgr.EnableAlarmActions($GetVMHost.ExtensionData.MoRef, $false)
}
$VMs = $GetVMHost | Get-VM
#Disconnect CDROM and/or VMtools ISO
foreach ($VM in $VMs) {
$GetVM = Get-VM $VM
$CDDrive = $GetVM | Get-CDDrive
if ($CDDrive | Where-Object { $_.IsoPath -Like "*vmware/isoimages*" }) {
$GetVM | Dismount-Tools
#$CDDrive | Set-CDDrive -NoMedia -Confirm:$false
}
elseif ($CDDrive.HostDevice -Like "*drive*") {
$CDDrive | Set-CDDrive -NoMedia -Confirm:$false
}
}
$GetVMHost = $null
}
#Move Powered Off VMs
foreach ($VMHostName in $VMHostNames) {
$VMHostDetails = Get-VMHost -Name $VMHostName
$VMHostParent = $VMHostDetails.Parent.Name
$VMHostMigrate = Get-Cluster $VMHostParent | Get-VMHost | Where-Object Name -NE $VMHostName | Select-Object -First 1
$VMsPoweredOff = Get-VMHost $VMHostName | Get-VM | Where-Object PowerState -EQ "PoweredOff"
If ($VMsPoweredOff) { Move-VM -VM $VMsPoweredOff -Destination $VMHostMigrate }
}
#Enter Maintenance Mode
Set-VMHost -VMHost $VMHostNames -State "Maintenance" -RunAsync
Start-Sleep -Seconds 10
#Monitor
Get-VMHost -Name $VMHostNames | Select-Object Name, ConnectionState, @{Name = "VM.count"; E = { @($_ | Get-VM | Where-Object { $_.ExtensionData.Summary.Config.ManagedBy.Type -NE "placeholderVm" }).Count } }
# Move to HostUpgradesInProgress Folder
Get-VMHost -Name $VMHostNames | Move-VMHost -Destination "HostUpgradesInProgress"
#----------------------------------------------------------------------------------------------------------------------------------------------------
#Shutdown Host
Stop-VMHost -VMHost $VMHostNames -Confirm:$false
#Monitor
Get-VMHost $VMHostNames | Select-Object -Property Name, ConnectionState, CpuUsageMhz
#----------------------------------------------------------------------------------------------------------------------------------------------------
#Verify OneView Server Profile Power State -EQ Off
<#foreach ($VMHostName in $VMHostNames){
$HPOVServerProfile = Get-HPOVServerProfile -Name $VMHostName
$HPOVServer = $HPOVServerProfile | Get-HPOVServer
if ($HPOVServer.powerState -EQ "On"){
$HPOVServer | Update-HPOVServer -Async
}
}#>
# ensure server power is off
foreach ($VMHostName in $VMHostNames) {
$HPOVServerProfile = Get-OVServerProfile -Name $VMHostName
$HPOVServer = $HPOVServerProfile | Get-OVServer
if ($HPOVServer.powerState -EQ "On") {
$HPOVServer | Update-OVServer -Async
}
}
#Monitor
foreach ($VMHostName in $VMHostNames) {
Get-OVServer -ServerName $VMHostName | Select-Object serverName, powerState
}
#----------------------------------------------------------------------------------------------------------------------------------------------------
#Join OneView Template to Host
$HPOVtemplates = Get-OVServerProfileTemplate
foreach ($VMHostName in $VMHostNames) {
$VMHostDetails = Get-VMHost -Name $VMHostName
$VMHostVIserver = $VMHostDetails.Uid.Split('@')[1].Split(':')[0]
switch ($VMHostVIserver) {
itdvmvc1.nd.gov { $HPOVtemplDataCenter = "BIS" }
Default { $HPOVtemplDataCenter = "MDN" }
}
$VMHostParent = $VMHostDetails.Parent.Name
<#switch ($VMHostParent.substring(0, $VMHostParent.Length - 1)) {
Avaya { $HPOVtemplType = "Avaya" }
TEL { $HPOVtemplType = "Avaya" }
DCN { $HPOVtemplType = "DCN" }
DES { $HPOVtemplType = "DES" }
Oracle { $HPOVtemplType = "Oracle" }
SQL { $HPOVtemplType = "SQL" }
SQL2-D { $HPOVtemplType = "SQL" }
TEST { $HPOVtemplType = "Test" }
Default { $HPOVtemplType = "General" }
}#>
If($VMHostName -like "*sql*" -or $VMHostName -like "*ora*"){
$HPOVtemplType = "SQL"
}
Else{
$HPOVtemplType = "General"
}
$HPOVtemplModel = $VMHostDetails.Model.Split()[2]
$NewHPOVtempl = $HPOVtemplates | Where-Object { $_.Name -Like "*$HPOVtemplDataCenter*" -and $_.Name -Like "*$HPOVtemplType*" -and $_.Name -Like "*$HPOVtemplModel*" } | Sort-Object Name | Select-Object -Last 1
Join-OVServerProfileToTemplate -Template $NewHPOVtempl -ServerProfile $VMHostName
}
#Monitor
foreach ($VMHostName in $VMHostNames) {
Get-OVServerProfile -Name $VMHostName
}
#----------------------------------------------------------------------------------------------------------------------------------------------------
#Check iLO Health Status
<#
foreach ($VMHostName in $VMHostNames){
$iLOHostName = ($VMHostName.split(".")[0])+"lo.nd.gov"
$iLoConnection = Connect-HPEiLO $iLOHostName -Credential $creds
Get-HPEiLOHealthSummary -Connection $iLoConnection | Select-Object Hostname,Status
Disconnect-HPEiLO -Connection $iLoConnection
}#>
#----------------------------------------------------------------------------------------------------------------------------------------------------
#Update OneView Server Template
foreach ($VMHostName in $VMHostNames) {
Get-OVServerProfile -Name $VMHostName | Update-OVServerProfile -Confirm:$false -Async
Start-Sleep -Seconds 30
}
#powershell finished in 20m, but continued to run for 36min
#Monitor
foreach ($VMHostName in $VMHostNames) {
Get-OVServerProfile -Name $VMHostName | Select-Object Name, State
}
#----------------------------------------------------------------------------------------------------------------------------------------------------
#Start OneView Server Profile
foreach ($VMHostName in $VMHostNames) {
$wait = $true
While ($wait -EQ $true) {
$HPOVServerProfile = Get-OVServerProfile -Name $VMHostName
if ($HPOVServerProfile.Status -NE "OK") {
$wait = $true
Start-Sleep -Seconds 60
}
else {
$wait = $false
$HPOVServerProfile | Start-OVServer -Async
}
}
}
#Monitor
foreach ($VMHostName in $VMHostNames) {
Get-OVServerProfile -Name $VMHostName
}
#----------------------------------------------------------------------------------------------------------------------------------------------------
# manual full install of v7.0u3 now
<# ISO connected from workstation via iLO -
boot @ 9:43
initial install screen @ 10:00
ISO connect from vmutil
boot @ 10:01
initial install screen @ 10:10
#>
# remove old from vcenter inventory
ForEach ($VMHostName in $VMHostNames) {
Get-VMHost -Name $VMHostName | Remove-VMHost -Confirm:$false
start-sleep -Seconds 3
}
# add to vcenter
$VmDefaultCred = Get-Secret VMDefault
ForEach ($VMHostName in $VMHostNames) {
Add-VMHost -Name $VMHostName -Credential $VmDefaultCred -Location "HostUpgradesInProgress" -Force -Server $ViServer
Start-Sleep -Seconds 3
}
# license host
Get-VMHost -Name $VMHostNames | Set-VMHost -LicenseKey '2M63H-8T391-P8YG4-00MR4-ARNP0'
# set maintenance and disable alarms
Get-VMHost -Name $VMHostNames | Set-VMHost -State "Maintenance" -RunAsync
ForEach ($VMHostName in $VMHostNames) {
$GetVMHost = Get-VMHost -Name $VMHostname
$VIServer = $GetVMHost.Uid.Split('@')[1].Split(':')[0]
$alarmMgr = Get-View AlarmManager -Server $VIServer
$alarmEnabled = $GetVMHost.ExtensionData.AlarmActionsEnabled
if ($alarmEnabled -eq $true) {
$alarmMgr.EnableAlarmActions($GetVMHost.ExtensionData.MoRef, $false)
}
}
# Set root password
ForEach ($VMHostName in $VMHostNames) {
$VMHostCred = Get-ITDPassword -Title $VMHostName -UserName root -Credential $PrvCred
Connect-VIServer -Server $VMHostName -Credential $VmDefaultCred
Set-VMHostAccount -Server $VMHostName -UserAccount root -Password $VMHostCred.GetNetworkCredential().Password
Disconnect-VIServer -Server $VMHostname -Confirm:$false
<#$EsxCli = Get-EsxCli -VMHost $VMHostName
/vmfs/volumes/5a737d2f-b45bb27d-7f74-e0071befea78/Scratch/itdbisvm-dcn01
$args = $EsxCli.system.account.set.CreateArgs()
$args.id = "root"
$args.password = $VMHostCred.GetNetworkCredential().Password
$args.passwordconfirmation = $VMHostCred.GetNetworkCredential().Password
$output = $EsxCli.system.account.set.invoke(@{
id = $VMHostCred.UserName;
password = $VMHostCred.GetNetworkCredential().Password;
passwordconfirmation = $VMHostCred.GetNetworkCredential().Password;
})#>
}
#Patch via Update Manager
#Monitor ConnectionState
foreach ($VMHostName in $VMHostNames) {
$VMHost = Get-VMHost $VMHostName
$VMHost | Select-Object -Property Name, ConnectionState
}
foreach ($VMHostName in $VMHostNames) {
$VMHost = Get-VMHost $VMHostName
$VMHostVIserver = $VMHost.Uid.Split('@')[1].Split(':')[0]
#$VMHostBaseline = Get-Baseline -Server $VMHostVIserver | Where-Object Name -Like "*ESXi 6.5.0*"
$VMHostBaselineUpgrade = Get-Baseline -Server $VMHostVIserver | Where-Object { $_.Name -EQ "vSphere 7.0U3-ProLiant" }
$VMHostBaselinePatch = Get-Baseline -Server $VMHostVIserver | Where-Object { $_.Name -EQ "vSphere 7.0U3 Patch" }
$VMHostBaselineAll = Get-Baseline -Server $VMHostVIserver | Where-Object { $_.Name -EQ "vSphere 7.0U3-ProLiant" -or $_.Name -EQ "7.0U3 Patch"}
Attach-Baseline -Baseline $VMHostBaselineUpgrade -Entity $VMHost
Attach-Baseline -Baseline $VMHostBaselinePatch -Entity $VMHost
}
#Remediate Baseline --- Do this in the GUI with all hosts in the same folder
<#
ForEach($VMHostName in $VMHostNames){
$VMHost = Get-VMHost $VMHostName
Scan-Inventory -Entity $VMHost
}
ForEach($VMHostName in $VMHostNames){
$VMHost = Get-VMHost $VMHostName
Stage-Patch -Entity $VMHost -Baseline $VMhostBaselineUpgrade
Stage-Patch -Entity $VMHost -Baseline $VMhostBaselinePatch -RunASync
}
ForEach($VMHostName in $VMHostNames){
$VMHost = Get-VMHost $VMHostName
Remediate-Inventory -Entity $VMHost -Baseline $VMHostBaselineAll -RunAsync -Confirm:$false
}#>
#Monitor
Get-Task | Where-Object Name -Like "*Remediate*"
#----------------------------------------------------------------------------------------------------------------------------------------------------
#Attach Host Profile and Test Compliance
foreach ($VMHostName in $VMHostNames) {
$CurrentHostProfiles = Get-VMHostProfile
$VMHostDetails = Get-VMHost -Name $VMHostName
$VMHostVIserver = $VMHostDetails.Uid.Split('@')[1].Split(':')[0]
switch ($VMHostVIserver) {
itdvmvc1.nd.gov { $VMHostVIserver = "BIS" }
Default { $VMHostVIServer = "MDN" }
}
$VMHostParent = $VMHostDetails.Parent.Name
switch ($VMHostParent.substring(0, $VMHostParent.Length - 1)) {
Avaya { $VMHostProfile = "Avaya" }
TEL { $VMHostProfile = "TEL" }
Default { $VMHostProfile = "General" }
}
#$VMHostBuild = $VMHostDetails.Build
#$VMHostVersion = $VMHostDetails.Version
#$VMHostProfileName = $CurrentHostProfiles | Where-Object {$_.Name -Like "*$VMHostVIserver*" -and $_.Name -Like "*$VMHostVersion*" -and $_.Name -Like "*$VMHostBuild*" -and $_.Name -Like "*$VMHostProfile*"} | Sort-Object Name | Select-Object -First 1
$VMHostProfileName = $CurrentHostProfiles | Where-Object { $_.Name -like "*$VMHostVIserver*" -and $_.Name -Like "*7.0.3*" -and $_.Name -like "*$VMHostProfile*" -and $_.Name -like "*BL460c*" }
Invoke-VMHostProfile -Entity $VMHostDetails -Profile $VMHostProfileName -AssociateOnly -Confirm:$false
}
# import host customization csv
foreach ($VMHostName in $VMHostNames) {
Get-VMHost -Name $VMHostName | Test-VMHostProfileCompliance
}
#Remediate Host Profile
foreach ($VMHostName in $VMHostNames) {
$VMHostDetails = Get-VMHost -Name $VMHostName
$VMHostProfileCompliance = $VMhostDetails | Test-VMHostProfileCompliance #### ???????
if ($VMHostProfileCompliance.ExtensionData.ComplianceStatus -Like "*non*") {
Invoke-VMHostProfile -Entity $VMhostDetails -Confirm:$false
}
$VMhostDetails | Test-VMHostProfileCompliance
}
# reboot hosts 0_Offline, Before Upgrade v7.0U3h
Get-VMHost -Name $VMHostNames | Restart-VMHost -Confirm:$false
#Test Host Profile Compliance
foreach ($VMHostName in $VMHostNames) {
Get-VMHost $VMHostName | Test-VMHostProfileCompliance
}
# maybe reboot again sometimes maybe
Get-VMHost -Name $VMHostNames | Restart-VMHost -Confirm:$false
#Exit Maintenance Mode and Enable Alarms
Set-VMHost -VMHost $VMHostNames -State "Connected" -RunAsync
Start-Sleep -Seconds 30
foreach ($VMHostName in $VMHostNames) {
$GetVMHost = Get-VMHost $VMHostName
$VIServer = $GetVMHost.Uid.Split('@')[1].Split(':')[0]
$alarmMgr = Get-View AlarmManager -Server $VIServer
$alarmEnabled = $GetVMHost.ExtensionData.AlarmActionsEnabled
if ($alarmEnabled -eq $false) {
$alarmMgr.EnableAlarmActions($GetVMHost.ExtensionData.MoRef, $true)
}
$GetVMHost = $null
}
#----------------------------------------------------------------------------------------------------------------------------------------------------
#----------------------------------------------------------------------------------------------------------------------------------------------------
#----------------------------------------------------------------------------------------------------------------------------------------------------
#----------------------------------------------------------------------------------------------------------------------------------------------------
#----------------------------------------------------------------------------------------------------------------------------------------------------
#----------------------------------------------------------------------------------------------------------------------------------------------------
#----------------------------------------------------------------------------------------------------------------------------------------------------
#----------------------------------------------------------------------------------------------------------------------------------------------------
#----------------------------------------------------------------------------------------------------------------------------------------------------
#----------------------------------------------------------------------------------------------------------------------------------------------------
#----------------------------------------------------------------------------------------------------------------------------------------------------
#----------------------------------------------------------------------------------------------------------------------------------------------------
#$VMCluster = Get-Cluster $VMHostParent #| Set-Cluster -HAAdmissionControlEnabled:$false -Confirm:$false
#$HAFailoverHost = Get-VMHost | Where-Object {$_.Id -Match ((Get-Cluster $VMHostParent).extensiondata.configuration.dasconfig.admissioncontrolpolicy.failoverhosts.value)}
#get-vmhost | where-object {$_.id -eq ($vmcluster.extensiondata.configuration.dasconfig.admissioncontrolpolicy.failoverhosts.value)}
<#
foreach ($VMHostProfile in $VMHostProfiles){
Export-VMHostProfile -FilePath $FilePath$Profile".xml" -Profile $VMHostProfile
}
Import-VMHostProfile -FilePath $FilePath"TestHostProfile.xml" -Name "Test Scripting"
#>
@@ -0,0 +1,481 @@
#----------------------------------------------------------------------------------------------------------------------------------------------------
$creds = Get-Credential
#Connect VC1
Connect-VIServer 'itdvmvc1.nd.gov' -Credential $creds
#Connect VC2
Connect-VIServer 'itdvmvc2.nd.gov' -Credential $creds
#Connect VCT1
Connect-VIServer 'itdvmvct1.nd.gov' -Credential $creds
#Connect VCT2
Connect-VIServer 'itdvmvct2.nd.gov' -Credential $creds
#Connect OneView
Connect-HPOVMgmt -Hostname 'itdoneviewp1.nd.gov' -Credential $creds -LoginAcknowledge
#----------------------------------------------------------------------------------------------------------------------------------------------------
#VMHosts to Patch
$VMHostNames = @"
itdvmbiswin19.nd.gov
itdvmbislin10.nd.gov
itdvmbiswas08.nd.gov
itdvmbissql14.nd.gov
itdvmbissql15.nd.gov
itdvmbistel09.nd.gov
itdvmbisvapp04.nd.gov
itdvmbissqla02.nd.gov
itdvmbiswas09.nd.gov
itdvmbiswin08.nd.gov
itdvmbiswin14.nd.gov
itdvmbisps18.nd.gov
"@
$VMHostNames = ConvertTo-Array -MultiLineString $VMHostNames
#----------------------------------------------------------------------------------------------------------------------------------------------------
#Disable Alarms and Disconnect CDROM
foreach ($VMHostName in $VMHostNames) {
Write-Warning -Message ("Start $VMHostName")
$GetVMHost = Get-VMHost $VMHostName
#$VMHostParent = $GetVMHost.Parent
#$HostCluster = Get-Cluster -VMHost $VMHostName
<#$NewSpec = New-Object VMware.Vim.ClusterConfigSpec
$NewSpec.DasConfig = New-Object VMware.Vim.ClusterDasConfigInfo
$NewSpec.DasConfig.AdmissionControlPolicy = New-Object VMware.Vim.ClusterFailoverResourcesAdmissionControlPolicy
$NewSpec.DasConfig.AdmissionControlPolicy.AutoComputePercentages = $true
$HostCluster.ExtensionData.ReconfigureCluster($NewSpec, $true)
#>
$VIServer = $GetVMHost.Uid.Split('@')[1].Split(':')[0]
$alarmMgr = Get-View AlarmManager -Server $VIServer
$alarmEnabled = $GetVMHost.ExtensionData.AlarmActionsEnabled
if ($alarmEnabled -eq $true) {
$alarmMgr.EnableAlarmActions($GetVMHost.ExtensionData.MoRef, $false)
}
$VMs = $GetVMHost | Get-VM
#Disconnect CDROM and/or VMtools ISO
foreach ($VM in $VMs) {
$GetVM = Get-VM $VM
$CDDrive = $GetVM | Get-CDDrive
if ($CDDrive | Where-Object { $_.IsoPath -Like "*vmware/isoimages*" }) {
$GetVM | Dismount-Tools
#$CDDrive | Set-CDDrive -NoMedia -Confirm:$false
}
elseif ($CDDrive.HostDevice -Like "*drive*") {
$CDDrive | Set-CDDrive -NoMedia -Confirm:$false
}
}
$GetVMHost = $null
}
#Move Powered Off VMs
foreach ($VMHostName in $VMHostNames) {
$VMHostDetails = Get-VMHost -Name $VMHostName
$VMHostParent = $VMHostDetails.Parent.Name
$VMHostMigrate = Get-Cluster $VMHostParent | Get-VMHost | Where-Object Name -NE $VMHostName | Select-Object -First 1
$VMsPoweredOff = Get-VMHost $VMHostName | Get-VM | Where-Object PowerState -EQ "PoweredOff"
If ($VMsPoweredOff) { Move-VM -VM $VMsPoweredOff -Destination $VMHostMigrate }
}
#Enter Maintenance Mode
Set-VMHost -VMHost $VMHostNames -State "Maintenance" -RunAsync
#Monitor
Get-VMHost -Name $VMHostNames | Sort-Object Name | Select-Object Name, ConnectionState, @{Name = "VM.count"; E = { @($_ | Get-VM | Where-Object { $_.ExtensionData.Summary.Config.ManagedBy.Type -NE "placeholderVm" }).Count } }
# Move to HostUpgradesInProgress Folder ??? -- if host is moved out of the cluster, may break affinity rules
#Get-VMHost -Name $VMHostNames | Move-VMHost -Destination "HostUpgradesInProgress"
#----------------------------------------------------------------------------------------------------------------------------------------------------
#Shutdown Host
Stop-VMHost -VMHost $VMHostNames -Confirm:$false
#Monitor
Get-VMHost $VMHostNames | Select-Object -Property Name, ConnectionState, CpuUsageMhz
#----------------------------------------------------------------------------------------------------------------------------------------------------
##Verify OneView Server Profile Power State -EQ Off
#<#foreach ($VMHostName in $VMHostNames){
# $HPOVServerProfile = Get-HPOVServerProfile -Name $VMHostName
# $HPOVServer = $HPOVServerProfile | Get-HPOVServer
# if ($HPOVServer.powerState -EQ "On"){
# $HPOVServer | Update-HPOVServer -Async
# }
# }#>
#
## ensure server power is off
#foreach ($VMHostName in $VMHostNames) {
# $HPOVServerProfile = Get-OVServerProfile -Name $VMHostName.Split('.')[0]
# $HPOVServer = $HPOVServerProfile | Get-OVServer
# if ($HPOVServer.powerState -EQ "On") {
# $HPOVServer | Update-OVServer -Async
# }
#}
##Monitor
#foreach ($VMHostName in $VMHostNames) {
# Get-OVServer -ServerName $VMHostName.split('.')[0] | Select-Object serverName, powerState
#}
##----------------------------------------------------------------------------------------------------------------------------------------------------
##Join OneView Template to Host
#$HPOVtemplates = Get-OVServerProfileTemplate
#foreach ($VMHostName in $VMHostNames) {
# $VMHostDetails = Get-VMHost -Name $VMHostName
# <#$VMHostVIserver = $VMHostDetails.Uid.Split('@')[1].Split(':')[0]
# switch ($VMHostVIserver) {
# itdvmvc1.nd.gov { $HPOVtemplDataCenter = "BIS" }
# Default { $HPOVtemplDataCenter = "MDN" }
# }#>
# $VMHostParent = $VMHostDetails.Parent.Name
# switch ($VMHostParent.substring(0, $VMHostParent.Length - 1)) {
# Avaya { $HPOVtemplType = "Avaya" }
# TEL { $HPOVtemplType = "Avaya" }
# DCN { $HPOVtemplType = "DCN" }
# DES { $HPOVtemplType = "DES" }
# Oracle { $HPOVtemplType = "Oracle" }
# SQL { $HPOVtemplType = "SQL" } # database
# SQL2-D { $HPOVtemplType = "SQL" }
# TEST { $HPOVtemplType = "Test" }
# Default { $HPOVtemplType = "General" }
# }
# $HPOVtemplModel = $VMHostDetails.Model.Split()[2]
# $NewHPOVtempl = $HPOVtemplates | Where-Object { $_.Name -Like "*$HPOVtemplDataCenter*" -and $_.Name -Like "*$HPOVtemplType*" -and $_.Name -Like "*$HPOVtemplModel*" } | Sort-Object Name | Select-Object -Last 1
# Join-OVServerProfileToTemplate -Template $NewHPOVtempl -ServerProfile $VMHostName.Split('.')[0]
#}
##Monitor
#foreach ($VMHostName in $VMHostNames) {
# Get-OVServerProfile -Name $VMHostName.Split('.')[0]
#}
##----------------------------------------------------------------------------------------------------------------------------------------------------
##Check iLO Health Status
#<#
# foreach ($VMHostName in $VMHostNames){
# $iLOHostName = ($VMHostName.split(".")[0])+"lo.nd.gov"
# $iLoConnection = Connect-HPEiLO $iLOHostName -Credential $creds
# Get-HPEiLOHealthSummary -Connection $iLoConnection | Select-Object Hostname,Status
# Disconnect-HPEiLO -Connection $iLoConnection
# }#>
##----------------------------------------------------------------------------------------------------------------------------------------------------
##Update OneView Server Template
#foreach ($VMHostName in $VMHostNames) {
# Get-OVServerProfile -Name $VMHostName.Split('.')[0] | Update-OVServerProfile -Confirm:$false -Async
# Start-Sleep -Seconds 30
#}
##powershell finished in 20m, but continued to run for 36min
##Monitor
#foreach ($VMHostName in $VMHostNames) {
# Get-OVServerProfile -Name $VMHostName | Select-Object Name, State
#}
##----------------------------------------------------------------------------------------------------------------------------------------------------
##Start OneView Server Profile
#foreach ($VMHostName in $VMHostNames) {
# #$wait = $true
# #While ($wait -EQ $true) {
# $HPOVServerProfile = Get-OVServerProfile -Name $VMHostName.split('.')[0]
# #if ($HPOVServerProfile.Status -NE "OK") {
# #$wait = $true
# #Start-Sleep -Seconds 60
# #}
# #else {
# #$wait = $false
# $HPOVServerProfile | Start-OVServer -Async
# Start-Sleep -Seconds 5
# #}
# #}
#}
#
## mount ISO in iLO
#
##Monitor
#foreach ($VMHostName in $VMHostNames) {
# Get-OVServerProfile -Name $VMHostName.Split('.')[0]
#}
##----------------------------------------------------------------------------------------------------------------------------------------------------
## manual full install of v7.0u3 now
#<# ISO connected from workstation via iLO -
# boot @ 9:43
# initial install screen @ 10:00
# ISO connect from vmutil
# boot @ 10:01
# initial install screen @ 10:10
##>
# remove old from vcenter inventory
ForEach ($VMHostName in $VMHostNames) {
Get-VMHost -Name $VMHostNames | Remove-VMHost -Confirm:$false
}
# add to vcenter
$VmDefaultCred = Get-Secret VMDefault
ForEach ($VMHostName in $VMHostNames) {
Add-VMHost -Name $VMHostName -Credential $VmDefaultCred -Location "Secondary Datacenter" -Server $VIServer -Force
}
# license host
Get-VMHost -Name $VMHostNames | Set-VMHost -LicenseKey 'M04W3-FEJ0H-P8J61-LMRKH-C4D1K'
# not avaya '2M63H-8T391-P8YG4-00MR4-ARNP0'
# avaya '3001L-FT19L-28PGX-099A2-2XQNH'
# VDI Desktop 'L56AQ-0VH1K-488GT-0NQU2-ADG64'
Start-Sleep -seconds 3
# set maintenance and disable alarms
Get-VMHost -Name $VMHostNames | Set-VMHost -State "Maintenance" -RunAsync
ForEach ($VMHostName in $VMHostNames) {
$GetVMHost = Get-VMHost -Name $VMHostname
$VIServer = $GetVMHost.Uid.Split('@')[1].Split(':')[0]
$alarmMgr = Get-View AlarmManager -Server $VIServer
$alarmEnabled = $GetVMHost.ExtensionData.AlarmActionsEnabled
if ($alarmEnabled -eq $true) {
$alarmMgr.EnableAlarmActions($GetVMHost.ExtensionData.MoRef, $false)
}
}
# Set root password
ForEach ($VMHostName in $VMHostNames) {
$VMHostCred = Get-ITDPassword -Title $VMHostName -UserName root -Credential $PrvCred
Connect-VIServer -Server $VMHostName -Credential $VmDefaultCred
Set-VMHostAccount -Server $VMHostName -UserAccount root -Password $VMHostCred.GetNetworkCredential().Password
Disconnect-VIServer -Server $VMHostname -Confirm:$false
<#
$EsxCli = Get-EsxCli -VMHost $VMHostName
$args = $EsxCli.system.account.set.CreateArgs()
$args.id = "root"
$args.password = $VMHostCred.GetNetworkCredential().Password
$args.passwordconfirmation = $VMHostCred.GetNetworkCredential().Password
$output = $EsxCli.system.account.set.invoke(@{
id = $VMHostCred.UserName;
password = $VMHostCred.GetNetworkCredential().Password;
passwordconfirmation = $VMHostCred.GetNetworkCredential().Password;
})
#>
}
# M.2 drives only, remove datastore1 from vmhost .... will get errors but still work
ForEach($VMHostName in $VMHostNames){
Remove-Datastore -Datastore "datastore1*" -VMHost $VMHostName -Confirm:$false
}
#Patch via Update Manager
#Monitor ConnectionState
foreach ($VMHostName in $VMHostNames) {
$VMHost = Get-VMHost $VMHostName
$VMHost | Select-Object -Property Name, ConnectionState
}
foreach ($VMHostName in $VMHostNames) {
$VMHost = Get-VMHost $VMHostName
$VMHostVIserver = $VMHost.Uid.Split('@')[1].Split(':')[0]
#$VMHostBaseline = Get-Baseline -Server $VMHostVIserver | Where-Object Name -Like "*ESXi 6.5.0*"
$VMHostBaselineUpgrade = Get-Baseline -Server $VMHostVIserver | Where-Object { $_.Name -EQ "vSphere 7.0U3-Synergy" }
$VMHostBaselinePatch = Get-Baseline -Server $VMHostVIserver | Where-Object { $_.Name -EQ "vSphere 7.0U3-Patch" }
$VMHostBaselineTools = Get-Baseline -Server $VMHostVIserver | Where-Object {$_.Name -EQ "VMware Tools"}
$VMHostBaselineAll = Get-Baseline -Server $VMHostVIserver | Where-Object { $_.Name -EQ "vSphere 7.0U3-Synergy" -or $_.Name -EQ "vSphere 7.0U3-Patch" -or $_.Name -EQ "VMware Tools"}
Attach-Baseline -Baseline $VMHostBaselineUpgrade -Entity $VMHost
Attach-Baseline -Baseline $VMHostBaselinePatch -Entity $VMHost
Attach-Baseline -Baseline $VMHostBaselineTools -Entity $VMHost
}
#Remediate Baseline # do manually with VUM on the Host Folder
ForEach($VMHostName in $VMHostNames){
$VMHost = Get-VMHost $VMHostName
Scan-Inventory -Entity $VMHost -RunASync
}
Foreach ($VMHostName in $VMHostNames){
$VMHost = Get-VMHost $VMHostName
#Stage-Patch -Entity $VMHost -Baseline $VMhostBaselineUpgrade -RunAsync
Stage-Patch -Entity $VMHost -Baseline $VMhostBaselinePatch -RunASync
Stage-Patch -Entity $VMHost -Baseline $VMHostBaselineTools -RunASync
}
ForEach ($VMHostName in $VMHostNames){
$VMHost = Get-VMHost $VMHostName
Remediate-Inventory -Entity $VMHost -Baseline $VMHostBaselinePatch -RunAsync -Confirm:$false
}
ForEach ($VMHostName in $VMHostNames){
$VMHost = Get-VMHost $VMHostName
Remediate-Inventory -Entity $VMHost -Baseline $VMHostBaselineTools -RunAsync -Confirm:$false
}#>
ForEach ($VMHostName in $VMHostNames){
$VMHost = Get-VMHost $VMHostName
Remediate-Inventory -Entity $VMHost -Baseline $VMHostBaselineAll -RunAsync -Confirm:$false
}
#Monitor
Get-Task | Where-Object Name -Like "*Remediate*"
#----------------------------------------------------------------------------------------------------------------------------------------------------
<# 2024/07/30 attach, test, invoke that works
$VMHosts = Get-Datacenter -Name Primary* | Get-VMHost | where-object Name -notlike "*av*"
ForEach($VMHost in $VMHosts){
Write-Warning -Message ("Start" + $VMHost.Name)
$VMHost | Invoke-VMHostProfile -Profile $HostProfile -AssociateOnly -Confirm:$false
$VMHost | Test-VMHostProfileCompliance
}
ForEach($VMHost in $VMHosts){
$VMHost | Invoke-VMHostProfile -Confirm:$false
}
#>
#Attach Host Profile and Test Compliance
foreach ($VMHostName in $VMHostNames) {
$CurrentHostProfiles = Get-VMHostProfile
$VMHostDetails = Get-VMHost -Name $VMHostName
$VMHostVIserver = $VMHostDetails.Uid.Split('@')[1].Split(':')[0]
switch ($VMHostVIserver) {
itdvmvc1.nd.gov { $VMHostVIserver = "BIS" }
Default { $VMHostVIServer = "MDN" }
}
$VMHostParent = $VMHostDetails.Parent.Name
switch ($VMHostParent.substring(0, $VMHostParent.Length - 1)) {
Avaya { $VMHostProfile = "Avaya" }
TEL { $VMHostProfile = "TEL" }
Default { $VMHostProfile = "General" }
}
#$VMHostBuild = $VMHostDetails.Build
#$VMHostVersion = $VMHostDetails.Version
#$VMHostProfileName = $CurrentHostProfiles | Where-Object {$_.Name -Like "*$VMHostVIserver*" -and $_.Name -Like "*$VMHostVersion*" -and $_.Name -Like "*$VMHostBuild*" -and $_.Name -Like "*$VMHostProfile*"} | Sort-Object Name | Select-Object -First 1
$VMHostProfileName = $CurrentHostProfiles | Where-Object { $_.Name -like "*$VMHostVIserver*" -and $_.Name -Like "*7.0.3*" -and $_.Name -like "*$VMHostProfile*" -and $_.Name -like "*Synergy*" } | Sort-Object -Descending Name | Select -First 1
Invoke-VMHostProfile -Entity $VMHostDetails -Profile $VMHostProfileName -AssociateOnly -Confirm:$false
}
# import host customization csv now
# then continue
foreach ($VMHostName in $VMHostNames) {
Get-VMHost -Name $VMHostName | Test-VMHostProfileCompliance
}
#Remediate Host Profile
foreach ($VMHostName in $VMHostNames) {
$VMHostDetails = Get-VMHost -Name $VMHostName
$VMHostProfileCompliance = $VMhostDetails | Test-VMHostProfileCompliance #### ???????
if ($VMHostProfileCompliance.ExtensionData.ComplianceStatus -Like "*non*") {
Invoke-VMHostProfile -Entity $VMhostDetails -Confirm:$false
}
$VMhostDetails | Test-VMHostProfileCompliance
}
#Test Host Profile Compliance
foreach ($VMHostName in $VMHostNames) {
Get-VMHost $VMHostName | Test-VMHostProfileCompliance
}
# Host requires reboot before previously applied configuration changes will take effect
Get-VMHost -Name $VMHostNames | Restart-VMHost -Confirm:$false
#Test Host Profile Compliance again
foreach ($VMHostName in $VMHostNames) {
Get-VMHost $VMHostName | Test-VMHostProfileCompliance
}
# move hosts back to their clusters
ForEach($VMHostName in $VMHostNames){
switch ($VMHostName.substring(8).split('.')[0].substring(0,2)){
'ps' {$ClusterStr = "PS"}
}
switch ($VMHostVIserver){
'itdvmvc1.nd.gov' {$ClusterInt = 1}
'itdvmvc2.nd.gov' {$ClusterInt = 2}
}
$ClusterName = $ClusterStr + $ClusterInt
Move-VMHost -VMHost $VMHostName -Destination (Get-Cluster -Name $ClusterName)
}
# restart again because HA is being weird
Get-VMHost -Name $VMHostNames | Restart-VMHost -Confirm:$false
# monitor
Get-VMHost -Name $VMHostNames
#----------------------------------------------------------------------------------------------------------------------------------------------------
#Monitor
Get-VMHost -Name $VMHostNames | Sort-Object Name | Select-Object Name, ConnectionState, @{Name = "VM.count"; E = { @($_ | Get-VM | Where-Object { $_.ExtensionData.Summary.Config.ManagedBy.Type -NE "placeholderVm" }).Count } }
#Exit Maintenance Mode and Enable Alarms
ForEach($VMHostName in $VMHostNames){
Set-VMHost -VMHost $VMHostName -State "Connected" -RunAsync
Start-Sleep -Seconds 2
}
foreach ($VMHostName in $VMHostNames) {
$GetVMHost = Get-VMHost $VMHostName
$VIServer = $GetVMHost.Uid.Split('@')[1].Split(':')[0]
$alarmMgr = Get-View AlarmManager -Server $VIServer
$alarmEnabled = $GetVMHost.ExtensionData.AlarmActionsEnabled
if ($alarmEnabled -eq $false) {
$alarmMgr.EnableAlarmActions($GetVMHost.ExtensionData.MoRef, $true)
}
$GetVMHost = $null
}
#----------------------------------------------------------------------------------------------------------------------------------------------------
#----------------------------------------------------------------------------------------------------------------------------------------------------
#----------------------------------------------------------------------------------------------------------------------------------------------------
#----------------------------------------------------------------------------------------------------------------------------------------------------
#----------------------------------------------------------------------------------------------------------------------------------------------------
#----------------------------------------------------------------------------------------------------------------------------------------------------
#----------------------------------------------------------------------------------------------------------------------------------------------------
#----------------------------------------------------------------------------------------------------------------------------------------------------
#----------------------------------------------------------------------------------------------------------------------------------------------------
#----------------------------------------------------------------------------------------------------------------------------------------------------
#----------------------------------------------------------------------------------------------------------------------------------------------------
#----------------------------------------------------------------------------------------------------------------------------------------------------
#$VMCluster = Get-Cluster $VMHostParent #| Set-Cluster -HAAdmissionControlEnabled:$false -Confirm:$false
#$HAFailoverHost = Get-VMHost | Where-Object {$_.Id -Match ((Get-Cluster $VMHostParent).extensiondata.configuration.dasconfig.admissioncontrolpolicy.failoverhosts.value)}
#get-vmhost | where-object {$_.id -eq ($vmcluster.extensiondata.configuration.dasconfig.admissioncontrolpolicy.failoverhosts.value)}
<#
foreach ($VMHostProfile in $VMHostProfiles){
Export-VMHostProfile -FilePath $FilePath$Profile".xml" -Profile $VMHostProfile
}
Import-VMHostProfile -FilePath $FilePath"TestHostProfile.xml" -Name "Test Scripting"
#>
#Get-OVServer -ov x
#$x | select Name,processorType,processorCount,processorCoreCount,serialnumber,memorymb,generation
## disable alarms entire datacenter
$VMHostNames=(Get-Datacenter primary* | Get-VMHost).Name
foreach ($VMHostName in $VMHostNames) {
Write-Warning -Message ("Start $VMHostName")
$GetVMHost = Get-VMHost $VMHostName
#$VMHostParent = $GetVMHost.Parent
#$HostCluster = Get-Cluster -VMHost $VMHostName
<#$NewSpec = New-Object VMware.Vim.ClusterConfigSpec
$NewSpec.DasConfig = New-Object VMware.Vim.ClusterDasConfigInfo
$NewSpec.DasConfig.AdmissionControlPolicy = New-Object VMware.Vim.ClusterFailoverResourcesAdmissionControlPolicy
$NewSpec.DasConfig.AdmissionControlPolicy.AutoComputePercentages = $true
$HostCluster.ExtensionData.ReconfigureCluster($NewSpec, $true)
#>
$VIServer = $GetVMHost.Uid.Split('@')[1].Split(':')[0]
$alarmMgr = Get-View AlarmManager -Server $VIServer
$alarmEnabled = $GetVMHost.ExtensionData.AlarmActionsEnabled
if ($alarmEnabled -eq $true) {
$alarmMgr.EnableAlarmActions($GetVMHost.ExtensionData.MoRef, $false)
}
}
## enable alarms for entire datacenter
$VMHostNames = (Get-VMHost).Name
foreach ($VMHostName in $VMHostNames) {
$GetVMHost = Get-VMHost $VMHostName
$VIServer = $GetVMHost.Uid.Split('@')[1].Split(':')[0]
$alarmMgr = Get-View AlarmManager -Server $VIServer
$alarmEnabled = $GetVMHost.ExtensionData.AlarmActionsEnabled
if ($alarmEnabled -eq $false) {
$alarmMgr.EnableAlarmActions($GetVMHost.ExtensionData.MoRef, $true)
}
$GetVMHost = $null
}
@@ -0,0 +1,971 @@
$IaasAuto = Get-Credential -UserName ndgov\svcitdiaasauto
$StdCred = $IaasAuto
$PrvCred = $IaasAuto
$FQDNs = @"
itdzmtest111.ndtestdev.nd.dev
"@
$FQDNs = ConvertTo-Array -MultiLineString $FQDNs
ForEach ($FQDN in $FQDNs) {
Write-Warning "[$FQDN]:Start"
$SPCred = $StdCred
$ADCred = $PrvCred
$PSCred = $PrvCred
$VMCred = $PrvCred
$CcmCred = $PrvCred
#>
<# 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 ($PSCred.UserName.split('\')[1], $ADCred.Password)
$VMCred = Get-AutomationPSCredential -Name 'VMware Auto'
$CcmCred = Get-AutomationPSCredential -Name 'ITD IaaS Automation'#>
#>
Clear-DnsClientCache
$SharePointList = Get-ITDVMwareSharePointVMGuestList -Credential $SPCred
Write-Warning ("SPList count: " + $SharePointList.count)
$SPItem = $SharePointList | Where-Object Title -EQ $FQDN
If ($null -eq $SPItem.Cluster) {
Write-Error "VMware Cluster not specified in SharePoint"
Stop
}
Write-Warning $SPItem
$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 $RadiusCred
[Net.IPAddress]$IpAddress = (Resolve-DnsName -Name $FQDN -ErrorAction SilentlyContinue).IPAddress
}
#>
If ((Test-NetConnection -ComputerName $IpAddress.IPAddressToString).PingSucceeded) {
Write-Error "IP Address already in use." -ErrorAction Stop
}
# Passwordstate BB before baseline, AB after baseline
If ($FQDN -like "itdcnd*") {
$PasswordStateList = "Peoplesoft Share PW"
}
Else {
$PasswordStateList = "CSRC"
}
$LocalCredential = New-ITDPassword -Title $FQDN -UserName itdadmin -Description 'Local Administrator' -PasswordList $PasswordStateList -Credential $PSCred
#$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))
$GuestCredentialAB = New-Object System.Management.Automation.PSCredential ('itdadmin', ($LocalCredential.Password | ConvertTo-SecureString -AsPlainText -Force))
$GuestCredentialBB = New-Object System.Management.Automation.PSCredential ('Administrator', ($LocalCredential.Password | ConvertTo-SecureString -AsPlainText -Force))
#$GuestCredential = $GuestCredentialBB
# VMware
Connect-ITDvCenter -Credential $VMCred
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'
$ComputeCluster = Get-Cluster WINDOWS1
$VirtualSwitch = Get-VDSwitch -Name "dvSwitch-PDC-Data-Server"
$DiskStorageFormat = 'Thin'
If ($SPItem.LicensingRestrictions -like "*SQL*") {
$DatastoreCluster = Get-DatastoreCluster -Name "WINDOWS1_FS92_SQL"
}
Else {
$DatastoreCluster = Get-DatastoreCluster -Name "WINDOWS1_FS92_Gen"
}
}
"WINDOWS2" {
$ViServer = 'itdvmvc2.nd.gov'
$ComputeCluster = Get-Cluster WINDOWS2
$VirtualSwitch = Get-VDSwitch -Name "dvSwitch-SDC-Data-Server"
$DiskStorageFormat = 'Thin'
If ($SPItem.LicensingRestrictions -like "*SQL*") {
$DatastoreCluster = Get-DatastoreCluster -Name "WINDOWS2_FS92_SQL"
}
Else {
$DatastoreCluster = Get-DatastoreCluster -Name "WINDOWS2_FS92_Gen"
}
}
"SQL1" {
$ViServer = 'itdvmvc1.nd.gov'
$ComputeCluster = Get-Cluster SQL1
$VirtualSwitch = Get-VDSwitch -Name "dvSwitch-PDC-Data-Server"
$DiskStorageFormat = 'EagerZeroedThick'
$DatastoreCluster = Get-DatastoreCluster -Name "SQL1_FS92_Gen"
}
"SQL2" {
$ViServer = 'itdvmvc2.nd.gov'
$ComputeCluster = Get-Cluster SQL2
$VirtualSwitch = Get-VDSwitch -Name "dvSwitch-SDC-Data-Server"
$DiskStorageFormat = 'EagerZeroedThick'
$DatastoreCluster = Get-DatastoreCluster -Name "SQL2_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
}
<#
"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
If ($DatastoreCluster) {
}
Else {
$DatastoreCluster = Get-DatastoreCluster | Where-Object Name -Like ("*" + $SPItem.Cluster + "*")
}
$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"
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" }
"Windows Server 2019 Datacenter (64-Bit)" { $Template = "Windows Server 2019 Standard" }
"Windows Server 2022 Datacenter (64-Bit)" { $Template = "Windows Server 2022 Standard" }
Default { Write-Error "Invalid template" -ErrorAction Stop }
}
$PortGroupsAvailable = Get-VDPortgroup -Server $ViServer -VDSwitch $VirtualSwitch
$PortGroup = $PortGroupsAvailable | Where-Object Name -Like ("dvPG_" + $SPItem.Vlan_Id + "*")
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
}
$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
<#
$NewVMParams = @{
Name = $FQDN;
ResourcePool = $SPItem.Cluster;
Datastore = $DatastoreCluster;
DiskStorageFormat = $DiskStorageFormat;
Template = $Template;
Location = $FolderLocation;
OSCustomizationSpec = $OSSpec;
}
$NewVMParams
New-VM @NewVMParams
#>
#Set-Location C:\Temp # required to make New-VM work, https://communities.vmware.com/thread/591294
# seems fixed on 2022/07/01
try {
Write-Warning $FQDN
Write-Warning $ComputeCluster.Name
Write-Warning $DatastoreCluster
Write-Warning $DiskStorageFormat
Write-Warning $Template
Write-Warning $FolderLocation
Write-Warning $OSSpec
New-VM -Name $FQDN -ResourcePool $ComputeCluster.Name -Datastore $DatastoreCluster -DiskStorageFormat $DiskStorageFormat -Template $Template -Location $FolderLocation -OSCustomizationSpec $OSSpec
}
catch {
Stop
Stop
}
#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
Write-Warning -Message "[$FQDN]:Modify disks 1,2,3"
$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 = $VM | Get-HardDisk | 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 = $VM | Get-HardDisk | 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 = $VM | Get-HardDisk | Where-Object Name -EQ "Hard disk 3"
If ($VMDisk3.CapacityGB -lt $SPItem.Disk3) {
Set-HardDisk -HardDisk $VMDisk3 -CapacityGB $SPItem.Disk3 -Confirm:$false
}
}
# skipping tag assignment for now
# Set-ITDVMwareVMTagFromSharePoint -ComputerName $FQDN -SharePointCredential $SPCred -Verbose
# Run Guest OS code
# Enable RDP with NLA - can be done with GPO
# Enable WinRM - ITD WinRM enable
# Configure Power Plan - ITD-PowerPlan-HighPerformance
# Activate Windows, KMS on-premise, Azure to Azure
# DVD Drive to Z:
# Expand C:
# Partition/Format the rest, GPT/NTFS
# Configure Page File Disk
# Enabling server manager performance monitors
# Configure Time Zone and NTP - no GPO available
# Disable Windows Firewall
# Join AD
#Initialize-ITDServer -Credential $ADCred
Write-Warning -Message "[$FQDN]:Assigning WMI Tag 000-Prod, SCCM will change it later if required"
Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredentialBB -ScriptType PowerShell -ScriptText {
# Move DVD Drive Mount
try {
Write-Verbose "Create new Class"
$Class = New-Object System.Management.ManagementClass("root\cimv2", [String]::Empty, $null);
$Class["__CLASS"] = "ITD";
$Class.Qualifiers.Add("Static", $true)
$Class.Properties.Add("MyKey", [System.Management.CimType]::String, $false)
$Class.Properties["MyKey"].Qualifiers.Add("Key", $true)
$Class.Properties.Add("LastModified", [System.Management.CimType]::String, $false)
$Class.Properties.Add("DTAP", [System.Management.CimType]::String, $false)
$Class.Properties.Add("Baseline", [System.Management.CimType]::String, $false)
$Class.Put()
Write-Verbose "Create single ITD Object"
Set-WmiInstance -Class ITD -Arguments @{LastModified = (Get-Date); DTAP = "Prod"; Baseline = "000" }
}
catch {
Throw $_
Break
}
}
Write-Warning -Message "[$FQDN]:Checking for DVD drive..."
Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredentialBB -ScriptType PowerShell -ScriptText {
# Move DVD Drive Mount
try {
$dvd_letter = 'Z'
$dvd = Get-WmiObject -Class Win32_Volume -Filter "DriveType=5" | Select-Object -First 1
if ($dvd.Name -notmatch $dvd_letter) {
Write-Verbose -Message "Found DVD drive, switching to $dvd_letter`:"
Set-WmiInstance -InputObject $dvd -Arguments @{DriveLetter = "$dvd_letter`:" } | Out-Null
Write-Verbose -Message "DVD drive moved to drive letter $dvd_letter`:"
}
else {
Write-Verbose -Message "No DVD drive changes required, continuing..."
}
}
catch {
Throw $_
Break
}
}
Write-Warning -Message "[$FQDN]:Checking for unpartitioned space on C: disk..."
Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredentialBB -ScriptType PowerShell -ScriptText {
# Expand C: Partition To Maximum Extent
try {
$cSize = ( Get-Partition -DriveLetter C ).Size
$cMaxSize = ( Get-PartitionSupportedSize -DriveLetter C ).SizeMax
if ($cSize -lt $cMaxSize) {
Write-Verbose -Message "Expanding C: from $($csize / 1GB)GB to $($cMaxSize / 1GB)GB..."
Resize-Partition -DriveLetter C -Size $cMaxSize
Write-Verbose -Message "C: expanded to $($cMaxSize / 1GB)GB."
}
else {
Write-Verbose -Message "C: is already at maximum size, continuing..."
}
}
catch {
Throw $_
Break
}
}
Write-Warning "[$FQDN]:Start Extra Disk(s) config"
Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredentialBB -ScriptType PowerShell -ScriptText {
# Initialize Additional Disks
try {
# Non-initialized and MBR-initialized disks will have 0 partitions by default, but GPT-initialized disks will have 1 system reserved partition by default
$disks = Get-Disk | Where-Object { $_.NumberOfPartitions -eq 0 -or ( $_.PartitionStyle -eq 'GPT' -and $_.NumberOfPartitions -eq 1 ) } | Sort-Object -Property Number
if ($disks) {
Write-Verbose -Message "Found $(@($disks).Count) unpartitioned disks."
# Prevent the "You must format this partition before using it." popup
if (Get-Service ShellHWDetection -ErrorAction SilentlyContinue) { Stop-Service ShellHWDetection -ErrorAction SilentlyContinue }
foreach ($disk in $disks) {
if ($disk.IsOffline) {
Set-Disk $disk.Number -IsOffline $false
Write-Verbose -Message "Brought disk $($disk.Number)($("{0:n0}GB" -f ($disk.Size / 1GB))) online..."
}
if ($disk.IsReadOnly) { Set-Disk $disk.Number -IsReadOnly $false }
if ($disk.PartitionStyle -eq 'RAW') { Initialize-Disk $disk.Number -PartitionStyle GPT -ErrorAction SilentlyContinue }
$diskParam = @{
FileSystem = 'NTFS'
Confirm = $false
}
$driveLetter = [Int][Char]'D'
while (Get-Volume -DriveLetter $([Char]$driveLetter) -ErrorAction SilentlyContinue) {
$driveLetter++
}
$diskParam.DriveLetter = [Char]$driveLetter
if (@($disks).IndexOf($disk) -eq 0 -and (-not (Get-Volume -DriveLetter D -ErrorAction SilentlyContinue))) {
$diskParam.NewFileSystemLabel = 'Temporary Storage'
}
elseif (@($disks).IndexOf($disk) -eq 1 -and (-not (Get-Volume -DriveLetter E -ErrorAction SilentlyContinue))) {
$diskParam.NewFileSystemLabel = 'Data'
}
[void](New-Partition -DiskNumber $disk.Number -DriveLetter $diskParam.DriveLetter -UseMaximumSize)
[void](Format-Volume @diskParam)
}
}
else {
Write-Verbose -Message "No unpartitioned disks found, continuing..."
}
}
catch {
Throw $_
Break
}
finally {
if (Get-Service ShellHWDetection -ErrorAction SilentlyContinue) { Start-Service ShellHWDetection -ErrorAction SilentlyContinue }
}
}
Write-Warning "[$FQDN]:Start Page File Configuration"
Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredentialBB -ScriptType PowerShell -ScriptText {
# Configure Page File
if (Get-Partition -DriveLetter D -ErrorAction SilentlyContinue) {
Write-Verbose -Message "Setting up pagefile.sys on D:..."
try {
if (-not [IO.File]::Exists('D:\pagefile.sys')) {
$autoPage = Get-WmiObject -Class Win32_ComputerSystem -EnableAllPrivileges
$autoPage.AutomaticManagedPagefile = $false
[void]$autoPage.Put()
Write-Verbose -Message "Disabled automatic pagefile management."
$pageFile = Get-WmiObject -Class Win32_PageFileSetting -EnableAllPrivileges
$pageFile.Delete()
Write-Verbose -Message "Deleted C:\pagefile.sys."
Set-WmiInstance -Class Win32_PageFileSetting -Arguments @{ Name = "D:\pagefile.sys"; InitialSize = 0; MaximumSize = 0; } -EnableAllPrivileges | Out-Null
Write-Verbose -Message "System managed page file created on D:\pagefile.sys."
}
else {
Write-Verbose -Message "Pagefile already configured on D:, continuing..."
}
}
catch {
Throw $_
Break
}
}
else {
Write-Verbose -Message "Page file drive not found, cannot set up page file. Continuing server configuration..."
Write-Warning "Page file drive not found, cannot set up page file. Continuing server configuration..."
}
}
Write-Warning -Message "[$FQDN]:Enabling Remote Management..."
Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredentialBB -ScriptType PowerShell -ScriptText {
# Configure Remote Management (RDP/PoSH)
try {
Write-Verbose -Message "Checking WinRM..."
if (Test-WSMan -ErrorAction SilentlyContinue) {
Write-Verbose -Message "WinRM is already enabled."
}
else {
Enable-PSRemoting -Force
Write-Verbose -Message "WinRM is now enabled."
}
Write-Verbose -Message "Checking RDP..."
$RDP = Get-WmiObject Win32_TerminalServiceSetting -Namespace root\cimv2\TerminalServices
$NLA = Get-WmiObject Win32_TSGeneralSetting -Namespace root\cimv2\TerminalServices -Filter "TerminalName='RDP-tcp'"
if ($RDP.AllowTSConnections -eq 0) {
Write-Verbose -Message "RDP is disabled, enabling..."
$RDP.SetAllowTSConnections(1, 1) | Out-Null
Write-Verbose -Message "RDP is enabled."
}
else {
Write-Verbose -Message "RDP is already enabled, checking NLA security..."
}
if ($NLA.UserAuthenticationRequired -eq 0) {
Write-Verbose -Message "RDP is not NLA secured, enabling..."
$NLA.SetUserAuthenticationRequired(1) | Out-Null
Write-Verbose -Message "RDP is now NLA secured."
}
else {
Write-Verbose -Message "RDP is already NLA secured."
}
}
catch {
Throw $_
Break
}
}
Write-Warning -Message "[$FQDN]:Checking current power plan..."
Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredentialBB -ScriptType PowerShell -ScriptText {
# Configure Power Plan
try {
$powerPlans = powercfg -l
if ($powerPlans -match '\*$' -notmatch 'High performance') {
$currentPlan = [regex]::Match($powerPlans, '(?<=(\())[^)]+(?=(\)\s\*))').Value
Write-Verbose -Message "Power plan is currently set to $currentPlan, changing to High Performance..."
$highPerformance = [regex]::Match($powerPlans, '([\d\w-\S]+)(?=\s+\(High performance\))').Value
[void](powercfg -setactive $highPerformance)
Write-Verbose -Message "Power plan set to High Performance."
}
else {
Write-Verbose -Message "Power plan already configured for High Performance."
}
[void](& w32tm.exe /resync /nowait)
}
catch {
Throw $_
Break
}
}
$TimeSyncFunc = {
# Configure Time/Date Settings
Write-Verbose -Message "Checking current time/date settings..."
$Domain = "<DomainName>"
try {
if ((Get-TimeZone).Id -ne 'Central Standard Time') {
Write-Verbose -Message "Current time zone set to $((Get-TimeZone).Id), setting to Central Standard Time."
Set-TimeZone -Id 'Central Standard Time'
Write-Verbose -Message "Time zone set to Central Standard Time."
}
else {
Write-Verbose -Message "Time zone is already set to Central Standard Time."
}
<#
Write-Verbose -Message "Beginning a time synchronization..."
if ((Get-Service W32Time).Status -eq 'Stopped') {
Start-Service W32Time
}
[void](& w32tm.exe /config /manualpeerlist:$Domain /syncfromflags:all /update)
[void](& w32tm.exe /resync /nowait)
# Start background job to check time service
$tmJob = Start-Job -Name 'ManualTimeSync' -ScriptBlock {
do {
$tmOut = & w32tm.exe /query /status /verbose
Start-Sleep -Seconds 10
} until($tmOut -match '^Last Sync Error: 0\D+$')
}
# If after three minutes time still has not synched, move on. This usually causes no problems.
if ((Wait-Job -Job $tmJob -Timeout 180).State -eq 'Completed') {
Write-Warning -Message "Time synchronization with $($Domain.ToLower()) successful."
}
else {
[void](Stop-Job -Job $tmJob)
Write-Warning -Message "Time synchronization with $($Domain.ToLower()) failed."
}
#>
}
catch {
Throw $_
Break
}
}
$TimeSyncScriptBlock = $TimeSyncFunc -replace '<DomainName>', $DomainName
$VM | Invoke-VMScript -GuestCredential $GuestCredentialBB -ScriptType PowerShell -ScriptText $TimeSyncScriptBlock
#>
Write-Warning -Message "[$FQDN]:Enabling the server manager performance monitors..."
Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredentialBB -ScriptType PowerShell -ScriptText {
# Enable Performance Counters
try {
if (Get-ScheduledTask -TaskName "Server Manager Performance Monitor" | Where-Object State -NE "Running" -ErrorAction SilentlyContinue) {
Enable-ScheduledTask -TaskPath "\Microsoft\Windows\PLA\" -TaskName "Server Manager Performance Monitor" | Start-ScheduledTask
Write-Verbose -Message "Performance monitors enabled."
}
else {
Write-Verbose -Message "Performance monitors already enabled, continuing..."
}
}
catch {
Throw $_
Break
}
}
Write-Warning -Message "[$FQDN]:Disable Windows Firewall"
Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredentialBB -ScriptType PowerShell -ScriptText {
# Disable Windows Firewall
Write-Verbose -Message "Checking for active Windows Firewall..."
if ((Get-NetFirewallProfile).Enabled -contains 'True') {
Write-Verbose -Message "Windows Firewall is still enabled, disabling it..."
Set-NetFirewallProfile -Profile Domain, Public, Private -Enabled False
Write-Verbose -Message "Windows Firewall disabled."
}
else {
Write-Verbose -Message "Windows Firewall already disabled, continuing..."
}
}
# Active Directory
Write-Warning "[$FQDN]:Join Active Directory (if required)"
$DomainName = $FQDN.Substring($FQDN.IndexOf(".") + 1)
$AppName = $SPItem.AppName
switch ($DomainName) {
'nd.gov' {
$SearchBaseDomain = "dc=nd,dc=gov"
}
'ndcloud.gov' {
$SearchBaseDomain = "dc=ndcloud,dc=gov"
}
}
If ($DomainName -eq "nd.gov") {
$OUAppName = Get-ADOrganizationalUnit -Server $DomainName -SearchBase ("OU=SERVERS,ou=COMPUTERS,ou=ITD," + $SearchBaseDomain) -Filter { Name -eq $AppName }
If (!($OUAppName)) {
$OUAppName = Get-ADOrganizationalUnit -SearchBase ("OU=SERVERS,ou=COMPUTERS,ou=ITD," + $SearchBaseDomain) -Filter { Name -eq 'All-General' }
}
$ExistingADComputer = Get-ADComputer -Filter { Name -eq $Hostname }
If ($ExistingADComputer) {
If ($ExistingADComputer.DistinguishedName -like ("*" + $SPItem.AppName + "*") -or $ExistingADComputer.DistinguishedName -like "*All-General*") {
Write-Warning "AD object already exists, OU path does match"
$OuFinal = $ExistingADComputer.DistinguishedName -replace '^.+?(?<!\\),', ''
}
Else {
Write-Error "AD object already exists, OU path mismatch"
Exit
Exit
}
}
Else {
switch ($SPItem.Environment) {
'Test' {
If ($AppName -like "Shared-Peoplesoft*") { $EnvString = "Non-Prod" }
Else { $EnvString = "Test" }
$OuAppNameEnv = Get-ADOrganizationalUnit -SearchBase $OUAppName.DistinguishedName -Filter * | Where-Object Name -Like "*$EnvString*"
}
'Production' {
$EnvString = "Prod"
$OuAppNameEnv = Get-ADOrganizationalUnit -SearchBase $OUAppName.DistinguishedName -Filter * | Where-Object Name -Like "*$EnvString*"
}
}
If ($OuAppNameEnv) { $OUFinal = $OUAppNameEnv.DistinguishedName }
Else { $OuFinal = $OUAppName.DistinguishedName }
#New-ADComputer -Name $HostName.ToUpper() -Path $OUFinal -Credential $ADCred -Description ($SPItem | Select-Object AppName, Environment | ConvertTo-Json)
}
$FirstScriptBlock = { $DomainJoinCred = New-Object System.Management.Automation.PSCredential('svcitdvmdomainjoin', ('hypes-Vgv8h89' | ConvertTo-SecureString -AsPlainText -Force)) }
$SecondScriptText = 'Add-Computer -DomainName <DomainName> -OUPath "<OuPath>" -Credential $DomainJoinCred'
$SecondScriptText = $SecondScriptText -replace '<DomainName>', $DomainName
$SecondScriptText = $SecondScriptText -replace '<OuPath>', $OuFinal
$SecondScriptText = $SecondScriptText -replace '<OuPath>', ("OU=SERVERS,ou=COMPUTERS,ou=ITD," + $SearchBaseDomain)
Write-Warning -Message "[$FQDN]:Invoke-VMScript to AD join"
$InvokeVMScriptFunc = [System.Management.Automation.ScriptBlock]::Create("$FirstScriptBlock ; $SecondScriptText")
Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredentialBB -ScriptType PowerShell -ScriptText $InvokeVMScriptFunc
Write-Warning -Message "[$FQDN]:Restart VMGuest, wait for Tools, then 90 seconds after"
Get-VM -Name $FQDN | Restart-VMGuest -Confirm:$false
Wait-Tools -VM (Get-VM -Name $FQDN)
Start-Sleep -Seconds 90
}
Write-Warning ("[$FQDN]:Copying SCCM client installer to C:\temp... " + (Get-Date))
Copy-VMGuestFile -Source C:\SCCM_Client\ -Destination C:\temp\SCCM_Client -VM (Get-VM -Name $FQDN) -LocalToGuest -GuestCredential $GuestCredentialAB -Force
Write-Warning ("[$FQDN]:SCCM client copy complete " + (Get-Date))
#E:\AutoBuild\SCCM_Client\
# Check if SCCM automatically installed the SCCM client and registered it
$CcmRegistered = $false
$CcmRegistration = Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredentialAB -ScriptType PowerShell -ScriptText {
Get-Content C:\windows\ccm\logs\ClientIDManagerStartup.log
}
If ($CcmRegistration.ScriptOutput -match "Client is registered") {
Write-Warning "Client is registered."
$CcmRegistered = $true
}
ElseIf ($CcmRegistration.ScriptOutput -match "Client is already registered") {
Write-Warning "Client is already registered."
$CcmRegistered = $true
}
If ($CcmRegistered -eq $false) {
Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredentialAB -ScriptType PowerShell -ScriptText {
If (Get-Process -Name ccmsetup -ErrorAction SilentlyContinue) {
Write-Warning "CCM client is already installing"
$CcmRegistered = $true
}
ElseIf (Get-Process -Name ccmexec -ErrorAction SilentlyContinue) {
Write-Warning "CCM client is already installed"
$CcmRegistered = $true
}
Else {
Write-Warning -Message "Installing SCCM Client..."
Invoke-Expression -Command "C:\temp\SCCM_Client\ccmsetup.exe SMSSITECODE=ITD SMSMP=itdsccmp2.nd.gov DNSSUFFIX=nd.gov"
}
}
}
Write-Warning "[$FQDN]:Register SCCM Client"
While ($CcmRegistered -eq $false) {
$CcmRegistration = Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredentialAB -ScriptType PowerShell -ScriptText {
Get-Content C:\windows\ccm\logs\ClientIDManagerStartup.log
}
If ($CcmRegistration.ScriptOutput -match "Client is registered") {
Write-Warning "Client is registered."
$CcmRegistered = $true
}
ElseIf ($CcmRegistration.ScriptOutput -match "Client is already registered") {
Write-Warning "Client is already registered."
$CcmRegistered = $true
}
ElseIf ($CcmRegistered -eq $false) { Start-Sleep -Seconds 30 }
}
Write-Warning -Message "[$FQDN]:Approve SCCM Client"
#Start-Sleep -Seconds 30 # ADD LOOP/SMARTS TO WAIT FOR DISCOVERY AND ANOTHER FOR APPROVAL
Invoke-Command -ComputerName itdsccmp2.nd.gov -Credential $CcmCred -ArgumentList $Hostname -ScriptBlock {
Import-Module 'D:\Program Files\Microsoft Configuration Manager\AdminConsole\bin\ConfigurationManager.psd1'
$PSDrives = Get-PSDrive
If ($PSDrives | Where-Object Name -EQ "ITD") {
# ITD Drive exists, do nothing
}
else {
New-PSDrive -Name "ITD" -PSProvider AdminUI.PS.Provider\CMSite -Root itdsccmp2.nd.gov
}
Set-Location ITD:\
$Device = Get-CMDevice -Name $args[0]
If ($Device.IsApproved -eq 0) {
Approve-CMDevice -DeviceName $args[0]
}
}
Write-Warning "[$FQDN]:Trigger SCCM MachinePolicy First Check-in"
Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredentialAB -ScriptType PowerShell -ScriptText {
[void] ([wmiclass] "\\localhost\root\ccm:SMS_Client").TriggerSchedule("{00000000-0000-0000-0000-000000000021}");
}
Write-Warning "[$FQDN]:Trigger SCCM MachinePolicy"
Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredentialAB -ScriptType PowerShell -ScriptText {
[void] ([wmiclass] "\\localhost\root\ccm:SMS_Client").TriggerSchedule("{00000000-0000-0000-0000-000000000021}");
}
#Start-Sleep -Seconds 180
Write-Warning -Message '[$FQDN]:Waiting for network connectivity / Then KVM Activation...'
Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredentialAB -ScriptType PowerShell -ScriptText {
# Pause until network connectivity is available
$KMS = 'kms.nd.gov'
try {
$nwJob = Start-Job -Name 'NetworkCheck' -ScriptBlock {
Param ( [String]$KMS )
do {
$nwStatus = Test-NetConnection -ComputerName $KMS -Port 1688 -InformationLevel Quiet
Start-Sleep -Seconds 10
} until($nwStatus)
} -ArgumentList $KMS
# If after 30 seconds the network connection is not responding continue on
if ((Wait-Job -Job $nwJob -Timeout 30).State -eq 'Completed') {
Write-Verbose -Message 'Network connectivity has been verified.'
}
else {
[void](Stop-Job -Job $nwJob)
Write-Verbose -Message 'Network connectivity could not be verified.'
}
}
catch {
Throw $_
Break
}
# Activate via KMS
Write-Verbose -Message "Activating windows against $KMS..."
if (!([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) {
Start-Process powershell.exe "-NoProfile -ExecutionPolicy Bypass -File `"$PSCommandPath`"" -Verb RunAs; exit
}
try {
cscript C:\Windows\System32\slmgr.vbs /skms $KMS | Out-Null
cscript C:\Windows\System32\slmgr.vbs /ato | Out-Null
Write-Verbose -Message "Checking activation status..."
$kmsOut = cscript C:\Windows\System32\slmgr.vbs /dli
if (($kmsOut | Select-String -Pattern '^License Status:') -match 'Licensed') {
Write-Verbose -Message "Windows successfully activated."
}
else {
Write-Verbose -Message "Windows failed to activate, run slmgr commands manually. Ensure server time is correct."
Write-Warning -Message "Windows failed to activate, run slmgr commands manually. Ensure server time is correct."
}
}
catch {
Throw $_
Break
}
}
Write-Warning "[$FQDN]:End"
}
Invoke-Command -ComputerName $FQDNs -Credential $PrvCred -ScriptBlock { Get-Process -Name ccmexec*, cohesity*, cyserver*, nessus*, vmtoolsd* }
Write-Warning "[$FQDN]:Trigger SCCM MachinePolicy First Check-in"
Invoke-Command -ComputerName $FQDNs -Credential $PrvCred -ScriptBlock {
[void] ([wmiclass] "\\localhost\root\ccm:SMS_Client").TriggerSchedule("{00000000-0000-0000-0000-000000000021}");
}
@@ -0,0 +1,41 @@
[CmdletBinding()]
param (
)
begin {
}
process {
Connect-ITDvCenter -Credential $Secret:ndgov_svcitdvmvcauto
$VMHosts = Get-Datacenter -Name "Grand Forks Vantis" | Get-VMHost
ForEach ($VMHost in $VMHosts) {
Write-Verbose -Message ("Start: " + $VMHost.Name) -Verbose
$VMHostStatus = Get-ITDVMwareVMHostStatus -Name $VMHost.Name
# if accurate, enable lockdown
If ($VMHostStatus.LockdownMode -eq 'lockdowndisabled') {
Write-Verbose -Message ("Lockdown is already disabled on " + $VMHost.Name + ", no change") -Verbose
$NoChange = $true
}
Else {
Write-Verbose -Message ("Lockdown is enabled on " + $VMHost.Name + ", disabling now") -Verbose
Disable-ITDVMwareVMHostFeature -Name $VMHost.Name -LockdownMode
}
Start-Sleep -Seconds 5
# confirm lockdown is enabled
$VMHostStatusCheck = Get-ITDVMwareVMHostStatus -Name $VMHost.Name
}
Disconnect-ITDvCenter
}
end {
}
@@ -0,0 +1,86 @@
[CmdletBinding()]
param (
[switch]
$IncludeInProgress
)
begin {
}
process {
New-ITDServiceNowSession -Credential $Secret:snow_vmcred -Environment Production
Connect-ITDvCenter -Credential $Secret:ndgov_svcitdvmvcauto
If($PSBoundParameters.ContainsKey("IncludeInProgress")){
$Filter = 'short_descriptionSTARTSWITHLockdown mode is disabled on VMware host^state=1^ORstate=2'
} Else {
$Filter = 'state=1^short_descriptionSTARTSWITHLockdown Mode is disabled on VMware host'
}
$Incidents = Get-ITDServiceNowRecord -ItemType Incident -Filter $Filter | Sort-Object {$_.number.value}
ForEach ($Incident in $Incidents) {
# reset variables for each loop
$VMHostName = $null
$VMHostStatus = $null
$VMHostStatusCheck = $null
$NoChange = $null
$VMHostName = $Incident.short_description.display_value.split(' ')[-1]
Write-Verbose -Message ("Start " + $Incident.number.display_value + " for host " + $VMHostName) -Verbose
# confirm ticket is accurate, that host has lockdown mode disabled
$VMHostStatus = Get-ITDVMwareVMHostStatus -Name $VMHostName
# if accurate, enable lockdown
If ($VMHostStatus.LockdownMode -eq 'lockdowndisabled') {
Write-Verbose -Message ("Lockdown is still disabled on " + $VMHostName + ", enabling lockdown mode") -Verbose
Enable-ITDVMwareVMHostFeature -Name $VMHostName -LockdownMode
}
Else {
Write-Verbose -Message ("Lockdown is already enabled on " + $VMHostName + ", no change") -Verbose
$NoChange = $true
}
Start-Sleep -Seconds 5
# confirm lockdown is enabled
$VMHostStatusCheck = Get-ITDVMwareVMHostStatus -Name $VMHostName
# update ticket with current status
If ($VMHostStatusCheck.LockdownMode -eq 'lockdowndisabled') {
# update work notes if disabled
Write-Verbose -Message ("Lockdown is still disabled on " + $VMHostName + ", update incident work notes") -Verbose
$WorkNotesMsg = ("Lockdown is still disabled on " + $VMHostName + " after attempted remediation, manual review required.")
Update-ITDServiceNowRecord -ItemType Incident -Number $Incident.number.display_value -Values @{
work_notes = $WorkNotesMsg
state = 'On Hold'
}
}
Else {
# close if enabled
If ($NoChange) {
Write-Verbose -Message ("Lockdown was already enabled on " + $VMHostName + ", closing incident") -Verbose
$close_notes = ("Lockdown was already enabled on " + $VMHostName + " when checked, closing incident")
}
Else {
Write-Verbose -Message ("Lockdown successfully enabled on " + $VMHostName + ", closing incident") -Verbose
$close_notes = ("Lockdown successfully auto-enabled on " + $VMHostName);
}
Write-Verbose -Message ("Lockdown successfully enabled on " + $VMHostName + ", closing incident") -Verbose
Update-ITDServiceNowRecord -ItemType Incident -Number $Incident.number.display_value -Values @{
close_code = 'Solved (Permanently)'
close_notes = $close_notes
u_underlying_cause = 'Configuration';
state = 'Closed'
}
}
}
Disconnect-ITDvCenter
}
end {
}
@@ -0,0 +1,59 @@
<#
.SYNOPSIS
Checks VMware host lockdown mode status and creates incidents for disabled hosts.
.DESCRIPTION
Recurring PSU schedule task, ~8am.
This script connects to the ITD vCenter, retrieves all VMware hosts, and checks their lockdown mode status.
If lockdown mode is disabled on any hosts, it creates a ServiceNow incident for review.
.EXAMPLE
.\VMware-LockdownTickets.ps1
.NOTES
Requires VMware PowerCLI and ITD ServiceNow modules.
Service account credentials must be available via $PrvCred and $Secret:ndgov_svcitdvmvcro.
#>
[CmdletBinding()]
param (
)
begin {
}
process {
New-ITDServiceNowSession -Credential $Secret:snow_vmcred -Environment Production
Connect-ITDvCenter -Credential $Secret:ndgov_svcitdvmvcro
$AllVMHosts = Get-VMHost
$CurrentState = Get-ITDVMwareVMHostStatus -Name $AllVMHosts
$LockdownDisabled = $CurrentState | where-object lockdownmode -eq lockdowndisabled
If ($LockdownDisabled) {
ForEach ($VMHost in ($LockdownDisabled | Select -First 2)) {
Write-Verbose -Message "Start $($VMHost.Name) incident creation"
$NewIncidentParams = @{
CallerUsername = 'svcvmwareadm';
ShortDescription = ("Lockdown Mode is disabled on VMware host " + $VMHost.Name);
Description = ("Lockdown Mode is disabled on VMware host " + $VMHost.Name + ". Lockdown mode is a required for CIS hardening compliance 3.20 (L1)");
Impact = 3;
Urgency = 1;
Category = 'Cloud Platforms'
Subcategory = 'Virtualization'
AssignmentGroup = 'NDIT-Cloud Platforms'
}
New-ITDServiceNowIncident @NewIncidentParams
}
}
Disconnect-ITDvCenter
}
end {
}
@@ -0,0 +1,982 @@
#$IaasAuto = Get-Credential -UserName ndgov\svcitdiaasauto
#$StdCred = $IaasAuto
#$PrvCred = $IaasAuto
$FQDN = "itdzmtest001.nd.gov"
$CPU = 1
$MemoryGB = 4
$OS = "Windows Server 2019 Standard (64-Bit)"
$Environment = "Production"
$AppName = "Shared-PowerSchool"
$LicensingRestrictions = "Powerschool"
$VLAN = 1161
$Datacenter = "Bismarck"
Write-Warning "[$FQDN]:Start"
$SPCred = $StdCred
$ADCred = $IaasAuto
$PSCred = $PrvCred
$VMCred = $PrvCred
$CcmCred = $PrvCred
#$RadiusCred = $RadiusCred
$RadiusCred = New-Object System.Management.Automation.PSCredential($PrvCred.username.split('\')[1], ($PrvCred.Password))
Clear-DnsClientCache
$HostName = $FQDN.split('.')[0]
# Infoblox
$InfobloxVlanMetadata = Get-ITDIbVlan -Vlan $VLAN -Credential $RadiusCred
$CIDR = $InfobloxVlanMetadata.AssignedTo
[Net.IpAddress]$NetworkId = $Cidr.split('/')[0]
[Net.IPAddress]$IpAddress = (Resolve-DnsName -Name $FQDN -ErrorAction SilentlyContinue).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 = $CIDR.Split('.')
[Net.IPAddress]$DefaultGateway = ($IPSplit[0] + '.' + $IPSplit[1] + '.' + $IPSplit[2] + '.' + (($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 $FQDN -CIDR $CIDR -Credential $RadiusCred
[Net.IPAddress]$IpAddress = (Resolve-DnsName -Name $FQDN -ErrorAction SilentlyContinue).IPAddress
}
#>
If ((Test-NetConnection -ComputerName $IpAddress.IPAddressToString).PingSucceeded) {
Write-Error "IP Address already in use." -ErrorAction Stop
}
# Passwordstate BB before baseline, AB after baseline
If ($FQDN -like "itdcnd*") {
$PasswordStateList = "Peoplesoft Share PW"
}
Else {
$PasswordStateList = "CSRC"
}
# Passwordstate validation WIP
<#$ExistingPassword = Get-ITDPassword -Title $FQDN -UserName itdadmin -Credential $PSCred -ErrorAction SilentlyContinue
If($ExistingPassword){
$LocalCredential = $ExistingPassword
}#>
$LocalCredential = New-ITDPassword -Title $FQDN -UserName itdadmin -Description 'Local Administrator' -PasswordList $PasswordStateList -Credential $PSCred
#$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))
$GuestCredentialAB = New-Object System.Management.Automation.PSCredential ('itdadmin', ($LocalCredential.Password | ConvertTo-SecureString -AsPlainText -Force))
$GuestCredentialBB = New-Object System.Management.Automation.PSCredential ('Administrator', ($LocalCredential.Password | ConvertTo-SecureString -AsPlainText -Force))
#$GuestCredential = $GuestCredentialBB
# VMware
Connect-ITDvCenter -Credential $VMCred
If (Get-VM -Name $FQDN -ErrorAction SilentlyContinue) {
Write-Error "Virtual machine with the name $FQDN already exists." -ErrorAction Stop
Stop
Stop
}
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 = "SQL" }
"Microsoft SQL Enterprise (Academic)" { $ClusterRoot = "WINDOWS" }
"IBM Websphere" { $ClusterRoot = "WAS" }
"Powerschool" { $ClusterRoot = "PS" }
"Pexip" { $ClusterRoot = "TEL" }
}
switch ($Datacenter) {
"Bismarck" { $ClusterInt = 1 }
"Mandan" { $ClusterInt = 2 }
}
$Cluster = $ClusterRoot + $ClusterInt
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 = 'EagerZeroThick'
}
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 = 'EagerZeroThick'
}
Else {
$DatastoreCluster = Get-DatastoreCluster -Name "WINDOWS2_FS92_Gen"
$DiskStorageFormat = 'Thin'
}
}
"SQL1" {
$ViServer = 'itdvmvc1.nd.gov'
$ComputeCluster = Get-Cluster SQL1
$VirtualSwitch = Get-VDSwitch -Name "dvSwitch-PDC-Data-Server"
$DiskStorageFormat = 'EagerZeroedThick'
$DatastoreCluster = Get-DatastoreCluster -Name "SQL1_FS92_Gen"
}
"SQL2" {
$ViServer = 'itdvmvc2.nd.gov'
$ComputeCluster = Get-Cluster SQL2
$VirtualSwitch = Get-VDSwitch -Name "dvSwitch-SDC-Data-Server"
$DiskStorageFormat = 'EagerZeroedThick'
$DatastoreCluster = Get-DatastoreCluster -Name "SQL2_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
}
}
# verify disk will fit
$DiskTotal = 70
If ($DatastoreCluster) {
}
Else {
$DatastoreCluster = Get-DatastoreCluster | Where-Object Name -Like ("*" + $SPItem.Cluster + "*")
}
$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"
switch ($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" }
"Windows Server 2019 Datacenter (64-Bit)" { $Template = "Windows Server 2019 Standard" }
"Windows Server 2022 Datacenter (64-Bit)" { $Template = "Windows Server 2022 Standard" }
Default { Write-Error "Invalid template" -ErrorAction Stop }
}
$PortGroupsAvailable = Get-VDPortgroup -Server $ViServer -VDSwitch $VirtualSwitch
$PortGroup = $PortGroupsAvailable | Where-Object Name -Like ("dvPG_" + $VLAN + "*")
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
}
$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
<#
$NewVMParams = @{
Name = $FQDN;
ResourcePool = $SPItem.Cluster;
Datastore = $DatastoreCluster;
DiskStorageFormat = $DiskStorageFormat;
Template = $Template;
Location = $FolderLocation;
OSCustomizationSpec = $OSSpec;
}
$NewVMParams
New-VM @NewVMParams
#>
#Set-Location C:\Temp # required to make New-VM work, https://communities.vmware.com/thread/591294
# seems fixed on 2022/07/01
try {
Write-Warning $FQDN
Write-Warning $ComputeCluster.Name
Write-Warning $DatastoreCluster
Write-Warning $DiskStorageFormat
Write-Warning $Template
Write-Warning $FolderLocation
Write-Warning $OSSpec
New-VM -Name $FQDN -ResourcePool $ComputeCluster.Name -Datastore $DatastoreCluster -DiskStorageFormat $DiskStorageFormat -Template $Template -Location $FolderLocation -OSCustomizationSpec $OSSpec
}
catch {
Stop
Stop
}
#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 $CPU -MemoryGB $MemoryGB -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
Write-Warning -Message "[$FQDN]:Modify disks 1,2,3"
$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"
$VMDisk1 = $VM | Get-HardDisk | Where-Object Name -EQ "Hard disk 1"
If ($VMDisk1.CapacityGB -lt 60) {
Set-HardDisk -HardDisk $VMDisk1 -CapacityGB 60 -Confirm:$false
}
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 ($MemoryGB + 1)) {
Set-HardDisk -HardDisk $VMDisk2 -CapacityGB ($MemoryGB + 1) -Confirm:$false
}
If (!$VMDisk3) {
$VM | New-HardDisk `
-CapacityGB 20 `
-StorageFormat Thin `
-DiskType Flat `
-Persistence Persistent
}
$VMDisk3 = $VM | Get-HardDisk | Where-Object Name -EQ "Hard disk 3"
If ($VMDisk3.CapacityGB -lt 20) {
Set-HardDisk -HardDisk $VMDisk3 -CapacityGB 20 -Confirm:$false
}
# skipping tag assignment for now
# Set-ITDVMwareVMTagFromSharePoint -ComputerName $FQDN -SharePointCredential $SPCred -Verbose
# Run Guest OS code
# Enable RDP with NLA - can be done with GPO
# Enable WinRM - ITD WinRM enable
# Configure Power Plan - ITD-PowerPlan-HighPerformance
# Activate Windows, KMS on-premise, Azure to Azure
# DVD Drive to Z:
# Expand C:
# Partition/Format the rest, GPT/NTFS
# Configure Page File Disk
# Enabling server manager performance monitors
# Configure Time Zone and NTP - no GPO available
# Disable Windows Firewall
# Join AD
#Initialize-ITDServer -Credential $ADCred
Write-Warning -Message "[$FQDN]:Assigning WMI Tag 000-Prod, SCCM will change it later if required"
Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredentialBB -ScriptType PowerShell -ScriptText {
# Move DVD Drive Mount
try {
Write-Verbose "Create new Class"
$Class = New-Object System.Management.ManagementClass("root\cimv2", [String]::Empty, $null);
$Class["__CLASS"] = "ITD";
$Class.Qualifiers.Add("Static", $true)
$Class.Properties.Add("MyKey", [System.Management.CimType]::String, $false)
$Class.Properties["MyKey"].Qualifiers.Add("Key", $true)
$Class.Properties.Add("LastModified", [System.Management.CimType]::String, $false)
$Class.Properties.Add("DTAP", [System.Management.CimType]::String, $false)
$Class.Properties.Add("Baseline", [System.Management.CimType]::String, $false)
$Class.Put()
Write-Verbose "Create single ITD Object"
Set-WmiInstance -Class ITD -Arguments @{LastModified = (Get-Date); DTAP = "Prod"; Baseline = "000" }
}
catch {
Throw $_
Break
}
}
Write-Warning -Message "[$FQDN]:Checking for DVD drive..."
Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredentialBB -ScriptType PowerShell -ScriptText {
# Move DVD Drive Mount
try {
$dvd_letter = 'Z'
$dvd = Get-WmiObject -Class Win32_Volume -Filter "DriveType=5" | Select-Object -First 1
if ($dvd.Name -notmatch $dvd_letter) {
Write-Verbose -Message "Found DVD drive, switching to $dvd_letter`:"
Set-WmiInstance -InputObject $dvd -Arguments @{DriveLetter = "$dvd_letter`:" } | Out-Null
Write-Verbose -Message "DVD drive moved to drive letter $dvd_letter`:"
}
else {
Write-Verbose -Message "No DVD drive changes required, continuing..."
}
}
catch {
Throw $_
Break
}
}
Write-Warning -Message "[$FQDN]:Checking for unpartitioned space on C: disk..."
Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredentialBB -ScriptType PowerShell -ScriptText {
# Expand C: Partition To Maximum Extent
try {
$cSize = ( Get-Partition -DriveLetter C ).Size
$cMaxSize = ( Get-PartitionSupportedSize -DriveLetter C ).SizeMax
if ($cSize -lt $cMaxSize) {
Write-Verbose -Message "Expanding C: from $($csize / 1GB)GB to $($cMaxSize / 1GB)GB..."
Resize-Partition -DriveLetter C -Size $cMaxSize
Write-Verbose -Message "C: expanded to $($cMaxSize / 1GB)GB."
}
else {
Write-Verbose -Message "C: is already at maximum size, continuing..."
}
}
catch {
Throw $_
Break
}
}
Write-Warning "[$FQDN]:Start Extra Disk(s) config"
Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredentialBB -ScriptType PowerShell -ScriptText {
# Initialize Additional Disks
try {
# Non-initialized and MBR-initialized disks will have 0 partitions by default, but GPT-initialized disks will have 1 system reserved partition by default
$disks = Get-Disk | Where-Object { $_.NumberOfPartitions -eq 0 -or ( $_.PartitionStyle -eq 'GPT' -and $_.NumberOfPartitions -eq 1 ) } | Sort-Object -Property Number
if ($disks) {
Write-Verbose -Message "Found $(@($disks).Count) unpartitioned disks."
# Prevent the "You must format this partition before using it." popup
if (Get-Service ShellHWDetection -ErrorAction SilentlyContinue) { Stop-Service ShellHWDetection -ErrorAction SilentlyContinue }
foreach ($disk in $disks) {
if ($disk.IsOffline) {
Set-Disk $disk.Number -IsOffline $false
Write-Verbose -Message "Brought disk $($disk.Number)($("{0:n0}GB" -f ($disk.Size / 1GB))) online..."
}
if ($disk.IsReadOnly) { Set-Disk $disk.Number -IsReadOnly $false }
if ($disk.PartitionStyle -eq 'RAW') { Initialize-Disk $disk.Number -PartitionStyle GPT -ErrorAction SilentlyContinue }
$diskParam = @{
FileSystem = 'NTFS'
Confirm = $false
}
$driveLetter = [Int][Char]'D'
while (Get-Volume -DriveLetter $([Char]$driveLetter) -ErrorAction SilentlyContinue) {
$driveLetter++
}
$diskParam.DriveLetter = [Char]$driveLetter
if (@($disks).IndexOf($disk) -eq 0 -and (-not (Get-Volume -DriveLetter D -ErrorAction SilentlyContinue))) {
$diskParam.NewFileSystemLabel = 'Temporary Storage'
}
elseif (@($disks).IndexOf($disk) -eq 1 -and (-not (Get-Volume -DriveLetter E -ErrorAction SilentlyContinue))) {
$diskParam.NewFileSystemLabel = 'Data'
}
[void](New-Partition -DiskNumber $disk.Number -DriveLetter $diskParam.DriveLetter -UseMaximumSize)
[void](Format-Volume @diskParam)
}
}
else {
Write-Verbose -Message "No unpartitioned disks found, continuing..."
}
}
catch {
Throw $_
Break
}
finally {
if (Get-Service ShellHWDetection -ErrorAction SilentlyContinue) { Start-Service ShellHWDetection -ErrorAction SilentlyContinue }
}
}
Write-Warning "[$FQDN]:Start Page File Configuration"
Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredentialBB -ScriptType PowerShell -ScriptText {
# Configure Page File
if (Get-Partition -DriveLetter D -ErrorAction SilentlyContinue) {
Write-Verbose -Message "Setting up pagefile.sys on D:..."
try {
if (-not [IO.File]::Exists('D:\pagefile.sys')) {
$autoPage = Get-WmiObject -Class Win32_ComputerSystem -EnableAllPrivileges
$autoPage.AutomaticManagedPagefile = $false
[void]$autoPage.Put()
Write-Verbose -Message "Disabled automatic pagefile management."
$pageFile = Get-WmiObject -Class Win32_PageFileSetting -EnableAllPrivileges
$pageFile.Delete()
Write-Verbose -Message "Deleted C:\pagefile.sys."
Set-WmiInstance -Class Win32_PageFileSetting -Arguments @{ Name = "D:\pagefile.sys"; InitialSize = 0; MaximumSize = 0; } -EnableAllPrivileges | Out-Null
Write-Verbose -Message "System managed page file created on D:\pagefile.sys."
}
else {
Write-Verbose -Message "Pagefile already configured on D:, continuing..."
}
}
catch {
Throw $_
Break
}
}
else {
Write-Verbose -Message "Page file drive not found, cannot set up page file. Continuing server configuration..."
Write-Warning "Page file drive not found, cannot set up page file. Continuing server configuration..."
}
}
Write-Warning -Message "[$FQDN]:Enabling Remote Management..."
Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredentialBB -ScriptType PowerShell -ScriptText {
# Configure Remote Management (RDP/PoSH)
try {
Write-Verbose -Message "Checking WinRM..."
if (Test-WSMan -ErrorAction SilentlyContinue) {
Write-Verbose -Message "WinRM is already enabled."
}
else {
Enable-PSRemoting -Force
Write-Verbose -Message "WinRM is now enabled."
}
Write-Verbose -Message "Checking RDP..."
$RDP = Get-WmiObject Win32_TerminalServiceSetting -Namespace root\cimv2\TerminalServices
$NLA = Get-WmiObject Win32_TSGeneralSetting -Namespace root\cimv2\TerminalServices -Filter "TerminalName='RDP-tcp'"
if ($RDP.AllowTSConnections -eq 0) {
Write-Verbose -Message "RDP is disabled, enabling..."
$RDP.SetAllowTSConnections(1, 1) | Out-Null
Write-Verbose -Message "RDP is enabled."
}
else {
Write-Verbose -Message "RDP is already enabled, checking NLA security..."
}
if ($NLA.UserAuthenticationRequired -eq 0) {
Write-Verbose -Message "RDP is not NLA secured, enabling..."
$NLA.SetUserAuthenticationRequired(1) | Out-Null
Write-Verbose -Message "RDP is now NLA secured."
}
else {
Write-Verbose -Message "RDP is already NLA secured."
}
}
catch {
Throw $_
Break
}
}
Write-Warning -Message "[$FQDN]:Checking current power plan..."
Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredentialBB -ScriptType PowerShell -ScriptText {
# Configure Power Plan
try {
$powerPlans = powercfg -l
if ($powerPlans -match '\*$' -notmatch 'High performance') {
$currentPlan = [regex]::Match($powerPlans, '(?<=(\())[^)]+(?=(\)\s\*))').Value
Write-Verbose -Message "Power plan is currently set to $currentPlan, changing to High Performance..."
$highPerformance = [regex]::Match($powerPlans, '([\d\w-\S]+)(?=\s+\(High performance\))').Value
[void](powercfg -setactive $highPerformance)
Write-Verbose -Message "Power plan set to High Performance."
}
else {
Write-Verbose -Message "Power plan already configured for High Performance."
}
[void](& w32tm.exe /resync /nowait)
}
catch {
Throw $_
Break
}
}
$TimeSyncFunc = {
# Configure Time/Date Settings
Write-Verbose -Message "Checking current time/date settings..."
$Domain = "<DomainName>"
try {
if ((Get-TimeZone).Id -ne 'Central Standard Time') {
Write-Verbose -Message "Current time zone set to $((Get-TimeZone).Id), setting to Central Standard Time."
Set-TimeZone -Id 'Central Standard Time'
Write-Verbose -Message "Time zone set to Central Standard Time."
}
else {
Write-Verbose -Message "Time zone is already set to Central Standard Time."
}
<#
Write-Verbose -Message "Beginning a time synchronization..."
if ((Get-Service W32Time).Status -eq 'Stopped') {
Start-Service W32Time
}
[void](& w32tm.exe /config /manualpeerlist:$Domain /syncfromflags:all /update)
[void](& w32tm.exe /resync /nowait)
# Start background job to check time service
$tmJob = Start-Job -Name 'ManualTimeSync' -ScriptBlock {
do {
$tmOut = & w32tm.exe /query /status /verbose
Start-Sleep -Seconds 10
} until($tmOut -match '^Last Sync Error: 0\D+$')
}
# If after three minutes time still has not synched, move on. This usually causes no problems.
if ((Wait-Job -Job $tmJob -Timeout 180).State -eq 'Completed') {
Write-Warning -Message "Time synchronization with $($Domain.ToLower()) successful."
}
else {
[void](Stop-Job -Job $tmJob)
Write-Warning -Message "Time synchronization with $($Domain.ToLower()) failed."
}
#>
}
catch {
Throw $_
Break
}
}
$TimeSyncScriptBlock = $TimeSyncFunc -replace '<DomainName>', $DomainName
$VM | Invoke-VMScript -GuestCredential $GuestCredentialBB -ScriptType PowerShell -ScriptText $TimeSyncScriptBlock
#>
Write-Warning -Message "[$FQDN]:Enabling the server manager performance monitors..."
Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredentialBB -ScriptType PowerShell -ScriptText {
# Enable Performance Counters
try {
if (Get-ScheduledTask -TaskName "Server Manager Performance Monitor" | Where-Object State -NE "Running" -ErrorAction SilentlyContinue) {
Enable-ScheduledTask -TaskPath "\Microsoft\Windows\PLA\" -TaskName "Server Manager Performance Monitor" | Start-ScheduledTask
Write-Verbose -Message "Performance monitors enabled."
}
else {
Write-Verbose -Message "Performance monitors already enabled, continuing..."
}
}
catch {
Throw $_
Break
}
}
Write-Warning -Message "[$FQDN]:Disable Windows Firewall"
Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredentialBB -ScriptType PowerShell -ScriptText {
# Disable Windows Firewall
Write-Verbose -Message "Checking for active Windows Firewall..."
if ((Get-NetFirewallProfile).Enabled -contains 'True') {
Write-Verbose -Message "Windows Firewall is still enabled, disabling it..."
Set-NetFirewallProfile -Profile Domain, Public, Private -Enabled False
Write-Verbose -Message "Windows Firewall disabled."
}
else {
Write-Verbose -Message "Windows Firewall already disabled, continuing..."
}
}
# Active Directory
Write-Warning "[$FQDN]:Join Active Directory (if required)"
$DomainName = $FQDN.Substring($FQDN.IndexOf(".") + 1)
switch ($DomainName) {
'nd.gov' {
$SearchBaseDomain = "dc=nd,dc=gov"
}
'ndcloud.gov' {
$SearchBaseDomain = "dc=ndcloud,dc=gov"
}
}
If ($DomainName -eq "nd.gov") {
$OUAppName = Get-ADOrganizationalUnit -Server $DomainName -SearchBase ("OU=SERVERS,ou=COMPUTERS,ou=ITD," + $SearchBaseDomain) -Filter {Name -eq $AppName}
If (!($OUAppName)) {
$OUAppName = Get-ADOrganizationalUnit -SearchBase ("OU=SERVERS,ou=COMPUTERS,ou=ITD," + $SearchBaseDomain) -Filter { Name -eq 'All-General' }
}
$ExistingADComputer = Get-ADComputer -Filter { Name -eq $Hostname }
If ($ExistingADComputer) {
If ($ExistingADComputer.DistinguishedName -like ("*" + $SPItem.AppName + "*") -or $ExistingADComputer.DistinguishedName -like "*All-General*") {
Write-Warning "AD object already exists, OU path does match"
$OuFinal = $ExistingADComputer.DistinguishedName -replace '^.+?(?<!\\),', ''
}
Else {
Write-Error "AD object already exists, OU path mismatch"
Exit
Exit
}
}
Else {
switch ($SPItem.Environment) {
'Test' {
If ($AppName -like "Shared-Peoplesoft*") { $EnvString = "Non-Prod" }
Else { $EnvString = "Test" }
$OuAppNameEnv = Get-ADOrganizationalUnit -SearchBase $OUAppName.DistinguishedName -Filter * | Where-Object Name -Like "*$EnvString*"
}
'Production' {
$EnvString = "Prod"
$OuAppNameEnv = Get-ADOrganizationalUnit -SearchBase $OUAppName.DistinguishedName -Filter * | Where-Object Name -Like "*$EnvString*"
}
}
If ($OuAppNameEnv) { $OUFinal = $OUAppNameEnv.DistinguishedName }
Else { $OuFinal = $OUAppName.DistinguishedName }
#New-ADComputer -Name $HostName.ToUpper() -Path $OUFinal -Credential $ADCred -Description ($SPItem | Select-Object AppName, Environment | ConvertTo-Json)
}
$FirstScriptBlock = { $DomainJoinCred = New-Object System.Management.Automation.PSCredential('svcitdvmdomainjoin', ('hypes-Vgv8h89' | ConvertTo-SecureString -AsPlainText -Force)) }
$SecondScriptText = 'Add-Computer -DomainName <DomainName> -OUPath "<OuPath>" -Credential $DomainJoinCred'
$SecondScriptText = $SecondScriptText -replace '<DomainName>', $DomainName
$SecondScriptText = $SecondScriptText -replace '<OuPath>', $OuFinal
$SecondScriptText = $SecondScriptText -replace '<OuPath>', ("OU=SERVERS,ou=COMPUTERS,ou=ITD," + $SearchBaseDomain)
Write-Warning -Message "[$FQDN]:Invoke-VMScript to AD join"
$InvokeVMScriptFunc = [System.Management.Automation.ScriptBlock]::Create("$FirstScriptBlock ; $SecondScriptText")
Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredentialBB -ScriptType PowerShell -ScriptText $InvokeVMScriptFunc
Write-Warning -Message "[$FQDN]:Restart VMGuest, wait for Tools, then 90 seconds after"
Get-VM -Name $FQDN | Restart-VMGuest -Confirm:$false
Wait-Tools -VM (Get-VM -Name $FQDN)
Start-Sleep -Seconds 90
}
Write-Warning ("[$FQDN]:Copying SCCM client installer to C:\temp... " + (Get-Date))
Copy-VMGuestFile -Source C:\SCCM_Client\ -Destination C:\temp\SCCM_Client -VM (Get-VM -Name $FQDN) -LocalToGuest -GuestCredential $GuestCredentialAB -Force
Write-Warning ("[$FQDN]:SCCM client copy complete " + (Get-Date))
#E:\AutoBuild\SCCM_Client\
# Check if SCCM automatically installed the SCCM client and registered it
$CcmRegistered = $false
$CcmRegistration = Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredentialAB -ScriptType PowerShell -ScriptText {
Get-Content C:\windows\ccm\logs\ClientIDManagerStartup.log
}
If ($CcmRegistration.ScriptOutput -match "Client is registered") {
Write-Warning "Client is registered."
$CcmRegistered = $true
}
ElseIf ($CcmRegistration.ScriptOutput -match "Client is already registered") {
Write-Warning "Client is already registered."
$CcmRegistered = $true
}
If ($CcmRegistered -eq $false) {
Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredentialAB -ScriptType PowerShell -ScriptText {
If (Get-Process -Name ccmsetup -ErrorAction SilentlyContinue) {
Write-Warning "CCM client is already installing"
$CcmRegistered = $true
}
ElseIf (Get-Process -Name ccmexec -ErrorAction SilentlyContinue) {
Write-Warning "CCM client is already installed"
$CcmRegistered = $true
}
Else {
Write-Warning -Message "Installing SCCM Client..."
Invoke-Expression -Command "C:\temp\SCCM_Client\ccmsetup.exe SMSSITECODE=ITD SMSMP=itdsccmp2.nd.gov DNSSUFFIX=nd.gov"
}
}
}
Write-Warning "[$FQDN]:Register SCCM Client"
While ($CcmRegistered -eq $false) {
$CcmRegistration = Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredentialAB -ScriptType PowerShell -ScriptText {
Get-Content C:\windows\ccm\logs\ClientIDManagerStartup.log
}
If ($CcmRegistration.ScriptOutput -match "Client is registered") {
Write-Warning "Client is registered."
$CcmRegistered = $true
}
ElseIf ($CcmRegistration.ScriptOutput -match "Client is already registered") {
Write-Warning "Client is already registered."
$CcmRegistered = $true
}
ElseIf ($CcmRegistered -eq $false) { Start-Sleep -Seconds 30 }
}
Write-Warning -Message "[$FQDN]:Approve SCCM Client"
#Start-Sleep -Seconds 30 # ADD LOOP/SMARTS TO WAIT FOR DISCOVERY AND ANOTHER FOR APPROVAL
Invoke-Command -ComputerName itdsccmp2.nd.gov -Credential $CcmCred -ArgumentList $Hostname -ScriptBlock {
Import-Module 'D:\Program Files\Microsoft Configuration Manager\AdminConsole\bin\ConfigurationManager.psd1'
$PSDrives = Get-PSDrive
If ($PSDrives | Where-Object Name -EQ "ITD") {
# ITD Drive exists, do nothing
}
else {
New-PSDrive -Name "ITD" -PSProvider AdminUI.PS.Provider\CMSite -Root itdsccmp2.nd.gov
}
Set-Location ITD:\
$Device = Get-CMDevice -Name $args[0]
If ($Device.IsApproved -eq 0) {
Approve-CMDevice -DeviceName $args[0]
}
}
# vcenter tags
#AppName Tag
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 $Environment) -Server $VIServer
Write-Warning "[$FQDN]:Trigger SCCM MachinePolicy First Check-in"
Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredentialAB -ScriptType PowerShell -ScriptText {
[void] ([wmiclass] "\\localhost\root\ccm:SMS_Client").TriggerSchedule("{00000000-0000-0000-0000-000000000021}");
}
Write-Warning "[$FQDN]:Trigger SCCM MachinePolicy"
Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredentialAB -ScriptType PowerShell -ScriptText {
[void] ([wmiclass] "\\localhost\root\ccm:SMS_Client").TriggerSchedule("{00000000-0000-0000-0000-000000000021}");
}
#Start-Sleep -Seconds 180
Write-Warning -Message '[$FQDN]:Waiting for network connectivity / Then KVM Activation...'
Get-VM -Name $FQDN | Invoke-VMScript -GuestCredential $GuestCredentialAB -ScriptType PowerShell -ScriptText {
# Pause until network connectivity is available
$KMS = 'kms.nd.gov'
try {
$nwJob = Start-Job -Name 'NetworkCheck' -ScriptBlock {
Param ( [String]$KMS )
do {
$nwStatus = Test-NetConnection -ComputerName $KMS -Port 1688 -InformationLevel Quiet
Start-Sleep -Seconds 10
} until($nwStatus)
} -ArgumentList $KMS
# If after 30 seconds the network connection is not responding continue on
if ((Wait-Job -Job $nwJob -Timeout 30).State -eq 'Completed') {
Write-Verbose -Message 'Network connectivity has been verified.'
}
else {
[void](Stop-Job -Job $nwJob)
Write-Verbose -Message 'Network connectivity could not be verified.'
}
}
catch {
Throw $_
Break
}
# Activate via KMS
Write-Verbose -Message "Activating windows against $KMS..."
if (!([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) {
Start-Process powershell.exe "-NoProfile -ExecutionPolicy Bypass -File `"$PSCommandPath`"" -Verb RunAs; exit
}
try {
cscript C:\Windows\System32\slmgr.vbs /skms $KMS | Out-Null
cscript C:\Windows\System32\slmgr.vbs /ato | Out-Null
Write-Verbose -Message "Checking activation status..."
$kmsOut = cscript C:\Windows\System32\slmgr.vbs /dli
if (($kmsOut | Select-String -Pattern '^License Status:') -match 'Licensed') {
Write-Verbose -Message "Windows successfully activated."
}
else {
Write-Verbose -Message "Windows failed to activate, run slmgr commands manually. Ensure server time is correct."
Write-Warning -Message "Windows failed to activate, run slmgr commands manually. Ensure server time is correct."
}
}
catch {
Throw $_
Break
}
}
Write-Warning "[$FQDN]:End"
<#
Invoke-Command -ComputerName $FQDNs -Credential $PrvCred -ScriptBlock { Get-Process -Name ccmexec*, cohesity*, cyserver*, nessus*, vmtoolsd* }
Write-Warning "[$FQDN]:Trigger SCCM MachinePolicy First Check-in"
Invoke-Command -ComputerName $FQDNs -Credential $PrvCred -ScriptBlock {
[void] ([wmiclass] "\\localhost\root\ccm:SMS_Client").TriggerSchedule("{00000000-0000-0000-0000-000000000021}");
}#>
@@ -0,0 +1,18 @@
$OVServers = Get-OVServer
ForEach($OVServer in $OVServers){
$Enclosure = $OVServer.Name.split('_')[0]
$VMHost = Get-VMHost -Name $OVServer.ServerName
$ViServer = $VMHost.Uid.Split("@")[1].Split(':')[0]
$OldTagAssignment = $VMhost | Get-TagAssignment
$OldTag = $OldTagAssignment.Tag
$NewTag = Get-Tag -Category "HPE Enclosure" -Name $Enclosure -Server $ViServer
If ($OldTag -eq $NewTag){
}
Else{
$OldTagAssignment | Remove-TagAssignment -Confirm:$false
$VMHost | New-TagAssignment -Tag $NewTag
}
}
@@ -0,0 +1,245 @@
function Set-ITDVMwareVMTag {
[CmdletBinding()]
param
(
[string]
$ComputerName,
[string]
$AppName,
[string]
$Dtap,
[string]
$OperatingSystem,
[string]
$StartupPriority
)
begin {
}
process {
$VMs = Get-VM -Name $ComputerName | Where-Object { $_.ExtensionData.summary.config.ManagedBy.Type -ne "placeholderVm" }
If ($VMs) {
ForEach ($VM in $VMs) {
#AppName Tag
Write-Verbose ($VM.Name + ": AppName Tag Start")
$OldTag = Get-TagAssignment -Category AppName -Entity $VM
$VIServer = $VM.Uid.split('@')[1].split(':')[0]
$OldTagName = $OldTag.tag.name
$NewTagName = $AppName
If ($OldTagName -ne $NewTagName) {
Write-Verbose ($VM.Name + " AppName old and new tags different")
Write-Verbose ("Old Tag " + $OldTagName)
Write-Verbose ("New Tag " + $NewTagName)
If ($OldTag) { $OldTag | Remove-TagAssignment -Confirm:$false -ErrorAction SilentlyContinue; Write-Host ($VM.Name + " Tag Removed") } #Errors with Remove-TagAssignment : Cannot bind argument to parameter 'TagAssignment' because it is null. --- but still works
#Get-Tag -Category AppName -Name $NewTagName -Server $VIServer
New-TagAssignment -Entity (Get-VM $VM.Name -Server $VIServer -OutVariable VM) -Tag (Get-Tag -Server $VIServer -Category AppName -Name $NewTagName) -Server $VIServer
Write-Verbose ($VM.Name + " tag updated " + $VIServer)#
}
Write-Verbose ($VM.Name + ": AppName Tag End")
$OldTag = $null
$VIServer = $null
$OldTagName = $null
$NewTagName = $null
#DTAP Tag
Write-Verbose ($VM.Name + ": DTAP Tag Start")
$OldTag = Get-TagAssignment -Category DTAP -Entity $VM
$VIServer = $VM.Uid.split('@')[1].split(':')[0]
$OldTagName = $OldTag.tag.name
$NewTagName = $DTAP
If ($OldTagName -ne $NewTagName) {
Write-Verbose ($VM.Name + " DTAP old and new tags different")
Write-Verbose ("Old Tag " + $OldTagName)
Write-Verbose ("New Tag " + $NewTagName)
If ($OldTag) { $OldTag | Remove-TagAssignment -Confirm:$false -ErrorAction SilentlyContinue; Write-Host ($VM.Name + " Tag Removed") } #Errors with Remove-TagAssignment : Cannot bind argument to parameter 'TagAssignment' because it is null. --- but still works
#Get-Tag -Category AppName -Name $NewTagName -Server $VIServer
New-TagAssignment -Entity (Get-VM $VM.Name -Server $VIServer -OutVariable VM) -Tag (Get-Tag -Server $VIServer -Category DTAP -Name $NewTagName) -Server $VIServer
Write-Verbose ($VM.Name + " tag updated " + $VIServer)
}
Write-Verbose ($VM.Name + ": DTAP Tag End")
$OldTag = $null
$VIServer = $null
$OldTagName = $null
$NewTagName = $null
#Startup Priority
Write-Verbose ($VM.Name + ": StartupPriority Tag Start")
$OldTag = Get-TagAssignment -Category 'StartupPriority' -Entity $VM
$VIServer = $VM.Uid.split('@')[1].split(':')[0]
$OldTagName = $OldTag.tag.name
$NewTagName = $StartupPriority
If ($OldTagName -ne $NewTagName) {
Write-Verbose ($VM.Name + " StartupPriority old and new tags different")
Write-Verbose ("Old Tag " + $OldTagName)
Write-Verbose ("New Tag " + $NewTagName)
If ($OldTag) { $OldTag | Remove-TagAssignment -Confirm:$false -ErrorAction SilentlyContinue; Write-Host ($VM.Name + " Tag Removed") } #Errors with Remove-TagAssignment : Cannot bind argument to parameter 'TagAssignment' because it is null. --- but still works
#Get-Tag -Category AppName -Name $NewTagName -Server $VIServer
New-TagAssignment -Entity (Get-VM $VM.Name -Server $VIServer -OutVariable VM) -Tag (Get-Tag -Server $VIServer -Category 'StartupPriority' -Name $NewTagName) -Server $VIServer
Write-Verbose ($VM.Name + " tag updated " + $VIServer)
}
Write-Verbose ($VM.Name + ": StartupPriority Tag End")
$OldTag = $null
$VIServer = $null
$OldTagName = $null
$NewTagName = $null
# OS Tag
Write-Verbose ($VM.Name + ": OS Tag Start")
$OldTag = Get-TagAssignment -Category "Operating System" -Entity $VM
$VIServer = $VM.Uid.split('@')[1].split(':')[0]
$OldTagName = $OldTag.tag.name
$NewTagName = $OperatingSystem
If ($OldTagName -ne $NewTagName) {
Write-Verbose ($VM.Name + " OS old and new tags different")
Write-Verbose ("Old Tag " + $OldTagName)
Write-Verbose ("New Tag " + $NewTagName)
If ($OldTag) { $OldTag | Remove-TagAssignment -Confirm:$False -ErrorAction SilentlyContinue; Write-Host ($VM.Name + " Tag Removed") }
If ($NewTagName -ne "None") {
New-TagAssignment -Entity (Get-VM $VM.Name -Server $VIServer -OutVariable VM) -Tag (Get-Tag -Server $VIServer -Category 'Operating System' -Name $NewTagName) -Server $VIServer
Write-Verbose ($VM.Name + " tag updated " + $VIServer)
}
else {
Write-Verbose ($VM.Name + " tag invalid or None " + $VIServer)
}
}
$OldTag = $null
$VIServer = $null
$OldTagName = $null
$NewTagName = $null
Write-Verbose ($VM.Name + ": OS Tag End")
# Licensing Tag
Write-Verbose ($VM.Name + ": Licensing Restrictions Tag Start")
$OldTag = Get-TagAssignment -Category "LicensingRestrictions" -Entity $VM
$VIServer = $VM.Uid.split('@')[1].split(':')[0]
$OldTagName = $OldTag.tag.name
$NewTagName = $LicensingRestrictions
If ($OldTagName -ne $NewTagName) {
Write-Verbose ($VM.Name + " Licensing old and new tags different")
Write-Verbose ("Old Tag " + $OldTagName)
Write-Verbose ("New Tag " + $NewTagName)
If ($OldTag) { $OldTag | Remove-TagAssignment -Confirm:$False -ErrorAction SilentlyContinue; Write-Host ($VM.Name + " Tag Removed") }
If ($NewTagName -ne "None") {
New-TagAssignment -Entity (Get-VM $VM.Name -Server $VIServer -OutVariable VM) -Tag (Get-Tag -Server $VIServer -Category 'LicensingRestrictions' -Name $NewTagName) -Server $VIServer
Write-Verbose ($VM.Name + " tag updated " + $VIServer)
}
else {
Write-Verbose ($VM.Name + " tag invalid or None " + $VIServer)
}
}
$OldTag = $null
$VIServer = $null
$OldTagName = $null
$NewTagName = $null
Write-Verbose ($VM.Name + ": Licensing Tag End")
$OldTag = $null
$VIServer = $null
$OldTagName = $null
$NewTagName = $null
<# SRM Recovery Type Tags
Write-Verbose ($VM.Name + ": SRM Recovery Type Tag Start")
$OldTag = Get-TagAssignment -Category "SRM Recovery Type" -Entity $VM
$VIServer = $VM.Uid.split('@')[1].split(':')[0]
$OldTagName = $OldTag.tag.name
If ($VM.ExtensionData.summary.config.ManagedBy.Type -eq "placeholderVm" ) {
#If VM is placeholder
$NewTagName = "Placeholder"
}
Else {
$NewTagName = $SPItem.SRM_RecoveryVMtype
}
If ($OldTagName -ne $NewTagName) {
Write-Verbose ($VM.Name + " SRM Recovery Type old and new tags different")
Write-Verbose ("Old Tag " + $OldTagName)
Write-Verbose ("New Tag " + $NewTagName)
If ($OldTag) { $OldTag | Remove-TagAssignment -Confirm:$False -ErrorAction SilentlyContinue; Write-Host ($VM.Name + " Tag Removed") }
If ($NewTagName -ne "None") {
New-TagAssignment -Entity (Get-VM $VM.Name -Server $VIServer -OutVariable VM) -Tag (Get-Tag -Server $VIServer -Category 'SRM Recovery Type' -Name $NewTagName) -Server $VIServer
Write-Verbose ($VM.Name + " tag updated " + $VIServer)
}
else {
Write-Verbose ($VM.Name + " tag invalid or None " + $VIServer)
}
}
Write-Verbose ($VM.Name + ": SRM Recovery Type Tag End")#>
$OldTag = $null
$VIServer = $null
$OldTagName = $null
$NewTagName = $null
<#VR RPO Tag
Write-Verbose ($VM.Name + ": SRM Tag Start")
$OldTag = Get-TagAssignment -Category 'VR RPO' -Entity $VM
$VIServer = $VM.Uid.split('@')[1].split(':')[0]
$OldTagName = $OldTag.tag.name
$NewTagName = $SPItem.DR_Protection -replace "VMware: "
If ($OldTagName -ne $NewTagName) {
Write-Verbose ($VM.Name + " SRM old and new tags different")
Write-Verbose ("Old Tag " + $OldTagName)
Write-Verbose ("New Tag " + $NewTagName)
If ($OldTag) { $OldTag | Remove-TagAssignment -Confirm:$false -ErrorAction SilentlyContinue; Write-Host ($VM.Name + " Tag Removed") } #Errors with Remove-TagAssignment : Cannot bind argument to parameter 'TagAssignment' because it is null. --- but still works
#Get-Tag -Category AppName -Name $NewTagName -Server $VIServer
If ($NewTagName -ne "None") {
New-TagAssignment -Entity (Get-VM $VM.Name -Server $VIServer -OutVariable VM) -Tag (Get-Tag -Server $VIServer -Category 'VR RPO' -Name $NewTagName) -Server $VIServer
Write-Verbose ($VM.Name + " tag updated " + $VIServer)
}
else {
Write-Verbose ($VM.Name + " tag invalid or None " + $VIServer)
}
}#>
}
}
Else {
}
#}
<#catch {
Write-Error ($VM.Name + " tag errored")
Write-Error $error[-1]
}#>
}
end {
}
}
@@ -0,0 +1,3 @@
$AllVMs = Get-Datacenter -Name Primary* | Get-VM | Where-Object { $_.ExtensionData.Summary.Config.ManagedBy.Type -ne "placeholderVm" -and $_.Name -notlike "vCLS*" }
$AllVMs | Select Name,NumCpu,MemoryGB,@{n='Cluster';e={$_.VMHost | Get-Cluster}},@{n='SRM Recovery Type';e={($_ | Get-TagAssignment -Category "SRM Recovery Type").Tag.Name}} -OutVariable result
@@ -0,0 +1,177 @@
<#
.SYNOPSIS
Daily VM metadata report for PowerBI trending and hardware capacity planning.
.DESCRIPTION
Collects VM metadata from vCenter including compute, storage, OS, and VMware Tools
information using only data available within vCenter (no direct guest connections).
Exports a timestamped CSV each run -- append daily runs to build a historical dataset
suitable for PowerBI trend analysis and physical hardware purchasing decisions.
.PARAMETER vCenterServers
One or more vCenter server hostnames. Defaults to itdvmvc1.nd.gov and itdvmvc2.nd.gov.
.PARAMETER DatacenterFilter
Wildcard filter applied to datacenter names. Defaults to 'Primary*'.
.PARAMETER OutputPath
Directory where CSV and log files are written.
Defaults to C:\ITDSCRIPT\Reports\VMMetadata.
.PARAMETER CredentialPath
Path to a saved PSCredential XML file for unattended/scheduled runs.
Create one interactively with:
Get-Credential | Export-Clixml -Path C:\ITDSCRIPT\Creds\vCenter.xml
When omitted the script prompts for credentials.
.EXAMPLE
# Interactive run
.\VMware-VMDailyMetadataReport.ps1
.EXAMPLE
# Scheduled / unattended run
.\VMware-VMDailyMetadataReport.ps1 -CredentialPath 'C:\ITDSCRIPT\Creds\vCenter.xml'
.NOTES
Scheduled Task suggestion (run as service account that owns the credential XML):
Program : powershell.exe
Args : -NonInteractive -ExecutionPolicy Bypass -File "C:\ITDSCRIPT\VMware-VMDailyMetadataReport.ps1" -CredentialPath "C:\ITDSCRIPT\Creds\vCenter.xml"
Trigger : Daily at 06:00
Guest OS disk capacity / used columns are populated only for powered-on VMs with
VMware Tools running; they will be empty for powered-off VMs and SRM placeholders.
#>
[CmdletBinding()]
param(
[string] $OutputPath = 'C:\temp\VM_Trends\'
)
#region --- Setup ---------------------------------------------------------------
$RunDate = Get-Date
$DateStamp = $RunDate.ToString('yyyyMMdd')
$Timestamp = $RunDate.ToString('yyyy-MM-dd HH:mm:ss')
if (-not (Test-Path -Path $OutputPath)) {
New-Item -ItemType Directory -Path $OutputPath | Out-Null
}
Start-Transcript -Path (Join-Path $OutputPath "VMMetadataReport_$DateStamp.log") -Append
#endregion
#region --- Build VMHost -> Cluster/Datacenter Lookups (avoids per-VM API calls) -
Write-Verbose 'Building host-to-cluster and host-to-datacenter maps...'
$HostClusterMap = @{}
$HostDatacenterMap = @{}
Get-Datacenter | ForEach-Object {
$DatacenterName = $_.Name
Get-VMHost -Location $_ | ForEach-Object {
$HostDatacenterMap[$_.Name] = $DatacenterName
}
}
Get-Cluster | ForEach-Object {
$ClusterName = $_.Name
Get-VMHost -Location $_ | ForEach-Object {
$HostClusterMap[$_.Name] = $ClusterName
}
}
#endregion
#region --- Collect VM Data -----------------------------------------------------
Write-Verbose "Gathering VMs"
# Include ALL VMs (SRM placeholders flagged via column, not excluded).
# vCLS agent VMs are excluded -- they are vSphere internal and not customer workloads.
$AllVMs = Get-VM | Where-Object { $_.Name -notlike 'vCLS*' }
Write-Verbose "Processing $($AllVMs.Count) VMs..."
$Results = foreach ($VM in $AllVMs) {
$Ext = $VM.ExtensionData # single API object -- reuse for all fields
#--- SRM placeholder detection
$IsSRMPlaceholder = $Ext.Summary.Config.ManagedBy.Type -eq 'placeholderVm'
#--- Cluster / Datacenter (null-safe: standalone hosts have no cluster entry)
$ClusterName = $HostClusterMap[$VM.VMHost.Name]
$DatacenterName = $HostDatacenterMap[$VM.VMHost.Name]
#--- Storage platform parsed from datastore name convention: VMCLUSTER_LUN_PLATFORM_Desc
# Segment 2 = storage platform identifier (e.g. FS92, A9K).
# Cluster grouping uses the compute Cluster column -- no need to re-derive it here.
$StoragePlatforms = foreach ($DSName in $Ext.Config.DatastoreUrl.Name) {
$Segments = $DSName -split '_'
if ($Segments.Count -ge 3) { $Segments[2] }
}
$StoragePlatform = ($StoragePlatforms | Sort-Object -Unique) -join '; '
#--- VMware Tools guest disk info
# Populated only when Tools is running; null otherwise.
$GuestDiskCapacityGB = $null
$GuestDiskUsedGB = $null
if ($Ext.Guest.Disk) {
$TotalCapBytes = ($Ext.Guest.Disk | Measure-Object -Property Capacity -Sum).Sum
$TotalFreeBytes = ($Ext.Guest.Disk | Measure-Object -Property FreeSpace -Sum).Sum
$GuestDiskCapacityGB = [Math]::Round($TotalCapBytes / 1GB, 2)
$GuestDiskUsedGB = [Math]::Round(($TotalCapBytes - $TotalFreeBytes) / 1GB, 2)
}
[PSCustomObject]@{
# --- Identity & grouping
ReportDate = $Timestamp # for PowerBI time-series/trend axis
VMName = $VM.Name
Datacenter = $DatacenterName
Cluster = $ClusterName
PowerState = $VM.PowerState
IsSRMPlaceholder = $IsSRMPlaceholder
StoragePlatform = $StoragePlatform
GuestOS = $Ext.Guest.GuestFullName
# --- Compute
vCPUs = $VM.NumCpu
MemoryGB = $VM.MemoryGB
# --- Datastore-level storage
# ProvisionedSpaceGB : maximum the VM could consume (thin disks counted at max size)
# UsedSpaceGB : bytes actually committed on datastores right now
ProvisionedSpaceGB = [Math]::Round($VM.ProvisionedSpaceGB, 2)
UsedSpaceGB = [Math]::Round($VM.UsedSpaceGB, 2)
# --- Guest OS-level storage (from VMware Tools; null when Tools not running)
# GuestDiskCapacityGB : sum of all volume capacities seen inside the guest
# GuestDiskUsedGB : sum of space consumed across those volumes
GuestDiskCapacityGB = $GuestDiskCapacityGB
GuestDiskUsedGB = $GuestDiskUsedGB
# --- VMware Tools
# ToolsRunningStatus : guestToolsRunning | guestToolsNotRunning | guestToolsExecutingScripts
# ToolsVersionStatus : guestToolsCurrent | guestToolsNeedUpgrade | guestToolsUnmanaged | guestToolsTooNew
# ToolsVersion : numeric build version string reported by vCenter
ToolsRunningStatus = $Ext.Guest.ToolsRunningStatus
ToolsVersionStatus = $Ext.Guest.ToolsVersionStatus
ToolsVersion = $Ext.Guest.ToolsVersion
}
}
#endregion
#region --- Export --------------------------------------------------------------
$OutputFile = Join-Path $OutputPath "VMMetadata_$DateStamp.csv"
$Results | Export-Csv -Path $OutputFile -NoTypeInformation
Write-Verbose "Exported $($Results.Count) VM records to: $OutputFile"
#endregion
#region --- Cleanup -------------------------------------------------------------
Stop-Transcript
#endregion
@@ -0,0 +1,42 @@
# report current status
$AllVMs = Get-VM | Where-Object { $_.ExtensionData.Summary.Config.ManagedBy.Type -ne "placeholderVm" }
$WS2022VMs = $AllVMs | Where-Object { $_.ExtensionData.Guest.GuestFullName -like "*2022*" } | Sort-Object Name
$WS2022VMs | select Name, @{n = 'EfiSecureBootEnabled'; e = { $_.ExtensionData.Config.BootOptions.EfiSecureBootEnabled } }
$VMNames = @"
itdexchtest1.testnd.gov
itdexchtest2.testnd.gov
itdexch1.nd.gov
itdexch2.nd.gov
"@
$VMNames = ConvertTo-Array -MultiLineString $VMNames
# power off VMs
ForEach ($VMName in $VMNames) {
Get-VM -Name $VMName | Where-Object { $_.ExtensionData.Summary.Config.ManagedBy.Type -ne "placeholderVm" } | Stop-VMGuest -Confirm:$false
}
# wait for all to be powered off
Get-VM -Name $VMNames
# disable secure boot on all of them
ForEach ($VMname in $VMNames) {
$vm = Get-VM -Name $VMName | Where-Object { $_.ExtensionData.Summary.Config.ManagedBy.Type -ne "placeholderVm" }
$spec = New-Object VMware.Vim.VirtualMachineConfigSpec
$spec.Firmware = [VMware.Vim.GuestOsDescriptorFirmwareType]::efi
$boot = New-Object VMware.Vim.VirtualMachineBootOptions
$boot.EfiSecureBootEnabled = $false # false to disable obviously
$spec.BootOptions = $boot
$vm.ExtensionData.ReconfigVM($spec)
}
# validate
Get-VM -Name $VMNames | Where-Object { $_.ExtensionData.Summary.Config.ManagedBy.Type -ne "placeholderVm" }| select Name, @{n = 'EfiSecureBootEnabled'; e = { $_.ExtensionData.Config.BootOptions.EfiSecureBootEnabled } }
# power on
ForEach($VMName in $VMNames){
Get-VM -Name $VMName | Where-Object { $_.ExtensionData.Summary.Config.ManagedBy.Type -ne "placeholderVm" } | Start-VM
}
@@ -0,0 +1,42 @@
# report current status
$AllVMs = Get-VM | Where-Object { $_.ExtensionData.Summary.Config.ManagedBy.Type -ne "placeholderVm" }
$WS2022VMs = $AllVMs | Where-Object { $_.ExtensionData.Guest.GuestFullName -like "*2022*" } | Sort-Object Name
$WS2022VMs | select Name, @{n = 'EfiSecureBootEnabled'; e = { $_.ExtensionData.Config.BootOptions.EfiSecureBootEnabled } }
$VMNames = @"
itdaddressprot2.nd.gov
itdqlikreptst1.ndcloud.gov
itdqlikrepprd1.ndcloud.gov
itdexch1.nd.gov
itdexch2.nd.gov
itdexchtest1.testnd.gov
itdexchtest2.testnd.gov
"@
$VMNames = ConvertTo-Array -MultiLineString $VMNames
# power off VMs
ForEach ($VMName in $VMNames) {
Get-VM -Name $VMName | Where-Object { $_.ExtensionData.Summary.Config.ManagedBy.Type -ne "placeholderVm" } | Stop-VMGuest -Confirm:$false
}
# wait for all to be powered off
Get-VM -Name $VMNames
# disable secure boot on all of them
ForEach ($VMname in $VMNames) {
$vm = Get-VM -Name $VMName | Where-Object { $_.ExtensionData.Summary.Config.ManagedBy.Type -ne "placeholderVm" }
$spec = New-Object VMware.Vim.VirtualMachineConfigSpec
$spec.Firmware = [VMware.Vim.GuestOsDescriptorFirmwareType]::efi
$boot = New-Object VMware.Vim.VirtualMachineBootOptions
$boot.EfiSecureBootEnabled = $true # false to disable obviously
$spec.BootOptions = $boot
$vm.ExtensionData.ReconfigVM($spec)
}
# power on
ForEach($VMName in $VMNames){
Get-VM -Name $VMName | Where-Object { $_.ExtensionData.Summary.Config.ManagedBy.Type -ne "placeholderVm" } | Start-VM
}
@@ -0,0 +1,71 @@
# Dump list of VMs from ServiceNow
Get-ITDServiceNowRecord -Table cmdb_ci_server -Filter "serial_numberSTARTSWITHvmware" -IncludeTotalCount | Export-Csv "C:\temp\CMDB_VMwareDump.csv"
# Disable DRS on all clusters
Get-Cluster LINUX*, MGMT*, ORACLE1, PS*, SQLa*, SQLe*, VAPP*, WAS*, WINDOWS* | Set-Cluster -DrsEnabled $false
# Dump location of all VMs to CSV
Get-VM | Where-Object { $_.ExtensionData.summary.config.ManagedBy.Type -ne "placeholderVm" } | select Name, PowerState, NumCpu, MemoryGB, VMHost, @{n = 'Datastores'; e = { ($_ | Get-Datastore).Name } } | Export-Csv "D:\State of North Dakota\-Tm-ITD-Virtualization - Documents\VMinfo.csv"
# VM array
$VMHosts = @(
'itdvmbismgmt02.nd.gov',
'itdvmbismgmt03.nd.gov',
'itdvmmdnmgmt01.nd.gov',
'itdvmbismgmt02.nd.gov'
)
# Disable lockdown on MGMT hosts
$VMHosts | ForEach-Object {
(Get-VMHost -Name $_ | Get-View).ExitLockdownMode()
}
# connect to mgmt cluster
$VMHosts | ForEach-Object {
Connect-VIServer -Server $_ -Credential (Get-ITDPassword -Title $_ -UserName root -Credential $PrvCred)
}
## verify lockdown mode is disabled manually
# get list of VMs | Where-Object { $_.ExtensionData.Summary.Config.ManagedBy.Type -ne "placeholderVm" }
$VMs = Get-VM | Where-Object { $_.Name -notlike "vCLS*" -and $_.PowerState -eq "PoweredOn" -and $_.Name -notlike "itdvmutil*" -and $_.ExtensionData.Summary.Config.ManagedBy.Type -ne "placeholderVm"} | Sort-Object Name
# Cleanup snapshots on MGMT cluster
$VMs | Get-Snapshot | Where-Object Name -NotLike "*9.0.2*" | Remove-Snapshot -RunAsync
# Shutdown all appliance VMs on MGMT cluster
$VMs | Stop-VMGuest -Confirm:$false #-RunAsync
# Wait for VMs to power off
Get-VM -Name $VMs.Name | Sort-Object Name
#Get-Cluster MGMT1, MGMT2 | Get-VM | Where-Object { $_.Name -notlike "itdvmutil*" } | Sort-Object Name
# Create offline snapshots
$VMs | New-Snapshot -Name "9_Before 8.0 U3e Upgrade" -Description "9_Before 8.0 U3e Upgrade" -Confirm:$false -RunAsync
# Power on all VMs on MGMT cluster
$VMs | Start-VM -Confirm:$false
Break
## online mid-upgrade snapshots
$VMs | New-Snapshot -Name "1_vc_upgrade_complete" -Description "2_vc1_stage2_complete" -Confirm:$false -RunAsync -Memory
Get-VM -Name itdvmvc*,itdvmsrm*, itdvmvra* | Where-Object {$_.Name -notlike "*7.0*"} | Stop-VMGuest -Confirm:$false
# post upgrade snapshot
Get-VM -Name itdvmvc*,itdvmsrm*, itdvmvra* | New-Snapshot -Name "2_vc_upgrade_complete" -Description "2_vc1_stage2_complete" -Confirm:$false -RunAsync -Memory
Get-VM -Name itdvmvc*,itdvmsrm*, itdvmvra* | Start-VM
##### after upgrade
# Enable DRS on clusters that should have it
Get-Cluster LINUX*, MGMT*, ORACLE1, PS*, SQLa*, SQLe*, VAPP*, WAS*, WINDOWS* | Set-Cluster -DrsEnabled $true
# Enable lockdown on MGMT hosts
(Get-VMHost itdvmbismgmt01.nd.gov | Get-View).EnterLockdownMode()
(Get-VMHost itdvmbismgmt02.nd.gov | Get-View).EnterLockdownMode()
(Get-VMHost itdvmmdnmgmt01.nd.gov | Get-View).EnterLockdownMode()
(Get-VMHost itdvmmdnmgmt02.nd.gov | Get-View).EnterLockdownMode()
# reconfigure distributed switch to use both vnics
#### manual
@@ -0,0 +1,13 @@
$AllVMs = Get-VM | where-object { $_.ExtensionData.summary.config.ManagedBy.Type -ne "placeholderVm" }
$data = $AllVMs | `
Select-Object Name, `
VMHost, `
UsedSpaceGB, `
ProvisionedSpaceGB #, `
#@{n = 'Disks'; e = { $_ | Get-HardDisk | Select Name, FileName, CapacityGB } }, `
#@{n = 'VRDatastore'; e = { ($_ | Get-TagAssignment | Where-Object Tag -like "*_VR").Tag } } `
#@{n = 'PortGroups'; e = { $_ | Get-VirtualPortGroup } }
$data | export-csv "C:\users\zmeier\desktop\VMs_20200122.csv"
get-vm itdvmpsc1*,itdvmvc1*,itdvmpsc2*,itdvmvc2* | new-snapshot -name "VC1-6.7 U3-Stage1 Complete"