21 Reasons to Use Windows PowerShell to Manage Microsoft Lync Server 2010

 

 

Things…

 

 

21 Reasons to Use Windows PowerShell to Manage Lync Server 2010

So you've installed the Release Candidate of Microsoft Lync Server 2010 (finally) and, if you're like most people, the first thing you did was take a look at the Lync Server Control Panel, the new management tool for Lync Server. And, if you're like most people, all it took was one look for you to say, "Wow, this Control Panel is pretty cool. Why would I ever want to use Windows PowerShell to manage Lync Server when I've got this cool new graphical user interface that I can use to manage Lync Server?"

Well, to begin with, we should note that the Control Panel is cool; in fact, we're willing to bet it will serve as a model for other Microsoft teams looking for a way to make it easy for people to manage their product. But does that mean there is no reason whatsoever to use Windows PowerShell to manage Lync Server 2010? Far from it. In fact, we were able to come up with 21 reasons to use Windows PowerShell to manage Microsoft Lync Server 2010:

You don't have to use just PowerShell

From past experience we know that people sometimes shy away from Windows PowerShell because they believe (or sort of believe) that once they start working from the command prompt they're now committed to having to always work from the command prompt. Is that true? Well, not with Lync Server 2010 it isn't. Suppose you do a few things using the Lync Server Control Panel, you switch to PowerShell (via the Lync Server Management Shell) to do something else, and then you switch back to Control Panel. Control Panel will be perfectly fine with that; you won't suddenly start getting the third-degree: "Where have you been? You've been with Windows PowerShell again, haven't you? Don't lie to me, I can see the little indentations in your fingertips where you've been typing! You told me it was over between the two of you!" Trust us: this is not going to happen.

Note. And this is one place where you really can trust us. After all, if there was a way to get yourself into trouble we would have already found it.

In other words, use the Lync Server Control Panel whenever it makes sense to use the Lync Server Control Panel and whenever it's easiest to use the Lync Server Control Panel. And what should you do whenever it doesn't make sense to use the Lync Server Control Panel, and whenever it isn't easiest to use the Lync Server Control Panel? Then use the Lync Server Management Shell. It's like having your cake and eating it, too.

You can glimpse the future of Windows management

A lot of people think that Windows PowerShell is revolutionary because it's the first time Microsoft has developed a command-line interface for system administration. Actually, that's not true: from Netsh to VBScript to Windows Management Instrumentation (WMI), Microsoft has released all sorts of command-line interfaces for system administration. No, what's truly revolutionary about Windows PowerShell is the fact that this is the first command-line interface that Microsoft has fully embraced. In the past, some product teams exposed their management interfaces as WMI objects; some product teams exposed their management interfaces as COM objects; some product teams didn't bother exposing their management interfaces at all. (Or at least not in a way accessible to the typical system administrator.) With Windows PowerShell, however, that has changed dramatically: now, all server teams have to ship a full set of Windows PowerShell cmdlets for their products. And by "full set" we simply mean this: if there's a setting in your application that administrators can manage, then there must be a way to manage that setting use Windows PowerShell. Period.

In other words, one very good reason to use Windows PowerShell to manage Lync Server 2010 is that this will give you a head start on managing other Microsoft server products (such as Microsoft Exchange and Microsoft SQL Server).

You can save the results of a command to a file

OK, we admit it: that last reason was a little lame, wasn't it? After all, as system administrators you aren't so much concerned about the future as you are concerned about the present: you'd rather see what you can do now than hear about all the things you might be able to do in the future. (Personally, we're still waiting for the personal jet packs and the flying cars.)

OK, well, how about this: with Lync Server Control Panel you can return a lot of useful information about your user accounts, your policies, your configuration settings, etc., etc. For example, suppose you need a list of all the users in the Finance department who have been enabled for Lync Server. That's useful information, information you might want to hang on to or forward to someone else. But how exactly do you save information from within the Control Panel?

Well, to be honest, you don't: you can't save data or print data from within the Control Panel. That's not the case with Windows PowerShell, however. For example, this command retrieves information about all the users in the Finance department who have been enabled for Lync Server, and then saves that data as a comma-separated values file:

Get-CsUser –LdapFilter "Department=Finance" | Export-Csv -Path C:\Logs\FinanceUsers.csv

And if you'd prefer to just print that information, well, this command will print the returned data to your default printer:

Get-CsUser –LdapFilter "Department=Finance" | Out-Printer

Note. OK, in this case the printout might not be all that easy-to-read. But that's probably because you're retrieving more information than you need. To learn how to run PowerShell like Golidlocks runs PowerShell ("This returned information is just right! ") see the article Dealing With Information Overload, Part 1.

You can search on LDAP attributes and Lync Server attributes at the same time

The Lync Server Control Panel has some excellent search capabilities: you can search for users based on one or more LDAP attributes (that is, generic Active Directory attributes such as department or job title) or you can search on Lync Server attributes (such as the voice policy assigned to a user). However, you can't search for both LDAP attributes and Lync Server attributes at the same time.

So can you search for both LDAP attributes and Lync Server attributes at the same time in Windows PowerShell? You bet you can, although you have to be a little sneaky about. Granted, neither the Get-CsUser nor the Get-CsAdUser cmdlet allows you to use both the Filter and the LdapFilter parameters in the same command. But here's a command that returns all the users in the Sales department who have been assigned the voice policy RedmondVoicePolicy:

Get-CsUser -LdapFilter "Department=Sales" | Where-Object {$_.VoicePolicy –match "RedmondVoicePolicy"}

You can return just the items configured at a given scope

Suppose you have a bunch of client policies, and you're looking at that list of policies in Lync Server Control Panel. If you want, you can sort those policies by scope; that is, you can sort those policies so that all the site policies are grouped together and all the per-user policies are grouped together. However, there's no way to truly filter by scope: if you sort by scope, with the intention of looking at only your site-scoped policies, you'll still see the global policy and the per-user policies.

So is that also true if you're using Windows PowerShell? Let's hope not; if so, this will be even a lamer reason than reason number 2 was! If you want to see a list of the client policies that have been configured at the site scope, and only those policies that have been configured at the site scope, all you have to do is run this command:

Get-CsClientPolicy -Filter "site:*" | Select-Object Identity

And to see only the per-user policies (also known as "tag policies") just run this command:

Get-CsClientPolicy -Filter "tag:*" | Select-Object Identity

Oh, and if you'd just like to know how many per-user client policies you have you can always use a command like this one:

Get-CsClientPolicy -Filter "tag:*" | Measure-Object

You can view multiple items at the same time

This might be the area where Windows PowerShell shines the brightest: its ability to deal with multiple objects (for example, multiple policies). In Lync Server Control Panel, you can simultaneously view basic information for, say, all your PIN policies. However, if you want to see detailed information for each of those policies you have to open them – and view them – one-by-one. What if you want to use Windows PowerShell to retrieve detailed information for all your PIN policies? Well, that's going to be a major hassle – assuming, of course, that you think it's a hassle to have to run one Windows PowerShell command. Here's a command that retrieves information about all your pin policies:

Get-CsPinPolicy

We know, that is asking an awful lot. But, still ….

You can modify multiple items at the same time

OK, this is really cool. Suppose you have 25 or 30 conferencing policies and each of these policies allows file transfers to all meeting participants as well as peer-to-peer file transfers between individual participants. Your organization has decided that, at least for the time being, file transfers of any kind should no longer be allowed in a conference. That means that you're going to need to modify each of these policies to make sure that file transfers and peer-to-peer file transfers are no longer allowed.

And how are you supposed to do that? Well, within the Lync Server Control Panel, you'll need to open the first conferencing policy, make sure the two types of file transfers have been disabled, then save and close policy 1. After that, you'll need to open the second conferencing policy, make sure the two types of file transfers have been disabled, then save and close policy 2. After that, you'll – well, you get the idea.

So how would you carry out this same task using Windows PowerShell? Like this:

Get-CsConferencingPolicy | Set-CsConferencingPolicy –EnableFileTransfer $False –EnableP2PFileTransfer $False

After that, you'll – well, actually, now that we think about it, there is no "after that." That one command is all you need: that single command uses Get-CsConferencingPolicy to retrieve all your conferencing policies, then pipes those policies to the Set-CsConferencingPolicy cmdlet. In turn, Set-CsConferencingPolicy disables file sharing and peer-to-peer file sharing for each and every policy.

Oh, and did we mention that this requires you to run only a single command. And when your organization changes its mind (because organizations always change your mind) it's just as easy to re-enable file sharing and peer-to-peer file sharing on all your conferencing policies:

Get-CsConferencingPolicy | Set-CsConferencingPolicy –EnableFileTransfer $True –EnableP2PFileTransfer $True

You can combine the output from multiple cmdlets

One of the admittedly-confusing things about Lync Server 2010 is the fact that there are two different cmdlets for retrieving user information: Get-CsAdUser, which is primarily used for retrieving generic Active Directory information; and Get-CsUser, which is primarily used for retrieving Lync Server-specific information. Like we said, at times that can be a little confusing; at other times, it can also be a little frustrating. For example, suppose you'd like to see the department (a generic Active Directory attribute) and the voice policy (a Lync Server attribute) for each of your Lync Server-enabled user accounts. The Lync Server Control Panel can't help you with that, and neither can the two user cmdlets.

Well, not directly anyway. But if you're willing to write a script (or willing to borrow a script written by someone else) you can use Windows PowerShell and the two user cmdlets to retrieve and display both generic Active Directory attribute values and Lync Server-specific attribute values, side-by-side and hand-in-hand. Here's a simple little script that reports back the DisplayName, Department, and VoicePolicy for each user enabled for Lync Server:

$x = Get-CsUser | Select-Object DisplayName, VoicePolicy

foreach ($i in $x)

    $a = $i.DisplayName

   if ($a -ne "")

     {

      $b = Get-CsAdUser -Identity $a

      $i | Add-Member -MemberType NoteProperty -Name `

       Department -Value $b.Department

       $i

     }

    }

And yes, that is kind of cool, isn't it? Which is why we'll investigate – and explain – this technique a little more fully sometime in the near future.

You can input data directly from a text file

In real life (not that those of us who work at Microsoft know much of anything about real life), when it comes time to enable users you're likely to enable multiple users at the same time. For example, perhaps your company has just hired 20 new people, and the Human Resources department has sent you a text file containing some basic information about those people. If you're using Windows PowerShell to enable user accounts then you don't have to retype all that information; instead, you can simply have PowerShell read the data in the text file and then take whatever action you want it to take. How hard is that going to be? Not too hard at all: all you need is the text file and a simple little script. For example, the text file handed to do you might look something like this:

Name,LineUri,Department

Ann Beebe,tel:+14255559998,Sales

Paul Shen,tel:+14255559997,Human Resources

Sara Davis,tel:+14255559996,Sales

Han Mu,tel:+14255559995,Finance

Dennis Bye,tel:+14255559994,Finance

Nothing too fancy there. And here's a sample script that reads the text file, then uses the information in that file to enable the specified users for Lync Server, to assign them a new line URI, and, if that user happens to be a member of the Sales department, assign them a per-user client policy as well:

$newusers = Import-Csv "C:\NewAccounts.txt"

foreach ($user in $newusers)

    {Enable-CsUser -Identity $user.Name `

        -RegistrarPool atl-cs-001.vdomain.com `

        -SipAddressType SamAccountName -SipDomain vdomain.com

     Set-CsUser -Identity $user.Name -LineUri $user.LineUri

     if ($user.Department -eq "Sales")

         {Grant-CsClientPolicy -Identity $user.Name ` -PolicyName "AllPhotosPolicy"}}

Incidentally, you can also input data directly from an Excel spreadsheet. And by the time Lync Server is officially released we plan on posting an article that explains exactly how to do that.

You can interoperate with Microsoft Exchange Server

There will certainly be a few exceptions, but we think it's safe to say that almost everyone who installs Microsoft Lync Server 2010 will also be running some version of Microsoft Exchange Server. (Because, let's face it, who doesn't run some version of Microsoft Exchange Server?) Well guess what? If you're one of those people who are running both Microsoft Exchange and Microsoft Lync Server, it's actually possible to use Windows PowerShell to manage both products at the same time. The details of exactly how you go about doing that are way beyond the scope of this little 21 Things article; that's something we'll have to explore down the road a bit. In the meantime, and just to whet your appetite, here's a command that creates a new mailbox for the user Ken Myer, then, in the same command, enables that user for Lync Server:

Enable-Mailbox "Ken Myer" | Enable-CsUser -RegistrarPool atl-cs-001.litwareinc.com –SipAddressType SamAccountName –SipDomain litwareinc.com

You can retrieve a list of all your user accounts

This doesn't sound like a very challenging task: you want to get back a list of all your Active Directory user accounts, regardless of whether or not those users have been enabled for Lync Server 2010. However, this can't be done with the Lync Server Control Panel. With the Control Panel you can retrieve a list of users who have been enabled for Lync Server or you can retrieve a list of users who have not been enabled for Lync Server. But, as they say, ne'er the twain shall meet.

Which, to the best of our knowledge, means you can't get back all your users at the same time. And if you'd like to, say, sort those users by the department they work in, well ….

With Windows PowerShell, however, it's a different story. You say you need a list of all your Active Directory user accounts, along with the department each user works for and information about whether or not that user has been enabled for Lync Server? Oh, and you want that list sorted by department as well? All you have to do is ask:

Get-CsAdUser | Select-Object DisplayName, Department, CsEnabled | Sort-Object Department, DisplayName

You can customize your output

We've already seen several examples of how you can use the Select-Object cmdlet to customize your output. Select-Object lets you specify which property values you want displayed onscreen (or saved to a file). For example, if you only want to know whether your voice policies allow simultaneous ringing and call forwarding you could run a command like this:

Get-CsVoicePolicy | Select-Object Identity, AllowSimulRing, AllowCallForwarding

However, if you're willing to do a tiny bit of scripting, you can do all sorts of cool things with your output. For example, here's a simple little script that you can run even if you don't have Lync Server 2010 installed:

$x = Get-Process

foreach ($i in $x)

    {if ($i.Cpu -ge 1)

        {Write-Host $i.Name -Foreground green}

    else

        {Write-Host $i.Name -Foreground white}

What's that script do? Well, it retrieves a collection of all the processes running on your computer and stores that information in a variable named $x. It then loops through all the items in $x, checking to see if the value of the CPU property is greater than or equal to 1 (-ge 1). If it is, the script displays the name of the process in green text (Write-Host $i.Name -Foreground green); if not, then it displays the name of the process in white text. Admittedly, it's probably not the absolute coolest thing you can do with your output, but it demonstrates that it is possible to customize your output. Here's a Lync Server example, one that displays in green text any voice policy that allows both simultaneous ringing and call forwarding:

$x = Get-CsVoicePolicy

foreach ($i in $x)

    {if ($i.AllowSimulRing –eq $True –and $i.AllowCallForwarding –eq $True)

        {Write-Host $i.Identity -Foreground green}

    else

        {Write-Host $i.Identity -Foreground white}

You can ask PowerShell to keep track of everything that you do

Of course, if you work for someone else and/or if you're married you might be thinking, "Great, that's just what I need: someone else keeping track of everything I do." Nevertheless, most of us who have worked with computers have experienced one of those moments when you fixed something and when you were asked what you did to fix it you just shook your head and said, "I have no idea." Well, with Windows PowerShell, you might be able to figure out what you did by reviewing your session history: by default, PowerShell keeps track of the last 64 commands you've run within that session.

Note. You say that's not good enough? Well, you can tell PowerShell to track as many as the last 32,768 commands you've run. To do that, just change the value of the $MaximumHistoryCount variable:

$MaximumHistoryCount = 32768

To review your history, just call the Get-History cmdlet:

Get-History

For more information (well, a little more, anyway), see our article Windows PowerShell Shortcut Keys.

If you'd like to keep a record of everything that takes place on screen (that is, not just the commands you ran but the output generated by those commands) then use PowerShell's Transcript cmdlets. Before you start working, run a command similar to this:

Start-Transcript –Path C:\Logs\LyncServer.txt

Press ENTER, and from that moment on everything you see within the PowerShell window (commands, output, error messages, warnings, you name it) will also be written to the file C:\Logs\LyncServer.txt. When you no longer need to record the session, just call Stop-Transcript:

Stop-Transcript

By the way, transcripts are particularly useful when working with Lync Server's "synthetic transaction" cmdlets. See item 14 (hey, that's the next item!) for more information.

You can run tests to help ensure that Lync Server is working as expected

Lync Server 2010 ships with a whole bunch of "synthetic transactions," built-in tests that let you do such things as verify whether a user (either a test user or a real-live user) can log on to the system; can send an instant message; can make an outbound phone call over the PSTN network; etc., etc. For a list of all the synthetic transaction cmdlets, just type the following command from the Windows PowerShell prompt:

Get-Command Test-Cs*

And here's a tip to keep in mind when you run one of Lync Server's synthetic transactions. If you include the Verbose parameter when you run one of the test cmdlets a detailed list of all the steps the cmdlet undertakes will be reported on screen. For better or worse, however, that step-by-step information is not reported in the log file generated in the cmdlet, and as near as we can tell there's no way to redirect that output to a file. If you want to capture that information (and, trust us, you will want to capture that information) then use the Transcript cmdlet described in reason 13. For example:

Start-Transcript –Path C:\Tests\Presence.txt

Test-CsPresence -TargetFqdn atl-cs-001.litwareinc.com

Stop-Transcript

You can schedule a command to run at any time

Do you have a resource-intensive script or command that you'd like to run at 2:00 every morning, and that you would run at 2:00 every morning except that they couldn't pay you enough to go into work at 2:00 every morning just to run a script or a command? That's fine; with Windows PowerShell you can use the Windows Task Scheduler to schedule scripts or commands to run any time you feel like running them. The only trick involved in all this is using the correct syntax when specifying the script or command to be run. To run a script (and to leave the PowerShell window open after the script finishes running), configure your Task Scheduler action to look something like this:

powershell.exe –NoExit –File C:\Scripts\EveryMorning.ps1

To run a command (and leave the PowerShell window open after the command finishes running) use this syntax when configuring the Task Scheduler action:

powershell.exe –NoExit –Command Get-CsAdUser | Export-Csv C:\Logs\Users.scv

You can enforce company styles and standards

Both the Lync Server Control Panel and the Enable-CsUser cmdlet provide several options for assigning a user a SIP address. You can:

· Assign the user a custom SIP address.

· Auto-assign the user a SIP address based on their SamAccountName

· Auto-assign the user a SIP address based on their User Principal name.

· Auto-assign the user a SIP address based on their email address.

· Auto-assign the user a SIP address based on their first and last names.

Of course, neither the Control Panel nor Enable-CsUser can force administrators to use just one of those options; needless to say, administrators can choose any of those options when assigning a SIP address. That means that you can easily end up with some users who have a SIP address based on their SamAccountName, some users who have a SIP address based on their email address, and other users who have a totally arbitrary SIP address.

OK, so then what's the point of reason 16, seeing as how we just said that Enable-CsUser can't force administrators to use a particular SIP address type? Well, that's true; however, if you use a script to enable user accounts then you can enforce a particular standard. For example, suppose you want users to have SIP addresses based on their User Principal Name (UPN). One way to help ensure that is to not have administrators directly call Enable-CsUser when enabling a user account. Instead, have them use a script, like this one:

Enable-CsUser –Identity $args[0] –RegistrarPool atl-cs-001.litwareinc.com –SipAddressType UserPrincipalName

 

This simple little script takes a parameter – the Identity of the user account to be enabled – and then enables that account, assigning the user to a Registrar pool and giving them a SIP address based on their User Principal Name. To run the script, just include the Identity of the user account as a command-line parameter:

 

C:\Scripts\EnableUser.ps1 "Ken Myer"

 

Oh, and here's something cool: you can easily write a command to verify that all your users have SIP addresses based on their UPN. Here's a simple little command that reports back any users who do not have their UPN embedded in their SIP address:

 

Get-CsUser | Where-Object {$_.SipAddress –notmatch $_.UserPrincipalName} | Select-Object Identity

You can backup (and restore) policies or configuration settings

Lync Server 2010 makes it possible for you to backup and restore the entire system. However, what if you'd like to backup (and then maybe someday restore) a single policy or a single collection of configuration settings? The truth is this: it can't be done.

Except for one thing: that isn't the truth at all. Although there is no obvious mechanism for backing up policies and settings, here's a sneaky way to accomplish the same task. To begin with, you retrieve the appropriate policy and then pipe that object to the Export-Clixml cmdlet, which saves the policy information as an XML file:

Get-CsClientPolicy -Identity "RedmondClientPolicy" | Export-Clixml -Path C:\Backup\RedmondClientPolicy.xml

Now, suppose you start messing around with RedmondClientPolicy, you change a bunch of the settings, and then you think, "Hmmm, I think I liked the old policy better." How can you restore the old policy? Like this:

$x = Import-Clixml -Path C:\Backup\RedmondClientPolicy.xml

Set-CsClientPolicy –Instance $x

Note that this simple little approach will work for most policies and settings; however, it won't work with some of the more complicated items, items that contain multiple sub-objects (like routing configuration settings, which contain a bunch of separate voice routes). But we'll see if we can find an easy way to handle those more complicated objects as well.

You can output data in a separate window

One of the most underappreciated Windows PowerShell cmdlets is Out-GridView. What's Out-GridView, you ask? (See? Nobody even knows about Out-GridView, let alone appreciates it.) Well, what Out-GridView does is take the results of a command and then displays them in a separate window, a "grid view" window that looks a lot like an Excel spreadsheet. Once data is displayed in a grid you can easily sort that data, you can easily filter that data, you can do all sorts of fun stuff with that data, and all without having to even run another Windows PowerShell command. If you've installed Lync Server 2010 run this command and you'll see what we mean:

Get-CsAdUser | Select-Object DisplayName, Department, Title, SipAddress, Enabled | Out-GridView

If you haven't installed Lync Server 2010 (gasp!) but you have installed Windows PowerShell 2.0 then run this command:

Get-Process | Out-GridView

Want to sort those processes by ID? Just click the ID column heading. Want to filter the display by processes that have 500 or more handles? OK. Click the Add Criteria button, click Handles, and then click OK. You should now see something that looks like this on screen:

and Handles is less than or equal to <Empty>

Click less than or equal to and select greater than or equal to. Now, click in the box where the value <Empty> is shown and type 500.

Is that cool or what? (And yes, it is cool, which is why we'll talk more about Out-GridView in a future article.)

You can perform conditional processing

Hooray! Windows PowerShell lets us do conditional processing! This is probably the best reason of all!

Or at least it would be if we had any idea what conditional processing is.

Actually, you do know what conditional processing is. For example, an if-then statement is an example of conditional processing: if X is equal to 1 I want you to do Y but if X is equal to 2 I want you to do Z. As long as you're willing to write scripts (and scripts are definitely not hard to write in Windows PowerShell; see the article Introduction to Windows PowerShell Scripting for more information) you can do all sorts of interesting conditional processing. For example, you might write a script that enables a user and then, based on the user's department assigns them a particular external access policy, and, based on their office location, assigns them a particular dial plan. Take a peek at the script Move or Enable Multiple User Accounts for a real-life example of what we're talking about. This script, by Scott Stubberfield and Nick Smith, reads information from a text file and then, based on that information, either enables a user for Lync Server 2010 or moves that user to a new Registrar pool.

We agree: very cool.

You can filter policies and settings by properties other than name

In Lync Server Control Panel you can typically filter properties and configuration settings based on the item name; for example, you can type Redmond in the Filter box to limit the display to any item that has the string value Redmond somewhere in its name. That's useful, but that's also pretty much the extent of the filtering capabilities built into the Control Panel. (Except when it comes to users; Lync Server does have some pretty sophisticated filtering capabilities for zeroing in on a particular user or set of users.)

Windows PowerShell, by contrast, is all about filtering. Want to retrieve only those meeting configuration settings that allow PSTN callers to bypass the lobby? No problem:

Get-CsMeetingConfiguration | Where-Object {$_.PstnCallersByPassLobby –eq $True}

How about the meeting configuration settings where PSTN callers bypass the lobby and anonymous users are admitted by default? Child's play:

Get-CsMeetingConfiguration | Where-Object {$_.PstnCallersByPassLobby –eq $True –and $_.AdmitAnonymousUsersByDefault –eq $True}

Now let's try a hard one: meeting configuration settings where PSTN callers bypass the lobby or anonymous users are admitted by default? Hmmm, guess it wasn't all that hard after all, was it:

Get-CsMeetingConfiguration | Where-Object {$_.PstnCallersByPassLobby –eq $True –or $_.AdmitAnonymousUsersByDefault –eq $True}

You can manage everything that can be managed in Lync Server

We saved the best for last. The Lync Server Control Panel enables you to manage most of the things than can be managed in the software. However, Control Panel can't manage everything found in Lync Server. For example, if you browse through the items in Control Panel you won't see options for managing such things as the E9-1-1 service, client policies, or even the Address Book server. Where can you find options for managing such things as E9-1-1 service, client policies, or even the Address Book server? Do you even need to ask?

Get-CsLisLocation | Where-Object {$_.Location -ceq "NorthCampus"}

Set-CsClientPolicy -Identity "RedmondClientPolicy" –DisplayPhoto "NoPhoto"

New-CsAddressBookConfiguration –Identity site:Redmond -KeepDuration 15 -SynchronizePollingInterval 00:10:00

And there you have it: 21 reasons to use Windows PowerShell to manage Lync Server 2010. Would you be crazy not to at least take a look at the Lync Server Management Shell (the easiest way to access the Lync Server implementation of Windows PowerShell)? Well, we would never, ever call anyone crazy.

But, yes.