Retrieve End of Life information using PowerShell

One of the things that I do when writing documents for customers is check if the products I advise or the customers use are still supported. The end-of-life date is essential, and in this blog post, I will show you how to retrieve that information quickly 🙂

End-of-life website

I use Microsoft Learn documentation online to determine the end-of-life date for Microsoft products. Still, many other vendors don’t always publish that information in an easy-to-find manner. The End of Life website was made just for that :

“End-of-life (EOL) and support information is often hard to track, or very badly presented. endoflife.date documents EOL dates and support lifecycles for various products.

endoflife.date aggregates data from various sources and presents it in an understandable and succinct manner. It also makes the data available using an easily accessible API and has iCalendar support.

endoflife.date currently tracks 366 products. “

Source: https://endoflife.date/

And they even have an API interface, which made me think… I can use PowerShell to query and report on that data 🙂

How the script works

Because you can read all the information about the products the website covers regarding their end-of-life information, you can query that using Invoke-RestMethod. I’ve added these Parameters to query and show the information on the screen using GridView or as an export to Excel for all data. Parameters are:

  • -AllProducts: This Parameter will show you a GridView of items you can select (One or more), and the end-of-life information will be displayed for those items.
  • -Product: This Parameter will allow you to select one or more products to be shown in GridView, separated by a comma. For example: .\Get-EndOfLife.ps1 -Product windowsserver, mssqlserver will show the Windows Server and SQL Server details.
  • -File: You can specify the Excel file name in which all the products and their end-of-life dates will be exported. For example, .\Get-EndofLife.ps1 -File c:\temp\eol.xlsx will save all products to that file.

Running the script

Using -AllProducts

If you run the script with the -AllProducts Parameter, see the example below, the output will be like this:

.\Get-EndOfLife.ps1 -allProducts

This will open an Out-ConsoleGridView (When running from PowerShell v7, it will show an Out-GridView pane in PowerShell v5) where you can select one or more items with Space. In the example below, I selected windows-server and mssqlserver. (You can use the Filter bar to search for items quickly; the list contains 366 products! )

Hit Enter to continue, after which the results will be shown like this: (Hit Escape to close)

The links in the Out-ConsoleGridView pane can be clicked (If available) to show more information. In PowerShell v5, using Out-GridView, this is not the case (Copy / Paste the link in that case)

Using -Product

You can also use the -Product Parameter; specify one or more products if you already know the product name. In the example below, I used Nutanix-AOS and Ubuntu:

.\Get-EndOfLife.ps1 -Product nutanix-aos, ubuntu

This will show the results like this: (Hit Escape to close)

Using -File

This Parameter will allow you to save all end-of-life information for all 366 products into one big Excel File. In the example below, I used that to save it to c:\temp\eol.xlsx:

.\Get-EndOfLife.ps1 -File c:\temp\eol.xlsx

This file will look this (It has rows 5580 😀 )

You can use the Filter options in Excel to search for specific products, dates, values, etc.

Wrapping up

This is how you can find end-of-life information using PowerShell. Kudos to the https://endoflife.date, which gathers all this information! Have a lovely weekend!

The script

Below are the script’s contents; save it to c:\scripts\Get-EndOfLife.ps1, for example.

param (
    [Parameter(Mandatory = $false, ParameterSetName = ('AllProducts'))][switch]$AllProducts,    
    [Parameter(Mandatory = $true, ParameterSetName = ('Product'))][ValidateNotNullOrEmpty()][string[]]$Product,
    [Parameter(Mandatory = $true, ParameterSetName = ('File'))][ValidateNotNullOrEmpty()][string]$File
)

#Check if Out-ConsoleGridView is installed if running from PowerShell v7
if ($host.Version.Major -ge 7) {
    try {
        Import-Module Microsoft.PowerShell.ConsoleGuiTools -ErrorAction Stop
    }
    catch {
        Write-Warning ("Microsoft.PowerShell.ConsoleGuiTools module was not installed, installing now...")
        try {
            Install-Module Microsoft.PowerShell.ConsoleGuiTools -Scope CurrentUser -ErrorAction Stop
        }
        catch {
            Write-Warning ("Error installing Microsoft.PowerShell.ConsoleGuiTools module, exiting...")
            return
        }
    }
}

#Retrieve all product data based, and output to Out-ConsoleGridView or Out-GridView for selection
if ($AllProducts) {
    try {
        $results = Invoke-RestMethod -Uri "https://endoflife.date/api/all.json" -Method Get -ContentType 'application/json' -ErrorAction Stop
    }
    catch {
        Write-Warning ("Could not retrieve product details, check internet access. Exiting...")
        return
    }
    if ($results.count -ge 1) {
        if ($host.Version.Major -ge 7) {
            $Product = $results | Out-ConsoleGridView -Title 'Select one or more products for determing End Of Life' -OutputMode Multiple -ErrorAction Stop
        }
        else {
            $Product = $results | Out-GridView -Title 'Select one or more products for determing End Of Life' -PassThru -ErrorAction Stop
        }
    }
    else {
        Write-Warning ("No product results found")
        return
    }
}

#Retrieve details for all selected products
if ($Product) {
    $total = foreach ($item in $Product) {
        try {
            $results = Invoke-RestMethod -Uri "https://endoflife.date/api/$($item).json" -Method Get -ContentType 'application/json' -ErrorAction Stop
            foreach ($result in $results) {
                [PSCustomObject]@{
                    Product         = $item
                    Cycle           = $result.cycle
                    ReleaseDate     = $result.releaseDate
                    EOL             = $result.eol
                    Latest          = $result.Latest
                    LTS             = $result.LTS
                    Support         = $result.support
                    ExtendedSupport = $result.extendedSupport
                    Link            = $result.link
                }
            }
        }
        catch {
            Write-Warning ("Could not retrieve details for product {0}, check spelling / internet access. Exiting..." -f $item)
            return
        }

    }
    if ($total.count -ge 1) {
        if ($host.Version.Major -ge 7) {
            $total | Out-ConsoleGridView -Title ("Details for End Of Life of product(s) {0}" -f $Product)
            return
        }
        else {
            $total | Out-GridView -Title ("Details for End Of Life of product(s) {0}" -f $Product)
            return
        }
    }
    else {
        Write-Warning ("No results to display for product(s) {0}" -f $Product)
    }
}

#Output all data to specified file
if ($File) {
    If (-not ($file.EndsWith('.xlsx'))) {
        Write-Warning ("Filename should end with .xlsx, exiting...")
        return
    }
    try {    
        #Install ImportExcel module if needed
        if (-not (Get-Module -Name importexcel -ListAvailable)) {
            Write-Warning ("`nImportExcel PowerShell Module was not found, installing...")
            Install-Module ImportExcel -Scope CurrentUser -Force:$true -ErrorAction Stop
            Import-Module ImportExcel -ErrorAction Stop
        }
    }
    catch {
        Write-Warning ("`nCould not import Excel PowerShell module, exiting...")
        return
    }
}

#Collect all end of life information and add to $total
try {
    $results = Invoke-RestMethod -Uri "https://endoflife.date/api/all.json" -Method Get -ContentType 'application/json' -ErrorAction Stop
}
catch {
    Write-Warning ("Could not retrieve product details, check internet access. Exiting...")
    return
}
$total = foreach ($product in $results) {
    foreach ($item in $Product) {
        try {
            $results = Invoke-RestMethod -Uri "https://endoflife.date/api/$($item).json" -Method Get -ContentType 'application/json' -ErrorAction Stop
            foreach ($result in $results) {
                [PSCustomObject]@{
                    Product         = $item
                    Cycle           = $result.cycle
                    ReleaseDate     = $result.releaseDate
                    EOL             = $result.eol
                    Latest          = $result.Latest
                    LTS             = $result.LTS
                    Support         = $result.support
                    ExtendedSupport = $result.extendedSupport
                    Link            = $result.link
                }
            }
        }
        catch {
            Write-Warning ("Could not retrieve details for product {0}, check spelling / internet access. Exiting..." -f $item)
            return
        }
    }
}

#Export all data to specified xlsx file
try {
    #Test path and remove empty file afterwards because xlsx is corrupted if not
    New-Item -Path $File -ItemType File -Force:$true -Confirm:$false -ErrorAction Stop | Out-Null
    Remove-Item -Path $File -Force:$true -Confirm:$false | Out-Null
    $total | Export-Excel -AutoSize -BoldTopRow -FreezeTopRow -AutoFilter -Path $File
    Write-Host ("`nExported results to {0}" -f $File) -ForegroundColor Green
    return
}
catch {
    Write-Warning ("`nCould not export results to {0}, check path and permissions" -f $File)
    return
}

Download the script(s) from GitHub here.

6 thoughts on “Retrieve End of Life information using PowerShell

  1. That’s actually pretty handy for monitoring purposes (in an edited way), like Checkmk, so a sysadmin can track their EOL, and if it’s near or overdue, he may get an alert.
    Way better than just checking the webpage. Serious, I like your content.

Leave a Reply

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