Hi All,
I've created the below to generate a report containing End of Life / End of Support information for approx 2000 ESXi Hosts, spread across multiple vCenters.
The report works to a point. I've just noticed that it's returning the same Serial numbers for a lot of the ESXi Hosts, these should all be unique. I've also noticed that the model numbers are not always correct either. If i run the script against individual ESXi Hosts, the data returned is correct.
The script runs without error so i don't understand why duplicate/incorrect information is being returned for some of the Servers.
Could it be that i don't have enough memory/cpu on the server that's running the script ?
Should i be using Get-View instead of Get-Esxcli to optimize the data collection ?
Should i be setting each variable to null before moving to the next ESXi Host (seems wasteful)
$cred = Get-Credential 'username@company.com'
$vCenters = @(
"vc1.company.com"
"vc2.company.com"
"vc3.company.com"
"vc4.company.com"
)
Connect-VIServer -Server $vCenters -Credential $cred -ErrorAction SilentlyContinue
# Server model to EOL date mappings, edit to add/correct dates
$vmHostModelEolMapping = @{
"UCS-C210" = "2020/Jun"
"UCS-C220" = "2020/Jun"
"UCS-C240" = "2018/Aug"
"UCS-C420" = "2017/Jan"
"PowerEdge R630" = "2018/May"
"PowerEdge R710" = "2016/May"
"PowerEdge R730xd" = "2018/May"
"PowerEdge R900" = "2015/Jul"
"PowerEdge R910" = "2015/Mar"
}
# Collect Server details
$results = @()
foreach ($vmHost in Get-VMHost) {
$esxcli = Get-EsxCli -vmhost $vmHost.name -V2 -ErrorAction SilentlyContinue
$vcName = [System.Net.Dns]::GetHostEntry((get-view $vmHost -ErrorAction SilentlyContinue).summary.managementserverip).HostName
$vmHostName = $vmHost.Name
$vmHostVendor = $esxcli.hardware.platform.get.invoke().VendorName
$vmHostModel = $esxcli.hardware.platform.get.invoke().ProductName
$vmHostSerial = $esxcli.hardware.platform.get.invoke().SerialNumber
$EolDate = "Unknown"
if ($vmHostModelEolMapping.ContainsKey($vmHostModel)){
$EolDate = $vmHostModelEolMapping[$vmHostModel]
}
$prop = [pscustomobject] @{
vCenter = $vcName
"ESXi Host Name" = $vmHostName
Vendor = $vmHostVendor
Model = $vmHostModel
Serial = $vmHostSerial
EOL = $EolDate
}
$results+=$prop
}
$results | Sort-Object vCenter,"ESXi Host Name" | Export-Csv -path c:\Temp\EOLreport.csv
When the Get-EsxCli for one or another reason fails, the script will continue with the values of the previous iteration in the loop.
Perhaps this try-catch construct could avoid that
$vCenters = @(
"vc1.company.com"
"vc2.company.com"
"vc3.company.com"
"vc4.company.com"
)
Connect-VIServer -Server $vCenters -Credential $cred -ErrorAction SilentlyContinue
# Server model to EOL date mappings, edit to add/correct dates
$vmHostModelEolMapping = @{
"UCS-C210" = "2020/Jun"
"UCS-C220" = "2020/Jun"
"UCS-C240" = "2018/Aug"
"UCS-C420" = "2017/Jan"
"PowerEdge R630" = "2018/May"
"PowerEdge R710" = "2016/May"
"PowerEdge R730xd" = "2018/May"
"PowerEdge R900" = "2015/Jul"
"PowerEdge R910" = "2015/Mar"
}
# Collect Server details
$results = @()
foreach ($vmHost in Get-VMHost) {
$vcName = [System.Net.Dns]::GetHostEntry((Get-View $vmHost -ErrorAction SilentlyContinue).summary.managementserverip).HostName
$vmHostName = $vmHost.Name
$EolDate = "Unknown"
$vmHostVendor = ''
$vmHostModel = ''
$vmHostSerial = ''
try {
$esxcli = Get-EsxCli -vmhost $vmHost -V2 -ErrorAction Stop
$vmHostVendor = $esxcli.hardware.platform.get.invoke().VendorName
$vmHostModel = $esxcli.hardware.platform.get.invoke().ProductName
$vmHostSerial = $esxcli.hardware.platform.get.invoke().SerialNumber
if ($vmHostModelEolMapping.ContainsKey($vmHostModel)) {
$EolDate = $vmHostModelEolMapping[$vmHostModel]
}
}
catch {
Write-Host -ForegroundColor red "Get-EsxCli failed for $($vmHost.Name)"
}
$prop = [pscustomobject] @{
vCenter = $vcName
"ESXi Host Name" = $vmHostName
Vendor = $vmHostVendor
Model = $vmHostModel
Serial = $vmHostSerial
EOL = $EolDate
}
$results += $prop
}
$results | Sort-Object vCenter, "ESXi Host Name" | Export-Csv -path c:\Temp\EOLreport.csv
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
When the Get-EsxCli for one or another reason fails, the script will continue with the values of the previous iteration in the loop.
Perhaps this try-catch construct could avoid that
$vCenters = @(
"vc1.company.com"
"vc2.company.com"
"vc3.company.com"
"vc4.company.com"
)
Connect-VIServer -Server $vCenters -Credential $cred -ErrorAction SilentlyContinue
# Server model to EOL date mappings, edit to add/correct dates
$vmHostModelEolMapping = @{
"UCS-C210" = "2020/Jun"
"UCS-C220" = "2020/Jun"
"UCS-C240" = "2018/Aug"
"UCS-C420" = "2017/Jan"
"PowerEdge R630" = "2018/May"
"PowerEdge R710" = "2016/May"
"PowerEdge R730xd" = "2018/May"
"PowerEdge R900" = "2015/Jul"
"PowerEdge R910" = "2015/Mar"
}
# Collect Server details
$results = @()
foreach ($vmHost in Get-VMHost) {
$vcName = [System.Net.Dns]::GetHostEntry((Get-View $vmHost -ErrorAction SilentlyContinue).summary.managementserverip).HostName
$vmHostName = $vmHost.Name
$EolDate = "Unknown"
$vmHostVendor = ''
$vmHostModel = ''
$vmHostSerial = ''
try {
$esxcli = Get-EsxCli -vmhost $vmHost -V2 -ErrorAction Stop
$vmHostVendor = $esxcli.hardware.platform.get.invoke().VendorName
$vmHostModel = $esxcli.hardware.platform.get.invoke().ProductName
$vmHostSerial = $esxcli.hardware.platform.get.invoke().SerialNumber
if ($vmHostModelEolMapping.ContainsKey($vmHostModel)) {
$EolDate = $vmHostModelEolMapping[$vmHostModel]
}
}
catch {
Write-Host -ForegroundColor red "Get-EsxCli failed for $($vmHost.Name)"
}
$prop = [pscustomobject] @{
vCenter = $vcName
"ESXi Host Name" = $vmHostName
Vendor = $vmHostVendor
Model = $vmHostModel
Serial = $vmHostSerial
EOL = $EolDate
}
$results += $prop
}
$results | Sort-Object vCenter, "ESXi Host Name" | Export-Csv -path c:\Temp\EOLreport.csv
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
LucD,
I ran the script but its shows blanks for all the host with error for each host
| Model | Serial | EOL |
| Unknown | ||
| Unknown | ||
| Unknown | ||
| Unknown | ||
| Unknown | ||
| Unknown | ||
| Unknown | ||
| Unknown | ||
| Unknown | ||
| Unknown | ||
| Unknown | ||
| Unknown | ||
| Unknown |
There was a typo in the Get-EsxCli line.
I corrected the code above, give it another try.
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Ok, LucD,
This time serial/Model is showing but EOL is unknown status...
| Vendor | Model | EOL |
| Cisco Systems Inc | UCSB-EX-M4-1 | Unknown |
| Cisco Systems Inc | UCSB-EX-M4-1 | Unknown |
| Cisco Systems Inc | UCSB-EX-M4-1 | Unknown |
| Cisco Systems Inc | UCSB-EX-M4-1 | Unknown |
| Cisco Systems Inc | UCSB-EX-M4-1 | Unknown |
| Cisco Systems Inc | UCSB-EX-M4-1 | Unknown |
| Cisco Systems Inc | UCSB-EX-M4-1 | Unknown |
| Cisco Systems Inc | UCSB-EX-M4-1 | Unknown |
| Cisco Systems Inc | UCSB-EX-M4-1 | Unknown |
| Cisco Systems Inc | UCSB-EX-M4-1 | Unknown |
| Cisco Systems Inc | UCSB-EX-M4-1 | Unknown |
| Cisco Systems Inc | UCSB-B200-M4 | Unknown |
| Cisco Systems Inc | UCSB-B200-M4 | Unknown |
| Cisco Systems Inc | UCSB-B200-M4 | Unknown |
| Cisco Systems Inc | UCSB-B200-M4 | Unknown |
| Cisco Systems Inc | UCSB-B200-M4 | Unknown |
| Cisco Systems Inc | UCSB-B200-M4 | Unknown |
| Cisco Systems Inc | UCSB-B200-M4 | Unknown |
| Cisco Systems Inc | UCSB-B200-M4 | Unknown |
| Cisco Systems Inc | UCSB-B200-M4 | Unknown |
| Cisco Systems Inc | UCSB-B200-M4 | Unknown |
| Cisco Systems Inc | UCSB-B200-M4 | Unknown |
| Cisco Systems Inc | UCSB-B200-M4 | Unknown |
| Cisco Systems Inc | UCSB-B200-M4 | Unknown |
| Cisco Systems Inc | UCSB-B200-M4 | Unknown |
| Cisco Systems Inc | UCSB-B200-M4 | Unknown |
| Cisco Systems Inc | UCSB-B200-M4 | Unknown |
| Cisco Systems Inc | UCSB-B200-M4 | Unknown |
| Cisco Systems Inc | UCSB-B200-M4 | Unknown |
| Cisco Systems Inc | UCSB-B200-M4 | Unknown |
| Cisco Systems Inc | UCSB-B200-M4 | Unknown |
| Cisco Systems Inc | UCSB-B200-M4 | Unknown |
| Cisco Systems Inc | UCSC-C220-M4S | Unknown |
| Cisco Systems Inc | UCSC-C220-M4S | Unknown |
| Cisco Systems Inc | UCSC-C220-M4S | Unknown |
| Cisco Systems Inc | UCSC-C220-M4S | Unknown |
thanks
V
The names listed under Model are not present in the $vmHostModelEolMapping hash table.
So the 'Unknown' seems to be correct
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Thanks Luc, that worked as expected.
After your first suggestion i got a lot of blank information back but quickly spotted the typo and once corrected it worked perfectly, thanks.
To anyone who wants to use this, run it first to get back the server model details as, this information is detailed on the Host, e.g. you may be using Cisco UCS C210's but, this report identifies these as R210-2121605W .
When you have all your Server models, google the EOL date and edit the $vmHostModelEolMapping hash table to match your servers.
I've re-worked this to make it a bit more user friendly :smileygrin:
The script can take a long time to run, depending on quantity of VC's and Hosts so i've also added a progress bar.
If anyone thinks this can be optimized in any way, please feel free to post comments
# login to vCenter(s) - use CTRL to select multiple vCenters
$cred = Get-Credential -Message " *********** Enter vCenter Credentials ***********"
$vCenters = @(
"vc1.company.com"
"vc2.company.com"
"vc3.company.com"
"vc4.company.com"
"vc5.company.com"
)
$selectedVC = $vCenters | Out-GridView -Title " *** vCenter Listing - Select required vCenter(s) ***" -OutputMode Multiple
Connect-VIServer -Server $selectedVC -Credential $cred -ErrorAction SilentlyContinue
# Server model to EOL date mappings, edit to add/correct dates
$vmHostModelEolMapping = @{
# Cisco Servers
"B230-BASE-M2" = "2020/Jun"
"C260-BASE-2646" = "2020/Jun"
"UCSB-B200-M4" = "2024/Feb"
"UCSC-BASE-M2-C460" = "2020/Apr"
# Dell Servers
"PowerEdge R630" = "2018/May"
"PowerEdge R640" = " "
"PowerEdge R710" = "2016/May"
# VxRails
"VxRail E460" = "2023/05"
"VxRail P570F"= " "
}
# Status Bar Variables
$vmHosts = Get-VMHost
$count = $vmHosts.count
$i = 1
# Collect Server details
$results = @()
foreach ($vmHost in $vmHosts) {
Write-Progress -Activity "Generating Server End Of Life Report" -Status "Getting info on $vmHost" -PercentComplete (($i*100)/$count)
$vcName = [System.Net.Dns]::GetHostEntry((Get-View $vmHost -ErrorAction SilentlyContinue).summary.managementserverip).HostName
$vmHostName = $vmHost.Name
$EolDate = "Unknown"
$vmHostVendor = ''
$vmHostModel = ''
$vmHostSerial = ''
try {
$esxcli = $null
$esxcli = Get-EsxCli -vmhost $vmHost -V2 -ErrorAction Stop
$vmHostVendor = $esxcli.hardware.platform.get.invoke().VendorName
$vmHostModel = $esxcli.hardware.platform.get.invoke().ProductName
$vmHostSerial = $esxcli.hardware.platform.get.invoke().SerialNumber
if ($vmHostModelEolMapping.ContainsKey($vmHostModel)) {
$EolDate = $vmHostModelEolMapping[$vmHostModel]
}
}
catch {
Write-Host -ForegroundColor red "Get-EsxCli failed for $($vmHost.Name)"
}
$prop = [pscustomobject] @{
vCenter = $vcName
"ESXi Host Name" = $vmHostName
Vendor = $vmHostVendor
Model = $vmHostModel
Serial = $vmHostSerial
EOL = $EolDate
}
$i++
$results += $prop
}
<#
requirement: ImportExcel module
Verify that ImportExcel is installed with 'Get-Module -ListAvailable ImportExcel'
If not installed, install with 'Find-Module ImportExcel | Install-Module'
Get available commands with 'Get-Command -Module ImportExcel'
#>
If (!(Get-module -ListAvailable "ImportExcel")) {
Find-Module -Name ImportExcel | Install-Module
}
$ContainsBlanks = New-ConditionalText -ConditionalType ContainsBlanks
$hash = @{
Path = "C:\Temp\EOLreport.xlsx"
Show = $true;
AutoSize = $true;
AutoFilter = $true;
ConditionalText = $ContainsBlanks
ShowPercent = $true;
#PivotTableName = "ESXi Version Detail";
#IncludePivotTable = $true;
#PivotRows = 'Version';
#PivotData = @{'Version' = 'Count'};
#IncludePivotChart = $true;
#ChartType = "PieExploded";
HideSheet = "Sheet1";
}
Remove-Item $hash.Path -ErrorAction Ignore
$results | Sort-Object vCenter,"ESXi Host Name" | Export-Excel @hash
Great, thanks for sharing that.
While playing with the script, I think there might be some performance improvements possible.
By using Foreach-Object and a Pipelinevariable, everything can be set up in a pipeline construct.
No need to have a $results variable.
The following also only uses 1 $esxcli method call, instead of three.
The If-Then for the EOL can also be eliminated.
If the Model is not in the hash table, it will return $null. Since the -replace operator can use a RegEx, we test for an empty string () with "^$") and replace it with 'Unknown'.
These are not corrections, just some suggestions :smileygrin:
$cred = Get-Credential -Message " *********** Enter vCenter Credentials ***********"
$vCenters = @(
"vc1.company.com"
"vc2.company.com"
"vc3.company.com"
"vc4.company.com"
"vc5.company.com"
)
$selectedVC = $vCenters | Out-GridView -Title " *** vCenter Listing - Select required vCenter(s) ***" -OutputMode Multiple
Connect-VIServer -Server $selectedVC -Credential $cred -ErrorAction SilentlyContinue
# Server model to EOL date mappings, edit to add/correct dates
$vmHostModelEolMapping = @{
# Cisco Servers
"B230-BASE-M2" = "2020/Jun"
"C260-BASE-2646" = "2020/Jun"
"UCSB-B200-M4" = "2024/Feb"
"UCSC-BASE-M2-C460" = "2020/Apr"
# Dell Servers
"PowerEdge R630" = "2018/May"
"PowerEdge R640" = " "
"PowerEdge R710" = "2016/May"
# VxRails
"VxRail E460" = "2023/05"
"VxRail P570F" = " "
}
If (!(Get-Module -ListAvailable "ImportExcel")) {
Find-Module -Name ImportExcel | Install-Module
}
$ContainsBlanks = New-ConditionalText -ConditionalType ContainsBlanks
$hash = @{
Path = "C:\Temp\EOLreport.xlsx"
Show = $true;
AutoSize = $true;
AutoFilter = $true;
ConditionalText = $ContainsBlanks
ShowPercent = $true;
#PivotTableName = "ESXi Version Detail";
#IncludePivotTable = $true;
#PivotRows = 'Version';
#PivotData = @{'Version' = 'Count'};
#IncludePivotChart = $true;
#ChartType = "PieExploded";
HideSheet = "Sheet1";
}
Remove-Item $hash.Path -ErrorAction Ignore
Get-VMHost -PipelineVariable vmhost |
ForEach-Object -Process {
try {
$esxcli = Get-EsxCli -vmhost $vmHost -V2 -ErrorAction Stop
$platform = $esxcli.hardware.platform.get.invoke()
}
catch {
Write-Host -ForegroundColor red "Get-EsxCli failed for $($vmHost.Name)"
}
[pscustomobject] @{
vCenter = [System.Net.Dns]::GetHostEntry((Get-View $vmHost -ErrorAction SilentlyContinue).summary.managementserverip).HostName
"ESXi Host Name" = $vmHost.Name
Vendor = $platform.VendorName
Model = $platform.ProductName
Serial = $platform.SerialNumber
EOL = $vmHostModelEolMapping[$platform.ProductName] -replace "^$", 'Unknown'
}
} | Sort-Object vCenter, "ESXi Host Name" | Export-Excel @hash
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
LucD,
I tried to excute but it shows an error and it never proceed further in console.
Name Port User
---- ---- ----
vc1.sg.con... 443 SGC\vk1
Install-Module : Administrator rights are required to install modules in 'C:\Program Files\WindowsPowerShell\Modules'.
Log on to the computer with an account that has Administrator rights, and then try again, or install
'D:\Users\vk1\Documents\WindowsPowerShell\Modules' by adding "-Scope CurrentUser" to your command. You can
also try running the Windows PowerShell session with elevated rights (Run as Administrator).
At D:\vk1\ESXHost-EOL.ps1:63 char:37
+ Find-Module -Name ImportExcel | Install-Module
+ ~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Install-Module], ArgumentException
+ FullyQualifiedErrorId : InstallModuleNeedsCurrentUserScopeParameterForNonAdminUser,Install-Module
New-ConditionalText : The term 'New-ConditionalText' is not recognized as the name of a cmdlet, function, script file,
or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and
try again.
At D:\vk1\ESXHost-EOL.ps1:68 char:19
+ $ContainsBlanks = New-ConditionalText -ConditionalType ContainsBlanks
+ ~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (New-ConditionalText:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
Get-EsxCli failed for ESX2.host.com
thanks
V
To install a module for All Users, you have to start your PowerShell sessions 'As Administrator'.
The alternative is to install the module for the CurrentUser (the -Scope CurrentUser mentioned in the error).
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Ok, i did run as Administrator but it ended with blank report. EOLreport.csv = 0 KB
thanks
V
My bad, I didn't place the object in the pipeline.
I corrected the code above
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Ok, i did run the script,
Get-VMHost : 1/30/2020 7:43:34 PM Get-VMHost Sequence contains more than one matching eleme
t D:\vmk\ESXHost-EOL.ps1:110 char:1
Get-VMHost -PipelineVariable vmhost |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Get-VMHost], VimException
+ FullyQualifiedErrorId : Core_BaseCmdlet_UnknownError,VMware.VimAutomation.ViCore.Cmdlets.Commands.GetVMH
xception calling "GetHostEntry" with "1" argument(s): "No such host is known"
t D:\vmk\ESXHost-EOL.ps1:130 char:5
[pscustomobject] @{
~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : SocketException
xception calling "GetHostEntry" with "1" argument(s): "No such host is known"
t D:\vmk\ESXHost-EOL.ps1:130 char:5
[pscustomobject] @{
~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : SocketException
xception calling "GetHostEntry" with "1" argument(s): "No such host is known"
t D:\vmk\ESXHost-EOL.ps1:130 char:5
Get-EsxCli failed for Host2.com
thanks
V
Not sure what is happening there, must be something in your script.
Also confused by the line numbers in the errors.
Line 110?
What else is in that .ps1 file?
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Thanks Luc,
Those optimizations are great, really helpful.
One question with them though. Previously i was using a count of the Hosts to generate a status bar
# Status Bar Variables
$vmHosts = Get-VMHost
$count = $vmHosts.count
$i = 1
# Collect Server details
$results = @()
foreach ($vmHost in $vmHosts) {
Write-Progress -Activity "Generating Server End Of Life Report" -Status "Getting info on $vmHost" -PercentComplete (($i*100)/$count)
Using a pipeline variable, how do i now count the total Hosts ?
Should i do something like
$vmHosts = Get-VMHost
$count = $vmHosts.count
$i = 1
Get-VMHost -PipelineVariable $vmhosts |
ForEach-Object -Process {
I would avoid doing the Get-VMHost twice.
As a skeleton, something like this
$i = 1
$vmHostAll | ForEach-Object -PipelineVariable vmhost -Process {
Write-Progress -PercentComplete ($i/$vmhostAll.Count*100) -Activity 'In loop'
$i++
}
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Getting an error (and looks like i don't fully understand your optimizations)
$vmHostAll = Get-VMHost
= 1
| ForEach-Object -PipelineVariable vmhost -Process {
Write-Progress -PercentComplete ($i/$vmHostAll.count*100) -Activity "Generating Server End Of Life Report" -Status "Getting info on $vmHost"
$i++
try {
$esxcli = Get-EsxCli -vmhost $vmHost -V2 -ErrorAction Stop
$platform = $esxcli.hardware.platform.get.invoke()
catch {
Write-Host -ForegroundColor red "Get-EsxCli failed for $($vmHost.Name)"
the above returns
Get-EsxCli failed for
Get-View : Cannot validate argument on parameter 'VIObject'. The argument is null or empty. Provide an argument that is not null or empty, and then try the command again.
At line:135 char:69
+ ... r = [System.Net.Dns]::GetHostEntry((Get-View $vmHost -ErrorA ...
+ ~~~~~~~
+ CategoryInfo : InvalidData: (:) [Get-View], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,VMware.VimAutomation.ViCore.Cmdlets.Commands.DotNetInterop.GetVIView
Not sure where that Get-View is coming from.
In any case, this is the complete script with the Write-Progress.
$cred = Get-Credential -Message " *********** Enter vCenter Credentials ***********"
$vCenters = @(
"vc1.company.com"
"vc2.company.com"
"vc3.company.com"
"vc4.company.com"
"vc5.company.com"
)
$selectedVC = $vCenters | Out-GridView -Title " *** vCenter Listing - Select required vCenter(s) ***" -OutputMode Multiple
Connect-VIServer -Server $selectedVC -Credential $cred -ErrorAction SilentlyContinue
# Server model to EOL date mappings, edit to add/correct dates
$vmHostModelEolMapping = @{
# Cisco Servers
"B230-BASE-M2" = "2020/Jun"
"C260-BASE-2646" = "2020/Jun"
"UCSB-B200-M4" = "2024/Feb"
"UCSC-BASE-M2-C460" = "2020/Apr"
# Dell Servers
"PowerEdge R630" = "2018/May"
"PowerEdge R640" = " "
"PowerEdge R710" = "2016/May"
# VxRails
"VxRail E460" = "2023/05"
"VxRail P570F" = " "
}
If (!(Get-Module -ListAvailable "ImportExcel")) {
Find-Module -Name ImportExcel | Install-Module
}
ContainsBlanks = New-ConditionalText -ConditionalType ContainsBlanks
$hash = @{
Path = "C:\Temp\EOLreport.xlsx"
Show = $true;
AutoSize = $true;
AutoFilter = $true;
ConditionalText = $ContainsBlanks
ShowPercent = $true;
#PivotTableName = "ESXi Version Detail";
#IncludePivotTable = $true;
#PivotRows = 'Version';
#PivotData = @{'Version' = 'Count'};
#IncludePivotChart = $true;
#ChartType = "PieExploded";
HideSheet = "Sheet1";
}
Remove-Item $hash.Path -ErrorAction Ignore
$vmHostAll = Get-VMHost
$i = 1
$vmHostAll | ForEach-Object -PipelineVariable vmhost -Process {
Write-Progress -PercentComplete ($i / $vmHostAll.count * 100) -Activity "Generating Server End Of Life Report" -Status "Getting info on $vmHost"
$i++
try {
$esxcli = Get-EsxCli -vmhost $vmHost -V2 -ErrorAction Stop
$platform = $esxcli.hardware.platform.get.invoke()
}
catch {
Write-Host -ForegroundColor red "Get-EsxCli failed for $($vmHost.Name)"
}
[pscustomobject] @{
vCenter = [System.Net.Dns]::GetHostEntry((Get-View $vmHost -ErrorAction SilentlyContinue).summary.managementserverip).HostName
"ESXi Host Name" = $vmHost.Name
Vendor = $platform.VendorName
Model = $platform.ProductName
Serial = $platform.SerialNumber
EOL = $vmHostModelEolMapping[$platform.ProductName] -replace "^$", 'Unknown'
}
} | Sort-Object vCenter, "ESXi Host Name" | Export-Excel @hash
Blog: lucd.info Twitter: @LucD22 Co-author PowerCLI Reference
Thanks Luc,
Running your last iteration of the code, i was still getting errors. Through a process of trial and error i spotted that the when using $vmhost variable,the following calls were failing
Get-EsxCli failed for
Get-View : Cannot validate argument on parameter 'VIObject'. The argument is null or empty. Provide an argument that is not null or empty, and then try the command again.
At line:138 char:69
+ ... r = [System.Net.Dns]::GetHostEntry((Get-View $vmHost -ErrorA ...
+ ~~~~~~~
+ CategoryInfo : InvalidData: (:) [Get-View], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,VMware.VimAutomation.ViCore.Cmdlets.Commands.DotNetInterop.GetVIView
I changed the code to the below (replacing the $vmhost with $_ in the "try" statement and in the [pscustomobject])
$vmHostAll = Get-VMHost
$i = 1
$vmHostAll | ForEach-Object -PipelineVariable vmhost -Process {
Write-Progress -PercentComplete ($i / $vmHostAll.count * 100) -Activity "Generating Server End Of Life Report" -Status "Getting info on $vmHost"
read-host "Press ENTER to Continue..."
$i++
try {
$esxcli = Get-EsxCli -vmhost $_ -V2 -ErrorAction Stop
$platform = $esxcli.hardware.platform.get.invoke()
}
catch {
Write-Host -ForegroundColor red "Get-EsxCli failed for $($_.Name)"
}
[pscustomobject] @{
vCenter = [System.Net.Dns]::GetHostEntry((Get-View $_ -ErrorAction SilentlyContinue).summary.managementserverip).HostName
"ESXi Host Name" = $_.Name
Vendor = $platform.VendorName
Model = $platform.ProductName
Serial = $platform.SerialNumber
EOL = $vmHostModelEolMapping[$platform.ProductName] -replace "^$", 'Unknown'
}
} | Sort-Object vCenter, "ESXi Host Name" | Export-Excel @hash
The output was now correct except for the Progress Bar, the Status was now reading
"Getting info on @{vCenter=vc1.company.com; ESXi Host Name=Host1.company.com; Vendor=Dell; Model=Poweredge R910; Serial =123abc; EOL=2015/Mar/29}"
I switched the Status from "Getting info on $vmHost" to "Getting info on $_", ran the code again and it worked 100%
I haven't used pscustomobjects before so don't understand what's happening here but, wanted to post it in case it helps others.
To keep this comment clean, i'm attaching the working code with your optimizations
Thanks again !
