PSListModifiers

Most Microsoft Lync Server 2010 properties store a single value. For example, the MaxMeetingSize property for a given conferencing policy can be set to only one number. Which makes sense: the maximum meeting size can’t be set both to 100 and to 200. (You’re either on the bus or you’re off the bus.) Likewise, this same policy can’t have more than one Identity: either this is the RedmondConferencingPolicy or it isn’t the RedmondConferencingPolicy

The truth is, your Windows PowerShell life would be perfect if all properties were limited to a single value. But guess what? Life isn’t always perfect. And that goes for Windows PowerShell life as well as regular life. As it is, certain Microsoft Lync Server properties are capable of storing more than one property value; for example, the instant message file transfer filter configuration’s Extensions property can store an entire list of properties. That’s good; after all, this enables you to store all the blocked file extensions in a single property. But it also introduces a new problem: how do you go about manipulating these property lists?

Let’s put it this way: does the name PSListModifier mean anything to you?

That’s a good point: the name PSListModifier probably doesn’t mean anything to you, does it? As it turns out, PSListModifier is a Windows PowerShell class that makes it possible to work with lists: you can add items to a list, remove items from a list, even replace items in a list. The PSListModifier class is exposed primarily through the Windows PowerShell Update-List cmdlet, but other cmdlets can also harness the power and capabilities of PSListModifier. And that’s exactly what Microsoft Lync Server cmdlets like Set-CsFileTransferFilterConfiguration do.

Probably the best way to explain how this works is simply to show you how it works. The following three commands use the Add method to add a new file extension (.ps1, the file extension for Windows PowerShell scripts) to the file transfer filter configuration site:Redmond:

$x = Get-CsFileTransferFilterConfiguration -Identity site:Redmond
$x.Extensions.Add(".ps1")
Set-CsFileTransferFilterConfiguration -Instance $x

In our first command, we’re using the cmdlet Get-CsFileTransferFilterConfiguration to retrieve the file transfer filter configuration site:Redmond; the property values for those settings are then stored in a variable named $x. In command 2 we use the Add method to add .ps1 to the Extensions property; that’s done simply by adding parentheses after the call to the Add method and then putting the new file extension inside those parentheses. Finally, with command 3 we use the Set-CsFileTransferFilterConfiguration cmdlet and the -Instance parameter to write the changes (i.e., to add the new file extension) to the actual file transfer filter configuration.

And how would you remove this same file extension from the list? You’d do pretty much the same thing, simply substituting the Remove method for the Add method:

$x = Get-CsFileTransferFilterConfiguration -Identity site:Redmond
$x.Extensions.Remove(".ps1")
Set-CsFileTransferFilterConfiguration -Instance $x

OK, so that wasn’t so bad, was it? The only problem is that it doesn’t always work this way; the command we just showed you works with properties where values are stored as lists. However, there are also properties that store arrays of objects; for example, the UserAgentMapping property of a client version configuration stores multiple instances of a client version map object, with these objects stored as an array of, well, client version map objects.  

Note. You think your head hurts from reading this? Try being the one writing this!

Early in development a number of cmdlets featured this behavior; most of those cmdlets have been removed or reworked so that they no longer store arrays of objects in a single property. However, there are still a few of them hanging around, which is why we’re going to quickly run through the steps involved in adding and removing objects from this type of list. We’ll use CsClientVersionConfiguration as an example.

Let’s start with adding a user agent map, which really isn’t too hard. Here’s how you add a map:

$x = Get-CsClientVersionConfiguration -Identity site:Redmond

$y = New-CsClientVersionMap -UserAgent CTA –FriendlyName ` "Communicator Test Agent"

$x.UserAgentMapping.Add($y)

Set-CsClientVersionConfiguration -Instance $x

And yes we know: this looks hard, and we specifically said that it wasn’t hard. But give us a chance to explain. In the first command we use Get-CsClientVersionConfiguration to retrieve the configuration with the Identity site:Redmond; that configuration is stored in a variable we named $x. In the second command, we use New-CsClientVersionMap to create a new client version map, which we store in the variable $y; this is the item we’re going to add to the UserAgentMapping collection of our site:Redmond configuration.

By amazing coincidence that’s exactly what we do in the third command: we use the Add method to add the new map to the UserAgentMapping property, using the variable $y as the sole parameter to the Add method.

And then, at long last, we use Set-CsClientVersionConfiguration to write the changes back to the actual configuration settings.

As it turns out, adding a new map isn’t all that bad; we just wish we could say the same thing about removing a map. Here are the commands for removing a user agent map from a client version configuration:

$x = Get-CsClientVersionConfiguration -Identity site:Redmond

$x.UserAgentMapping.Remove($x.UserAgentMapping[0])

Set-CsClientVersionConfiguration -Instance $x

Lines 1 and 3 above aren’t too bad; in line 1 we grab the client version configuration, and in line 3 we write the changes back to the configuration. That leaves us with line 2:

$x.UserAgentMapping.Remove($x.UserAgentMapping[0])

What we’re doing here is removing the first map found in the UserAgentMapping property. Unfortunately, though, the only way to indicate the first map in the collection is to use this syntax:

$x.UserAgentMapping[0]

In Windows PowerShell, $x.UserAgentMapping[0] represents the first item in the array stored in the UserAgentMapping property of the object $x (…that lived in the house that Jack built). And yes, we know: the first item in an array should be item 1, shouldn’t it? For better or worse, however, it’s not: in Windows PowerShell (and in most shell/programming languages) the first item in an array is always item 0. That’s why we see [0] ; in arrays-speak, that means “Item 1.”

That’s … interesting … but at least there’s a pattern you can follow: the index number for an array item is always one less than the item’s position in the array. (In other words, item 1 has an index number of 0; item 2 has an index number of 1; item 3 has an index number of 2; and so on.) If we want to remove the fifteenth map in our array of user agent maps we’d use this command:

$x.UserAgentMapping.Remove($x.UserAgentMapping[14])

And if we want to remove the 29th map we’d – well, you get the idea. 

Hint. We’d use this command:

$x.UserAgentMapping.Remove($x.UserAgentMapping[28])

So how do you know which is the first map in the list and which is the 29th map in the list? This command will show you all the individual maps:

(Get-CsClientVersionConfiguration –Identity site:Redmond).UserAgentMapping

And this command will show you just the first map:

(Get-CsClientVersionConfiguration –Identity site:Redmond).UserAgentMapping[0]

Etc., etc.

Note. Look on the bright side: very little of this exists in the pre-release implementation of Lync Server, and it’s likely that even less will exist in the released product.