This blogpost is about deploying Teams with custom settings, like automatic startup, automatic login, open in background and so on. To make auto-logon work, AzureAD join is a prerequisite.
TL;DR
– Make sure AzureAD seamless SSO is set up (link)
– Download Teams installers from here (link)
– Create a folder in NETLOGON (or other share that can be accessed by users) and place the installers there
– Deploy the script below as user logon script, correct paths in the first two lines
+1: Use Microsoft’s script (link) as startup script to create firewall exceptions
$Teams_x64_installer = "\\domain.com\Netlogon\Teams\x64\Teams_windows_x64.exe"
$Teams_x86_installer = "\\domain.com\Netlogon\Teams\x86\Teams_windows.exe"
#OSCheck
if ((gwmi -query "select Caption from Win32_OperatingSystem").Caption -notmatch "Windows 10"){exit}
#Check office version
$bitness = (get-itemproperty HKLM:\Software\Microsoft\Office\14.0\Outlook -name Bitness -ErrorAction SilentlyContinue).Bitness
if($bitness -eq $null) {
$bitness = (get-itemproperty HKLM:\Software\Microsoft\Office\15.0\Outlook -name Bitness -ErrorAction SilentlyContinue).Bitness}
if($bitness -eq $null) {
$bitness = (get-itemproperty HKLM:\Software\Microsoft\Office\16.0\Outlook -name Bitness -ErrorAction SilentlyContinue).Bitness}
if($bitness -eq $null) {
$bitness = (get-itemproperty HKLM:\SOFTWARE\WOW6432Node\Microsoft\Office\14.0\Outlook -name Bitness -ErrorAction SilentlyContinue).Bitness}
if($bitness -eq $null) {
$bitness = (get-itemproperty HKLM:\SOFTWARE\WOW6432Node\Microsoft\Office\15.0\Outlook -name Bitness -ErrorAction SilentlyContinue).Bitness}
if($bitness -eq $null) {
$bitness = (get-itemproperty HKLM:\SOFTWARE\WOW6432Node\Microsoft\Office\16.0\Outlook -name Bitness -ErrorAction SilentlyContinue).Bitness}
#if no Office found, set bitness to match OS architecture
if ($bitness -eq $null) {
$bitness = "x"+(gwmi -query "select osarchitecture from win32_operatingsystem").osarchitecture.substring(0,2)
}
#select installer
switch ($bitness){
"x64"{$EXE_teamsInstall = $Teams_x64_installer}
"x86"{$EXE_teamsInstall = $Teams_x86_installer}
}
#Check if Teams is already present, install if needed
If (Test-Path "$env:USERPROFILE\Appdata\Local\Microsoft\Teams\Update.exe"){}else{
#Install Teams
$Command_teamsInstall = "$EXE_teamsInstall -s"
Invoke-Expression $Command_teamsInstall
#Wait for install process to finish
while (Get-Process | ? {$_.Path -eq "$EXE_teamsInstall"}){
Start-Sleep 1}
}
$desktopConfig = "$env:appdata\Microsoft\Teams\desktop-config.json"
##If it was not previously backed up, then back it up and modify configuration
if (Test-Path "$desktopConfig.original"){}else{
#Create backup
Copy-Item $desktopConfig -Destination "$desktopConfig.original"
#Import JSON config
$JSON_desktopConfig = Get-Content $desktopConfig -Raw | ConvertFrom-Json
#Set JSON config
$JSON_desktopConfig.isAppFirstRun = $false
$JSON_desktopConfig | Add-Member -MemberType NoteProperty -Name "isForeground" -Value $false -Force
$JSON_desktopConfig | Add-Member -MemberType NoteProperty -Name "isMaximized" -Value $false -Force
$JSON_desktopConfig | Add-Member -MemberType NoteProperty -Name "teamsUrlProtocolsRegistered" -Value $true -Force
$JSON_desktopConfig | Add-Member -MemberType NoteProperty -Name "lyncUrlProtocolsRegistered" -Value $true -Force
$JSON_desktopConfig | Add-Member -MemberType NoteProperty -Name "appPreferenceSettings" -Value "" -Force
$JSON_desktopConfig.appPreferenceSettings = [pscustomobject]@{
openAsHidden = $true
openAtLogin = $true
runningOnClose = $true
}
$JSON_desktopConfig | Add-Member -MemberType NoteProperty -Name "isLoggedOut" -Value $false -Force
$JSON_desktopConfig | Add-Member -MemberType NoteProperty -Name "pastModernAuthSucceeded" -Value $true -Force
#Export JSON config
$JSON_desktopConfig | ConvertTo-Json -Depth 20 | Set-Content $desktopConfig
}
#If it is not set to run automatically, then change this behavior
if (Get-ItemProperty HKCU:\Software\Microsoft\Windows\CurrentVersion\Run\ -Name com.squirrel.Teams.Teams -ErrorAction SilentlyContinue){}else{
#Create startup registry setting
New-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Run\" -name "com.squirrel.Teams.Teams" -PropertyType String -Value ("$env:USERPROFILE" + '\Appdata\Local\Microsoft\Teams\Update.exe --processStart "Teams.exe" --process-start-args "--system-initiated"')
}
Explained
To enable automatic login, AzureAD seamless SSO is needed. It’s very easy to set up, just follow Microsoft’s guide (link)
Downloading Teams EXE installers is also very straightforward:

Next step is to place these installers to a shared folder where users have at least READ permission. I prefer to use the domains NETLOGON folder for this:

Next, prepare the deployment script. This one consists of the following:
First, the paths of the exe files are defined in separate variables:$Teams_x64_installer = "\domain.com\Netlogon\Teams\x64\Teams_windows_x64.exe"
$Teams_x86_installer = "\domain.com\Netlogon\Teams\x86\Teams_windows.exe"
Then, there is an OS check (it will install only on Windows 10):if ((gwmi -query "select Caption from Win32_OperatingSystem").Caption -notmatch "Windows 10"){exit}
The following lines are looking for Office (Outlook exactly) to determine the bitness – so that the script will install the same version of Teams:$bitness = (get-itemproperty HKLM:\Software\Microsoft\Office\14.0\Outlook -name Bitness -ErrorAction SilentlyContinue).Bitness
if($bitness -eq $null) {
$bitness = (get-itemproperty HKLM:\Software\Microsoft\Office\15.0\Outlook -name Bitness -ErrorAction SilentlyContinue).Bitness}
if($bitness -eq $null) {
$bitness = (get-itemproperty HKLM:\Software\Microsoft\Office\16.0\Outlook -name Bitness -ErrorAction SilentlyContinue).Bitness}
if($bitness -eq $null) {
$bitness = (get-itemproperty HKLM:\SOFTWARE\WOW6432Node\Microsoft\Office\14.0\Outlook -name Bitness -ErrorAction SilentlyContinue).Bitness}
if($bitness -eq $null) {
$bitness = (get-itemproperty HKLM:\SOFTWARE\WOW6432Node\Microsoft\Office\15.0\Outlook -name Bitness -ErrorAction SilentlyContinue).Bitness}
if($bitness -eq $null) {
$bitness = (get-itemproperty HKLM:\SOFTWARE\WOW6432Node\Microsoft\Office\16.0\Outlook -name Bitness -ErrorAction SilentlyContinue).Bitness}
If Office is not found, the matching OS architecture will be used:if ($bitness -eq $null) {$bitness = "x"+(gwmi -query "select osarchitecture from win32_operatingsystem").osarchitecture.substring(0,2)}
Based on the determined architecture, $EXE_teamsInstall variable is defined:switch ($bitness){
"x64"{$EXE_teamsInstall = $Teams_x64_installer}
"x86"{$EXE_teamsInstall = $Teams_x86_installer}
}
Then the script is checking if Teams is already installed. If not, the installer invokes the installation command and waits for the process to finish:If (Test-Path "$env:USERPROFILE\Appdata\Local\Microsoft\Teams\Update.exe"){}else{
#Install Teams
$Command_teamsInstall = "$EXE_teamsInstall -s"
Invoke-Expression $Command_teamsInstall
#Wait for install process to finish
while (Get-Process | ? {$_.Path -eq "$EXE_teamsInstall"}){
Start-Sleep 1}
}
The following step is to configure the Teams client. Teams stores its configuration data in a JSON file, this is what we have to manipulate. You can find an awesome walkthrough by Dr Scripto (link). My version works as follows:
First, the configuration JSON file is defined in $desktopConfig variable:$desktopConfig = "$env:appdata\Microsoft\Teams\desktop-config.json"
Then the script checks if there is a backup file (desktop-config.json.original).if (Test-Path "$desktopConfig.original"){}else{
If it finds one, it assumes that the script already ran. If there is no backup file, it creates a backup:Copy-Item $desktopConfig -Destination "$desktopConfig.original"
Then comes the JSON manipulation:
– import the config to a variable:$JSON_desktopConfig = Get-Content $desktopConfig -Raw | ConvertFrom-Json
– make the following changes: disable first run wizard, open in backup, keep the app running on close, omit first time login screen:$JSON_desktopConfig.isAppFirstRun = $false
$JSON_desktopConfig | Add-Member -MemberType NoteProperty -Name "isForeground" -Value $false -Force
$JSON_desktopConfig | Add-Member -MemberType NoteProperty -Name "isMaximized" -Value $false -Force
$JSON_desktopConfig | Add-Member -MemberType NoteProperty -Name "teamsUrlProtocolsRegistered" -Value $true -Force
$JSON_desktopConfig | Add-Member -MemberType NoteProperty -Name "lyncUrlProtocolsRegistered" -Value $true -Force
$JSON_desktopConfig | Add-Member -MemberType NoteProperty -Name "appPreferenceSettings" -Value "" -Force
$JSON_desktopConfig.appPreferenceSettings = [pscustomobject]@{
openAsHidden = $true
openAtLogin = $true
runningOnClose = $true
}
$JSON_desktopConfig | Add-Member -MemberType NoteProperty -Name "isLoggedOut" -Value $false -Force
$JSON_desktopConfig | Add-Member -MemberType NoteProperty -Name "pastModernAuthSucceeded" -Value $true -Force
-the changes then get exported to the configuration file:$JSON_desktopConfig | ConvertTo-Json -Depth 20 | Set-Content $desktopConfig
The last step is to make the app run automatically by creating a registry key (if it does not exist):if (Get-ItemProperty HKCU:\Software\Microsoft\Windows\CurrentVersion\Run\ -Name com.squirrel.Teams.Teams -ErrorAction SilentlyContinue){}else{
#Create startup registry setting
New-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Run\" -name "com.squirrel.Teams.Teams" -PropertyType String -Value ("$env:USERPROFILE" + '\Appdata\Local\Microsoft\Teams\Update.exe --processStart "Teams.exe" --process-start-args "--system-initiated"')
}
Now that the script is ready, it is time to deploy the script as a user logon script:

Make sure the user has Teams licence too 🙂