<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://theessentialexchange.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Michael&amp;#39;s meanderings...</title><link>http://theessentialexchange.com/blogs/michael/default.aspx</link><description /><dc:language>en</dc:language><generator>CommunityServer 2007.1 (Build: 20917.1142)</generator><item><title>Microsoft MVP 2009...</title><link>http://theessentialexchange.com/blogs/michael/archive/2009/07/02/microsoft-mvp-2009.aspx</link><pubDate>Thu, 02 Jul 2009 21:16:00 GMT</pubDate><guid isPermaLink="false">57ea7d7e-b8c6-404f-99fb-04d07393726a:521</guid><dc:creator>michael</dc:creator><slash:comments>0</slash:comments><comments>http://theessentialexchange.com/blogs/michael/archive/2009/07/02/microsoft-mvp-2009.aspx#comments</comments><description>&lt;p&gt;Yesterday I was notified that my MVP was renewed for another year (MVPs are awarded for one-year at a time, and there is a quarterly cycle of Jan/Apr/Jul/Oct). This is my sixth MVP award and part of it is due to you, my loyal readers! Officially, my MVP award is for &amp;quot;Windows Server System - Exchange Server&amp;quot;, but that&amp;#39;s generally shortened to &amp;quot;Exchange MVP&amp;quot;.&lt;/p&gt;
&lt;p&gt;If you aren&amp;#39;t familiar with the MVP program, check out &lt;a href="http://mvp.support.microsoft.com/"&gt;http://mvp.support.microsoft.com&lt;/a&gt; and my personal MVP profile at &lt;a href="https://mvp.support.microsoft.com/profile/Michael.B." target="_blank"&gt;https://mvp.support.microsoft.com/profile/Michael.B.&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Thanks for your ongoing support!&lt;/p&gt;
&lt;p&gt;Until next time...&lt;/p&gt;
&lt;p&gt;If there are things you would like to see written about, please let me know!&lt;/p&gt;&lt;img src="http://theessentialexchange.com/aggbug.aspx?PostID=521" width="1" height="1"&gt;</description><category domain="http://theessentialexchange.com/blogs/michael/archive/tags/Exchange/default.aspx">Exchange</category><category domain="http://theessentialexchange.com/blogs/michael/archive/tags/Microsoft/default.aspx">Microsoft</category></item><item><title>PowerScripting PodCast on Exchange Server 2010</title><link>http://theessentialexchange.com/blogs/michael/archive/2009/06/17/powerscripting-podcast-on-exchange-server-2010.aspx</link><pubDate>Wed, 17 Jun 2009 23:59:00 GMT</pubDate><guid isPermaLink="false">57ea7d7e-b8c6-404f-99fb-04d07393726a:519</guid><dc:creator>michael</dc:creator><slash:comments>0</slash:comments><comments>http://theessentialexchange.com/blogs/michael/archive/2009/06/17/powerscripting-podcast-on-exchange-server-2010.aspx#comments</comments><description>&lt;p&gt;I was recently a guest on the &amp;quot;Get-PodCast PowerScripting&amp;quot; podcast, discussing (primarily) Exchange Server 2010.&lt;/p&gt;
&lt;p&gt;To listen to the podcast, Episode 73, &lt;a href="http://powerscripting.wordpress.com/2009/06/08/episode-73-mvp-michael-smith-talks-exchange/" target="_blank"&gt;MVP Michael Smith Talks Exchange&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Until next time...&lt;/p&gt;
&lt;p&gt;If there are things you would like to see written about, please let me know!&lt;/p&gt;&lt;img src="http://theessentialexchange.com/aggbug.aspx?PostID=519" width="1" height="1"&gt;</description><category domain="http://theessentialexchange.com/blogs/michael/archive/tags/Exchange/default.aspx">Exchange</category><category domain="http://theessentialexchange.com/blogs/michael/archive/tags/PowerShell/default.aspx">PowerShell</category><category domain="http://theessentialexchange.com/blogs/michael/archive/tags/Upgrade_2F00_Migration/default.aspx">Upgrade/Migration</category></item><item><title>Getting the Contents of an Active Directory Integrated DNS Zone</title><link>http://theessentialexchange.com/blogs/michael/archive/2009/06/17/getting-the-contents-of-an-active-directory-integrated-dns-zone.aspx</link><pubDate>Wed, 17 Jun 2009 21:09:00 GMT</pubDate><guid isPermaLink="false">57ea7d7e-b8c6-404f-99fb-04d07393726a:517</guid><dc:creator>michael</dc:creator><slash:comments>0</slash:comments><comments>http://theessentialexchange.com/blogs/michael/archive/2009/06/17/getting-the-contents-of-an-active-directory-integrated-dns-zone.aspx#comments</comments><description>&lt;p&gt;Microsoft has long offered (where &amp;quot;long&amp;quot; means &amp;quot;since Windows Server 2003&amp;quot;) the &amp;quot;dnscmd.exe&amp;quot; program to control the actions of a DNS server. And, if you installed the adminpack (RSAT-Tools-DNS on Vista/Server 2008 and above) you could perform this control on a remote workstation/server as well.&lt;/p&gt;
&lt;p&gt;However, the output of dnscmd leaves....something.... to be desired, especially when you want to format and manipulate that output.&lt;/p&gt;
&lt;p&gt;Using a prior blog post of mine (&lt;a href="http://theessentialexchange.com/blogs/michael/archive/2009/05/07/hex-and-decimal-output-in-powershell.aspx" target="_blank"&gt;Hex and Decimal Output In PowerShell&lt;/a&gt;), I more-or-less reverse-engineered the format of how Active Directory Integrated zones (DNS domains) are stored in Active Directory. For all of my personal testing, the program below was successful at displaying the output and decoding it properly. However, that doesn&amp;#39;t mean I decode &lt;strong&gt;everything&lt;/strong&gt;!!! Just those things I could test.&lt;/p&gt;
&lt;p&gt;A key desire of mine was to be able to get the contents of an ADI zone into a CSV (comma-separated-value) format; so of course that option is present. I also wanted proper timeout values for aging/scavenging, so of course that happens by default (which dnscmd can&amp;#39;t do at all).&lt;/p&gt;
&lt;p&gt;If the script below doesn&amp;#39;t work for you, I&amp;#39;d be interested in hearing about it, and why it doesn&amp;#39;t work. Of course, I make no promises, but I&amp;#39;ll probably fix those issues. :-)&lt;/p&gt;
&lt;p&gt;Without further ado...&lt;/p&gt;
&lt;p&gt;&lt;font color="green"&gt;&lt;pre&gt;##
## dns-dump.ps1
##
## Michael B. Smith
## michael at smithcons dot com
## http://TheEssentialExchange.com/blogs/michael
## May/June, 2009
##
## Use as you wish, no warranties expressed, implied or explicit.
## Works for me, but it may not for you.
## If you use this, I would appreciate an attribution.
##

Param(
	[string]$zone,
	[string]$dc,
	[switch]$csv,
	[switch]$help
)

function dumpByteArray([System.Byte[]]$array, [int]$width = 9)
{
	## this is only used if we run into a record format
	## we don&amp;#39;t understand.

	$hex = &amp;quot;&amp;quot;
	$chr = &amp;quot;&amp;quot;
	$int = &amp;quot;&amp;quot;

	$i = $array.Count
	&amp;quot;Array contains {0} elements&amp;quot; -f $i
	$index = 0
	$count = 0
	while ($i-- -gt 0)
	{
		$val = $array[$index++]

		$hex += (&amp;quot;{0} &amp;quot; -f $val.ToString(&amp;quot;x2&amp;quot;))

		if ([char]::IsLetterOrDigit($val) -or 
		    [char]::IsPunctuation($val)   -or 
		   ([char]$val -eq &amp;quot; &amp;quot;))
		{
			$chr += [char]$val
		}
		else
		{
			$chr += &amp;quot;.&amp;quot;
		}

		$int += &amp;quot;{0,4:N0}&amp;quot; -f $val

		$count++
		if ($count -ge $width)
		{
			&amp;quot;$hex $chr $int&amp;quot;
			$hex = &amp;quot;&amp;quot;
			$chr = &amp;quot;&amp;quot;
			$int = &amp;quot;&amp;quot;
			$count = 0
		}		
	}

	if ($count -gt 0)
	{
		if ($count -lt $width)
		{
			$hex += (&amp;quot; &amp;quot; * (3 * ($width - $count)))
			$chr += (&amp;quot; &amp;quot; * (1 * ($width - $count)))
			$int += (&amp;quot; &amp;quot; * (4 * ($width - $count)))
		}

		&amp;quot;$hex $chr $int&amp;quot;
	}
}

function dword([System.Byte[]]$arr, [int]$startIndex)
{
	## convert four consecutive bytes in $arr into a
	## 32-bit integer value... if I had bit-manipulation
	## primitives in PowerShell, I&amp;#39;d use them instead
	## of the multiply operator.

	$res = $arr[$startIndex]
	$res = ($res * 256) + $arr[$startIndex + 1]
	$res = ($res * 256) + $arr[$startIndex + 2]
	$res = ($res * 256) + $arr[$startIndex + 3]

	return $res
}

function analyzeArray([System.Byte[]]$arr, [System.Object]$var)
{
	$nameArray = $var.distinguishedname.ToString().Split(&amp;quot;,&amp;quot;)
	$name = $nameArray[0].SubString(3)

	## AGE is stored backwards. The most-significant-byte comes
	## last, instead of first, unlike all the other 32-bit values.
	$age = $arr[23]
	$age = ($age * 256) + $arr[22]
	$age = ($age * 256) + $arr[21]
	$age = ($age * 256) + $arr[20]
	if ($age -ne 0)
	{
		## hours since January 1, 1601 (start of Windows epoch)
		## there is a long-and-dreary way to do this manually,
		## but get-date makes it trivial to do the conversion.
		$timestamp = (get-date -year 1601 -month 1 -day 1 -hour 0 -minute 0 -second 0).AddHours($age)
	}

	$ttl = dword $arr 12

	if ($arr[0] -eq 4 -and $arr[1] -eq 0)
	{
		# &amp;quot;A&amp;quot; record
		$ip = &amp;quot;{0}.{1}.{2}.{3}&amp;quot; -f $arr[24], $arr[25], $arr[26], $arr[27]

		if ($csv)
		{
			$formatstring = &amp;quot;{0},{1},{2},{3},{4}&amp;quot;
		}
		else
		{
			$formatstring = &amp;quot;{0,-30}`t{1,-24}`t{2}`t{3}`t{4}&amp;quot;
		}

		if ($age -eq 0)
		{
			$formatstring -f $name, &amp;quot;[static]&amp;quot;, $ttl, &amp;quot;A&amp;quot;, $ip
		}
		else
		{
			$formatstring -f $name, (&amp;quot;[&amp;quot; + $timestamp.ToString() + &amp;quot;]&amp;quot;), $ttl, &amp;quot;A&amp;quot;, $ip
		}
	}
	elseif ((($arr[0] -eq 80) -or ($arr[0] -eq 82)) -and $arr[1] -eq 0)
	{
		# &amp;quot;SOA&amp;quot; record
		# &amp;quot;Start-Of-Authority&amp;quot;

		$nslen = $arr[44]
		$segments = $arr[45]
		$index = 46
		$nsname = &amp;quot;&amp;quot;
		while ($segments-- -gt 0)
		{
			$segmentlength = $arr[$index++]
			while ($segmentlength-- -gt 0)
			{
				$nsname += [char]$arr[$index++]
			}
			if ($segments -gt 0) { $nsname += &amp;quot;.&amp;quot; }
		}
		$priserver = $nsname
		# &amp;quot;Primary server: $nsname&amp;quot;

		$index += 1
		$nslen = $arr[$index++]
		$segments = $arr[$index++]

		$nsname = &amp;quot;&amp;quot;
		while ($segments-- -gt 0)
		{
			$segmentlength = $arr[$index++]
			while ($segmentlength-- -gt 0)
			{
				$nsname += [char]$arr[$index++]
			}
			if ($segments -gt 0) { $nsname += &amp;quot;.&amp;quot; }
		}
		# &amp;quot;Responsible party: $nsname&amp;quot;
		$resparty = $nsname

		#&amp;quot;TTL: $ttl&amp;quot;
		# &amp;quot;Age: $age&amp;quot;

####		$unk1 = dword $arr 16
####		&amp;quot;Unknown1: $unk1&amp;quot;

		$serial = dword $arr 24
		# &amp;quot;Serial: $serial&amp;quot;

		$refresh = dword $arr 28
		# &amp;quot;Refresh: $refresh&amp;quot;

		$retry = dword $arr 32
		# &amp;quot;Retry: $retry&amp;quot;

		$expires = dword $arr 36
		# &amp;quot;Expires: $expires&amp;quot;

		$minttl = dword $arr 40
		# &amp;quot;Minimum TTL: $minttl&amp;quot;

		if ($age -eq 0)
		{
			$agestr = &amp;quot;[static]&amp;quot;
		}
		else
		{
			$agestr = &amp;quot;[&amp;quot; + $timestamp.ToString() + &amp;quot;]&amp;quot;
		}

		if ($csv)
		{
			$formatstring = &amp;quot;{0},{1},{2},{3},{4},{5},{6},{7},{8},{9},{10}&amp;quot;

			$formatstring -f $name, $agestr, $ttl, `
				&amp;quot;SOA&amp;quot;, $priserver, $resparty, `
				$serial, $refresh, $retry, `
				$expires, $minttl
		}
		else
		{
			$formatstring = &amp;quot;{0,-30}`t{1,-24}`t{2}`t{3}&amp;quot;

			$formatstring -f $name, $agestr, $ttl, &amp;quot;SOA&amp;quot;
			(&amp;quot; &amp;quot; * 32) + &amp;quot;Primary server: $priserver&amp;quot;
			(&amp;quot; &amp;quot; * 32) + &amp;quot;Responsible party: $resparty&amp;quot;
			(&amp;quot; &amp;quot; * 32) + &amp;quot;Serial: $serial&amp;quot;
			(&amp;quot; &amp;quot; * 32) + &amp;quot;TTL: $ttl&amp;quot;
			(&amp;quot; &amp;quot; * 32) + &amp;quot;Refresh: $refresh&amp;quot;
			(&amp;quot; &amp;quot; * 32) + &amp;quot;Retry: $retry&amp;quot;
			(&amp;quot; &amp;quot; * 32) + &amp;quot;Expires: $expires&amp;quot;
			(&amp;quot; &amp;quot; * 32) + &amp;quot;Minimum TTL (default): $minttl&amp;quot;
		}

		#### dumpByteArray $arr
	}
	elseif ((($arr[0] -eq 32) -or ($arr[0] -eq 30)) -and $arr[1] -eq 0)
	{
		# &amp;quot;NS&amp;quot; record
		$nslen = $arr[24]
		$segments = $arr[25]
		$index = 26
		$nsname = &amp;quot;&amp;quot;
		while ($segments-- -gt 0)
		{
			$segmentlength = $arr[$index++]
			while ($segmentlength-- -gt 0)
			{
				$nsname += [char]$arr[$index++]
			}
			if ($segments -gt 0) { $nsname += &amp;quot;.&amp;quot; }
		}

		if ($csv)
		{
			$formatstring = &amp;quot;{0},{1},{2},{3},{4}&amp;quot;
		}
		else
		{
			$formatstring = &amp;quot;{0,-30}`t{1,-24}`t{2}`t{3}`t{4}&amp;quot;
		}

		if ($age -eq 0)
		{
			$formatstring -f $name, &amp;quot;[static]&amp;quot;, $ttl, &amp;quot;NS&amp;quot;, $nsname
		}
		else
		{
			$formatstring -f $name, (&amp;quot;[&amp;quot; + $timestamp.ToString() + &amp;quot;]&amp;quot;), $ttl, &amp;quot;NS&amp;quot;, $nsname
		}
	}
	elseif ((($arr[0] -eq 36) -or ($arr[0] -eq 38)) -and $arr[1] -eq 0)
	{
		# &amp;quot;SRV&amp;quot; record

		$port = $arr[28]
		$port = ($port * 256) + $arr[29]

		$weight = $arr[26]
		$weight = ($weight * 256) + $arr[27]

		$pri = $arr[24]
		$pri = ($pri * 256) + $arr[25]

		$nslen = $arr[30]
		$segments = $arr[31]
		$index = 32
		$nsname = &amp;quot;&amp;quot;
		while ($segments-- -gt 0)
		{
			$segmentlength = $arr[$index++]
			while ($segmentlength-- -gt 0)
			{
				$nsname += [char]$arr[$index++]
			}
			if ($segments -gt 0) { $nsname += &amp;quot;.&amp;quot; }
		}

		if ($csv)
		{
			$formatstring = &amp;quot;{0},{1},{2},{3},{4},{5}&amp;quot;
		}
		else
		{
			$formatstring = &amp;quot;{0,-30}`t{1,-24}`t{2}`t{3} {4} {5}&amp;quot;
		}

		if ($age -eq 0)
		{
			$formatstring -f `
				$name, &amp;quot;[static]&amp;quot;, `
				$ttl, &amp;quot;SRV&amp;quot;, `
				(&amp;quot;[&amp;quot; + $pri.ToString() + &amp;quot;][&amp;quot; + $weight.ToString() + &amp;quot;][&amp;quot; + $port.ToString() + &amp;quot;]&amp;quot;), `
				$nsname
		}
		else
		{
			$formatstring -f `
				$name, (&amp;quot;[&amp;quot; + $timestamp.ToString() + &amp;quot;]&amp;quot;), `
				$ttl, &amp;quot;SRV&amp;quot;, `
				(&amp;quot;[&amp;quot; + $pri.ToString() + &amp;quot;][&amp;quot; + $weight.ToString() + &amp;quot;][&amp;quot; + $port.ToString() + &amp;quot;]&amp;quot;), `
				$nsname
		}

	}
	else
	{
		$name
		$var.distinguishedname.ToString()
		dumpByteArray $arr
	}

}

function processAttribute([string]$attrName, [System.Object]$var)
{
	$array = $var.$attrName.Value
####	&amp;quot;{0} contains {1} rows of type {2} from {3}&amp;quot; -f $attrName, $array.Count, $array.GetType(), $var.distinguishedName.ToString()

	if ($array -is [System.Byte[]])
	{
####		dumpByteArray $array
####		&amp;quot; &amp;quot;
		analyzeArray $array $var
####		&amp;quot; &amp;quot;
	}
	else
	{
		for ($i = 0; $i -lt $array.Count; $i++)
		{
####			dumpByteArray $array[$i]
####			&amp;quot; &amp;quot;
			analyzeArray $array[$i] $var
####			&amp;quot; &amp;quot;
		}
	}
}

function usage
{
&amp;quot;
.\dns-dump -zone  [-dc ] [-csv] |
	   -help

dns-dump will dump, from Active Directory, a particular named zone. 
The zone named must be Active Directory integrated.

Zone contents can vary depending on domain controller (in regards
to replication and the serial number of the SOA record). By using
the -dc parameter, you can specify the desired DC to use. Otherwise,
dns-dump uses the default DC.

Usually, output is formatted for display on a workstation. If you
want CSV (comma-separated-value) output, specify the -csv parameter.
Use out-file in the pipeline to save the output to a file.

Finally, to produce this helpful output, you can specify the -help
parameter.

This command is basically equivalent to (but better than) the:

	dnscmd /zoneprint 
or
	dnscmd /enumrecords  &amp;#39;@&amp;#39;

commands.

Example 1:

	.\dns-dump -zone essential.local -dc win2008-dc-3

Example 2:

	.\dns-dump -help

Example 3:

	.\dns-dump -zone essential.local -csv |
            out-file essential.txt -encoding ascii

	Note: the &amp;#39;-encoding ascii&amp;#39; is important if you want to
	work with the file within the old cmd.exe shell. Otherwise,
	you can usually leave that off.
&amp;quot;
}

	##
	## Main
	##

	if ($help)
	{
		usage
		return
	}

	if ($args.Length -gt 0)
	{
		write-error &amp;quot;Invalid parameter specified&amp;quot;
		usage
		return
	}

	if (!$zone)
	{
		throw &amp;quot;must specify zone name&amp;quot;
		return
	}

	$root = [ADSI]&amp;quot;LDAP://RootDSE&amp;quot;
	$defaultNC = $root.defaultNamingContext

	$dn = &amp;quot;LDAP://&amp;quot;
	if ($dc) { $dn += $dc + &amp;quot;/&amp;quot; }
	$dn += &amp;quot;DC=&amp;quot; + $zone + &amp;quot;,CN=MicrosoftDNS,CN=System,&amp;quot; + $defaultNC

	$obj = [ADSI]$dn
	if ($obj.name)
	{
		if ($csv)
		{
			&amp;quot;Name,Timestamp,TTL,RecordType,Param1,Param2&amp;quot;
		}

		#### dNSProperty has a different format than dNSRecord
		#### processAttribute &amp;quot;dNSProperty&amp;quot; $obj

		foreach ($record in $obj.psbase.Children)
		{
			####	if ($record.dNSProperty) { processAttribute &amp;quot;dNSProperty&amp;quot; $record }
			if ($record.dnsRecord)   { processAttribute &amp;quot;dNSRecord&amp;quot;   $record }
		}
	}
	else
	{
		write-error &amp;quot;Can&amp;#39;t open $dn&amp;quot;
	}

	$obj = $null

&lt;/pre&gt;&lt;/font&gt;
&lt;p&gt;Until next time...&lt;/p&gt;
&lt;p&gt;If there are things you would like to see written about, please let me know!&lt;/p&gt;&lt;img src="http://theessentialexchange.com/aggbug.aspx?PostID=517" width="1" height="1"&gt;</description><category domain="http://theessentialexchange.com/blogs/michael/archive/tags/Active+Directory/default.aspx">Active Directory</category><category domain="http://theessentialexchange.com/blogs/michael/archive/tags/Script/default.aspx">Script</category><category domain="http://theessentialexchange.com/blogs/michael/archive/tags/Exchange/default.aspx">Exchange</category><category domain="http://theessentialexchange.com/blogs/michael/archive/tags/PowerShell/default.aspx">PowerShell</category><category domain="http://theessentialexchange.com/blogs/michael/archive/tags/DNS/default.aspx">DNS</category></item><item><title>Named Properties, What Lies Ahead...</title><link>http://theessentialexchange.com/blogs/michael/archive/2009/06/17/named-properties-what-lies-ahead.aspx</link><pubDate>Wed, 17 Jun 2009 19:52:00 GMT</pubDate><guid isPermaLink="false">57ea7d7e-b8c6-404f-99fb-04d07393726a:516</guid><dc:creator>michael</dc:creator><slash:comments>0</slash:comments><comments>http://theessentialexchange.com/blogs/michael/archive/2009/06/17/named-properties-what-lies-ahead.aspx#comments</comments><description>&lt;p&gt;Microsoft is preparing to make a potentially breaking change that deals with how Exchange Server 2007 handles named properties. This change is scheduled to be a part of Service Pack 2 and of Exchange Server 2010 at RTM.&lt;/p&gt;
&lt;p&gt;This change involves the promotion (i.e., the visibility to non-MAPI clients) of X-* headers in incoming e-mail messages. This can potentially affect the operation of e-mail clients that depend on POP-3 and IMAP (and even Outlook, if you are using rules that look at headers).&lt;/p&gt;
&lt;p&gt;Unlike certain earlier versions of Exchange, Exchange 2007 and above do not have a STM file - this means that incoming Internet e-mail is ALWAYS translated to MAPI format and that all headers are not necessarily retained - especially if they are X-* headers. This can cause a fidelity issue (i.e., you can&amp;#39;t reproduce EXACTLY what you received). For probably 99.999% of customers - this isn&amp;#39;t an issue. At least, that&amp;#39;s the opinion.&lt;/p&gt;
&lt;p&gt;So.... Microsoft is looking for input and they&amp;#39;ve asked for Exchange MVPs to help get the word out.&lt;/p&gt;
&lt;p&gt;To express your opinion, see &lt;a href="http://msexchangeteam.com/archive/2009/06/11/451596.aspx" target="_blank"&gt;Named Properties, Round 2: What lies Ahead&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Until next time...&lt;/p&gt;
&lt;p&gt;If there are things you would like to see written about, please let me know!&lt;/p&gt;&lt;img src="http://theessentialexchange.com/aggbug.aspx?PostID=516" width="1" height="1"&gt;</description><category domain="http://theessentialexchange.com/blogs/michael/archive/tags/Exchange/default.aspx">Exchange</category><category domain="http://theessentialexchange.com/blogs/michael/archive/tags/Upgrade_2F00_Migration/default.aspx">Upgrade/Migration</category></item><item><title>Hex and decimal output in PowerShell</title><link>http://theessentialexchange.com/blogs/michael/archive/2009/05/07/hex-and-decimal-output-in-powershell.aspx</link><pubDate>Thu, 07 May 2009 17:47:00 GMT</pubDate><guid isPermaLink="false">57ea7d7e-b8c6-404f-99fb-04d07393726a:499</guid><dc:creator>michael</dc:creator><slash:comments>1</slash:comments><comments>http://theessentialexchange.com/blogs/michael/archive/2009/05/07/hex-and-decimal-output-in-powershell.aspx#comments</comments><description>&lt;p&gt;In UNIX/Linux/whatever there is this little utility called &amp;#39;od&amp;#39; which makes it trivial to dump the output of a file in multiple formats.&lt;/p&gt;
&lt;p&gt;Yesterday, I was working on a project and needed something similar. I could&amp;#39;ve downloaded Cygwin and installed it, or UnixUtils from Sourceforge, but no - I decided to write a PowerShell routine to give me what I needed.&lt;/p&gt;
&lt;p&gt;If you&amp;#39;ve never had the need to see hexadecimal, alphanumeric, and decimal information on a file all at once, well, move along now!&lt;/p&gt;
&lt;p&gt;Otherwise, below is my solution for your benefit. A couple of interesting points are my use of System.Char methods to determine whether a character is printable (viewable) and my use of the format operator (-f) which uses System.Format.&lt;/p&gt;
&lt;p&gt;Many attributes in Active Directory (including many Exchange and DNS related attributes) have a raw form that devolves into a System.Byte[] array (or an array of System.Byte[] arrays). You can get an arbitrary file as a byte array by using the Get-Content cmdlet with the &amp;quot;-Encoding Byte&amp;quot; parameter.&lt;/p&gt;
&lt;p&gt;Here is example output (with a line of header information that isn&amp;#39;t from this routine):&lt;/p&gt;
&lt;p&gt;&lt;font color="green"&gt;&lt;pre&gt;dNSRecord contains 62 rows of type System.Byte[] from DC=_gc._tcp.E14-Site._sites,DC=essential.local,CN=MicrosoftDNS,CN=System,DC=essential,DC=local
Array contains 62 entries
26 00 21 00 05 f0 00 00 d7  &amp;amp;.!..ð...   38   0  33   0   5 240   0   0 215
07 00 00 00 00 02 58 00 00  ......X..    7   0   0   0   0   2  88   0   0
00 00 ac 9a 36 00 00 00 00  ....6....    0   0 172 154  54   0   0   0   0
64 0c c4 1e 03 0c 77 69 6e  d.Ä...win  100  12 196  30   3  12 119 105 110
32 30 30 38 2d 64 63 2d 33  2008-dc-3   50  48  48  56  45 100  99  45  51
09 65 73 73 65 6e 74 69 61  .essentia    9 101 115 115 101 110 116 105  97
6c 05 6c 6f 63 61 6c 00     l.local.   108   5 108 111  99  97 108   0    
&lt;/pre&gt;&lt;/font&gt;
&lt;p&gt;And without further ado:&lt;/p&gt;
&lt;p&gt;&lt;font color="green"&gt;&lt;pre&gt;function dumpByteArray([System.Byte[]]$array, [int]$width = 9)
{
	$hex = &amp;quot;&amp;quot;
	$chr = &amp;quot;&amp;quot;
	$int = &amp;quot;&amp;quot;

	$i = $array.Count
	&amp;quot;Array contains {0} elements&amp;quot; -f $i
	$index = 0
	$count = 0
	while ($i-- -gt 0)
	{
		$val = $array[$index++]

		$hex += (&amp;quot;{0} &amp;quot; -f $val.ToString(&amp;quot;x2&amp;quot;))

		if ([char]::IsLetterOrDigit($val) -or 
		    [char]::IsPunctuation($val)   -or 
		   ([char]$val -eq &amp;quot; &amp;quot;))
		{
			$chr += [char]$val
		}
		else
		{
			$chr += &amp;quot;.&amp;quot;
		}

		$int += &amp;quot;{0,4:N0}&amp;quot; -f $val

		$count++
		if ($count -ge $width)
		{
			&amp;quot;$hex $chr $int&amp;quot;
			$hex = &amp;quot;&amp;quot;
			$chr = &amp;quot;&amp;quot;
			$int = &amp;quot;&amp;quot;
			$count = 0
		}		
	}

	if ($count -gt 0)
	{
		if ($count -lt $width)
		{
			$hex += (&amp;quot; &amp;quot; * (3 * ($width - $count)))
			$chr += (&amp;quot; &amp;quot; * (1 * ($width - $count)))
			$int += (&amp;quot; &amp;quot; * (4 * ($width - $count)))
		}

		&amp;quot;$hex $chr $int&amp;quot;
	}
}
&lt;/pre&gt;&lt;/font&gt;
&lt;p&gt;Until next time...&lt;/p&gt;
&lt;p&gt;If there are things you would like to see written about, please let me know!&lt;/p&gt;&lt;img src="http://theessentialexchange.com/aggbug.aspx?PostID=499" width="1" height="1"&gt;</description><category domain="http://theessentialexchange.com/blogs/michael/archive/tags/Script/default.aspx">Script</category><category domain="http://theessentialexchange.com/blogs/michael/archive/tags/PowerShell/default.aspx">PowerShell</category></item><item><title>Removing the Last Exchange 2003 Server...</title><link>http://theessentialexchange.com/blogs/michael/archive/2009/05/04/removing-the-last-exchange-2003-server.aspx</link><pubDate>Mon, 04 May 2009 17:17:00 GMT</pubDate><guid isPermaLink="false">57ea7d7e-b8c6-404f-99fb-04d07393726a:494</guid><dc:creator>michael</dc:creator><slash:comments>0</slash:comments><comments>http://theessentialexchange.com/blogs/michael/archive/2009/05/04/removing-the-last-exchange-2003-server.aspx#comments</comments><description>&lt;p&gt;Microsoft has lots of guidance about removing the last Exchange 2003 server from an administrative group (see &lt;a href="http://support.microsoft.com/kb/822931" target="_blank"&gt;KB 822931&lt;/a&gt;) and I definitely recommend you give that a read. They also have a &lt;a href="http://technet.microsoft.com/en-us/library/bb288905.aspx" target="_blank"&gt;technet article&lt;/a&gt; about removing the last Exchange 2003 server from your organization (after you&amp;#39;ve upgraded to Exchange 2007, of course). You should give that a read too.&lt;/p&gt;
&lt;p&gt;But if you do these things lots of times (and if you are a consultant, you probably do - or if you play in your Exchange lab a lot, you probably do too); you just need a quick list of reminders. Here is the list I take onsite with me, when I&amp;#39;m removing an Exchange 2003 server:&lt;/p&gt;
&lt;p&gt;Verify that all mailbox moves are complete (either within the console or &amp;quot;get-mailbox -server &amp;lt;servername&amp;gt;&amp;quot;).&lt;/p&gt;
&lt;p&gt;Verify that all public folder moves are complete (&amp;quot;get-publicfolderstatistics -server &amp;lt;servername&amp;gt;&amp;quot;). Note: if they aren&amp;#39;t this can be tough. Check the scripts in $ExScripts like MoveAllReplicas and RemoveReplicaFromPFRecursive.&lt;/p&gt;
&lt;p&gt;If you do NOT have an Edge server, verify that the Default receive connector allows Anonymous connections.&lt;/p&gt;
&lt;p&gt;If you DO have an Edge server, verify that Edge synchronization has occurred and is operational (&amp;quot;test-edgesynchronization&amp;quot;).&lt;/p&gt;
&lt;p&gt;Move all Offline Address Book generation servers to servers that will continue to exist&lt;/p&gt;
&lt;p&gt;Move the &amp;quot;Default Public Store&amp;quot; on all Exchange 2003 Mailbox Stores to point to a Exchange 2007 PF&lt;/p&gt;
&lt;p&gt;Delete the Public Folder databases from the Exchange 2003 server (note: this is not a required step, but if you can&amp;#39;t do this, then de-install of Exchange will fail - so this is a good place to go ahead and figure that out).&lt;/p&gt;
&lt;p&gt;Delete both sides of Interop RGCs (and verify that they are the only RGCs still present: &amp;quot;get-routinggroupconnector&amp;quot;)&lt;/p&gt;
&lt;p&gt;Delete SMTP connectors from ESM on the Exchange 2003 server (you can do this from the EMC on Exchange 2007 later, but you&amp;#39;ll get a version warning)&lt;/p&gt;
&lt;p&gt;Evaluate Recipient Policies and delete all unused RPs from ESM on the Exchange 2003 server&lt;/p&gt;
&lt;p&gt;Verify status of all recipient policies (ensure that Mailbox Manager boxes are unchecked)&lt;/p&gt;
&lt;p&gt;Note: you may want to record Mailbox Manager settings to recreate MRM policies on Exchange 2007 to replace the MM policies&lt;/p&gt;
&lt;p&gt;Relocate the PF heirarchy (in Exchange 2003 ESM, right-click the Exchange 2007 Administrative Group, select Next -&amp;gt; PF Container, drag PF object from the Exchange 2003 Administrative Group to the Exchange 2007 Administrative Group)&lt;/p&gt;
&lt;p&gt;Delete the Domain Recipient Update Service(s) from ESM on Exchange 2003&lt;/p&gt;
&lt;p&gt;Point the Enterprise Recipient Update Server to an Exchange 2007 mailbox server (or delete the RUS from Active Directory using adsiedit or LDP)&lt;/p&gt;
&lt;p&gt;Uninstall Exchange&lt;/p&gt;
&lt;p&gt;.....&lt;/p&gt;
&lt;p&gt;Now, this is one of those postings where I have to say &amp;quot;this works for me&amp;quot;. I bet it&amp;#39;ll work for you too - but I can&amp;#39;t guarantee it!&lt;/p&gt;
&lt;p&gt;Until next time...&lt;/p&gt;
&lt;p&gt;If there are things you would like to see written about, please let me know!&lt;/p&gt;&lt;img src="http://theessentialexchange.com/aggbug.aspx?PostID=494" width="1" height="1"&gt;</description><category domain="http://theessentialexchange.com/blogs/michael/archive/tags/Exchange/default.aspx">Exchange</category><category domain="http://theessentialexchange.com/blogs/michael/archive/tags/Upgrade_2F00_Migration/default.aspx">Upgrade/Migration</category></item><item><title>Backing Up Exchange 2007 on Windows 2008</title><link>http://theessentialexchange.com/blogs/michael/archive/2009/04/11/backing-up-exchange-2007-on-windows-2008.aspx</link><pubDate>Sat, 11 Apr 2009 22:52:00 GMT</pubDate><guid isPermaLink="false">57ea7d7e-b8c6-404f-99fb-04d07393726a:483</guid><dc:creator>michael</dc:creator><slash:comments>6</slash:comments><comments>http://theessentialexchange.com/blogs/michael/archive/2009/04/11/backing-up-exchange-2007-on-windows-2008.aspx#comments</comments><description>&lt;p&gt;It has been suggested to me that my series on backing up Exchange Server 2007 on Windows Server 2008 was so complicated that the content was truly inaccessible for the novice admin. For that, I apologize. At heart, I am a techie kind of guy and I spend a lot of time trying to make complicated things easy - in my blog articles, my magazines articles, and in the presentations I make at various conferences.&lt;/p&gt;
&lt;p&gt;So, to make up for that, without any technical discussion whatsoever, I present my GUI solution (still PowerShell based) for backing up Exchange Server 2007 on Windows Server 2008. With the exception of the forms-based handling, all of the technical infrastructure has been discussed &lt;a href="http://theessentialexchange.com/blogs/michael/archive/2009/01/26/exchange-2007-and-windows-2008-online-exchange-backup-part-6-of-7.aspx" target="_blank"&gt;here&lt;/a&gt; and in article preceding that article.&lt;/p&gt;
&lt;p&gt;The GUI solution requires .NET 2.0, but that&amp;#39;s already installed on any Exchange Server 2007 computer.&lt;/p&gt;
&lt;p&gt;To use the&amp;nbsp;backup script:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;div&gt;Download the zip file to a directory for PowerShell scripts on the Exchange Server you want to back up&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;Extract the two files contained in the zip file into that directory&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;Create (or identify) a directory where you want backups to go&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;Identify the first free drive letter on the server&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;Modify the MBS-GUI-Exchange-backup.ps1 script parameter block to insert those two parameters&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;Execute the script (from PowerShell, move to the directory where you extracted the scripts and type in &lt;strong&gt;./MBS-GUI-Exchange-backup.ps1&lt;/strong&gt;)&lt;/div&gt;&lt;/li&gt;&lt;/ol&gt;
&lt;p&gt;That&amp;#39;s it.That&amp;#39;s all it takes.&lt;/p&gt;
&lt;p&gt;Down the script &lt;a href="http://theessentialexchange.com/blogs/michael/MBS-GUI-Exchange2007-Backup.zip"&gt;MBS-GUI-Exchange2007-Backup.zip&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Just one tiny technical comment: if you are on Exchange 2003, it would be relatively easy to modify this script to use &lt;strong&gt;BEtest&lt;/strong&gt; to execute VSS backups for Exchange 2003.&lt;/p&gt;
&lt;p&gt;Until next time...&lt;/p&gt;
&lt;p&gt;If there are things you would like to see written about, please let me know!&lt;/p&gt;&lt;img src="http://theessentialexchange.com/aggbug.aspx?PostID=483" width="1" height="1"&gt;</description><category domain="http://theessentialexchange.com/blogs/michael/archive/tags/Script/default.aspx">Script</category><category domain="http://theessentialexchange.com/blogs/michael/archive/tags/Exchange/default.aspx">Exchange</category><category domain="http://theessentialexchange.com/blogs/michael/archive/tags/VSS/default.aspx">VSS</category></item><item><title>Handling the userPrincipalName in PowerShell</title><link>http://theessentialexchange.com/blogs/michael/archive/2009/04/07/handling-the-userprincipalname-in-powershell.aspx</link><pubDate>Tue, 07 Apr 2009 22:22:00 GMT</pubDate><guid isPermaLink="false">57ea7d7e-b8c6-404f-99fb-04d07393726a:480</guid><dc:creator>michael</dc:creator><slash:comments>0</slash:comments><comments>http://theessentialexchange.com/blogs/michael/archive/2009/04/07/handling-the-userprincipalname-in-powershell.aspx#comments</comments><description>&lt;p&gt;I dealt with the importance of the userPrincipalName in one of my very early blog postings, dated May 26, 2004: &lt;a href="http://theessentialexchange.com/blogs/michael/archive/2007/11/13/the-user-principle-name-and-you.aspx" target="_blank"&gt;The User Principal Name and You&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;While my company has changed, the basic information contained within that post has not changed at all.&lt;/p&gt;
&lt;p&gt;I would add one fact: the current Active Directory forest domain is an implied userPrincipalName domain and is not reflected in the list of userPrincipalName domains (also called uPNSuffixes) that are presented in such tools as Active Directory Domains and Trusts. The Active Directory Users and Computer tool is aware of this, and will present it as an option when configuring new user objects.&lt;/p&gt;
&lt;p&gt;This PowerShell code handles the addition, reporting, and elimination of UPN suffixes:&lt;/p&gt;
&lt;p&gt;&lt;font color="green"&gt;&lt;pre&gt;#
# userPrincipalName processing routines
#
# Michael B. Smith
# michael@smithcons.com
# April 6, 2009
#
[int] $ADS_PROPERTY_CLEAR	= 1
[int] $ADS_PROPERTY_UPDATE	= 2
[int] $ADS_PROPERTY_APPEND	= 3
[int] $ADS_PROPERTY_DELETE	= 4

function get-ConfigurationPartition
{
	$rootdse  = [ADSI]&amp;quot;LDAP://RootDSE&amp;quot;
	$configNC = $rootdse.ConfigurationNamingContext
	$rootdse  = $null

	$partition = [ADSI](&amp;quot;LDAP://CN=Partitions,&amp;quot; + $configNC)

	return $partition
}

function get-UPN
{
	$config = get-ConfigurationPartition
	$suffix = $config.uPNSuffixes
	$config = $null

	return $suffix
}

function test-UPN([string]$upn)
{
	$suffixes = get-UPN

	if (!$suffixes)
	{
		return $false
	}

	if (($suffixes -is [System.String]) -and ($suffixes -eq $upn))
	{
		return $true
	}

	foreach ($suffix in $suffixes)
	{
		if ($suffix -eq $upn)
		{
			return $true
		}
	}

	return $false
}

function new-UPN([string]$upn)
{
	if (test-UPN $upn)
	{
		write-error &amp;quot;$upn already exists&amp;quot;
	}
	else
	{
		$config = get-ConfigurationPartition
		$config.PutEx($ADS_PROPERTY_APPEND, &amp;quot;uPNSuffixes&amp;quot;, @($upn))
		$config.SetInfo()
		$config = $null
	}
}

function remove-UPN([string]$upn)
{
	if (test-UPN $upn)
	{
		$config = get-ConfigurationPartition
		$config.PutEx($ADS_PROPERTY_DELETE, &amp;quot;uPNSuffixes&amp;quot;, @($upn))
		$config.SetInfo()
		$config = $null
	}
	else
	{
		write-error &amp;quot;$upn doesn&amp;#39;t exist&amp;quot;
	}
}
&lt;/pre&gt;&lt;/font&gt;
&lt;p&gt;Until next time...&lt;/p&gt;
&lt;p&gt;If there are things you would like to see written about, please let me know!&lt;/p&gt;&lt;img src="http://theessentialexchange.com/aggbug.aspx?PostID=480" width="1" height="1"&gt;</description><category domain="http://theessentialexchange.com/blogs/michael/archive/tags/Active+Directory/default.aspx">Active Directory</category><category domain="http://theessentialexchange.com/blogs/michael/archive/tags/Script/default.aspx">Script</category><category domain="http://theessentialexchange.com/blogs/michael/archive/tags/Exchange/default.aspx">Exchange</category><category domain="http://theessentialexchange.com/blogs/michael/archive/tags/PowerShell/default.aspx">PowerShell</category></item><item><title>More Multi-valued Parameters in PowerShell (SourceTransportServers in Set-SendConnector)</title><link>http://theessentialexchange.com/blogs/michael/archive/2009/04/07/more-multi-valued-parameters-in-powershell-sourcetransportservers-in-set-sendconnector.aspx</link><pubDate>Tue, 07 Apr 2009 21:39:00 GMT</pubDate><guid isPermaLink="false">57ea7d7e-b8c6-404f-99fb-04d07393726a:478</guid><dc:creator>michael</dc:creator><slash:comments>0</slash:comments><comments>http://theessentialexchange.com/blogs/michael/archive/2009/04/07/more-multi-valued-parameters-in-powershell-sourcetransportservers-in-set-sendconnector.aspx#comments</comments><description>&lt;p&gt;In my first article on &lt;a href="http://theessentialexchange.com/blogs/michael/archive/2008/02/08/Multivalued-Parameters-.aspx" target="_blank"&gt;Multi-valued Parameters in PowerShell&lt;/a&gt;, I discussed a certain class of array parameters that Exchange 2007 uses many times - the [System.Object[]] (i.e., array of arbitrary elements) class for RemoteIpRanges.&lt;/p&gt;
&lt;p&gt;Unfortunately, that isn&amp;#39;t the only multi-valued type used by PowerShell for Exchange Server 2007. There are actually quite a few of them.&lt;/p&gt;
&lt;p&gt;Another type that comes up fairly often is SourceTransportServers. This is used by the Set-SendConnector cmdlet among others. It is a collection of a specific type of objects that Exchange 2007 refers to as ADobjectIDs.&lt;/p&gt;
&lt;p&gt;An ADobjectID is actually quite similar to a System.DirectoryServices.DirectoryEntry - however, in comparison, this type has very few populated properties. The fact that the property list for ADobjectID is quite small indicates the reason why Exchange uses this type instead of System.DirectoryServices.DirectoryEntry - the population of a few types is much more efficient than the population of all the types present for a DirectoryEntry.&lt;/p&gt;
&lt;p&gt;Populating and updating SourceTransportServers is a common idea, especially when you are using provisioning scripts to completely deploy new servers. Here is an example of PowerShell code that you can use to do this:&lt;/p&gt;
&lt;p&gt;&lt;font color="green"&gt;&lt;pre&gt;$newhub = Get-ExchangeServer &amp;quot;newhubserver&amp;quot;
$adobject = New-Object Microsoft.Exchange.Data.Directory.ADobjectID $newhub.distinguishedName

$a = Get-SendConnector &amp;quot;Internet Email&amp;quot;
$a.SourceTransportServers.Add($adobject)

$a | Set-SendConnector
&lt;/pre&gt;&lt;/font&gt;
&lt;p&gt;Until next time...&lt;/p&gt;
&lt;p&gt;If there are things you would like to see written about, please let me know!&lt;/p&gt;&lt;img src="http://theessentialexchange.com/aggbug.aspx?PostID=478" width="1" height="1"&gt;</description><category domain="http://theessentialexchange.com/blogs/michael/archive/tags/Administration/default.aspx">Administration</category><category domain="http://theessentialexchange.com/blogs/michael/archive/tags/Exchange/default.aspx">Exchange</category><category domain="http://theessentialexchange.com/blogs/michael/archive/tags/PowerShell/default.aspx">PowerShell</category></item><item><title>First Article in Red Gate's Simple-Talk</title><link>http://theessentialexchange.com/blogs/michael/archive/2009/03/30/first-article-in-red-gate-s-simple-talk.aspx</link><pubDate>Mon, 30 Mar 2009 18:06:00 GMT</pubDate><guid isPermaLink="false">57ea7d7e-b8c6-404f-99fb-04d07393726a:472</guid><dc:creator>michael</dc:creator><slash:comments>0</slash:comments><comments>http://theessentialexchange.com/blogs/michael/archive/2009/03/30/first-article-in-red-gate-s-simple-talk.aspx#comments</comments><description>&lt;p&gt;Red Gate is a company based out of Cambridge in the UK. I ran into some of their team at TechEd last year. They are a great bunch of folks.&lt;/p&gt;
&lt;p&gt;I&amp;#39;ve been doing tech. review for them on a number of articles since then, and I just had my first article published with them.&lt;/p&gt;
&lt;p&gt;If you&amp;nbsp;have a minute, take a look-see: &lt;a href="http://www.simple-talk.com/exchange/exchange-articles/determining-ms-exchange-disk-performance/" target="_blank"&gt;Determining MS Exchange Disk Performance&lt;/a&gt;. It covers what&amp;#39;s important to look at in measuring Exchange disk performance and some tools to use.&lt;/p&gt;
&lt;p&gt;My next article with them will be Outlook/Exchange related, and then I hope to do an article on calculating the anticipated performance of a RAID subsystem. Neat techie stuff. :-)&lt;/p&gt;
&lt;p&gt;Until next time... &lt;/p&gt;
&lt;p&gt;As always, if there are items you would like me to talk about, please drop me a line and let me know!&lt;/p&gt;&lt;img src="http://theessentialexchange.com/aggbug.aspx?PostID=472" width="1" height="1"&gt;</description><category domain="http://theessentialexchange.com/blogs/michael/archive/tags/Exchange/default.aspx">Exchange</category><category domain="http://theessentialexchange.com/blogs/michael/archive/tags/Articles/default.aspx">Articles</category></item><item><title>TEC'09 In Review</title><link>http://theessentialexchange.com/blogs/michael/archive/2009/03/30/tec-09-in-review.aspx</link><pubDate>Mon, 30 Mar 2009 12:47:00 GMT</pubDate><guid isPermaLink="false">57ea7d7e-b8c6-404f-99fb-04d07393726a:471</guid><dc:creator>michael</dc:creator><slash:comments>1</slash:comments><comments>http://theessentialexchange.com/blogs/michael/archive/2009/03/30/tec-09-in-review.aspx#comments</comments><description>&lt;p&gt;Last week I attended and spoke at &amp;quot;The Experts Conference&amp;quot; (&lt;a href="http://www.tec2009.com/"&gt;www.tec2009.com&lt;/a&gt;) in Las Vegas. I spoke on using VSS with Exchange, and on designing highly available solutions and infrastructure.&lt;/p&gt;
&lt;p&gt;This was the eighth year for this conference. In earlier years it was known as DEC (Directory Experts Conference), but over the last several years, as the organizers added more tracks, that has become less and less accurate. So they expanded the name. This year was the first year for an Exchange track.&lt;/p&gt;
&lt;p&gt;Note: In prior years, this conference was hosted by NetPro. Last year, Quest acquired NetPro, so this conference is now hosted by Quest.&lt;/p&gt;
&lt;p&gt;Can I hear a &amp;quot;wow&amp;quot;?! It was great. You should&amp;#39;ve been there.&lt;/p&gt;
&lt;p&gt;TEC is famous for being in-depth. Instead of the 100-200 level presentations you get at most conferences, at TEC you get 300-400 level presentations. In-depth, technical, and very interesting...&lt;/p&gt;
&lt;p&gt;Among Exchange MVPs, I and Ilse van Criekinge were speakers, with Lee Mackey also in attendance. But the real stars of the Exchange track were David Espinoza, Brett Shirley and Evan Dodds.&lt;/p&gt;
&lt;p&gt;David is the man responsible at Microsoft for getting new releases of Exchange shipped. His title is &amp;quot;Senior Program Manager, Exchange Ship Team&amp;quot;. Among other things, he runs the Exchange TAP. David gave a talk on the software development process for Exchange at Microsoft and answered many questions. He indicated that his talk had never been given outside of Microsoft before and I can believe it - it was very in-depth and instructive as to how &amp;quot;things get done&amp;quot; at Microsoft.&lt;/p&gt;
&lt;p&gt;Brett Shirley calls himself &amp;quot;Borg #2 of 6&amp;quot;. He is one of the six programmers of the ESE database engine. The second in seniority, which is where the #2 comes from. :-) Brett gave two&amp;nbsp;deep-dive presentations. One was&amp;nbsp;about the development of ESE over the last several years and the second about how ESE works. They were both pretty stellar.&lt;/p&gt;
&lt;p&gt;Evan Dodds is &amp;quot;PowerShell Guy&amp;quot; for Exchange at Microsoft. He spoke on a panel.&lt;/p&gt;
&lt;p&gt;Now, regardless of the presentations, the major cool factor was being able to hang with these guys and talk with them and discuss items. Hearing the inside story. Finally being able to understand why &amp;quot;this&amp;quot; happened instead of &amp;quot;that&amp;quot;. That is - the truth before it got scrubbed by marketing!&lt;/p&gt;
&lt;p&gt;And I did go to two Active Directory presentations. The Microsoft attendance on that side of the fence was just as stellar, with Nathan Muggli, Stuart Kwan, and Mark Wahl from Microsoft present.&amp;nbsp;There were also&amp;nbsp;many well-known Directory Services MVPs. Somewhat surprisingly, Dmitri Gavrilov, who is now on the Exchange Team,&amp;nbsp;presented sessions&amp;nbsp;on the Directory Services track instead of the Exchange Track.&lt;/p&gt;
&lt;p&gt;I&amp;nbsp;recommend&amp;nbsp;that you&amp;nbsp;put this very technical conference on your short list in years to come - if you are a technical guy or gal. Much more of a techie conference than a management conference, you get some very guru-like folks here.&lt;/p&gt;
&lt;p&gt;Until next time... &lt;/p&gt;
&lt;p&gt;As always, if there are items you would like me to talk about, please drop me a line and let me know! &lt;/p&gt;&lt;img src="http://theessentialexchange.com/aggbug.aspx?PostID=471" width="1" height="1"&gt;</description><category domain="http://theessentialexchange.com/blogs/michael/archive/tags/Active+Directory/default.aspx">Active Directory</category><category domain="http://theessentialexchange.com/blogs/michael/archive/tags/Exchange/default.aspx">Exchange</category><category domain="http://theessentialexchange.com/blogs/michael/archive/tags/Conferences/default.aspx">Conferences</category></item><item><title>Monitoring Exchange Server 2007 with System Center Operations Manager 2007</title><link>http://theessentialexchange.com/blogs/michael/archive/2009/03/02/monitoring-exchange-server-2007-with-system-center-operations-manager-2007.aspx</link><pubDate>Mon, 02 Mar 2009 20:28:00 GMT</pubDate><guid isPermaLink="false">57ea7d7e-b8c6-404f-99fb-04d07393726a:464</guid><dc:creator>michael</dc:creator><slash:comments>0</slash:comments><comments>http://theessentialexchange.com/blogs/michael/archive/2009/03/02/monitoring-exchange-server-2007-with-system-center-operations-manager-2007.aspx#comments</comments><description>&lt;p&gt;Just a few days ago, my new book (of the subject title!) started shipping from Amazon. If it hasn&amp;#39;t already, it should start appearing in your local bookstores this week.&lt;/p&gt;
&lt;p&gt;If you want to order from Amazon, you can get it &lt;a class="" href="http://snurl.com/45ppf" target="_blank"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Eight months in the making, this book was a labor of love. Including information on installing and configuring OpsMgr 2007, it also includes much information about operating a reliable Exchange environment. Even if you don&amp;#39;t have OpsMgr in your organization, you can learn from this book the key areas of Exchange that need monitoring and how to do so.&lt;/p&gt;
&lt;p&gt;A strong PowerShell component is provided in several chapters to assist you in the generation of synthetic transactions for testing your Exchange environment.&lt;/p&gt;
&lt;p&gt;While the book is written toward a key audience of Exchange Server 2007 administrators, much material is also provided for the Exchange Server 2003 administrator. The book uses a virtualized environment to describe a test roll-out of an OpsMgr 2007 and Exchange 2003/2007 mixed environment.&lt;/p&gt;
&lt;p&gt;Since Exchange Server depends on the health of Windows Server, Active Directory, DNS, and IIS; tracking the health and well-being of these key services&amp;nbsp;is also covered.&lt;/p&gt;
&lt;p&gt;Go buy it. You&amp;#39;ll like it. :-)&lt;/p&gt;
&lt;p&gt;&amp;nbsp;The chapter titles are:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;div&gt;An Evolution of Server Management&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;Monitoring Exchange Server 2007&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;Installing and Configuring OpsMgr 2007&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;Deplying OpsMgr 2007&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;The First Management Pack: WIndows Server&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;The Active Directory Management Pack&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;The Domain Name System (DNS) Management Pack&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;The Internet Information Services Management Pack&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;SQL Server: An Ancillary Management Pack&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;Exchange Server 2003&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;Exchange Server 2007&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;Exchange Server 2007 Redundancy&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;Exchange Server Operations&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;div&gt;Tracking Mail Flow&lt;/div&gt;&lt;/li&gt;&lt;/ol&gt;
&lt;p&gt;Until next time... &lt;/p&gt;
&lt;p&gt;As always, if there are items you would like me to talk about, please drop me a line and let me know! &lt;/p&gt;&lt;img src="http://theessentialexchange.com/aggbug.aspx?PostID=464" width="1" height="1"&gt;</description><category domain="http://theessentialexchange.com/blogs/michael/archive/tags/Administration/default.aspx">Administration</category><category domain="http://theessentialexchange.com/blogs/michael/archive/tags/Active+Directory/default.aspx">Active Directory</category><category domain="http://theessentialexchange.com/blogs/michael/archive/tags/Exchange/default.aspx">Exchange</category><category domain="http://theessentialexchange.com/blogs/michael/archive/tags/Windows/default.aspx">Windows</category><category domain="http://theessentialexchange.com/blogs/michael/archive/tags/IIS/default.aspx">IIS</category><category domain="http://theessentialexchange.com/blogs/michael/archive/tags/Books/default.aspx">Books</category><category domain="http://theessentialexchange.com/blogs/michael/archive/tags/PowerShell/default.aspx">PowerShell</category><category domain="http://theessentialexchange.com/blogs/michael/archive/tags/OpsMgr/default.aspx">OpsMgr</category></item><item><title>A Small Patch: Online Exchange Backup</title><link>http://theessentialexchange.com/blogs/michael/archive/2009/01/30/a-small-patch-online-exchange-backup.aspx</link><pubDate>Fri, 30 Jan 2009 21:14:00 GMT</pubDate><guid isPermaLink="false">57ea7d7e-b8c6-404f-99fb-04d07393726a:451</guid><dc:creator>michael</dc:creator><slash:comments>1</slash:comments><comments>http://theessentialexchange.com/blogs/michael/archive/2009/01/30/a-small-patch-online-exchange-backup.aspx#comments</comments><description>&lt;p&gt;If you only had a single storage group, the script in Exchange 2007 and Windows 2008: Online Exchange Backup (part 6 of 7) would not find any storage groups. The primary reason for that I always have a RSG too! :-) The fix is easy. In getStoragegroups, change the beginning few lines: &lt;/p&gt;
&lt;p&gt;&lt;font color="green"&gt;&lt;pre&gt;function getStorageGroups
{
	$count = 0
	#
	# locate the storage groups and their log files and system files
	#
	$colSG = get-StorageGroup -server $computername
	if ($colSG.Count -lt 1)
	else
	{
		write-host &amp;quot;No storage groups found on server $computername&amp;quot;
		return 1
	} 
&lt;/pre&gt;&lt;/font&gt;
&lt;p&gt;to look like this: &lt;/p&gt;
&lt;p&gt;&lt;font color="green"&gt;&lt;pre&gt;function getStorageGroups
{
	$count = 0
	#
	# locate the storage groups and their log files and system files
	#
	$colSG = get-StorageGroup -server $computername
###	if ($colSG.Count -lt 1)
	if (($colSG -is [Microsoft.Exchange.Data.Directory.SystemConfiguration.StorageGroup]) -or
	    ($colSG -is [System.Object[]]))
	{
		## everything is good
	}
	else
	{
		write-host &amp;quot;No storage groups found on server $computername&amp;quot;
		return 1
	}
&lt;/pre&gt;&lt;/font&gt;
&lt;p&gt;Until next time... &lt;/p&gt;
&lt;p&gt;As always, if there are items you would like me to talk about, please drop me a line and let me know! &lt;/p&gt;&lt;img src="http://theessentialexchange.com/aggbug.aspx?PostID=451" width="1" height="1"&gt;</description><category domain="http://theessentialexchange.com/blogs/michael/archive/tags/Administration/default.aspx">Administration</category><category domain="http://theessentialexchange.com/blogs/michael/archive/tags/Script/default.aspx">Script</category><category domain="http://theessentialexchange.com/blogs/michael/archive/tags/Exchange/default.aspx">Exchange</category><category domain="http://theessentialexchange.com/blogs/michael/archive/tags/VSS/default.aspx">VSS</category><category domain="http://theessentialexchange.com/blogs/michael/archive/tags/Diskshadow/default.aspx">Diskshadow</category></item><item><title>Single-Label Domains (SLDs) and the Next Version of Exchange</title><link>http://theessentialexchange.com/blogs/michael/archive/2009/01/28/single-label-domains-slds-and-the-next-version-of-exchange.aspx</link><pubDate>Wed, 28 Jan 2009 16:16:00 GMT</pubDate><guid isPermaLink="false">57ea7d7e-b8c6-404f-99fb-04d07393726a:444</guid><dc:creator>michael</dc:creator><slash:comments>0</slash:comments><comments>http://theessentialexchange.com/blogs/michael/archive/2009/01/28/single-label-domains-slds-and-the-next-version-of-exchange.aspx#comments</comments><description>&lt;p&gt;I&amp;#39;ve written several times about the inadvisability of having an Active Directory domain name that has a single-label. My most recent article was &lt;a class="" href="http://theessentialexchange.com/blogs/michael/archive/2008/04/03/wrapping-up-slds-and-exchange-server-2007.aspx" target="_blank"&gt;Wrapping Up SLDs and Exchange Server 2007&lt;/a&gt;&amp;nbsp;in April of 2008.&lt;/p&gt;
&lt;p&gt;At that time, Ed Beck of Microsoft wanted to assure me that if&amp;nbsp;customers found&amp;nbsp;bugs, they should report them and Microsoft would investigate the issues and address&amp;nbsp;the issues&amp;nbsp;based on the standard engineering review decision process within Microsoft. That is, Microsoft was&amp;#39;t closing the door on fixing problems with SLDs in Exchange 2007.&lt;/p&gt;
&lt;p&gt;Now, the next version of Exchange, which is code-named E14, is in development. Yesterday, Ed emailed me and told me that Microsoft released a forward-looking statement indicating that they are investigating the SLD policy for E14 (Ed authored the article on the MS Exchange Team Blog: &lt;a class="" id="bp___v____ctl0__ctl0_bcr_r___postlist___EntryItems__ctl0_PostTitle" href="http://msexchangeteam.com/archive/2009/01/27/450514.aspx"&gt;Next version of Exchange and Single Label Domain (SLD) policy under review&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;I guess if I were you - and using an SLD - now would be the time to make yourself known! Feedback is accepted on the Exchange Team Blog site for quite a while after a posting. Let them know your opinion!&lt;/p&gt;
&lt;p&gt;Until next time...&lt;/p&gt;
&lt;p&gt;As always, if there are items you would like me to talk about, please drop me a line and let me know!&lt;/p&gt;&lt;img src="http://theessentialexchange.com/aggbug.aspx?PostID=444" width="1" height="1"&gt;</description></item><item><title>Exchange 2007 and Windows 2008: Online Exchange Backup (part 6 of 7)</title><link>http://theessentialexchange.com/blogs/michael/archive/2009/01/26/exchange-2007-and-windows-2008-online-exchange-backup-part-6-of-7.aspx</link><pubDate>Mon, 26 Jan 2009 17:56:00 GMT</pubDate><guid isPermaLink="false">57ea7d7e-b8c6-404f-99fb-04d07393726a:437</guid><dc:creator>michael</dc:creator><slash:comments>12</slash:comments><comments>http://theessentialexchange.com/blogs/michael/archive/2009/01/26/exchange-2007-and-windows-2008-online-exchange-backup-part-6-of-7.aspx#comments</comments><description>&lt;p&gt;In the first five parts of this series, I&amp;#39;ve given you the background to understand how Exchange backup works when using VSS and how to acquire the necessary information from your Exchange server to know what you should back up. Today, I present to you a full-blown working script that will generate a full-backup of your Exchange 2007 Server on Windows Server 2008, verify that the backup is good using ESEUTIL, and flush&amp;nbsp;the transaction logs for the Exchange storage groups if the backup is good.&lt;/p&gt;
&lt;p&gt;The first five parts of the series were:&lt;/p&gt;
&lt;p&gt;Part 1: &lt;a class="" href="http://theessentialexchange.com/blogs/michael/archive/2008/12/11/getting-a-list-of-storagegroups-in-a-powershell-script.aspx" target="_blank"&gt;&lt;font color="#0000ff"&gt;Getting a List of Storage Groups in a PowerShell Script&lt;/font&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Part 2: &lt;a class="" href="http://theessentialexchange.com/blogs/michael/archive/2008/12/23/getting-a-list-of-stores-in-a-powershell-script.aspx" target="_blank"&gt;&lt;font color="#0000ff"&gt;Getting a List of Stores in a PowerShell Script&lt;/font&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Part 3: &lt;a class="" href="http://theessentialexchange.com/blogs/michael/archive/2009/01/06/exchange-2007-and-windows-2008-offline-exchange-backup.aspx" target="_blank"&gt;&lt;font color="#0000ff"&gt;Exchange 2007 and Windows 2008: Offline Exchange Backup&lt;/font&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Part 4: &lt;a class="" href="http://theessentialexchange.com/blogs/michael/archive/2009/01/14/volume-shadow-copy-services-vss-and-exchange-the-basics.aspx" target="_blank"&gt;&lt;font color="#0000ff"&gt;Volume Shadow Copy Services (VSS) and Exchange - The Basics&lt;/font&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Part 5: &lt;a class="" href="http://theessentialexchange.com/blogs/michael/archive/2009/01/23/exchange-2007-and-windows-2008-using-diskshadow-for-online-exchange-backup-part-5-of-7.aspx" target="_blank"&gt;Exchange 2007 and Windows 2008: Using Diskshadow for Online Exchange Backup&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Now, before you ask - is this a supported backup tool? The answer is yes and no. VSS backups are a supported way to back up an Exchange server&amp;#39;s databases. Diskshadow is a supported tool on Windows Server 2008. Is my script supported? No. Only so far as I find the time, energy, and effort to provide support for it. I can&amp;#39;t warrant that it will work in your environment. It&amp;#39;s worked everywhere I&amp;#39;ve tested it, that&amp;#39;s all I can tell you. If you find a problem, let me know and I&amp;#39;ll try to help, but there are no guarantees.&lt;/p&gt;
&lt;p&gt;You won&amp;#39;t find anything new in this script (from the prior postings in this series), except that the Diskshadow script is generated within the PowerShell script. This makes it easier when you run into a situation that you are using multiple volumes in your Exchange environment (which is a best practice for performance reasons).&lt;/p&gt;
&lt;p&gt;The script takes three parameters:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;$backupLocation&lt;/strong&gt; - This is the volume and directory (or mountpoint) where the backup should go. It defaults to &lt;strong&gt;&lt;em&gt;C:\Backups&lt;/em&gt;&lt;/strong&gt;. You will probably need to change this for your environment.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;$startLetter&lt;/strong&gt; - This is the first letter that should be used by the script for exposing shadow copies as drive letters for the backup scripts. This defaults to &lt;strong&gt;&lt;em&gt;g&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;$startScript&lt;/strong&gt; - This is a switch parameter. When set, the PowerShell script will initiate the backup using &lt;em&gt;diskshadow.exe&lt;/em&gt; as soon as the script is built. The switch defaults to &lt;strong&gt;&lt;em&gt;unset&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The #1 limitation of this script is that it backs up &lt;strong&gt;all&lt;/strong&gt; storage groups on an Exchange server. I have plans to address that in a future revision.&lt;/p&gt;
&lt;p&gt;The #2 limitation of this script is that it&amp;#39;s &amp;quot;an ugly command line tool&amp;quot;. I have plans to address that in a future revision.&lt;/p&gt;
&lt;p&gt;This script will create a metadata file named (join-path $backupLocation &amp;quot;online-backup.cab&amp;quot;) (That is &lt;strong&gt;&lt;em&gt;C:\Backups\online-backup.cab&lt;/em&gt;&lt;/strong&gt; by default). This&amp;nbsp;file is&amp;nbsp;used by &lt;em&gt;diskshadow.exe&lt;/em&gt; for storing information required for restores. We will cover basic restores in part 7 of this series.&lt;/p&gt;
&lt;p&gt;The &lt;em&gt;cmd.exe&lt;/em&gt; script is stored as (join-path %TEMP% &amp;quot;online-backup.cmd&amp;quot;). The &lt;em&gt;Diskshadow.exe&lt;/em&gt; script is stored as (join-path %TEMP% &amp;quot;online-backup.dsh&amp;quot;).&lt;/p&gt;
&lt;p&gt;On my server, I store PowerShell scripts in the &lt;strong&gt;c:\scripts&lt;/strong&gt; folder, and name this particular script &lt;strong&gt;MBS-online-backup.ps1&lt;/strong&gt;. A typical invocation is:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;join-path &amp;quot;F:\ExchangeBackups&amp;quot; (get-date -uFormat &amp;quot;%Y-%m-%d-%H-%M-%S&amp;quot;) |% { md $_ |% { ./MBS-online-backup.ps1 -backupLocation $_.FullName -startScript } }&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;This causes a unique directory to be created for each invocation of the backup script and for the script to be automatically run.&lt;/p&gt;
&lt;p&gt;Granted, that&amp;#39;s a dense for a beginner to understand. You can separate that into multiple lines quite easily:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;$backupSubDir = get-date -uFormat &amp;quot;%Y-%m-%d-%H-%M-%S&amp;quot;&lt;br /&gt;## As specified,&amp;nbsp;the uFormat string&amp;nbsp;means: yyyy-mm-dd-hh-mm-ss&lt;br /&gt;## where the first &amp;#39;mm&amp;#39; is the month number, and&lt;br /&gt;## the second &amp;#39;mm&amp;#39; is the minute number.&lt;br /&gt;$backupDir = join-path &amp;quot;F:\ExchangeBackups&amp;quot; $backupSubDir&lt;br /&gt;md $backupDir&lt;br /&gt;./MBS-online-backup.ps1 -backupLocation $backupDir -startScript&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;And that is much easier to understand. Without further ado, here is the script:&lt;/p&gt;
&lt;p&gt;&lt;font color="green"&gt;&lt;pre&gt;##
## MBS-online-backup.ps1
##
## Michael B. Smith
## January, 2009
##
## This program generates an online VSS-based backup of an Exchange server
## (Exchange related files only) to a specified remote disk location.
##
## No warranties, express or implied, are available. It works for me. If
## you find errors or have problems, please feel free to let me know, but
## I can&amp;#39;t guarantee that I can fix them.
##
## Feel free to use this in your own scripts. I would appreciate attribution.
##
Param(
	[string]$backupLocation = &amp;quot;C:\Backups&amp;quot;,
	[string]$startLetter    = &amp;quot;g&amp;quot;,
	[switch]$startScript    = $false
)

## $backupLocation is where the files and metadata go.

## $startLetter will contain the first letter we use to remap
## the volume letters contained in $volumes.

## $nl is the DOS newline character string

$nl = &amp;quot;`r`n&amp;quot;

## $volumes will contain the volume letters used by all named
## files and directories.

$volumes = @{}

## any storage group will contain:
## a] a system file directory
## b] a log file directory
## c] a filename for each database within the SG
##
## $pathPattern contains the dos patterns of files in the storage group

$pathpattern = @{}		### Exx.chk, Exx*.log, *.edb

## $storeList contains the filenames of the Exchange databases that need
## to be checked.

$storeList = @{}

## $letters contains the mapping between the original drive letter
## and the exposed driver letter in the shadow copy.

$letters = @{}

## $computerName contains the local computer&amp;#39;s name

$computerName = $env:ComputerName

function buildRobocopyString($collection)
{
	$str = &amp;quot;&amp;quot;

	foreach ($filepath in $collection)
	{
		$file = split-path $filepath -leaf
		$path = split-path $filepath -parent
		#
		# the destination path is the source path appended to
		# the backup folder location.
		#
		$destpath = join-path $backupLocation $path.SubString(3, $path.Length - 3)
		#
		# the source path is the true path modified by the
		# letter of the exposed shadow copy
		#
		$letter = $letters.($path.SubString(0, 1))
		$subpath = $path.SubString(1, $path.Length - 1)
		$srcpath = &amp;quot;$letter$subpath&amp;quot;
		$str += &amp;quot;echo Copying &amp;quot; + $filepath + &amp;quot;...&amp;quot; + $nl
		$str += &amp;quot;robocopy &amp;quot; + &amp;#39;&amp;quot;&amp;#39; + $srcpath + &amp;#39;&amp;quot; &amp;quot;&amp;#39; + $destpath + 
		        &amp;#39;&amp;quot; &amp;quot;&amp;#39; + $file + &amp;#39;&amp;quot; /copyall /ZB &amp;gt;nul&amp;#39; + $nl
		$str += &amp;quot;if not errorlevel 0 goto :abort&amp;quot; + $nl
	}

	return $str
}

function buildESEUTILString($collection)
{
	$str = &amp;quot;&amp;quot;

	foreach ($path in $collection)
	{
		#
		# the destination path is the source path appended to
		# the backup folder location.
		#
		$path = $path.ToString()
		$destpath = join-path $backupLocation $path.SubString(3, $path.Length - 3)

		$str += &amp;quot;echo Checking &amp;quot; + $destpath + &amp;quot;...&amp;quot; + $nl
		$str += &amp;quot;call :checkit &amp;quot; + &amp;#39;&amp;quot;&amp;#39; + $destpath, &amp;#39;&amp;quot;&amp;#39; + $nl
		$str += &amp;quot;if not errorlevel 0 goto :abort&amp;quot; + $nl
	}

	return $str
}

function buildCMD
{
	$script = &amp;quot;@echo off&amp;quot; + $nl

	$script += buildRobocopyString $pathPattern.keys
	$script += $nl
	$script += buildESEUTILString $storeList.keys
	$script += $nl
	$script += &amp;quot;exit 0&amp;quot; + $nl
	$script += &amp;quot;:abort&amp;quot; + $nl
	$script += &amp;quot;exit 1&amp;quot; + $nl
	$script += $nl
	$script += &amp;quot;:checkit&amp;quot; + $nl
##	$script += &amp;quot;echo Checking %1&amp;quot; + $nl
	$script += &amp;quot;eseutil /k %1 &amp;gt;nul&amp;quot; + $nl
	$script += &amp;quot;if not errorlevel 0 exit 1&amp;quot; + $nl
	$script += $nl

	$scriptFile = join-path $env:temp &amp;quot;online-backup.cmd&amp;quot;
	$script | out-file $scriptFile -encoding ascii

	return $scriptFile
}

function writerOptimizationGarbage
{
	$script  = &amp;quot;&amp;quot;

	$script += &amp;quot;# verify presence of Exchange Writer&amp;quot; + $nl
	$script += &amp;quot;writer verify {76fe1ac4-15f7-4bcd-987e-8e1acb462fb7}&amp;quot; + $nl
	$script += &amp;quot;# exclude system writer&amp;quot; + $nl
	$script += &amp;quot;writer exclude {e8132975-6f93-4464-a53e-1050253ae220}&amp;quot; + $nl
	$script += &amp;quot;# exclude IIS config writer&amp;quot; + $nl
	$script += &amp;quot;writer exclude {2a40fd15-dfca-4aa8-a654-1f8c654603f6}&amp;quot; + $nl
	$script += &amp;quot;# exclude ASR writer&amp;quot; + $nl
	$script += &amp;quot;writer exclude {be000cbe-11fe-4426-9c58-531aa6355fc4}&amp;quot; + $nl
	$script += &amp;quot;# exclude BITS writer&amp;quot; + $nl
	$script += &amp;quot;writer exclude {4969d978-be47-48b0-b100-f328f07ac1e0}&amp;quot; + $nl
	$script += &amp;quot;# exclude WMI writer&amp;quot; + $nl
	$script += &amp;quot;writer exclude {a6ad56c2-b509-4e6c-bb19-49d8f43532f0}&amp;quot; + $nl
	$script += &amp;quot;# exclude registry writer&amp;quot; + $nl
	$script += &amp;quot;writer exclude {afbab4a2-367d-4d15-a586-71dbb18f8485}&amp;quot; + $nl
	$script += &amp;quot;# exclude iis metabase writer&amp;quot; + $nl
	$script += &amp;quot;writer exclude {59b1f0cf-90ef-465f-9609-6ca8b2938366}&amp;quot; + $nl
	$script += &amp;quot;# exclude com+ regdb writer&amp;quot; + $nl
	$script += &amp;quot;writer exclude {542da469-d3e1-473c-9f4f-7847f01fc64f}&amp;quot; + $nl
	$script += &amp;quot;# exclude shadow-copy optimization writer (does not apply to exchange)&amp;quot; + $nl
	$script += &amp;quot;writer exclude {4dc3bdd4-ab48-4d07-adb0-3bee2926fd7f}&amp;quot; + $nl
	$script += $nl

	return $script
}

function buildDSH([string]$cmdfilename)
{
	write-host &amp;quot;Building backup script&amp;quot;

	$script  = &amp;quot;&amp;quot;
	$script += &amp;quot;# Diskshadow backup script.&amp;quot; + $nl
##	$script += &amp;quot;set verbose on&amp;quot; + $nl
	$script += &amp;quot;set context persistent&amp;quot; + $nl
	$script += &amp;quot;set metadata &amp;quot; + (join-path $backupLocation &amp;quot;online-backup.cab&amp;quot;) + $nl
	$script += $nl
	$script += writerOptimizationGarbage
	$script += &amp;quot;begin backup&amp;quot; + $nl
	$script += $nl

	foreach ($drive in $volumes.keys)
	{
		$script += &amp;quot;add volume &amp;quot; + $drive + &amp;quot;: alias shadow_&amp;quot; + $drive + $nl
	}

	$script += $nl + &amp;quot;create&amp;quot; + $nl + $nl

	foreach ($drive in $volumes.keys)
	{
		$script += &amp;quot;expose %shadow_&amp;quot; + $drive + &amp;quot;% &amp;quot; + $letters.$drive + &amp;quot;:&amp;quot; + $nl
	}

	$script += $nl
	$script += &amp;quot;exec &amp;quot; + $cmdfilename + $nl

	#
	# If the batch file from exec fails, diskshadow terminates without
	# executing any more commands.
	#
	$script += &amp;quot;end backup&amp;quot; + $nl

	foreach ($drive in $volumes.keys)
	{
		## remove the temporary shadow copy and unexpose the letter
		$script += &amp;quot;delete shadows exposed &amp;quot; + $letters.$drive + &amp;quot;:&amp;quot; + $nl
	}

	$script += $nl
	$Script += &amp;quot;exit&amp;quot; + $nl

	$scriptFile = join-path $env:temp &amp;quot;online-backup.dsh&amp;quot;

	$script | out-file $scriptFile -encoding ascii
	write-host &amp;quot;Diskshadow script file $scriptFile&amp;quot;
	return $scriptFile
}

function getStores
{
	## locate the databases, both mailbox and public folder

	$colMB = get-MailboxDatabase -server $computername
	$colPF = get-PublicFolderDatabase -server $computername

	## parse them for volumes too

	foreach ($mdb in $colMB)
	{
		if ($mdb.Recovery)
		{
			write-host (&amp;quot;Skipping RECOVERY MDB &amp;quot; + $mdb.Name)
			continue
		}
		write-host ($mdb.Name + &amp;quot;`t &amp;quot; + $mdb.Guid)
		write-host (&amp;quot;`t&amp;quot; + $mdb.EdbFilePath)
		write-host &amp;quot; &amp;quot;

		$pathPattern.($mdb.EdbFilePath) = 1
		$storeList.($mdb.EdbFilePath)   = 1

		$vol = $mdb.EdbFilePath.ToString().SubString(0, 1)
		$volumes.$vol += 1
	}

	foreach ($mdb in $colPF)
	{
		## a PF db can never be in a recovery storage group
		## which is why the Recovery check isn&amp;#39;t done here

		write-host ($mdb.Name + &amp;quot;`t &amp;quot; + $mdb.Guid)
		write-host (&amp;quot;`t&amp;quot; + $mdb.EdbFilePath)
		write-host &amp;quot; &amp;quot;

		$pathPattern.($mdb.EdbFilePath) = 1
		$storeList.($mdb.EdbFilePath)   = 1

		$vol = $mdb.EdbFilePath.ToString().SubString(0, 1)
		$volumes.$vol += 1
	}

	return
}

function getStorageGroups
{
	$count = 0
	#
	# locate the storage groups and their log files and system files
	#
	$colSG = get-StorageGroup -server $computername
	if ($colSG.Count -lt 1)
	{
		write-host &amp;quot;No storage groups found on server $computername&amp;quot;
		return 1
	}

	## parse the pathnames for each SG to determine what
	## volumes it stores data upon and what directories are used

	foreach ($sg in $colSG)
	{
		if ($sg.Recovery)
		{
			write-host (&amp;quot;Skipping RECOVERY STORAGE GROUP &amp;quot; + $sg.Name)
			continue
		}

		$count++

		$prefix  = $sg.LogFilePrefix
		$logpath = $sg.LogFolderPath.ToString()
		$syspath = $sg.SystemFolderPath.ToString()

		write-host $sg.Name.ToString() &amp;quot;`t&amp;quot; $sg.Guid.ToString()
		write-host &amp;quot;`tLog prefix:      $prefix&amp;quot;
		write-host &amp;quot;`tLog file path:   $logpath&amp;quot;
		write-host &amp;quot;`tSystem path:     $syspath&amp;quot;

		## E00*.log
		$pathpattern.(join-path $logpath ($prefix + &amp;quot;*.log&amp;quot;)) = 1

		$vol = $logpath.SubString(0, 1)
		$volumes.$vol += 1

		## E00.chk
		$pathpattern.(join-path $syspath ($prefix + &amp;quot;.chk&amp;quot;)) = 1

		$vol = $syspath.SubString(0, 1)
		$volumes.$vol += 1

		write-host &amp;quot; &amp;quot;
	}

	if ($count -lt 1)
	{
		write-host &amp;quot;No storage groups found on server $computername&amp;quot;
		return 1
	}

	return 0
}

function validateArrays
{
	$drives = $volumes.keys
	if ($drives.Count -lt 1)
	{
		write-host &amp;quot;No disk volumes were found. Aborting.&amp;quot;
		return 1
	}

	write-host (&amp;quot;There were &amp;quot; + $drives.Count.ToString() + &amp;quot; disk volumes for Exchange server $computername. They are:&amp;quot;)
	foreach ($drive in $drives)
	{
		write-host &amp;quot;`t$drive&amp;quot;
	}

	write-host &amp;quot; &amp;quot;

	$paths = $pathPattern.keys
	if ($paths.Count -lt 1)
	{
		write-host &amp;quot;No paths were found. Aborting.&amp;quot;
		return 1
	}

	write-host (&amp;quot;There are &amp;quot; + $pathPattern.Count.ToString() + &amp;quot; directories to be backed up. They are:&amp;quot;)
	foreach ($directory in $pathPattern.keys)
	{
		write-host &amp;quot;`t$directory&amp;quot;
	}
	write-host &amp;quot; &amp;quot;

	$letter = $startLetter.Chars(0)

	foreach ($drive in $volumes.keys)
	{
		$letters.$drive = $letter
		$letter = [char]([int]$letter + 1)
	}

	return 0
}

	##
	## Main
	##

	if ((getStorageGroups) -eq 0)
	{
		getStores
		if ((validateArrays) -eq 0)
		{
			$scriptFile = buildCMD
			$scriptFile = buildDSH $scriptFile
			if ($startScript -and ($scriptFile.Length -gt 0))
			{
				diskshadow.exe -s $scriptFile
			}
		}
	}
&lt;/pre&gt;&lt;/font&gt;
&lt;p&gt;Until next time...&lt;/p&gt;
&lt;p&gt;As always, if there are items you would like me to talk about, please drop me a line and let me know!&lt;/p&gt;&lt;img src="http://theessentialexchange.com/aggbug.aspx?PostID=437" width="1" height="1"&gt;</description><category domain="http://theessentialexchange.com/blogs/michael/archive/tags/Administration/default.aspx">Administration</category><category domain="http://theessentialexchange.com/blogs/michael/archive/tags/Script/default.aspx">Script</category><category domain="http://theessentialexchange.com/blogs/michael/archive/tags/Exchange/default.aspx">Exchange</category><category domain="http://theessentialexchange.com/blogs/michael/archive/tags/VSS/default.aspx">VSS</category><category domain="http://theessentialexchange.com/blogs/michael/archive/tags/Diskshadow/default.aspx">Diskshadow</category></item></channel></rss>