[PowerShell] Set Skype for Business Presence to "In a Call" when you are in a Microsoft Teams call.

I wanted the ability to sync Skype for Business with Microsoft Teams when I was in a Microsoft Teams call. I couldn't find any solutions online so i created a PowerShell script. You can then create a Windows Service to run this script however often as you want. 5 seconds is good enough for me. 

The only things to make sure you have is Skype Modules installed and an Office 365 app with Microsoft Graph permissions:

Delegated - Read user's presence information 
Delegated - Read presence information of all users in your organization 

 Also set your token to expire after 1 day. My script will check the day and renew it if they don't match. 

Enjoy!

______________________________________________________________________

# SET YOUR CACHE DIRECTORY TO VARIABLE

$tokenCache = ($env:APPDATA + "\token.tmp")



Function getToken{



    # Azure AD OAuth User Token for Graph API

    # Get OAuth token for a AAD User (returned as $token)

    # Application (client) ID, tenant ID and redirect URI

    $resourceAppIdURI = "https://graph.microsoft.com"

    $clientId         = "xxxxx-xxxxxx-xxxxxxx-xxxxxx-xxxxx"

    $TenantId       = "xxxxx-xxxxxx-xxxxxxx-xxxxxx-xxxxx"

    $redirectUri      = "https://login.microsoftonline.com/common/oauth2/nativeclient"

    # Add required assemblies

    Add-Type -AssemblyName System.Web, PresentationFramework, PresentationCore

    # Scope - Needs to include all permisions required separated with a space

    $scope = "User.Read.All Group.Read.All" # This is just an example set of permissions

    # Random State - state is included in response, if you want to verify response is valid

    $state = Get-Random

    # Encode scope to fit inside query string

    $scopeEncoded = [System.Web.HttpUtility]::UrlEncode($scope)

    # Redirect URI (encode it to fit inside query string)

    $redirectUriEncoded = [System.Web.HttpUtility]::UrlEncode($redirectUri)

    # Construct URI

    $uri = "https://login.microsoftonline.com/$tenantId/oauth2/v2.0/authorize?client_id=$clientId&response_type=code&redirect_uri=$redirectUriEncoded&response_mode=query&scope=$scopeEncoded&state=$state"

    # Create Window for User Sign-In

    $windowProperty = @{

        Width  = 500

        Height = 700

    }

    $signInWindow = New-Object System.Windows.Window -Property $windowProperty  

    # Create WebBrowser for Window

    $browserProperty = @{

        Width  = 480

        Height = 680

    }

    $signInBrowser = New-Object System.Windows.Controls.WebBrowser -Property $browserProperty

    # Navigate Browser to sign-in page

    $signInBrowser.navigate($uri)  

    # Create a condition to check after each page load

    $pageLoaded = {

        # Once a URL contains "code=*", close the Window

        if ($signInBrowser.Source -match "code=[^&]*") {

            # With the form closed and complete with the code, parse the query string

            $urlQueryString = [System.Uri]($signInBrowser.Source).Query

            $script:urlQueryValues = [System.Web.HttpUtility]::ParseQueryString($urlQueryString)

            $signInWindow.Close()

        }

    }



    # Add condition to document completed

    $signInBrowser.Add_LoadCompleted($pageLoaded)

    # Show Window

    $signInWindow.AddChild($signInBrowser)

    $signInWindow.ShowDialog()

    # Extract code from query string

    $authCode = $script:urlQueryValues.GetValues(($script:urlQueryValues.keys | Where-Object { $_ -eq "code" }))

    if ($authCode) {

        # With Auth Code, start getting token

        # Construct URI

        $uri = "https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token"

        # Construct Body

        $body = @{

            client_id    = $clientId

            scope        = $scope

            code         = $authCode[0]

            redirect_uri = $redirectUri

            grant_type   = "authorization_code"

        }

        # Get OAuth 2.0 Token

        $tokenRequest = Invoke-WebRequest -Method Post -Uri $uri -ContentType "application/x-www-form-urlencoded" -Body $body

        # Access Token

        $token = ($tokenRequest.Content | ConvertFrom-Json).access_token

        $store = storeSecureString -filePath $tokenCache -string $token

    }

    else {

        Write-Error "Unable to obtain Auth Code!"

    }

}



function SetSFBStatus

{

import-module "C:\Program Files\WindowsPowerShell\Modules\Microsoft.Lync.Model.dll"

import-module "C:\Program Files\WindowsPowerShell\Modules\Microsoft.Office.Uc.dll"



# Obtain the entry point to the Lync.Model API

$client = [Microsoft.Lync.Model.LyncClient]::GetClient()



$self = $client.Self;



#Set Details of Personal Note and Availability

#Useful availability codes for use below - 3500 Available, 15500 Away (converted to "Off Work" in this script by setting activity ID), 6500 Busy, 9500 Do not disturb, 12000 Be Right Back)

$availability = 6500

$date = [DateTime]::Now

#$message = "Availability script last run $date"



#Publish personal note and presence availability of the local user

$contactInfo = new-object 'System.Collections.Generic.Dictionary[Microsoft.Lync.Model.PublishableContactInformationType, object]'

$contactInfo.Add([Microsoft.Lync.Model.PublishableContactInformationType]::PersonalNote,

            $message)

$contactInfo.Add([Microsoft.Lync.Model.PublishableContactInformationType]::Availability,

            $availability)

If ($availability -eq 6500) {$contactInfo.Add([Microsoft.Lync.Model.PublishableContactInformationType]::ActivityID, "on-the-phone")}



$ar = $self.BeginPublishContactInformation($contactInfo, $null, $null)

$self.EndPublishContactInformation($ar)

}



# Cache the token if doesnt exist, but check modified date and delete it if its not today



# STORE TOKEN TO A SECURE FILE

function storeSecureString{

    Param(

        $filePath,

        $string

    )

    try{

        $stringForFile = $string | ConvertTo-SecureString -AsPlainText -Force -ErrorAction Stop | ConvertFrom-SecureString -ErrorAction Stop

        Set-Content -Path $filePath -Value $stringForFile -Force -ErrorAction Stop | Out-Null

    }catch{

        Throw "Failed to store string: $($Error[0] | out-string)"

    }

}



# LOAD PASSWORD FROM SECURE FILE

function loadSecureString{

    Param(

        $filePath

    )

    try{

        $string = Get-Content $filePath -ErrorAction Stop | ConvertTo-SecureString -ErrorAction Stop

        $string = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($string)

        $string = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($string)

        if($string.Length -lt 3){throw "no valid string returned from cache"}

        return $string

    }catch{

        Throw

    }

}



$Today = (Get-Date).Day



$attempts = 0

while($true){

    If((Get-Content -Path $tokenCache).Length -lt 3){



        getToken

      

        $token = loadSecureString -filePath $tokenCache



        If(((get-item $tokenCache).LastWriteTime).Day -ne $Today){



            getToken



            $token = loadSecureString -filePath $tokenCache

        }



    }Else{

        $token = loadSecureString -filePath $tokenCache



        try{



            # Specify the URI to call and method

            $uri = "https://graph.microsoft.com/beta/me/presence"

            $method = "GET"



            # Run Graph API query

            $query = Invoke-WebRequest -Method $method -Uri $uri -ContentType "application/json" -Headers @{Authorization = "Bearer $token"} -ErrorAction Stop

            $status = ($query.Content | ConvertFrom-Json).activity



            Write-host "Your current Teams status is $status" -ForegroundColor Green

            If($status -eq "InACall") {

          

            # Set Skype Status to in a call

            SetSFBStatus



            }

            return $False



        }catch{

                Write-host "Your token didn't work! Try again..."

                Remove-Item -Path $tokenCache

                return $False

            }



        }



$attempts++

}







Comments

  1. I only get "your token did not work" :/ . The app IS logging-in, but:

    "Get-Content : Cannot find path 'C:\Users\chavv\AppData\Roaming\token.tmp' because it does not exist.
    At C:\Projects\PowerShell\teams\setSkypeStatus.ps1:289 char:9
    + If((Get-Content -Path $tokenCache).Length -lt 3){
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : ObjectNotFound: (C:\Users\chavv\AppData\Roaming\token.tmp:String) [Get-Content], ItemNot
    FoundException
    + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetContentCommand

    False
    Your token didn't work! Try again..."

    Any help? 10x

    ReplyDelete
    Replies
    1. Make sure the app you created in asure is "Visible to Users"

      Delete

Post a Comment

Popular Posts