Exporting ESX/ESXi Host Information to Excel

hostinfoFor 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
}
}

 

 

4 thoughts on “Exporting ESX/ESXi Host Information to Excel

  1. Little Jim

    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: – –

    Reply
  2. IvanS

    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

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *