Freigeben über


Dealing with Information Overload, Part 1

Displaying Select Microsoft Lync Server 2010 Property Values

Here’s a rhetorical question for you: although you hear the phrase “information overload” all the time, does anyone know what that term actually means? Well, after doing a little research, we managed to come up with a pretty good example of information overload. In the late 1880s the US War Department decided to transcribe all its personnel records – dating back to the Revolutionary War – onto index cards. Within a few years, several hundred clerks were busily at work in Ford’s Theater in Washington DC, copying information onto index cards. Some 30 million index cards later, disaster struck: three floors of the theater collapsed, and 22 clerks were crushed to death.

And you think you have problems dealing with too much information.

Note. So did that really happen? Well, kind of. The War Department really did try transcribing all its personnel records onto index cards, and several floors in Ford’s Theater really did collapse and kill a number of clerks. As it turns out, however, it wasn’t so much the weight of the index cards that was responsible for the collapse; instead, it was the fact that construction workers who were renovating the basement removed portions of the foundation without providing adequate support.

In other words, the building was going to collapse anyway, index cards or no index cards. But telling you that would have ruined a perfectly good example of information overload.

Information overload can be a problem in Microsoft Lync Server 2010 as well. (Although, to the best of our knowledge, Lync Server’s information overload has never collapsed three floors of a theater.) For example, suppose you run this simple command to return information about the user Ken Myer:

Get-CsAdUser –Identity "Ken Myer"

Do that and you’ll get back something that looks like this:

SamAccountName : kenmyer

Sid : S-1-5-21-1573807623-1597889489-1765977225-1235

SidHistory : {}

PasswordLastSet : 6/14/2010 6:06:00 PM

UserAccountControl : NormalAccount, DoNotExpirePassword

UserPrincipalName : kenmyer@Litwareinc.com

PrimaryGroupId : 513

Id : CN=Ken Myer,CN=Users,DC=Litwareinc,DC=com

AltSecurityIdentities : {}

Assistant :

Company : LitwareInc

CountryOrRegionDisplayName :

Department : Finance

Fax :

FirstName : Ken

HomePhone :

Initials :

LastName : Myer

CountryAbbreviation : US

City : Redmond

CountryCode : 0

Description : {}

EmployeeId :

Info :

IPPhone :

MiddleName :

Manager :

MobilePhone :

Office :

OtherFax : {}

OtherHomePhone : {}

OtherMobile : {}

OtherIPPhone : {}

OtherPager : {}

OtherTelephone : {}

Pager :

PostalCode : 98052

PostOfficeBox : {}

PreferredLanguage :

StateOrProvince : WA

Street :

StreetAddress :

Title : Accountant

Url : {}

WindowsEmailAddress :

ObjectCategoryCN : person

DisplayName : Ken Myer

AddressListMembership : {}

Phone :

WebPage :

ProxyAddresses : {sip:kenmyer@litwareinc.com}

TenantId : 00000000-0000-0000-0000-000000000000

SipAddress : sip:kenmyer@litwareinc.com

CSEnabled : True

Name : Ken Myer

DistinguishedName : CN=Ken Myer,CN=Users,DC=Litwareinc,DC=com

Identity : CN=Ken Myer,CN=Users,DC=Litwareinc,DC=com

Guid : e715038a-3639-44be-aefb-690307289e1e

ObjectCategory : CN=Person,CN=Schema,CN=Configuration,DC=Litwareinc,DC=com

ObjectClass : {top, person, organizationalPerson, user}

WhenChanged : 6/14/2010 2:44:14 PM

WhenCreated : 6/14/2010 11:06:00 AM

OriginatingServer : DC.Litwareinc.com

IsValid : True

ObjectState : Unchanged

That’s what we said: wow.

Needless to say, that’s a lot of information to wade through, especially if all you really wanted to know about Ken was:

· His Active Directory display name

· The department he works for

· His job title

· Whether or not his account has been enabled for Lync Server

Even worse, suppose you wanted to return these same four attribute values – display name; department; job title; and Lync Server account-enabled status – for all 987 of your users? That’s what we said: ouch. Trying to make sense of all that information probably wouldn’t collapse a theater and kill 22 clerks, but it wouldn’t be all that much fun, either.

The truth is, there are times when Lync Server presents us with a classic case of too much information. So is there any way to work around the fact that you sometimes get back way more information than you really need? Did you even have to ask? Of course there are some things you can do to limit the amount of information you get back when running a Lync Server cmdlet. And, with a tip of the hat to Dr. Seuss, here’s Thing One: Using Select-Object.

Using Select-Object

Now that we have you all excited about how to limit the information returned by a Lync Server cmdlet we’re going to switch gears and go off on a bit of a tangent: before we do anything else we’re going to talk about how Windows PowerShell decides which property values should be displayed any time you run a cmdlet.

Note. What if you don’t want to know how Windows PowerShell decides which property values should be displayed any time you run a cmdlet? Then just skip ahead to the section titled OK, This Time We Mean It: Using Select-Object .

If you don’t skip ahead, well, you have only yourself to blame, we told you that you could.

To explain what happens when Windows PowerShell displays property values, let’s take a closer look at the Get-Process cmdlet. If you want to play along at home, start Notepad, then type the following at the Windows PowerShell prompt and press ENTER:

Get-Process notepad

You should get back something that looks a little like this:

Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName

------- ------ ----- ----- ----- ------ -- -----------

     67 8 252 7360 77 0.12 3048 notepad

OK, that’s nice. Not exactly a ton of information, but, then again, Get-Process can only return what Get-Process can return, right?

Well, maybe. Now try typing this command and see what happens:

Get-Process notepad | Select-Object *

Yowzers! Take a look what you get back when you run that command:

__NounName : Process

Name : notepad

Handles : 67

VM : 80805888

WS : 7626752

PM : 2306048

NPM : 8040

Path : C:\Windows\system32\NOTEPAD.EXE

Company : Microsoft Corporation

CPU : 0.156001

FileVersion : 6.1.7600.16385 (win7_rtm.090713-1255)

ProductVersion : 6.1.7600.16385

Description : Notepad

Product : Microsoft Windows Operating System

Id : 3048

PriorityClass : Normal

HandleCount : 67

WorkingSet : 7626752

PagedMemorySize : 2306048

PrivateMemorySize : 2306048

VirtualMemorySize : 80805888

TotalProcessorTime : 00:00:00.1560010

BasePriority : 8

ExitCode :

HasExited : False

ExitTime :

Handle : 1172

MachineName : .

MainWindowHandle : 1835888

MainWindowTitle : blog.txt - Notepad

MainModule : System.Diagnostics.ProcessModule (NOTEPAD.EXE)

MaxWorkingSet : 1413120

MinWorkingSet : 204800

Modules : {System.Diagnostics.ProcessModule (NOTEPAD.EXE), System.Diagnostics.ProcessModule (ntdll.d

                ll), System.Diagnostics.ProcessModule (kernel32.dll), System.Diagnostics.ProcessModule (KE

                             RNELBASE.dll)...}

NonpagedSystemMemorySize : 8040

NonpagedSystemMemorySize64 : 8040

PagedMemorySize64 : 2306048

PagedSystemMemorySize : 154320

PagedSystemMemorySize64 : 154320

PeakPagedMemorySize : 2314240

PeakPagedMemorySize64 : 2314240

PeakWorkingSet : 8110080

PeakWorkingSet64 : 8110080

PeakVirtualMemorySize : 86597632

PeakVirtualMemorySize64 : 86597632

PriorityBoostEnabled : True

PrivateMemorySize64 : 2306048

PrivilegedProcessorTime : 00:00:00.1404009

ProcessName : notepad

ProcessorAffinity : 15

Responding : True

SessionId : 1

StartInfo : System.Diagnostics.ProcessStartInfo

StartTime : 6/15/2010 8:15:46 AM

SynchronizingObject :

Threads : {3856}

UserProcessorTime : 00:00:00.0156001

VirtualMemorySize64 : 80805888

EnableRaisingEvents : False

StandardInput :

StandardOutput :

StandardError :

WorkingSet64 : 7626752

Site :

Container :

Holy smokes; where did all of those property values come from?

As it turns out, those are all the property values that Get-Process is capable of returning. So then why didn’t we see all of those values the first time we called Get-Process? Well, by default, Windows PowerShell cmdlets are designed to return all the property values of an object. And that makes sense: you ask for information about something and Windows PowerShell returns that information. However, there’s an important exception to the general rule that a cmdlet returns all the property values for an object: formatting files.

What’s a formatting file? Actually, a formatting file is pretty much what the name implies: it’s a file that contains formatting information. In this case, we’re talking about Windows PowerShell formatting files. These files (which have a .ps1xml file extension) determine how the information returned by a cmdlet is to be displayed. As you may or may not know, any time you run a PowerShell cmdlet you get back a .NET Framework object; for example, when you run the Get-Process cmdlet you get back one or more instances of the System.Diagnostics.Process object. That’s because the System.Diagnostics.Process object is the object type of the .NET Framework object used to represent a process running on a computer.

However, Get-Process doesn’t just go grab an instance or two of the System.Diagnostics.Process object and then display all that information onscreen; far from it. Instead, the cmdlet first checks all the available PowerShell formatting files to see if any of those files have instructions on how a System.Diagnostics.Process object should be displayed. If none of the formatting files mentions System.Diagnostics.Process then all the property values for the object will be displayed; again, that’s the default behavior for a cmdlet.

But what if one of the formatting files does mention System.Diagnostics.Process? In that case, process information will be displayed using the instructions found in the formatting file.

Note. What do you mean you’re bored? Trust us; in Part 2 of this two-part series you’ll be very happy that we explained all this to you. (And we did tell you that you could skip ahead.)

So how exactly does that all work? Tell you what. Do this: take a look in the folder %systemroot% \System32\WindowsPowerShell\v1.0 (e.g., C:\Windows\System32\WindowsPowerShell\v1.0) and locate the file named DotNetTypes.format.ps1xml. If you open that file and search for System.Diagnostics.Process you’ll eventually stumble upon a section that looks like this (we’ve actually abridged the output a little, and added a touch of boldfacing, but you’ll get the idea):

    <TableColumnHeader>

        <Label>Handles</Label>

        <Width>7</Width>

        <Alignment>right</Alignment>

    </TableColumnHeader>

    <TableColumnHeader>

        <Label>NPM(K) </Label>

        <Width>7</Width>

        <Alignment>right</Alignment>

    </TableColumnHeader>

    <TableColumnHeader>

        <Label>PM(K)</Label>

        <Width>8</Width>

        <Alignment>right</Alignment>

    </TableColumnHeader>

    <TableColumnHeader>

        <Label>WS(K) </Label>

        <Width>10</Width>

        <Alignment>right</Alignment>

    </TableColumnHeader>

    <TableColumnHeader>

        <Label>VM(M) </Label>

        <Width>5</Width>

        <Alignment>right</Alignment>

    </TableColumnHeader>

    <TableColumnHeader>

        <Label>CPU(s) </Label>

        <Width>8</Width>

        <Alignment>right</Alignment>

    </TableColumnHeader>

...

    <TableColumnItem>

        <PropertyName>Id</PropertyName>

    </TableColumnItem>

    <TableColumnItem>

        <PropertyName>ProcessName</PropertyName>

    </TableColumnItem>

This just happens to be the section of the formatting file that lists the labels for each column of information that gets displayed any time you run the Get-Process cmdlet. So what, you say? Well, take a closer look at the label names:

· Handles

· NPM(K)

· PM(K)

· WS(K)

· VM(M)

· CPU(s)

· Id

· ProcessName

                                

Do any of those names look familiar? They should. Remember the default output we get back when we run Get-Process:

Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName

------- ------ ----- ----- ----- ------ -- -----------

     67 8 252 7360 77 0.12 3048 notepad

Ah, yes, now it makes sense: the information found in the file DotNetTypes.format.ps1xml matches up perfectly with the information displayed onscreen when you run Get-Process. Why does Get-Process display only certain property values, why does Get-Process use specific column labels, and why is the information returned by Get-Process displayed in a table rather than a list? You got it: because that’s the way the formatting file told Get-Process to display information.

And Get-Process always does what it’s told.

The moral of the story? Formatting files dictate the way information is displayed onscreen. If there’s a formatting file for an object then the object will be displayed using that formatting file. That’s going to mean you’re going to get back only the property values specified in that file. The formatting file DotNetTypes.format.ps1xml lists only 8 property values for the System.Diagnostics.Process object and that’s why, by default, Get-Process displays the values for only 8 properties.

Pretty simple, huh?

Yes, it is. Except for this: why does the command Get-Process notepad | Select-Object * display a million different property values? Good question, and here’s the answer: because the formatting file has a loophole: you can always use the Select-Object cmdlet to override the formatting files and display the property values of your choice. In this case, we used the asterisk (*) to indicate that we want to see every single property value Get-Process can return. That’s why we get back a million different items: the command Select-Object * simply means, “Show me all the property values for this particular object.”

That’s nice. But suppose the only properties we care about are ProcessName and MainWindowTitle; what do we do then? Well, in that case, we use Select-Object to tell Get-Process to return only those two property values:

Get-Process notepad | Select-Object ProcessName, MainWindowTitle

Note. OK, technically Get-Process returns all the values; Select-Object just dictates what gets displayed on screen. But that’s a technicality that doesn’t matter much, at least not for this article.

When you run the preceding command you should get back something that looks like this:

ProcessName MainWindowTitle

----------- ---------------

notepad blog.txt - Notepad

What do you know: all we get back are the two properties that we wanted to get back. You say you’d prefer that the MainWindowTitle property be listed first in your output? That’s fine; Select-Object also lets you control the order in which the information is displayed. All you have to do is switch the order of the property names when you call the cmdlet:

Get-Process notepad | Select-Object MainWindowTitle, ProcessName

Now you should get back this:

MainWindowTitle ProcessName

--------------- -----------

blog.txt - Notepad notepad

Pretty cool, huh?

Of course, if you’re wondering what any of this has to do with information overload and Lync Server, well, here’s your answer: Lync Server PowerShell is, at heart, good old-fashioned Windows PowerShell. That means that you can use the “generic” PowerShell cmdlets, like Select-Object, with all your Lync Server cmdlets. And that’s going to be our ticket to alleviating information overload.

Note. So does that mean that Lync Server also uses formatting files? As a matter of fact, it does. But we’re not going to tell you that just yet; we’re saving that for Part 2 of this series.

OK, This Time We Mean It: Using Select-Object

Way back at the beginning of this article, we decided that there were only four user account properties we were interested in:

· DisplayName

· Department

· Title

· CsEnabled

How can we tell Get-CsAdUser to return only those four property values? If you read the preceding explanation of how Windows PowerShell cmdlets decide which property values to display then you already know the answer. On the off-chance that you didn’t read the preceding explanation, well, we’ll just tell you the answer: we let Select-Object do that for us. In other words:

Get-CsAdUser –Identity "Ken Myer" | Select-Object DisplayName, Department, Title, CsEnabled

If we run the preceding command we should get back something that looks like this:

DisplayName Department Title CsEnabled

----------- ---------- ----- ---------

Ken Myer Finance Accountant True

Now that’s more like it, eh? Only want the DisplayName? Then use this command:

Get-CsAdUser –Identity "Ken Myer" | Select-Object DisplayName

All you have to do is call Get-CsAdUser (or any of the other Get-Cs cmdlets), pipe the returned data to Select-Object, then tell Select-Object which property values you’d like displayed. Oh, and you can also use wildcards to indicate the property values you want returned. Try running this command and seeing what happens:

Get-CsAdUser –Identity "Ken Myer" | Select-Object Disp*, Dep*, Ti*, Cs*

It’s that simple.

Note. But what if you don’t know the names of all the property values a cmdlet is capable of returning? In that case, try running a command similar to this:

Get-Process | Get-Member –MemberType Property

In other words, grab a representative sample of information (like a process object) and then pipe that information to the Get-Member cmdlet; in turn, Get-Member will show you all the properties of that object, along with the data type for each property. (That is, does this property take a string value, an integer value, a datetime value, etc.?)

Incidentally, in the example above we used the –MemberType parameter to limit the returned data to properties; we did that because the Lync Server cmdlets typically don’t support methods. But what if you want to see methods as well as properties? That’s fine; just leave off –MemberType:

Get-Process | Get-Member

And yes, in some ways this really is too easy, isn’t it? But we’ll live with that.

But That’s a Lot of Typing, Isn’t It?

As we’ve just seen, it’s actually pretty easy to limit the property values returned by a Lync Server cmdlet. Or, in all fairness, it’s easy for us; after all, as technical writers we typically don’t issue the same commands over and over again. (We typically don’t do much of anything. But that’s another story.)

Needless to say, this isn’t the case for someone (say, a Lync Server administrator) who actually has to work for a living. It’s nice that Select-Object lets you specify which property values get displayed onscreen. On the other hand, who wants to spend their time typing a command like this one over and over again:

Get-CsAdUser –Identity "Ken Myer" | Select-Object DisplayName, Department, Title, SamAccountName, SipAddress, UserPrincipalName, CsEnabled

That’s right: no one wants to spend their time typing a command like that one over and over again. So is there a way around that issue?

Well, we can think of two ways: a simple little trick, and a slightly more complicated little trick. The simple little trick is this: Suppose that, when you run Get-CsAdUser, you typically want to get back the same set of property values. That’s nice, but you really don’t want to type that big list of properties over and over again. After all, not only is that tedious and time-consuming, but it opens the door to mistyping a property name, accidentally leaving out a property, or making some other mistake that tosses a monkey wrench into your command. So what can you do to cut down on all that typing? Here’s one suggestion:

$AdUser = "DisplayName","Department","Title","SamAccountName","SipAddress","UserPrincipalName","CsEnabled"

What we’re doing here is storing property names (the same property names we typically want displayed when we run Get-CsAdUser) in a variable named $AdUser. (Note that we named the variable after the cmdlet — just like one of the authors did with his son.) You say you want to get back this same set of user attribute values for Ken Myer’s user account? OK; just run this command:

Get-CsAdUser –Identity "Ken Myer" | Select-Object $AdUser

What’s going to happen when we do this? That’s an easy one to answer: Get-CsAdUser is going to retrieve Ken Myer’s user account, then loop through the property names stored in the variable $AdUser and display only those property values. In other words, you’ll get back something that looks like this:

DisplayName : Ken Myer

Department : Finance

Title : Accountant

SamAccountName : kenmyer

SipAddress : sip:kenmyer@litwareinc.com

UserPrincipalName : kenmyer@Litwareinc.com

CSEnabled : True

Is that cool or what? You say you want to retrieve this same information for all your Active Directory user accounts? Sure; why not:

Get-CsAdUser | Select-Object $AdUser

And, assuming your PowerShell window is wide enough, you can even display this information in a table rather than a list; all you have to do is pipe the preceding command to the Format-Table cmdlet:

Get-CsAdUser | Select-Object $AdUser | Format-Table

Our Web pages really aren’t wide enough to display tables, but just pretend we’re showing you all the properties for Ken Myer:

DisplayName Department Title SamAccountName

----------- ---------- ----- --------------

Ken Myer Finance Accountant kenmyer

Note. We know what you’re thinking: you’re thinking, “Nothing could ever be cooler than this!” Well, maybe not. But here’s something that comes close: storing these property names in a variable is pretty slick in and of itself, but variables have a bad habit of disappearing any time you end a PowerShell session. That means that, the next time you start PowerShell, you’re going to have to re-create the variable than contains your property names. If you’d prefer to keep these variables a little more permanent, here’s a suggestion: stash the command that defines the variables in your Windows PowerShell profile. That way, every time you start PowerShell the variable $AdUser will be assigned the desired property values.

Oh, and don’t worry: if you don’t know much about Windows PowerShell profiles, well, we’ve got you covered.

Of course, we should mention that there is one catch here. (It’s a minor catch, but a catch nonetheless.) Suppose that, just this once, you’d like to return your standard set of property values plus an additional property value: Title. You might think that a command similar to this one will do the trick:

Get-CsAdUser | Select-Object $AdUser, Title

Unfortunately, a command like that one won’t do the trick, nor will any variation of the command. (Well, maybe some variation of the command will work. But we couldn’t find one right offhand.) So does that mean that you have to type out the entire command, like this:

$AdUser = "DisplayName","Department","Title","SamAccountName","SipAddress","UserPrincipalName","CsEnabled","Title"

That will work. If you prefer, however, you could create a second variable ($AdUser2) and store your standard set of properties plus the Title property in that variable:

$AdUser2= $AdUser + "Title"

Note. Yes, that is odd-looking syntax. But that’s because $AdUser is an array, and the easiest way to add an item to an array is to use the + operator. The preceding command simply says, “Create a new variable named $AdUser2, and set the value of the variable to the values already in $AdUser plus the additional property Title.”

Now you can retrieve your standard property values, plus the value of the Title property, by using this command:

Get-CsAdUser | Select-Object $AdUser2

It’s not a perfect solution to the information overload problem. But it’s definitely better than wading through the millions of property values that Get-CsAdUser returns by default.

OK, That Was Pretty Good. But, Still ….

Yes, we know: as cool as Select-Object might be, you still have to do some extra typing, and you do have to remember the name of the variable (or variables) where you stashed your property names.

Note. It’s actually pretty easy to retrieve a list of all your Windows PowerShell variables; just type the following command at the PowerShell prompt and press ENTER:

dir variable:

So is there a way around those problems? Well, at the very least there’s a way to reduce the amount of typing you have to do. When it comes to the Get-CsAdUser cmdlet (and most Lync Server cmdlets, for that matter) you can actually omit the –Identity parameter and just type the Identity you’re looking for. (Why? See the All About Identities article under “What if I don’t specify an Identity?” section for an explanation.) Thus:

Get-CsAdUser "Ken Myer" | Select-Object $AdUser

On top of that, you can also use the Windows PowerShell alias Select instead of typing out Select-Object:

Get-CsAdUser "Ken Myer" | Select $AdUser

That’s definitely less typing than our original command:

Get-CsAdUser –Identity "Ken Myer" | Select-Object $AdUser

Get-CsAdUser "Ken Myer" | Select $AdUser

Of course, you still have to pipe your output to Select-Object, and you still have to use the variable $AdUser. Isn’t there a way to just have the desired properties magically appear any time you call Get-CsAdUser?

As a matter of fact there is. Remember when we explained how formatting files worked? Well, as it turns out, you can write your own formatting files; on top of that, you can coax PowerShell into using your formatting files rather than the formatting files that get installed with Lync Server. If you’re really gung-ho about changing the output you get by default when you run a cmdlet, well, in Part 2 of this series we’ll show you how to do just that.

And yes, we could have shown you that in this article. But that would have qualified as too much information.

Comments

  • Anonymous
    July 10, 2010
    Nice article with a neat writing style thanks