For those of us who do not jump around from environment to environment often forget how lucky we are to know the details of our servers intimately. Over time you come to know what to expect and when something is just not right.
What if someone were to hand you a list of VMware hosts….with little to no documentation? This can be a bit daunting for sure. There are literally hundreds of details to look at from host setup, to networking, to storage and everything in between.
Recently, this happened to me and it got me thinking about ways to document such ‘new-to-me’ hosts. As an added bonus, not all VMware hosts (for whatever the reason) are tied to a vCenter server. Opening up multiple vSphere clients individually wasn’t the plan for me – I decided to write a PowerCLI script that would do the heavy lifting for me. The idea, was to gather as much info as possible and export the data to an Excel workbook.
I’ve seen a few Export-Xlsx functions floating around but had not gotten the chance to take a look and see what they could do and how easily they could accomplish the task. These functions give you the ability to create workbooks with multiple sheets – much more robust than Export-CSV. I finally settled on a function written by LucD and Gilbert van Griensven. It seems to work really well and I plan to add this functionality to reporting type scripts in the future. To keep everything nice and in a single file, I added the Export-Xlsx function to the script itself as opposed to calling from a module or something similar.
Running the script is pretty basic. There are only two parameters – server and path. The server parameter is used to feed the script one or more VMware host names (Not vCenters(!)) while the path parameter defines a folder to save the output to. Once run, you will be prompt for the host credentials (they must be the same for all servers in a single run).
I’ve tried my best to test the script on ESX (4) and ESXi hosts (4.1 – 5.5) using the latest version of PowerCLI (5.8 R1). While the script is not exactly optimized with all the fancy Get-View commands, I don’t expect to run it often. In my testing, it takes anywhere from 2 to 5 mins per host to complete. PowerShell v3 and Excel are required on the script host for the script to run.
I tried to grab any and all info I could find browsing the available cmdlets – if you feel something is missing, please let me know and I’ll see if it can be incorporated.
The following is a list of data exported:
- General Host Info
- HBA Info
- Disks
- SCSI LUNs
- Multipath Info
- iSCSI Targets
- Diagnostic Partition Info
- Datastores
- Datastore Chart (Used vs Free)
- Physical NIC Info
- VMKernel Info
- Service Console Info
- Standard Switch Info
- Standard Port Group Info
- Distributed Switch Info (Limited)
- Distributed Port Group Info (Limited)
- Firewall Exceptions
- Services Info
- SNMP Info
- Installed Patches
- Local Users/Groups
- VI Roles
- Permissions
- VM Info
- Snapshot Info
#Requires –Version 3 | |
#Requires -PSSnapin VMware.VimAutomation.Core | |
<# | |
.SYNOPSIS | |
Exports VMware host (ESX/ESXi) information to Excel | |
.DESCRIPTION | |
Queries one or more ESX/ESXi servers directly and exports all info to an Excel workbook | |
A new workbook/file will be created for each host | |
.PARAMETER Server | |
The name of one or more ESX/ESXi servers to query | |
.PARAMETER Path | |
Path to folder where Excel workbook is saved | |
.EXAMPLE | |
.\Get-VMHostInfo.ps1 -server myesxhost -path "E:\Reports" | |
Gathers info from myesxhost and exports info to an Excel workbook saved in E:\Reports | |
.EXAMPLE | |
.\Get-VMHostInfo.ps1 -server "myesxhost","myotheresxhost" -path "E:\Reports" | |
Gathers info from myesxhost and myotheresxhost, exports info to separate Excel workbooks located in E:\Reports | |
.EXAMPLE | |
$servers = Get-Content "E:\myhosts.txt";.\Get-VMHostInfo.ps1 -server $servers -path "E:\Reports" | |
Gathers a list of ESX/ESXi host names from E:\myhosts.txt and gathers\exports info to separate Excel workbooks located in E:\Reports | |
.NOTES | |
Author : Shawn Masterson | |
Export-Xlsx function from Gilbert van Griensven https://www.itpilgrims.com/2013/01/export-xlsx-extended/ | |
Excel is required to be installed on script host | |
Tested with ESX 4 and ESXi 4.1 thru 5.5 | |
#> | |
[CmdletBinding()] | |
Param ( | |
[parameter(Mandatory=$true)] | |
[String[]] | |
$server, | |
[parameter(Mandatory=$true)] | |
[String] | |
$path | |
) | |
### Supporting function ### | |
Function Export-Xlsx { | |
<# | |
.SYNOPSIS | |
Exports objects to an Excel workbook | |
.DESCRIPTION | |
Exports objects to an Excel workbook and applies cosmetics. Optionally add a title, autofilter, autofit and a chart. | |
Allows for export to .xls and .xlsx format. If .xlsx is specified but not available (Excel 2003) the data will be exported to .xls. | |
.PARAMETER InputObject | |
The data to be exported to Excel | |
.PARAMETER Path | |
The path of the Excel file. Defaults to %HomeDrive%\Export.xlsx. | |
.PARAMETER WorksheetName | |
The name of the worksheet. Defaults to filename in $Path without extension. | |
.PARAMETER ExpandArrayValues | |
Joins an array value to a newline separated list. | |
.PARAMETER ChartType | |
Name of an Excel chart to be added. | |
.PARAMETER TableStyle | |
Apply a style to the created table. Does not work in Excel 2003. | |
For an overview of styles see http://msdn.microsoft.com/fr-fr/library/documentformat.openxml.spreadsheet.tablestyle.aspx | |
The Pivot styles are not used in this function. | |
.PARAMETER Title | |
Adds a title to the worksheet. | |
.PARAMETER SheetPosition | |
Adds the worksheet either to the 'begin' or 'end' of the Excel file. | |
.PARAMETER TransposeColumnProperty | |
Selects a property of the input object which will be moved to the top row of the transposed table. | |
.PARAMETER ChartOnNewSheet | |
Adds a chart to a new worksheet instead of to the worksheet containing data. | |
The Chart will be placed after the sheet containing data. | |
.PARAMETER AppendWorksheet | |
Appends a worksheet to an existing Excel file. | |
.PARAMETER Borders | |
Adds borders to all cells. Defaults to True. | |
.PARAMETER HeaderColor | |
Applies background color to the header row. Defaults to True. | |
.PARAMETER AutoFit | |
Apply autofit to columns. Defaults to True. | |
.PARAMETER AutoFilter | |
Apply autofilter. Defaults to True. | |
.PARAMETER PassThru | |
Returns file object of the generated file. | |
.PARAMETER Force | |
Overwrites existing Excel sheet. When this switch is not used but the Excel file already exists, a new file with datestamp will be generated. | |
.PARAMETER Transpose | |
Transposes the data in Excel. This will automatically disable AutoFilter and HeaderColor. | |
.PARAMETER FreezePanes | |
Freezes the title row. | |
.EXAMPLE | |
Get-Process | Export-Xlsx -Path D:\Data\ProcessList.xlsx | |
Exports a list of running processes to Excel | |
.EXAMPLE | |
Get-ADuser -Filter {enabled -ne $True} | Select-Object Name,Surname,GivenName,DistinguishedName | Export-Xlsx -Path 'D:\Data\Disabled Users.xlsx' -Title 'Disabled users of Contoso.com' | |
Export all disabled AD users to Excel with optional title | |
.EXAMPLE | |
Get-Process | Sort-Object CPU -Descending | Export-Xlsx -Path D:\Data\Processes_by_CPU.xlsx | |
Export a sorted processlist to Excel | |
.EXAMPLE | |
Export-Xlsx (Get-Process) -AutoFilter:$False -PassThru | Invoke-Item | |
Export a processlist to %HomeDrive%\Export.xlsx with AutoFilter disabled, and open the Excel file | |
.NOTES | |
Author : Gilbert van Griensven | |
Based on http://www.lucd.info/2010/05/29/beyond-export-csv-export-xls/ | |
#> | |
[CmdletBinding(DefaultParametersetName="Default")] | |
Param ( | |
[Parameter(Position=0,Mandatory=$True,ValueFromPipeline=$True)] | |
[ValidateNotNullOrEmpty()] | |
$InputObject, | |
[ValidateScript({ | |
$ReqExt = [System.IO.Path]::GetExtension($_) | |
($ReqExt -eq ".xls") -or | |
($ReqExt -eq ".xlsx") | |
})] | |
$Path=(Join-Path $env:HomeDrive "Export.xlsx"), | |
$WorksheetName = [System.IO.Path]::GetFileNameWithoutExtension($Path), | |
[Switch] $AppendWorksheet, | |
[ValidateSet("begin","end")] $SheetPosition="begin", | |
$Title, | |
[Switch] $AutoFit=$True, | |
[Switch] $AutoFilter=$True, | |
[Switch] $FreezePanes, | |
[Switch] $Transpose, | |
[String] $TransposeColumnProperty, | |
[Switch] $ExpandArrayValues, | |
[PSObject] $ChartType, | |
[Switch] $ChartOnNewSheet, | |
[Parameter(ParameterSetName="CustomStyle")] | |
[Switch] $Borders=$True, | |
[Parameter(ParameterSetName="CustomStyle")] | |
[Switch] $HeaderColor=$True, | |
[Parameter(ParameterSetName="TableStyle")] | |
[String] $TableStyle, | |
[Switch] $Force, | |
[Switch] $PassThru | |
) | |
DynamicParam { | |
# Adds custom argument completers for 'ChartType' and 'TableStyle' parameters for this function only | |
If ([Reflection.Assembly]::LoadWithPartialName("Microsoft.Office.Interop.Excel") -ne $Null) { | |
$Completion_xlChartType = { | |
Param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameter) | |
[Enum]::GetValues([Microsoft.Office.Interop.Excel.XlChartType]) | % { | |
New-Object System.Management.Automation.CompletionResult $_, $_, 'ParameterValue', "$($_)" | |
} | |
} | |
$Completion_xlTableStyle = { | |
Param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameter) | |
1..28 | % { | |
@("TableStyleMedium$($_)") | |
If ($_ -le 21) { @("TableStyleLight$($_)") } | |
If ($_ -le 11) { @("TableStyleDark$($_)") } | |
} | | |
Sort-Object | % { | |
New-Object System.Management.Automation.CompletionResult $_, $_, 'ParameterValue', "$($_)" | |
} | |
} | |
If (!($global:options)) { $global:options = @{CustomArgumentCompleters = @{};NativeArgumentCompleters = @{}} } | |
$global:options['CustomArgumentCompleters']['Export-Xlsx:ChartType'] = $Completion_xlChartType | |
$global:options['CustomArgumentCompleters']['Export-Xlsx:TableStyle'] = $Completion_xlTableStyle | |
$function:tabexpansion2 = $function:tabexpansion2 -replace 'End\r\n{','End { If ($Null -ne $options) {$options += $global:options} Else {$options = $global:options}' | |
} | |
} | |
Begin { | |
Function Convert-NumberToA1 { | |
Param([parameter(Mandatory=$true)] [int]$number) | |
$a1Value = $null | |
While ($number -gt 0) { | |
$multiplier = [int][system.math]::Floor(($number / 26)) | |
$charNumber = $number - ($multiplier * 26) | |
If ($charNumber -eq 0) { $multiplier-- ; $charNumber = 26 } | |
$a1Value = [char]($charNumber + 96) + $a1Value | |
$number = $multiplier | |
} | |
Write-Verbose "Converted '$($number)' to '$($a1Value)'" | |
Return $a1Value | |
} | |
Function Using-Culture ([System.Globalization.CultureInfo]$Culture, [ScriptBlock]$Script) { | |
$OldCulture = [System.Threading.Thread]::CurrentThread.CurrentCulture | |
Trap { [System.Threading.Thread]::CurrentThread.CurrentCulture = $OldCulture } | |
[System.Threading.Thread]::CurrentThread.CurrentCulture = $Culture | |
$ExecutionContext.InvokeCommand.InvokeScript($Script) | |
[System.Threading.Thread]::CurrentThread.CurrentCulture = $OldCulture | |
} | |
$Path = [System.IO.Path]::GetFullPath($Path) | |
$Script:WorkingData = @() | |
} | |
Process { | |
$Script:WorkingData += $InputObject | |
} | |
End { | |
If ($Script:WorkingData.Count -eq 0) { | |
$ExceptionMessage = New-Object System.FormatException "Input object is empty. Nothing to export to Excel." | |
Throw $ExceptionMessage | |
} | |
$Props = $Script:WorkingData[0].PSObject.properties | % { $_.Name } | |
Write-Verbose "$($Props.Count) object properties detected" | |
If ($Transpose) { | |
Write-Verbose "Setting up for transposed data collection" | |
If (($TransposeColumnProperty) -and ($Props -contains $TransposeColumnProperty)) { | |
$Props = $Props | ? {$_ -ne $TransposeColumnProperty} | |
$Rows = 1 | |
} Else { | |
$TransposeColumnProperty = $Null | |
$HeaderColor = $False | |
} | |
$Rows += $Props.Count | |
$Cols = $Script:WorkingData.Count+1 | |
$AutoFilter = $False | |
} Else { | |
Write-Verbose "Setting up for data collection" | |
$Rows = $Script:WorkingData.Count+1 | |
$Cols = $Props.Count | |
} | |
Write-Verbose "Input object has $($Rows) rows and $($Cols) columns" | |
$A1Cols = Convert-NumberToA1 $Cols | |
$Array = New-Object 'object[,]' $Rows,$Cols | |
$Col = 0 | |
$Row = 0 | |
Write-Verbose "Storing object properties as data headers into array" | |
If (($Transpose) -and ($TransposeColumnProperty)) { | |
$Array[$Row,$Col] = $TransposeColumnProperty | |
$Row++ | |
} | |
$Props | % { | |
$Array[$Row,$Col] = $_.ToString() | |
If ($Transpose) { | |
$Row++ | |
} Else { | |
$Col++ | |
} | |
} | |
Write-Verbose "Storing object data into array" | |
$Row = 1 | |
$Script:WorkingData | % { | |
$Item = $_ | |
$Col = 0 | |
$Props | % { | |
If (($Transpose) -and ($TransposeColumnProperty) -and ($Col -eq 0)) { | |
$Array[$Col,$Row] = $Item.($TransposeColumnProperty).ToString() | |
$Col++ | |
} | |
If ($Item.($_) -eq $Null) { | |
If ($Transpose) { | |
$Array[$Col,$Row] = "" | |
} Else { | |
$Array[$Row,$Col] = "" | |
} | |
} Else { | |
If (($Item.($_) -is [System.Array]) -and ($ExpandArrayValues)) { | |
$ItemData = [String]::Join("`r`n",$Item.($_)) | |
} Else { | |
$ItemData = $Item.($_).ToString() | |
} | |
If ($Transpose) { | |
$Array[$Col,$Row] = $ItemData | |
} Else { | |
$Array[$Row,$Col] = $ItemData | |
} | |
} | |
$Col++ | |
} | |
$Row++ | |
} | |
Using-Culture en-US { | |
Write-Verbose "Attempting to start Excel as COM object" | |
Try { $ExcelApplication = New-Object -ComObject Excel.Application } | |
Catch { | |
$ExceptionMessage = New-Object System.FormatException "Could not create COM object. Please ensure Microsoft Excel is installed." | |
Throw $ExceptionMessage | |
} | |
$ExcelApplication.DisplayAlerts = $False | |
$ExcelApplicationFixedFormat = [Microsoft.Office.Interop.Excel.XLFileFormat]::xlWorkbookNormal | |
If ([System.IO.Path]::GetExtension($Path) -eq '.xlsx') { | |
Write-Verbose "Selected file format: .xlsx" | |
If ($ExcelApplication.Version -lt 12) { | |
Write-Verbose "Current Excel version `($($ExcelApplication.Version)`)does not support .xlsx format. Switching to .xls format" | |
$Path = [System.IO.Path]::ChangeExtension($Path,".xls") | |
} Else { | |
$ExcelApplicationFixedFormat = [Microsoft.Office.Interop.Excel.XLFileFormat]::xlWorkbookDefault | |
} | |
} Else { | |
Write-Verbose "Selected file format: .xls" | |
} | |
If (Test-Path -Path $Path -PathType "Leaf") { | |
Write-Verbose "$($Path) exists" | |
If ($AppendWorkSheet) { | |
Write-Verbose "AppendWorkSheet parameter received. Attempting to open $($Path)" | |
$Workbook = $ExcelApplication.Workbooks.Open($Path) | |
If ($Workbook.ReadOnly) { | |
$Workbook.Close() | |
$ExcelApplication.Quit() | |
While ([System.Runtime.Interopservices.Marshal]::ReleaseComObject($Workbook)) {} | |
While ([System.Runtime.Interopservices.Marshal]::ReleaseComObject($ExcelApplication)) {} | |
[GC]::Collect() | |
$ExceptionMessage = New-Object System.FormatException "The file $($Path) is marked read-only. Please check NTFS permissions and ensure the file is not open in other applications" | |
Throw $ExceptionMessage | |
} | |
If ($SheetPosition -eq "end") { | |
Write-Verbose "Setting sheet position to 'end'" | |
$Workbook.Worksheets.Add([System.Reflection.Missing]::Value,$Workbook.Sheets.Item($Workbook.Sheets.Count)) | Out-Null | |
} Else { | |
Write-Verbose "Setting sheet position to 'begin'" | |
$Workbook.Worksheets.Add($Workbook.Worksheets.Item(1)) | Out-Null | |
} | |
} Else { | |
If (!($Force)) { | |
$Path = $Path.Insert($Path.LastIndexOf(".")," - $(Get-Date -Format "ddMMyyyy-HHmm")") | |
Write-Verbose "No Force parameter specified. Target file is changed to: $($Path)" | |
} Else { | |
Write-Verbose "Force parameter specified. Overwriting existing file" | |
} | |
Write-Verbose "Adding new workbook" | |
$Workbook = $ExcelApplication.Workbooks.Add() | |
While ($Workbook.Worksheets.Count -gt 1) { $Workbook.Worksheets.Item(1).Delete() } | |
} | |
} Else { | |
Write-Verbose "$($Path) does not exist. Adding new workbook" | |
$Workbook = $ExcelApplication.Workbooks.Add() | |
While ($Workbook.Worksheets.Count -gt 1) { $Workbook.Worksheets.Item(1).Delete() } | |
} | |
$Worksheet = $Workbook.ActiveSheet | |
Try { $Worksheet.Name = $WorksheetName } | |
Catch { | |
Write-Verbose "!!! Unable to set worksheet name to $($WorksheetName)" | |
} | |
If ($Title) { | |
Write-Verbose "Adding title" | |
$Worksheet.Cells.Item(1,1) = $Title | |
$TitleRange = $Worksheet.Range("a1","$($A1Cols)2") | |
$TitleRange.Font.Size = 18 | |
$TitleRange.Font.Bold=$True | |
$TitleRange.Font.Name = "Cambria" | |
$TitleRange.Font.ThemeFont = 1 | |
$TitleRange.Font.ThemeColor = 4 | |
$TitleRange.Font.ColorIndex = 55 | |
$TitleRange.Font.Color = 8210719 | |
$TitleRange.Merge() | |
$TitleRange.VerticalAlignment = -4160 | |
While ([System.Runtime.Interopservices.Marshal]::ReleaseComObject($TitleRange)) {} | |
$UsedRange = $Worksheet.Range("a3","$($A1Cols)$($Rows + 2)") | |
If ($HeaderColor) { | |
Write-Verbose "Setting header row background color" | |
$Worksheet.Range("a3","$($A1Cols)3").Interior.ColorIndex = 48 | |
$Worksheet.Range("a3","$($A1Cols)3").Font.Bold = $True | |
} | |
If (($FreezePanes) -and ((($Transpose) -and ($TransposeColumnProperty)) -or (!($Transpose)))) { | |
Write-Verbose "Freezing panes" | |
$Worksheet.Range("a4:a4").Select() | Out-Null | |
$ExcelApplication.ActiveWindow.FreezePanes = $True | |
} | |
} Else { | |
$UsedRange = $Worksheet.Range("a1","$($A1Cols)$($Rows)") | |
If ($HeaderColor) { | |
Write-Verbose "Setting header row background color" | |
$Worksheet.Range("a1","$($A1Cols)1").Interior.ColorIndex = 48 | |
$Worksheet.Range("a1","$($A1Cols)1").Font.Bold = $True | |
} | |
If (($FreezePanes) -and ((($Transpose) -and ($TransposeColumnProperty)) -or (!($Transpose)))) { | |
Write-Verbose "Freezing panes" | |
$Worksheet.Range("a2:a2").Select() | Out-Null | |
$ExcelApplication.ActiveWindow.FreezePanes = $True | |
} | |
} | |
Write-Verbose "Transferring array data to selected range in Excel" | |
$UsedRange.Value2 = $Array | |
$UsedRange.HorizontalAlignment = -4131 | |
$UsedRange.VerticalAlignment = -4160 | |
If ($Borders) { | |
Write-Verbose "Adding borders" | |
$UsedRange.Borders.LineStyle = 1 | |
$UsedRange.Borders.Weight = 2 | |
} | |
If ($AutoFilter) { | |
Write-Verbose "Applying autofilter" | |
$UsedRange.AutoFilter() | Out-Null | |
} | |
If ($AutoFit) { | |
Write-Verbose "Applying autofit" | |
$Worksheet.UsedRange.EntireColumn.AutoFit() | Out-Null | |
$Worksheet.UsedRange.EntireRow.AutoFit() | Out-Null | |
} | |
If (($TableStyle) -and ($ExcelApplication.Version -ge 12)) { | |
Write-Verbose "Applying table style '$($TableStyle)'" | |
$ListObject = $Worksheet.ListObjects.Add([Microsoft.Office.Interop.Excel.XlListObjectSourceType]::xlSrcRange, $UsedRange, $Null, [Microsoft.Office.Interop.Excel.XlYesNoGuess]::xlYes, $Null) | |
$ListObject.TableStyle = $TableStyle | |
While ([System.Runtime.Interopservices.Marshal]::ReleaseComObject($ListObject)) {} | |
} | |
If ($ChartType) { | |
Try { | |
Write-Verbose "Attempting to add chart of type '$($ChartType)'" | |
[Microsoft.Office.Interop.Excel.XlChartType]$ChartType = $ChartType | |
If ($ChartOnNewSheet) { | |
Write-Verbose "Adding chart to new worksheet" | |
$Workbook.Charts.Add().ChartType = $ChartType | |
$Workbook.ActiveChart.setSourceData($UsedRange) | |
Try { $Workbook.ActiveChart.Name = "$($WorksheetName) - Chart" } | |
Catch { } | |
$Workbook.ActiveChart.Move([System.Reflection.Missing]::Value,$Workbook.Sheets.Item($Worksheet.Name)) | |
} Else { | |
Write-Verbose "Adding chart to current sheet" | |
$Worksheet.Shapes.AddChart($ChartType).Chart.setSourceData($UsedRange) | Out-Null | |
} | |
} | |
Catch { | |
Write-Verbose "!!! '$($ChartType)' is not a valid Excel chart type. Use tab expansion to choose between valid chart types." | |
} | |
} | |
Write-Verbose "Saving Excel workbook to $($Path)" | |
$Workbook.Worksheets.Item(1).Select() | |
Try { $Workbook.SaveAs($Path,$ExcelApplicationFixedFormat) } | |
Catch { $ExceptionMessage = New-Object System.FormatException "Unable to save to $($Path). Please ensure you have write access." } | |
Write-Verbose "Closing Excel and cleaning up references" | |
$Workbook.Close() | |
$ExcelApplication.Quit() | |
While ([System.Runtime.Interopservices.Marshal]::ReleaseComObject($UsedRange)) {} | |
While ([System.Runtime.Interopservices.Marshal]::ReleaseComObject($Worksheet)) {} | |
While ([System.Runtime.Interopservices.Marshal]::ReleaseComObject($Workbook)) {} | |
While ([System.Runtime.Interopservices.Marshal]::ReleaseComObject($ExcelApplication)) {} | |
[GC]::Collect() | |
If ($ExceptionMessage) { Throw $ExceptionMessage } | |
} | |
If ($PassThru) { Return Get-Item $Path } | |
} | |
} | |
### Main script begin ### | |
# Test path | |
If (!(Test-Path $path)) { | |
Write-Host "Path not found - $path" -ForegroundColor Red | |
Exit | |
} | |
# Obtain Credentials | |
$creds = Get-Credential -Message "Enter ESX/ESXi host credentials used to connect" -UserName root | |
# Cycle through servers gathering and exporting info | |
Foreach ($ESX in $Server) { | |
# Create full path to Excel workbook | |
$FullPath = $Path.Trimend('\') + "\HostInfo_" + $ESX + "_" + (Get-Date -Format MM-dd-yyyy) + ".xlsx" | |
# Connect to ESX/ESXi host | |
$connection = Connect-VIServer $ESX -Credential $creds | |
# Ensure connection | |
If ($connection) { | |
Write-Host "Connected to $ESX" | |
# Get ESX(i) Host Info | |
$VMHost = Get-VMHost $ESX | |
$VMHostProp = [ordered]@{} | |
$VMHostProp.Name = $VMHost.NetworkInfo.HostName | |
$VMHostProp."Domain Name" = $VMHost.NetworkInfo.DomainName | |
$VMHostProp.Hypervisor = $VMHost.Extensiondata.Config.Product.FullName | |
$VMHostProp.License = $VMHost.LicenseKey | |
$VMHostProp.Vendor = $VMHost.Manufacturer | |
$VMHostProp.Model = $VMHost.Model | |
$VMHostProp."BIOS Version" = $VMHost.Extensiondata.Hardware.BiosInfo.BiosVersion | |
$VMHostProp."CPU Model" = $VMHost.ProcessorType | |
$VMHostProp."CPU Count" = $VMHost.ExtensionData.Summary.Hardware.NumCpuPkgs | |
$VMHostProp."Total Cores" = $VMHost.ExtensionData.Summary.Hardware.numCpuCores | |
$VMHostProp."Total Threads" = $VMHost.ExtensionData.Summary.Hardware.numCpuThreads | |
$VMHostProp."Hyperthreading Enabled" = $VMHost.HyperThreadingActive | |
$VMHostProp."CPU Current Usage (Mhz)" = $VMHost.CpuUsageMhz | |
$VMHostProp."Memory (GB)" = [Math]::Round($VMHost.MemoryTotalGB,0) | |
$VMHostProp."Memory Current Usage (GB)" = [Math]::Round($VMHost.MemoryUsageGB,0) | |
$VMHostProp."FC HBAs" = ($VMHost | Get-VMHostHba | where {$_.Type -eq "FibreChannel"}).Count | |
$VMHostProp."iSCSI HBAs" = ($VMHost | Get-VMHostHba | where {$_.Type -eq "IScsi"}).Count | |
$VMHostProp."Physical NICs" = $VMHost.ExtensionData.Config.Network.Pnic.Count | |
If ($VMHost.NetworkInfo.VMKernelGateway) { | |
$VMHostProp."VMKernel Gateway" = $VMHost.NetworkInfo.VMKernelGateway | |
} Else { | |
$VMHostProp."Console Gateway" = $VMHost.NetworkInfo.ConsoleGateway | |
} | |
Try { | |
$domainStatus = "" | |
$domainStatus = $VMHost | Get-VMHostAuthentication -ErrorAction Stop | |
$VMHostProp."Authentication Domain" = If ($domainStatus.Domain){$domainStatus.Domain} Else {"Not Configured"} | |
$VMHostProp."Authentication Domain Status" = If ($domainStatus.DomainMembershipStatus){$domainStatus.DomainMembershipStatus} Else {"Unknown"} | |
$VMHostProp."Trusted Domains" = If ($domainStatus.Trusteddomains) {$domainStatus | Select -ExpandProperty TrustedDomains | Out-String} Else {"None"} | |
} Catch {} | |
$VMHostProp."DNS Server(s)" = $VMHost.ExtensionData.Config.Network.DnsConfig.Address | Out-String | |
$VMHostProp."Search Domain(s)" = $VMHost.NetworkInfo.SearchDomain | Out-String | |
$VMHostProp.TimeZone = $VMHost.TimeZone | |
$VMHostProp."NTP Server(s)" = $VMHost | Get-VMHostNtpServer | Out-String | |
Try { | |
$VMHostProp."Syslog Server(s)" = $VMHost | Get-VMHostSysLogServer -ErrorAction Stop | %{$_.Host + ":" + $_.Port} | Out-String | |
} Catch { | |
$VMHostProp."Syslog Server(s)" = "Unavailable" | |
} | |
Try { | |
$VMHostProp."Firewall Default Allow Incoming" = $VMHost | Get-VMHostFirewallDefaultPolicy -ErrorAction Stop | Select -ExpandProperty IncomingEnabled | |
$VMHostProp."Firewall Default Allow Outgoing" = $VMHost | Get-VMHostFirewallDefaultPolicy -ErrorAction Stop | Select -ExpandProperty OutgoingEnabled | |
} Catch {} | |
$VMHostProp."VM Count" = ($VMHost | Get-VM).Count | |
$VMHostProp."Report Created" = Get-Date | |
$VMHostInfo = New-Object –TypeName PSObject –Prop $VMHostProp | |
$VMHostInfo | Export-Xlsx -Path $FullPath -WorksheetName "ESX(i) Info" -Title "VMHost Information" -Transpose -Borders:$false -Force | |
# Get HBA Info | |
$HBAInfo = @() | |
$HBAs = $VMHost | Get-VMHostHba | |
Foreach ($HBA in $HBAs) { | |
$HBAProp = [ordered]@{} | |
$HBAProp.Device = $HBA.Device | |
$HBAProp."HBA Model" = $HBA.Model | |
$HBAProp."HBA Type" = $HBA.Type | |
$HBAProp.Driver = $HBA.Driver | |
$HBAProp.PCI = $HBA.PCI | |
$NWWN = $null | |
$NWWNFormatted = $null | |
[String] $NWWN = "{0:x}" -f $HBA.NodeWorldWideName | |
If ($NWWN) { | |
For ($i=0;$i -lt 8;$i++) | |
{ | |
$NWWNFormatted += "{0}:" -f $($NWWN.SubString($i * 2, 2)) | |
} | |
$NWWNFormatted = $NWWNFormatted.SubString(0, $NWWNFormatted.Length - 1) | |
} | |
$PWWN = $null | |
$PWWNFormatted = $null | |
[String] $PWWN = "{0:x}" -f $HBA.PortWorldWideName | |
If ($PWWN) { | |
For ($i=0;$i -lt 8;$i++) | |
{ | |
$PWWNFormatted += "{0}:" -f $($PWWN.SubString($i * 2, 2)) | |
} | |
$PWWNFormatted = $PWWNFormatted.SubString(0, $PWWNFormatted.Length - 1) | |
} | |
$HBAProp.NWWN = $NWWNFormatted | |
$HBAProp.PWWN = $PWWNFormatted | |
$HBAProp."Software Based" = $HBA.IsSoftwareBased | |
$HBAProp."iSCSI Name" = $HBA.IScsiName | |
$HBAProp."iSCSI Alias" = $HBA.IScsiAlias | |
$HBAProp.Status = $HBA.Status | |
$HBATemp = New-Object –TypeName PSObject –Prop $HBAProp | |
$HBAInfo += $HBATemp | |
} | |
If ($HBAInfo) { | |
$HBAInfo | Export-Xlsx -Path $FullPath -WorksheetName "HBA Info" -Title "HBA Info" -AppendWorksheet -SheetPosition "end" | |
} | |
# Get Host Disks | |
$diskInfo = @() | |
$disks = $VMHost | Get-VMHostDisk | |
ForEach ($disk in $disks) { | |
$diskProp = [ordered]@{} | |
$diskProp."Device Name" = $disk.DeviceName | |
$diskProp."SCSI LUN" = $disk.ScsiLun | |
$diskProp.Cylinders = $disk.Cylinders | |
$diskProp.Heads = $disk.Heads | |
$diskProp.Sectors = $disk.Sectors | |
$diskProp.TotalSectors = $disk.TotalSectors | |
$diskTemp = New-Object –TypeName PSObject –Prop $diskProp | |
$diskInfo += $diskTemp | |
} | |
If ($diskInfo) { | |
$diskInfo | Sort "Device Name" | Export-Xlsx -Path $FullPath -WorksheetName "Disks" -Title "Host Disks" -AppendWorksheet -SheetPosition "end" | |
} | |
# Get SCSI LUNs | |
$lunInfo = @() | |
$scsiLuns = $VMHost | Get-ScsiLun | |
ForEach ($scsiLun in $scsiLuns) { | |
$scsiLunProp = [ordered]@{} | |
$scsiLunProp."Runtime Name" = $scsiLun.RuntimeName | |
$scsiLunProp."Canonical Name" = $scsiLun.CanonicalName | |
$scsiLunProp."Device Path" = $scsiLun.ConsoleDeviceName | |
$scsiLunProp.Type = $scsiLun.LunType | |
$scsiLunProp.Vendor = $scsiLun.Vendor | |
$scsiLunProp.Model = $scsiLun.Model | |
$scsiLunProp."Serial Number" = $scsiLun.SerialNumber | |
$scsiLunProp."Capacity (GB)" = [Math]::Round($scsiLun.CapacityGB,2) | |
$scsiLunProp."Multipath Policy" = $scsiLun.MultipathPolicy | |
$scsiLunProp.Local = $scsiLun.IsLocal | |
$scsiLunProp.SSD = $scsiLun.ExtensionData.Ssd | |
$scsiLunProp.UUID = $scsiLun.ExtensionData.Uuid | |
$scsiLunTemp = New-Object –TypeName PSObject –Prop $scsiLunProp | |
$lunInfo += $scsiLunTemp | |
} | |
If ($lunInfo) { | |
$lunInfo | Sort Type | Export-Xlsx -Path $FullPath -WorksheetName "SCSI LUNs" -Title "SCSI LUNs" -AppendWorksheet -SheetPosition "end" | |
} | |
# Get Multipathing Info | |
$pathInfo = @() | |
$luns = $VMhost.ExtensionData.config.storagedevice.multipathinfo.lun | |
ForEach ($lun in $luns) { | |
$lunName = $lun.Id | |
$lunPolicy = $lun.policy.policy | |
$lunPaths = $lun.path | |
Foreach ($lunPath in $lunPaths) { | |
$pathProp = [ordered]@{} | |
$pathProp."LUN ID" = $lunName | |
$pathProp."LUN Policy" = $lunPolicy | |
$pathProp.State = $lunPath.pathstate | |
$pathProp."Path Name" = $lunPath.Name | |
$pathProp."Adapter Name" = ($lunPath.Name).Split("-")[0] | |
$pathProp."Target Name" = ($lunPath.Name).Split("-")[1] | |
$pathProp."LUN Name" = ($lunPath.Name).Split("-")[2] | |
$pathTemp = New-Object –TypeName PSObject –Prop $pathProp | |
$pathInfo += $pathTemp | |
} | |
} | |
If ($pathInfo) { | |
$pathInfo | Sort "LUN ID" | Export-Xlsx -Path $FullPath -WorksheetName "Multipath Info" -Title "Multipath Info" -AppendWorksheet -SheetPosition "end" | |
} | |
# Get iSCSI HBA Targets | |
$iscsiTargetInfo = @() | |
$iscsiTargets = Get-IScsiHbaTarget -Server $ESX | |
ForEach ($iscsiTarget in $iscsiTargets) { | |
$iscsiTargetProp = [ordered]@{} | |
$iscsiTargetProp.Name = $iscsiTarget.Name | |
$iscsiTargetProp."iSCSI Name" = $iscsiTarget.IScsiName | |
$iscsiTargetProp.Address = $iscsiTarget.Address | |
$iscsiTargetProp.Port = $iscsiTarget.Port | |
$iscsiTargetProp.Authentication = $iscsiTarget.AuthenticationProperties | |
$iscsiTargetProp.Type = $iscsiTarget.Type | |
$iscsiTargetProp."iSCSI HBA Name" = $iscsiTarget.IScsiHbaName | |
$iscsiTargetTemp = New-Object –TypeName PSObject –Prop $iscsiTargetProp | |
$iscsiTargetInfo += $iscsiTargetTemp | |
} | |
If ($iscsiTargetInfo) { | |
$iscsiTargetInfo | Sort Name | Export-Xlsx -Path $FullPath -WorksheetName "iSCSI Targets" -Title "iSCSI HBA Targets" -AppendWorksheet -SheetPosition "end" | |
} | |
# Get Host Diagnostic Partitions | |
$diagInfo = @() | |
$diags = $VMHost | Get-VMHostDiagnosticPartition | |
ForEach ($diag in $diags) { | |
$diagProp = [ordered]@{} | |
$diagProp."Canonical Name" = $diag.CanonicalName | |
$diagProp."Diagnostic Type" = $diag.DiagnosticType | |
$diagProp."Storage Type" = $diag.StorageType | |
$diagProp.Slots = $diag.SlotCount | |
$diagProp.Active = $diag.Active | |
$diagTemp = New-Object –TypeName PSObject –Prop $diagProp | |
$diagInfo += $diagTemp | |
} | |
If ($diagInfo) { | |
$diagInfo | Sort Active -Descending | Export-Xlsx -Path $FullPath -WorksheetName "Diagnostic Partitions" -Title "Diagnostic Partitions" -AppendWorksheet -SheetPosition "end" | |
} | |
# Get Datastore Info | |
$DSInfo = @() | |
$DSs = $VMHost | Get-Datastore | |
Foreach ($DS in $DSs) { | |
$DSProp = [ordered]@{} | |
$DSProp.Name = $DS.Name | |
$DSProp.Type = $DS.Type | |
$DSProp."Size (GB)" = [Math]::Round($DS.CapacityGB,2) | |
$DSProp."Used (GB)" = [Math]::Round($DS.CapacityGB - $DS.FreeSpaceGB,2) | |
$DSProp."Free (GB)" = [Math]::Round($DS.FreeSpaceGB,2) | |
$usedPerc = ($DS.CapacityGB - $DS.FreeSpaceGB)/$DS.CapacityGB | |
$DSProp."Used %" = "{0:P1}" -f $usedPerc | |
$DSProp."Mount Point" = $DS.ExtensionData.Info.Url | |
$DSProp.Extents = If ($DS.Type -eq "VMFS"){$DS.ExtensionData.Info.Vmfs.Extent.DiskName} | |
ElseIf ($DS.Type -eq "NFS"){$DS.ExtensionData.Info.Nas.RemoteHost + ":" + $DS.ExtensionData.Info.Nas.RemotePath} | |
$DSProp.StorageIOControlEnabled = $DS.StorageIOControlEnabled | |
$DSProp.FileSystemVersion = $DS.FileSystemVersion | |
$DSProp.BlockSize = $DS.ExtensionData.Info.Vmfs.BlockSizeMB | |
$DSProp.SSD = $DS.ExtensionData.Info.Vmfs.Ssd | |
$DSProp.Local = $DS.ExtensionData.Info.Vmfs.Local | |
$DSProp."VM Count" = ($DS | Get-VM).Count | |
$DSProp.State = $DS.State | |
$DSTemp = New-Object –TypeName PSObject –Prop $DSProp | |
$DSInfo += $DSTemp | |
} | |
If ($DSInfo) { | |
$DSInfo | Sort Name | Export-Xlsx -Path $FullPath -WorksheetName "Datastores" -Title "Datastores" -AppendWorksheet -SheetPosition "end" | |
} | |
# Get Datastore Chart | |
$DSInfo = @() | |
Foreach ($DS in $DSs) { | |
$DSProp = [ordered]@{} | |
$DSProp.Name = $DS.Name | |
$DSProp."Used (GB)" = [Math]::Round($DS.CapacityGB - $DS.FreeSpaceGB,2) | |
$DSProp."Free (GB)" = [Math]::Round($DS.FreeSpaceGB,2) | |
$DSTemp = New-Object –TypeName PSObject –Prop $DSProp | |
$DSInfo += $DSTemp | |
} | |
If ($DSInfo) { | |
$DSInfo | Sort Name | Export-Xlsx -Path $FullPath -WorksheetName "Datastores - Chart" -Title "Datastores - Chart" -ChartType xlColumnStacked -AppendWorksheet -SheetPosition "end" | |
} | |
# Get Physical NIC Info | |
$pNICInfo = @() | |
$NICs = $VMHost | Get-VMHostNetworkAdapter -Physical | |
Foreach ($NIC in $NICs) { | |
$NICProp = [ordered]@{} | |
$NICProp.pNIC = $NIC.DeviceName | |
$NICProp.Model = ($VMHost.ExtensionData.Hardware.PciDevice | where {$_.Id -eq $NIC.ExtensionData.Pci}).DeviceName | |
$NICProp.Driver = $NIC.ExtensionData.Driver | |
$NICProp."Speed (MB)" = $NIC.ExtensionData.LinkSpeed.SpeedMB | |
$NICProp."Full Duplex" = $NIC.ExtensionData.LinkSpeed.Duplex | |
$NICProp.MAC = $NIC.Mac | |
$NICProp."PCI Location" = $NIC.ExtensionData.Pci | |
$NICProp.vSwitch = ($VMHost | Get-VirtualSwitch | where {$_.Nic -contains $NIC.DeviceName}).Name | |
$NICTemp = New-Object –TypeName PSObject –Prop $NICProp | |
$pNICInfo += $NICTemp | |
} | |
If ($pNICInfo) { | |
$pNICInfo | Export-Xlsx -Path $FullPath -WorksheetName "pNIC Info" -Title "Physical NIC Info" -AppendWorksheet -SheetPosition "end" | |
} | |
# Get VMKernel Virtual Network Adapter Info | |
$vNICInfo = @() | |
$vNICs = $VMHost | Get-VMHostNetworkAdapter -VMKernel | |
Foreach ($vNIC in $vNICs) { | |
$vNICProp = [ordered]@{} | |
$vNICProp.VMKernel = $vNIC.DeviceName | |
$vNICProp.MAC = $vNIC.Mac | |
$vNICProp.MTU = $vNIC.Mtu | |
$vNICProp.IPv6Enabled = $vNIC.IPv6Enabled | |
$vNICProp.DHCPEnabled = $vNIC.DhcpEnabled | |
$vNICProp.IP = $vNIC.IP | |
$vNICProp.SubnetMask = $vNIC.SubnetMask | |
$vNICProp.PortGroupName = $vNIC.PortGroupName | |
$vNICProp.MgmtEnabled = $vNIC.ManagementTrafficEnabled | |
$vNICProp.vMotionEnabled = $vNIC.vMotionEnabled | |
$vNICProp.FTEnabled = $vNIC.FaultToleranceLoggingEnabled | |
$vNICProp.VSANEnabled = $vNIC.VsanTrafficEnabled | |
$vNICTemp = New-Object –TypeName PSObject –Prop $vNICProp | |
$vNICInfo += $vNICTemp | |
} | |
If ($vNICInfo) { | |
$vNICInfo | Export-Xlsx -Path $FullPath -WorksheetName "VMKernel Info" -Title "VMKernel Info" -AppendWorksheet -SheetPosition "end" | |
} | |
# Get Service Console Info | |
$cNICInfo = @() | |
$cNICs = $VMHost | Get-VMHostNetworkAdapter -Console | |
Foreach ($cNIC in $cNICs) { | |
$cNICProp = [ordered]@{} | |
$cNICProp.cNIC = $cNIC.DeviceName | |
$cNICProp.MAC = $cNIC.Mac | |
$cNICProp.DHCPEnabled = $cNIC.DhcpEnabled | |
$cNICProp.IP = $cNIC.IP | |
$cNICProp.SubnetMask = $cNIC.SubnetMask | |
$cNICProp.PortGroupName = $cNIC.PortGroupName | |
$cNICTemp = New-Object –TypeName PSObject –Prop $cNICProp | |
$cNICInfo += $cNICTemp | |
} | |
If ($cNICInfo) { | |
$cNICInfo | Export-Xlsx -Path $FullPath -WorksheetName "Service Console Info" -Title "Service Console Info" -AppendWorksheet -SheetPosition "end" | |
} | |
# Get Standard Switch Info | |
$sSwInfo = @() | |
$sSwitchs = $VMHost | Get-VirtualSwitch -Standard | |
Foreach ($sSwitch in $sSwitchs) { | |
$sSwProp = [ordered]@{} | |
$sSwProp.Name = $sSwitch.Name | |
$sSwProp.MTU = $sSwitch.Mtu | |
$sSwProp."pNIC(s)" = $sSwitch.Nic | Out-String | |
$sSwProp."Load Balancing" = $sSwitch.ExtensionData.Spec.Policy.NicTeaming.Policy | |
$sSwProp."Network Failure Detection" = If ($sSwitch.ExtensionData.Spec.Policy.NicTeaming.FailureCriteria.CheckBeacon) { | |
"Beacon probing"} Else {"Link status only"} | |
$sSwProp."Notify Switches" = $sSwitch.ExtensionData.Spec.Policy.NicTeaming.NotifySwitches | |
$sSwProp."Failback" = $sSwitch.ExtensionData.Spec.Policy.NicTeaming.ReversePolicy | |
$sSwProp."Active pNIC(s)" = $sSwitch.ExtensionData.Spec.Policy.NicTeaming.NicOrder.ActiveNic | Out-String | |
$sSwProp."Standby pNIC(s)" = $sSwitch.ExtensionData.Spec.Policy.NicTeaming.NicOrder.StandbyNic | Out-String | |
$sSwProp."Promiscuous Mode" = $sSwitch.ExtensionData.Spec.Policy.Security.AllowPromiscuous | |
$sSwProp."Mac Address Changes" = $sSwitch.ExtensionData.Spec.Policy.Security.MacChanges | |
$sSwProp."Forged Transmits" = $sSwitch.ExtensionData.Spec.Policy.Security.ForgedTransmits | |
$sSwProp."Traffic Shaping Enabled" = $sSwitch.ExtensionData.Spec.Policy.ShapingPolicy.Enabled | |
$sSwProp."Average Bandwidth" = $sSwitch.ExtensionData.Spec.Policy.ShapingPolicy.AverageBandwidth | |
$sSwProp."Peak Bandwidth" = $sSwitch.ExtensionData.Spec.Policy.ShapingPolicy.PeakBandwidth | |
$sSwProp."Burst Size" = $sSwitch.ExtensionData.Spec.Policy.ShapingPolicy.BurstSize | |
$sSwProp."Portgroup(s)" = $sSwitch | Get-VirtualPortGroup | Select -ExpandProperty Name | Out-String | |
$sSwTemp = New-Object –TypeName PSObject –Prop $sSwProp | |
$sSwInfo += $sSwTemp | |
} | |
If ($sSwInfo) { | |
$sSwInfo | Export-Xlsx -Path $FullPath -WorksheetName "Standard Switch Info" -Title "Standard Switch Info" -AppendWorksheet -SheetPosition "end" | |
} | |
# Get Distributed Switch Information | |
$dvSwInfo = @() | |
$dvSwitchs = $VMHost | Get-VDSwitch | |
Foreach ($dvSwitch in $dvSwitchs) { | |
$dvSwProp = [ordered]@{} | |
$dvSwProp.Name = $dvSwitch.Name | |
$dvSwProp.MTU = $dvSwitch.Mtu | |
$dvSwProp."Overall Status" = $dvSwitch.ExtensionData.OverallStatus | |
$dvSwProp."Config Status" = $dvSwitch.ExtensionData.ConfigStatus | |
$dvSwProp.Note = "vCenter needed for further info" | |
$dvSwTemp = New-Object –TypeName PSObject –Prop $dvSwProp | |
$dvSwInfo += $dvSwTemp | |
} | |
If ($dvSwInfo) { | |
$dvSwInfo | Export-Xlsx -Path $FullPath -WorksheetName "Distributed Switch Info" -Title "Distributed Switch Info" -AppendWorksheet -SheetPosition "end" | |
} | |
# Get Standard Portgroup Information | |
$sPortInfo = @() | |
$sPortGroups = $VMHost | Get-VirtualPortGroup -Standard | |
Foreach ($sPortGroup in $sPortGroups) { | |
$sPortProp = [ordered]@{} | |
$sPortProp."Virtual Switch" = $sPortGroup.VirtualSwitchName | |
$sPortProp.Portgroup = $sPortGroup.Name | |
$sPortProp.VLAN = $sPortGroup.Vlanid | |
$sPortProp."Load Balancing" = $sPortGroup.ExtensionData.ComputedPolicy.NicTeaming.Policy | |
$sPortProp."Network Failure Detection" = If ($sPortGroup.ExtensionData.ComputedPolicy.NicTeaming.FailureCriteria.CheckBeacon) { | |
"Beacon probing"} Else {"Link status only"} | |
$sPortProp."Notify Switches" = $sPortGroup.ExtensionData.ComputedPolicy.NicTeaming.NotifySwitches | |
$sPortProp."Failback" = $sPortGroup.ExtensionData.ComputedPolicy.NicTeaming.ReversePolicy | |
$sPortProp."Active pNIC(s)" = $sPortGroup.ExtensionData.ComputedPolicy.NicTeaming.NicOrder.ActiveNic | Out-String | |
$sPortProp."Standby pNIC(s)" = $sPortGroup.ExtensionData.ComputedPolicy.NicTeaming.NicOrder.StandbyNic | Out-String | |
$sPortProp."Promiscuous Mode" = $sPortGroup.ExtensionData.ComputedPolicy.Security.AllowPromiscuous | |
$sPortProp."Mac Address Changes" = $sPortGroup.ExtensionData.ComputedPolicy.Security.MacChanges | |
$sPortProp."Forged Transmits" = $sPortGroup.ExtensionData.ComputedPolicy.Security.ForgedTransmits | |
$sPortProp."Traffic Shaping Enabled" = $sPortGroup.ExtensionData.ComputedPolicy.ShapingPolicy.Enabled | |
$sPortProp."Average Bandwidth" = $sPortGroup.ExtensionData.ComputedPolicy.ShapingPolicy.AverageBandwidth | |
$sPortProp."Peak Bandwidth" = $sPortGroup.ExtensionData.ComputedPolicy.ShapingPolicy.PeakBandwidth | |
$sPortProp."Burst Size" = $sPortGroup.ExtensionData.ComputedPolicy.ShapingPolicy.BurstSize | |
$sPortProp."VM Count" = ($sPortGroup | Get-VM).Count | |
$sPortTemp = New-Object –TypeName PSObject –Prop $sPortProp | |
$sPortInfo += $sPortTemp | |
} | |
If ($sPortInfo) { | |
$sPortInfo | Sort "Virtual Switch", Portgroup | Export-Xlsx -Path $FullPath -WorksheetName "Standard Portgroup Info" -Title "Standard Portgroup Info" -AppendWorksheet -SheetPosition "end" | |
} | |
# Get Distributed Portgroup Information | |
$dvPortInfo = @() | |
$dvPortGroups = Get-VDPortgroup -Server $ESX | |
Foreach ($dvPortGroup in $dvPortGroups) { | |
$dvPortProp = [ordered]@{} | |
$dvPortProp."Virtual Switch" = $dvPortGroup.VDSwitch | |
$dvPortProp.Portgroup = $dvPortGroup.Name | |
$dvPortProp."Port Binding" = $dvPortGroup.PortBinding | |
$dvPortProp."Overall Status" = $dvPortGroup.ExtensionData.OverallStatus | |
$dvPortProp."Config Status" = $dvPortGroup.ExtensionData.ConfigStatus | |
$dvPortProp.Note = "vCenter needed for further info" | |
$dvPortTemp = New-Object –TypeName PSObject –Prop $dvPortProp | |
$dvPortInfo += $dvPortTemp | |
} | |
If ($dvPortInfo) { | |
$dvPortInfo | Sort "Virtual Switch", Portgroup | Export-Xlsx -Path $FullPath -WorksheetName "Distributed Portgroup Info" -Title "Distributed Portgroup Info" -AppendWorksheet -SheetPosition "end" | |
} | |
# Get Firewall Exceptions | |
$fwInfo = @() | |
Try { | |
$fwExceptions = $VMHost | Get-VMHostFirewallException -ErrorAction Stop | |
Foreach ($fwException in $fwExceptions) { | |
$fwProp = [ordered]@{} | |
$fwProp.Enabled = $fwException.Enabled | |
$fwProp.Name = $fwException.Name | |
$fwProp."Incoming Ports" = $fwException.IncomingPorts | |
$fwProp."Outgoing Ports" = $fwException.OutgoingPorts | |
$fwProp."Protocol(s)" = $fwException.Protocols | |
$fwProp."Allow all IPs" = $fwException.ExtensionData.AllowedHosts.AllIp | |
$fwProp.Service = $fwException.ExtensionData.Service | |
$fwProp."Service Running" = $fwException.ServiceRunning | |
$fwTemp = New-Object –TypeName PSObject –Prop $fwProp | |
$fwInfo += $fwTemp | |
} | |
} Catch {} | |
If ($fwInfo) { | |
$fwInfo | Sort Enabled, Name | Export-Xlsx -Path $FullPath -WorksheetName "Firewall Exceptions" -Title "Firewall Exceptions" -AppendWorksheet -SheetPosition "end" | |
} | |
# Get Services Information | |
$svcInfo = @() | |
$services = $VMHost | Get-VMHostService | |
Foreach ($service in $services) { | |
$svcProp = [ordered]@{} | |
$svcProp.Service = $service.Label | |
$svcProp.Key = $service.Key | |
$svcProp.Running = $service.Running | |
switch ($service.Policy) | |
{ | |
"on" {$svcProp."Startup Policy" = "Start and stop with host"} | |
"off" {$svcProp."Startup Policy" = "Start and stop manually"} | |
"automatic" {$svcProp."Startup Policy" = "Start and stop with port usage"} | |
default {$svcProp."Startup Policy" = "Unknown"} | |
} | |
$svcProp.Required = $service.Required | |
$svcProp.Uninstallable = $service.Uninstallable | |
$svcProp."Source Package" = $service.ExtensionData.SourcePackage.SourcePackageName | |
$svcProp."Source Package Desc" = $service.ExtensionData.SourcePackage.Description | |
$svcTemp = New-Object –TypeName PSObject –Prop $svcProp | |
$svcInfo += $svcTemp | |
} | |
If ($svcInfo) { | |
$svcInfo | Sort Service | Export-Xlsx -Path $FullPath -WorksheetName "Services Info" -Title "Services Info" -AppendWorksheet -SheetPosition "end" | |
} | |
# Get SNMP Info | |
$snmpInfo = @() | |
$snmpDetails = Get-VMHostSnmp -Server $ESX | |
$snmpProp = [ordered]@{} | |
$snmpProp.Enabled = $snmpDetails.Enabled | |
$snmpProp.Port = $snmpDetails.Port | |
$snmpProp."Read Only Communities" = $snmpDetails.ReadOnlyCommunities | Out-String | |
$snmpProp."Trap Targets" = $snmpDetails.TrapTargets | Out-String | |
$snmpTemp = New-Object –TypeName PSObject –Prop $snmpProp | |
$snmpInfo += $snmpTemp | |
If ($snmpInfo) { | |
$snmpInfo | Export-Xlsx -Path $FullPath -WorksheetName "SNMP Info" -Title "SNMP Info" -AppendWorksheet -SheetPosition "end" | |
} | |
# Get Installed ESX(i) Patches | |
$patchInfo = @() | |
Try { | |
$patches = (Get-EsxCli).software.vib.list() | |
ForEach ($patch in $patches) { | |
$patchProp = [ordered]@{} | |
$patchProp.Name = $patch.Name | |
$patchProp.ID = $patch.ID | |
$patchProp.Vendor = $patch.Vendor | |
$patchProp.Version = $patch.Version | |
$patchProp."Acceptance Level" = $patch.AcceptanceLevel | |
$patchProp."Created Date" = $patch.CreationDate | |
$patchProp."Install Date" = $patch.InstallDate | |
$patchProp.Status = $patch.Status | |
$patchTemp = New-Object –TypeName PSObject –Prop $patchProp | |
$patchInfo += $patchTemp | |
} | |
} Catch { | |
$patches = $VMHost | Get-VMHostPatch | |
ForEach ($patch in $patches) { | |
$patchProp = [ordered]@{} | |
$patchProp.Name = $patch.Description | |
$patchProp.ID = $patch.ID | |
$patchProp."Install Date" = $patch.InstallDate | |
$patchTemp = New-Object –TypeName PSObject –Prop $patchProp | |
$patchInfo += $patchTemp | |
} | |
} | |
If ($patchInfo) { | |
$patchInfo | Sort "Install Date" -Descending | Export-Xlsx -Path $FullPath -WorksheetName "Patch Info" -Title "Patch Info" -AppendWorksheet -SheetPosition "end" | |
} | |
# Get Local Users | |
$accountInfo = @() | |
$accounts = Get-VMHostAccount -Server $ESX | |
ForEach ($account in $accounts) { | |
$accountProp = [ordered]@{} | |
$accountProp.Name = $account.Name | |
$accountProp.Description = $account.Description | |
$accountProp.ShellAccess = $account.ShellAccessEnabled | |
$accountProp.Groups = $account.Groups | Out-String | |
$accountTemp = New-Object –TypeName PSObject –Prop $accountProp | |
$accountInfo += $accountTemp | |
} | |
If ($accountInfo) { | |
$accountInfo | Sort IsSystem, Name | Export-Xlsx -Path $FullPath -WorksheetName "Local Users" -Title "Local Users" -AppendWorksheet -SheetPosition "end" | |
} | |
# Get Local Groups | |
$grpInfo = @() | |
Try { | |
$grps = Get-VMHostAccount -Server $ESX -Group -ErrorAction Stop | |
ForEach ($grp in $grps) { | |
$grpProp = [ordered]@{} | |
$grpProp.Name = $grp.Name | |
$grpProp.Description = $grp.Description | |
$grpProp.Users = $grp.Users | Out-String | |
$grpTemp = New-Object –TypeName PSObject –Prop $grpProp | |
$grpInfo += $grpTemp | |
} | |
} Catch {} | |
If ($grpInfo) { | |
$grpInfo | Sort Name | Export-Xlsx -Path $FullPath -WorksheetName "Local Groups" -Title "Local Groups" -AppendWorksheet -SheetPosition "end" | |
} | |
# Get VI Roles | |
$roleInfo = @() | |
$roles = Get-VIRole -Server $ESX | |
ForEach ($role in $roles) { | |
$roleProp = [ordered]@{} | |
$roleProp.Name = $role.Name | |
$roleProp.Description = $role.Description | |
$roleProp.IsSystem = $role.IsSystem | |
$roleProp.Privileges = $role.PrivilegeList | Out-String | |
$roleTemp = New-Object –TypeName PSObject –Prop $roleProp | |
$roleInfo += $roleTemp | |
} | |
If ($roleInfo) { | |
$roleInfo | Sort IsSystem, Name | Export-Xlsx -Path $FullPath -WorksheetName "VI Roles" -Title "VI Roles" -AppendWorksheet -SheetPosition "end" | |
} | |
# Get Permissions | |
$permInfo = @() | |
$perms = Get-VIPermission -Server $ESX | |
ForEach ($perm in $perms) { | |
$permProp = [ordered]@{} | |
$permProp.Entity = $perm.Entity | |
$permProp.Role = $perm.Role | |
$permProp.Principal = $perm.Principal | |
$permProp.IsGroup = $perm.IsGroup | |
$permProp.Propagate = $perm.Propagate | |
$permTemp = New-Object –TypeName PSObject –Prop $permProp | |
$permInfo += $permTemp | |
} | |
If ($permInfo) { | |
$permInfo | Sort Entity, Principal | Export-Xlsx -Path $FullPath -WorksheetName "Permissions" -Title "Permissions" -AppendWorksheet -SheetPosition "end" | |
} | |
# Get VM Info | |
$vmInfo = @() | |
$vms = $VMHost | Get-VM | |
ForEach ($vm in $vms) { | |
$vmProp = [ordered]@{} | |
$vmProp.Name = $vm.Name | |
$vmProp.State = $vm.PowerState | |
$vmProp.FullName = If (!$VM.Guest.hostname) {"Tools Not Running\Unknown"} Else {$VM.Guest.hostname} | |
$vmProp.GuestOS = If (!$VM.Guest.OSFullName) {"Tools Not Running\Unknown"} Else {$VM.Guest.OSFullName} | |
$vmProp.IP = If (!$VM.Guest.IPAddress[0]) {"Tools Not Running\Unknown"} Else {$VM.Guest.IPAddress[0]} | |
$vmProp.NumCPU = $vm.NumCPU | |
[int]$vmProp."Memory (GB)" = $vm.MemoryGB | |
$vmProp."Disk (GB)" = [Math]::Round((($vm.HardDisks | Measure-Object -Property CapacityKB -Sum).Sum * 1KB / 1GB),2) | |
$vmProp."DiskFree (GB)" = If (![Math]::Round((($vm.Guest.Disks | Measure-Object -Property FreeSpace -Sum).Sum / 1GB),2)) ` | |
{"Tools Not Running\Unknown"} Else {[Math]::Round((($vm.Guest.Disks | Measure-Object -Property FreeSpace -Sum).Sum / 1GB),2)} | |
$vmProp."DiskUsed (GB)" = If ($vmProp."DiskFree (GB)" -eq "Tools Not Running\Unknown") ` | |
{"Tools Not Running\Unknown"} Else {$vmProp."Disk (GB)" - $vmProp."DiskFree (GB)"} | |
$vmProp.Notes = $VM.Notes | |
$vmTemp = New-Object –TypeName PSObject –Prop $vmProp | |
$vmInfo += $vmTemp | |
} | |
If ($vmInfo) { | |
$vmInfo | Sort Created -Descending | Export-Xlsx -Path $FullPath -WorksheetName "VM Info" -Title "VM Info" -AppendWorksheet -SheetPosition "end" | |
} | |
# Get VM Snapshots | |
$snapInfo = @() | |
$snaps = $VMHost | Get-VM | Get-Snapshot | |
ForEach ($snap in $snaps) { | |
$snapProp = [ordered]@{} | |
$snapProp.VM = $snap.VM | |
$snapProp.Name = $snap.Name | |
$snapProp.Description = $snap.Description | |
$snapProp.Created = $snap.Created | |
$snapProp."Size (GB)" = [Math]::Round($snap.SizeGB,2) | |
$snapProp.IsCurrent = $snap.IsCurrent | |
$snapTemp = New-Object –TypeName PSObject –Prop $snapProp | |
$snapInfo += $snapTemp | |
} | |
If ($snapInfo) { | |
$snapInfo | Sort Created -Descending | Export-Xlsx -Path $FullPath -WorksheetName "Snapshot Info" -Title "Snapshot Info" -AppendWorksheet -SheetPosition "end" | |
} | |
Disconnect-VIServer $ESX -Confirm:$false | |
Write-Host "$ESX Report Complete - $FullPath" | |
} Else { | |
Write-Host "Unable to connect to $ESX" -ForegroundColor Red | |
} | |
} |
Thank You!! This is very much appreciated.
If anybody runs into an error that goes;
+ #Requires â?”Version 3
+ ~~~~~~~~~~
The string is missing the terminator: “.
At .\Get-VMHostInfo.ps1:1 char:11
+ #Requires â?”Version 3
+ ~~~~~~~~~~~~
It’s because your editor is using an HTML “-“symbol (&ndash) instead of what you were expecting. Type another dash next to it and see the tiny little difference: – –
55 of them, to be precise.
Hi,
Im getting following error, could you please help me out of here?
Cannot find an overload for “Round” and the argument count: “2”.
At D:\Get-VMHostInfo.ps1:518 char:3
+ $VMHostProp.”Memory (GB)” = [Math]::Round($VMHost.MemoryTotalGB,0)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodException
+ FullyQualifiedErrorId : MethodCountCouldNotFindBest
Thank you