Cleaning Azure File Shares with Azure Functions


One of the complaints I have about using FSLogix to store AVD User Profiles on Azure File Shares is that there’s no native way to clean up the stale / unneeded VHDs once users move on. If you search the web, you’ll come across some curiously misleading examples that discuss setting up an Azure Function to do this. I’ll share what actually worked for me, as the others did not!

Requirements: I’d like to delete all VHDs that haven’t been modified in the last 90 days.

Solution: I created a consumption (serverless) Azure Function App with a PowerShell core runtime.

The official Microsoft documentation states that newly created Functions App projects have the necessary Az PowerShell modules by default, but that was not my experience. To enable the Functions Service to install / maintain the required modules, edit the requirements.psd1 file to look like so:

@{
    'Az' = '10.*'
    'Az.Storage' = '5.*'
}

Once that’s done, you can create your Function. I created a basic timer function that runs daily at 30 minutes past midnight. To do that, my function.json file looks like:

{
  "bindings": [
    {
      "name": "Timer",
      "type": "timerTrigger",
      "direction": "in",
      "schedule": "0 30 0 * * *"
    }
  ]
}

The last piece of this is the run.ps1 file that actually gets executed:

$fileShare = "share"
$storageAccountName = "simplefilesharestorage"
$storageAccountKey = "YqoRK/En6bMJl+xWi7PVyDyTToOt/bwoGjaSZ/4adgyRRBvUW9K+HQBicyt2rVHRFUlrsSr4F/gg+AStOiapWg=="

$filelist = Get-AzStorageFile -ShareName $fileShare -Context (New-AzStorageContext -StorageAccountName $storageAccountName -StorageAccountKey $storageAccountKey)

foreach ($file in $filelist | Where-Object {$_.lastModified -lt ((Get-Date).AddDays(-90))})
    {
        $removefile = $file.name
        if ($removefile -ne $null)
        {
            Write-Host "Removing file $removefile"
            Remove-AzStorageFile -ShareName $fileShare -Path $removefile -Context (New-AzStorageContext -StorageAccountName $storageAccountName -StorageAccountKey $storageAccountKey)

        }
    }

Obviously you’ll need to update the variables above with values relevant to your deployment. A quick way to test that things are working is to modify the Get-Date to AddSeconds instead of Days, upload a random file to your share, then kick off a Test Run.

The first run will take a while as the Functions service installs the required dependencies. You may have to fiddle with a stop / start to coax this along, but it will eventually work!