Talking to Lync 2013/Skype for Business

In a previous post, I said I would make a post on how to get Lync or Skype for Business to respond to Powershell. This post will give you the basics for a script that writes to lync contacts on your behalf. I started writing code for Lync with 2013 and have since then migrated to Skype for Business without any backwards compatibility issues.

While it is possible to have a script running that sets your status to Do not Disturb every time a certain persion (your manager) tries to talk to you, this would result in a DDos attack on your Lync server. There is a way to go on Do not Disturb after the first message has been received, which I will shortly explain at the end of this post.

But first some things you need in order to get Lync to aknowledge the existence of Powershell in the first place. inside the Lync SDK are a couple of Dll’s that we will need. So download de SDK, open it with any archive programme like 7-zip. Inside are the following dll’s that we will need:

  • \LYNC..M.L.MODEL.dll
  • \LYNC..M.L.C.FRAMEWORK.dll
  • \LYNC..M.O.UC.dll
  • \LYNC..M.L.Utilities.dll

First, import the dll’s and make contact with the Lync client:

Import-Module –Name ".\LYNC..M.L.MODEL.dll"
Import-Module –Name ".\LYNC..M.L.C.FRAMEWORK.dll"
Import-Module –Name ".\LYNC..M.o.uc.dll"
Import-Module –Name ".\LYNC..M.L.Utilities.dll"

#Try to connect using a bit of dotnet
Try {
     $Client = [Microsoft.Lync.Model.LyncClient]::GetClient()
}
Catch {
     Write-Host "Lync client not running"
Exit
}
#check if the client is actually signed in, not just running
If ($Client.State -ne "SignedIn") {
     Write-host "Lync client not signed in"
Exit
}

Next,  grab the client status, the contact manager and the status of your contacts:

#get the clients status (put it on 1 line)
$Status_Info = New-Object 'System.Collections.Generic.Dictionary
[Microsoft.Lync.Model.PublishableContactInformationType, object]'
#get all contacts
$contact_man = $Client.self.Contact.ContactManager
#get availability status of all contacts
$contact_stat = $contact_man.GetContactInformation("Availability")

Changing your status

In order to change your lync status, you have to know what number in  $Status_info corresponds to what status (instead of numbers, you could use strings in the switch):

switch($status_String){
    1 {$status = 3000}  # "Available" 
    2 {$status = 6000}  # "Busy"
    3 {$status = 9000}  # "Do Not Disturb"
    4 {$status = 12000} # "Be Right Back"
    5 {$status = 15000} # "Away"
    6 {$status = 15500} # "Off Work"
    7 {$status = 18000} # "Appear Offline"
}

So if you wanted to have a script that changes your Lync status between busy and available, you could do something like this (withouth a switch in this case):


if ($Client.self.Contact.GetContactInformation("Availability") -eq 6500)
{ #for some reason $client always reports 500 more then it wants to receive
$status = 3000 #available}
elseif($Client.self.Contact.GetContactInformation("Availability") -eq 3500)
{
$status = 6000 #busy
}
#publish the change to the client
$Status_Info.Add([Microsoft.Lync.Model.PublishableContactInformationType]::Availability, $status)
$Publish = $client.Self.BeginPublishContactInformation($Status_Info, $null, $null)
$client.self.EndPublishContactInformation($Publish)

Sending a message

So how about sending a message? Given some prior knowledge about your contact list, or the sip of your contact, you can write a script to talk to any contact or person that you would normally be able to talk to through the GUI.

Finding the addres or name of the Lync contact:

#The name of a group:
$Client.ContactManager.Groups[0].Name
#The displaynames in the group:
$Client.ContactManager.Groups[0].getcontactinformation(10)
#the SIP addresses in the group:
$Client.ContactManager.Groups[0].getcontactinformation(11)
#or
$Client.ContactManager.Groups[0].uri

# $contact is now the email address of my first contact (group1, contact 1)
$Contact = $Client.ContactManager.Groups[0].getcontactinformation(11)[0]
#what do you want to say:
$message = "Hello World"
#start the conversation:
$Conversation = $Client.ConversationManager.AddConversation()
#add your contact to it
$Conversation.AddParticipant($contact)
#make the message
$Msg = New-Object "System.Collections.Generic.Dictionary[Microsoft.Lync.Model.Conversation.InstantMessageContentType,String]"
$Msg.Add(0,$Message)
#set the modality to instant message (rather then audio or any other modality)
$Modality = $Conversation.Modalities[1]
#send the message:
$Modality.BeginSendMessage($Msg, $null, $Msg)

Reacting to a message

Work in progress.

Posted in Script Snippets | Tagged , , | Leave a comment

Create a new AD user script (1): What can we set

While making small scripts or games in order to learn Powershell is fine for some, I’ve always found the need for a goal when learning a new skill or language.

This was not different when learning Powershell. My very first complex script was written to talk to the company’s Lync 2013 server (I’ll write a post on how to set yourself on Do not Disturb whenever HR wants to talk to you). But nowadays I advice starting Powershellers to start with writing a script that will create an AD user according to company policy, as this forces you to get acquinted with some odd corners of Powershell.

Making a new user in the right OU, with the right memberships, can be done in 1 or 2 lines, but most companies require both AD and ADSI fields to be filled, mailboxes to be made and Office 365 Licenses to be handed out. So in this line of posts, I will be explaining how to create a script that handles most requirements in any production environment.

To start off, we have an extremely simply script that makes new user in AD. Some of the info could be from a csv or a read-host, but for now we will enter them directly in the code.

$user_ou   = 'OU=Users,DC=Contoso,DC=com'
$firstname = 'John'
$lastname  = 'Doe'
$identity  = "$firstname.$lastname"
$passw = ConvertTo-SecureString "Welcome123" -AsPlainText -force

New-ADUser -Name $identity -GivenName $firstname -Surname `
$lastname -Path $user_ou -AccountPassword $passw

Enable-ADAccount -Identity $identity

So now we have a simply user John.Doe that is only a member of Domain Users. But what about all the other field? Well, most can be done both in New-ADUser  directly and in Set-ADUser. Using the in-build help function we get the following.

PS C:\> Get-Help Set-ADUser
'NAME
 Set-ADUser
SYNTAX

-AccountExpirationDate <datetime>
-CannotChangePassword <bool>
-ChangePasswordAtLogon <bool>
-City <string>
-Company <string>
-Country <string>
-Department <string>
-Description <strin
-DisplayName <string>
-Division <string>
-...'

And the list goes on for some time. But still there are some things we cannot set with AD cmdlets, simply because under the hood they are not part of Active Directory, but are directly from ADSI, shown in AD. The most notorious two of these are the Remote Desktop Services Profile tab and the  Attribute Editor. While the latter can be addressed using

Set-ADUser -Identity $identity -Add @{"extensionattribute1"='..'}

I’ve found that doesn’t always respond the same way to Powershell object, sometimes also adding any special characters like “”. using an [ADSI] object seems to be more reliable, and also allows us to set any Remote Desktop Services for our user:

$homedrive     = 'H:'
$homedir       = "\\server\homedirs\$identity"
$user = [ADSI] "LDAP://CN=$identity,$path"
$user.psbase.Invokeset("TerminalServicesHomeDirectory",$homedir) 
$user.psbase.invokeSet("TerminalServicesHomeDrive",$homedrive)
$user.psbase.invokeset('Extensionattribute1','MyString')
$user.setinfo()

Starting with these pointers, together with Google and Get-help, we will start building a first new_user.ps1 script for our imaginary company. <future link to next blog post>

 

Posted in Script Snippets | Tagged , , | Comments Off on Create a new AD user script (1): What can we set