<# .SYNOPSIS Function to process a VMware change request .DESCRIPTION A longer description of the function, its purpose, common use cases, etc. .NOTES Information or caveats about the function e.g. 'This function is not supported in Linux' .LINK Specify a URI to a help page, this will show when Get-Help -Online is used. .EXAMPLE Test-MyTestFunction -Verbose Explanation of the function or its result. You can include multiple examples with additional .EXAMPLE lines #> function Set-ITDVMwareVMViaSnowTask { [CmdletBinding()] param ( [string] $SCTaskNum, [switch] $Override, [switch] $CloseTask ) begin { $FreePercentThreshold = 0.20 # 20% free space required before disk expansions are automated } process { # get current user, SCTask, Ritm $assignTo = Get-ITDServiceNowUser -Username $Env:USERNAME $SCTask = Get-ITDServiceNowRecord -ItemType 'Catalog Task' -Number $SCTaskNum $Ritm = Get-ITDServiceNowRecord -ItemType 'Request Item' -SysId ($SCTask.request_item.value) -IncludeVariableSet $RitmNum = $Ritm.number.value # Get Hostname and CMDB object [string]$SCTaskDescriptionHostname = $SCTask.description.display_value.split(' ')[-1] $TaskCmdb = @() Write-Verbose -Message ("Gathering VariableSet data from $RitmNum") $MatchFound = $false ForEach ($Row in $Ritm.VariableSet) { $TempCi = Get-ITDServiceNowRecord -Table cmdb_ci -SysId ($Row.host_name_ref) -ErrorAction Stop If ($SCTaskDescriptionHostname -eq $TempCi.name.display_value) { $Ci = $TempCi $MatchFound = $true } } If ($MatchFound -eq $false) { Write-Error -Message "ComputerName $ComputerName was not found in VariableSet for $RitmNum" -ErrorAction Stop } $FQDN = $Ci.fqdn.display_value If ( @($Ci).count -gt 1 ) { Write-Error -Message "More than one CMDB object found that matches the hostname in this task's description" -ErrorAction Stop } # update SCTask description and assignment for humans Update-ITDServiceNowRecord -ItemType 'Catalog Task' -Number $SCTaskNum -Values @{assigned_to = $assignTo.name } # search for VMware VM try { $VM = Get-VM -Name $Ci.fqdn.display_value | Where-Object { $_.ExtensionData.summary.config.ManagedBy.Type -ne "placeholderVm" } } catch { Write-Error "Error on VM lookup. Are you connected to vCenter?" -ErrorAction Stop } switch ( @($VM).count ) { { 0 -or $null } { # no matches Write-Error -Message "Zero VM matches found, ending script" -ErrorAction Stop } { $_ -ne 1 } { # more than one match Write-Error -Message "Multiple VM matches found, ending script" -ErrorAction Stop } { 1 } { # exactly one match, gather request information, and populate variables Write-Verbose -Message ("VM: " + $VM.Name) [int]$CPU = ($Ritm.VariableSet | Where-Object { $_.host_name_ref -EQ $Ci.sys_id.value } ).Processors [int]$MemoryGB = ($Ritm.VariableSet | Where-Object { $_.host_name_ref -EQ $Ci.sys_id.value } ).memory_gb [int]$Disk1 = ($Ritm.VariableSet | Where-Object { $_.host_name_ref -EQ $Ci.sys_id.value } ).disk_1_os [int]$Disk2 = ($Ritm.VariableSet | Where-Object { $_.host_name_ref -EQ $Ci.sys_id.value } ).disk_2_swap_disk 3..16 | ForEach-Object { $DiskNum = $_ Write-Verbose "Populating variable Disk$DiskNum" ###Set-Variable -Name "Disk$DiskNum" -Value ([int](($Ritm.CustomVariable | Where-Object Name -Like "disk_$DiskNum*").Value)) Set-Variable -Name "Disk$DiskNum" -Value ([int]( ($Ritm.VariableSet | Where-Object { $_.host_name_ref -EQ $Ci.sys_id.value } )."disk_$DiskNum")) } # CPU modification If ($CPU -ne 0 -and $CPU -ne $VM.NumCpu) { Write-Verbose -Message ($VM.Name + " attempt changing CPU from " + $VM.NumCPU + " to " + $CPU) try { $OldCpu = $VM.NumCpu $VM | Set-VM -NumCpu $CPU -Confirm:$false -ErrorAction Stop $CommentsForWorkNotes += "CPU was updated from $OldCpu to $CPU. `n" } catch { } } # MemoryGB modification If ($MemoryGB -ne 0 -and $MemoryGB -ne $VM.MemoryGB) { Write-Verbose -Message ($VM.Name + " attempt changing MemoryGB to " + $MemoryGB) try { $OldMemoryGB = $VM.MemoryGB $VM | Set-VM -MemoryGB $MemoryGB -Confirm:$false -ErrorAction Stop $CommentsForWorkNotes += "MemoryGB was updated from $OldMemoryGB to $MemoryGB. `n" } catch { } } # Disk modification loop $VMDisks = $VM | Get-HardDisk 1..16 | ForEach-Object { Write-Verbose "Start Loop for Disk $_" $HardDisk = $null $DiskGBNewValue = $null $DiskVarName = $null $DiskNum = $_ $DiskGBNewValue = (Get-Variable -Name Disk$DiskNum).Value switch ($DiskNum){ 1 { $DiskVarName = "Disk1" } 2 { $DiskVarName = "Disk2" } Default { $DiskVarName = ("Disk" + $DiskNum) } } If ( (Get-Variable -Name $DiskVarName).Value -ne 0 ) { Write-Verbose -Message ("DiskNum: $DiskNum, DiskGBNewValue: $DiskGBNewValue") $HardDisk = $VM | Get-HardDisk -Name "Hard disk $DiskNum" -ErrorAction SilentlyContinue If ($HardDisk) { $Datastore = $HardDisk | Get-Datastore $DiskGBOldValue = $HardDisk.CapacityGB $HardDiskIncreaseGB = $DiskGBNewValue - $DiskGBOldValue If ($HardDiskIncreaseGB -ge 500) { # manual intervention } $FreePercentBefore = ($Datastore.FreeSpaceGB) / $Datastore.CapacityGB $FreePercentAfter = ($Datastore.FreeSpaceGB - $HardDiskIncreaseGB) / $Datastore.CapacityGB Write-Verbose -Message ("Datastore " + $Datastore.Name + " free space will lower from " + [math]::round($FreePercentBefore, 4) + " to " + [math]::round($FreePercentAfter, 4) + "") -Verbose Write-Verbose -Message ("Override is " + $Override) If ( ($FreePercentAfter -gt $FreePercentThreshold) -or ($Override -eq $true)) { try { Write-Verbose -Message ("Hard disk $DiskNum : Increasing from " + $HardDisk.CapacityGB + "GB to " + $DiskGBNewValue + "GB") -Verbose $VM | Get-HardDisk -Name "Hard disk $DiskNum" | Set-HardDisk -CapacityGB $DiskGBNewValue -Confirm:$false $CommentsForWorkNotes += "Hard disk $DiskNum CapacityGB was modified from $DiskGBOldValue GB to $DiskGBNewValue GB. `n" $DiskChanged = $true } catch { Write-Error -Message "Disk $DiskNum expansion failed" -ErrorAction Stop } } Else { try { Write-Error -Message ("Hard disk $DiskNum failed. " + $FreePercentThreshold * 100 + "% free space is required for automated disk expansions. " + $Datastore.Name + " would be " + [math]::round($FreePercentAfter, 4) + ".") -ErrorAction Stop } catch { Write-Error -Message ("Hard disk $DiskNum failed. " + $FreePercentThreshold * 100 + "% free space is required for automated disk expansions. " + $Datastore.Name + " would be " + [math]::round($FreePercentAfter, 4) + ".") -ErrorAction Stop } } } Else { Write-Verbose "Hard disk $DiskNum was not found. New disk will attempt to be created." -Verbose # get licensing and storage format of existing disks $VMTag = Get-TagAssignment -Entity $VM -Category LicensingRestrictions If (@($VMDisks | Where-Object StorageFormat -Like "*Thick*").count -gt 0) { $StorageFormat = 'EagerZeroedThick' } Else { $StorageFormat = 'Thin' } # if not SQL, validate available space and create if possible. if VM is SQL, stop If ($VMTag.Tag.Name -notlike "*SQL*") { # place new disk with disk 1 and validate datastore free space $Datastore = $VM | Get-HardDisk -Name "Hard disk 1" | Get-Datastore $DiskGBOldValue = 0 $HardDiskIncreaseGB = $DiskGBNewValue - $DiskGBOldValue If ($HardDiskIncreaseGB -ge 500) { # manual intervention ? } $FreePercentBefore = ($Datastore.FreeSpaceGB) / $Datastore.CapacityGB $FreePercentAfter = ($Datastore.FreeSpaceGB - $HardDiskIncreaseGB) / $Datastore.CapacityGB #create the disk, with decided storageformat and persistent persistence on hard disk 1 datastore If ($FreePercentAfter -gt $FreePercentThreshold) { try { Write-Warning -Message ("Hard disk $DiskNum : Creating new disk " + $DiskGBNewValue + " 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 | New-HardDisk -CapacityGB $DiskGBNewValue -StorageFormat $StorageFormat $CommentsForWorkNotes += "Hard disk $DiskNum was created with $DiskGBNewValue GB. " $DiskChanged = $true } catch { } } Else { Write-Error -Message ("Hard disk $_ failed. " + $FreePercentThreshold * 100 + "% free space is required for automated disk expansions. " + $Datastore.Name + " would be " + [math]::round($FreePercentAfter, 4) + ".") $DiskChanged = $false $DiskError = $true } } Else { # require human review Write-Error -Message ($HostName + " has SQL licensing, create the new disk manually due to SQL Server best practices. Once complete, rerun to validate size and close task.") -ErrorAction Stop } } } } # update sctask and ritm, reassign if disk changed $CommentsToAdd = "VMware VM " + $VM.Name + " was modified: `n" + $CommentsForWorkNotes Update-ITDServiceNowRecord -ItemType 'Catalog Task' -Number $SCTaskNum -Values @{comments = $CommentsToAdd } Update-ITDServiceNowRecord -ItemType 'Request Item' -Number $Ritm.number.value -Values @{comments = $CommentsToAdd } If ($CloseTask) { Update-ITDServiceNowRecord -ItemType 'Catalog Task' -Number $SCTaskNum -Values @{close_notes = $CommentsToAdd; state = "Closed Complete" } } } } } end { } }