Automating with PowerShell: Automating Warranty information reporting.

One of the reddits I frequent has been seeing a lot of complaints lately about warranty information being incomplete or there’s complaints about the pricing of warranty information products. Most of these complaints are aimed at a specific product which is showing very shady sales tactics and general bad business practices lately.

I figured I would try to take up these complaints and solve them with a PowerShell script. This script grabs the warranty information for most major manufactures. It will generate a warranty report based on the input data. The input data can either be a CSV file or the Autotask PSA.

You can also upload the warranty date back to Autotask to keep your warranty information in sync too. Currently I’ve only made support for Autotask but I’m willing to create one for CW too if there is enough interest πŸ™‚

So lets get started.

Prerequisites

Before we can dive into the script we’ll have to collect some API keys. These keys will be used to get the warranty information at the vendors, or there are some “gotcha’s” you must know beforehand.

When you have Dell as a vendor:

  • Go to the Dell TechDirect website and register if you do not yet have an account. Complete the enrollment.
  • After registration, browse to the Dell TechDirect API enrollment page and wait for approval. This is a manual procedure so can take a day or two.
  • When the approval has been given, request a new API key and save this in a secure location.

When you have HP as a vendor:

Officially the HP API has been disabled because it was getting hammered by requests. The unofficial API is still available though so this script is based on that API.

When you have Microsoft as a vendor:

So Microsoft officially does not have a warranty lookup tool, but I found the Surface Diagnostic App does have a way to have programmatic access to the warranty environment. I reverse engineered this method. This is an unofficial and unsupported API so it might not function in the future. I’m quite proud of this one because as far as I can see, people have only achieved MS warranty checks by evading the CAPTCHA.

When you have Lenovo as a vendor:

You don’t have to do anything πŸ™‚ Lenovo has an open API.

The Script

So now that we have our API keys and data, we can start feeding the script information. This can be via a CSV file or via Autotask. The CSV file should have the following information:

serialnumber,vendor,client
1234,HP,contoso
1234,Dell,toiletpaperco
1234,MS,contoso
1234,Lenovo,johndoe inc

If you are using Autotask, fill in the API integration key from your API user, and log in when your username/password is requested.

$source = "CSV" #AT, CSV, ITG, CW
##### Sync Settings
$SyncWithSource = $true  #Sync status warranty dates/status back to PSA/Management system. Only works with dynamic sources like ITG and AT.
$OverwriteWarranty = $true #Overwrites the date already found in AT with the one based on this API, unless the API could not find information.
$CreateHTMLReport = $true #Creates an HTML report.
###### File locations
$ReportsLocation = "C:\temp\reports" #Only required if Reporting is enabled.
$sourcefile = "C:\temp\temp.csv" #only required if source is not autotask.
$ATLogPath = "C:\temp\AT.txt" #Only used to log which objects have been synced with AT as AT does not have a audit log.
##### AT API Settings
$ATAPIKey = "Your-API-Key-For-Autotask" #only required if source is Autotask.
##### ITG API Settings
$ITGAPIKey = "Your-API-Key-For-ITG"  #only required if source is ITG
$ITGAPIURL = "https://api.eu.itglue.com" #only required if source is ITG
##### CW API Settings
$CWAPIURL = "https://api-staging.connectwisedev.com/v4_6_release/apis/3.0" #https://developer.connectwise.com/Best_Practices/Manage_Cloud_URL_Formatting?mt-learningpath=manage
$CWApiKeyPublic = "CWPublicKey" #Only required if source is CW
$CWApiKeyPrivate = "CwPrivateKey" #Only required if source is CW
$CWcompanyid = "CompanyID_1" #Only required if source is CW
##### Warranty Vendor API Keys
$DellClientID = "Dell-Client-ID"
$DellClientSecret = "Dell-Client-Secret"



function get-HPWarranty([Parameter(Mandatory = $true)]$SourceDevice, $Client) {
    $MWSID = (invoke-restmethod -uri 'https://support.hp.com/us-en/checkwarranty/multipleproducts/' -SessionVariable 'session' -Method get) -match '.*mwsid":"(?<wssid>.*)".*'
    $HPBody = " { `"gRecaptchaResponse`":`"`", `"obligationServiceRequests`":[ { `"serialNumber`":`"$SourceDevice`", `"isoCountryCde`":`"US`", `"lc`":`"EN`", `"cc`":`"US`", `"modelNumber`":null }] }"
 
    $HPReq = Invoke-RestMethod -Uri "https://support.hp.com/hp-pps-services/os/multiWarranty?ssid=$($matches.wssid)" -WebSession $session -Method "POST" -ContentType "application/json" -Body $HPbody
    if ($HPreq.productWarrantyDetailsVO.warrantyResultList.obligationStartDate) {
        $WarObj = [PSCustomObject]@{
            'Serial'                = $SourceDevice
            'Warranty Product name' = $hpreq.productWarrantyDetailsVO.warrantyResultList.warrantyType | Out-String
            'StartDate'             = $hpreq.productWarrantyDetailsVO.warrantyResultList.obligationStartDate | sort-object | select-object -last 1
            'EndDate'               = $hpreq.productWarrantyDetailsVO.warrantyResultList.obligationEndDate | sort-object | select-object -last 1
            'Warranty Status'       = $hpreq.productWarrantyDetailsVO.obligationStatus
            'Client'                = $Client
        }
    }
    else {
        $WarObj = [PSCustomObject]@{
            'Serial'                = $SourceDevice
            'Warranty Product name' = 'Could not get warranty information'
            'StartDate'             = $null
            'EndDate'               = $null
            'Warranty Status'       = 'Could not get warranty information'
            'Client'                = $Client
        }
    }
    return $WarObj
}
function get-DellWarranty([Parameter(Mandatory = $true)]$SourceDevice, $client) {
    $today = Get-Date -Format yyyy-MM-dd
    $AuthURI = "https://apigtwb2c.us.dell.com/auth/oauth/v2/token"
    if ($Global:TokenAge -lt (get-date).AddMinutes(-55)) { $global:Token = $null }
    If ($null -eq $global:Token) {
        $OAuth = "$global:DellClientID`:$global:DellClientSecret"
        $Bytes = [System.Text.Encoding]::ASCII.GetBytes($OAuth)
        $EncodedOAuth = [Convert]::ToBase64String($Bytes)
        $headersAuth = @{ "authorization" = "Basic $EncodedOAuth" }
        $Authbody = 'grant_type=client_credentials'
        $AuthResult = Invoke-RESTMethod -Method Post -Uri $AuthURI -Body $AuthBody -Headers $HeadersAuth
        $global:token = $AuthResult.access_token
        $Global:TokenAge = (get-date)
    }

    $headersReq = @{ "Authorization" = "Bearer $global:Token" }
    $ReqBody = @{ servicetags = $SourceDevice }
    $WarReq = Invoke-RestMethod -Uri "https://apigtwb2c.us.dell.com/PROD/sbil/eapi/v5/asset-entitlements" -Headers $headersReq -Body $ReqBody -Method Get -ContentType "application/json"
    $warlatest = $warreq.entitlements.enddate | sort-object | select-object -last 1 
    $WarrantyState = if ($warlatest -le $today) { "Expired" } else { "OK" }
    if ($warreq.entitlements.serviceleveldescription) {
        $WarObj = [PSCustomObject]@{
            'Serial'                = $SourceDevice
            'Warranty Product name' = $warreq.entitlements.serviceleveldescription -join "`n"
            'StartDate'             = (($warreq.entitlements.startdate | sort-object -Descending | select-object -last 1) -split 'T')[0]
            'EndDate'               = (($warreq.entitlements.enddate | sort-object | select-object -last 1) -split 'T')[0]
            'Warranty Status'       = $WarrantyState
            'Client'                = $Client
        }
    }
    else {
        $WarObj = [PSCustomObject]@{
            'Serial'                = $SourceDevice
            'Warranty Product name' = 'Could not get warranty information'
            'StartDate'             = $null
            'EndDate'               = $null
            'Warranty Status'       = 'Could not get warranty information'
            'Client'                = $Client
        }
    }
    return $WarObj
}
function get-LenovoWarranty([Parameter(Mandatory = $true)]$SourceDevice, $client) {
    $today = Get-Date -Format yyyy-MM-dd
    $APIURL = "https://ibase.lenovo.com/POIRequest.aspx"
    $SourceXML = "xml=<wiInputForm source='ibase'><id>LSC3</id><pw>IBA4LSC3</pw><product></product><serial>$SourceDevice</serial><wiOptions><machine/><parts/><service/><upma/><entitle/></wiOptions></wiInputForm>"
    $Req = Invoke-RestMethod -Uri $APIURL -Method POST -Body $SourceXML -ContentType 'application/x-www-form-urlencoded'
    if ($req.wiOutputForm) {
        $warlatest = $Req.wiOutputForm.warrantyInfo.serviceInfo.wed | sort-object | select-object -last 1 
        $WarrantyState = if ($warlatest -le $today) { "Expired" } else { "OK" }
         
        $WarObj = [PSCustomObject]@{
            'Serial'                = $Req.wiOutputForm.warrantyInfo.machineinfo.serial
            'Warranty Product name' = $Req.wiOutputForm.warrantyInfo.machineinfo.productname -join "`n"
            'StartDate'             = $Req.wiOutputForm.warrantyInfo.serviceInfo.warstart | sort-object -Descending | select-object -last 1
            'EndDate'               = $Req.wiOutputForm.warrantyInfo.serviceInfo.wed | sort-object | select-object -last 1
            'Warranty Status'       = $WarrantyState
            'Client'                = $Client
        }
    }
    else {
        $WarObj = [PSCustomObject]@{
            'Serial'                = $SourceDevice
            'Warranty Product name' = 'Could not get warranty information'
            'StartDate'             = $null
            'EndDate'               = $null
            'Warranty Status'       = 'Could not get warranty information'
            'Client'                = $Client
        }
    }
    return $WarObj
 
 
}
function Get-MSWarranty([Parameter(Mandatory = $true)]$SourceDevice, $client) {
    $body = ConvertTo-Json @{
        sku          = "Surface_"
        SerialNumber = $SourceDevice
        ForceRefresh = $false
    }
    $today = Get-Date -Format yyyy-MM-dd
    $PublicKey = Invoke-RestMethod -Uri 'https://surfacewarrantyservice.azurewebsites.net/api/key' -Method Get
    $AesCSP = New-Object System.Security.Cryptography.AesCryptoServiceProvider 
    $AesCSP.GenerateIV()
    $AesCSP.GenerateKey()
    $AESIVString = [System.Convert]::ToBase64String($AesCSP.IV)
    $AESKeyString = [System.Convert]::ToBase64String($AesCSP.Key)
    $AesKeyPair = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes("$AESIVString,$AESKeyString"))
    $bodybytes = [System.Text.Encoding]::UTF8.GetBytes($body)
    $bodyenc = [System.Convert]::ToBase64String($AesCSP.CreateEncryptor().TransformFinalBlock($bodybytes, 0, $bodybytes.Length))
    $RSA = New-Object System.Security.Cryptography.RSACryptoServiceProvider
    $RSA.ImportCspBlob([System.Convert]::FromBase64String($PublicKey))
    $EncKey = [System.Convert]::ToBase64String($rsa.Encrypt([System.Text.Encoding]::UTF8.GetBytes($AesKeyPair), $false))
     
    $FullBody = @{
        Data = $bodyenc
        Key  = $EncKey
    } | ConvertTo-Json
     
    $WarReq = Invoke-RestMethod -uri "https://surfacewarrantyservice.azurewebsites.net/api/v2/warranty" -Method POST -body $FullBody -ContentType "application/json"
    if ($WarReq.warranties) {
        $WarrantyState = foreach ($War in ($WarReq.warranties.effectiveenddate -split 'T')[0]) {
            if ($War -le $today) { "Expired" } else { "OK" }
        }
        $WarObj = [PSCustomObject]@{
            'Serial'                = $SourceDevice
            'Warranty Product name' = $WarReq.warranties.name -join "`n"
            'StartDate'             = (($WarReq.warranties.effectivestartdate | sort-object -Descending | select-object -last 1) -split 'T')[0]
            'EndDate'               = (($WarReq.warranties.effectiveenddate | sort-object | select-object -last 1) -split 'T')[0]
            'Warranty Status'       = $WarrantyState
            'Client'                = $Client
        }
    }
    else {
        $WarObj = [PSCustomObject]@{
            'Serial'                = $SourceDevice
            'Warranty Product name' = 'Could not get warranty information'
            'StartDate'             = $null
            'EndDate'               = $null
            'Warranty Status'       = 'Could not get warranty information'
            'Client'                = $Client
        }
    }
    return $WarObj
}
 
function  Get-WarrantyCSV($sourcefile) {
    write-host "Source is CSV file. Grabbing all devices." -ForegroundColor Green
    $CSVLines = import-csv -path $sourcefile -Delimiter ","
    $warrantyObject = foreach ($Line in $CSVLines) {
        switch ($line.vendor) {
            HP { get-HPWarranty -SourceDevice $line.SerialNumber -Client $line.client }
            Dell { get-DellWarranty -SourceDevice $line.SerialNumber -Client $line.client }
            Lenovo { get-LenovoWarranty -SourceDevice $line.SerialNumber -Client $line.client }
            MS { Get-MSWarranty -SourceDevice $line.SerialNumber -Client $line.client }
        }
    }
    return $warrantyObject
}
 
function Get-WarrantyAutotask($APIKey) {
    write-host "Source is Autotask." -ForegroundColor Green
    If (Get-Module -ListAvailable -Name "Autotask") { Import-module "Autotask" } Else { install-module "Autotask" -Force }
    $Credential = Get-Credential -Message "Enter your Autotask Credentials"
    remove-module autotask
    Import-Module Autotask -ArgumentList $Credential, $global:ATAPIKey
    write-host "Logging into Autotask. Grabbing all client information." -ForegroundColor "Green"
    $AllClients = $AllAccounts = Get-AtwsAccount -All | Where-Object { $_.Active -eq $true }
    write-host "Client information found. Grabbing all devices" -ForegroundColor "Green"
    $AllDevices = Get-AtwsInstalledProduct -All | Where-Object { $_.Active -eq $true -and $null -ne $_.SerialNumber }
    write-host "Collecting information. This can take a long time." -ForegroundColor "Green"
    $i = 0
    $warrantyObject = foreach ($Device in $AllDevices) {
        $i++
        Write-Progress -Activity "Grabbing Warranty information" -status "Processing $($device.serialnumber). Device $i of $($Alldevices.Count)" -percentComplete ($i / $Alldevices.Count * 100)
        $Client = ($AllClients | Where-Object { $_.id -eq $device.AccountID }).AccountName
        #We use a guess-smart method for serialnumbers. 
        #Dell is always 7, Lenovo is always 8, 10 is HP, 12 is Surface. 
        #This is because we cannot safely find the manafacture in the AT info.
        switch ($device.SerialNumber.Length) {
            7 { $WarState = get-DellWarranty -SourceDevice $device.SerialNumber -client $Client }
            8 { $WarState = get-LenovoWarranty -SourceDevice $device.SerialNumber -client $Client }
            10 { $WarState = get-HPWarranty  -SourceDevice $device.SerialNumber -client $Client }
            12 { $WarState = Get-MSWarranty  -SourceDevice $device.SerialNumber -client $Client }
        }
        if ($script:SyncWithSource -eq $true) {
            switch ($script:OverwriteWarranty) {
                $true {
                    if ($null -ne $warstate.EndDate) {
                        $device | Set-AtwsInstalledProduct -WarrantyExpirationDate $warstate.EndDate
                        "$Client / $($device.SerialNumber) with AT ID $($device.id) warranty has been overwritten to $($warstate.EndDate)" | out-file $script:ATLogPath -Append -Force
                    }
                     
                }
                $false { 
                    if ($null -eq $device.WarrantyExpirationDate -and $null -ne $warstate.EndDate) { 
                        $device | Set-AtwsInstalledProduct -WarrantyExpirationDate $warstate.EndDate 
                        "$Client / $($device.SerialNumber) with AT ID $($device.id) warranty has been set to $($warstate.EndDate)" | out-file $script:ATLogPath -Append -Force
                    } 
                }
            }
        }
        $WarState
    }
 
    return $warrantyObject
}
function  Get-WarrantyITG() {
    write-host "Source is IT-Glue. Grabbing all devices." -ForegroundColor Green
    If (Get-Module -ListAvailable -Name "ITGlueAPI") { 
        Import-module ITGlueAPI 
    }
    Else { 
        Install-Module ITGlueAPI -Force
        Import-Module ITGlueAPI
    }
    #Settings IT-Glue logon information
    Add-ITGlueBaseURI -base_uri $Global:ITGAPIURL
    Add-ITGlueAPIKey  $Global:ITGAPIKey
    write-host "Getting IT-Glue configuration list" -foregroundColor green
    $i = 0
    $AllITGlueConfigs = @()
    do {
        $AllITGlueConfigs += (Get-ITglueconfigurations -page_size 1000 -page_number $i).data
        $i++
        Write-Host "Retrieved $($AllITGlueConfigs.count) configurations" -ForegroundColor Yellow
    }while ($AllITGlueConfigs.count % 1000 -eq 0 -and $AllITGlueConfigs.count -ne 0) 
     
    $warrantyObject = foreach ($device in $AllITGlueConfigs) {
        $i++
        Write-Progress -Activity "Grabbing Warranty information" -status "Processing $($device.attributes.'serial-number'). Device $i of $($AllITGlueConfigs.Count)" -percentComplete ($i / $AllITGlueConfigs.Count * 100)
        $Client = ($AllClients | Where-Object { $_.id -eq $device.AccountID }).AccountName
        $client = $device.attributes.'organization-name'
        switch ($device.attributes.'serial-number'.Length) {
            7 { $WarState = get-DellWarranty -SourceDevice $device.attributes.'serial-number' -client $Client }
            8 { $WarState = get-LenovoWarranty -SourceDevice $device.attributes.'serial-number' -client $Client }
            10 { $WarState = get-HPWarranty  -SourceDevice $device.attributes.'serial-number' -client $Client }
            12 { $WarState = Get-MSWarranty  -SourceDevice $device.attributes.'serial-number' -client $Client }
        }
        if ($script:SyncWithSource -eq $true) {
            $FlexAssetBody = @{
                "type"       = "configurations"
                "attributes" = @{
                    'warranty-expires-at' = $warstate.EndDate
                } 
            }
            switch ($script:OverwriteWarranty) {
                $true {
                    if ($null -ne $warstate.EndDate) {
                        Set-ITGlueConfigurations -id $device.id -data $FlexAssetBody
                    }
                     
                }
                $false { 
                    if ($null -eq $device.WarrantyExpirationDate -and $null -ne $warstate.EndDate) { 
                        Set-ITGlueConfigurations -id $device.id -data $FlexAssetBody
                    } 
                }
            }
        }
        $WarState
    }
    return $warrantyObject
}
 
function  Get-WarrantyCW() {
    write-host "Source is Connectwise Manage. Grabbing all devices." -ForegroundColor Green
    $Base64Key = [Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes("$($Global:CWcompanyid)+$($Global:CWApiKeyPublic):$($global:CWApiKeyPrivate)"))
 
    $Header = @{
        'clientId'      = '3613dda6-fa25-49b9-85fb-7aa2b628befa' #This is the warranty script client id. Do not change. 
        'Authorization' = "Basic $Base64Key"
        'Content-Type'  = 'application/json'
    }
    $i = 0
    $Devices = @()
    do {
        $Devices += invoke-restmethod -headers $header -method GET -uri "$($Global:CWAPIURL)/company/configurations?pageSize=1000&page=$i"
        $i++
        Write-Host "Retrieved $($devices.count) configurations" -ForegroundColor Yellow
    }while ($devices.count % 1000 -eq 0 -and $devices.count -ne 0) 
 
    $warrantyObject = foreach ($device in $Devices) {
        $i++
        Write-Progress -Activity "Grabbing Warranty information" -status "Processing $($device.serialnumber). Device $i of $($devices.Count)" -percentComplete ($i / $Devices.Count * 100)
        $client = $device.company.name
        switch ($device.serialnumber.Length) {
            7 { $WarState = get-DellWarranty -SourceDevice $device.serialnumber -client $Client }
            8 { $WarState = get-LenovoWarranty -SourceDevice $device.serialnumber -client $Client }
            10 { $WarState = get-HPWarranty  -SourceDevice $device.serialnumber -client $Client }
            12 { $WarState = Get-MSWarranty  -SourceDevice $device.serialnumber -client $Client }
        }
        if ($script:SyncWithSource -eq $true) {
            if (!$device.warrantyExpirationDate) {
                $device | Add-Member -NotePropertyName "warrantyExpirationDate" -NotePropertyValue "$($WarState.enddate)T00:00:00Z"
            }
            else { 
                $device.warrantyExpirationDate = "$($WarState.enddate)T00:00:00Z"
            }
            $CWBody = $device | ConvertTo-Json
            switch ($script:OverwriteWarranty) {
                $true {
                    if ($null -ne $warstate.EndDate) {
                        invoke-restmethod -headers $header -method put -uri "$($Global:CWAPIURL)/company/configurations/$($device.id)" -body $CWBody
                    }
                     
                }
                $false { 
                    if ($null -eq $device.WarrantyExpirationDate -and $null -ne $warstate.EndDate) { 
                        invoke-restmethod -headers $header -method put -uri "$($Global:CWAPIURL)/company/configurations/$($device.id)" -body $CWBody
                    } 
                }
            }
        }
        $WarState
    }
    return $warrantyObject
}
 
 
switch ($source) {
    AT { $warrantyObject = Get-WarrantyAutotask -APIKey $ATAPIKey | Sort-Object -Property Client }
    CSV { $warrantyObject = Get-WarrantyCSV -Sourcefile $sourcefile | Sort-Object -Property Client }
    ITG { $warrantyObject = Get-WarrantyITG | Sort-Object -Property Client }
    CW { $warrantyObject = Get-WarrantyCW | Sort-Object -Property Client }
}
write-host "Done updating warrenties. Generating reports if required." -ForegroundColor Green
$head = @"
<script>
function myFunction() {
    const filter = document.querySelector('#myInput').value.toUpperCase();
    const trs = document.querySelectorAll('table tr:not(.header)');
    trs.forEach(tr => tr.style.display = [...tr.children].find(td => td.innerHTML.toUpperCase().includes(filter)) ? '' : 'none');
  }</script>
<Title>Warranty Report</Title>
<style>
body { background-color:#E5E4E2;
      font-family:Monospace;
      font-size:10pt; }
td, th { border:0px solid black; 
        border-collapse:collapse;
        white-space:pre; }
th { color:white;
    background-color:black; }
table, tr, td, th {
     padding: 2px; 
     margin: 0px;
     white-space:pre; }
tr:nth-child(odd) {background-color: lightgray}
table { width:95%;margin-left:5px; margin-bottom:20px; }
h2 {
font-family:Tahoma;
color:#6D7B8D;
}
.footer 
{ color:green; 
 margin-left:10px; 
 font-family:Tahoma;
 font-size:8pt;
 font-style:italic;
}
#myInput {
  background-image: url('https://www.w3schools.com/css/searchicon.png'); /* Add a search icon to input */
  background-position: 10px 12px; /* Position the search icon */
  background-repeat: no-repeat; /* Do not repeat the icon image */
  width: 50%; /* Full-width */
  font-size: 16px; /* Increase font-size */
  padding: 12px 20px 12px 40px; /* Add some padding */
  border: 1px solid #ddd; /* Add a grey border */
  margin-bottom: 12px; /* Add some space below the input */
}
</style>
"@
   
$PreContent = @"
<H1> Warranty Report </H1> <br>
   
Please consult the report for more information. you can use the search window to find a specific device, date, or warranty state.
<br/>
<br/>
    
<input type="text" id="myInput" onkeyup="myFunction()" placeholder="Search...">
"@
   
 
if ($CreateHTMLReport -eq $true) {
    $CheckReportFolder = Test-Path($ReportsLocation)
    if (!$CheckReportFolder) { new-item -ItemType Directory -Path $ReportsLocation -Force | Out-Null }
    foreach ($client in $warrantyObject.client | Select-Object -Unique) {
        write-host "Generating report for $Client at $($ReportsLocation)\$client.html" -ForegroundColor Green
        $warrantyObject | Where-Object { $_.Client -eq $client } | convertto-html -Head $head -precontent $precontent | out-file "$($ReportsLocation)\$client.html"
    }
 
}

After executing the script, the HTML reports will look like this:

And that’s it! the script isn’t perfect yet and could use some more error handling which I’ll work on in the coming weeks but I really think this is a fantastic solution to get rid of warranty information providers that are asking big bucks. πŸ™‚

So as always, Happy PowerShelling!

Update 1: Added ITGlue as source.

Update 2: Added CW as resource

Update 3: Added some better logic for the script, also the script is on Github now! https://github.com/KelvinTegelaar/PowerShellWarrantyReports

139 Comments

  1. Robin Thomas May 4, 2020 at 1:38 pm

    So I just ran the script and it updated all my datto resources. This is pretty dang cool. Thanks Kevin! We’re canceling our warranty master subscription now.

    1. Tim Bixley May 5, 2020 at 9:25 am

      Thanks Kevin, we will be testing this shortly to hopefully remove warrantymaster. Do you know if it can write the data back to Datto RMM even if via the PSA writeback?

      1. Kelvin Tegelaar May 5, 2020 at 11:38 am

        I have no clue! I’ll ask one of my contacts at Datto :). Its Kelvin by the way, not Kevin πŸ™‚

    2. Kelvin Tegelaar May 5, 2020 at 11:39 am

      Hi Robin,

      Its Kelvin, not Kevin πŸ™‚ Glad I helped!

  2. Krystal May 6, 2020 at 3:42 pm

    Thank you so much for sharing. Definitely interested and would appreciate if there was one for Connectiwse. Please let me know

  3. Chelsea May 7, 2020 at 7:50 pm

    Hi! Thanks for creating such a cool tool for everyone to use!
    I was wondering if this integrates with Ninja PSA?
    Thanks!
    Chelsea

  4. Chelsea May 7, 2020 at 8:05 pm

    Oops!! I asked if you had Ninja PSA capability when I really meant does this work with Sherpadesk PSA. Please let me know, sorry about the confusion!

  5. Daniel Nunns May 8, 2020 at 6:32 am

    Hi Kelvin

    Thanks for your hard work, prior to going with Warranty Master myself, I was looking at a way to do this with scripting. I immediately hit the HP API roadblock and burnt a day, without finding your workaround.

    I have elected Kaseya as our central point of hardware information, so any advancements on that front would be fantastic, however, I believe I would be able to repurpose your script with a procedure.

    Thanks for sharing!

    Cheers

  6. carlo May 8, 2020 at 5:18 pm

    Hi Kelvin,

    This is absolutely awesome! Currently working on implementing this into our systems. One thing I did notice was that one or two test machines for the Dell API check failed due to using old TLS version. I added the following line to force the script to use TLS 1.2 and it works perfectly: [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12

  7. Pingback: ICYMI: PowerShell Week of 08-May-2020 | PowerShell.org

  8. Pingback: PowerShell SnippetRace 19-2020 | | PowerShell Usergroup Austria

  9. David May 20, 2020 at 5:35 am

    Dank u Kelvin

    Does the script update Autotask PSA or IT Glue warranty dates or does it only report in an HTML?

    1. Kelvin Tegelaar May 20, 2020 at 8:28 am

      Depends on how you set it! if you set $SyncWithSource = $true – it will also update ITG,CW,or Autotask PSA.

  10. Pingback: Documenting and monitoring blogs updates - CyberDrain

  11. Dave M May 22, 2020 at 3:11 am

    Thank you so much for this.

    When I use CW as a source, I seem to be missing something , as I keep getting the below error.
    I have confirmed that my CW api key is correct.

    Source is Connectwise Manage. Grabbing all devices.
    invoke-restmethod : Invalid Token
    At Warranty information reporting.ps1:303 char:21
    + … $Devices += invoke-restmethod -headers $header -method GET -uri “$($G …
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException
    + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
    Retrieved 0 configurations
    Done updating warrenties. Generating reports if required.

    Line 303 is:
    $Devices += invoke-restmethod -headers $header -method GET -uri “$($Global:CWAPIURL)/company/configurations?pageSize=1000&page=$i”

    1. Kelvin Tegelaar May 22, 2020 at 9:30 am

      Have you edited the URL to the correct host? There’s a whole bunch of different hosts πŸ™‚

      1. Dave M May 24, 2020 at 11:02 pm

        That was it indeed!
        Thank you. πŸ™‚

  12. Henk Jansen May 22, 2020 at 9:56 am

    Hi Kelvin,

    Verry nice script, is it also possible to store and run this script by using Azure functions?

    So thay way it could be automated by a scheduled job.

    1. Kelvin Tegelaar May 22, 2020 at 10:07 am

      Hi Henk,

      Yeah, this script is able to run via an azure function.

      1. Henk Jansen July 2, 2020 at 4:18 pm

        Nice! But i’m unable to get it up and running.
        Are there specific requirements needed in the Azure Function?

        1. Kelvin Tegelaar July 2, 2020 at 6:45 pm

          It really depends on which version you’re using and how much you’re feeding the script. (CW, CSV, Autotask, etc) Standard functions have a runtime of 10 minutes. It might be better to run it with Azure Automation runbooks.

          for functions; remember to enable 64bit mode.

          1. Henk July 9, 2020 at 10:36 am

            Thankyou! I’ve got it working as a Azure Automation runbook, you’re really awesome!

  13. Toby May 26, 2020 at 2:55 pm

    Hi Kelvin,
    Thank you for yet another amazing bit of code! Totally changes the way we get the warranty information now πŸ™‚

    I had to adjust a couple of bits to get this working for me, for instance there may have a typo in the Get-WarrantyAutotask function where “$AllClients” and/or “$AllAccounts” is being set (line 193):

    $AllClients = $AllAccounts = Get-AtwsAccount -All | Where-Object { $_.Active -eq $true }

    I dropped the ‘$AllAccounts =’ part as it doesn’t appear to be used and that got this working.

    I also had an issue with the Get-MSWarranty function and found I had to specify the parameter $SourceDevice as a string before it would work properly – not sure if others found the same of it’s just a quirk of Datto PSA perhaps?

    In using this against our client base, I’ve found a few HP devices where the returned warranty expiration date is ‘N/A’ – this then fails on the writeback to our PSA as it cannot be converted to a system datetime. To prevent this, I added an additional “-and $warstate.EndDate -ne ‘N/A'” to the switch used in the various “if ($script:SyncWithSource -eq $true)” sections of code.

    I was looking forward to seeing all the reports at the end of the process but spotted the wrong variable is used on line 413 – the test should be against the variable $CheckReportFolder declared in the line above.

    Hope the above proves useful to others πŸ™‚
    Toby

    1. Kelvin Tegelaar May 26, 2020 at 3:04 pm

      Hi Toby,

      Thanks πŸ™‚ I think some small updates caused this. I’ll be updating the blog with your comments soon! πŸ™‚

  14. Prashant June 8, 2020 at 11:18 am

    Hi Kelivin, I am new to Powershell. I am using the CSV file & added Client ID and Client secret for Dell. Script runs withing fraction of seconds and comes out. No errors and no report generated though $CreateHTMLReport is set to true.

    1. Kelvin Tegelaar June 8, 2020 at 5:57 pm

      well, it seems there was a little bug a friend of mine caught. If you use the latest version of the script, that shoulnd’t happen anymore! πŸ™‚

  15. Prashant June 9, 2020 at 9:09 am

    Hi Kelvin, Thanks for the quick response πŸ™‚ It was not working because of upper case and lower case letter in “line” in “Get-WarrantyCSV” function. I am using it for Dell servers and it is working perfectly fine now. Thanks for the script. Could you please help to add an alert in script saying if warranty is getting expired in less than 30 days then send an email?

  16. Matt Cameron June 12, 2020 at 8:17 pm

    The Get-HPWarranty appears to work fine for certain/older serials. Debugging a little I see that $HPReq.Status is 301 for these ones that I couldn’t get to work. I suspect this is related to what the manual site does wherein it says it needs more information and asks for a product number as well.

    I need to play more but I saw that Chrome Dev Tools showed modelNum being used in the request. So I added another option field for the SKU/Product number which populates modelNumber in the JSON (which was null in the script). I got a proper response after that. More testing is needed but I though that might help someone.

  17. Graham Pocta June 17, 2020 at 6:55 am

    Just implemented this tonight. I am very impressed – excellent bit of scripting. Do you take payment/beer donations? I’ll be cancelling a certain service after today and would like you to reap some of the benefits of that.

    Two questions which I may look into myself if I can find the time to fiddle with the script:

    1. Have you looked into getting Apple warranty info at all?
    2. Have you looked into grabbing purchase date and syncing that back up as well?

    1. Kelvin Tegelaar June 18, 2020 at 3:33 pm

      1.) No, I haven’t really. I completely forgot the existed! πŸ˜‰ I’m gonna see if I can add something.

      2.) Yes, there are some modifications regarding that on my github. πŸ™‚

  18. Tom June 18, 2020 at 3:23 pm

    Hi there,

    I’ve been reimplementing your script into c#, working on HP warranty search. When I run the powershell and my c# version, I do not get the json returned data but instead html containing the HP help section (seems to be a redirect). I was inspecting the network traffic and I noticed that the request contains a populated “captcha_token” field now which has a capatcha token generated by googles recaptcha service. Can you confirm it is still working please?

    Thanks for the script!

    1. Kelvin Tegelaar June 18, 2020 at 3:33 pm

      HP’s API tends to break from time to time. Let’s hope it gets back up in a couple of days πŸ™‚

      1. Tom June 30, 2020 at 3:49 pm

        Hi again,

        Thanks for the reply.

        So I got it working, but after a day I am now getting captcha token failure errors. Here’s the json:

        {“errorCode”:”UNEXPECTED_ERROR”,”errorReason”:”Captcha didnt match and failed for the user”,”constraintViolations”:null}

        You ever seen this before?

        1. Jeff July 16, 2020 at 10:13 am

          Did you manage to get it working Tom?

  19. jeff June 25, 2020 at 12:37 pm

    Thanks for this awesome tool! We were looking into warranty master, but this might be better!

    The scripts was getting an error 500. I checked the url:
    https://support.hp.com/hp-pps-services/os/multiWarranty?ssid=SERIALNO
    and it shows “HP Customer Support site is temporarily unavailable”

    I looked it up on google and It seems that this happens often or the website is not offering this service anymore.

    1. Kelvin Tegelaar June 25, 2020 at 12:38 pm

      Yeah, The HP website tends to go offline from time to time, normally it lasts about a week. Hopefully they’ll get it fixed soon πŸ™‚

  20. bandukia June 29, 2020 at 4:37 am

    Hi,

    Is it possible to have the output in csv instead of html, and combined instead for separated files.

    Regards

    1. Kelvin Tegelaar June 29, 2020 at 8:28 am

      Sure! you’d just have to replace the convertto-html cmdlets with convertto-csv. πŸ™‚

    2. Brennan August 19, 2020 at 6:51 pm

      Did you ever get it to send it to a nice csv file? I can get it to output to the csv file format but because they all have different client names they separate into different files (just as my HTML files do).

      serialnumber,vendor,client
      1234,HP,contoso
      1234,Dell,toiletpaperco
      1234,MS,contoso
      1234,Lenovo,johndoe inc

      My csv output ends up looking like this, which is almost fine, except when opened in excel it doesn’t display nicely.

      #TYPE System.Management.Automation.PSCustomObject
      “Serial”,”Warranty Product name”,”StartDate”,”EndDate”,”Warranty Status”,”Client”
      “A1B2C3D”,”C, NBD ONSITE
      C, NBD ONSITE”,”2010-06-21″,”2013-06-22″,”Expired”,”console”

  21. Prashant June 30, 2020 at 8:16 am

    Hi,

    Is it possible to include feature like sending an single email alert of systems whose warranty is getting expired in 30 days in script?

    Thanks,
    Prashant

  22. Prashant July 1, 2020 at 8:26 am

    Thanks for the link Kelvin πŸ™‚

  23. Martin July 1, 2020 at 10:31 am

    kelvin you are awesome πŸ˜€
    we will use this scipt and run it in azure automation as a runbook. this will check all our intune devices and push the warranty data to our cmdb.

    1. Kelvin Tegelaar July 1, 2020 at 12:18 pm

      Thanks! I’d just be careful with the HP API. It seems to die a bit more than usual now… πŸ™‚

      1. Martin July 28, 2020 at 5:01 pm

        Just got my Dell API Keys… all APIs are working fine now…. except HP.
        So far I was not able to get it working.

        We query the warranty data for devices which are not yet updated in the cmdb. So from time to time the amount of warranty informations will grow. If one query failes its not an issue.

  24. Niv Dolgin July 6, 2020 at 3:27 pm

    This is brilliant. Thank you. Any plans to make Intune (or, the EndPoint Manager Graph API data) a source?

  25. Marc C July 13, 2020 at 9:43 am

    Hey!

    Thanks for sharing this! I’m a bit new to scripting and have been trying to read over the code to learn what I can. Before implementing this into my environment, will the “Warranty Product Name” be filled with the device hostname, or is this a generic field that will populate the device name (eg. Dell OptiPlex 3070)?

    1. Kelvin Tegelaar July 13, 2020 at 9:45 am

      It will fill it with the Warranty Product name the vendor supplies, so for Dell that could be “Dell ProSupport 3 years” or HP “HP Carepaq”. hope that helps πŸ™‚

  26. Brennan August 4, 2020 at 12:22 am

    First of all I think this is absolutely brilliant. I needed a way to show if our surface’s are in warranty or not since Kaseya doesn’t do that for us.

    I did find a slight problem when running my own machine. It shows the warranty status as expired but shows the warranty date as being good until 2021. Technically, yes, the original 1 year warranty has expired, but because of the additional warranty it is under warranty. (so warranty status would not be expired.)

    Any ideas on how to fix this would be greatly appreciated.

  27. Shaun K August 9, 2020 at 3:51 am

    Hi Kelvin,

    You are going Gods work here!!

    Just with Datto RMM as tye have force MFA onto all users now so the script fails to connect with basic auth. Is it possible to change to connect using the API Key and API secret ?

  28. James Croxford August 10, 2020 at 9:28 am

    Is anyone getting the following error when running the script for Autotask?

    Import-Module : IntegrationCode is invalid.
    Stacktrace:
    at Get-AtwsData, C:\Program Files\WindowsPowerShell\Modules\Autotask\1.6.9\Private\Get-AtwsData.ps1: line 117
    at Connect-AtwsWebServices, C:\Program Files\WindowsPowerShell\Modules\Autotask\1.6.9\Private\Connect-AtwsWebServices.ps1: line 215
    at , C:\Program Files\WindowsPowerShell\Modules\Autotask\1.6.9\Autotask.psm1: line 134

    1. Kelvin Tegelaar August 10, 2020 at 10:03 am

      This means you’ve entered an invalid API identifier.

      1. James Croxford August 18, 2020 at 11:46 am

        Many Thanks Kelvin, all working now.

  29. Mark August 17, 2020 at 6:42 am

    This is excellent! Thanks Kelvin, much appreciated!

    A few things I’d like to know.

    – Is there any way to exclude duplicates in the Warranty Product Name? I see the same product names listed twice for the same machine i.e. “ND ProSupport EndUser On-Site Extended with Dates”
    – Is it possible to include some sort of count down til the warranty end date?

    Regards

    1. Kelvin Tegelaar August 17, 2020 at 8:50 am

      The names are all warranty products on the device, so if you extended the warranty it’ll show the same anme.

      You could add a column to count down the days too.

  30. Owen August 17, 2020 at 7:09 am

    Is it just me or is the HP functions till broken?
    I keep getting 500 errors, I did some snooping and found their website has an “api_version” tag in the body which I added and this got past the 500 error but then returns null objects so it just as helpful.

    1. Kelvin Tegelaar August 17, 2020 at 8:50 am

      HP has marked this to be fixed in September. πŸ™‚

      1. Andrew D September 1, 2020 at 1:28 am

        Wait, what?? We’ve been waiting so long for HP to fix automated warranty lookup. Is this really happening??

      2. Owen March 25, 2021 at 8:50 pm

        Have just re-checked this and it looks like it still broken? Their website is still reporting as fixed in september 2020, did you find another way to query HP warranties for your new script/azure function?

  31. James Croxford August 18, 2020 at 12:20 pm

    Is there anyway to embed the Username and Password for the AutoTask API account into scirpt?

    Also can you get Apple warranty information?

    1. James Croxford August 19, 2020 at 12:39 pm

      Also could you add Acers warranty information?

  32. Martin Tylich September 23, 2020 at 4:09 pm

    Hi please I have problem. I am getting this:
    Invoke-RESTMethod : {
    “error”:”invalid_client”,
    “error_description”:”The given client credentials were not valid”
    }
    At C:\Users\MTylich\Downloads\PowerShellWarrantyReports-master\PowerShellWarrantyReports-master\WarrantyRetrieval.ps1:6
    3 char:23
    + … uthResult = Invoke-RESTMethod -Method Post -Uri $AuthURI -Body $AuthB …
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebExc
    eption
    + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
    Invoke-RestMethod : {

    “Fault”: {
    “faultcode”: “401”,
    “faultstring”: “Invalid Authentication”,
    “faultactor”: “https://apigtwb2c.us.dell.com/PROD/sbil/eapi/v5/asset-entitlements?servicetags=3TF3VN2”
    }

    }
    At C:\Users\MTylich\Downloads\PowerShellWarrantyReports-master\PowerShellWarrantyReports-master\WarrantyRetrieval.ps1:7
    0 char:15
    + … $WarReq = Invoke-RestMethod -Uri “https://apigtwb2c.us.dell.com/PRO …
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebExc
    eption
    + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand

    I am sure that API key and secure is correct so I don’t know what is wrong.

    Thanks

  33. Colin Barr October 7, 2020 at 1:41 am

    Thanks so much for posting this!

    I’m trying to do this with IT Glue. I have generated an API key in ITG and have put it after the -ITGlueAPIKey switch, but when I run it, it seems to prompt for credentials, and no matter what I put in, it retrieves no data with no errors.

    Just wondering if you could hint at what I am doing wrong?

    This is the syntax I am using (with the API Key replaced)

    update-warrantyinfo -ITGue -ITGlueAPIKey xxMadeUpAPIKeyxxx -GenerateReports -returnwarrantyobject -ReportsLocation c:\script\warr

    1. Colin Barr October 7, 2020 at 4:29 pm

      sorry, I forgot the parameter for the URL. This is the command I am using:

      update-warrantyinfo -ITGue ITGlueAPIURL https://api.itglue.com -ITGlueAPIKey xxMadeUpAPIKeyxxx -GenerateReports -returnwarrantyobject -ReportsLocation c:\script\warr

      1. Colin Barr October 7, 2020 at 4:30 pm

        Argh! This is the command with the typos fixed:

        update-warrantyinfo -ITGue -ITGlueAPIURL https://api.itglue.com -ITGlueAPIKey xxMadeUpAPIKeyxxx -GenerateReports -returnwarrantyobject -ReportsLocation c:\script\warr

        Sorry

        1. Kelvin Tegelaar October 7, 2020 at 5:03 pm

          It seems that the PSGallery had a rollback and one of the updates has not been registered. Version 0.7.1 is has the fixes for these issues.

          I’ll try to reupload today, but the PSGallery is having some issues. If you want, you can download the module from github instead.

  34. Marcel B October 7, 2020 at 4:34 pm

    Somehow when running this script i’m getting a lot of errors. This parameters where used (error below):

    $source = “AT” #AT, CSV, ITG, CW
    ##### Sync Settings
    $SyncWithSource = $false #Sync status warranty dates/status back to PSA/Management system. Only works with dynamic sources like ITG and AT.
    $OverwriteWarranty = $false #Overwrites the date already found in AT with the one based on this API, unless the API could not find information.
    $CreateHTMLReport = $true #Creates an HTML report.
    ###### File locations
    $ReportsLocation = “C:\temp\reports” #Only required if Reporting is enabled.
    $sourcefile = “C:\temp\temp.csv” #only required if source is not autotask.
    $ATLogPath = “C:\temp\AT.txt” #Only used to log which objects have been synced with AT as AT does not have a audit log.
    ##### AT API Settings
    $ATAPIKey = “key@domain.nl” #only required if source is Autotask.

    — errors —
    At C:\Marcel\Warranty.ps1:365 char:95
    + … splay = […tr.children].find(td => td.innerHTML.toUpperCase().includ …
    + ~
    An expression was expected after ‘(‘.
    At C:\Marcel\Warranty.ps1:365 char:106
    + … .tr.children].find(td => td.innerHTML.toUpperCase().includes(filter)) …
    + ~
    Missing ‘)’ in method call.
    At C:\Marcel\Warranty.ps1:362 char:23
    + function myFunction() {
    + ~
    Missing closing ‘}’ in statement block or type definition.
    At C:\Marcel\Warranty.ps1:309 char:8
    + do {
    + ~
    Missing closing ‘}’ in statement block or type definition.
    At C:\Marcel\Warranty.ps1:365 char:128
    + … nd(td => td.innerHTML.toUpperCase().includes(filter)) ? ” : ‘none’);
    + ~
    Missing while or until keyword in do loop.
    At C:\Marcel\Warranty.ps1:298 char:28
    + function Get-WarrantyCW() {
    + ~
    Missing closing ‘}’ in statement block or type definition.
    At C:\Marcel\Warranty.ps1:365 char:128
    + … nd(td => td.innerHTML.toUpperCase().includes(filter)) ? ” : ‘none’);
    + ~
    Unexpected token ‘)’ in expression or statement.
    At C:\Marcel\Warranty.ps1:366 char:3
    + }
    + ~
    Unexpected token ‘}’ in expression or statement.
    At C:\Marcel\Warranty.ps1:372 char:3
    + td, th { border:0px solid black;
    + ~
    Missing argument in parameter list.
    At C:\Marcel\Warranty.ps1:377 char:6
    + table, tr, td, th {
    + ~
    Missing argument in parameter list.
    Not all parse errors were reported. Correct the reported errors and try again.
    + CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : ExpectedExpression

      1. Marcel B October 8, 2020 at 2:33 pm

        Hi Kelin,

        I did same results. Now I have loaded 2 modules from the library.

        install-module AutotaskAPI -Force
        install-module PSWarranty -Force

        Ran it and when the credentials where asked. Do I need to enter my own credentials? I use 2FA in AT. This never works I think. I get this….

        update-warrantyinfo -Autotask -AutotaskCredentials $creds -AutotaskAPIKey ‘fykxwunce5nwfyf@EXPERIT.NL’ -GenerateReports
        cmdlet Get-Credential at command pipeline position 1
        Supply values for the following parameters:
        [Autotask, True] [AutotaskCredentials, System.Management.Automation.PSCredential] [AutotaskAPIKey, fykxwunce5nwfyf@EXPERIT.NL] [GenerateReports, True]
        Retrieving webservices URI based on username
        Setting AutotaskBaseURI to https://webservices4.autotask.net/ATServicesRest/ using version V1.0
        Setting API resource parameters. This may take a moment.
        Logging into Autotask. Grabbing all client information.
        Get-AutotaskAPIResource : Connecting to the Autotask API failed. De externe server heeft een fout geretourneerd: (500) Interne serverfout.
        At C:\Program Files\WindowsPowerShell\Modules\PSWarranty\0.7\private\Get-WarrantyAutotask.ps1:13 char:19
        + … llClients = Get-AutotaskAPIResource -resource Companies -SimpleSearch …
        + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
        + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Get-AutotaskAPIResource

        Client information found. Grabbing all devices
        Get-AutotaskAPIResource : Connecting to the Autotask API failed. De externe server heeft een fout geretourneerd: (500) Interne serverfout.
        At C:\Program Files\WindowsPowerShell\Modules\PSWarranty\0.7\private\Get-WarrantyAutotask.ps1:15 char:19
        + … llDevices = Get-AutotaskAPIResource -resource ConfigurationItems -Sim …
        + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
        + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Get-AutotaskAPIResource

        Collecting information. This can take a long time.
        Done collecting warranty information. Generating reports.

        1. Kelvin Tegelaar October 8, 2020 at 2:43 pm

          You’ll need the Autotask API user integration code, username, and password. As that’s currently returning error 500 you most likely are not using the correct credentials. MFA does not matter if you configured the API correctly.

          1. Marcel B October 13, 2020 at 4:48 pm

            Hi Kelvin,

            Is there a howto discription somewhere how to create that API user. No matter what creds I use I’ll keep bumping into the 500 error. And also what fields do I need to enter where?

            Is the field called AutotaskAPIKey in the script the Username(key) in Autotask? And within the popup, what is the username and password when looking into the API user in Autotask? I have 4 fields, Username(key, Secret, Internal Integration Name and Tracking Identifyer. Where do I map them wihtin the script and popup?

            Sorry for all the questions.

            Thanks (dank!)

          2. JRS October 17, 2020 at 7:24 pm

            I had the same problem. The AutoTask API Key in the command needs to be the Tracking Identifier from the Autotask API user account (you have to set up a new API user account and mark it as a custom integration). Then use the API User account username and password for the credentials.

  35. jordy October 14, 2020 at 4:39 pm

    Will DattoRMM as source be possible ? πŸ˜€

  36. Michael October 21, 2020 at 5:29 pm

    I’m seeing this error when trying trying to check warranty on Hp devices. I’m importing from csv

    You don’t have permission to access “http://support.hp.com/hp-pps-services/os/multiWarranty?” on this server.
    Reference #18.44d54c68.1603293817.a2a52d9
    At C:\Program Files\WindowsPowerShell\Modules\PSWarranty\0.9.1\private\Get-HPWarranty.ps1:5 char:14
    + … $HPReq = Invoke-RestMethod -Uri “https://support.hp.com/hp-pps-ser …
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException
    + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
    Invoke-RestMethod :
    Access Denied
    Access Denied

    Not working if I try the function directly either
    Any suggestions

    1. Kelvin Tegelaar October 21, 2020 at 10:57 pm

      The HP API is very spotty and only seems to work sometimes. working on replacing it. πŸ™‚

  37. Jeff October 26, 2020 at 10:30 pm

    I tried Autotask and it worked great! So thank you, but I just tried using Datto RMM and it went through with no errors, but nothing got updated in Datto RMM and also nothing in the WarrantyUpdateLog. Any thoughts?

  38. Jeff October 27, 2020 at 11:27 pm

    Hmmm, I sent this in yesterday and saw it get published, but looks like it was taken down. Im trying to use Datto RMM and its going through with no errors, but nothing in the log stating that any devices were updated and Ive spot checked some systems in Datto RMM and none have the warranty field updated. Any thoughts?

  39. Marcel B October 28, 2020 at 3:53 pm

    Hi Kelvin,

    Finaly thanks to JRS and you I got this working somehow πŸ™‚
    I do bump into the You don’t have permission to access message like the post of Michael with HP devices. Any news on that?

    Also I am getting this error: The term ‘New-HTML’ is not recognized as the name of a cmdlet. I am using this:

    install-module AutotaskAPI -Force
    install-module PSWarranty -Force
    $Creds = get-credential
    update-warrantyinfo -Autotask -AutotaskCredentials $creds -AutotaskAPIKey ‘blabla’ -GenerateReports

    1. Marcel B November 4, 2020 at 11:03 am

      Hi Kelvin,

      Any news on both issues? Tested it today but still the errors.

      I do bump into the You don’t have permission to access message like the post of Michael with HP devices. Any news on that?

      Also I am getting this error: The term β€˜New-HTML’ is not recognized as the name of a cmdlet. I am using this:

      install-module AutotaskAPI -Force
      install-module PSWarranty -Force
      $Creds = get-credential
      update-warrantyinfo -Autotask -AutotaskCredentials $creds -AutotaskAPIKey β€˜blabla’ -GenerateReports

      1. Dave M November 18, 2020 at 9:24 pm

        You can run Install-module PSWriteHTML -force to resolve this.

  40. Dan November 10, 2020 at 7:43 pm

    Hello! Been looking for a script just like this! Can you please provide insight on how to run and interface with CW? Thanks so much!

      1. Dan November 13, 2020 at 7:02 pm

        Think we got it working! Thanks so much for doing this work! Any progress on the CW Automate version? Seems we can update Manage just fine but Manage does not talk to Automate for updating those fields.

  41. Marcel B November 19, 2020 at 9:33 am

    Hi there,

    Got it mostly running with help from you guys. Still have this error on the HP side …
    Other vendors seem to be working fine (in report mode). But I think 95% is HP we have …..

    Any news on this?

    Thanks!

    You don’t have permission to access “http://support.hp.com/hp-pps-services/os&#
    47;multiWarranty?” on this server.
    Reference #18.d5b2f748.1605773494.2a445bb
    At C:\Program Files\WindowsPowerShell\Modules\PSWarranty\0.9.1\private\Get-HPWarranty.ps1:5 char:14
    + … $HPReq = Invoke-RestMethod -Uri “https://support.hp.com/hp-pps-ser …
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], We
    bException
    + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand Invoke-RestMethod :
    Access Denied
    Access Denied

  42. Rob Eberhardt November 22, 2020 at 11:10 pm

    get-HPWarranty is throwing the same “Access Denied” error for me.

    I suspect HP’s unofficial API is now officially an un-API πŸ™

    1. Kelvin Tegelaar November 23, 2020 at 9:47 am

      Yeah, but the good news a new API is on its way. I have alpha access and expect to update the module soon!

      1. Owen November 25, 2020 at 10:15 pm

        Great news, I have been hanging out for the HP fix!

  43. Michael Darby November 23, 2020 at 2:54 am

    I download the zip file for this but I cannot get it to run in powershell? How would I run it taking the excel file as a input parameter? thanks

      1. Michael Darby November 23, 2020 at 4:08 pm

        I see instructions on how to use it with autoask but not with importing data from a csv file

      2. Michael Darby November 24, 2020 at 6:38 pm

        I cant seem to find the “manual” where specifically is it on there?

  44. DC November 25, 2020 at 7:50 pm

    Kelvin, KUDOS!
    We have quite a few Microsoft Surface devices and they simply don’t allow easy lookups (as you are well aware) so this logic you figured out is really handy. Several 501c3’s are now in a better place thanks to you.
    Regards,

  45. Tim Jackson November 27, 2020 at 5:10 am

    On the GitHub version of the project, it might be nice to add the command “Get-WarrantyInfo” as one of the module’s commands so we could easily use in our own scripting for a single serial number. Right now everything is geared towards mass updating with “Set-WarrantyAPIKeys” and “Update-WarrantyInfo” as the only two functions in “Get-Command -Module PSWarranty”

    Love your site… it’s inspired me to learn PowerShell and automate more in our SolarWinds RMM!

  46. Michael Darby December 16, 2020 at 8:59 pm

    hey kelvin so i got microsoft and lenovo working but for HP are we needing a key? i see it has websession inside the powershell so im wondering if thats why i dont have access. thanks

  47. MarcelB December 24, 2020 at 11:00 am

    Hi Kelvin,

    I’m still facing the HP problem when using your script.
    This is what I use below. Am I doing something wrong maybe? Thank you.

    install-module AutotaskAPI -Force
    install-module PSWarranty -Force
    Install-module PSWriteHTML -force
    $Creds = get-credential
    update-warrantyinfo -Autotask -AutotaskCredentials $creds -AutotaskAPIKey ‘xxxx’ -GenerateReports

    This is what I get ….

    Invoke-RestMethod :
    Access Denied
    Access Denied

    You don’t have permission to access “http://support.hp.com/hp-pps-services/os/multiWarranty?” on this se
    rver.
    Reference #18.6ea9645f.1608803648.36440755
    At C:\Program Files\WindowsPowerShell\Modules\PSWarranty\0.9.1\private\Get-HPWarranty.ps1:5 char:14
    + … $HPReq = Invoke-RestMethod -Uri “https://support.hp.com/hp-pps-ser …
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebException
    + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand
    Invoke-RestMethod :

  48. Adam Randall January 26, 2021 at 3:29 am

    Is there a secret handshake or something with regards to the HP API?
    It blows my mind that there would be companies out there with many thousands of machines that are not getting their warranty information for over a year now.
    Have they sold the rights to their warranty data & are hoping to cash in on it? It just seems to me that it is completely intentional they are not providing this information & nothing takes over a year especially not something that is relatively low overhead.

    I put it in the same basket as IT Glue not building a backup that saves the whole database, if they did that then it is a disadvantage to them regardless as to the best interests of their clients.

    Its a pretty disheartening state of affairs that they have not been bothered to turn it on for so long.

    1. Marcel B January 28, 2021 at 11:29 am

      Hi Adam,

      Indeed strange with the HP problem. I am still hoping and waiting on the new API that Kelvin mentioned on the 23rd of november.

  49. Richard February 7, 2021 at 6:45 am

    You can use Intune as the source:

    function Get-WarrantyIntune {

    #https://github.com/Microsoft/Intune-PowerShell-SDK/releases
    #import-module C:\Users\administrator\Downloads\Intune-PowerShell-SDK_v6.1907.00921.0001\drop\outputs\build\Release\net471\Microsoft.Graph.Intune.psd1
    #Connect-MSGraph -AdminConsent
    #Get-Command -Module Microsoft.Graph.Intune | measure
    #Get-IntuneManagedDevice | Out-GridView

    write-host “Source is Intune. Grabbing all devices.” -ForegroundColor Green
    $AllDevices = Get-IntuneManagedDevice | Select Manufacturer, SerialNumber, DeviceName
    $warrantyObject = foreach ($Device in $AllDevices) {
    switch ($device.Manufacturer) {
    HP { get-HPWarranty -SourceDevice $device.SerialNumber -Client $device.DeviceName -Manufacturer $device.Manufacturer }
    Dell { get-DellWarranty -SourceDevice $device.SerialNumber -Client $device.DeviceName -Manufacturer $device.Manufacturer }
    “LENOVO” { get-LenovoWarranty -SourceDevice $device.SerialNumber -Client $device.DeviceName -Manufacturer $device.Manufacturer}
    #MS { Get-MSWarranty -SourceDevice $line.SerialNumber -Client $line.client }
    “Microsoft Corporation” { Get-MSWarranty -SourceDevice $device.SerialNumber -Client $device.DeviceName -Manufacturer $device.Manufacturer }
    }
    }
    return $warrantyObject
    }

    1. Marcel B February 11, 2021 at 12:07 pm

      Hi Richard,

      How do you do that? I just use the PS commands mentioned in my post on the 24th of dec……

  50. Christian von Wendt-Jensen February 13, 2021 at 8:57 am

    How can I get a username and password for the Lenovo API? It seems that the one given in the example in this post has been revoked in the last couple of weeks.

    1. John February 26, 2021 at 1:48 pm

      This is dead as a dodo now, Lenovo are moving over to their new warranty service (which is actually great) https://SupportAPI.lenovo.com/ which is hosted internally.

      You’ll need an API key and the only way to get one is to reach out to your Lenovo rep or see if your Lenovo reseller can put you in touch with their Lenovo rep.

      1. Kelvin Tegelaar February 26, 2021 at 2:01 pm

        That’s not true at all, the latest Github version works completely and has a Lenovo API proxy.

    2. Kelvin Tegelaar February 26, 2021 at 2:02 pm

      Make sure you pull the latest version from the PowerShell gallery πŸ™‚

  51. Chuck February 25, 2021 at 4:29 pm

    I’ve been attempting to get this running using a CSV for proof of concept for my Office. No errors are reported during the scripts run, but the report shows “Could not get warranty information” under both Product Warranty Name and Warranty Status.

    Right now just trying to get Lenovo’s check up and running.

    I’m also trying to figure out what flags or arguments to use with the PSWarranty gallery script, however I can’t seem to figure it out

    1. Kelvin Tegelaar February 26, 2021 at 2:04 pm

      The PowerShell gallery module should help in this; first run ‘install-module pswarranty’

      With this module you can either look-up all devices,or just a single device with “Get-Warrantyinfo”.

      1. Chuck March 1, 2021 at 2:44 pm

        Thanks so much for the reply!

        When I run “Get-WarrantyInfo” it returns back with both Warranty Product name and Warranty Status showing “Could not get warranty Information”

        This is the same output that I receive when I try using CSV as a resource, entering the serial’s for MS, Lenovo, Dell or HP.

        Any thoughts on what might be causing this?
        Faithfully yours
        Chuck

        1. Kelvin Tegelaar March 1, 2021 at 3:33 pm

          Trying running it with -verbose. The commands used use Invoke-Restmethod so if you can’t access the servers etc you won’t get any reply. -verbose should help show the URLs it tries, check if you can visit those. πŸ™‚

  52. Timo March 4, 2021 at 9:00 am

    Hi there,

    Tried this script …

    install-module AutotaskAPI -Force
    install-module PSWarranty -Force
    Install-module PSWriteHTML -force
    $Creds = get-credential
    update-warrantyinfo -Autotask -AutotaskCredentials $creds -AutotaskAPIKey ‘keykey’ -GenerateReports

    Gave me access denied on https://support.hp.com/hp-pps-se.

    Thanks!

    1. Kelvin Tegelaar March 4, 2021 at 11:43 am

      The HP API is offline, the new one should be released soon but they keep postponing, not saying any more dates… πŸ™‚

  53. Pingback: Hudu Warranty Expiration Tracking – MSPP

  54. Chris March 17, 2021 at 7:06 pm

    Anyone having an issue with CSV with -GenerateReports? It doesn’t seem to dump anything out. with -Verbose I can see it hitting all of the APIs and if I pull the URLs it’s valid warranty info. If I specify the report path it just creates a directory but no file. I feel like I’m missing something stupid here.

  55. Bob March 19, 2021 at 6:38 pm

    Updated Lenovo check works well, except it’s reading extended warranty data odd. For example, P209MYH5 reads as:

    [Serial] => MP1XH3A3
    [WarProduct] => 30M On-site, 9X5 1Y Mail-in Warranty
    [StartDate] => 02/03/2021 00:00:00
    [EndDate] => 02/02/2022 00:00:00

    Lenovo’s support site shows that 30M is a 30 month warranty, so it’s actually 8/2/2023. Not impossible to just toss in an extra 18 months when it detects 30M, but I don’t know how many other odd packages there may be.

    Thanks so much for this package!

    1. Kelvin Tegelaar March 19, 2021 at 6:58 pm

      That’s pretty awesome, because it’s detecting the 1 year warranty the dates it returns are a single year, but it has 3 years onsite. I’m gonna try to find a fix for this. πŸ™‚

  56. Manish March 20, 2021 at 1:08 pm

    Getting error while call “Get-MSWarranty” function from powershell

    Error :

    Invoke-RestMethod : The remote server returned an error: (400) Bad Request.
    At line:26 char:15
    + … $WarReq = Invoke-RestMethod -uri “https://surfacewarrantyservice.az …
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebExc
    eption
    + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand

    1. Kelvin Tegelaar March 20, 2021 at 1:38 pm

      Make sure you use the latest version of the module:
      update-module PSWarranty -force

  57. Marcel B March 31, 2021 at 3:38 pm

    Hi Kelvin,

    There seems to be some progress with the HP API . When running the script there are no more errors saying Access Denied and the script runs a lot longer then normaly. But now every HP device says in the HTML Could not get warranty information…….

    Almost a party overhere ……

    1. Marcel B March 31, 2021 at 3:41 pm

      Hmmm I do see a few Surface devices with info …. thats all

  58. Laura April 15, 2021 at 12:09 am

    Is anyone still using this script? I am getting a bunch of invalid credential errors for HP and Dell (and we are using the Dell ID and Secret). Just wondering if any of the URL’s or API interfaces have changed.

    1. Laura April 15, 2021 at 12:58 am

      I did get the Dell portion working. We downloaded the latest Module as well. You can ignore this. Thank you!

  59. Bruno Sander April 28, 2021 at 12:10 pm

    Hi Kelvin,
    Any news about HP API?
    Do you have any plans for to take in Samsung or any other vendor?
    Regards Bruno

  60. Dan April 29, 2021 at 1:10 am

    Hey Kelvin, can’t seem to get more than 250 devices from CWM.

    I can watch devices.json getting written to the c:\temp but then it deletes at the end of the script so I also can’t resume (Line 82: Remove-Item ‘devices.json’ -Force -ErrorAction SilentlyContinue).

    Still looking at code to see if I’m missing a flag or something here, but I’m at a loss currently.

    Happens with both -generatereports flag as well as -syncwithsource

    1. Dan April 29, 2021 at 1:37 am

      Not amazing at PowerShell or programming here, but figure I’d see if I can find some info.

      It seems line 35 sets $i to 0, which ends up being the first page in the query “$($CWMAPIURL)/company/configurations?pageSize=250&page=$i”
      Then it becomes 1 on line 38 aftward.

      If I use Postman, I get the same results from page=0 as I do with page=1.

      Still doesn’t explain breaking the while() statement far as I can tell, but I believe it will technically bring up the first 250 results twice in the loop. Also, using Postman I can continue to get results on subsequent pages when I increment the page#, so I think the while() loop is breaking early for me.

  61. Dan April 29, 2021 at 5:21 pm

    Hey Kelvin, you can disregard my previous messages. Turns out when I updated I needed to close out of PowerShell completely before trying again. Even when tinkering with the code PowerShell wouldn’t use the updated script until I closed/reopened.

    That said, I believe Postman does show the same results for page=0 and page=1 in CWM, so that might be something to look into still.

  62. Michael Darby May 3, 2021 at 4:05 pm

    hey Kelvin,

    so several months ago i had the lenovo portion working however, now it isnt returning any information (its showing the else portion). I took the code out of the function and just tried running from $today = Get-Date until the bottom when it returns the $warobj. but also tried inside the function as well and neither one will return any information. I tried hardcoding my serial number into the sourcexml variable which was what i did before

  63. Kevin Vincent May 13, 2021 at 11:49 am

    I’m getting warranty product name “could not get warranty info” and same for status when sending using get-warrantyinfo “xyz” “Client” “HP”

  64. Matt Taylor May 25, 2021 at 4:23 pm

    Im having some issues understanding how to use the powershell module with Dell’s client ID and Secret.
    I initially had the script working and it started throwing an error that the credentials were not valid but now with importing the module I am unsure how to add both the client ID and secret since it only asks for the client ID.

  65. Tyson May 25, 2021 at 8:28 pm

    Anyone else having issues with the Lenovo warranty check? Just found this script and I am testing but I keep getting “Could not get warranty information” when looking up Lenovo warranties.

    1. Tyson May 26, 2021 at 5:27 pm

      After looking on the github site, I found that the get-Lenovowarranty.ps1 file had been updated recently. I was able to copy the function out and swapped it from the one above for the Lenovo warranty look up. I tested with the csv and was able to return results!

  66. Brennan May 28, 2021 at 9:18 pm

    Kelvin I don’t know what my problem is. I was able to run this last year, but now that I’m trying the new one I don’t know what my problem is. I am trying to import a csv (and hopefully eventually output to a csv too) but I keep getting the could not get warranty information.

    If I run a single machine get-warrantyinfo -vendor ms -deviceserial 123456789876 then it comes back with information that I expect to see.

    Also I am having trouble remembering where I get the Dell Client ID (I have the key) and where to put it now as well.

    Any help you can offer would be greatly appreciated. You are a rockstar for writing this amazing program.

  67. Pete August 26, 2021 at 1:21 pm

    Any more ideas on when HP might have a working API? It’s almost crazy that its been so long, hell I wouldn’t mind if they made us sign up for it. Anything than nothing.

    (Good site btw!)

  68. Lolo September 17, 2021 at 4:22 pm

    I’m trying to get the warranty for DELL products
    I get the following ourput:
    Source is CSV file. Grabbing all devices.
    Done updating warrenties. Generating reports if required.
    The Reports folder is created but it’s empty.
    What am I doing wrong? Please help

Leave a comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.