Easily Identity Function Apps Running Retired Runtime Versions

With ever more deprecation on the horizon, it’s important to be able to easily identify Function Apps which may now be running deprecated language versions. This ensures you continue to receive support and security updates, avoid performance degradation and unexpected failures and remain in compliance with Azure’s best practice guidelines.

This article and the code are based on an excellent recent post from madhurabharadwaj, titled Keep Your Azure Functions Up to Date: Identify Apps Running on Retired Versions.

It laid out several methods for identifying Function Apps running unsupported versions of common runtimes, however there were a few issues I wanted to remediate to make my own life easier.

  • Process every Subscription rather than just 1
  • Use proper [version] comparison rather than [double] to remediate issues such as 7.10 becoming 7.1
  • Use the AZ module rather than the Azure CLI directly
  • Allow easy updating of the oldest supported version numbers

My attempt at this may be found below.

PowerShell Script

This script requires read access to each Subscription and Function App you wish to report on. I have included PowerShell, DotNet and Python runtimes, adding additional runtimes should be quite straightforward. If you’d like to take the time to add additional runtimes then please send me a copy and I can update the code below for others to use.

# Update with the latest supported runtimes
$supportedPowershellVersion = '7.4'
$supportedDotnetVersion = '7.0'
$supportedPythonVersion = '3.7'

$date = Get-Date
$reportPath = "C:\temp\FunctionAppReport-$($date.Year)$($date.Month)$($date.Day)$($date.Millisecond).csv"

# Connect to Azure
Connect-AzAccount

# Get all subscriptions
$subscriptions = Get-AzSubscription

$results = @()

# Loop through all available subscriptions
foreach ($sub in $subscriptions) {
    Select-AzSubscription -SubscriptionId $sub.Id

    # Get all Function Apps in Subscription
    $functionApps = Get-AzFunctionApp

    foreach ($app in $functionApps) {
        $version = "Unknown"
        $isSupported = $false

        # Retrieve the runtime version and compare to supported using the correct [version] type for accurate comparison
        switch ($app.Runtime.toLower()) {
            'python' {
                $version = $app.SiteConfig["LinuxFxVersion"]
                $versionNumber = if ($version -match '\|(\d+(\.\d+)?)$') {
                    [version]$Matches[1]
                } else {
                    'Unknown'
                }
                
                $supportedVersion = $supportedPythonVersion
                $isSupported = $versionNumber -ge [version]$supportedPythonVersion
            }
            'powershell' {
                if($app.OSType -eq "Linux") {
                    $version = $app.SiteConfig["LinuxFxVersion"]
                    $versionNumber = if ($version -match '\|(\d+(\.\d+)?)$') {
                        [version]$Matches[1]
                    } else {
                        'Unknown'
                    }
                } else {
                    $version = $app.SiteConfig["PowerShellVersion"]
                    $versionNumber = [version]$version
                }
                
                $supportedVersion = $supportedPowershellVersion
                $isSupported = $versionNumber -ge [version]$supportedPowershellVersion
            }
            {$_ -in 'dotnet', 'dotnet-isolated'} {
                $version = $app.SiteConfig["NetFrameworkVersion"]
                $versionNumber = if ($version -match '^v(\d+(\.\d+)?)$') {
                    [version]$Matches[1]
                } else {
                    'Unknown'
                }

                $supportedVersion = $supportedDotnetVersion
                $isSupported = $versionNumber -ge [version]$supportedDotnetVersion
            }
            default {
                $version = "Unknown"
            }
        }

        $results += [PSCustomObject]@{
            SubscriptionName = $sub.Name
            SubscriptionId   = $sub.Id
            FunctionAppName  = $app.Name
            ResourceGroup    = $app.ResourceGroup
            OS               = $app.OSType
            Runtime          = $app.Runtime
            Version          = $version
            VersionNumber    = $versionNumber
            SupportedVersion = $supportedVersion
            IsSupported      = $isSupported
        }
    }
}

# Output to CSV and open the report
$results | export-csv -NoClobber -NoTypeInformation $reportPath
Invoke-Item $reportPath

I hope this helps somebody, if it does then please be sure to share the post!

One response to “Easily Identity Function Apps Running Retired Runtime Versions”

  1.  Avatar
    Anonymous

    I didn’t need that now but bookmark this for later. Great stuff! Thanks a lot

    Like

Leave a reply to Anonymous Cancel reply

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

Design a site like this with WordPress.com
Get started