<# .NOTES Written by Ian Cammarata http://ian.cammarata.us Get-HpProductInfo.ps1 v0.9 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) -Filter out more irrelevant parts by country code suffix on the PN. ex: -BG1 = Swiss -Fix: When there are multiple matching products, it will output a bunch of errors on the first query for that serial number. Subsequent queries will pull data that was cached and will display fine. 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 IF ( -not ( Test-Path Variable:\\fullRegionName ) ) { #This prevents errors from being generated when running from ISE Set-Variable fullRegionName -Option Constant -value "United States" Set-Variable abbrRegionName -Option Constant -Value "US" Set-Variable regionSuffix -Option Constant -Value "#ABA" 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 } ### This was causing issues with other PowerShell scripts. It will remain disabled till I learn to fix it across all versions of PowerShell or I no longer need to support PS 1.0. <# ###### Default display property set #Maybe this will be added back in future, not really necessary anyway $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 { Function CleanHtml($htData) { RETURN $htData -replace "(\r|\f|\n)*" -replace "\t", " " -replace " " -replace "> <", "><" -replace " " -replace "" -replace "" } 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 "
Write-Debug "Downloading PartSurfer HTML data" #$htData = $htClient.DownloadString("$($partSurferQueryUrl)$($SerialNumber)") [net.httpWebRequest] $webReq = [net.webRequest]::create("$($partSurferQueryUrl)$($SerialNumber)") ###$webReq.CookieContainer = $cookieContainer [net.httpWebResponse] $webResp = $webReq.GetResponse() $strRdr = New-Object IO.StreamReader($webResp.GetResponseStream()) $htData = $strRdr.ReadToEnd() $webResp.Close() $htData = CleanHtml( $htData ) Write-Debug "Raw HTML written to cache" Set-Content (Join-Path $cacheDir "$($SerialNumber).raw.html") $htData <# } } ELSE { Write-Debug "Downloading PartSurfer HTML data" #$htData = $htClient.DownloadString("$($partSurferQueryUrl)$($SerialNumber)") [net.httpWebRequest] $webReq = [net.webRequest]::create("$($partSurferQueryUrl)$($SerialNumber)") $webReq.CookieContainer = $cookieContainer [net.httpWebResponse] $webResp = $webReq.GetResponse() $strRdr = New-Object IO.StreamReader($webResp.GetResponseStream()) $htData = $strRdr.ReadToEnd() $webResp.Close() Write-Debug "Clean line breaks, tabs, multiple spaces, and blank space between tags" $htData = CleanHtml( $htData ) } #commented to match top part of if block commented out#> Write-Debug "Check if page is asking to choose which region the product is from due to multiple serial number matches." IF ( $htData -match 'type="radio"' ) { Write-Debug "Attempting to select the correct product based on region suffix." $fullSku = "" IF ( $Script:PSBoundParameters.ContainsKey("Debug") ) { Write-Debug "Debugging is enabled, renaming original cache file to ...please.select.raw.html." Move-Item -Force ( Join-Path $cacheDir "$($SerialNumber).raw.html" ) ( Join-Path $cacheDir "$($SerialNumber).please.select.raw.html" ) } $htData -match "`".......$($regionSuffix)`"" IF ( $Matches.Count -eq 1 ) { $fullSku = $Matches[0] -replace '"', "" $partSurferRetries = 0 DO { $partSurferRetries++ Write-Debug "Create POST request to search PartSurfer again with SKU ($($fullSku)). Attempt# $($partSurferRetries)" # Sleep 45 [net.httpWebRequest] $webReq = [net.webRequest]::create("$($partSurferQueryUrl)$($SerialNumber)") $webReq.CookieContainer = $cookieContainer $webReq.Method = "POST" $webReq.Host = "partsurfer.hp.com" $webReq.Referer = "http://partsurfer.hp.com/Search.aspx?SearchText=$($SerialNumber)" Write-Debug "Looking for (strikeout non-blank) all (blank or not) form fields to include in POST header..." $postData = "" $postInputs = Select-String "" -inputObject $htData -AllMatches $postInputs.Matches | ? { $_ -notmatch ".*(submit|image|radio).*" } | % { $null = $_ -match ".*?name=`"(.*?)`".*?>" $newData = "$($Matches[1])=" IF ( $_ -match ".*?value=`"(.*?)`".*?>" ) { Write-Debug "$($newData) `"$( IF ( $Matches[1].Length -gt 65 ) { "$($Matches[1].Substring(0,55))...(truncated)" } ELSE { $Matches[1] } )`"" $newData += $Matches[1] } $postData += "$($newData)&" } Write-Debug "ctl00`$BodyContentPlaceHolder`$radProd = $($fullSku)" $postData += "ctl00`$BodyContentPlaceHolder`$radProd=$($fullSku)" #Write-Debug "`$postData=`n$PostData" #$postData = "&__EVENTTARGET=" #$postData += "&__EVENTARGUMENT=" #$postData += "&__VIEWSTATE=/wEPDwUKMTI2NzMyMTI0OA9kFgJmD2QWAmYPZBYGZg8WAh4Fd2lkdGgFBjE0MDBweGQCEA9kFggCDw9kFgJmD2QWAgIBD2QWAgIDDw8WBB4EVGV4dAUTUHJvZHVjdCBJbmZvcm1hdGlvbh4HVmlzaWJsZWdkZAIQD2QWAmYPZBYCAgEPDxYKHglGb3JlQ29sb3IKex8BBRVIUCBBU1DigJlzIGNsaWNrIGhlcmUeC05hdmlnYXRlVXJsBQEjHghDc3NDbGFzcwUKZW5hYmxlTGluax4EXyFTQgIGZGQCEg8QDxYGHg1EYXRhVGV4dEZpZWxkBQxDT1VOVFJZX05BTUUeDkRhdGFWYWx1ZUZpZWxkBQxDT1VOVFJZX0NPREUeC18hRGF0YUJvdW5kZxYEHghPbkNoYW5nZQUNZXJhc2VDb29raWUoKR4HT25Gb2N1cwUQY291bnRyeU9uRm9jdXMoKRAVggELU0VMRUNUIE9ORT4HQWxiYW5pYQdBbGdlcmlhCEFuZ3VpbGxhG0FudGlndWEgYW5kIEJhcmJ1ZGEgSXNsYW5kcwlBcmdlbnRpbmEFQXJ1YmEJQXVzdHJhbGlhB0F1c3RyaWEKQXplcmJhaWphbgdCYWhhbWFzB0JhaHJhaW4IQmFyYmFkb3MHQmVsYXJ1cwdCZWxnaXVtBkJlbGl6ZQdCZXJtdWRhB0JvbGl2aWESQm9zbmlhLUhlcnplZ292aW5hBkJyYXppbAhCdWxnYXJpYQZDYW5hZGEcQ2FudG9uIGFuZCBFbmRlcmJ1cnkgSXNsYW5kcw5DYXltYW4gSXNsYW5kcwVDaGlsZQVDaGluYQhDb2xvbWJpYQVDb25nbwpDb3N0YSBSaWNhB0Nyb2F0aWEGQ3lwcnVzDkN6ZWNoIFJlcHVibGljB0Rlbm1hcmsIRG9taW5pY2ESRG9taW5pY2FuIFJlcHVibGljDkVhc3Rlcm4gRXVyb3BlB0VjdWFkb3IFRWd5cHQLRWwgU2FsdmFkb3IGRXVyb3BlEEZhbGtsYW5kIElzbGFuZHMHRmlubGFuZAZGcmFuY2UHR2VybWFueQZHcmVlY2UHR3JlbmFkYQRHdWFtCUd1YXRlbWFsYQZHdXlhbmEFSGFpdGkISG9uZHVyYXMJSG9uZyBLb25nB0h1bmdhcnkFSW5kaWEJSW5kb25lc2lhBElyYXEHSXJlbGFuZAZJc3JhZWwFSXRhbHkHSmFtYWljYQVKYXBhbgZKb3JkYW4KS2F6YWtoc3RhbgVLZW55YQZLdXdhaXQNTGF0aW4gQW1lcmljYQdMZWJhbm9uCkx1eGVtYm91cmcJTWFjZWRvbmlhCE1hbGF5c2lhDk1hbHRhIGFuZCBHb3pvBk1leGljbw1NaWR3YXkgSXNsYW5kB01vbGRvdmEGTW9uYWNvCk1vbnRlbmVncm8KTW9udHNlcnJhdAdNb3JvY2NvC05ldGhlcmxhbmRzFE5ldGhlcmxhbmRzIEFudGlsbGVzC05ldyBaZWFsYW5kCU5pY2FyYWd1YQdOaWdlcmlhBk5vcndheQRPbWFuBlBhbmFtYQhQYXJhZ3VheQRQZXJ1C1BoaWxpcHBpbmVzBlBvbGFuZAhQb3J0dWdhbAtQdWVydG8gUmljbwVRYXRhchFSZXB1YmxpYyBvZiBZZW1lbgdSb21hbmlhBlJ1c3NpYQtTYWludCBMdWNpYQxTYXVkaSBBcmFiaWEGU2VyYmlhCVNpbmdhcG9yZQ9TbG92YWsgUmVwdWJsaWMIU2xvdmVuaWEMU291dGggQWZyaWNhC1NvdXRoIEtvcmVhBVNwYWluDVN0IEJhcnRoZWxlbXkJU3QgTWFydGluEVN0LiBLaXR0cyAtIE5ldmlzHlN0LiBWaW5jZW50IGFuZCB0aGUgR3JlbmFkaW5lcwhTdXJpbmFtZQZTd2VkZW4LU3dpdHplcmxhbmQGVGFpd2FuCFRoYWlsYW5kE1RyaW5pZGFkIGFuZCBUb2JhZ28HVHVuaXNpYQZUdXJrZXkUVHVya3MgYW5kIENhaWNvcyBJc2wZVVMgTWlub3IgT3V0bHlpbmcgSXNsYW5kcwdVa3JhaW5lFFVuaXRlZCBBcmFiIEVtaXJhdGVzDlVuaXRlZCBLaW5nZG9tDVVuaXRlZCBTdGF0ZXMHVXJ1Z3VheQlWZW5lenVlbGEHVmlldG5hbRhWaXJnaW4gSXNsYW5kcyBvZiB0aGUgVVMXVmlyZ2luIElzbGFuZHMsIEJyaXRpc2gLV2FrZSBJc2xhbmQKWXVnb3NsYXZpYRWCAQtTRUxFQ1QgT05FPgJBTAJEWgJBSQJBRwJBUgJBVwJBVQJBVAJBWgJCUwJCSAJCQgJCWQJCRQJCWgJCTQJCTwJCQQJCUgJCRwJDQQJDVAJLWQJDTAJDTgJDTwJDRwJDUgJIUgJDWQJDWgJESwJETQJETwJFRQJFQwJFRwJTVgJFVQJGSwJGSQJGUgJERQJHUgJHRAJHVQJHVAJHWQJIVAJITgJISwJIVQJJTgJJRAJJUQJJRQJJTAJJVAJKTQJKUAJKTwJLWgJLRQJLVwJMQQJMQgJMVQJNSwJNWQJNVAJNWAJNSQJNRAJNQwJNRQJNUwJNQQJOTAJBTgJOWgJOSQJORwJOTwJPTQJQQQJQWQJQRQJQSAJQTAJQVAJQUgJRQQJZRQJSTwJSVQJMQwJTQQJSUwJTRwJTSwJTSQJaQQJLUgJFUwJCTAJNRgJLTgJWQwJTUgJTRQJDSAJUVwJUSAJUVAJUTgJUUgJUQwJVTQJVQQJBRQJHQgJVUwJVWQJWRQJWTgJWSQJWRwJXSwJZVRQrA4IBZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2RkAhgPZBYEZg9kFg4CAQ9kFgJmD2QWBAIFDw9kFgIeB09uQ2xpY2sFHmphdmFzY3JpcHQ6Y2hlY2tDb3VudHJ5KGV2ZW50KWQCCw9kFgICAw8WAh4Fc3R5bGUFDGNvbG9yOmJsYWNrO2QCBw8WAh8CaGQCCQ8WAh8CZxYKZg8WAh8CZxYCZg9kFgQCAQ8PFgQfAQUPU2VyaWFsIE51bWJlciA6HwJnZGQCAw8PFgIfAQUKQ05VMzQ5QkRURGRkAgEPFgIfAmgWAmYPZBYCAgEPDxYCHwFlZGQCAg8WAh8CZxYCZg8WAh8CaBYCAgEPDxYCHwFlZGQCAw9kFgJmD2QWBAIBDw8WAh8CaGRkAgMPDxYCHwJoZGQCBA9kFgJmD2QWAgIBDw8WBB8BBR8qIFBSRUxJTUlOQVJZIFVORU5IQU5DRUQgREFUQSAqHwJoZGQCDQ8WAh8CaGQCDw9kFgICAw88KwANAgAPFgQfCWceC18hSXRlbUNvdW50ZmQMFCsAAGQCEQ9kFgYCAQ8WAh4FY2xhc3NlZAIDDxYCHw8FLmpzX3RhYl90cmlnZ2VyIHRhYl90cmlnZ2VyIGN1cnJlbnRfZnN0IGN1cnJlbnRkAgUPZBYEZg9kFgYCAQ8WAh8NBQ1kaXNwbGF5OiBub25lFgICAQ9kFg4CAQ8QDxYCHwlnZBAVABUAFCsDABYAZAIDDxAPFgIeB0NoZWNrZWRoZGRkZAIFDxAPFgIfEGhkZGRkAgcPEA8WAh8JZ2QQFQAVABQrAwAWAGQCCQ8QZGQWAWZkAgsPEGRkFgBkAg0PEA8WBB4FV2lkdGgbAAAAAADAYkABAAAAHwYCgAJkEBUAFQAUKwMAFgBkAgIPZBYCAgEPEGRkFgBkAgUPDxYCHwFlZGQCAQ9kFgYCBw9kFgJmDxYCHw0FDiBkaXNwbGF5OiBub25lFgICAQ9kFgoCAQ8QDxYCHwlnZBAVABUAFCsDABYAZAIDDxAPFgIfEGhkZGRkAgUPEGRkFgFmZAIHDxBkZBYAZAINDxAPFgQfERsAAAAAAMBiQAEAAAAfBgKAAmQQFQAVABQrAwAWAGQCCQ9kFgICAQ88KwANAQAPFgQfCWcfDmZkZAILD2QWAgIBDzwrAA0BAA8WBB8JZx8OZmRkAhMPDxYCHwJnZBYEAgMPDxYCHwEFCkNOVTM0OUJEVERkZAIFDxAPFgIfCWdkEBUCJ0M3TTMxVVAgLSBFODQ3MHBVNTMzNk1NTjE4ME1JQzA4TmVTIEFMTCpDN00zMVVQI0FCQSAtIEU4NDcwcFU1MzM2TU1OMTgwTUlDMDhOZVMgVVMVAgdDN00zMVVQC0M3TTMxVVAjQUJBFCsDAmdnZGQCAQ9kFgICAQ9kFgJmD2QWCgIDDxQrAAJkZGQCBQ8UKwACZGRkAgcPPCsACQEADxYCHg1OZXZlckV4cGFuZGVkZ2RkAgoPFCsAAmRkZAIMDxQrAAJkZGQCEw8PFgQfAQUZRmVlZGJhY2sgdG8gSFAgUGFydFN1cmZlch4QQ2F1c2VzVmFsaWRhdGlvbmhkZBgKBShjdGwwMCRCb2R5Q29udGVudFBsYWNlSG9sZGVyJFByb2R1Y3RMaXN0D2dkBSdjdGwwMCRCb2R5Q29udGVudFBsYWNlSG9sZGVyJE11bHRpVmlldzEPD2RmZAUpY3RsMDAkQm9keUNvbnRlbnRQbGFjZUhvbGRlciRncmlkU3BhcmVCT00PPCsACgEIZmQFKmN0bDAwJEJvZHlDb250ZW50UGxhY2VIb2xkZXIkSGllcmFyY2h5TGlzdA9nZAUmY3RsMDAkQm9keUNvbnRlbnRQbGFjZUhvbGRlciRndkdlbmVyYWwPPCsACgIGFQELUEFSVF9OVU1CRVIIZmQFHl9fQ29udHJvbHNSZXF1aXJlUG9zdEJhY2tLZXlfXxYCBSdjdGwwMCRCb2R5Q29udGVudFBsYWNlSG9sZGVyJFNDYXJ0JEhvbWUFJ2N0bDAwJEJvZHlDb250ZW50UGxhY2VIb2xkZXIkU0NhcnQkY2FydAUtY3RsMDAkQm9keUNvbnRlbnRQbGFjZUhvbGRlciRUb3BIaWVyYXJjaHlMaXN0D2dkBSdjdGwwMCRCb2R5Q29udGVudFBsYWNlSG9sZGVyJGdyaWRDT01CT00PPCsACgEIZmQFLWN0bDAwJEJvZHlDb250ZW50UGxhY2VIb2xkZXIkSGllcmFyY2h5VG9wTGlzdA9nZAUnY3RsMDAkQm9keUNvbnRlbnRQbGFjZUhvbGRlciRNdWx0aVZpZXcyDw9kAgFke9jF3YWEcTMlFAPpXsH4fUOKOmw" #$postData += "&__PREVIOUSPAGE=uel1OJqwRzAzE7TWcjP1qs5L_mZbu5sqD7lqKYLrWJW8jPPUiBIirA7ZvP81" <# $postData += "ctl00`$BodyContentPlaceHolder`$hType=" $postData += "&ctl00`$BodyContentPlaceHolder`$hCountry=" $postData += "&ctl00`$BodyContentPlaceHolder`$hdnPSP=" $postData += "&ctl00`$BodyContentPlaceHolder`$hdnBuyPart=" $postData += "&ctl00`$BodyContentPlaceHolder`$hdnPSPType=" $postData += "&ctl00`$BodyContentPlaceHolder`$hdnPartNo=" $postData += "&ctl00`$BodyContentPlaceHolder`$hdnFileName=" $postData += "&ctl00`$BodyContentPlaceHolder`$hdnSearchText=$($SerialNumber)" $postData += "&ctl00`$BodyContentPlaceHolder`$hHPPSFlag=Y" $postData += "&ctl00`$BodyContentPlaceHolder`$hdnstrType=SERIAL" $postData += "&ctl00`$BodyContentPlaceHolder`$hdnMULTI_PART=" $postData += "&ctl00`$BodyContentPlaceHolder`$hdnAddPartsFlag=N" $postData += "&ctl00`$BodyContentPlaceHolder`$txtOutlet_id=" $postData += "&ctl00`$BodyContentPlaceHolder`$ddlCountry=$($abbrRegionName)" $postData += "&ctl00`$BodyContentPlaceHolder`$hdDIVButton=0" $postData += "&ctl00`$BodyContentPlaceHolder`$SearchText`$TextBox1=$($SerialNumber)" $postData += "&ctl00`$BodyContentPlaceHolder`$radProd=$($fullSku)" $postData += "&ctl00`$BodyContentPlaceHolder`$btnProdSubmit= View Selected Product Details " $postData += "&ctl00`$BodyContentPlaceHolder`$hiddenEnhancedStatus=" #> #$postData += "&ctl00`$BodyContentPlaceHolder`$SearchText`$TextBox1=$($SerialNumber)" $postData += "&ctl00`$BodyContentPlaceHolder`$btnProdSubmit= View Selected Product Details " $postData += "&ctl00`$BodyContentPlaceHolder`$ddlCountry=$($abbrRegionName)" Write-Debug "Post header complete. Submitting..." $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 ) IF ( $Script:PSBoundParameters.ContainsKey("Debug") ) { Write-Debug "Raw HTML written to cache" Set-Content (Join-Path $cacheDir "$($SerialNumber).raw.html") $htData } } WHILE ( $htData -match 'type="radio"' ) } ELSE { Write-Error "Multiple serial# matches, and we weren't able to determine the correct one." } <#Gets posted back to the same query URL ctl00$BodyContentPlaceHolder$hdnSearchText:"CNU349BDTD" ctl00$BodyContentPlaceHolder$hHPPSFlag:"Y" ctl00$BodyContentPlaceHolder$hdnstrType:"SERIAL" ctl00$BodyContentPlaceHolder$hdnAddPartsFlag:"N" ctl00$BodyContentPlaceHolder$ddlCountry:"US" ctl00$BodyContentPlaceHolder$hdDIVButton:"0" ctl00$BodyContentPlaceHolder$SearchText$TextBox1:"CNU349BDTD" ctl00$BodyContentPlaceHolder$radProd:"C7M31UP#ABA" ctl00$BodyContentPlaceHolder$btnProdSubmit:"+View+Selected+Product+Details+" #> } 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." } } $warrAttempts = 0 $trMatches = "" DO { sleep ( 15 + $warrAttempts * 3 ) Write-Debug "Create POST request to retrieve warranty 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" $postData = "rows[0].item.serialNumber=$($SerialNumber)&rows[0].item.countryCode=$($abbrRegionName)&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 "" -inputObject $htData -AllMatches } WHILE ( $warrAttempts -lt 6 -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 "" -inputObject $trMatch -AllMatches $warrData = $tdMatches.Matches | % { $_.value -replace "]*>" -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:yyyy-MM-dd}' -f ( Get-Date $warrData[1] ) ) $warrObject | Add-Member NoteProperty End ( '{0:yyyy-MM-dd}' -f ( Get-Date $warrData[2] ) ) $hpProduct.Warranties | Add-Member NoteProperty $warrData[0] $warrObject Write-Debug "Added Warranty: $($warrData[0]) - $( '{0:yyyy-MM-dd}' -f ( Get-Date $warrData[1] ) ) to $( '{0:yyyy-MM-dd}' -f ( Get-Date $warrData[2] ) )" } 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 } } }