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

View of /Get-HpProductInfo.ps1

Parent Directory Parent Directory | Revision Log Revision Log


Revision 15 - (download) (annotate)
Mon Sep 16 01:18:50 2013 UTC (10 years, 7 months ago) by ian
File size: 19226 byte(s)
added refresh switch to force fetching new data;
fixed custom object type error in PowerShell 3.0;
re-added count of order-able parts;
þÿ<#



.NOTES

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

 Get-HpProductInfo.ps1 v0.2

 

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:

 -Make it a proper PowerShell script (receive piped input, input validation, multiple SNs at once)

 -Cache objects to an XML file for faster loading if the same SN is queried again.

 -Multi-threading the http downloads and multiple retry attemps (partsufer is so unreliable lately)

 -Option to filter parts output



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  )]

    [Alias( "SN" )]

    [String]

    $SerialNumber,

    

    #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

)





### Being Setup

Set-StrictMode -Version Latest



###### Set Constants

#<#  ### uncomment this line for testing in ISE after initial run

Set-Variable productObjectVersion -option Constant -value 0.2

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

}

### End Setup





### Begin Check Cache

$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)"

### End Check Cache





function downloadProductData () {

    ### Create WebClient and cookie needed for PartSurfer

    $htClient = New-Object System.Net.Webclient

    $htClient.Headers.Set([System.Net.HttpRequestHeader]::Cookie, "Country=United%20States")





    ### Download and clean PartSurfer HTML so it can be parsed into XML

    $ErrorActionPreference = "Stop" #Needed so script won't continue if the web server returns an error

    $htData = $htClient.DownloadString("$($partSurferQueryUrl)$($SerialNumber)")

    $htData = -join $htData[$htData.IndexOf("<body")..($htData.LastIndexOf("</body>")+6)]

    $htData = $htData -replace '(?sx:<script[\s\S]*?</script[\s\S]*?>)' -replace '(?sx:<noscript[\s\S]*?</noscript[\s\S]*?>)'

    $htData = $htData -replace ' & ', " and " -replace "&\w{2,6};"

    $partSurferXml = [xml]$htData





    ### Parse collections of data

    $ErrorActionPreference = "SilentlyContinue" #Needed so filtering by ID won't generate an error on nodes with no ID property



    $partsHash = @{}

    $partSurferXml.SelectNodes("//span") | ? { $_.id -like "*gridSpareBOM_ctl*" -and $_.'#text' -notlike "*N/A*" } |

        % { $partsHash[$_.id] = $_.'#text' }

        

    $orderCheckboxArray = @()

    $partSurferXml.SelectNodes("//input") | ? { $_.id -like "*chkSpareBOM" } | % { $orderCheckboxArray += $_.id }



    $skuDataHash = @{}

    $partSurferXml.SelectNodes("//span") | ? { $_.id -like "*lbl*" -and $_.id -notlike "*BOM*" -and $_.id -notlike "*text*" } |

        % { $skuDataHash[$_.id] = $_.'#text' }



    $ErrorActionPreference = "Continue"





    ### Create psObject and start adding to it

    $hpProduct = New-Object psObject



    ### Load generic sku data into the object

    foreach ( $skuDatum in $skuDataHash.GetEnumerator() ){

        $propName = ""

        switch -wildcard ($skuDatum.Name) {

            "*SerialNumber" { $propName ="SerialNumber" }

            "*ProductNumber" { $propName ="ProductNumber" }

            "*Description" { $propName ="Description" }

        }

        if ( $propName ) { $hpProduct | Add-Member NoteProperty $propName $skuDatum.Value }

    }

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





    ### 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 "<br>"

    while ($htData -match "<td[^>]*>\s*([\w\s:]*)\s*</td>\s*<td[^>]*>\s*(\d{1,2} \w{3} \d{4})\s*</td>\s*<td[^>]*>\s*(\d{1,2} \w{3} \d{4})\s*</td>" ) {

        $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

    }





    ### Add orderable parts to psObject

    foreach ( $cb in $orderCheckboxArray ) {

        $null = $cb -match ".*(_ctl\d{2,3}_).*"

        $curPartData = $partsHash.GetEnumerator() | ? { $_.Name -like "*$($Matches[1])*" }

        $partObject = New-Object psObject

        foreach ( $part in $curPartData.GetEnumerator() ) {

            $propName = ""

            switch -wildcard ($part.Name) {

                "*spart1" { $propName ="PartNumber" }

                "*desc1" { $propName ="Description" }

                "*Enhanced" { $propName ="EnhancedDescription" }

                "*Category1" { $propName ="Category" }

                "*CSR1" { $propName ="CSR" }

                "*Rohs1" { $propName ="ROHS" }

                "*tech1" { $propName ="Tech" }

            }

            if ( $propName ) { $partObject | Add-Member NoteProperty $propName $part.Value }

        }

        $hpProduct.Parts | Add-Member NoteProperty $partObject.PartNumber $partObject

    }





    $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)"

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



    "-" * $lineLen



    "Warranty:"

    foreach ( $warrantyItem in $hpProduct | Get-Member | ? { $_.Name -like "Warranty*" } | % { $_.Name } ) {

      "$($warrantyItem):"

      "     Start: $($hpProduct.$warrantyItem.Start)     End: $($hpProduct.$warrantyItem.End)"

    }



    "-" * $lineLen

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

    "Available Parts: $($parts.Length)"



    "-" * $lineLen

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

        "$($hpProduct.Parts.$part.PartNumber) - $($hpProduct.Parts.$part.Description)"

    }

    "-"*$lineLen

}

Contact
ViewVC Help
Powered by ViewVC 1.0.4