Deploy Teams with custom settings (automatic login, run in background, etc.)

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:

https://teams.microsoft.com/uswe-01/downloads#allDevicesSection

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 🙂

Leave a Reply