Deploy Organizational Teams Backgrounds without Teams Premium licenses – Azure Storage Account + Intune Remediations

Last updated on November 2nd, 2023 at 11:48 am

***A new post covering how to do this for New Teams is available here – Deploy Custom Backgrounds to New Teams with Remediations – SMBtotheCloud

A client recently wanted to deploy organizational backgrounds to all Teams users. However, this is now a Teams Premium feature, which is an additional cost per user per month (Custom meeting backgrounds for Teams meetings – Microsoft Teams | Microsoft Learn). There are several other blogs already out there on how we can deploy Teams backgrounds using Win32 apps, like this one from Florian Salzman (Microsoft Teams virtual background with Intune | scloud).

The end result of this post is essentially the same, but I wanted to take this a little further to make it easier when new backgrounds want to get deployed. If we use a Win32 app, we need to manually update our install script and then repackage (or update) the Win32 app. I had the idea of using a Remediation for this in combination with an Azure Storage account to hold the background images. It allows an admin or certain users to place organizational background images in a single managed location, which the Remediation distributes to the endpoints (this will only work for Windows devices). In the end, you only add your background files to the storage container, and the remediation does the rest. If your organization has a handful of backgrounds they want to deploy and rarely changes them, then using a Win32 app is probably less overall effort and easier to do. But, if your organization wants to manage the images from a central location, or makes regular additions to the Teams backgrounds, then this solution is a workaround instead of paying for Teams premium licenses.

Create the storage account

This is straightforward. In Azure, navigate to storage accounts, and create a new one. Provide a resource group and name and click review at the bottom of the screen. We can take all the defaults for this storage account since this will only be used to distribute background images.

Once you have a storage account created, create a container.

Provide a name for the container and make the public access level “container”, which will allow clients to list the contents of the container and see the blob file details. Since we are dealing with background images for teams, this shouldn’t be an issue for most organizations. However, you can disable public access and specify certain IPs or IP blocks that are allowed to access the storage account if you’d like. You can do this under the networking tab for the storage account.

Next, add your background files to the container:

Detection Script

The detection script for our remediation is shown below and also available on GitHub. It does a few things:

  • Checks for and installs the az.storage module if it’s not already installed.
  • Compares the names of the image file names in the blob container against the teams backgrounds directory (%appdata%\microsoft\teams\backgrounds\uploads) to see if they already exist
  • If the files exist in the backgrounds directory, then the script exits without the need to run the remediation script. If not, we get an exit code of 1, which triggers the remediation script
#Checks for Az.Storage module and installs if it doesn't exist
Write-Host "Checking for Az.Storage Module..." -ForegroundColor Green 
$azstoragemodule = Get-Module -name Az.Storage
if ($azstoragemodule -eq $null) {
Install-PackageProvider -Scope CurrentUser -Name NuGet -MinimumVersion 2.8.5.201 -Force
install-module az.storage -scope currentuser -Force
}

#Connects to storage account and pulls background image file names
$BlobURL = "https://smbtothecloudblob.blob.core.windows.net/"
$container = 'backgrounds'
$storageaccount = New-AzStorageContext -Anonymous -BlobEndpoint $BlobURL
$blobs = Get-AzStorageBlob -Container $container -Context $storageaccount
$Images = $Blobs.name
$BackgroundDir = "$env:APPDATA\Microsoft\Teams\Backgrounds\Uploads"
$Backgrounds = Get-ChildItem $BackgroundDir | Select -ExpandProperty Name -ErrorAction SilentlyContinue

#compare file names to see if they exist in the teams backgrounds destination
$FileComparison = 
foreach ($image in $images)
{
$image -in $backgrounds
}


Write-Host "Checking to see if blob container images already exist..." -ForegroundColor Green 
If ($FileComparison -contains $False) {
Write-Output "Background Images are Missing"
exit 1
}
else {
Write-Output "All background images exist"
exit 0
}

Remediation Script

The remediation script downloads all images from the blob storage container to the teams backgrounds directory (%appdata%\microsoft\teams\backgrounds\uploads).

#Check for Teams Backgrounds Directory and create if it doesn't exist
Write-Host "Checking for Teams background directory..." -ForegroundColor Green
$BackgroundDir = "$env:APPDATA\Microsoft\Teams\Backgrounds\Uploads"
$DirExists = Test-Path $BackgroundDir
If ($DirExists -ne $True) {
New-Item -Path "$env:APPDATA\Microsoft\Teams\Backgrounds" -Name Uploads -ItemType Directory
}

#Checks for Az.Storage module and installs if it doesn't exist
Write-Host "Checking for Az.Storage Module..." -ForegroundColor Green
$azstoragemodule = Get-Module -name Az.Storage
if ($azstoragemodule -eq $null) {
install-module az.storage -scope currentuser -Force
}

#Variables for blob connection and download
$BlobURL = "https://smbtothecloudblob.blob.core.windows.net/"
$container = 'backgrounds'
$storageaccount = New-AzStorageContext -Anonymous -BlobEndpoint $BlobURL
$blobs = Get-AzStorageBlob -Container $container -Context $storageaccount
foreach ($blob in $blobs)
{
Get-AzStorageBlobContent -Container $container -Blob $blob.Name -Destination $BackgroundDir -Context $storageaccount -Force
}

Build the Remediation

This part is self-explanatory, but we will cover it anyway. Navigate to intune.microsoft.com and select Devices > Remediations and select create script package:

Provide a name and description, and then click next. Browse to the detection and remediation script. Also, make sure you select to run the script as the logged-on user. This is necessary since Teams background images (and most other teams data) is stored in the user’s profile:

Lastly, assign to your desires groups and specify a schedule for how frequently you want the remediation to run:

At the scheduled time, your endpoints will run the detection script and remediate if necessary, creating the background\uploads directory, and copying the images:

Conclusion

This still isn’t a perfect solution for everyone. For example, the remediation above won’t remove any backgrounds. If your organization wants to remove old backgrounds and replace them with newer ones, your script will need to be edited to clean up old backgrounds that don’t exist in the storage account. Also, if your organization updates background files using the same file name, then this detection script won’t work. For my use case, file name comparisons were acceptable. However, if you want to check if files in the blob storage with the same file name are newer/updated than what’s in the destination, you’ll need to make some changes to the detection script. Using Get-AzStorageBlobContent does not copy the file metadata, which includes the timestamps. For that, you can use start-bitstransfer to a temporary location:

#Blob download
$BlobURL = "https://smbtothecloudblob.blob.core.windows.net/"
$container = 'backgrounds'
$storageaccount = New-AzStorageContext -Anonymous -BlobEndpoint $BlobURL
$blobs = Get-AzStorageBlob -Container $container -Context $storageaccount | Select-Object -ExpandProperty Name
foreach ($blob in $blobs) 
{
Start-BitsTransfer -Source "https://smbtothecloudblob.blob.core.windows.net/backgrounds/$blob" -Destination "c:\temp\$blob" -ErrorAction SilentlyContinue
}

And then do a comparison on the last write time like we did in the detection script for wallpapers from this blog – Set desktop & lock screen background on Windows 10 Pro using Intune – SMBtotheCloud.