Microsoft Teams Status

I created an IoTLink Addon for MS Teams. It uses @Egglestron’s approach (Tail + RegEx). If anyone is interested you can find it here: GitHub - ledhed-jgh/IoTLink-Addons: Addons for IoTLink

I prefer IoTLink because my automation stuff lives in an isolated VLAN and can’t communicate directly with my PC. I was already using it to shutdown my PC, so it made sense to create the Addon and use what was already there rather than create Scheduled Tasks or PowerShell services.

1 Like

Thanks for doing this. Does this addon constantly poll or check the log file and therefore consume cpu cycles that would impact overall pc performance?
thanks

Its fairly efficient from the small amount of testing I’ve done. The code I used to watch the log file comes from a code snippet called Tail .NET. Essentially it checks the size of the log file every 1 second and if the filesize has changed it only reads the changed data (rather than loading the entire log file which can be quite large). I expect it to consume similar resource as the PowerShell based solutions (which also tail the log file).

Gotcha, thanks

maybe someone know what to do …
I`ve try to do it like EBOOZ wrote… instruction looks very easy but got error with last command in PowerShell

PS C:\Scripts> Start-Service -Name "Microsoft Teams Status Monitor"
Start-Service : Service 'Microsoft Teams Status Monitor (Microsoft Teams Status Monitor)' cannot be started due to the
following error: Cannot start service Microsoft Teams Status Monitor on computer '.'.
At line:1 char:1
+ Start-Service -Name "Microsoft Teams Status Monitor"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : OpenError: (System.ServiceProcess.ServiceController:ServiceController) [Start-Service],
   ServiceCommandException
    + FullyQualifiedErrorId : CouldNotStartService,Microsoft.PowerShell.Commands.StartServiceCommand

PS C:\Scripts>

Great idea using the Teams log, that’s exactly what I was looking for. However I came with a different way of extracting the status from Teams, I’m looking for “Setting the taskbar overlay icon”. Here is the Powershell script I created, it works well. I find that querying the log every 5 seconds and grabbing the last 2000 lines is sufficient so far.

$token = 'mytoken'
$headers = @{"Authorization" = "Bearer $token"; }

while ($true) {
    $tl = Get-Content "$env:APPDATA\Microsoft\Teams\logs.txt" -tail 2000 | ? { $_ -like '*Setting the taskbar overlay icon*' }
    $lastline = $tl[$tl.Count - 1]
    $i = $lastline.IndexOf('Setting the taskbar overlay icon - ') + 35
    $CurrentState = $lastline.SubString($i).Trim()

    $params = @{
        "state"      = "$CurrentState";
        "attributes" = @{
            "friendly_name" = "Microsoft Teams";
            "icon"          = "mdi:microsoft-teams";
        }
    }
    
    Invoke-RestMethod -Uri 'https://homeassistant:8123/api/states/sensor.teams_status' -Method POST -Headers $headers -Body ($params | ConvertTo-Json) -ContentType "application/json" 
    Start-Sleep 5
}

4 Likes

Like your solution. :+1:

Got this working on my work machine.
For anyone wanting to automate this.

  1. Open “Task Scheduler
  2. Create Task
  3. Give it a “Name” and importantly tick “Run with highest privileges
  4. Triggers tab
    a. New
    b. Dropdown “Begin task” set to “On log on
  5. Action tab
    a. New
    b. “Start a Program
    c. Program/script: “C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe”
    d. Add arguments -NonInteractive -WindowStyle Hidden -File "C:\path\to\the\script\on\your\machine\teams_meeting_presence.ps1"

Note: you might need to look for Powershell on your machine with Get-Command powershell.exe from a powershell session.

3 Likes

Hi all,

I got it all working, very nice job of you all !!! (I use the scheduler task to start the script when I boot). But, I have one more question: If reboot Home Assistant, my status is changed to ‘Unknown’ and get changed again when I run the script on my laptop.

Does anyone have a clue on how to ‘update’ the status once HA gets rebooted ?

Thanks in advance !!

Kr,

Bart

@weemaba999 I don’t see where the problem is.

If you restart Home Assistant then it needs to wait for the script to send the status.
Personally, I wouldn’t want HA to assume I am not in a meeting.

Can you explain what the issue is?

Well, how long does it take after reboot of HA for the script to send once again the status of my teams agent ? It seems that, unless I manually execute the script, the status will remain on ‘UNKNOWN’

Kr,

Bart

Looking at the last script it sends a status update every 5 seconds to HA - regardless of the state of your Teams. So that is odd …

Hi Fanuch,

I’m using the Get-TeamStatus with following content:

<#
.NOTES
    Name: Get-TeamsStatus.ps1
    Author: Danny de Vries
    Requires: PowerShell v2 or higher
    Version History: https://github.com/EBOOZ/TeamsStatus/commits/main
.SYNOPSIS
    Sets the status of the Microsoft Teams client to Home Assistant.
.DESCRIPTION
    This script is monitoring the Teams client logfile for certain changes. It
    makes use of two sensors that are created in Home Assistant up front.
    The status entity (sensor.teams_status by default) displays that availability 
    status of your Teams client based on the icon overlay in the taskbar on Windows. 
    The activity entity (sensor.teams_activity by default) shows if you
    are in a call or not based on the App updates deamon, which is paused as soon as 
    you join a call.
.PARAMETER SetStatus
    Run the script with the SetStatus-parameter to set the status of Microsoft Teams
    directly from the commandline.
.EXAMPLE
    .\Get-TeamsStatus.ps1 -SetStatus "Offline"
#>
# Configuring parameter for interactive run
Param($SetStatus)

# Import Settings PowerShell script
. ($PSScriptRoot + "\Settings.ps1")

$headers = @{"Authorization"="Bearer $HAToken";}

# Run the script when a parameter is used and stop when done
If($null -ne $SetStatus){
    Write-Host ("Setting Microsoft Teams status to "+$SetStatus+":")
    $params = @{
     "state"="$SetStatus";
     "attributes"= @{
        "friendly_name"="$entityStatusName";
        "icon"="mdi:microsoft-teams";
        }
     }
	 
    $params = $params | ConvertTo-Json
    Invoke-RestMethod -Uri "$HAUrl/api/states/$entityStatus" -Method POST -Headers $headers -Body ([System.Text.Encoding]::UTF8.GetBytes($params)) -ContentType "application/json"
    break
}

If ($env:APPDATA -match "C:\\Users") {
	$path = "$env:APPDATA\Microsoft\Teams\logs.txt"
}
Else {
	$path = "C:\Gebruikers\bart.weemaels$([char]0X0040)cegeka.be\AppData\Roaming\Microsoft\Teams\logs.txt"
}

# Start monitoring the Teams logfile when no parameter is used to run the script
Get-Content -Path $path -Tail 10000 -ReadCount 0 -Encoding Utf8 -Wait | % {
    
    # Get Teams Logfile and last icon overlay status
    $TeamsStatus = $_ | Select-String -Pattern `
        'Setting the taskbar overlay icon -',`
        'StatusIndicatorStateService: Added' | Select-Object -Last 1

    # Get Teams Logfile and last app update deamon status
    $TeamsActivity = $_ | Select-String -Pattern `
        'Resuming daemon App updates',`
        'Pausing daemon App updates',`
        'SfB:TeamsNoCall',`
        'SfB:TeamsPendingCall',`
        'SfB:TeamsActiveCall',`
        'name: desktop_call_state_change_send, isOngoing' | Select-Object -Last 1

    # Get Teams application process
    $TeamsProcess = Get-Process -Name Teams -ErrorAction SilentlyContinue

    # Check if Teams is running and start monitoring the log if it is
    If ($null -ne $TeamsProcess) {
        If($TeamsStatus -eq $null){ }
        ElseIf ($TeamsStatus -like "*Setting the taskbar overlay icon - $lgAvailable*" -or `
            $TeamsStatus -like "*StatusIndicatorStateService: Added Available*" -or `
            $TeamsStatus -like "*StatusIndicatorStateService: Added NewActivity (current state: Available -> NewActivity*") {
            $Status = $lgAvailable
            Write-Host $Status
        }
        ElseIf ($TeamsStatus -like "*Setting the taskbar overlay icon - $lgBusy*" -or `
                $TeamsStatus -like "*StatusIndicatorStateService: Added Busy*" -or `
                $TeamsStatus -like "*Setting the taskbar overlay icon - $lgOnThePhone*" -or `
                $TeamsStatus -like "*StatusIndicatorStateService: Added OnThePhone*" -or `
                $TeamsStatus -like "*StatusIndicatorStateService: Added NewActivity (current state: Busy -> NewActivity*") {
            $Status = $lgBusy
            Write-Host $Status
        }
        ElseIf ($TeamsStatus -like "*Setting the taskbar overlay icon - $lgAway*" -or `
                $TeamsStatus -like "*StatusIndicatorStateService: Added Away*" -or `
                $TeamsStatus -like "*StatusIndicatorStateService: Added NewActivity (current state: Away -> NewActivity*") {
            $Status = $lgAway
            Write-Host $Status
        }
        ElseIf ($TeamsStatus -like "*Setting the taskbar overlay icon - $lgBeRightBack*" -or `
                $TeamsStatus -like "*StatusIndicatorStateService: Added BeRightBack*" -or `
                $TeamsStatus -like "*StatusIndicatorStateService: Added NewActivity (current state: BeRightBack -> NewActivity*") {
            $Status = $lgBeRightBack
            Write-Host $Status
        }
        ElseIf ($TeamsStatus -like "*Setting the taskbar overlay icon - $lgDoNotDisturb *" -or `
                $TeamsStatus -like "*StatusIndicatorStateService: Added DoNotDisturb*" -or `
                $TeamsStatus -like "*StatusIndicatorStateService: Added NewActivity (current state: DoNotDisturb -> NewActivity*") {
            $Status = $lgDoNotDisturb
            Write-Host $Status
        }
        ElseIf ($TeamsStatus -like "*Setting the taskbar overlay icon - $lgFocusing*" -or `
                $TeamsStatus -like "*StatusIndicatorStateService: Added Focusing*" -or `
                $TeamsStatus -like "*StatusIndicatorStateService: Added NewActivity (current state: Focusing -> NewActivity*") {
            $Status = $lgFocusing
            Write-Host $Status
        }
        ElseIf ($TeamsStatus -like "*Setting the taskbar overlay icon - $lgPresenting*" -or `
                $TeamsStatus -like "*StatusIndicatorStateService: Added Presenting*" -or `
                $TeamsStatus -like "*StatusIndicatorStateService: Added NewActivity (current state: Presenting -> NewActivity*") {
            $Status = $lgPresenting
            Write-Host $Status
        }
        ElseIf ($TeamsStatus -like "*Setting the taskbar overlay icon - $lgInAMeeting*" -or `
                $TeamsStatus -like "*StatusIndicatorStateService: Added InAMeeting*" -or `
                $TeamsStatus -like "*StatusIndicatorStateService: Added NewActivity (current state: InAMeeting -> NewActivity*") {
            $Status = $lgInAMeeting
            Write-Host $Status
        }
        ElseIf ($TeamsStatus -like "*Setting the taskbar overlay icon - $lgOffline*" -or `
                $TeamsStatus -like "*StatusIndicatorStateService: Added Offline*") {
            $Status = $lgOffline
            Write-Host $Status
        }

        If($TeamsActivity -eq $null){ }
        ElseIf ($TeamsActivity -like "*Resuming daemon App updates*" -or `
            $TeamsActivity -like "*SfB:TeamsNoCall*" -or `
            $TeamsActivity -like "*name: desktop_call_state_change_send, isOngoing: false*") {
            $Activity = $lgNotInACall
            $ActivityIcon = $iconNotInACall
            Write-Host $Activity
        }
        ElseIf ($TeamsActivity -like "*Pausing daemon App updates*" -or `
            $TeamsActivity -like "*SfB:TeamsActiveCall*" -or `
            $TeamsActivity -like "*name: desktop_call_state_change_send, isOngoing: true*") {
            $Activity = $lgInACall
            $ActivityIcon = $iconInACall
            Write-Host $Activity
        }
    }
    # Set status to Offline when the Teams application is not running
    Else {
            $Status = $lgOffline
            $Activity = $lgNotInACall
            $ActivityIcon = $iconNotInACall
            Write-Host $Status
            Write-Host $Activity
    }

    # Call Home Assistant API to set the status and activity sensors
    If ($CurrentStatus -ne $Status -and $Status -ne $null) {
        $CurrentStatus = $Status

        $params = @{
        "state"="$CurrentStatus";
        "attributes"= @{
            "friendly_name"="$entityStatusName";
            "icon"="mdi:microsoft-teams";
            }
        }
        
        $params = $params | ConvertTo-Json
        Invoke-RestMethod -Uri "$HAUrl/api/states/$entityStatus" -Method POST -Headers $headers -Body ([System.Text.Encoding]::UTF8.GetBytes($params)) -ContentType "application/json" 
    }

    If ($CurrentActivity -ne $Activity) {
        $CurrentActivity = $Activity

        $params = @{
        "state"="$Activity";
        "attributes"= @{
            "friendly_name"="$entityActivityName";
            "icon"="$ActivityIcon";
            }
        }
        $params = $params | ConvertTo-Json
        Invoke-RestMethod -Uri "$HAUrl/api/states/$entityActivity" -Method POST -Headers $headers -Body ([System.Text.Encoding]::UTF8.GetBytes($params)) -ContentType "application/json" 
    }
        
}

Quick look at the code and it only sends state to HA when there is a change

So in your case, you restart HA but didn’t change Teams state it will show “Unavailable”.
The last script up there runs every 5 seconds so it would send state regardless.

If you change

If ($CurrentStatus -ne $Status -and $Status -ne $null) {

to

If ($Status -ne $null) {

Then it will send status every time the code runs. Or you could get this code to check if the state is unavailable and send an update if so.

Several ways to slice this cat.

Hi @fanuch,

Tried to adapt following your remarks, but still my teamsstatus gets an unknown state after reboot of Hass. I think the problem is that the start / sleep functionality doesn’t work somehow to periodically send the status over:

# Configuring parameter for interactive run
Param($SetStatus)

# Import Settings PowerShell script
. ($PSScriptRoot + "\Settings.ps1")

$headers = @{"Authorization"="Bearer $HAToken";}

# Run the script when a parameter is used and stop when done
If($null -ne $SetStatus){
    Write-Host ("Setting Microsoft Teams status to "+$SetStatus+":")
    $params = @{
     "state"="$SetStatus";
     "attributes"= @{
        "friendly_name"="$entityStatusName";
        "icon"="mdi:microsoft-teams";
        }
     }
	 
    $params = $params | ConvertTo-Json
    Invoke-RestMethod -Uri "$HAUrl/api/states/$entityStatus" -Method POST -Headers $headers -Body ([System.Text.Encoding]::UTF8.GetBytes($params)) -ContentType "application/json"
    break
}

If ($env:APPDATA -match "C:\\Users") {
	$path = "$env:APPDATA\Microsoft\Teams\logs.txt"
}
Else {
	$path = "C:\Gebruikers\bart.weemaels$([char]0X0040)cegeka.be\AppData\Roaming\Microsoft\Teams\logs.txt"
}

# Start monitoring the Teams logfile when no parameter is used to run the script
Get-Content -Path $path -Tail 10000 -ReadCount 0 -Encoding Utf8 -Wait | % {
    
    # Get Teams Logfile and last icon overlay status
    $TeamsStatus = $_ | Select-String -Pattern `
        'Setting the taskbar overlay icon -',`
        'StatusIndicatorStateService: Added' | Select-Object -Last 1

    # Get Teams Logfile and last app update deamon status
    $TeamsActivity = $_ | Select-String -Pattern `
        'Resuming daemon App updates',`
        'Pausing daemon App updates',`
        'SfB:TeamsNoCall',`
        'SfB:TeamsPendingCall',`
        'SfB:TeamsActiveCall',`
        'name: desktop_call_state_change_send, isOngoing' | Select-Object -Last 1

    # Get Teams application process
    $TeamsProcess = Get-Process -Name Teams -ErrorAction SilentlyContinue

    # Check if Teams is running and start monitoring the log if it is
    If ($null -ne $TeamsProcess) {
        If($TeamsStatus -eq $null){ }
        ElseIf ($TeamsStatus -like "*Setting the taskbar overlay icon - $lgAvailable*" -or `
            $TeamsStatus -like "*StatusIndicatorStateService: Added Available*" -or `
            $TeamsStatus -like "*StatusIndicatorStateService: Added NewActivity (current state: Available -> NewActivity*") {
            $Status = $lgAvailable
            Write-Host $Status
        }
        ElseIf ($TeamsStatus -like "*Setting the taskbar overlay icon - $lgBusy*" -or `
                $TeamsStatus -like "*StatusIndicatorStateService: Added Busy*" -or `
                $TeamsStatus -like "*Setting the taskbar overlay icon - $lgOnThePhone*" -or `
                $TeamsStatus -like "*StatusIndicatorStateService: Added OnThePhone*" -or `
                $TeamsStatus -like "*StatusIndicatorStateService: Added NewActivity (current state: Busy -> NewActivity*") {
            $Status = $lgBusy
            Write-Host $Status
        }
        ElseIf ($TeamsStatus -like "*Setting the taskbar overlay icon - $lgAway*" -or `
                $TeamsStatus -like "*StatusIndicatorStateService: Added Away*" -or `
                $TeamsStatus -like "*StatusIndicatorStateService: Added NewActivity (current state: Away -> NewActivity*") {
            $Status = $lgAway
            Write-Host $Status
        }
        ElseIf ($TeamsStatus -like "*Setting the taskbar overlay icon - $lgBeRightBack*" -or `
                $TeamsStatus -like "*StatusIndicatorStateService: Added BeRightBack*" -or `
                $TeamsStatus -like "*StatusIndicatorStateService: Added NewActivity (current state: BeRightBack -> NewActivity*") {
            $Status = $lgBeRightBack
            Write-Host $Status
        }
        ElseIf ($TeamsStatus -like "*Setting the taskbar overlay icon - $lgDoNotDisturb *" -or `
                $TeamsStatus -like "*StatusIndicatorStateService: Added DoNotDisturb*" -or `
                $TeamsStatus -like "*StatusIndicatorStateService: Added NewActivity (current state: DoNotDisturb -> NewActivity*") {
            $Status = $lgDoNotDisturb
            Write-Host $Status
        }
        ElseIf ($TeamsStatus -like "*Setting the taskbar overlay icon - $lgFocusing*" -or `
                $TeamsStatus -like "*StatusIndicatorStateService: Added Focusing*" -or `
                $TeamsStatus -like "*StatusIndicatorStateService: Added NewActivity (current state: Focusing -> NewActivity*") {
            $Status = $lgFocusing
            Write-Host $Status
        }
        ElseIf ($TeamsStatus -like "*Setting the taskbar overlay icon - $lgPresenting*" -or `
                $TeamsStatus -like "*StatusIndicatorStateService: Added Presenting*" -or `
                $TeamsStatus -like "*StatusIndicatorStateService: Added NewActivity (current state: Presenting -> NewActivity*") {
            $Status = $lgPresenting
            Write-Host $Status
        }
        ElseIf ($TeamsStatus -like "*Setting the taskbar overlay icon - $lgInAMeeting*" -or `
                $TeamsStatus -like "*StatusIndicatorStateService: Added InAMeeting*" -or `
                $TeamsStatus -like "*StatusIndicatorStateService: Added NewActivity (current state: InAMeeting -> NewActivity*") {
            $Status = $lgInAMeeting
            Write-Host $Status
        }
        ElseIf ($TeamsStatus -like "*Setting the taskbar overlay icon - $lgOffline*" -or `
                $TeamsStatus -like "*StatusIndicatorStateService: Added Offline*") {
            $Status = $lgOffline
            Write-Host $Status
        }

        If($TeamsActivity -eq $null){ }
        ElseIf ($TeamsActivity -like "*Resuming daemon App updates*" -or `
            $TeamsActivity -like "*SfB:TeamsNoCall*" -or `
            $TeamsActivity -like "*name: desktop_call_state_change_send, isOngoing: false*") {
            $Activity = $lgNotInACall
            $ActivityIcon = $iconNotInACall
            Write-Host $Activity
        }
        ElseIf ($TeamsActivity -like "*Pausing daemon App updates*" -or `
            $TeamsActivity -like "*SfB:TeamsActiveCall*" -or `
            $TeamsActivity -like "*name: desktop_call_state_change_send, isOngoing: true*") {
            $Activity = $lgInACall
            $ActivityIcon = $iconInACall
            Write-Host $Activity
        }
    }
    # Set status to Offline when the Teams application is not running
    Else {
            $Status = $lgOffline
            $Activity = $lgNotInACall
            $ActivityIcon = $iconNotInACall
            Write-Host $Status
            Write-Host $Activity
    }

    # Call Home Assistant API to set the status and activity sensors
#    If ($CurrentStatus -ne $Status -and $Status -ne $null) {
     If ($Status -ne $null) {
        $CurrentStatus = $Status

        $params = @{
        "state"="$CurrentStatus";
        "attributes"= @{
            "friendly_name"="$entityStatusName";
            "icon"="mdi:microsoft-teams";
            }
        }
        
        $params = $params | ConvertTo-Json
        Invoke-RestMethod -Uri "$HAUrl/api/states/$entityStatus" -Method POST -Headers $headers -Body ([System.Text.Encoding]::UTF8.GetBytes($params)) -ContentType "application/json" 
    }

    If ($CurrentActivity -ne $Activity) {
        $CurrentActivity = $Activity

        $params = @{
        "state"="$Activity";
        "attributes"= @{
            "friendly_name"="$entityActivityName";
            "icon"="$ActivityIcon";
            }
        }
        $params = $params | ConvertTo-Json
        Invoke-RestMethod -Uri "$HAUrl/api/states/$entityActivity" -Method POST -Headers $headers -Body ([System.Text.Encoding]::UTF8.GetBytes($params)) -ContentType "application/json"
	Start-Sleep 5 
    }
        
}

Kind regards,

Bart

Hi @fanuch , @Egglestron , @EBOOZ ,

Has anyone an idea why the script above doesn’t pass status to HA after I reboot my HA ?

Thanks in advance !

Kr,

Bart

I know this is not 100% the requested topic to pull “microsoft teams stauts”,
but I am using Hass-Workstation-Service, which provides sensors for WebCam & Microphone being active out-of-the-box (and a lot of possible WMI based sensors you can create on your own).

A use case I have created is, as soon as my WebCam gets active or my microphone is on I am turning off / putting my alexa into DND mode. That way I cover not only teams meeting calls, but additionally others with externals using Zoom, WebEx, (legacy skype) etc…or just doing a phone call via differnet VOIP application on my PC.

1 Like

I’ve told you why.
The script pushes a status as a “dynamic sensor” or whatever.
On reboot, HA has no way to find out until another push happens.

I rebooted my HA during a meeting and I still had my status; because of my high status refresh rate.

I am using this script:

Which sends a status to HA every 5 seconds regardless of the status (unlike the script you are using)

Thanks a lot @fanuch ,

I gave it a try, but got the following error:

Invoke-RestMethod : 401: Unauthorized
At C:\scripts\Get-TeamsStatus.ps1:18 char:5
+     Invoke-RestMethod -Uri 'http://192.168.1.142:8123/api/states/sens ...
+     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebExc
   eption
    + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand

I’ve changed the homeassistant address to my homeassistant address and that’s it…

Any clue ?

Clue is this one :wink:
Your HA is replying unauthorized

@dcnoren thanks for sharing your edit. This is great!

I was unable to find the registry key in HKEY_CURRENT_USER, however I was able to find it in HKEY_LOCAL_MACHINE. Below is the change I made to get this working:

$webcam = Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\CapabilityAccessManager\ConsentStore\webcam\NonPackaged\C:#Users#$UserName#AppData#Local#Microsoft#Teams#current#Teams.exe" -Name LastUsedTimeStop | select LastUsedTimeStop

I’m assuming this is the result of some change by Microsoft and not specific to me or my machine.