#
.NOTES
Written by Ian Cammarata http://ian.cammarata.us
Get-HpProductInfo.ps1 v0.5
This will probably only work for products sold in the U.S. unless you change the country codes in $hpWarrantyQueryURL and the $htClient.Headers.set(...Cookie...
To Do:
-Multi-threading the http downloads and multiple retry attemps (partsufer is so unreliable lately)
SNs for testing: CND120CJH0, CNU305BP9N, CNFKF52058, JPBCD3R1H3
.SYNOPSIS
Query by SN to retreive HP product info from PartSufer and HP Business warranty lookup.
.EXAMPLE
PS> Get-HpProductInfo JPBCD3R1H3
#>
param(
#The serial number to query.
[Parameter( Mandatory = $True, Position = 0, ValueFromPipeline= $True )]
[Alias( "SN" )]
[String[]]
$SerialNumber,
#Search string for parts listing.
[Parameter( Position = 1 )]
[Alias( "Part" )]
$PartQuery,
#Output an object instead of an plain text.
[Switch]
[Alias( "Object" )]
$OutputObject,
#Purge cash for supplied SN(s) and fetch fresh data
[Switch]
[Alias( "Purge" )]
$Refresh
)
BEGIN {
Set-StrictMode -Version Latest
if ( $Script:PSBoundParameters.Keys.Contains("Debug") ) { $DebugPreference = "Continue" } ### For some reason I was getting first 3 debug lines output in the Process block even with using -Debug, but none afterwards
###### Set Constants
#<# ### uncomment this line for testing in ISE after initial run
Set-Variable productObjectVersion -option Constant -value 0.3
Set-Variable partSurferQueryUrl -option Constant -value "http://partsurfer.hp.com/Search.aspx?searchText="
#Set-Variable hpWarrantyQueryUrl -option Constant -value "http://h20000.www2.hp.com/bizsupport/TechSupport/WarrantyResults.jsp?lang=en&cc=us&country=US&find=Display+Warranty+Information+%C2%BB"
Set-Variable hpWarrantyStartUrl -option Constant -value "http://h20566.www2.hp.com/portal/site/hpsc/template.PAGE/public/wc/results/"
Set-Variable hpWarrantyQueryUrl -option Constant -value "http://h20566.www2.hp.com/portal/site/hpsc/template.PAGE/public/wc/results/?spf_p.tpst=wcMain&spf_p.prp_wcMain=wsrp-navigationalState%3Daction%253Dsummary&javax.portlet.begCacheTok=com.vignette.cachetoken&javax.portlet.endCacheTok=com.vignette.cachetoken"
Set-Variable cacheDir -option Constant -value (Join-Path $env:APPDATA "HpProductInfo_Cache")
Set-Variable maxCacheAge -option Constant -value 90 #In Days
#>
###### Prep
if ( !( Test-Path $cacheDir ) ){ $null = New-Item -Type "Directory" -Path $cacheDir }
###### Default display property set
$objectTemplateFile = Join-Path $cacheDir "HpProductObjectTemplate_v$($productObjectVersion).ps1xml"
if ( !( Test-Path $objectTemplateFile ) ) {
$template = ""
$template += "System.Management.Automation.PSCustomObject"
$template += "PSStandardMembersDefaultDisplayPropertySet"
$template += "ProductNumber"
$template += "SerialNumber"
$template += "Description"
$template += "WarrantyOnsite"
$template += "Parts"
$template += ""
Out-File $objectTemplateFile -Encoding "UTF8" -InputObject $template -Force
}
if ( $PSVersionTable.PSVersion.Major -gt 2 ) {
Update-TypeData $objectTemplateFile
}
elseif ( ! ( $host.Runspace.RunspaceConfiguration.Types | ? { $_.FileName -eq $objectTemplateFile } ) ) {
Update-TypeData $objectTemplateFile
}
}
PROCESS {
Foreach ($SerialNumber in $SerialNumber) {
$SerialNumber = $SerialNumber.Trim().ToUpper()
Write-Debug ">> Check cache for XML copy of data"
$useCache = $false
if ( $cacheHit = ls $cacheDir | ? { $_.Name -like "$($SerialNumber)_*" } ) {
Write-Debug "Cache Hit!!! ($cacheHit)"
$useCache = $true
if ( $Refresh ) {
$useCache = $false
}
elseif ( $cacheHit -notlike "*_v$($productObjectVersion).xml" ) {
Write-Debug "Version Mismatch; Deleting... :-("
$useCache = $false
}
elseif ( ( Get-Date ) -gt $cacheHit.CreationTime.AddDays(90) ) {
Write-Debug "Stale Cache; Deleting... :-("
$useCache = $false
}
if ( ! $useCache ) { Remove-Item ( Join-Path $cacheDir $cacheHit ) }
}
Write-Debug "Using Cache: $($useCache)"
Write-Debug "<< End Check Cache"
function downloadProductData () {
Write-Debug "Create WebClient and cookie needed for PartSurfer"
$htClient = New-Object System.Net.Webclient
$htClient.Headers.Set([System.Net.HttpRequestHeader]::Cookie, "Country=United%20States")
Write-Debug "/!\Begin critical section/!\ Any errors here break the entire script."
$ErrorActionPreference = "Stop"
if ( $Script:PSBoundParameters.Keys.Contains("Debug") ) {
Write-Debug "Debugging is enabled, using cached raw html if available"
if ( ls $cacheDir | ? { $_.Name -eq "$($SerialNumber).raw.html" } ) {
Write-Debug "Raw HTML read from cache"
$htData = Get-Content (Join-Path $cacheDir "$($SerialNumber).raw.html")
}
Else {
Write-Debug "Download PartSurfer HTML data"
$htData = $htClient.DownloadString("$($partSurferQueryUrl)$($SerialNumber)")
Write-Debug "Clean line breaks, tabs, multiple spaces, and blank space between tags"
$htData = $htData -replace "(\r|\f|\n)*", "" -replace "\t", " " -replace " ", "" -replace "> <", "><"
Write-Debug "Raw HTML written to cache"
Set-Content (Join-Path $cacheDir "$($SerialNumber).raw.html") $htData
}
}
Else {
Write-Debug "Download PartSurfer HTML data"
$htData = $htClient.DownloadString("$($partSurferQueryUrl)$($SerialNumber)")
Write-Debug "Clean line breaks, tabs, multiple spaces, and blank space between tags"
$htData = $htData -replace "(\r|\f|\n)*", "" -replace "\t", " " -replace " ", "" -replace "> <", "><"
}
Write-Debug "Create psObject representing the product"
$hpProduct = New-Object psObject
Write-Debug "Load generic sku data into the object"
Write-Debug "Load SerialNumber"
$hpProduct | Add-Member NoteProperty SerialNumber $SerialNumber
Write-Debug "Load ProductNumber"
$null = $htData -match "(.*?)"
$hpProduct | Add-Member NoteProperty ProductNumber $Matches[1]
Write-Debug "Load Description"
$null = $htData -match "(.*?)"
$hpProduct | Add-Member NoteProperty Description $Matches[1]
$ErrorActionPreference = "Continue"
Write-Debug "/!\End critical section/!\"
Write-Debug "Add Spare and OEM parts to psObject (Check boxes are no longer supplied by the site to determine part availability)"
$hpProduct | Add-Member NoteProperty OemParts (New-Object psObject)
$hpProduct | Add-Member NoteProperty Spares (New-Object psObject)
$trMatches = Select-String "
.*?
" -inputObject $htData -AllMatches
foreach ( $trMatch in $trMatches.Matches ){
if ( $trMatch.Value -notmatch ".*(no longer supplied|Not Available|Hebrew|Cyrillic|Greek|Arabic|Bulk|220V|- AR|- CS|- DA|- NL|- FI|- DE|- EL|- HE|- HU|- KO|- NO|- PL|- ZHCN|- ZHTW|- TH|PCID|SWID| CH | CH<|CHINARUSS).*" )
{
$spanMatches = Select-String "(.*?)" -inputObject $trMatch.Value -AllMatches
$partObject = New-Object psObject
$partObject | Add-Member NoteProperty PartNumber $spanMatches.Matches[0].Groups[1].Value
$partObject | Add-Member NoteProperty Description $spanMatches.Matches[1].Groups[1].Value
$BomType = "OemParts"
if ( $trMatch.Value -match ".*_gridSpareBOM_.*" ) { $BomType = "Spares" }
$ErrorActionPreference = "SilentlyContinue"
$hpProduct.$BomType | Add-Member NoteProperty $partObject.PartNumber $partObject
$ErrorActionPreference = "Continue"
Write-Debug "$($BomType): $($partObject.PartNumber) - $($partObject.Description)"
}
Else { Write-Debug "Discarding invalid or no longer supplied part." }
}
<#
### Download and parse warranty info -- Page is too messy to clean for XML casting, will just scrape with regex
$ErrorActionPreference = "Stop" #Needed so script won't continue if the web server returns an error
$htData = $htClient.DownloadString("$($hpWarrantyQueryUrl)&sn=$($hpProduct.SerialNumber)&pn=$($hpProduct.ProductNumber)")
$ErrorActionPreference = "Continue"
$warranty = @()
$htData = $htData -replace "
"
while ($htData -match "]*>\s*([\w\s:]*)\s* | \s*]*>\s*(\d{1,2} \w{3} \d{4})\s* | \s*]*>\s*(\d{1,2} \w{3} \d{4})\s* | " ) {
$warranty += $Matches[1..3]
$htData = $htData.Replace($Matches[0],1)
}
$warranty = $warranty -replace "wty: |HWM |HP |HW |Maintenance |Support |for| "
### Add warranty data to psObject
$i = 0
while ( $i -lt $warranty.Length ){
#"$($warranty[$i])`t`tStart: $($warranty[$i+1])`t`tEnd: $($warranty[$i+2])"
$hpProduct | Add-Member NoteProperty "Warranty$($warranty[$i])" @{ Start = ( '{0:MMM d yyyy}' -f ( Get-Date $warranty[$i+1] ) ); End = ( '{0:MMM d yyyy}' -f ( Get-Date $warranty[$i+2] ) ) }
$i += 3
}#>
### Download and parse warranty info
<#
Parametersapplication/x-www-form-urlencoded
rows[0].item.countryCode US
rows[0].item.serialNumber CND120CJH0
rows[1].item.countryCode US
rows[1].item.serialNumber
rows[2].item.countryCode US
rows[2].item.serialNumber
rows[3].item.countryCode US
rows[3].item.serialNumber
rows[4].item.countryCode US
rows[4].item.serialNumber
rows[5].item.countryCode US
rows[5].item.serialNumber
rows[6].item.countryCode US
rows[6].item.serialNumber
rows[7].item.countryCode US
rows[7].item.serialNumber
rows[8].item.countryCode US
rows[8].item.serialNumber
rows[9].item.countryCode US
rows[9].item.serialNumber
submitButton Submit
###################################################
Source
rows%5B0%5D.item.serialNumber=CND120CJH0&rows%5B0%5D.item.countryCode=US&rows%5B1%5D.item.serialNumber=&rows%5B1%5D.item.countryCode=US&rows%5B2%5D.item.serialNumber=&rows%5B2%5D.item.countryCode=US&rows%5B3%5D.item.serialNumber=&rows%5B3%5D.item.countryCode=US&rows%5B4%5D.item.serialNumber=&rows%5B4%5D.item.countryCode=US&rows%5B5%5D.item.serialNumber=&rows%5B5%5D.item.countryCode=US&rows%5B6%5D.item.serialNumber=&rows%5B6%5D.item.countryCode=US&rows%5B7%5D.item.serialNumber=&rows%5B7%5D.item.countryCode=US&rows%5B8%5D.item.serialNumber=&rows%5B8%5D.item.countryCode=US&rows%5B9%5D.item.serialNumber=&rows%5B9%5D.item.countryCode=US&submitButton=Submit
#>
<#
wc.Headers[HttpRequestHeader.ContentType] = "application/x-www-form-urlencoded";
string HtmlResult = wc.UploadString(URI, myParameters);
#>
<#
$ErrorActionPreference = "Stop" #Needed so script won't continue if the web server returns an error
#$htClient.Headers["Content-Type"] = "application/x-www-form-urlencoded"
$htClient.Headers.Set( "Content-Type", "application/x-www-form-urlencoded" )
#$htData = $htClient.DownloadString("$($partSurferQueryUrl)$($SerialNumber)")
$htData = $htClient.UploadString( $hpWarrantyQueryUrl, "rows[0].item.serialNumber=$($SerialNumber)&rows[0].item.countryCode=US" )
$htData = -join $htData[$htData.IndexOf("")+6)]
$htData = $htData -replace '(?sx: