March 2013 - Posts

Every major Exchange release comes with updates to the Active Directory schema. In this case, "major release" means new major version (at RTM), every service pack, and (probably) every Cumulative Update with the new servicing model introduced for Exchange 2013.

Each update is unique to that particular release and, in general, they are cumulative. A notable exception to this was when Exchange Server 2007 SP3 had a higher schema version than that of Exchange Server 2010 RTM.

Over the lifetime of modern Exchange (since the integration to Active Directory with Exchange 2000), there have been a number of issues making it important to know the current schema version of Exchange. Most instructions on the web suggest using ADSIEdit to examine the relevant variable and value.

However, that is potentially risky (because ADSIEdit can be a dangerous tool) and can be a little confusing to use.

Here is a quick little PowerShell script to report on the proper value:

$root  = [ADSI]"LDAP://RootDSE"
$name  = "CN=ms-Exch-Schema-Version-Pt," + $root.schemaNamingContext
$value = [ADSI]( "LDAP://" + $name )
"Exchange Schema Version = $( $value.rangeUpper )"

The ms-Exch-Schema-Version-Pt attribute is never assigned to a class in the schema, it is used exclusively to identify the value of the Exchange Schema Version.

To anyone who has used ADSI in PowerShell or VBScript before, the little four-line script will appear very familiar. The PowerShell ADSI accelerator syntax allows for the corresponding PowerShell script to be shorter than the equivalent VBScript script.

In order for this script to work, it must be executed on a computer joined to an Active Directory domain. The execution context for the script (that is, the user account) requires no special privileges.

Oh, and if you prefer PowerShell one-liners, here is the same script as a one-liner for you:

"Exchange Schema Version = " + ([ADSI]("LDAP://CN=ms-Exch-Schema-Version-Pt," + ([ADSI]"LDAP://RootDSE").schemaNamingContext)).rangeUpper

Follow me on Twitter @essentialexch

Posted by michael | with no comments

One of the features added to PowerShell v2 (and of course continued with PowerShell v3) is splatting. Without going into extreme detail (there are plenty of other blogs and books that do that), splatting allows you to pass parameters to a PowerShell cmdlet via an associative array (that is a fancy name for a hash table).

The hash table contains the parameter name as a key and the parameter's value as a value. The hash table contains two matched arrays, the keys array and the values array. For example, if a hash table contains three values, then accessing $hash.keys[ 1 ] will provide the name of a given hash entry and $hash.values[ 1 ] will provide the corresponding value for that entry.

The big deal behind splatting is that it allows you to easily construct custom parameter lists that get passed to cmdlets based on the special needs of a calling script. That sounds dense. :) But it is a good thing. For example, if you want to call a cmdlet with different parameters based on the time of day, or on a particular computer, or whether your script was started with a switch parameter, or whether a particular string parameter has a value - then splatting is for you.

Splatting has a somewhat hidden advantage. Switch parameters require special handling under normal circumstances. With splatting, no special handling is required. You set a switch to $true or $false, without using special spacing and/or a colon.

I use splatting extensively in scripts I have developed since PowerShell v2 was released. Today, my friend Carl Webster, the Accidental Citrix Admin, asked about a way to simplify calling cmdlets in certain of his scripts. My answer was "use splatting". After a couple of back-and-forth emails, about the best way to use splatting, I concluded that the easiest thing to do was to generalize a routine to provide splatting for a cmdlet and pass that over to Carl.

After further thought and evolution on the basic concept of the routine I sent to Carl, I decided it could be a great deal more powerful (get it - powerful vs. PowerShell? HAHAHAHA) if I added in some logging capabilities and provided for the suppression of empty parameters. Thus was born Invoke-Splat. I have already taken Invoke-Splat and used it to simplify several of my own scripts.

Invoke-Splat takes the cmdlet to invoke as a parameter, plus all of the parameters for that cmdlet, as "parameter value" pairs, plus a couple of optional switch parameters to control Invoke-Splat itself. Invoke-Splat is dependent on PowerShell's named parameter matching, combined with positional parameter matching, and that everything that does not meet either of those, is stored in the special argument $args.

The splatNotEmpty switch ensures that parameters whose values evaluate as either null or empty strings are not passed as parameters to the called cmdlet. This is especially important for parameters that cannot normally be null or empty!

The splatDebug switch causes the cmdlet and each of the "parameter value" pairs to be output to the calling host.

The splatCmdlet string parameter is (obviously) the name of the cmdlet that will be executed with the other parameters.

Note that the other parameters may be empty!

For example:

Invoke-Splat Get-Process ID $PID FileVersionInfo $false -splatDebug

and

Invoke-Splat Get-Process ID $PID Name '' -splatDebug -splatNotEmpty

Without further ado, here is Invoke-Splat.

function Invoke-Splat
{
	Param(
		[string]$splatCmdlet,
		[switch]$splatNotEmpty,
		[switch]$splatDebug
	)

	## $args[ 0 .. n ] are matching "parameter argument" pairs

	$splats = @{}
	for( $i = 0; $i –lt $args.Length; $i = $i + 2 )
	{
		if( $splatNotEmpty )
		{
			## don’t pass arguments with empty strings
			if( ( $args[ $i + 1 ] –as [string] ).Length –gt 0 )  
			{
				$splats.$( $args[ $i ] ) = $args[ $i + 1 ]
			}
		}
		else
		{
			$splats.$( $args[ $i ] ) = $args[ $i + 1 ]
		}
	}
	if( $splatDebug )
	{
		write-host -ForeGroundColor Yellow "DEBUG: Invoke-Splat: cmdlet = $splatCmdlet"
		foreach( $entry in $splats.Keys )
		{
			write-host -ForeGroundColor Yellow "DEBUG: Invoke-Splat: entry: $entry = $($splats.$entry)"
		}
	}

	& $splatCmdlet @splats
}

Please follow me on Twitter: @essentialexch.

Thanks for your visit!

Posted by michael | with no comments
Filed under: ,