Get Dell ESX host warranty info via PowerCLI version 2

Originally made to quickly see which ESX hosts are in or out of warranty.  The Dell Management plugin still doesn't seem to give this information interestingly enough.  Anyway, my old script doesn't work these days because the property for service tag doesn't exist @ the vCenter level.  It does exist @ the host level though, so I had to work a little magic.

Here is an screenshot example of you can end up with:

  • Dell changed their warranty site so the ShipDate field is incorrect.  Pulling the site string down only faithfully pulls down the warranty end date.  If that field is important to you, then feel free to share w/ me how I can pull that info along w/ the end date.
  • The script also assumes you have the same root password on all your hosts.  If you have a different password, then you'll need to generate an xml credential file for each.
  • It's designed to grab data from your vCenter server for your list of ESX hosts.  It then uses that list to loop connect through each of your ESX hosts and puts them into an array variable.
  • These should be applied in the context of the account you plan to run this under in a scheduled task fashion.
    • If your ESX servers are not signed by a trusted CA, you'll need to set your powercli configuration to ignore certificate errors:
      • Set-PowerCLIConfiguration -InvalidCertificateAction:Ignore
    • Since you are working w/ multiple VI server connections, you may need to set your defaultVIservermode to multiple
      • Set-PowerCLIConfiguration -DefaultVIServerMode:Multiple
Click through for the code:


Add-PSsnapin VMware.VimAutomation.Core
Connect-VIServer YourvCenterServer

$date            = Get-Date
$htmpath        = "C:\inetpub\wwwroot\"
$csvpath        = "C:\inetpub\wwwroot\csv\"
$htmname        = "VMHostInvReport.htm"
$csvname         = "VMHostInvReport.csv"

#Report Title appears in <title> section and shows in the browser window.
$ReportTitle     = "VM/ESX Host Inventory Data"

#IconPath is the icon that is rendered on supported web browsers tab or address bar
$IconPath        = "/images/mySuperAwesomeIcon.ico"

#AppleIconType, set this to "Apple-touch-icon" if you would like the iOS device to render a glass effect on top of your custom icon.
#Otherwise use "Apple-touch-icon-precomposed" to just use your stock image.  45x45 is recommended, but higher rez can be used.
$AppleIconType     = "apple-touch-icon-precomposed"

#AppleTouchIcon is the image that appears on an iOS and/or Android device when a home screen bookmark is created.
$AppleTouchIcon = "/images/apple-touch-icon.png"

#Stylesheet is the path where your CSS file lies.
$Stylesheet        = "./styles/style.css"

#SortScript is where the sorttable.js script resides.  This allows dynamic sorting of table information within the browser.
$SortScript     = "./scripts/sorttable.js"

#Used to generate encrypted xml password file
#New-VICredentialStoreItem -Host doesntreallymatter -User root -Password "" -File "C:\CredentialStore\VIroot.xml"
#xml is only valid w/ yourServiceAccount account.
$Creds = Get-VICredentialStoreItem -File C:\VIroot.xml
$ESXServers = Get-VMHost
Disconnect-VIServer -Confirm:$false
$ESXServerView = @()
$Count = $ESXServers.Count
While ($Count -gt 0)
$Count = $Count - 1
$VIESXHost = Connect-VIServer $ESXServers[($Count)].Name -User $Creds.User -Password $Creds.Password
$ESXServerView += Get-VMHost -Server $VIESXHost | Get-View
Disconnect-VIServer -Server $VIESXHost -Confirm:$false
#$ESXServerView = $ESXServers | Get-View
#$ServiceTagList = foreach($VMHost in $ESXServerView){($VMHost.hardware.systeminfo.OtherIdentifyingInfo | where {$_.IdentifierType.Key -eq "servicetag"}).identifierValue}
$ESXInfo = @()

$oWeb = New-Object System.Net.WebClient

Foreach ($ESX in $ESXServers){
$TargetESXServerView = $ESXServerView | where {$_.Name -eq $ESX.Name}
$NewObj         = "" | Select Cluster, Name, Model, Version, BIOs, ServiceTag, AssetTag, ShipDate, ExpiryDate
$NewObj.Cluster = $ESX.Parent.Name
$NewObj.Name    = $ESX.Name
$NewObj.Model    = $ESX.Model
$NewObj.Version    = $ESX.Version
$NewObj.BIOs    = (($TargetESXServerView.Runtime.HealthSystemRuntime.SystemHealthInfo.NumericSensorInfo | where {$_.Name -like "*BIOS*"  -and $_.SensorType -eq "Software Components"}).Name) -replace(".* BIOS ","") -replace(" .*","")
$NewObj.ServiceTag     = ($TargetESXServerView.hardware.systeminfo.OtherIdentifyingInfo | where {$_.IdentifierType.Key -eq "servicetag"}).identifierValue -replace(" ","")
$NewObj.AssetTag    = ($TargetESXServerView.hardware.systeminfo.OtherIdentifyingInfo | where {$_.IdentifierType.Key -eq "assettag"}).identifierValue -replace(" ","")
## Gets ServiceTag Info from Dell
#$oWeb = New-Object System.Net.WebClient
$ServiceTag = $null
If ($NewObj.ServiceTag -eq $null -or $NewObj.ServiceTag -eq "unknown" -or $NewObj.ServiceTag -eq "") {$ServiceTag = $NewObj.AssetTag} Else {$ServiceTag = $NewObj.ServiceTag}
#$sUrl = "$($ServiceTag)"
$sUrl = "$($ServiceTag)"
$sData = $oWeb.DownloadString($sUrl)
#get just the dates from the dell site.
$oRegEx = [regex]'\d{1,2}/\d{1,2}/\d{4}'
$cMatches = $oRegEx.Matches($sData)
#convert to a date object
$test = @()
foreach ($a in $cMatches){$Test += ([datetime]$a.Value)}
#Sort by the year
$datedata = $test | Sort-Object year
#Grab the earliest date for Shipdate
$ShipDate = ($Datedata[0]).toshortdatestring()
#Find the last object in the array
$cDates = ($Datedata.count) - 1
#Grab the latest date from the array for the warranty end date
$EndDate = ($Datedata[$cDates]).toshortdatestring()
## End Dell Site Code
$ExpiryDateType = [datetime]$EndDate
If ($EndDate -ne $null)
If ($ExpiryDateType -lt $date) {$EndDateHTM = "<p style='font-weight:bold;color:red'>$($EndDate)</p>"}
ElseIf ($ExpiryDateType -lt $date.AddDays(-90)) {$EndDateHTM = "<p style='font-weight:bold;color:orange'>$($EndDate)</p>"}
ElseIf ($ExpiryDateType -gt $date.AddDays(-90)) {$EndDateHTM = $EndDate}
If ($EndDate -eq $null -or $EndDate -eq "") {$EndDateHTM = $EndDate}
$NewObj.ShipDate    = $ShipDate
$NewObj.ExpiryDate    = $EndDateHTM

$ESXInfo += $NewObj
$ShipDate = $null
$EndDate = $null
$EndDateHTM = $null
$Head = "<LINK REL='SHORTCUT ICON' HREF='$($IconPath)'><link rel='$($AppleIconType)' href='$($AppleTouchIcon)'/><title>$($ReportTitle)</title><link rel='stylesheet' type='text/css' href='$($Stylesheet)'><script src='$($SortScript)'></script>"
$ESXInfo | ConvertTo-Html –body "<a name='Data'></a><strong>$ReportTitle $date</strong>
<br><a href=./csv/$($csvname)>(Click here to download csv copy)</a>" -head "$($Head)" | 
foreach {$_.replace("&lt;","<").replace("&gt;",">").replace("<tr><th>","<table class='sortable'><thead><tr><th>").replace("</th></tr>","</th></tr></thead><tbody>").replace("</table>","</tbody><tfoot></tfoot></table>")} | 
Out-File -Encoding ASCII -FilePath "$($htmpath)$($htmname)"

$ESXInfo | convertto-csv -NoTypeInformation | foreach {$_ -replace("<p style='font-weight:bold;color:orange'>","") -replace("<p style='font-weight:bold;color:red'>","") -replace("</p>","")} | Out-File -Encoding ASCII -FilePath "$($csvpath)$($csvname)"


Stephen Dion said...

Hey Chris, dumb question, but can you post a zip with this ps1, your css stylesheet, and the js file? I want to completely mimic what you pictured but have no idea how.

Chris Nakagaki said...

Here you go.

I found out recently you can query the dell website and get an xml result which is much better than my 'web page' scrape. I haven't had time to augment change mine to get this info below yet.

Stephen Dion said...


I keep getting a few errors about null or empty arguments. Perhaps hosts in my vCenter that don't have the same root password and cannot be logged into. Is the expected result for the script to fail if it hits an ESX host with a different password?

I end up with a list of hosts, and only the first with a valid service tag. All of the rest in the list show a service tag of "System Object..."

Looking forward to your updated script if you decide to go that route!

Stephen Dion said...

For example:
PowerEdge M610 5.1.0 3.0.0 System.Object[] unknown 7/27/2012

Yet the ST does appear in vCenter (after I ran your other script for the disconnect/reconnect)

Chris Nakagaki said...

Interesting. System.Object leads me to believe that the script is finding more than one entry for 'service tag'. Try running the script against just one host, specifically against one that returns that system.object. You can do so by simply changing the following line:
$ESXServers = Get-VMHost theESXHost
Run it in something like powerGUI so that $ESXInfo.ServiceTag variable populates.

Robby said...

Hey Chris,

Would you be willing/able to post the .zip file again online? I tried the dropbox link and it apparently is no longer there.

Many thanks in advance,

This is exactly what I was looking for.


Chris Nakagaki said...

Sure thing Robby. I actually have a new version here:

Here is a new dropbox link:

Robby said...

Awesome work!

Thanks Chris!