Skip to content

Automatically Change Wallpaper on Teams Room System Every Day

I found a blogpost at UC Unleashed: New-MtrWallpaper – Automatically Change Wallpaper on Teams Room System Every Day

The source if New-MtrWallpaper is available on GitHub. So I forked it, tweaked and extend it a bit.

Here is my version of New-MtrWallpaper:

function New-MtrWallpaper
{
   <#
         .SYNOPSIS
         Configure a new wallpaper for Microsoft Teams Room (MTR) System

         .DESCRIPTION
         Configure a new wallpaper for Microsoft Teams Room (MTR) System.

         This is done by randomly choosing a supported image file from a folder.

         Wallpaper is then copied to the proper folder, and a corresponding XML file is also written.

         When the system reboots as part of its normal scheduled nightly maintenance,
         the new wallpaper is set for the 'Custom' them in MTR.

         .PARAMETER Path
         Local MTR User root path, as for now this is the same on every MTR device!
         Can be a Share (\\<MTRHostname>\\C$\Users\Skype\AppData\Local\Packages\Microsoft.SkypeRoomSystem_8wekyb3d8bbwe\LocalState),
         if you have more then one MTR or want to do it remotely!

         .PARAMETER Check
         Check if a given Wallpaperfile has the correct resolution

         .PARAMETER RedComponent
         RedComponent for the template
         Default is 100

         .PARAMETER GreenComponent
         GreenComponent for the template
         Default is 100

         .PARAMETER BlueComponent
         BlueComponent for the template
         Default is 100

         .EXAMPLE
         New-MtrWallpaper

         Picks a random image, copies to the root folder, and writes XML file

         .NOTES
         In the code you will find some exaples for more customization. Not scope of this script, but possible.
         Please see: https://docs.microsoft.com/en-us/MicrosoftTeams/room-systems/xml-config-file

         All Images must be exactly 3840×1080, for Single or dual screen!

         If you copy the wallpaper image (wallpaper.jpg), with or without the settings XML,
         to different MTR systems the change will not be activated!
         The MTR doesn't do a reload or check if a file is changed.
         The MTR will reboot every day at 2:30 (AM), then the changes will be activated.

         The MTR support .jpg, .jpeg, .png, and .bmp for wallpapers!

         My version of the script has no enhancements, at least not yet!
         It's just a minor changed version based on the great work of Pat Richard.

         .LINK
         https://www.ucunleashed.com/4323

         .LINK
         https://github.com/patrichard/New-MtrWallpaper

         .LINK
         https://docs.microsoft.com/en-us/MicrosoftTeams/downloads/ThemingTemplateMicrosoftTeamsRooms_v2.1.psd

         .LINK
         https://docs.microsoft.com/en-us/MicrosoftTeams/room-systems/xml-config-file

         .LINK
         https://www.ucit.blog/post/configuring-custom-themes-for-microsoft-teams-skype-room-systems

         .LINK
         https://www.bing.com/images/search?q=wallpaper+3840x1080&qpvt=wallpaper+3840x1080&form=IGRE&first=1&cw=1680&ch=939
   #>

   [CmdletBinding(ConfirmImpact = 'None',
   SupportsShouldProcess)]
   param
   (
      [Parameter(ValueFromPipeline,
      ValueFromPipelineByPropertyName)]
      [ValidateNotNullOrEmpty()]
      [Alias('ThisRoot')]
      [string]
      $Path = "$env:HOMEDRIVE\Users\Skype\AppData\Local\Packages\Microsoft.SkypeRoomSystem_8wekyb3d8bbwe\LocalState",
      [Parameter(ValueFromPipeline,
      ValueFromPipelineByPropertyName)]
      [switch]
      $Check,
      [Parameter(ValueFromPipeline,
      ValueFromPipelineByPropertyName)]
      [ValidateRange(0, 255)]
      [Alias('Red')]
      [int]
      $RedComponent = 100,
      [Parameter(ValueFromPipeline,
      ValueFromPipelineByPropertyName)]
      [ValidateRange(0, 255)]
      [Alias('Green')]
      [int]
      $GreenComponent = 100,
      [Parameter(ValueFromPipeline,
      ValueFromPipelineByPropertyName)]
      [ValidateRange(0, 255)]
      [Alias('Blue')]
      [int]
      $BlueComponent = 100
   )

   begin
   {
      #region Defaults
      $STP = 'Stop'
      $CNT = 'Continue'
      $SCT = 'SilentlyContinue'
      #endregion Defaults

      #region Helpers
      function Test-MtrWallpaper
      {
         <#
               .SYNOPSIS
               Check if a given Wallpaperfile has the correct resolution

               .DESCRIPTION
               Check if a given Wallpaperfile has the correct resolution.
               All Images must be exactly 3840×1080, for Single or dual screen!

               .PARAMETER Path
               Wallpaperfile to check (Full path)

               .INPUTS
               String

               .OUTPUTS
               Bool

               .EXAMPLE
               PS C:\> Test-MtrWallpaper -Path 'Z:\Desktop\wallpaper\TheBeachView.jpg'

               True

               .EXAMPLE
               PS C:\> Test-MtrWallpaper -Path 'Z:\Desktop\wallpaper\TheBeachView.jpg'

               False

               .NOTES
               All Images must be exactly 3840×1080, for Single or dual screen!
         #>
         [CmdletBinding(ConfirmImpact = 'None')]
         [OutputType([bool])]
         param
         (
            [Parameter(Mandatory, HelpMessage = 'Wallpaperfile to check (Full path)',
                  ValueFromPipeline,
            ValueFromPipelineByPropertyName)]
            [ValidateNotNullOrEmpty()]
            [Alias('Wallpaper', 'MTRWallpaper', 'Image')]
            [string]
            $Path
         )

         begin
         {
            # Cleanup
            $Check = $null

            # Load the Assembly
            $null = (Add-Type -AssemblyName System.Drawing)
         }

         process
         {
            # Creat the new variable with the Image (Assembly needed)
            $image = [Drawing.Image]::FromFile($Path)

            # Do the check
            if (($image.Width -eq '3840') -and ($image.Height -eq '1080'))
            {
               [bool]$Check = $true
            }
            else
            {
               [bool]$Check = $false
            }
         }

         end
         {
            return $Check
         }
      }
      #endregion Helpers

      #region Check
      try
      {
         # Cleanup
         $AllWallpapers = $null

         # Get a list of all of the wallpapers to choose from. Wallpaper images MUST be exactly 3840x1080, regardless if the MTR is a single or dual screen system.
         $paramGetChildItem = @{
            Path        = ($Path + '\Wallpapers')
            ErrorAction = $STP
         }
         $AllWallpapers = (Get-ChildItem @paramGetChildItem | Where-Object -FilterScript {
               $_.Extension -in '.jpg', '.jpeg', '.png', '.bmp'
         } | Select-Object -Property Name, Extension)

         # Prevent any futher action if there are no files (wallpapers)
         if (-not ($AllWallpapers))
         {
            # Just in case
            throw
         }
      }
      catch
      {
         # Create the String, just for the error message
         [string]$NewWallpaperPath = ($Path + '\Wallpapers')

         Write-Error -Message ('No wallpapers where found in {0}' -f $NewWallpaperPath) -Exception 'No wallpapers where found' -Category ObjectNotFound -RecommendedAction 'Check given path' -ErrorAction $STP

         # Just in case
         exit 1
      }
      #endregion Check
   }

   process
   {
      # Files to remove
      $FileToCleanup = @(
         'wallpaper.jpg'
         'wallpaper.jpeg'
         'wallpaper.png'
         'wallpaper.bmp'
         'SkypeSettings.xml'
      )

      # Default parameters
      $paramRemoveItem = @{
         Force         = $true
         Confirm       = $false
         ErrorAction   = $SCT
         WarningAction = $SCT
      }

      #region CleanupLoop
      foreach ($item in $FileToCleanup)
      {
         # Build the String
         $CleanupPath = ($Path + '\' + $item)

         # Check if the file exists
         if (Get-Item -Path $CleanupPath -ErrorAction $SCT)
         {
            # Add the parameter
            $paramRemoveItem.Path = $CleanupPath

            # Remove the File
            $null = (Remove-Item @paramRemoveItem)
         }

         # Cleanup
         $paramRemoveItem.Path = $null
         $CleanupPath = $null
      }
      #endregion CleanupLoop

      <#
            Pick a random wallpaper
            Keep in mind that the fewer images to choose from,
            the higher the potential to choose the same image that was used last time.
      #>
      $NewWallpaper = (Get-Random -InputObject $AllWallpapers)

      #region NewWallpaper
      if ($NewWallpaper)
      {
         # New Variables to support all extensions
         $NewWallpaperName = $NewWallpaper.Name
         $NewWallpaperFilename = ('wallpaper' + $NewWallpaper.Extension)

         if ($Check)
         {
            if (-not (Test-MtrWallpaper -Path ($Path + '\Wallpapers\' + $NewWallpaperName)))
            {
               Write-Error -Message ('Sorry, but {0} is not in the required resultion!' -f $NewWallpaperName) -Exception 'Wrong resulution' -Category InvalidData -RecommendedAction 'Check resulution' -ErrorAction $STP

               # Just in case
               exit 1
            }
         }

         Write-Verbose -Message ('Chosen wallpaper is ' + $Path + '\Wallpapers\' + $NewWallpaperName)

         # Copy the chosen wallpaper to the right folder. We rename it to a generic name as a safeguard against improper characters or file names that are too long.
         $paramCopyItem = @{
            Path          = ($Path + '\Wallpapers\' + $NewWallpaperName)
            Destination   = ($Path + '\' + $NewWallpaperFilename)
            Force         = $true
            Confirm       = $false
            ErrorAction   = $CNT
            WarningAction = $CNT
         }
         $null = (Copy-Item @paramCopyItem)

         <#
               Create the new SkypeSettings.xml using only the fields we need to populate to configure the new wallpaper
               More configuration is possible: https://docs.microsoft.com/en-us/MicrosoftTeams/room-systems/xml-config-file
               You get the idea...
         #>
         $paramNewObject = @{
            TypeName     = 'System.XMl.XmlTextWriter'
            ArgumentList = (($Path + '\SkypeSettings.xml'), $null)
         }
         $xmlWriter = (New-Object @paramNewObject)

         $xmlWriter.Formatting = 'Indented'
         $xmlWriter.Indentation = 1
         $xmlWriter.IndentChar = "`t"

         $xmlWriter.WriteStartDocument()
         $xmlWriter.WriteStartElement('SkypeSettings')

         <#
               Other Setting can be placed here, here are a few examples:

               $xmlWriter.WriteElementString('DualScreenMode', $true)
               $xmlWriter.WriteElementString('IsTeamsDefaultClient', $true)
               $xmlWriter.WriteElementString('BluetoothAdvertisementEnabled', $true)

               Please Note: If you want to configure the Devices (<Devices>), you need to add this to a container:

               # Open Devices
               $xmlWriter.WriteStartElement('Devices')
               # Add the config to Devices
               $xmlWriter.WriteElementString('MicrophoneForCommunication', 'Microsoft LifeChat LX-6000')
               $xmlWriter.WriteElementString('SpeakerForCommunication', 'Realtek High Definition Audio')
               $xmlWriter.WriteElementString('DefaultSpeaker', 'Polycom CX5100')
               # Close Devices
               $xmlWriter.WriteEndElement()

               Same applies to: UserAccount (<UserAccount>):
               # Open UserAccount
               $xmlWriter.WriteStartElement('UserAccount')
               # Add the config to UserAccount
               $xmlWriter.WriteElementString('SkypeSignInAddress', '[email protected]')
               $xmlWriter.WriteElementString('ExchangeAddress', '[email protected]')
               $xmlWriter.WriteElementString('DomainUsername', 'Seattle\RanierConf')
               $xmlWriter.WriteElementString('Password', 'password')
               $xmlWriter.WriteElementString('ConfigureDomain', 'domain1, domain2')
               # Close UserAccount
               $xmlWriter.WriteEndElement()

               It also applies to SendLogs (<SendLogs>):
               # Open SendLogs
               $xmlWriter.WriteStartElement('SendLogs')
               # Add the config to SendLogs
               $xmlWriter.WriteElementString('EmailAddressForLogsAndFeedback', '[email protected]')
               $xmlWriter.WriteElementString('SendLogsAndFeedback', $true)
               # Close SendLogs
               $xmlWriter.WriteEndElement()

               You might want to add some parameters for them above!
         #>

         # Theming starts here
         $xmlWriter.WriteStartElement('Theming')
         $xmlWriter.WriteElementString('ThemeName', 'Custom')
         $xmlWriter.WriteElementString('CustomThemeImageUrl', $NewWallpaperFilename)
         $xmlWriter.WriteStartElement('CustomThemeColor')

         # Review the Color Settings!
         $xmlWriter.WriteElementString('RedComponent', $RedComponent)
         $xmlWriter.WriteElementString('GreenComponent', $GreenComponent)
         $xmlWriter.WriteElementString('BlueComponent', $BlueComponent)

         # Close CustomThemeColor
         $xmlWriter.WriteEndElement()

         # Close Theming
         $xmlWriter.WriteEndElement()

         # Close SkypeSettings
         $xmlWriter.WriteEndElement()

         # Save the XML
         $xmlWriter.WriteEndDocument()
         $xmlWriter.Flush()
         $xmlWriter.Close()
      }
      #endregion NewWallpaper
   }

   end
   {
      Write-Verbose -Message ('The new wallpaper is {0}' -f $NewWallpaper)
   }
}

New-MtrWallpaper

It is also available on GitHub.

The Changelog of my version of New-MtrWallpaper:

  • 1.0.4 Fixed the Color parameters (Range was 0-100, should be, and now is is, 0-255)
    Add some more description for further customisation, with a few examples
  • 1.0.3 Add more parmeters (e.g. check resolution, and Template coloring)
  • 1.0.2 Add the Check (resolution) helper function: Test-MtrWallpaper
  • 1.0.1 Add support for all supported wallpaper Types (based on extensions)
  • 1.0.0 Fork from Pat Richard’s New-MtrWallpaper

Please see the Links in the Script header for more informations about the Wallpaper handling of the Teams Room System!

Feedback is welcome!

Published inPowerShell

2 Comments

  1. Adam Adam

    I like yours much better than the original. Thank you.

    Question for you, though. I can’t find this documented anywhere. The custom theme image provided to me by my marketing department is pretty light in color. I’d like to change the text color of the time and MTR name. Is that what the “CustomThemeColor” element is for? I changed the values of RedComponent, GreenComponent, and BlueComponent. Ran the script, XML file was generated, rebooted, and I didn’t notice anything different. Thoughts? Appreciate it.

    • Joerg Hochwald Joerg Hochwald

      Hi Adam,

      this is something I saw as well! It looks like the feature is not working at the moment. I just implemented it, because it is there.
      It never worked in my Tests 🙁

      Sorry, I will point that out in a future update to the script.

Comments are closed.