Azure Function App names must be 32 characters or less

Confused sysadmin trying to work out why their Function Apps are not working

I recently learned that the name for an Azure Function App cannot be longer than 32 characters. Unfortunately, I learned this the hard way by spending about 24 hours trying to work out what was going on. What makes it worse is that Microsoft does document this here, albeit in a note towards the end of the page.

So, what happens if you name a Function App longer than 32 characters? The name gets truncated in the back end, and back-end services like storage use the truncated name.

Let’s take an example, I have four Function Apps with the following names:

ImportantApplication-Production-01
ImportantApplication-Production-02
ImportantApplication-Production-03
ImportantApplication-Production-04

The 32nd character in each of these names is the ‘-‘ near the end. This means every one of these gets truncated to “ImportantApplication-Production-” which means they lose the identifying number at the end, and all appear with the same name.

This causes all sorts of problems, particularly around accessing resources in storage accounts (assuming they are all using a shared storage account). I saw my apps failing to pick up messages from a storage queue, and managed dependencies seemed to take an incredibly long time to download or would stop part way and then try again after 5-10 minutes.

Deploy an Azure Function app with PowerShell

AI generated image of people writing code

Deploying updated code to an Azure Function App can be done through a variety of methods, and one of those methods is by uploading a zip file to the Function App via the Kudu REST API.

To start, go to your Function App in the Azure Portal and download the publish profile. This contains the ZipDeploy URL and the username and password that will be needed. You can do this from the Overview page of the Function App:

Location showing where the publish profile can be downloaded
Download the publish profile for your Function App

This will download an xml file that contains a few different publish profiles that you can use. In this case, look for the ZipDeploy profile and take note of the publishURL, userName and userPWD. The URL will take the form of FunctionAppName.scm.azurewebsites.net, the username will be $FunctionAppName and the password will be a long, randomised string.

The ZipDeploy publish profile
The ZipDeploy publish profile

Next you will need to make sure that SCM Basic Auth Publishing Credentials are enabled in the General Settings for your Function App. This can be found under Settings > Configuration > General Settings:

Updating the configuration of your Function App to enable SCM Basic Auth Publishing Credentials
Enable SCM Basic Auth Publishing Credentials

With this done let’s start coding the deployment, starting with the creation of the zip file. The root directory that you zip should contain the files that you want in the wwwroot folder of your Function App. Typically this will include your functions, a Modules folder, and a host.json file (and perhaps other files depending on the scripting language you selected for your Function App).

Let’s also say you have a .funcignore file that has a list of files or folders that are in the folder structure of the Function App but should not be included in the deployment.

So, your Function App source folder might look something like this:

Typical Function App folder structure
Typical Function App folder structure

Here’s the code to create the zip file:

$FolderPath = "C:\FunctionApps\KevinStreetsFunctionApp"
$Exclude = Import-Csv -Path "$FolderPath\.funcignore" -Header "Exclude"
$Destination = "$FolderPath\KevinStreetsFunctionApp.zip"
$Files = Get-ChildItem -Path $FolderPath -Exclude $Exclude.Exclude
# Create the zip file
Compress-Archive -Path $Files -DestinationPath $Destination -CompressionLevel Fastest

Now that the zip file has been created it is time to deploy it. Start by defining some variables with the publishURL, userName and userPWD you noted down earlier. Also, update the publishURL to include the correct API and include “isAsync=true” which will immediately return a response that you can use to monitor the deployment status.

$DeploymentUrl = 'https://kevinstreetsfunctionapp.scm.azurewebsites.net'
$Username = '$KevinStreetsFunctionApp'
$Password = 'Hnsl114TmGlpmEis9afDe5KEZoqvJDpcNZyri8ucAJx2b2uSoKhd4ovlCg9Q'
$ApiUrl = "$($DeploymentUrl):443/api/zipdeploy?isAsync=true"

Create the base-64 encoded string to pass in the Authorization header when we make the request:

$Base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $Username, $Password)))

Next create a variable to define the zip file location:

$ZipFileLocation = "C:\FunctionApps\KevinStreetsFunctionApp\KevinStreetsFunctionApp.zip"

And finally deploy!

$Result = Invoke-WebRequest -Uri $ApiUrl -Headers @{Authorization=("Basic {0}" -f $Base64AuthInfo)} -Method POST -InFile $ZipFileLocation -ContentType "multipart/form-data"

As mentioned above, this should return immediately, and you can this by checking the content of the $Result variable. If all has gone well, you will get a StatusCode 202 meaning it has been accepted.

Feedback from the deployment showing that the deployment has been accepted and the URL that can be used to monitor the deployment
Deployment has been accepted

As previously mentioned, you can now monitor the status of the deployment. The URL you use to monitor the deployment is contained in the Headers in the return of the previous request. You can view it by looking in $Result.Headers.Location:

The URL to monitor the deployment
$Result.Headers.Location

To query the status of the deployment, run the following command:

$Complete = Invoke-WebRequest -Uri $($Result.Headers.Location) -Headers @{Authorization=("Basic {0}" -f $base64AuthInfo)} -Method GET
($Complete.Content | ConvertFrom-Json).provisioningState

This will likely return one of two statuses: InProgress or Succeeded. In my experience it takes very little time to complete the deployment. I like to create a small loop that checks the status every 5 seconds until the status is completed:

do {
    $Complete = Invoke-WebRequest -Uri $($Result.Headers.Location) -Headers @{Authorization=("Basic {0}" -f $Base64AuthInfo)} -Method GET
    Write-Host -Object "Current deployment progress: $(($Complete.Content | ConvertFrom-Json).provisioningState)"
    if ($(($Complete.Content | ConvertFrom-Json).provisioningState) -ne "Succeeded") {
        Start-Sleep -Seconds 5
    }
}
until ($(($Complete.Content | ConvertFrom-Json).provisioningState) -eq "Succeeded")

This gives me a nice output that shows when my deployment has completed:

Monitoring status of deployment by querying the monitoring URL every 5 seconds until the deployment has succeeded
Monitoring status of deployment

That is the foundation needed to deploy a Function App with PowerShell. If you have multiple Function Apps you could wrap this code around a loop to deploy each in turn or include other configuration changes as part of a deployment pipeline.