≡ Menu

It’s time for another Exchange Connections conference in Vegas. This year Exchange Connections runs from September 30th through October 4th. There’s some really great content this year (along with a lot of really awesome speakers) covering On-premises Exchange, Hybrid deployments, Exchange Online, Exchange integration with Lync, and more. I’ll be delivering a pre-conference workshop Monday on how to use PowerShell to manage Exchange. Here’s the details:

From Zero to Hero: PowerShell for Exchange Server Boot Camp

In this pre-conference workshop, you will learn how to be effective in the Exchange Management Shell (EMS), even if you have little to no PowerShell experience. The command syntax in PowerShell can be intimidating at first, but once you understand some simple core concepts, you can vastly maximize your efficiency. Learn the techniques used to automate routine tasks and solve common problems that Exchange administrators face on a regular basis. Finally discover how to deal with the common pitfalls and stumbling blocks that arise when working with EMS. When you walk away, you’ll be ready to automate tasks in your own Exchange environment, armed with clear code samples that provision multiple recipients, make changes in bulk, generate advanced reports, and much more. Don’t let point and click administration slow you down any longer.

You can find the conference website here:
http://www.devconnections.com/dev13/public/Content.aspx?ID=1050160&sortMenu=102005

If you register before the end of June you can get an early bird registration discount:
http://www.devconnections.com/dev13/public/Content.aspx?ID=1050160&sortMenu=102005

Also check out Tony Redmond’s write up on the conference:
http://windowsitpro.com/blog/fantastic-session-line-selected-exchange-connections

See you in Vegas!

0 comments

I’ll be speaking at TechMentor, which runs September 30th through October 4th 2013 in Las Vegas, Nevada. Join me at the newly formatted event with hand-on labs and deep dive sessions. Surrounded by your fellow IT professionals, TechMentor provides you with immediately usable IT education that will keep you relevant in the workforce. There is a ton of great content covering Security, Networking, PowerShell, System Center, SharePoint, Virtualization, and of course, Exchange & Office 365.

I’ll be presenting the following sessions:

  • Moving to Exchange 2013: An Upgrade and Coexistence Deep Dive – It’s no secret that executing a smooth Exchange upgrade requires a lot of careful planning. In this session, you’ll learn what is required to successfully implement and move to an Exchange 2013 on-premises deployment. Get a head start on planning your project and walk away with tips from the field, best practices, and implementation techniques used by early adopters in real-world deployments.
  • To the Cloud! Exchange Hybrid Deployments and Office 365 – Find out how you can seamlessly integrate your on-premises Exchange organization with Office 365. With rich co-existence, organizations can host mailboxes in the cloud, and on-premises, while retaining the best features offered by Exchange across both platforms. You can share calendars and free/busy information; maintain a unified global address list, archive e-mail messages, and much more. Learn about key components such as Directory Synchronization and Active Directory Federation Services, and leave the session with a good grasp on how to implement your own hybrid deployment.

As a speaker, I can extend $400 savings on the 5-day package. Register here: http://bit.ly/TMVSK14Reg and use code TMVSK14.

Learn how you can build a more productive IT environment at TechMentor Las Vegas — bring the IT issues that keep you up at night and prepare to leave this event with the answers, guidance and training you need. Register now and I’ll see you in Vegas!

1 comment

Here’s a quick tip. If you want to view or export a list of all your Response Group agents and associated groups in Lync, use the Get-CsRgsAgentGroup cmdlet.

foreach($i in Get-CsRgsAgentGroup) {
    $i.AgentsByUri | select @{n='Response Group';e={$i.name}},@{n='Agent';e={$_.LocalPath}}
} 

The output would give you something like this.

If you want to export to a CSV file, use this syntax.

$report = foreach($i in Get-CsRgsAgentGroup) {
    $i.AgentsByUri | select @{n='Response Group';e={$i.name}},@{n='Agent';e={$_.LocalPath}}
}
$report | Export-Csv c:\rgs.csv -NoTypeInformation

Not the most intuitive or elegant code, but it works.

1 comment

I’ve been asked several times how to modify my previous function to add custom holidays to a calendar. I figured I would create a new function geared specifically for this task. If you take a look at a typical holiday event on a calendar, like the one below (yes, Golfer’s Day really is a holiday, at least for some), you’ll notice that its basically just an all day appointment, where the free/busy status is set to free, and the category is set to Holiday. I’ve added the required changes to the previous function and added the ability to accept pipeline input.

If you’re looking for more background on exactly what is going on with a the majority of this code, like getting connected to the end-point on your CAS, specifying credentials, etc., check out my older posts on EWS. Also, Glenn has a great “How-To” series over at his blog. What you need to do is add the following function to your PowerShell session:

function New-Holiday {
    [CmdletBinding(DefaultParametersetName='Identity')]
    param(
        [Parameter(Position=0, ParameterSetName='Identity')]
        $Identity,

        [Parameter(Position=1, Mandatory=$true)]
        $Subject,

        [Parameter(Position=2, Mandatory=$true)]
        $Date,

        [Parameter(Position=3)]
        [Switch]$Impersonate,

        [Parameter(Position=4)]
        $ExchangeVersion = 'Exchange2010_SP2',

        [Parameter(Position=5, ParameterSetName='Pipeline', ValueFromPipelineByPropertyName=$true)]
        $PrimarySmtpAddress,

        [Parameter(Position=6)]
        [System.Management.Automation.PSCredential]
        $Credential,

        [Parameter(Position=7)]
        $EWSUrl
    )

    begin {
        #Load the EWS Assembly
        Add-Type -Path "C:\Program Files\Microsoft\Exchange\Web Services\1.2\Microsoft.Exchange.WebServices.dll"
    }

    process {
        #Is the identity coming from the pipeline?
        if($PsCmdlet.ParameterSetName -eq 'Pipeline') {
            $Identity = $PrimarySmtpAddress.ToString()
        }

        #Create the ExchangeService object
        $service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService -ArgumentList ([Microsoft.Exchange.WebServices.Data.ExchangeVersion]::$ExchangeVersion)

        #If Credential parameter used, set the credentials on the $service object
        if($Credential) {
            $service.Credentials = New-Object Microsoft.Exchange.WebServices.Data.WebCredentials -ArgumentList $Credential.UserName, $Credential.GetNetworkCredential().Password
        }

        #If EWSUrl parameter not used, locate the end-point using autoD
        if(!$EWSUrl) {
            $service.AutodiscoverUrl($Identity, {$true})
        }
        else {
            $service.Url = New-Object System.Uri -ArgumentList $EWSUrl
        }        

        #If Impersonation parameter used, impersonate the user
        if($Impersonate) {
            $ImpersonatedUserId = New-Object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId -ArgumentList ([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress),$Identity
            $service.ImpersonatedUserId = $ImpersonatedUserId
        }

        #Configure the start and end time for this all day event
        $start = (get-date $date)
        $end = $start.addhours(24)

        #Create and save the appointment
        $appointment = New-Object Microsoft.Exchange.WebServices.Data.Appointment -ArgumentList $service
        $appointment.Subject = $Subject
        $appointment.Start = $Start
        $appointment.End = $End
        $appointment.IsAllDayEvent = $true
        $appointment.IsReminderSet = $false
        $appointment.Categories.Add('Holiday')
        $appointment.Location = 'United States'
        $appointment.LegacyFreeBusyStatus = [Microsoft.Exchange.WebServices.Data.LegacyFreeBusyStatus]::Free
        $appointment.Save([Microsoft.Exchange.WebServices.Data.SendInvitationsMode]::SendToNone)
    }
}

Here are a few examples of how to run this code. Keep in mind that to add entries to another persons calendar you’ll need to be assigned the Application Impersonaiton RBAC role or have rights to their mailbox.

Here’s an example of adding a holiday to my own calendar. I’m already signed into Windows with my own mailbox-enabled Active Directory account, and this could be done in the standard “blue” shell or EMS:

New-Holiday -Identity mike@domain.com -Subject "Golfer's Day" -Date 4/10/13

This function also has an additional parameter set, and it can accept the identity of the mailbox from the pipeline in EMS. This means its easy to create these custom holidays on behalf of other users, in bulk, as long as you have impersonation rights:

Get-Mailbox -OrganizationalUnit Sales | New-Holiday -Subject "Golfer's Day" -Date 4/10/13 -Impersonate

Finally, you can use this function to add custom holidays to the calendars for Office 365 mailboxes. For example, here’s how I would add a holiday to my cloud mailbox, using the -Credential parameter to authenticate:

$cred = Get-Credential
New-Holiday -Identity mike@domain.onmicrosoft.com -Subject "Golfer's Day" -Date 4/10/13 -Credential $cred

I’ve added lots of comments in the code for each phase of the function. Hopefully it will be fairly straight forward if you need to extend it further to meet your specific requirements. One more FYI – prior to posting this, I tested the code on PowerShell v3 with both on prem Exchange 2010 SP2, and Exchange Online (Wave 15) mailboxes with the 1.2 version of the EWS Managed Api and everything worked great.

0 comments

I’ve worked with a few customers lately that have asked for an automated method to deactivate Lync for disabled AD accounts. For most applications, such as Exchange, these two things go hand in hand. Disabling the AD account prevents access to the application. Lync, however, works a little differently.

After initially signing into Lync (with the “Save My Password” box checked), users are issued a certificate which can be used for authentication, and it is valid for up to six months. Subsequent logons to Lync will use TLS-DSK as the primary authentication protocol over Kerberos or NTLM. Certificate based authentication makes it possible to authenticate without AD (think branch site resiliency), and makes PIN based authentication easier for devices without a keyboard.

You’ll want to keep this in mind when it comes to de-provisioning users. As Jeff points out in his article “Disabling a User in AD Does Not Disable the User In Lync“, you need to disable the Lync user, or revoke the certificate to ensure that disabled AD accounts cannot access the application.

Of course, extra steps can lead to missed steps, so automation in the form of a PowerShell script once again comes to the rescue. The Lync Server Management Shell provides an easy way to detect and fix this.

As you can see above, checking a single disabled users account with the Get-CsAdUser cmdlet shows two interesting properties: UserAccountControl and Enabled. If the UserAccountControl property contains AccountDisabled, and Enabled is set to $True, then we know this is a user who may still sign into Lync if he has a valid certificate installed.

To automate a fix, you can use a simple one-liner to retrieve all users and check these two properites. If you find a match, you can disable their access to Lync permanently using Disable-CsUser. This would be the way to go if the user is gone for good and is never coming back.

Get-CsAdUser -ResultSize Unlimited | 
  Where-Object {$_.UserAccountControl -match 'AccountDisabled' -and $_.Enabled -eq $true} | 
    Disable-CsUser

You could also simply revoke the certificate with Revoke-CsClientCertificate. This might be a better solution if the AD account is only temporarily being disabled and the user will eventually sign back into Lync again later.

Get-CsAdUser -ResultSize Unlimited | 
  Where-Object {$_.UserAccountControl -match 'AccountDisabled' -and $_.Enabled -eq $true} | 
    Revoke-CsClientCertificate

Pick the best method for your environment and save the code to a .ps1 script. Don’t forget the import the Lync cmdlets with either Import-Module Lync or with remoting at the beginning of your script to get the Lync cmdlets loaded. You can schedule PowerShell.exe using the Windows Task Scheduler to run your .ps1 script on a regular basis for a completely automated solution.

0 comments