If you’re managing Function Apps across multiple environments, you probably already know how easy it is to lose track of runtime versions.
One outdated runtime, and suddenly you're dealing with broken flows, unsupported features or worse, security issues.
Microsoft sends the following alerts, well, ahead of this expiry time:
Azure Portal notifications
Emails to subscription owners
Warnings in client tools and Azure Portal UI when an app is running on a version that is either retired, or about to be retired in the next 6 months
Official Azure Functions Supported Languages document
This might not be proactive enough in your setups spanning multiple subscriptions.
This is where these CLI scripts might help to:
✅ Scan across subscriptions
✅ Identify apps on outdated runtimes/language versions
✅ Stay compliant and secure with minimal effort
List all Windows-based Function Apps:
az functionapp list --query '[?contains(kind, `functionapp`) && !contains(kind, `linux`)].{Name:name, ResourceGroup:resourceGroup, OS:`Windows`}' --output table
List Windows-based Function Apps with their language stack versions:
az functionapp list --query "[? !contains(kind, 'linux')].{name:name, resourceGroup:resourceGroup}" -o json | ConvertFrom-Json | ForEach-Object {
$appSettings = az functionapp config appsettings list `
-n $_.name -g $_.resourceGroup `
--query "[?name=='FUNCTIONS_WORKER_RUNTIME' || name=='WEBSITE_NODE_DEFAULT_VERSION']" -o json | ConvertFrom-Json
$siteConfig = az functionapp config show `
-n $_.name -g $_.resourceGroup `
--query "{powerShellVersion: powerShellVersion, netFrameworkVersion: netFrameworkVersion, javaVersion: javaVersion}" -o json | ConvertFrom-Json
$runtime = ($appSettings | Where-Object { $_.name -eq 'FUNCTIONS_WORKER_RUNTIME' }).value
$version = switch ($runtime) {
'node' { ($appSettings | Where-Object { $_.name -eq 'WEBSITE_NODE_DEFAULT_VERSION' }).value }
'powershell'{ $siteConfig.powerShellVersion }
'dotnet' { $siteConfig.netFrameworkVersion }
'java' { $siteConfig.javaVersion }
default { 'Unknown' }
}
[PSCustomObject]@{
Name = $_.name
ResourceGroup = $_.resourceGroup
OS = 'Windows'
Runtime = $runtime
Version = $version
}
} | Format-Table -AutoSize
List Windows-based Function Apps running on unsupported language runtimes: (as of April 2025):
az functionapp list --query "[? !contains(kind, 'linux')].{name: name, resourceGroup: resourceGroup}" -o json | ConvertFrom-Json | ForEach-Object {
$appSettings = az functionapp config appsettings list -n $_.name -g $_.resourceGroup `
--query "[?name=='FUNCTIONS_WORKER_RUNTIME' || name=='WEBSITE_NODE_DEFAULT_VERSION']" -o json | ConvertFrom-Json
$siteConfig = az functionapp config show -n $_.name -g $_.resourceGroup `
--query "{powerShellVersion: powerShellVersion, netFrameworkVersion: netFrameworkVersion}" -o json | ConvertFrom-Json
$runtime = ($appSettings | Where-Object { $_.name -eq 'FUNCTIONS_WORKER_RUNTIME' }).value
$version = switch ($runtime) {
'node' {
$nodeVer = ($appSettings | Where-Object { $_.name -eq 'WEBSITE_NODE_DEFAULT_VERSION' }).value
if ([string]::IsNullOrEmpty($nodeVer)) { 'Unknown' } else { $nodeVer }
}
'powershell' { $siteConfig.powerShellVersion }
'dotnet' { $siteConfig.netFrameworkVersion }
default { 'Unknown' }
}
$isUnsupported = switch ($runtime) {
'node' {
$ver = $version -replace '~', ''
[double]$ver -le 16
}
'powershell' {
$ver = $version -replace '~', ''
[double]$ver -le 7.2
}
'dotnet' {
$ver = $siteConfig.netFrameworkVersion
$ver -notlike 'v7*' -and $ver -notlike 'v8*'
}
default { $false }
}
if ($isUnsupported) {
[PSCustomObject]@{
Name = $_.name
ResourceGroup = $_.resourceGroup
OS = 'Windows'
Runtime = $runtime
Version = $version
}
}
} | Format-Table -AutoSize
If result empty, this means: all your Windows-based Azure Function Apps are running supported versions of: Node.js, PowerShell or .NET.
List Windows Function Apps running on a specific language version (Example: Node.js 18):
az functionapp list --query "[?!contains(kind, 'linux')].{name: name, resourceGroup: resourceGroup}" -o json | ConvertFrom-Json | ForEach-Object { $appSettings = az functionapp config appsettings list ` -n $_.name ` -g $_.resourceGroup ` --query "[?name=='FUNCTIONS_WORKER_RUNTIME' || name=='WEBSITE_NODE_DEFAULT_VERSION']" ` -o json | ConvertFrom-Json $runtime = ($appSettings | Where-Object { $_.name -eq 'FUNCTIONS_WORKER_RUNTIME' }).value $nodeVersion = ($appSettings | Where-Object { $_.name -eq 'WEBSITE_NODE_DEFAULT_VERSION' }).value if ($runtime -eq 'node' -and $nodeVersion -eq '~18') { [PSCustomObject]@{ Name = $_.name ResourceGroup = $_.resourceGroup OS = 'Windows' Runtime = $runtime Version = $nodeVersion } } } | Format-Table -AutoSize
List Windows Function Apps running on Node.js runtime:
az functionapp list `
--query "[?!contains(kind, 'linux')].{name: name, resourceGroup: resourceGroup}" `
-o json | ConvertFrom-Json | ForEach-Object {
$appSettings = az functionapp config appsettings list `
-n $_.name `
-g $_.resourceGroup `
--query "[?name=='FUNCTIONS_WORKER_RUNTIME' || name=='WEBSITE_NODE_DEFAULT_VERSION']" `
-o json | ConvertFrom-Json
$runtime = ($appSettings | Where-Object { $_.name -eq 'FUNCTIONS_WORKER_RUNTIME' }).value
if ($runtime -eq 'node') {
$version = ($appSettings | Where-Object { $_.name -eq 'WEBSITE_NODE_DEFAULT_VERSION' }).value
[PSCustomObject]@{
Name = $_.name
ResourceGroup = $_.resourceGroup
OS = 'Windows'
Runtime = $runtime
Version = $version
}
}
} | Format-Table -AutoSize
List Linux* Function Apps with their language stack versions.
az functionapp list \
--query "[?siteConfig.linuxFxVersion!=null && siteConfig.linuxFxVersion!=''].{
Name: name,
ResourceGroup: resourceGroup,
OS: 'Linux',
LinuxFxVersion: siteConfig.linuxFxVersion
}" \
--output table
Linux* Function Apps on a specific language stack version (Ex: Node.js 18):
az functionapp list \
--query "[?siteConfig.linuxFxVersion=='Node|18'].{
Name: name,
ResourceGroup: resourceGroup,
OS: 'Linux',
LinuxFxVersion: siteConfig.linuxFxVersion
}" \
--output table
*Running on Elastic Premium and App Service Plans
With just a few Azure CLI commands and PowerShell scripts, you can quickly identify outdated runtimes, prioritize upgrades, and stay ahead of upcoming retirements.
That’s all for today, see you in the next one.