Showing posts with label PowerShell. Show all posts
Showing posts with label PowerShell. Show all posts

10 June 2014

PowerShell: Disabling Lync Accounts

When you use certificate authentication with Lync, a user can still use Lync for up to 6 months by default. You can change this setting using the Set-CsWebServiceConfiguration -MaxValidityPeriodHours XX cmdlet. Even when we change this setting, once a user's AD account has been disabled we don't want them signing into Lync and using the system. In my environment when the user's account is disabled, the Lync account is disabled that night. Rather than adding to the Service Desk's task list, I automated the process.

This script searches AD for disabled accounts, checks to see if the account is still enabled for Lync and if so Lync disables it. It also removes the account from the AD Lync groups that we have. It then sends an email report of the accounts disabled and what the Conferencing Policy was.

Email report

** I'm posting the script here for you to review, but the display can mess with some of the HTML code I have included in the script. If you waould like to use it, I would recommend you download it from here.

#******************************************
#
#   DESCRIPTION:  Disables Lync accounts after the AD account has been disabled and removes from Lync AD groups
#   VERSION:  1.0
#   UPDATED: 
#   AUTHOR: Brad Roberts
#   CONTACT: brad@thatucguy.com
#   BLOG: http://www.thatUCguy.com
#   BLOG ENTRY:  http://www.thatucguy.com/2014/06/powershell-disabling-lync-accounts.html
#
#   DISCLAIMER: You running this script means you won't blame me if this breaks your stuff. This script is provided AS IS and is not guaranteed to work perfectly in your environment. Testing is always a good idea. Any risk in running this script is entirely on you.
#
#******************************************

#******************************************
#
# Variable Definitions
#
#******************************************

$strComputerName = gc env:computername
$strSMTPServer = "smtp.thatucguy.com"
$strToEmail = "lync.admin@thatucguy.com"
$strFromEmail = "no-reply@thatucguy.com"
$strSubject = "Lync User Disablement Report"
$dtTimeNow = get-date

#******************************************
#
# Load Required PS Modules
#
#******************************************

if ((Get-Module ActiveDirectory) -eq $null){Import-Module ActiveDirectory}
if ((Get-Module Lync) -eq $null){Import-Module Lync}

#******************************************
#
# Prepare HTML for email
#
#******************************************

$strScriptInfo = "


Script Info
Script Name: " + $MyInvocation.MyCommand.Definition + "
Time: " + $dtTimeNow + "
Run From: " + $strComputerName $strHTMLHeader = $strHTMLHeader + "" $strHTMLHeader = $strHTMLHeader + "" $strHTMLHeader = $strHTMLHeader + "" $strHTMLHeader = $strHTMLHeader + "" $strHTMLHeader = $strHTMLHeader + "" $strHTMLFooter = $strHTMLFooter + $strScriptInfo $strHTMLFooter = $strHTMLFooter + "" $strHTMLFooter = $strHTMLFooter + "" #******************************** # # Look for AD accounts that are disabled but still enabled for Lync # Remove from Lync AD groups # Generate report of accounts to disable in Lync and disable them # #******************************** $strResults = $strResults + "

Lync User Disablement Report

" $DisabledUsers = Get-CsAdUser | ?{$_.UserAccountControl -match "AccountDisabled" -and $_.Enabled -eq $true} if ($DisabledUsers) { $DisabledUsers | Disable-CsUser Remove-ADGroupMember -Identity "Lync-2010-Users" -Members $DisabledUsers.samaccountname Remove-ADGroupMember -Identity "Lync-2010-Silver" -Members $DisabledUsers.samaccountname Remove-ADGroupMember -Identity "Lync-2010-Gold" -Members $DisabledUsers.samaccountname Remove-ADGroupMember -Identity "Lync-2010-Platinum" -Members $DisabledUsers.samaccountname $DisabledUsers = $DisabledUsers | Get-CsUser | Select-Object DisplayName,SamAccountName,SipAddress,ConferencingPolicy | ConvertTo-Html -fragment } else { $DisabledUsers = "There is no one to disable." } $strResults = $strResults + $DisabledUsers #******************************** # # Create email body # #******************************** $strHTMLBody = $strHTMLHeader + $strResults + $strHTMLFooter #******************************** # # Send email report # #******************************** $msg = new-object Net.Mail.MailMessage $smtp = new-object Net.Mail.SmtpClient($strSMTPServer) $msg.From = $strFromEmail $strToEmail | foreach {$msg.To.Add($_)} $msg.subject = $strSubject $msg.IsBodyHtml = $true $msg.body = $strHTMLBody $smtp.Send($msg)

~ brad

"Good communication is as stimulating as black coffee, and just as hard to sleep after." ~ Anne Morrow Lindbergh

13 May 2014

Powershell: Lync User Report

When I first started in my current position, we were positioning to roll out Lync to all of our users company wide. My boss wanted a way to track how many users we actually had enabled. Rather than giving him a simple number of users by running (Get-CsUser).Count, I wanted to be able to provide him more information. In addition I could easily see how well my pools were balanced. This is actually part of a larger report that I have set up as a daily scheduled task. I decided to break it into two pieces for the blog and will post the combined script after that.

Basically this script collects user counts based on registrar pool and Conferencing policy, puts it into a couple nice tables, and emails the report to me. This script provided here looks at two registrar pools and three Conferencing policies. You should be able to modify this as needed for your environment.

I have run this on my Lync 2010 and 2013 Front End servers.

Download the script here. Some of the HTML code included in the script doesn't show up correctly in the preview below.

#******************************************
#
#   DESCRIPTION: Email Report of Lync users based on Registrar Pool and Conferencing Policy
#   VERSION: 1.0
#   UPDATED: 
#   AUTHOR: Brad Roberts
#   CONTACT: brad@thatucguy.com
#   BLOG: http://www.thatUCguy.com
#   BLOG ENTRY: http://www.thatucguy.com/2014/04/powershell-lync-user-report.html
#
#   DISCLAIMER: You running this script means you won't blame me if this breaks your stuff. This script is provided AS IS and is not guaranteed to work perfectly in your environment. Testing is always a good idea. Any risk in running this script is entirely on you.
#
#******************************************

#******************************************
#
# Variable Definitions
#
#******************************************

$strSubject = "Lync User Report"
$strSMTPServer = "smtp.thatucguy.com"
$strToEmail = "lync.admin@thatucguy.com"
$strFromEmail = "no-reply@thatucguy.com"
# Registrar Pools
$poolAmericasFQDN = "lync-pool-americas.thatucguy.com"
$poolAmericas = "Americas Users"
$poolEMEAFQDN = "lync-pool-emea.thatucguy.com"
$poolEMEA = "EMEA Users"
# Conferencing Policies
$ConfSilver = "Lync-Conferencing-Silver"
$ConfGold = "Lync-Conferencing-Gold"
$ConfPlatinum = "Lync-Conferencing-Platinum"

#******************************************
#
# Load Required PS Modules
#
#******************************************

if ((Get-Module ActiveDirectory) -eq $null){Import-Module ActiveDirectory}
if ((Get-Module Lync) -eq $null){Import-Module Lync}

$blnDebug = $false

#********************************
#
# Get User counts, total and for each pool
#
#********************************

$counttotal = (Get-CsUser -OnLyncServer).count
$countamericas = (Get-CsUser -filter {registrarpool -eq $poolAmericasFQDN}).count
$countemea = (Get-CsUser -filter {registrarpool -eq $poolEMEAFQDN}).count
$usercount = $usercount + "

Lync User Report

" $usercount = $usercount + "" $usercount = $usercount + "
Total Users$poolAmericas$poolEMEA
$counttotal$countamericas$countemea
" #******************************** # # Get User counts by Conferencing Policy # #******************************** $countSilver = (Get-CsUser -filter {ConferencingPolicy -eq $ConfSilver}).count $countGold = (Get-CsUser -filter {ConferencingPolicy -eq $ConfGold}).count $countPlatinum = (Get-CsUser -filter {ConferencingPolicy -eq $ConfPlatinum}).count $ConfCount = $ConfCount + "

Lync User Report by Conferencing Policy

" $ConfCount = $ConfCount + "" $ConfCount = $ConfCount + "
Silver UsersGold UsersPlatinum Users
$countSilver$countGold$countPlatinum
" #******************************** # # Create and send email # #******************************** $strComputerName = gc env:computername $dtTimeNow = get-date $strScriptInfo = " Script Info Script Name: " + $MyInvocation.MyCommand.Definition + " Time: " + $dtTimeNow + " Run From: " + $strComputerName $strHTMLHeader = $strHTMLHeader + "" $strHTMLHeader = $strHTMLHeader + "" $strHTMLHeader = $strHTMLHeader + "" $strHTMLHeader = $strHTMLHeader + "" $strHTMLHeader = $strHTMLHeader + "" $strHTMLFooter = $strHTMLFooter + $strScriptInfo $strHTMLFooter = $strHTMLFooter + "" $strHTMLFooter = $strHTMLFooter + "" $strHTMLBody = $strHTMLHeader + $usercount + $ConfCount + $strHTMLFooter $msg = new-object Net.Mail.MailMessage $smtp = new-object Net.Mail.SmtpClient($strSMTPServer) $msg.From = $strFromEmail $strToEmail | foreach {$msg.To.Add($_)} $msg.subject = $strSubject $msg.IsBodyHtml = $true $msg.body = $strHTMLBody $smtp.Send($msg)

Hope this helps!

brad

Fun Fact:
Louisiana is the first state to have an Official Crustacean and it is the crawfish.

22 April 2014

Managing Users with Default Policies

User Management is always fun. The longer you have Lync installed, the more policies seem to build up and overlap. Frequently I will pull and manage users based on the policies that they have assigned. This can be done through the Console, but it does get slow the more users you are trying to manage.

While I do have all of my Global policies configured, I prefer to keep specific policies assigned for the major policies. Like I mentioned above this can be slow and tricky in the Console. Finding users who already have a policy assigned is pretty easy using a command like:
Get-CsUser -filter {ConferencingPolicy -eq "Lync-Conferencing-Gold"}

This will pull up all the users with the specified policy name, and can easily be piped to another command such as Grant-CsMobilityPolicy.

Finding the users that are inheriting the default Global policy is a little trickier. Running the command
Get-CsUser -filter {ConferencingPolicy -eq "Default"}
will give you the following error.
   "Get-CsUser : Cannot bind parameter 'Filter' to the target. Exception setting "Filter": "Policy "Default" is not a user policy. You can assign only a user policy to a specific user."

In order to find all the users with the default policy assigned you will need to use a command like:
Get-CsUser -filter {ConferencingPolicy -eq $Null}

~brad

Fun Fact:
In a short period of ten years Van Gogh made approximately 900 paintings.

04 April 2014

Changing a User's SIP Domain

One of the big projects that we have been working on is re-branding with a global image. This project started with migrating all of our users to have the same email domain and SIP domain. When Lync was initially installed the decision was made to support two SIP domains.

I was lucky and we only had a handful of users that needed to be changed to out primary SIP domain and could make the changes manually. To change a lot of users you could use a script like this. I have not tested this script, so test it first.

$UserList = Get-CsUser -Filter 'SipAddress -like "*olddomain.com"'
foreach ($User in $UserList)
{
   $oldAddress = $User.SipAddress
   $newAddress = $oldAddress -replace "@olddomain.com", "@newdomain.com"
   Set-CsUser -Identity $User.Identity -SipAddress $newAddress
}

Once you change all of the users, you will want to update the Lync and Exchange address books. The changes will update eventually depending on your replication time and when Address Books are scheduled to rebuild, but we want to have as little impact on the users as possible. I ran all of the PowerShell commands just to be on the safe side.

To update the Lync address book:
     Update-CsAddressBook

To update the Exchange address books:
     Update-GlobalAddressList
     Update-OfflineAddressBook

Impacts to the User
  • When the change is made, the user will be logged off Lync, and they will need to log in with the new SIP address.
  • Internal contacts should update the SIP address automatically – no action required.
  • External contacts will have to re-add the user to their contact list.
  • Lync Online Meetings will now be scheduled using the new meet web address. Any existing meetings will need to be rescheduled. There will be a delay between the changing of the SIP address and the ability to schedule meetings with the new address. Once you have updated the Exchange Address List and Offline Address Book the users will need to close and relaunch Outlook for this change to be picked up.
~ brad

Fun Fact:
The MS 150 is a two-day, 180-mile fund raising cycling ride organized by the National Multiple Sclerosis (MS) Society: Lone Star chapter. This ride is the largest event of its kind in North America taking in about 13,000 riders each year with a goal of raising $18 million towards finding a cure for MS.
This year's 30th Anniversary ride is scheduled 12-13 April 2014.

29 January 2014

Lync Backups with PowerShell

** EDIT: After running this script more, I noticed that running from a Scheduled Task was hit or miss on copying files to the DFS share. I have cleaned up the robocopy command and added some basic error checking to this portion of the script. **

Backups of any production system are always a good idea. SQL backups and vmdk backups of the virtual machines are all great, but may not be the solution you need.

Microsoft has posted the following recommendations for Lync backups.
2010 Backups
2013 Backups

Since I have an environment that contains Lync 2010 and 2013 I wanted one script that would back up my entire environment. The script I have written backs up all the core settings (topology, LIS, voice data, policies, etc) and user information for both Lync 2010 and Lync 2013. It backs the information up locally to the server and then copies the information to a DFS fileshare. The backups are kept for 30 days and then deleted.

To backup the 2010 user data, I copied dbimpexp.exe locally to the 2013 server. Since the output xml file is quite large in my case, I zip the file and delete it before copying everything to the fileshare.

Once the backup and copy are complete a basic email report is sent out.

I have the script set up as a Scheduled Task that runs twice a week. Make sure whatever account you schedule this with has Full Control of the Lync share.

You can download the script here. *Please note there is currently a compatibility issue with IE and some of the code is not displaying here. Please download the script or load it in another browser.*

#############################
#
#   Export Script for Backup 
#   Written by Brad Roberts
#   Backs up user data for 2010/2013, config data - copies to $drFolderPath below
#   Updated 27 February 2014
#
#############################
 
Function Add-Zip{
 Param([string]$ZipFilename)
 If(-Not (Test-Path($ZipFilename))){
  Set-Content $ZipFilename ("PK" + [char]5 + [char]6 + ("$([char]0)" * 18))
  (Dir $ZipFilename).IsReadOnly = $False 
 }
 $ShellApplication = New-Object -COM Shell.Application
 $ZipPackage = $ShellApplication.NameSpace($ZipFilename)
 ForEach($File in $Input){ 
  $ZipPackage.CopyHere($File.FullName)
  Start-Sleep -Milliseconds 15000
 }
}
 
### Import Lync Module 
Import-Module "C:\Program Files\Common Files\Microsoft Lync Server 2013\Modules\Lync\Lync.psd1"
 
### Variables To Set 
$folderPath = "C:\Backup" 
$lengthOfBackup = "-30" 
$drFolderPath = "\\thatucguy.com\Lync\Backup" 
$poolFQDN = "lync-2013-pool.thatucguy.com"
 
### Production – Delete Older Than x Days 
get-childitem $folderPath -recurse | where {$_.lastwritetime -lt (get-date).adddays($lengthOfBackup) -and -not $_.psiscontainer} |% {remove-item $_.fullname -force }
 
### Production – Delete Empty Folders 
$a = Get-ChildItem $folderPath -recurse | Where-Object {$_.PSIsContainer -eq $True} 
$a | Where-Object {$_.GetFiles().Count -eq 0} | Remove-Item
 
### Production – Get Date and Create Folder 
$currDate = get-date -uformat "%a-%m-%d-%Y-%H-%M" 
New-Item $folderPath\$currDate -Type Directory
 
### Delete Older Than x Days – DR Side 
get-childitem $drFolderPath -recurse | where {$_.lastwritetime -lt (get-date).adddays($lengthOfBackup) -and -not $_.psiscontainer} |% {remove-item $_.fullname -force }
 
### Delete Empty Folders – DR Side 
$a = Get-ChildItem $drFolderPath -recurse | Where-Object {$_.PSIsContainer -eq $True} 
$a | Where-Object {$_.GetFiles().Count -eq 0} | Remove-Item
 
### Message Out 
Write-Host -ForegroundColor Green "Backup to server in progress"
$strTranscript += "
Backup to server in progress...
"
 
### Export CMS/XDS and LIS 
Export-CsConfiguration -FileName $folderPath\$currDate\XdsConfig.zip 
Export-CsLisConfiguration -FileName $folderPath\$currDate\LisConfig.zip
 
### Export Voice Information
Get-CsDialPlan | Export-Clixml -path $folderPath\$currDate\DialPlan.xml
Get-CsVoicePolicy | Export-Clixml -path $folderPath\$currDate\VoicePolicy.xml
Get-CsVoiceRoute | Export-Clixml -path $folderPath\$currDate\VoiceRoute.xml
Get-CsPstnUsage | Export-Clixml -path $folderPath\$currDate\PSTNUsage.xml
Get-CsVoiceConfiguration | Export-Clixml -path $folderPath\$currDate\VoiceConfiguration.xml
Get-CsTrunkConfiguration | Export-Clixml -path $folderPath\$currDate\TrunkConfiguration.xml
 
### Export RGS Config 
Export-CsRgsConfiguration -Source "service:ApplicationServer:$poolFQDN" -FileName $folderPath\$currDate\RgsConfig.zip
Write-Host -ForegroundColor Green "XDS, LIS and RGS backup to server is completed." 
$strTranscript += "
XDS, LIS and RGS backup to server is complete."
 
### Export User Information 
# Export 2013 data
Export-CsUserData -PoolFqdn $poolFQDN -FileName $folderPath\$currDate\Lync2013UserData.zip
$strTranscript += "
Export of Lync 2013 user data complete."
# Export 2010 data
C:\Admin\Software\dbimpexp /hrxmlfile:"$folderPath\$currDate\Lync2010UserData.xml" /sqlserver:sql-01
$strTranscript += "
Export of Lync 2010 user data complete."
 
#Create new zip file
Get-ChildItem $folderPath\$currDate\Lync2010UserData.xml | Add-Zip $folderPath\$currDate\Lync2010UserData.zip
Remove-Item $folderPath\$currDate\Lync2010UserData.xml
 
### Copy Files to DR Server 
robocopy $folderPath\$currDate $drFolderPath\$currDate /mir /S /tbd
# Check for last file written
if (Test-Path $drFolderPath\$currDate\* -include XdsConfig.zip) {
   $strTranscript += "

Files copied to $drfolderPath\$currDate"
   }
else  {
   $strTranscript += "

Files were NOT copied to $drfolderPath\$currDate. Please validate backup."
   }
 
### Email Transcript
$strSMTPServer = "smtp.thatucguy.com"
$msg = new-object Net.Mail.MailMessage
$smtp = new-object Net.Mail.SmtpClient($strSMTPServer)
 
$strHTMLHeader = $strHTMLHeader + ""
$strHTMLHeader = $strHTMLHeader + ""
$strHTMLHeader = $strHTMLHeader + ""
$strHTMLHeader = $strHTMLHeader + ""
$strHTMLHeader = $strHTMLHeader + ""
 
$strComputerName = gc env:computername
$dtTimeNow = get-date
$strScriptInfo = "


Script Info
Script Name:  " + $MyInvocation.MyCommand.Definition + "
Time:  " + $dtTimeNow + "
Run From:  " + $strComputerName
$strHTMLFooter = $strHTMLFooter + $strScriptInfo
$strHTMLFooter = $strHTMLFooter + ""
$strHTMLFooter = $strHTMLFooter + ""
#$strTranscript = Get-Content $logpath
$strHTMLBody = $strHTMLHeader + $strTranscript + $strHTMLFooter
 
$msg = New-Object System.Net.Mail.MailMessage 
$msg.From = "no-reply@thatucguy.com" 
$msg.To.Add("lync.admin@thatucguy.com") 
$msg.Subject = "Lync Backup Report - " + (Get-Date -format D)
$msg.IsBodyHtml = $true
$msg.body = $strHTMLBody
$smtp.Send($msg)

You can download the script here.
Remember to always test your scripts first in your environment. I cannot be held responsible for any adverse affects.

Hope this helps!

~ Brad

28 January 2014

PowerShell Philosophy

Love it or hate it, PowerShell is a great tool. When I first started out in Lync I would only touch it if I had no other option. These days I do a lot of PowerShell and a lot though the Lync Control Panel, it all depends on what I am trying to accomplish.

My current job has really forced me into learning PowerShell and I'm glad it did. When you are trying to manage 16,000+ users and 14 servers, there are some things that are just so much easier to do via scripting.

I am decent in PowerShell, but there's a lot that I am still learning. Like most of you, I have done my share of looking for scripts online, and then customizing them to my needs. So here its time for me to give some of that back. Hopefully they will be useful to you.

~ Brad