#Take an action when Lync presence indicates you are on a phone call
#v1.4.4 5/30/13
[CmdletBinding()]
param()
#Put your custom code in this function in response to being on or off the phone
function OffHook-Action ($action)
{
if ($action -eq 'offhook')
{
#Do something
Pause-Winamp
Write-VerboseEvent "Off-hook action executed"
}
else
{
#Undo something
Play-Winamp
Write-VerboseEvent "On-hook action executed"
}
}
#Region Your dependent function(s) for off-hook actions
$winamp = New-Object -ComObject ActiveWinamp.Application
function Play-Winamp
{
#Play only if Winamp currently paused
if ($winamp.PlayState -eq 3)
{
$winamp.Play()
}
}
function Pause-Winamp
{
#Pause only if Winamp currently playing
if ($winamp.PlayState -eq 1)
{
$winamp.Pause()
}
}
#EndRegion
#Region Core functions
function Write-VerboseEvent ($text)
{
if ($verboseEvent)
{
Write-Host "VERBOSE: $((Get-Date).ToLongTimeString()) - $text" -ForegroundColor Yellow -BackgroundColor Black
}
}
function Connect-LyncClient
{
$i = 1
do
{
#Attach to Lync process, if running
#Choose 'lync' line for 2013, 'communicator' line for 2010
$lyncProcess = [System.Diagnostics.Process]::GetProcessesByName('lync')
#$lyncProcess = [System.Diagnostics.Process]::GetProcessesByName('communicator')
if ($lyncProcess.Length -eq 0) #Process is not running
{
if ($i -eq 1) #Report status only on first attempt
{
Write-Host "$((Get-Date).ToLongTimeString()) - Waiting for Lync process to start (15-second intervals)..." -ForegroundColor Yellow
}
$i++
Start-Sleep 15
}
}
until ($lyncProcess.Length -eq 1)
#Register for when Lync process exits
Register-ObjectEvent -InputObject $lyncProcess[0] -EventName "Exited" -SourceIdentifier "LyncProcessHandler" -Action {LyncProcess-Handler} | Out-Null
#Wait for client object initialization to complete
do
{
$global:client = [Microsoft.Lync.Model.LyncClient]::GetClient()
}
while (-not $client -or $client.State -eq [Microsoft.Lync.Model.ClientState]::Invalid)
}
function Register-ContactChange
{
#Create self object as a contact
$global:selfContact = $client.Self.Contact
#Register for contact changes
Register-ObjectEvent -InputObject $selfContact -EventName "ContactInformationChanged" -SourceIdentifier "OffHookHandler" -Action {Offhook-Handler $event} | Out-Null
#Get initial off-hook status and set state variable
$activity = $selfContact.GetContactInformation([Microsoft.Lync.Model.ContactInformationType]::Activity)
if ($activity -eq 'In a call' -or $activity -eq 'In a conference call')
{
$global:offhook = $true
}
else
{
$global:offhook = $false
}
}
function Register-ClientStateChange
{
#Register for sign-in changes
Register-ObjectEvent -InputObject $client -EventName "StateChanged" -SourceIdentifier "ClientStateHandler" -Action {ClientState-Handler $event} | Out-Null
}
function Offhook-Handler ($event)
{
#Act if what has changed is activity
if ($event.SourceEventArgs.ChangedContactInformation -contains 'Activity')
{
$newActivity = $selfContact.GetContactInformation([Microsoft.Lync.Model.ContactInformationType]::Activity)
#Act only on true activity change
if ($newActivity -ne $currentActivity)
{
#Act if off- or on-hook
if ($newActivity -eq 'In a call' -or $newActivity -eq 'In a conference call')
{
if ($offhook -eq $false) #Only run off-hook action if not already on a call
{
Write-VerboseEvent $newActivity
OffHook-Action 'offhook'
$global:offhook = $true #Stateful tracking of status in successive changes
}
}
else
{
if ($offhook)
{
OffHook-Action 'onhook'
Write-VerboseEvent "No longer on the phone ($newActivity)"
$global:offhook = $false
}
else
{
Write-VerboseEvent "Non-phone activity change: $newActivity"
}
}
#Global variable provides stateful tracking of activity change
$global:currentActivity = $newActivity
}
}
}
function ClientState-Handler ($event)
{
#Get current client state
$newState = $event.SourceEventArgs.NewState
if ($newState -eq 'SignedIn')
{
Register-ContactChange
Write-VerboseEvent "Activity changes now being monitored."
}
elseif ($newState -eq 'SignedOut')
{
$subscriptionSource = Get-EventSubscriber | Select-Object -ExpandProperty SourceIdentifier
if ($subscriptionSource -contains "OffHookHandler")
{
#If subscription currently is registered, remove it so it can
#be successfully created again when signed in
Unregister-Event OffHookHandler
Write-VerboseEvent "Activity changes will be monitored when the client signs in."
}
}
}
function LyncProcess-Handler
{
Write-Host "$((Get-Date).ToLongTimeString()) - Lync client has shut down." -ForegroundColor Yellow
#Client object is invalid if Lync process stops
Stop-Monitoring
#Restart connection and registration steps
Connect-LyncClient
Initialize-Registration
}
function Initialize-Registration
{
#Register for contact changes if client is already signed in
if ($client.State -eq [Microsoft.Lync.Model.ClientState]::SignedIn)
{
Register-ContactChange
Write-Host "$((Get-Date).ToLongTimeString()) - Activity changes now being monitored." -ForegroundColor Green
Register-ClientStateChange
}
#Register for client changes, which will handle contact change registration
else
{
Register-ClientStateChange
Write-VerboseEvent "Activity changes will be monitored when the client has signed in."
}
}
function Stop-Monitoring
{
Unregister-Event OffHookHandler -ErrorAction SilentlyContinue
Unregister-Event ClientStateHandler -ErrorAction SilentlyContinue
Unregister-Event LyncProcessHandler -ErrorAction SilentlyContinue
Write-VerboseEvent "Events unregistered"
$global:client = $null
$global:lyncProcess = $null
$global:currentActivity = $null
}
#EndRegion
#Region Script body
#Check for dot sourcing
if ($MyInvocation.InvocationName -ne '.')
{
Write-Error "Script was not dot-sourced. This script is designed to be executed by dot sourcing it: . <pathtoscript>" -Category InvalidOperation
break
}
#Check for SDK installation
$apiPath = "C:\Windows\assembly\GAC_MSIL\Microsoft.Lync.Model\4.0.0.0__31bf3856ad364e35\Microsoft.Lync.Model.dll"
if (Test-Path $apiPath)
{
Add-Type -Path $apiPath
#Connect to local Lync client
Connect-LyncClient
}
else
{
Write-Error "This script requires the Lync SDK runtime library." -Category NotInstalled
break
}
#Check for Verbose parameter for event functions
if ($MyInvocation.BoundParameters['verbose'])
{
$global:verboseEvent = $true
}
else
{
$global:verboseEvent = $false
}
#Start event registration
Initialize-Registration
#EndRegion