Track Lync Schema update with Powershell

When I perform schema changes in very large forests it is nice to be able to track the status of the change as it replicates throughout the forest. I wanted to create a script that would quickly tell me what the current schema was on over 100 DCs.

If you don’t want to see how it was done you can just Download Track-LyncSchema.ps1

Starting with some scripts that I have built before foreach-parallel to do parallel processing, get-forestDomainControlles to get a list of all DCs in the forest and get-LdapData to do direct ldap lookups quickly. get-LdapData is necessary because it will take too long to import the AD module into each thread of the parallel processor.

Import-module ActiveDirectory          
function get-ForestDomainControllers () {...}
function get-ldapData ($ldapfilter,$searchRoot,$Server,[switch]$GC,$pageSize=1000,$Properties="*",$sizeLimit=0,[switch]$verbose,$o365FilterAddress){...}
function ForEach-Parallel () {...}

First we need to get all the DCs into an array, this can take a long time for large domains. We will only get the list if $DCs is empty - this way we can run this script multiple times but only do this step once.

if ($DCs -eq $null) {$DCs = get-ForestDomainControllers}

Next we locate the schema partition - likewise we only want to do this once. The PartitionsContainer value on the AD forest object has a value like DC=Partitions,CN=Configuration,DC=Domain,DC=com. We will use -replace to replace the partitions value with cn=schema to get the schema partition.

if ($SchemaPartiton -eq $null) {$SchemaPartition = (get-adforest).partitionscontainer -replace 'CN=Partitions','CN=Schema'}

To get the Lync Schema version we need the rangeUpper value of the ms-RTC-SIP-SchemaVersion object in the schema partition. To do that, we will use get-ldapdata with the searchroot specified as the Lync schema object. In this code $_ represents the server being worked on in the pipeline when we do foreach.

$Value = get-ldapdata  -searchRoot "CN=ms-RTC-SIP-SchemaVersion,$SchemaPartion" -properties rangeupper -server $_ | select -expand rangeupper

ForEach-Parallel makes use of worker threads for parallelism, so we need to import the functions into the thread and also any values we want to pass. To get the $SchemaPartition value into the thread, we pass it using the -Arguments parameter and then the first line of the executed code includes $SchemaPartition=$args[0]

Depending on the value, we want to return text that tells us what the version is, for this we use a switch statement

switch ($value) {
	'1006' {$value = "LCS 2005 [$value]"}
	'1007' {$value = "OCS 2007 R1 [$value]"}
	'1008' {$value = "OCS 2007 R2 [$value]"}
	'1100' {$value = "Lync Server 2010 [$value]"}
	'1150' {$value = "Skype for Business 2015 [$value]"}
	default: {$value = "Unknown schema value or no value [$value]"}
}

Then we export the value to an object so that it looks like a nice table and we can manipulate it if we want.

new-object psobject -Property @{server=$_;LyncSchemaVersion=$value}

The function that does the work looks like this. The foreach-parallel command ends with -ImportFunctions to import the get-ldapdata into scope of each thread.

function track-LyncSchema {
    $DCs.hostname |  %p{
        $SchemaPartition= $args[0]
        $Value = get-ldapdata  -searchRoot "CN=ms-RTC-SIP-SchemaVersion,$SchemaPartition" -properties rangeupper -server $_ | select -expand rangeupper
        switch ($value) {
            '1006' {$value = "LCS 2005 [$value]"}
            '1007' {$value = "OCS 2007 R1 [$value]"}
            '1008' {$value = "OCS 2007 R2 [$value]"}
            '1100' {$value = "Lync Server 2010 [$value]"}
            '1150' {$value = "Skype for Business 2015 [$value]"}
            default {$value = "Unknown [$value]"}
        }

        new-object psobject -Property @{server=$_;LyncSchemaVersion=$value}
    } -ImportFunctions get-ldapData -arguments $schemaPartition
}

We call the script from the commandline to get a list of all the servers and the schema version.

. .\track-LyncSchema.ps1
server                        LyncSchemaVersion
------                        -----------------
TestDC100.wrish.com           Skype for Business 2015 [1...
TestDC101.wrish.com           Skype for Business 2015 [1...
TestDC213.wrish.com           Skype for Business 2015 [1...
TestDC12.wrish.com            Skype for Business 2015 [1...
...

Because we built the script to output objets, we can easily see how many are left to replicate.

. .\track-lyncschema.ps1 | group LyncSchemaVersion
Count Name                       Group
----- ----                       -----
  202 Skype for Business 2010... {@{server=Test..
   20 Lync Server 2010 [1100]    {@{server=Test..

Download Track-LyncSchema.ps1