[PowerShell] / Get-HpProductInfo.ps1 Repository:
ViewVC logotype

View of /Get-HpProductInfo.ps1

Parent Directory Parent Directory | Revision Log Revision Log


Revision 31 - (download) (annotate)
Wed Jul 9 05:24:43 2014 UTC (9 years, 9 months ago) by ian
File size: 32894 byte(s)
Fixed Get-HpProductInfo.ps1 to function again with updated HP Warranty site;
þÿ<#



.NOTES

 Written by Ian Cammarata  http://ian.cammarata.us

 Get-HpProductInfo.ps1 v0.6

 

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)

 -Generate a proper object (this will allow tab completion and easier programmatic use)



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.ContainsKey("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.4

    Set-Variable partSurferQueryUrl -option Constant -value "http://partsurfer.hp.com/Search.aspx?searchText="

    Set-Variable hpWarrantyBaseUrl -option Constant -value "https://h20565.www2.hp.com"

    Set-Variable hpWarrantyStartPath -option Constant -value "/portal/site/hpsc/public/wc/home/"

    Set-Variable hpWarrantyQueryUrl -option Constant -value "https://h20566.www2.hp.com/portal/site/hpsc/template.PAGE/action.process/public/wc/home/?javax.portlet.action=true&javax.portlet.sync=d549c6d9a9acda7f8405adb432a15c01&javax.portlet.tpst=c4efedb99acca32ea782977bb053ce01&javax.portlet.prp_c4efedb99acca32ea782977bb053ce01=wsrp-interactionState%3Daction%253Dfind&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 = "<?xml version='1.0' encoding='utf-8' ?>"

        $template += "<Types><Type><Name>System.Management.Automation.PSCustomObject</Name><Members><MemberSet>"

        $template += "<Name>PSStandardMembers</Name><Members><PropertySet><Name>DefaultDisplayPropertySet</Name><ReferencedProperties>"

        $template += "<Name>ProductNumber</Name>"

        $template += "<Name>SerialNumber</Name>"

        $template += "<Name>Description</Name>"

        $template += "<Name>WarrantyOnsite</Name>"

        $template += "<Name>Parts</Name>"

        $template += "</ReferencedProperties></PropertySet></Members></MemberSet></Members></Type></Types>"

        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 {

    Function CleanHtml($htData) {

        Return $htData -replace "(\r|\f|\n)*" -replace "\t", " " -replace "  " -replace "> <", "><" -replace "&nbsp;" -replace "<a .*?>" -replace "</a>"

    }

    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 "Load initial warranty lookup page to get ID cookies, run ahead of time for the session to settle on the server or w/e"

            $cookieContainer = New-Object System.Net.CookieContainer



            [net.httpWebRequest] $webReq = [net.webRequest]::create("$($hpWarrantyBaseURL)$($hpWarrantyStartPath)")

            $webReq.CookieContainer = $cookieContainer

            [net.httpWebResponse] $webResp = $webReq.GetResponse()

            $strRdr = New-Object IO.StreamReader($webResp.GetResponseStream())

            $htData = $strRdr.ReadToEnd()

            $webResp.Close()





           Write-Debug "Parse out POST action"

            $null = $htData -match "<form .*? name=`"warrantyCheck`" .*? action=`"([^`"]*)`""

            $hpWarrantyQueryPath = $Matches[1]





           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.ContainsKey("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 = CleanHtml( $htData )



               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 = CleanHtml( $htData )

            }

            



           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 "<span id=`"ctl00_BodyContentPlaceHolder_lblProductNumber`">(.*?)</span>"

            $hpProduct | Add-Member NoteProperty ProductNumber $Matches[1]



           Write-Debug "Load Description"

            $null = $htData -match "<span id=`"ctl00_BodyContentPlaceHolder_lblDescription`">(.*?)</span>"

            $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 "<tr class=`"[^`"]*RowStyle`">.*?</tr>" -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 "<span.*?>(.*?)</span>" -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." }

            }

            

            $warrAttempts = 0

            $trMatches = ""

            do {

            sleep ( 8 + $warrAttempts )

           Write-Debug "Create POST request to retrieve SN data. Attempt #$($warrAttempts)"

            [net.httpWebRequest] $webReq = [net.webRequest]::create("$($hpWarrantyBaseURL)$($hpWarrantyQueryPath)")

            $webReq.CookieContainer = $cookieContainer

            $webReq.Method = "POST"



            $postData = "rows[0].item.serialNumber=$($SerialNumber)&rows[0].item.countryCode=US&rows[1].item.serialNumber=&rows[1].item.countryCode=US&rows[2].item.serialNumber=&rows[2].item.countryCode=US&rows[3].item.serialNumber=&rows[3].item.countryCode=US&rows[4].item.serialNumber=&rows[4].item.countryCode=US&rows[5].item.serialNumber=&rows[5].item.countryCode=US&rows[6].item.serialNumber=&rows[6].item.countryCode=US&rows[7].item.serialNumber=&rows[7].item.countryCode=US&rows[8].item.serialNumber=&rows[8].item.countryCode=US&rows[9].item.serialNumber=&rows[9].item.countryCode=US&submitButton=Submit"

            $postBuffer = [Text.Encoding]::Ascii.GetBytes($postData)

            $webReq.ContentLength = $postBuffer.Length

            $webReq.ContentType = "application/x-www-form-urlencoded"

            $reqStr = $webReq.GetRequestStream()

            $reqStr.Write( $postBuffer, 0, $postBuffer.Length)

            $reqStr.Flush()

            $reqStr.Close()



            [net.httpWebResponse] $webResp = $webReq.GetResponse()

            $strRdr = New-Object IO.StreamReader($webResp.GetResponseStream())

            $htData = $strRdr.ReadToEnd()

            $webResp.Close()



            $htData = CleanHtml( $htData )

            $warrAttempts++

            $trMatches = Select-String "<tr class='hpui-(normal|altername)-row'.*?</tr>" -inputObject $htData -AllMatches

            }

            while ( $warrAttempts -lt 4 -and -not $trMatches )



           Write-Debug "Parse warranty data and add to the object"

            $hpProduct | Add-Member NoteProperty Warranties (New-Object psObject)



            

            foreach ( $trMatch in $trMatches.Matches ){

              $tdMatches = Select-String "<td((?!rowspan|color).)*?</td>" -inputObject $trMatch -AllMatches

  

              $warrData = $tdMatches.Matches | % {

                $_.value -replace "</?td[^>]*>" -replace "Wty: " -replace "HP " -replace "HW Maintenance ", "HWM " -replace "Support ?(for )?"

              }



              if ( $warrData[1].Length -or $warrData[2].Length ) {

                $warrObject = New-Object psObject

                $warrObject | Add-Member NoteProperty Start ( '{0:MMM d yyyy}' -f ( Get-Date $warrData[1] ) )

                $warrObject | Add-Member NoteProperty End ( '{0:MMM d yyyy}' -f ( Get-Date $warrData[2] ) )

                $hpProduct.Warranties | Add-Member NoteProperty $warrData[0] $warrObject

              }

              Else { $hpProduct.Warranties | Add-Member NoteProperty $warrData[0] "" }

            }

          



            $hpProduct | Add-Member NoteProperty __QueryDate (Get-Date)

            $hpProduct | Add-Member NoteProperty __productObjectVersion $productObjectVersion



            $hpProduct | Export-Clixml (Join-Path $cacheDir "$($hpProduct.SerialNumber)_$($hpProduct.ProductNumber)_v$($productObjectVersion).xml")

            return $hpProduct

        }





        #Import line is potentially error prone, make it more specific later on

        if ( $useCache ) { $hpProduct = Import-Clixml ( Join-Path $cacheDir "$($SerialNumber)_*" ) }

        else { $hpProduct = downloadProductData }





        if ( $OutputObject ) {

            $hpProduct

        }

        Else {

            $lineLen = 75



            "%ˆ" * $lineLen



            "Serial Number:`t$($hpProduct.SerialNumber)"

            "Product Number:`t$($hpProduct.ProductNumber -replace '#ABA' )"

            "Description:`t$($hpProduct.Description)"

            ""

            



            $partsTxt = @()

            $warranties = $hpProduct.Warranties | get-member -MemberType "NoteProperty"

            foreach ( $warranty in $warranties | % { $_.Name } ) {

                if ( ($hpProduct.Warranties.$warranty | Get-Member | % { $_.Name } ) -contains "Start" ) {

                    $partsTxt += "$($warranty)`t$($hpProduct.Warranties.$warranty.Start)`t$($hpProduct.Warranties.$warranty.End)"

                }

                Else { $partsTxt += $warranty }

            }

            "Warranties: $($partsTxt.Length)"

            "%" * $lineLen

            $partsTxt



            ""

            $parts = $hpProduct.OemParts | get-member -MemberType "NoteProperty"

            $partsTxt = @()

            foreach ( $part in $parts | % { $_.Name } ) {

                if ( $PartQuery ) {

                    if ( $hpProduct.OemParts.$part.Description -match ".*$($PartQuery).*" ) {

                        $partsTxt += "$($hpProduct.OemParts.$part.PartNumber) - $($hpProduct.OemParts.$part.Description)"

                    }

                }

                Else { $partsTxt += "$($hpProduct.OemParts.$part.PartNumber) - $($hpProduct.OemParts.$part.Description)" }

            }

            "OEM Parts$(if ( $PartQuery ) {" matching query '$($PartQuery)'"}): $($partsTxt.Length)"

            "%" * $lineLen

            $partsTxt





            ""

            $parts = $hpProduct.Spares | get-member -MemberType "NoteProperty"

            $partsTxt = @()

            foreach ( $part in $parts | % { $_.Name } ) {

                if ( $PartQuery ) {

                    if ( $hpProduct.Spares.$part.Description -match ".*$($PartQuery).*" ) {

                        $partsTxt += "$($hpProduct.Spares.$part.PartNumber) - $($hpProduct.Spares.$part.Description)"

                    }

                }

                Else { $partsTxt += "$($hpProduct.Spares.$part.PartNumber) - $($hpProduct.Spares.$part.Description)" }  

            }

            "Spares$(if ( $PartQuery ) {" matching query '$($PartQuery)'"}): $($partsTxt.Length)"

            "%" * $lineLen

            $partsTxt

            

            "%ˆ"*$lineLen

        }

    }

}

Contact
ViewVC Help
Powered by ViewVC 1.0.4