vPOSH.Core.psm1
<# .SYNOPSIS Common collection of frequently used Powershell and PowerCLI functions. .DESCRIPTION Common collection of frequently used Powershell and PowerCLI functions. PowerCLI specific functions will have "[PowerCLI]" at the beginning of the Synopsis #> $global:vCenterCredentials = '' $global:VMGuestCredentials = '' function Initialize-Config { ## The $Global:vPOSHConfigPath variable must be set before calling this, such as in a profile. $global:vCenterObjects = [PSCustomObject[]](Get-Content $Global:vPOSHConfigPath/vcenters.json | ConvertFrom-JSON) } Initialize-Config Function Connect-vCenter { <# .SYNOPSIS [PowerCLI]Wrapper for Connect-VIServer .DESCRIPTION This is a wrapper for Connect-VIServer that allows for a stored session credential and checks for existing connections. Also, you can pass a credential object into the command to allow for externally stored credentials to be used. .EXAMPLE Connect-vCenter -vCenters myvcenter.mydomain.com .EXAMPLE Connect-vCenter -vCenters myvcenter.mydomain.com -CredentialObject $credObject .PARAMETER vCenters Which vCenter(s) to connect to .PARAMETER vCenter Which vCenter to connect to .PARAMETER CredentialObject Credential object to use if you already have one .PARAMETER ClearPreviousCreds Clear out any previous credentials? .PARAMETER UseSSPI Use current users credentials .PARAMETER Menu Indicate that you want to select a connection server from a list of recently connected servers. .PARAMETER SSHNoDomain Creates a new SSHCredential object that strips the domain name (in format {domain}\{username}), by default this is done. #> [CmdletBinding(DefaultParameterSetName = 'base')] param ( [Parameter(Mandatory = $true, HelpMessage = 'Which vCenter(s) to connect to', ParameterSetName = 'base', Position = 0)] [alias("vCenter")] [string[]]$vCenters, [Parameter(Mandatory = $false, HelpMessage = 'Credential object to use', ParameterSetName = 'base')] [Parameter(ParameterSetName = 'menu')] $CredentialObject = '', [Parameter(mandatory = $false, HelpMessage = 'Clear out any previous credentials?', ParameterSetName = 'base')] [Parameter(ParameterSetName = 'menu')] [Parameter(ParameterSetName = 'all')] [switch]$ClearPreviousCreds = $false, [Parameter(mandatory = $false, HelpMessage = 'Use current users credentials', ParameterSetName = 'base')] [Parameter(ParameterSetName = 'menu')] [Parameter(ParameterSetName = 'all')] [Parameter(ParameterSetName = 'sspi')] [switch]$UseSSPI = $false, # [Parameter(mandatory = $true, # HelpMessage = 'Indicate that you want to select a connection server from a list of recently connected servers.', # ParameterSetName = 'menu')] # [switch]$Menu = $false, [Parameter(mandatory = $true, HelpMessage = 'Indicate that you want to connect to all vCenters.', ParameterSetName = 'all')] [switch]$All = $false, [Parameter(mandatory = $false, HelpMessage = "Strip domain from SSH Credentials", ParameterSetName = 'base')] [Parameter(ParameterSetName = 'all')] [Parameter(ParameterSetName = 'menu')] [Parameter(ParameterSetName = 'sspi')] [switch]$SSHNoDomain = $true ) DynamicParam { # Define the dictionary object $RuntimeParameterDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary # Set the first parameter ## Set the dynamic parameters' name $ParamName_Location = 'Location' ## Create the collection of attributes $AttributeCollection = New-Object System.Collections.ObjectModel.Collection[System.Attribute] ## Create and set the parameters' attributes $ParameterAttribute = New-Object System.Management.Automation.ParameterAttribute $ParameterAttribute.Mandatory = $false $ParameterAttribute.ParameterSetName = 'specified' $ParameterAttribute.HelpMessage = 'Location to filter vCenters by as defined in the vcenters.json file' ## Add the attributes to the attributes collection $AttributeCollection.Add($ParameterAttribute) ## Generate and set the ValidateSet $arrSet = @(($global:vCenterObjects | Select -Unique Location).Location) $ValidateSetAttribute = New-Object System.Management.Automation.ValidateSetAttribute($arrSet) ## Add the ValidateSet to the attributes collection $AttributeCollection.Add($ValidateSetAttribute) ## Create and return the dynamic parameter $RuntimeParameter = New-Object System.Management.Automation.RuntimeDefinedParameter($ParamName_Location, [string], $AttributeCollection) $RuntimeParameterDictionary.Add($ParamName_Location, $RuntimeParameter) # End of first parameter # Set the first parameter ## Set the dynamic parameters' name $ParamName_Environment = 'Environment' ## Create the collection of attributes $AttributeCollection = New-Object System.Collections.ObjectModel.Collection[System.Attribute] ## Create and set the parameters' attributes $ParameterAttribute = New-Object System.Management.Automation.ParameterAttribute $ParameterAttribute.Mandatory = $false $ParameterAttribute.ParameterSetName = 'specified' $ParameterAttribute.HelpMessage = 'Environment to filter vCenters by as defined in the vcenters.json file' ## Add the attributes to the attributes collection $AttributeCollection.Add($ParameterAttribute) ## Generate and set the ValidateSet $arrSet = @(($global:vCenterObjects | Select -Unique Environment).Environment) $ValidateSetAttribute = New-Object System.Management.Automation.ValidateSetAttribute($arrSet) ## Add the ValidateSet to the attributes collection $AttributeCollection.Add($ValidateSetAttribute) ## Create and return the dynamic parameter $RuntimeParameter = New-Object System.Management.Automation.RuntimeDefinedParameter($ParamName_Environment, [string], $AttributeCollection) $RuntimeParameterDictionary.Add($ParamName_Environment, $RuntimeParameter) # End of second parameter # Return the entire set return $RuntimeParameterDictionary } begin { } process { $Location = $PSBoundParameters[$ParamName_Location] $Environment = $PSBoundParameters[$ParamName_Environment] if ($Menu) { Clear-Host [int]$i = 1 #$recentConnections = Get-RecentConnections if ($ClearPreviousCreds) { Write-Verbose "Clearing previous credentials" $recentConnections = Get-vCentersFromDashboard } elseif ($CredentialObject) { $recentConnections = Get-vCentersFromDashboard } elseif ($UseSSPI) { Write-Verbose "Using SSPI style conenction" $recentConnections = Get-vCentersFromDashboard } else { $recentConnections = Get-vCentersFromDashboard } Write-Host "Items in " -NoNewline -ForegroundColor Yellow Write-Host "Green " -NoNewline -ForegroundColor Green Write-Host "are able to be contacted and selected. Items in " -NoNewline -ForegroundColor Yellow Write-Host "Red " -NoNewline -ForegroundColor Red Write-Host "failed a ping check." -ForegroundColor Yellow Write-Host foreach ($entry in $recentConnections) { if ($entry.Length -gt 0) { if (!(Test-Connection -ComputerName $entry -Count 1 -Quiet)) { Write-Host "$i - $($entry)" -ForegroundColor Red } else { Write-Host "$i - $($entry)" -ForegroundColor Green } $i++ } } [int]$menuChoice = Read-Host 'Please make a selection' $vCenters = $($recentConnections[$menuChoice - 1]) } if ($All) { $vCenters = ($global:vCenterObjects).vCenter } if ($Location) { $vCenters = @(($global:vCenterObjects | Where Location -match $Location).vCenter) } if($Environment) { $vCenters = @(($global:vCenterObjects | Where Environment -match $Environment).vCenter) } if($Environment -and $Location) { $vCenters = @(($global:vCenterObjects | Where {($_.Environment -match $Environment) -and ($_.Location -match $Location)}).vCenter) } Write-Verbose "$vCenters" foreach ($vCenter in $vCenters) { if ($vCenter.Length -gt 0) { if ($UseSSPI) { Connect-VIServer -Server $vCenter -ErrorAction Stop } else { if ($ClearPreviousCreds) { $global:vCenterCredentials = $Host.UI.PromptForCredential("Domain Credentials for vCenter", 'Enter your domain account used to access this vCenter', '', '') $global:DefaultVIServers = $null } if ($CredentialObject) { $global:vCenterCredentials = $CredentialObject } else { if (!$global:vCenterCredentials) { $global:vCenterCredentials = $Host.UI.PromptForCredential("Domain Credentials for vCenter", 'Enter your domain account used to access this vCenter', '', '') } } if ($global:DefaultVIServers -notcontains $vCenter) { if (Test-Connection -ComputerName $vCenter -Count 1 -Quiet) { Connect-VIServer -Server $vCenter -Credential $global:vCenterCredentials -ErrorAction SilentlyContinue | Out-Null if ($?) { Write-Host "Connected to $($vCenter)" -ForegroundColor Green } else { Write-Host "Could not connect to $($vCenter)" -ForegroundColor Red } } else { Write-Host "Could not connect to $($vCenter)" -ForegroundColor Red } } } } } } end { } } #TODO: Check this function before release function Move-OldFile { <# .SYNOPSIS Performs a file rotation of the given file. .DESCRIPTION Performs a file rotation of the given file, moving the existing file to a new file with a sequence number in Parenthases .EXAMPLE Move-OldFile -OutputFile C:\Temp\test.xml #> [CmdletBinding()] param ( [Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, HelpMessage='Full Path and Name of the file to rotate')] [string]$OutputFile ) if(Test-Path -Path $OutputFile) { $baseFile = Get-Item -Path $OutputFile $basePath = $baseFile.Directory $baseFileName = $baseFile.BaseName $files = @(Get-ChildItem -Path $basePath | Where-Object {$_.BaseName -match $baseFile.BaseName}) $newFile = "$basePath\$baseFileName(" + $files.Count + ')' + $baseFile.Extension Move-Item -Path $baseFile -Destination $newFile } } #TODO: Check this function before release function Get-GuestCredentials { <# .SYNOPSIS [PowerCLI]Sets the global VMGuest Credentials that can be easily passed to cmdlets .DESCRIPTION Allows for easy setting of the global VMGuestCredentials variable .PARAMETER ClearPreviousCreds Clears out credentials stored in session memory .EXAMPLE Get-GuestCredentials .EXAMPLE Get-GuestCredentials -ClearPreviousCreds #> param ( [Parameter(Mandatory=$false)] [switch]$ClearPreviousCreds=$false ) if($ClearPreviousCreds) { $global:VMGuestCredentials=$null } if(!$global:VMGuestCredentials) { $global:VMGuestCredentials = $Host.UI.PromptForCredential('VMGuest Credentials','Enter a set of credentials to access a VM Guest with','','') } } #TODO: Check this function before release Function Connect-ESXiHost { <# .SYNOPSIS [PowerCLI]Wrapper for Connect-VIServer .DESCRIPTION This is a wrapper for Connect-VIServer that allows for a stored session credential and checks for existing connections. Also, you can pass a credential object into the command to allow for externally stored credentials to be used. .EXAMPLE Connect-ESXiHost -ESXiHosts myHost.mydomain.com .EXAMPLE Connect-ESXiHost -ESXiHosts myHost.mydomain.com -CredentialObject $credObject .PARAMETER ESXiHosts Name of host(s) to connect to .PARAMETER CredentialObject Credential object to use if you already have one .PARAMETER ClearPreviousCreds Clear out any previous credentials #> [CmdletBinding()] param ( [Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, HelpMessage='Which ESXi Host(s) to connect to')] [alias("ESXiHost")] [string[]]$ESXiHosts, [Parameter(Mandatory=$false, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, HelpMessage='Credential object to use')] $CredentialObject='', [Parameter(mandatory=$false, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, HelpMessage='Clear out any previous credentials?')] [switch]$ClearPreviousCreds=$false ) foreach($ESXiHost in $ESXiHosts) { if($ClearPreviousCreds) { $global:vCenterCredentials=$Host.UI.PromptForCredential("Domain Credentials for ESXi Host $ESXiHost",'Enter your domain account used to access this ESXi Host','','') $global:DefaultVIServers=$null } if($CredentialObject) { $global:vCenterCredentials=$CredentialObject } else { if(!$global:vCenterCredentials) { $global:vCenterCredentials=$Host.UI.PromptForCredential("Domain Credentials for ESXi Host $ESXiHost",'Enter your domain account used to access this ESXi Host','','') } } if($global:DefaultVIServers -notcontains $ESXiHost) { Connect-VIServer -Server $ESXiHost -Credential $global:vCenterCredentials -ErrorAction Stop } if($?) { Write-Host $true } else { Write-Host $false } } } Function Get-VMCPUReadyPercentDatacenter { <# .SYNOPSIS [PowerCLI]Gathers the vCPU Ready % statistics for a given Datacenter for the given interval .DESCRIPTION Gathers the vCPU Ready % statistics for a given Datacenter for the given interval .EXAMPLE Get-VMCPUReadyPercentDatacenter -DataCenter prod -Interval day .PARAMETER DataCenter Which Datacenter to gather metrics from .PARAMETER Interval Interval for the metrics. Valid values are day, week, month #> param ( [Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, HelpMessage='Which Datacenter to gather metrics from')] [string]$DataCenter, [Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, HelpMessage='Interval for the metrics. Valid values are day, week, month')] [ValidateSet('day','week','month')] [string]$Interval ) Switch ($Interval) { 'day' {$days=-1;$mins=5;$divider=3000} 'week' {$days=-7;$mins=30;$divider=18000} 'month' {$days=-30;$mins=120;$divider=72000} } $groups=Get-Stat -Entity (Get-vm -Location $DataCenter ) -Stat cpu.ready.summation -start (Get-date).adddays($days) -finish (Get-date) -interval $mins -instance '' -ea silentlycontinue|Group-Object entity $output=@() ForEach ($group in $groups) { $objOut = New-Object PSObject | Select-Object Name, CPURdyPcnt $objOut.Name=$group.Name $objOut.CPURdyPcnt= '{0:n2}' -f ((($group.group |measure-object value -ave).average/$divider) * 100 ) $output+=$objOut } return $output } Function Get-VMCPUReadyPercentVM { <# .SYNOPSIS [PowerCLI]Gathers the vCPU Ready % statistics for a given Datacenter for the given interval .DESCRIPTION Gathers the vCPU Ready % statistics for a given Datacenter for the given interval .EXAMPLE Get-VMCPUReadyPercentDatacenter -VMs fdxsql65,fdxsql66 -Interval day .PARAMETER VMs Which VM(s) to gather metrics from .PARAMETER Interval Interval for the metrics. Valid values are day, week, month, year #> param ( [Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, HelpMessage='Which VM(s) to gather metrics from')] [string[]]$VMs, [Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, HelpMessage='Interval for the metrics. Valid values are day, week, month, year')] [ValidateSet('day','week','month','year')] [string]$Interval ) Switch ($interval) { 'day' {$days=-1;$mins=5;$divider=3000} 'week' {$days=-7;$mins=30;$divider=18000} 'month' {$days=-30;$mins=120;$divider=72000} 'year' {$days=-365;$mins=1440;$divider=864000} } $output=@() foreach ($vm in $VMs) { $vmStat=Get-Stat -Entity (Get-vm -Name $vm ) -Stat cpu.ready.summation -start (Get-date).adddays($days) -finish (Get-date) -interval $mins -instance '' -ea silentlycontinue|Group-Object entity $objOut = New-Object PSObject | Select-Object Name, CPURdyPcnt $objOut.Name=$vmStat.Name $objOut.CPURdyPcnt= '{0:n2}' -f ((($vmStat.group |measure-object value -ave).average/$divider) * 100) $output+=$objOut } return $output } #TODO: Implement this in a .1 release #region futurerelease # Function Watch-Output { # <# # .SYNOPSIS # Runs a scriptblock or the preceeding pipeline repeatedly until there is change. # .DESCRIPTION # The Watch-Output cmdlet runs a specified scriptblock repeatedly at the specified interval (or # every 1 second by default) and returns the result of the scriptblock when the output has changed. # For the command to work the specified scriptblock must return a result to the pipeline. # .PARAMETER ScriptBlock # The scriptblock to execute, specified via curly braces. If you provide input via the pipleine that # isn't a scriptblock then the entire invocation line that preceeded the cmdlet will be used as the # scriptblock input. # .PARAMETER Seconds # Number of seconds to wait between checks. Default = 10 # .PARAMETER Difference # Switch: Use to only output items in the collection that have changed # dditions or modifications). # .PARAMETER Continuous # Switch: Run continuously (even after a change has occurred) until exited with CTRL+C. # .PARAMETER AsString # Switch: Converts the result of the scriptblock into an array of strings for comparison. # .PARAMETER ClearScreen # Switch: Clears the screen between each result. You can also use 'cls' as an alias. # .PARAMETER Property # Manually specify one or more property names to be used for comparison. If not specified, # the default display property set is used. If there is not a default display property set, # all properties are used. You can also use '*' to force all properties. # .EXAMPLE # Watch-Output -ScriptBlock { Get-Process } # Runs Get-Process and waits for any returns the result when the data has changed. # .EXAMPLE # Get-Service | Watch-Output -Diff -Cont # Runs Get-Service and returns any differences in the resultant data, continuously until interrupted # by CTRL+C. # .EXAMPLE # Watch-Output { Get-Content test.txt } -Difference -Verbose -ClearScreen # Uses Get-Content to monitor test.txt. Shows any changes and clears the screen between changes. # .EXAMPLE # Get-ChildItem | Watch-Output -Difference -AsString # Monitors the result of GEt-ChildItem for changes, returns any differences. Treats the input as # strings not objects. # .EXAMPLE # Get-Process | Watch-Output -Difference -Property processname,id -Continuous # Monitors Get-Process for differences in the specified properties only, continues until interrupted # by CTRL+C. # #> # [cmdletbinding()] # Param( # [parameter(ValueFromPipeline, Mandatory)] # [object] # $ScriptBlock, # [int] # $Seconds = 10, # [switch] # $Difference, # [switch] # $Continuous, # [switch] # $AsString, # [alias('cls')] # [switch] # $ClearScreen, # [string[]] # $Property # ) # if ($ScriptBlock -isnot [scriptblock]) { # if ($MyInvocation.PipelinePosition -gt 1) { # $ScriptBlock = [Scriptblock]::Create( ($MyInvocation.Line -Split "\|\s*$($MyInvocation.InvocationName)")[0] ) # } # else { # Throw 'The -ScriptBlock parameter must be provided an object of type ScriptBlock unless invoked via the Pipeline.' # } # } # Write-Verbose "Started executing $($ScriptBlock | Out-String)" # $FirstResult = Invoke-Command $ScriptBlock # if ($AsString) { # $FirstResult = $FirstResult | Out-String -Stream # } # elseif (($FirstResult | Select-Object -First 1) -isnot [string]){ # if (-not $Property) { # $Property = ($FirstResult | Select-Object -First 1).PSStandardMembers.DefaultDisplayPropertySet.ReferencedPropertyNames # } # if (-not $Property -or $Property -eq '*') { # $Property = ($FirstResult | Select-Object -First 1).PSObject.Properties.Name # } # Write-Verbose "Watched properties: $($Property -Join ',')" # } # do { # do { # if ($Result) { # Start-Sleep $Seconds # } # if ($ClearScreen) { # Clear-Host # } # $Result = Invoke-Command $ScriptBlock # if ($AsString) { # $Result = $Result | Out-String -Stream # } # $CompareParams = @{ # ReferenceObject = @($FirstResult | Select-Object) # DifferenceObject = @($Result | Select-Object) # } # if ($Property) { # $CompareParams.Add('Property', $Property) # } # $Diff = Compare-Object @CompareParams -PassThru # } # until ($Diff) # Write-Verbose "Change occurred at $(Get-Date)" # if ($Difference) { # $Diff | Where-Object {$_.SideIndicator -eq '=>'} # } # else { # $Result # } # $FirstResult = $Result # } # until (-not $Continuous) # } #endregion #TODO: Add in last update at top of screen Function Watch-Command { <# .SYNOPSIS [PowerCLI]Continually runs a command at the specified interval .DESCRIPTION Continually runs a command at the specified interval .EXAMPLE Watch-Command -CommandToRun Get-proc .EXAMPLE Watch-Command -CommandToRun Get-proc -WaitSeconds 5 .PARAMETER CommandToRun Command to run in the form of a script block. .PARAMETER WaitSeconds Amount of time to wait to repeat the task, in seconds. Default of 5. #> param ( [Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, HelpMessage='Command to run in the form of a script block')] [scriptblock]$CommandToRun, [Parameter(Mandatory=$false, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, HelpMessage='Amount of time to wait to repeat the task, in seconds. Default of 5')] [int]$WaitSeconds=5 ) $private:sb = New-Object System.Text.StringBuilder $private:w0 = $private:h0 = 0 for(;;) { # invoke command, format output data $private:n = $sb.Length = 0 $private:w = $Host.UI.RawUI.BufferSize.Width $private:h = $Host.UI.RawUI.WindowSize.Height-1 [void]$sb.EnsureCapacity($w*$h) .{ & $CommandToRun | Out-String -Stream | .{process{ if ($_ -and ++$n -le $h) { $_ = $_.Replace("`t", ' ') if ($_.Length -gt $w) { [void]$sb.Append($_.Substring(0, $w-1) + '*') } else { [void]$sb.Append($_.PadRight($w)) } } }} }>$null # fill screen if ($w0 -ne $w -or $h0 -ne $h) { $w0 = $w; $h0 = $h Clear-Host; $private:origin = $Host.UI.RawUI.CursorPosition } else { $Host.UI.RawUI.CursorPosition = $origin } Write-Host "Update Interval: $($WaitSeconds)s`tLast Update: $(Get-Date -Format T)`n" Write-Host $sb -NoNewLine $private:cursor = $Host.UI.RawUI.CursorPosition if ($n -lt $h) { Write-Host (' '*($w*($h-$n)+1)) -NoNewLine } elseif($n -gt $h) { Write-Host '*' -NoNewLine } $Host.UI.RawUI.CursorPosition = $cursor Start-Sleep $WaitSeconds } } Function Start-RollingReboot { <# .SYNOPSIS [PowerCLI]Performs a rolling reboot of hosts that are supplied .DESCRIPTION Performs a rolling reboot of hosts that are supplied, for instance all hosts in a cluster, etc. This will place the host in Maintenance Mode, reboot the host, wait for the hsot to return to the Maintenance status, then bring the host out of Maintenance Mode and continue to the next host in the supplied array. .EXAMPLE Start-RollingReboot -VMHostsToReboot "vlabapp19.uu.deere.com","vlabapp18.uu.deere.com" .PARAMETER VMHostsToReboot Array of VM Hosts you wish to reboot in a rolling fashion. The order of this array is not modified from what is supplied. .PARAMETER HostPause Pause between hosts to allow the cluster DRS to normalize in seconds. Defaults to 300 seconds, or 5 minutes. #> param ( [Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, HelpMessage='VM Hosts to Reboot in a rolling fashion')] [string[]]$VMHostsToReboot, [Parameter(Mandatory=$false, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, HelpMessage='Pause between hosts in seconds')] [int]$HostPause = 300 ) foreach ($VMHostToReboot in $VMHostsToReboot) { [switch]$MaintMode=$false $tmpVMHost = Get-VMHost $VMHostToReboot -WarningAction SilentlyContinue if($tmpVMHost) { if($tmpVMHost.State -eq "Maintenance") { $MaintMode=$true } else { $tmpVMHost | Set-VMHost -State Maintenance -Evacuate -Confirm:$false -ErrorAction Stop } $tmpVMHost | Restart-VMHost -Confirm:$false | Out-Null # Wait for Server to show as down do { Start-Sleep 15 $ServerState = (Get-vmhost $VMHostToReboot).ConnectionState } while ($ServerState -ne 'NotResponding') Write-Host "$VMHostToReboot is Down" do { Start-Sleep 60 $ServerState = (Get-vmhost $VMHostToReboot).ConnectionState Write-Host 'Waiting for Reboot ...' } while ($ServerState -ne 'Maintenance') Write-Host "$VMHostToReboot is back up" if(!$MaintMode) { Set-VMHost $VMHostToReboot -State Connected -ErrorAction Stop } #Wait 5 minutes for DRS to normalize before moving to the next host Write-Host "Waiting 5 minutes for DRS to normalize" Start-Sleep -Seconds $HostPause } } } Function Wait-VMShutdown { <# .SYNOPSIS [PowerCLI]Waits for a VM to power off .DESCRIPTION When shutting down a VM, it returns when the shutdown command is good, not waiting for the VM to actually power off. This will wait for the VM to completly power off. .EXAMPLE Wait-VMShutdown -VM (Get-VM linuxtest-fsdevcr3) .PARAMETER VMName Name of VM Object to watch .PARAMETER WaitSeconds Number of seconds before performing a hard kill, defaults to 360 (5 min) #> [CmdletBinding()] param ( [Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, HelpMessage='Name of VM Object to watch')] [string]$VMName, [Parameter(Mandatory=$false, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, HelpMessage='Number of seconds before performing a hard kill')] [int]$WaitSeconds = 360 ) process { #Check to see if we are connected, if not, warn the user to connect first and exit if(!$global:DefaultVIServer) { Write-Host '' Write-Host 'You must first connect to a vCenter before proceeding' -ForegroundColor Red Exit } $tempvm = Get-VM $VMName $guestView = Get-View -ViewType VirtualMachine -Filter @{'Name'=$tempvm.Name} $guestView.UpdateViewData('Runtime.PowerState') if ($guestView.Runtime.PowerState -ne 'poweredOff') { $tempVM | Wait-Tools -TimeoutSeconds $WaitSeconds Shutdown-VMGuest -VM $tempVM -Confirm:$false $guestView.UpdateViewData('Runtime.PowerState') } $i = 0 $waitRemain = $WaitSeconds while (($guestView.Runtime.PowerState -ne 'poweredOff') -and ($i -le [Math]::Ceiling($WaitSeconds / 5))) { Write-Progress -id 99337 -Activity "Wait for VM Shutdown" -SecondsRemaining $waitRemain Start-Sleep -Seconds 5 try { $guestView.UpdateViewData('Runtime.PowerState') } catch { } $i++ $waitRemain = $waitRemain - 5 } Write-Progress -id 99337 -Completed -Activity "Wait for VM Shutdown" } end { return $tempvm } } Function Get-vCenterSessions { <# .SYNOPSIS Lists vCenter Sessions. .DESCRIPTION Lists all connected vCenter Sessions, and some added properties such as idle time. .PARAMETER ExportPath Where to save the file to, including filename .EXAMPLE Get-vCenterSessions .EXAMPLE Get-vCenterSessions | Where { $_.IdleMinutes -gt 5 } #> [CmdletBinding()] param ( [Parameter(Mandatory=$false, ParameterSetName='export')] [string]$ExportPath ) $SessionMgr = Get-View $DefaultViserver.ExtensionData.Client.ServiceContent.SessionManager $AllSessions = @() $SessionMgr.SessionList | Foreach { $Session = New-Object -TypeName PSObject -Property @{ Key = $_.Key UserName = $_.UserName FullName = $_.FullName LoginTime = ($_.LoginTime).ToLocalTime() LastActiveTime = ($_.LastActiveTime).ToLocalTime() } If ($_.Key -eq $SessionMgr.CurrentSession.Key) { $Session | Add-Member -MemberType NoteProperty -Name Status -Value 'Current Session' } Else { $Session | Add-Member -MemberType NoteProperty -Name Status -Value 'Idle' } $Session | Add-Member -MemberType NoteProperty -Name IdleMinutes -Value ([Math]::Round(((Get-Date) - ($_.LastActiveTime).ToLocalTime()).TotalMinutes)) $AllSessions += $Session } if($ExportPath) { $AllSessions | Export-Csv -NoTypeInformation -Path $ExportPath -NoClobber } return $AllSessions } function Get-LastPowerOn { <# .SYNOPSIS Retrieves the last time a VM was powered on .DESCRIPTION Retrieves the last time a VM was powered on .EXAMPLE Get-LastLogOn -VM vm-object .PARAMETER VM VM to work on. #> param ( [Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, HelpMessage='VM Object')] [VMware.VimAutomation.Types.VirtualMachine]$VM # [Parameter(Mandatory=$false, # HelpMessage='Hours timeframe')] # [string]$Hours="" ) # if($Hours) # { # $events = $VM | Get-VIEvent -Start (Get-Date).AddHours($Hours) | where {$_.FullFormattedMessage -match "Power On Virtual"} # } # else # { $events = $VM | Get-VIEvent | Where-Object {$_.FullFormattedMessage -match 'Power On Virtual'} # } return ($events | Select-Object -Last 1 | Select-Object @{N='VM';E={$_.VM.Name}},@{N='LastPoweredOnTime';E={$_.CreatedTime}}) } function Get-ConsolidationRatio { <# .SYNOPSIS Retrieves the consolidation ratio of vRAM and vCPU in a given Datacenter/Cluster .DESCRIPTION Retrieves the consolidation ratio of vRAM and vCPU in a given Datacenter/Cluster .PARAMETER Datacenters Comma-seperated list of Datacenter(s) you wish the script to act on. If this is left blank, it will get all datacenters on the vCenter .EXAMPLE Get-consolidationRatio.ps1 -Datacenters "fdxvcr3" Get-consolidationRatio.ps1 -Datacenters "fdxvcr3","fsdevcr3" #> [CmdletBinding()] param ( [Parameter(Mandatory=$false, Position=0, HelpMessage='Comma-seperated list of Datacenter(s) you wish the script to act on.')] [string[]]$Datacenters ) #Clear-Host #Check to see if we are connected, if not, warn the user to connect first if(!$global:DefaultVIServer) { Write-Host '' Write-Host 'You must first connect to a vCenter before proceeding' -ForegroundColor Red Exit } if(!$Datacenters) { $Datacenters = Get-Datacenter } $objDataCenters=Foreach ($dc in $Datacenters) { $cluster = get-cluster -location $dc $objClusters=foreach ($cl in $cluster) { $ClusterVMs = $cl | Get-VM if($ClusterVMs.Count -gt 0) { $ClusterMemory = [math]::round($cl.ExtensionData.Summary.TotalMemory / 1GB,0) $ClusterCPUCores = $cl.ExtensionData.Summary.NumCpuCores $ClusterAllocatedvCPUs = ($ClusterVMs | Measure-Object -Property NumCPu -Sum).Sum $ClusterAllocatedvRAM = [Math]::Round(($ClusterVMs | Measure-Object -Property MemoryGB -Sum).Sum,0) $CPUClusterRatio = 0 $RAMClusterRatio = 0 try { $CPUClusterRatio = [math]::round($ClusterAllocatedvCPUs / $ClusterCPUCores,2) } catch { } try { $RAMClusterRatio = [Math]::Round($ClusterAllocatedvRAM / $ClusterMemory,2) } catch { } New-Object PSObject -Property @{ 'Cluster Name'=$cluster 'pCPU Available'=$ClusterCPUCores 'vCPU Allocated'=$ClusterAllocatedvCPUs 'pRAM Available'=$ClusterMemory 'vRAM Allocated'=$ClusterAllocatedvRAM 'v/pCPU Ratio'=" $CPUClusterRatio : 1" 'v/pRAM Ratio'=" $RAMClusterRatio : 1 " } } New-Object PSObject -Property @{ Datacenter=$dc Clusters=$objClusters } } } return $objDatacenters } function Get-ConsoleAsText { <# .SYNOPSIS The script captures console screen buffer up to the current cursor position and returns it in plain text format. .DESCRIPTION The script captures console screen buffer up to the current cursor position and returns it in plain text format. ASCII-encoded string. .PARAMETER Datacenter Comma-seperated list of Datacenter(s) you wish the script to act on. If this is left blank, it will get all datacenters on the vCenter .EXAMPLE $textFileName = "$env:temp\ConsoleBuffer.txt" Get-ConsoleAsText | out-file $textFileName -encoding ascii #> # Check the host name and exit if the host is not the Windows PowerShell console host. if ($host.Name -ne 'ConsoleHost') { write-host -ForegroundColor Red "This script runs only in the console host. You cannot run this script in $($host.Name)." exit -1 } # Initialize string builder. $textBuilder = new-object system.text.stringbuilder # Grab the console screen buffer contents using the Host console API. $bufferWidth = $host.ui.rawui.BufferSize.Width $bufferHeight = $host.ui.rawui.CursorPosition.Y $rec = new-object System.Management.Automation.Host.Rectangle 0,0,($bufferWidth - 1),$bufferHeight $buffer = $host.ui.rawui.GetBufferContents($rec) # Iterate through the lines in the console buffer. for($i = 0; $i -lt $bufferHeight; $i++) { for($j = 0; $j -lt $bufferWidth; $j++) { $cell = $buffer[$i,$j] $null = $textBuilder.Append($cell.Character) } $null = $textBuilder.Append("`r`n") } return $textBuilder.ToString() } function Get-VMXPath { <# .SYNOPSIS [PowerCLI]The will return the full path to a VMs VMX file, useful in regestering a VM on a new host .DESCRIPTION The will return the full path to a VMs VMX file, useful in regestering a VM on a new host .PARAMETER VM The VM object you need the VMX file for .EXAMPLE Get-VM myVM | Get-VMX Get-Datacenter MyDC | Get-VM | %{Get-VMX $_} #> [CmdletBinding()] Param ( [Parameter(Mandatory=$true, Position=1, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)] [VMware.VimAutomation.Types.VirtualMachine]$VM ) Begin { Write-Verbose "Retrieving VMX Path Info . . ." } Process { try { $VM | Add-Member -MemberType ScriptProperty -Name 'VMXPath' -Value {$this.extensiondata.config.files.vmpathname} -Passthru -Force | Select-Object Name,VMXPath } catch { "Error: You must connect to vCenter first." | Out-host } } End { } } function Get-ConnectedvCenters { $vCenterData = @() foreach($vCenter in $global:DefaultVIServers) { $vCenter | Select Name, Version, Build, User } return $vCenterData } function Get-Lsh { <# .SYNOPSIS Bitwise Left-Shift .DESCRIPTION Bitwise Left-Shift .PARAMETER n .PARAMETER bits #> [CmdletBinding()] param ( [uint32]$n, [byte]$bits ) $n * [Math]::Pow(2, $bits) } function Get-VersionStringAsObject { <# .SYNOPSIS Takes a dot-noted versions string (major.minor.build) and converts it into a parsable object .DESCRIPTION Takes a dot-noted versions string (major.minor.build) and converts it into a parsable object .PARAMETER VersionString #> [CmdletBinding()] param ( [CmdletBinding()] [Parameter(Mandatory=$true)] [String]$VersionString ) $parts = $VersionString.Split(".") if($parts.Count -le 3) { $tmpObj = New-Object PSObject -Property @{ Major = $parts[0] Minor = $parts[1] Build = $parts[2] } } else { $tmpObj = New-Object PSObject -Property @{ Major = $parts[0] Minor = $parts[1] Build = $parts[2] } } return $tmpObj } function Get-VersionStringAsArray { <# .SYNOPSIS Returns a dotted version string as a numeric array for easier comparision .DESCRIPTION Returns a version number "a.b.c.d" as a two-element numeric array. The first array element is the most significant 32 bits, and the second element is the least significant 32 bits. .PARAMETER Version Dotted Version number string #> [CmdletBinding()] param ( [string]$version ) $parts = $version.Split(".") if ($parts.Count -lt 5) { for ($n = $parts.Count; $n -lt 5; $n++) { $parts += "0" } } [UInt32] ((Get-Lsh $parts[1] 16) + $parts[2]) } function Test-IsEven { param ( [string]$NumToCheck ) [bool]$retVal = $true if([Math]::Truncate( [Int32]($NumToCheck % 2) )) { $retVal = $false } return $retVal } function Get-VMPerfStat { <# .SYNOPSIS [PowerCLI]Get's the given VM's performance stats .DESCRIPTION Get's the given VM's performance stats and returns the results as either the average of CPU and Mem over the given time period or as the raw values .PARAMETER VMName Name of the VM to get data for .PARAMETER Hours Hours to go back from current time; defaults to 6 .PARAMETER rawData Returns an object of rawData instead of avereged data .OUTPUT PSObject .EXAMPLE Just get the averaged data for the default of 6 hours Get-VMPerfStat -VMName (get-vm myVMName).Name .EXAMPLE Get the averaged data for the last 2 hours Get-VMPerfStat -VMName (get-vm myVMName).Name -Hours 2 .EXAMPLE Get the raw data returned as arrays in the object's members. $myVariable = Get-VMPerfStat (get-vm myVMName).Name -rawData #> [CmdletBinding()] param ( [string]$VMName, [int]$Hours = 6, [switch]$rawData ) $vm = Get-VM $VMName $cpustat = $vm | Get-Stat -Stat cpu.usage.average -Start (Get-Date).AddHours(($Hours * -1)) -Finish (Get-Date) | where{ $_.Instance -eq "" } $cpuuse = ( $cpustat | Measure-Object -Property Value -Maximum -Minimum -Average ) $memstat = $vm | Get-Stat -Stat mem.usage.average -Start (Get-Date).AddHours(($Hours * -1)) -Finish (Get-Date) | where{ $_.Instance -eq "" } $memuse = ( $memstat | Measure-Object -Property Value -Maximum -Minimum -Average ) if($rawData) { $PerfStat = New-Object PSObject -Property @{ VMName = $VMName "CpuUsageRaw" = $cpustat "MemUsageRaw" = $memstat "TimeStart" = (Get-Date).AddHours(($Hours * -1)) "TimeSpan" = $Hours } } else { $PerfStat = New-Object PSObject -Property @{ VMName = $VMName "CPUAv%" = ( [System.Math]::Round( $cpuuse.Average,2 ) ) "CPUMax%" = ( [System.Math]::Round( $cpuuse.Maximum,2 ) ) "CPUMin%" = ( [System.Math]::Round( $cpuuse.Minimum,2 ) ) "MemAv%" = ( [System.Math]::Round( $memuse.Average,2 ) ) "MemMax%" = ( [System.Math]::Round( $memuse.Maximum,2 ) ) "MemMin%" = ( [System.Math]::Round( $memuse.Minimum,2 ) ) } } return $PerfStat } function Get-VMHostPerfStat { param ( [string]$VMhostName, [int]$Days = "30" ) Begin { $PerfStat = New-Object PSObject $VMhost = Get-VMhost $VMhostName $todayMidnight = ( Get-Date -Hour 0 -Minute 0 -Second 0 ).AddMinutes( -1 ) $cpustat = $VMhost | Get-Stat -Stat cpu.usage.average -Start $todayMidnight.AddDays( - $Days ) -Finish $todayMidnight.AddDays( -1 ) | where { $_.Instance -eq "" } $cpuuse = ( $cpustat | Measure-Object -Property Value -Maximum -Minimum -Average ) $memstat = $VMhost | Get-Stat -Stat mem.usage.average -Start $todayMidnight.AddDays( - $Days ) -Finish $todayMidnight.AddDays( -1 ) | where { $_.Instance -eq "" } $memuse = ( $memstat | Measure-Object -Property Value -Maximum -Minimum -Average ) } Process { $PerfStat | add-member -MemberType NoteProperty -name "VMhostName" -Value $VMhost.Name $PerfStat | add-member -MemberType NoteProperty -name "CPUAv%" -Value ( [System.Math]::Round( $cpuuse.Average, 2 ) ) $PerfStat | add-member -MemberType NoteProperty -name "CPUMax%" -Value ( [System.Math]::Round( $cpuuse.Maximum, 2 ) ) $PerfStat | add-member -MemberType NoteProperty -name "CPUMin%" -Value ( [System.Math]::Round( $cpuuse.Minimum, 2 ) ) $PerfStat | add-member -MemberType NoteProperty -name "MemAv%" -Value ( [System.Math]::Round( $memuse.Average, 2 ) ) $PerfStat | add-member -MemberType NoteProperty -name "MemMax%" -Value ( [System.Math]::Round( $memuse.Maximum, 2 ) ) $PerfStat | add-member -MemberType NoteProperty -name "MemMin%" -Value ( [System.Math]::Round( $memuse.Minimum, 2 ) ) } End { $PerfStat } } function Get-CapacityPlanningData { <# .SYNOPSIS [PowerCLI] Get's the Capacity Planning data .DESCRIPTION Get's the Capacity Planning data for a specified cluster(s) or all connected clusters .PARAMETER Clusters Non-mandatory parameter that is a comma-seperated list .EXAMPLE Get the capacity report for all clusters on all connected vCenters and output to a GridView Get-CapacityPlanningData | Out-GridView .EXAMPLE Get the capacity report for a specific cluster Get-CapacityPlanningData -Clusters Cluster1 .EXAMPLE Get the capacity report for a specific clusters Get-CapacityPlanningData -Clusters Cluster1, Cluster2, Cluster3 .INPUTS Cluster names .OUTPUTS Custom object #> [CmdletBinding()] param ( [Parameter(Mandatory=$false)] [string[]]$Clusters ) $yesterdayStart = (Get-Date -Hour 0 -Minute 0 -Second 0).AddDays(-1) $todayStart = (Get-Date -Hour 0 -Minute 0 -Second 0) if(!($clusters)) { $clusters = Get-Cluster } $retObj = foreach($cluster in $Clusters) { $cpustat = $cluster | Get-Stat -Stat cpu.usagemhz.average -Start $yesterdayStart -Finish $todayStart -IntervalMins 15 | where{ $_.Instance -eq "" } $cpuuse = ( $cpustat | Measure-Object -Property Value -Maximum -Minimum -Average ) $memstat = $cluster | Get-Stat -Stat mem.consumed.average -Start $yesterdayStart -Finish $todayStart -IntervalMins 15 | where{ $_.Instance -eq "" } $memuse = ( $memstat | Measure-Object -Property Value -Maximum -Minimum -Average ) $maxvcpu = '{0:N0}' -f (($cluster | Get-VMHost | Measure-Object -Property NumCpu -Sum | Select Sum).Sum) $usedvcpu = '{0:N0}' -f (($cluster | get-vm | Measure-Object -Property NumCpu -Sum | Select Sum).Sum) New-Object PSObject -Property @{ clusterName = $cluster.Name usedMhzAvg = [Math]::Round($cpuuse.Average,2) usedMhzMax = [Math]::Round($cpuuse.Maximum,2) usedMhzMin = [Math]::Round($cpuuse.Minimum,2) percentUsedMhz = '{0:N2}' -f (($cluster | Get-VMHost | Measure-Object -Property CpuUsageMhz -Sum | Select Sum).Sum / $cluster.UsableCpuMhz * 100) usedMemAvg = [Math]::Round($memuse.Average * 1KB / 1GB,2) #Little funky math because we are given value in KB not B usedMemMax = [Math]::Round($memuse.Maximum * 1KB / 1GB,2) #Little funky math because we are given value in KB not B usedMemMin = [Math]::Round($memuse.Minimum * 1KB / 1GB,2) #Little funky math because we are given value in KB not B maxMhz = $cluster.UsableCpuMhz maxMem = $cluster.UsableRamGb maxVcpus = $maxvcpu usedVcpu = $usedvcpu availVcpu = $maxvcpu - $usedvcpu } } return $retObj } function Get-VIEventPlus { <# .SYNOPSIS Returns vSphere events .DESCRIPTION The function will return vSphere events. With the available parameters, the execution time can be improved, compered to the original Get-VIEvent cmdlet. .PARAMETER Entity When specified the function returns events for the specific vSphere entity. By default events for all vSphere entities are returned. .PARAMETER EventType This parameter limits the returned events to those specified on this parameter. .PARAMETER Start The start date of the events to retrieve .PARAMETER Finish The end date of the events to retrieve. .PARAMETER Recurse A switch indicating if the events for the children of the Entity will also be returned .PARAMETER User The list of usernames for which events will be returned .PARAMETER System A switch that allows the selection of all system events. .PARAMETER ScheduledTask The name of a scheduled task for which the events will be returned .PARAMETER FullMessage A switch indicating if the full message shall be compiled. This switch can improve the execution speed if the full message is not needed. .EXAMPLE Get-VIEventPlus -Entity $vm .EXAMPLE Get-VIEventPlus -Entity $cluster -Recurse:$true #> [CmdletBinding()] param( [VMware.VimAutomation.ViCore.Impl.V1.Inventory.InventoryItemImpl[]]$Entity, [string[]]$EventType, [DateTime]$Start, [DateTime]$Finish = (Get-Date), [switch]$Recurse, [string[]]$User, [Switch]$System, [string]$ScheduledTask, [switch]$FullMessage = $false ) process { $eventnumber = 100 $events = @() $eventMgr = Get-View EventManager $eventFilter = New-Object VMware.Vim.EventFilterSpec $eventFilter.disableFullMessage = ! $FullMessage $eventFilter.entity = New-Object VMware.Vim.EventFilterSpecByEntity $eventFilter.entity.recursion = & { if ($Recurse) { "all" }else { "self" } } $eventFilter.eventTypeId = $EventType if ($Start -or $Finish) { $eventFilter.time = New-Object VMware.Vim.EventFilterSpecByTime if ($Start) { $eventFilter.time.beginTime = $Start } if ($Finish) { $eventFilter.time.endTime = $Finish } } if ($User -or $System) { $eventFilter.UserName = New-Object VMware.Vim.EventFilterSpecByUsername if ($User) { $eventFilter.UserName.userList = $User } if ($System) { $eventFilter.UserName.systemUser = $System } } if ($ScheduledTask) { $si = Get-View ServiceInstance $schTskMgr = Get-View $si.Content.ScheduledTaskManager $eventFilter.ScheduledTask = Get-View $schTskMgr.ScheduledTask | where { $_.Info.Name -match $ScheduledTask } | Select -First 1 | Select -ExpandProperty MoRef } if (!$Entity) { $Entity = @(Get-Folder -Name Datacenters) } $entity | % { $eventFilter.entity.entity = $_.ExtensionData.MoRef $eventCollector = Get-View ($eventMgr.CreateCollectorForEvents($eventFilter)) $eventsBuffer = $eventCollector.ReadNextEvents($eventnumber) while ($eventsBuffer) { $events += $eventsBuffer $eventsBuffer = $eventCollector.ReadNextEvents($eventnumber) } $eventCollector.DestroyCollector() } $events } } function Get-MotionHistory { <# .SYNOPSIS Returns the vMotion/svMotion history .DESCRIPTION The function will return information on all the vMotions and svMotions that occurred over a specific interval for a defined number of virtual machines .PARAMETER Entity The vSphere entity. This can be one more virtual machines, or it can be a vSphere container. If the parameter is a container, the function will return the history for all the virtual machines in that container. .PARAMETER Days An integer that indicates over how many days in the past the function should report on. .PARAMETER Hours An integer that indicates over how many hours in the past the function should report on. .PARAMETER Minutes An integer that indicates over how many minutes in the past the function should report on. .PARAMETER Sort An switch that indicates if the results should be returned in chronological order. .EXAMPLE Get-MotionHistory -Entity $vm -Days 1 .EXAMPLE Get-MotionHistory -Entity $cluster -Sort:$false .EXAMPLE Get-Datacenter -Name $dcName | Get-MotionHistory -Days 7 -Sort:$false #> [CmdletBinding(DefaultParameterSetName = "Days")] param( [Parameter(Mandatory = $true, ValueFromPipeline = $true)] [VMware.VimAutomation.ViCore.Impl.V1.Inventory.InventoryItemImpl[]]$Entity, [Parameter(ParameterSetName = 'Days')] [int]$Days = 1, [Parameter(ParameterSetName = 'Hours')] [int]$Hours, [Parameter(ParameterSetName = 'Minutes')] [int]$Minutes, [switch]$Recurse = $false, [switch]$Sort = $true ) begin { $history = @() switch ($psCmdlet.ParameterSetName) { 'Days' { $start = (Get-Date).AddDays(- $Days) } 'Hours' { $start = (Get-Date).AddHours(- $Hours) } 'Minutes' { $start = (Get-Date).AddMinutes(- $Minutes) } } $eventTypes = "DrsVmMigratedEvent", "VmMigratedEvent" } process { $history += Get-VIEventPlus -Entity $entity -Start $start -EventType $eventTypes -Recurse:$Recurse | Select CreatedTime, @{N = "Type"; E = { if ($_.SourceDatastore.Name -eq $_.Ds.Name) { "vMotion" }else { "svMotion" } } }, @{N = "UserName"; E = { if ($_.UserName) { $_.UserName }else { "System" } } }, @{N = "VM"; E = { $_.VM.Name } }, @{N = "SrcVMHost"; E = { $_.SourceHost.Name.Split('.')[0] } }, @{N = "TgtVMHost"; E = { if ($_.Host.Name -ne $_.SourceHost.Name) { $_.Host.Name.Split('.')[0] } } }, @{N = "SrcDatastore"; E = { $_.SourceDatastore.Name } }, @{N = "TgtDatastore"; E = { if ($_.Ds.Name -ne $_.SourceDatastore.Name) { $_.Ds.Name } } } } end { if ($Sort) { $history | Sort-Object -Property CreatedTime } else { $history } } } #region "PowerCLI Settings" Set-PowerCLIConfiguration -InvalidCertificateAction Ignore -DefaultVIServerMode Multiple -DisplayDeprecationWarnings $true -Scope Session -Confirm:$false #endregion #region "Custom VIProperty Definitions" New-VIProperty -Name PercentFree -ObjectType Datastore -Value { param($datastore) '{0:P0}' -f ($datastore.FreeSpaceMB/$datastore.CapacityMB) } -Force New-VIProperty -Name PercentUsed -ObjectType Datastore -Value { param($datastore) '{0:P0}' -f (1-($datastore.FreeSpaceMB/$datastore.CapacityMB)) } -Force New-VIProperty -Name ProvisionedVMStorageGB -ObjectType Datastore -Value { param($datastore) '{0:N2}' -f ((get-vm -Datastore $datastore).ProvisionedSpaceGB | Measure-Object -Sum).Sum } New-VIProperty -Name UsedStorageGB -ObjectType Datastore -Value { param($datastore) [math]::Round($datastore.CapacityGB - $datastore.FreeSpaceGB,2) } New-VIProperty -Name OverCommitPercent -ObjectType Datastore -Value { param($datastore) '{0:P0}' -f ($datastore.ProvisionedVMStorageGB / $datastore.CapacityGB) } New-VIProperty -Name OverCommitRatio -ObjectType Datastore -Value { param($datastore) '{0:N2}' -f ($datastore.ProvisionedVMStorageGB / $datastore.CapacityGB) } New-VIProperty -Name RemoteHost -ObjectType Datastore -Value { param($datastore) $datastore.ExtensionData.Info.Nas.RemoteHost } -Force New-VIProperty -Name vCenter -ObjectType VirtualMachine -Value { param($vm) return ((($vm.Uid.Split("/")[1] -split("="))[1] -split("@"))[1] -split(":"))[0] } -Force New-VIProperty -Name vCenter -ObjectType VMHost -Value { param($vmHost) return ((($vmHost.Uid.Split("/")[1] -split("="))[1] -split("@"))[1] -split(":"))[0] } -Force New-VIProperty -Name vCenter -ObjectType Cluster -Value { param($cluster) return ((($cluster.Uid.Split("/")[1] -split("="))[1] -split("@"))[1] -split(":"))[0] } -Force New-VIProperty -Name vCenter -ObjectType DataCenter -Value { param($dataCenter) return ((($dataCenter.Uid.Split("/")[1] -split("="))[1] -split("@"))[1] -split(":"))[0] } -Force New-VIProperty -Name vCenter -ObjectType Datastore -Value { param($datastore) return ((($datastore.Uid.Split("/")[1] -split("="))[1] -split("@"))[1] -split(":"))[0] } -Force New-VIProperty -Name SanLunId -ObjectType Datastore -Value { param([VMware.VimAutomation.ViCore.Impl.V1.DatastoreManagement.DatastoreImpl]$datastore) [string]$lunID = "" if($datastore.Type -eq "VMFS") { $lunID = $datastore.ExtensionData.Info.Vmfs.Extent.DiskName.Substring($datastore.ExtensionData.Info.Vmfs.Extent.DiskName.Length - 4) } return $lunID } -Force | Out-Null New-VIProperty -Name IOPSRead -ObjectType VirtualMachine -Value { param($vm) [math]::round((Get-Stat $vm -stat "datastore.numberReadAveraged.average" -RealTime | Select -Expand Value | measure -average).Average, 1) } -Force New-VIProperty -Name IOPSWrite -ObjectType VirtualMachine -Value { param($vm) [math]::round((Get-Stat $vm -stat "datastore.numberWriteAveraged.average" -RealTime | Select -Expand Value | measure -average).Average, 1) } -Force New-VIProperty -Name ProvisionedStorageGB -ObjectType VirtualMachine -Value { param($vm) '{0:N2}' -f $([Math]::Round($vm.ProvisionedSpaceGB, 2)) } -Force New-VIProperty -Name UsedStorageGB -ObjectType VirtualMachine -Value { param($vm) #'{0:N2}' -f $([Math]::Round($vm.UsedSpaceGB, 2)) '{0:N2}' -f [math]::round((($vm.Guest.Disks | measure -Property capacitygb -Sum).Sum - ($vm.Guest.Disks | measure -Property freespacegb -Sum).Sum),2) } -Force New-VIProperty -Name MACAddress -ObjectType VirtualMachine -Value { param($vm) (Get-NetworkAdapter (Get-vm $vm) | Select-Object MacAddress).MacAddress } -Force New-VIProperty -Name Cluster -ObjectType VirtualMachine -Value { param($vm) ($vm | Select-Object -ExpandProperty VMHost | Select-Object Parent).Parent } -Force New-VIProperty -Name lunID -ObjectType ScsiLun -Value { param([VMware.VimAutomation.ViCore.Impl.V1.Host.Storage.Scsi.ScsiLunImpl]$lun) [int](Select-String ":L(?<lunID>\d+)$" -InputObject $lun.RuntimeName).Matches[0].Groups['lunID'].Value } -Force | Out-Null New-VIProperty -Name PercentUsedRAM -ObjectType VMHost -Value { param($vmhost) '{0:P0}' -f ($vmhost.MemoryUsageMB / $vmhost.MemoryTotalMB) } -Force New-VIProperty -Name TotalRamGb -ObjectType Cluster -Value { param($cluster) [int](($cluster | Get-VMHost | Measure-Object -Property MemoryTotalGB -Sum | Select Sum).Sum) } -Force New-VIProperty -Name UsableRamGb -ObjectType Cluster -Value { param($cluster) #This is as follows #(({AllHostsInClusterRAM - LargestHostInClusterRAM) * {MaxClusterUsage}) - ({HostRAMBuffer} * {CountOfHosts}) $clusterHosts = $cluster | Get-VMHost [Math]::Round(((($clusterHosts | Measure-Object -Property MemoryTotalGB -Sum).Sum - ($clusterHosts | Sort -Descending -Property MemoryTotalGB | Select -First 1 | Select MemoryTotalGB).MemoryTotalGB) * .9) - ($clusterHosts.Count * 3),2) } -Force New-VIProperty -Name TotalCpuMhz -ObjectType Cluster -Value { param($cluster) [int](($cluster | Get-VMHost | Measure-Object -Property CpuTotalMhz -Sum | Select Sum).Sum) } -Force New-VIProperty -Name UsableCpuMhz -ObjectType Cluster -Value { param($cluster) [int](($cluster | Get-VMHost | Measure-Object -Property CpuTotalMhz -Sum | Select Sum).Sum - ($cluster | Get-VMHost | Sort -Descending -Property CpuTotalMhz | Select -First 1 | Select CpuTotalMhz).CpuTotalMhz) } -Force New-VIProperty -Name PercentUsedCPU -ObjectType VMHost -Value { param($vmhost) '{0:P0}' -f ($vmhost.CpuUsageMhz / $vmhost.CpuTotalMhz) } -Force New-VIProperty -Name UsedCpuMhz -ObjectType Cluster -Value { param($cluster) [int]($cluster | Get-VMHost | Measure-Object -Property CpuUsageMhz -Sum | Select Sum).Sum } -Force New-VIProperty -Name PercentUsedCPU -ObjectType Cluster -Value { param($cluster) '{0:P0}' -f (($cluster | Get-VMHost | Measure-Object -Property CpuUsageMhz -Sum | Select Sum).Sum / $cluster.UsableCpuMhz) } -Force New-VIProperty -Name ProvisionedRamGb -ObjectType Cluster -Value { param($cluster) [int](($cluster | Get-VM | Where {$_.PowerState -eq "PoweredOn"} | measure -Property MemoryGB -Sum).Sum) } -Force -WarningAction SilentlyContinue New-VIProperty -Name ActualUsageRamGb -ObjectType Cluster -Value { param($cluster) [int](($cluster | Get-VMHost | Measure-Object -Property MemoryUsageGB -Sum | Select Sum).Sum) } -Force New-VIProperty -Name UsableRemainingRamPercent -ObjectType Cluster -Value { param($cluster) '{0:P0}' -f ($cluster.RemainingUsableRAMGB / $cluster.UsableRAMGB) } -Force New-VIProperty -Name RAMOverCommitRatio -Object Cluster -Value { param($cluster) '{0:N2}' -f ($cluster.ProvisionedRamGb / $cluster.UsableRamGb) } New-VIProperty -Name RemainingUsableRamGb -ObjectType Cluster -Value { param($cluster) $usableGB = ($cluster.UsableRAMGB - $cluster.ProvisionedRAMGB) if($usableGB -le 0) { [Math]::Floor($usableGB) } else { [Math]::Ceiling($usableGB) } } -Force New-VIProperty -Name DatastoreList -ObjectType VirtualMachine -Value { param($VirtualMachine) ($VirtualMachine.ExtensionData.Config.DatastoreUrl | Select Name).Name } -ErrorAction SilentlyContinue -Verbose:$false -WarningAction SilentlyContinue New-VIProperty -ObjectType VMHost -Name AvgRAMUsage24Hr -Value { param($vmHost) "{0:p2}" -f (($vmHost | Get-Stat -Stat mem.usage.average -Start (Get-Date).AddDays(-1) | Measure-Object -Property Value -Average).Average/100) } -Force New-VIProperty -ObjectType Cluster -Name NumPoweredOnVMs -Value { param($cluster) ($cluster | get-vm | Where {$_.PowerState -eq "PoweredOn"} | Measure-Object).Count } -Force -WarningAction SilentlyContinue New-VIProperty -ObjectType VMHost -Name NumPoweredOnVMs -Value { param($vmhost) ($vmhost | get-vm | Where {$_.PowerState -eq "PoweredOn"} | Measure-Object).Count } -Force -WarningAction SilentlyContinue New-VIProperty -ObjectType VIServer -Name NumPoweredOnVms -Value { param($viServer) (get-vm -Server $viServer | Where {$_.PowerState -eq "PoweredOn"} | Measure-Object).Count } -Force -WarningAction SilentlyContinue New-VIProperty -ObjectType VMHost -Name SerialNumber -Value { param($viServer) (Get-EsxCli -VMHost $viServer).hardware.platform.get().SerialNumber } -Force -WarningAction SilentlyContinue #endregion #region "Custom Alias definitions" New-Alias -Name RTFM -Value Get-Help -Description 'Read The Fabulous Manual' New-Alias -Name Disconnect-vCenter -Value Disconnect-VIServer -Description 'Wrapper for Disconnect-VIServer so we have consistency' #endregion |