<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>108.bz &#187; Active Directory</title>
	<atom:link href="http://www.108.bz/posts/tag/active-directory/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.108.bz</link>
	<description>Wandering futilities...</description>
	<lastBuildDate>Fri, 27 May 2011 09:08:43 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.1.1</generator>
		<item>
		<title>Cloning an Active Directory group</title>
		<link>http://www.108.bz/posts/it/cloning-an-active-directory-group/</link>
		<comments>http://www.108.bz/posts/it/cloning-an-active-directory-group/#comments</comments>
		<pubDate>Wed, 12 Jan 2011 12:06:10 +0000</pubDate>
		<dc:creator>Giuliano</dc:creator>
				<category><![CDATA[IT]]></category>
		<category><![CDATA[Active Directory]]></category>
		<category><![CDATA[Command Line]]></category>
		<category><![CDATA[Windows]]></category>

		<guid isPermaLink="false">http://www.108.bz/?p=617</guid>
		<description><![CDATA[Or how to use the dsquery/dsget/dsmod commands to copy all the members from an Active Directory group (source), to another one (destination). If, like me, you are on a neverending quest to click less and script more, you can solve the problem this way: Create the destination group, should it not exist. Find the source [...]]]></description>
			<content:encoded><![CDATA[<p>Or how to use the <a href="http://technet.microsoft.com/en-us/library/cc732952(WS.10).aspx">dsquery</a>/<a href="http://technet.microsoft.com/en-us/library/cc755162(WS.10).aspx">dsget</a>/<a href="http://technet.microsoft.com/en-us/library/cc732406(WS.10).aspx">dsmod</a> commands to copy all the members from an<br />
Active Directory group (<i>source</i>), to another one (<i>destination</i>).</p>
<p>If, like me, you are on a neverending quest to click less and script more, you can solve the problem this way:</p>
<ul>
<li>Create the destination group, should it not exist.</li>
<li>Find the source group&#8217;s <a href="http://en.wikipedia.org/wiki/Distinguished_Name">DN</a>:
<div class="codecolorer-container text blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:550px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&gt;dsquery group -samid sourcegroup<br />
&quot;CN=sourcegroup,OU=Groups,DC=contoso,DC=com&quot;</div></div>
<p>&#8220;<span style="font-family: Bitstream Vera Sans Mono,Courier New,monospace;">-samid</span>&#8221; argument is the group name whose DN you&#8217;re looking for. You can use &#8220;<span style="font-family: Bitstream Vera Sans Mono,Courier New,monospace;">*</span>&#8221; as a wildcard.</li>
<li>Ditto for the destination group:
<div class="codecolorer-container text blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:550px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&gt;dsquery group -samid destinationgroup<br />
&quot;CN=destinationgroup,OU=Groups,DC=contoso,DC=com&quot;&lt;/li&gt;</div></div>
<li>On with the copy itself:
<div class="codecolorer-container text blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:550px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&gt;dsget group &quot;CN=sourcegroup,OU=Groups,DC=contoso,DC=com&quot; -members -expand | dsmod group &quot;CN=destinationgroup,OU=Groups,DC=contoso,DC=com&quot; -addmbr -c<br />
dsmod succeeded:CN=destinationgroup,OU=Groups,DC=contoso,DC=com</div></div>
<p>These are two commands: &#8220;<span style="font-family: Bitstream Vera Sans Mono,Courier New,monospace;">dsget group</span>&#8221; and &#8220;<span style="font-family: Bitstream Vera Sans Mono,Courier New,monospace;">dsmod group</span>&#8220;. Output from the first is piped to the second. &#8220;<span style="font-family: Bitstream Vera Sans Mono,Courier New,monospace;">-members</span>&#8221; causes the group members&#8217; DNs to be listed on standard output (one by line, quoted). &#8220;<span style="font-family: Bitstream Vera Sans Mono,Courier New,monospace;">-expand</span>&#8221; makes <span style="font-family: Bitstream Vera Sans Mono,Courier New,monospace;">dsget</span> to recursively expand the sub-groups that <i>sourcegroup</i> may hold.<br />
Conversely, <span style="font-family: Bitstream Vera Sans Mono,Courier New,monospace;">dsmod</span> modifies <i>destinationgroup</i> adding members to it.<br />
Very cool, so far. The only caveat is that the &#8220;<span style="font-family: Bitstream Vera Sans Mono,Courier New,monospace;">-c</span>&#8221; switch doesn&#8217;t work as advertised. It should copy members over <i>destinationgroup</i> even if already exist, but it doesn&#8217;t. If you need to re-sync source and dest, delete source&#8217;s contents from dest.</li>
</ul>
<p>Bonus note; here&#8217;s a quick way to discover a user&#8217;s DN given his username:</p>
<div class="codecolorer-container text blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:550px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&gt;dsquery user -samid jdoe<br />
&quot;CN=John Doe,CN=Users,DC=contoso,DC=com&quot;</div></div>
 <img src="http://www.108.bz/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=617" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://www.108.bz/posts/it/cloning-an-active-directory-group/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Using the CLI to manage Windows DNS servers</title>
		<link>http://www.108.bz/posts/uncategorized/using-the-cli-to-manage-windows-dns-servers/</link>
		<comments>http://www.108.bz/posts/uncategorized/using-the-cli-to-manage-windows-dns-servers/#comments</comments>
		<pubDate>Mon, 24 May 2010 14:16:46 +0000</pubDate>
		<dc:creator>Giuliano</dc:creator>
				<category><![CDATA[IT]]></category>
		<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Active Directory]]></category>
		<category><![CDATA[CLI]]></category>
		<category><![CDATA[DNS]]></category>
		<category><![CDATA[Networking]]></category>

		<guid isPermaLink="false">http://www.108.bz/?p=486</guid>
		<description><![CDATA[(This, for once, is going to be quick.) Did you know about the Dnscmd.exe command? Read about it here and here. It&#8217;s the command-line/DOS prompt way to configure Microsoft&#8217;s DNS servers&#8230; If you need to create many zones/records at once, it saves you lots of clicks. Here&#8217;s how to add six DNS zones (same domain [...]]]></description>
			<content:encoded><![CDATA[<p>(This, for once, is going to be quick.)<br />
Did you know about the <span style="font-family: Bitstream Vera Sans Mono,Courier New,monospace;">Dnscmd.exe</span> command? Read about it <a href="http://technet.microsoft.com/en-us/library/cc778513(WS.10).aspx">here</a> and <a href="http://www.petri.co.il/dnscmd_command_in_windows_2000_2003.htm">here</a>. It&#8217;s the command-line/DOS prompt way to configure Microsoft&#8217;s DNS servers&#8230; If you need to create many zones/records at once, it saves you lots of clicks.<br />
Here&#8217;s how to add six DNS zones (same domain name, different TLD). With the <span style="font-family: Bitstream Vera Sans Mono,Courier New,monospace;">/DSPrimary</span> option, the zone will be stored into Active Directory (rather than a file).</p>
<div class="codecolorer-container text blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:550px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">dnscmd /ZoneAdd domainname.bz &nbsp;/DSPrimary<br />
dnscmd /ZoneAdd domainname.biz /DSPrimary<br />
dnscmd /ZoneAdd domainname.com /DSPrimary<br />
dnscmd /ZoneAdd domainname.eu &nbsp;/DSPrimary<br />
dnscmd /ZoneAdd domainname.net /DSPrimary<br />
dnscmd /ZoneAdd domainname.org /DSPrimary</div></div>
<p>And here&#8217;s how to add the same &#8220;A&#8221; record (named &#8220;www&#8221;) to each of the zones created above.</p>
<div class="codecolorer-container text blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:550px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">dnscmd dns-dc-hostname /RecordAdd domainname.bz &nbsp;www A 10.0.0.123<br />
dnscmd dns-dc-hostname /RecordAdd domainname.biz www A 10.0.0.123<br />
dnscmd dns-dc-hostname /RecordAdd domainname.com www A 10.0.0.123<br />
dnscmd dns-dc-hostname /RecordAdd domainname.eu &nbsp;www A 10.0.0.123<br />
dnscmd dns-dc-hostname /RecordAdd domainname.net www A 10.0.0.123<br />
dnscmd dns-dc-hostname /RecordAdd domainname.org www A 10.0.0.123</div></div>
<p>As you may have guessed this is the typical scenario where you&#8217;ve got to re-create some external zones, on the internal DNS servers. That&#8217;s needed in order for the internal hosts to reach some server with the &#8220;public&#8221; DNS name, but the private IP.<br />
For the sake of completeness, let me also mention that you could achieve the same effect by leaving DNS as it is, and configuring  &#8220;loopback NAT&#8221;/&#8221;double NAT&#8221; on the router/firewall. E.g.: an internal Host wants to reach an internal Server, given it&#8217;s public hostname, mapped to a public IP address. It asks the (possibly internal) DNS to translate the name. DNS doesn&#8217;t know the zone, it forwards the query to an external DNS Server, obtaining a public IP address that it hands back to the Client. Since its address is non-local, while trying to talk with the Server, the Client sends packets to its default gateway (possibly the router/firewall). The firewall matches the server&#8217;s public IP addresses, substituting it with the right private one. It also changes the source IP, swapping the Client&#8217;s with the firewall&#8217;s LAN address. This way Client and Server are actually communicating <i>through</i> the firewall, even if they&#8217;re both internal hosts. And the Server can&#8217;t tell Client A from Client B since every connection to it comes from the firewall&#8217;s IP address. That&#8217;s the main reason why I prefer duplicating the public DNS zones on internal DNS servers, with private IP addresses: you avoid routing internal traffic through the firewall, and avoid NAT where there shouldn&#8217;t be any.</p>
 <img src="http://www.108.bz/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=486" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://www.108.bz/posts/uncategorized/using-the-cli-to-manage-windows-dns-servers/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Bulk unlocking Active Directory user accounts</title>
		<link>http://www.108.bz/posts/it/bulk-unlocking-active-directory-user-accounts/</link>
		<comments>http://www.108.bz/posts/it/bulk-unlocking-active-directory-user-accounts/#comments</comments>
		<pubDate>Sat, 15 May 2010 22:23:59 +0000</pubDate>
		<dc:creator>Giuliano</dc:creator>
				<category><![CDATA[IT]]></category>
		<category><![CDATA[Active Directory]]></category>
		<category><![CDATA[LDAP]]></category>
		<category><![CDATA[VBScript]]></category>

		<guid isPermaLink="false">http://www.108.bz/?p=475</guid>
		<description><![CDATA[This post will show you how to generate a list of all the users&#8217; Distinguished Name, then filter it, then do something useful with it. Scenario: saturday morning (after having crashed into bed at 4:00 a.m., btw), Customer calls. A virus hit the Company and one of the most annoying consequences of the outburst, is [...]]]></description>
			<content:encoded><![CDATA[<p>This post will show you how to generate a list of all the users&#8217; <a href="http://en.wikipedia.org/wiki/Distinguished_Name">Distinguished Name</a>, then filter it, then do something useful with it.</p>
<p>Scenario: saturday morning (after having crashed into bed at 4:00 a.m., btw), Customer calls. A virus hit the Company and one of the most annoying consequences of the outburst, is that every domain user account gets locked due to brute-force login attempts (as per the &#8220;Account Lockout Threshold&#8221; <a href="http://technet.microsoft.com/en-us/library/dd277400.aspx">policy</a>). While they run around cleaning PCs and fixing A/V installations<sup class='footnote'><a href='#fn-475-1' id='fnref-475-1'>1</a></sup>, I&#8217;m asked for a method to quickly unlock the accounts.</p>
<p>I tend to carry out these kind of tasks &#8220;the Unix way&#8221;, using the available DOS prompt commands and a bit of VBScript.</p>
<ul>
<li>Start off by calling LDIFDE:</p>
<div class="codecolorer-container text blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:550px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">ldifde -r &quot;(objectclass=user)&quot; -l sAMAccountName -m -f users.ldf</div></div>
<p><a href="http://support.microsoft.com/kb/237677">LDIFDE</a> exports/imports Active Directory data to/from properly formatted (<a href="http://en.wikipedia.org/wiki/LDIF">LDIF</a>) text files. I use it a lot. Ran as shown above, LDIFDE exports the objects of class &#8220;user&#8221; into a file named <span style="font-family: Bitstream Vera Sans Mono,Courier New,monospace;">users.ldf</span> . Of the many attributes an LDAP object bears, I tell LDIFDE to output just the &#8220;sAMAccountName&#8221; one. If I hadn&#8217;t specified any attribute, in the resulting file I&#8217;d have found duplicate DNs for the same user. That&#8217;s because of how the resulting LDIF file is described. Some A/D data is &#8220;incrementally&#8221; added to existing objects given their DN. I just picked sAMAccountName because every user has one and, also, to keep the file small.</li>
<li>Then:
<div class="codecolorer-container text blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:550px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">findstr /I /b dn.*ou=service.users users.ldf &gt; service_users.txt<br />
findstr /I /b dn.*cn=users users.ldf &gt; normal_users.txt</div></div>
<p><a href="http://technet.microsoft.com/en-us/library/bb490907.aspx">findstr</a> is Microsoft&#8217;s &#8220;poor man version&#8221; of <a href="http://en.wikipedia.org/wiki/Grep">grep</a>, supporting a subset of the regular expression everyone has or should&#8217;ve come to love. Here I&#8217;m using it to extract Distinguished Names from the LDIF (only the ones that lie in a given Organizational Unit), and saving them to the <span style="font-family: Bitstream Vera Sans Mono,Courier New,monospace;">*_users.txt</span> files. They will look like:</p>
<div class="codecolorer-container text blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:550px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">dn: CN=squidauth,OU=Service Users,DC=contoso,DC=com<br />
dn: CN=exchangebackup,OU=Service Users,DC=contoso,DC=com<br />
dn: CN=ldap,OU=Service Users,DC=contoso,DC=com<br />
dn: CN=batchcopy,OU=Service Users,DC=contoso,DC=com</div></div>
</li>
<li>Here&#8217;s the VBScript function to unlock an account given its DN:
<div class="codecolorer-container vb blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:550px;"><div class="vb codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000080;">Sub</span> unlockuser(userDN)<br />
&nbsp; <span style="color: #000080;">Set</span> objUser = GetObject (<span style="color: #800000;">&quot;LDAP://&quot;</span> &amp; userDN)<br />
&nbsp; objUser.IsAccountLocked = <span style="color: #000080;">False</span><br />
&nbsp; objUser.SetInfo<br />
<span style="color: #000080;">End</span> <span style="color: #000080;">Sub</span></div></div>
<p>We just need to transform findstr&#8217;s output, substituting the leading &#8220;<span style="font-family: Bitstream Vera Sans Mono,Courier New,monospace;">dn: </span>&#8221; with &#8220;<span style="font-family: Bitstream Vera Sans Mono,Courier New,monospace;">unlockuser</span>&#8221; and enclosing in double quotes what follows. At the top of the new, transformed, file, we&#8217;ll copy/paste <span style="font-family: Bitstream Vera Sans Mono,Courier New,monospace;">unlockuser</span> subroutine definition. That&#8217;ll make our final script.</li>
<li>How to carry out the transform? Using this VBS snippet; it processes its <a href="http://en.wikipedia.org/wiki/Standard_input">Standard Input</a> line by line, and outputs the modifications on Standard Output, just like any Unix file filtering command.
<div class="codecolorer-container vb blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:550px;"><div class="vb codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #000080;">Set</span> StdIn = WScript.StdIn <br />
<span style="color: #000080;">Do</span> <span style="color: #000080;">While</span> <span style="color: #000080;">Not</span> StdIn.AtEndOfStream <br />
&nbsp; &nbsp; <span style="color: #000080;">line</span> = stdin.readline<br />
&nbsp; &nbsp; <span style="color: #000080;">line</span> = right(<span style="color: #000080;">line</span>,len(<span style="color: #000080;">line</span>)-4)<br />
&nbsp; &nbsp; wscript.echo <span style="color: #800000;">&quot;unlockuser &quot;</span><span style="color: #800000;">&quot;&quot;</span> &amp; <span style="color: #000080;">line</span> &amp; <span style="color: #800000;">&quot;&quot;</span><span style="color: #800000;">&quot;&quot;</span><br />
<span style="color: #000080;">Loop</span></div></div>
<p>I saved it in a &#8220;<span style="font-family: Bitstream Vera Sans Mono,Courier New,monospace;">dnfilter.vbs</span>&#8221; file and used it this way:</p>
<div class="codecolorer-container text blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:550px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">type service_users.txt | cscript /nologo dnfilter.vbs &gt; unlock_service_users.vbs</div></div>
<p>To obtain something like this:</p>
<div class="codecolorer-container vb blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:550px;"><div class="vb codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">unlockuser <span style="color: #800000;">&quot;CN=squidauth,OU=Service Users,DC=contoso,DC=com&quot;</span><br />
unlockuser <span style="color: #800000;">&quot;CN=exchangebackup,OU=Service Users,DC=contoso,DC=com&quot;</span><br />
unlockuser <span style="color: #800000;">&quot;CN=ldap,OU=Service Users,DC=contoso,DC=com&quot;</span><br />
unlockuser <span style="color: #800000;">&quot;CN=batchcopy,OU=Service Users,DC=contoso,DC=com&quot;</span></div></div>
</li>
</ul>
<p>As I said, add the <span style="font-family: Bitstream Vera Sans Mono,Courier New,monospace;">unlockuser</span> function at the top of <span style="font-family: Bitstream Vera Sans Mono,Courier New,monospace;">unlock_service_users.vbs</span> and you&#8217;ll have your bulk unlocking script.</p>
<div class='footnotes'>
<div class='footnotedivider'></div>
<ol>
<li id='fn-475-1'>A/V usefulness is often questionable. At least three times a year an unfortunate Customer gets infected by a 0-day threat&#8230; <img src='http://www.108.bz/wp-includes/images/smilies/icon_sad.gif' alt=':(' class='wp-smiley' />  <span class='footnotereverse'><a href='#fnref-475-1'>&#8617;</a></span></li>
</ol>
</div>
 <img src="http://www.108.bz/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=475" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://www.108.bz/posts/it/bulk-unlocking-active-directory-user-accounts/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Active Directory Graphs</title>
		<link>http://www.108.bz/posts/it/active-directory-graphs/</link>
		<comments>http://www.108.bz/posts/it/active-directory-graphs/#comments</comments>
		<pubDate>Wed, 28 Apr 2010 15:26:32 +0000</pubDate>
		<dc:creator>Giuliano</dc:creator>
				<category><![CDATA[IT]]></category>
		<category><![CDATA[Active Directory]]></category>
		<category><![CDATA[Graphs]]></category>
		<category><![CDATA[VBS]]></category>

		<guid isPermaLink="false">http://www.108.bz/?p=443</guid>
		<description><![CDATA[Domain Controllers replicate Active Directory data with each other. They do so through Connections that are partly generated by the KCC (Knowledge Consistency Checker), partly configured by you: the Sysadmin . Each connection is one-way. If you open Active Directory Sites and Services, expand a Site and then a Server node, you&#8217;ll notice that Connections [...]]]></description>
			<content:encoded><![CDATA[<p>Domain Controllers replicate Active Directory data with each other. They do so through <i>Connections</i> that are partly generated by the <i>KCC</i> (Knowledge Consistency Checker), partly configured by you: the Sysadmin . Each connection is one-way. If you open <i>Active Directory Sites and Services</i>, expand a Site and then a Server node, you&#8217;ll notice that Connections listed under <i>NTDS Settings</i> are labeled &#8220;From Server&#8221; and &#8220;From Site&#8221;. In the image below (stolen from <a href="http://technet.microsoft.com/en-us/library/dd277430.aspx">here</a>), the DC named HEIDITEST will replicate AD changes by sending them <i>to</i> MHILLMAN2. The Connection Object is thus defined <i>from</i> HEIDITEST, <i>to</i> MHILLMAN2. You can expect a specular Connection to exist, defined under the <i>NTDS Settings</i> node of HEIDITEST.<br />
<a href="http://www.108.bz/wp-content/uploads/2010/04/adss.gif"><img src="http://www.108.bz/wp-content/uploads/2010/04/adss-300x135.gif" alt="" title="Active Directory Sites and Services" width="300" height="135" class="alignnone size-medium wp-image-452" /></a><br />
See <a href="http://technet.microsoft.com/en-us/library/dd277429.aspx">Active Directory Replication</a> for a more in-depth explanation.<br />
Besides Connection objects automatically created by the <i>KCC</i>, which does its best to build a proper replication topology, you sometimes add your own for fault/link tolerance or other reasons. If the domain is sufficiently big, things may become messy. Instead of fumbling my way through <i>Active Directory Sites and Services</i> I wanted to automatically generate a visual representation of such topology, with DCs and Connections: time to write yet another script. </p>
<p>This time I chose VBS over Perl, hoping that this post would be more &#8220;instructional&#8221;. Perl on Windows is not so common, while VBScript is the standard way to automate stuff on that O.S. (despite the language being incredibly clumsy and annoying<sup class='footnote'><a href='#fn-443-1' id='fnref-443-1'>1</a></sup>).</p>
<p>As for the graph format, I chose to output <a href="http://www.graphviz.org/">Graphviz</a> <a href="http://www.graphviz.org/doc/info/lang.html">DOT</a> format/language.</p>
<p>The script works this way:</p>
<ul>
<li>Find the current domain.</li>
<li>Find all the Domain Controllers (AD objects of class <span style="font-family: Bitstream Vera Sans Mono,Courier New,monospace;">nTDSDSA</span>, see <a href="http://blogs.technet.com/heyscriptingguy/archive/2004/12/16/how-can-i-get-a-list-of-all-the-domain-controllers-in-my-domain.aspx">this</a>) and the <i>Site</i> they&#8217;re in.</li>
<li>For each DC/Site, select <span style="font-family: Bitstream Vera Sans Mono,Courier New,monospace;">nTDSConnection</span> objects in <i>NTDS Settings</i>. Of course this is done by means of LDAP queries over <a href="http://en.wikipedia.org/wiki/ActiveX_Data_Objects">ADO</a>, but the view we get is equivalent to what we&#8217;re seeing in <i>Active Directory Sites and Services</i>.</li>
<li>Print the DOT graph on standard output: DCs, connections and sites. DCs in the same site will be clustered together.</li>
</ul>
<p>To use it, first generate the graph&#8217;s definition:</p>
<div class="codecolorer-container text blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:550px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">cscript /nologo ntdsconnections_graph.vbs &gt; AD-pre.dot</div></div>
<p>Then use Graphviz&#8217;s tools to lay out the graph and turn it into an actual image. For optimal results, I suggest something like:</p>
<div class="codecolorer-container text blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:550px;"><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">ccomps -x AD-pre.dot | dot | gvpack -u | neato -Tpng -n2 &gt; AD-pre.png</div></div>
<p>Here&#8217;s what showed up, in my test case:<br />
<a href="http://www.108.bz/wp-content/uploads/2010/04/AD-pre.png"><img src="http://www.108.bz/wp-content/uploads/2010/04/AD-pre-300x160.png" alt="" title="AD-pre" width="300" height="160" class="alignnone size-medium wp-image-454" /></a></p>
<p>And here&#8217;s the same Domain, after some treatment:<br />
<a href="http://www.108.bz/wp-content/uploads/2010/04/AD-post.png"><img src="http://www.108.bz/wp-content/uploads/2010/04/AD-post-300x104.png" alt="" title="AD-post" width="300" height="104" class="alignnone size-medium wp-image-455" /></a><br />
Such graphs may be useful from a Sysadmin point of view, but they&#8217;re quite ugly, honestly. I originally thought to use Graphviz to output &#8220;some&#8221; format, read it in <a href="http://projects.gnome.org/dia/">Dia</a> or similar diagram drawing software, and then fix the aesthetics. But Dia support (if it ever worked) has been dropped from Grapviz (<a href="http://www.graphviz.org/cvs/ChangeLog">December 10, 2009</a>). Dia&#8217;s 0.97.1 tarball bears a &#8220;dot2dia.py&#8221; plugin, but I haven&#8217;t hacked it into working. Any other editable format known to Graphviz (e.g.: SVG) doesn&#8217;t support &#8220;connector&#8221; primitives meaning that arrows won&#8217;t stick to objects while you drag them around&#8230; I&#8217;ll follow up if I make some progress.</p>
<div class="codecolorer-container vb blackboard" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:550px;height:300px;"><div class="vb codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #008000;">' A/D replication topology graph (Graphviz .DOT format)<br />
</span><span style="color: #008000;">' in the current Domain.<br />
</span><span style="color: #008000;">' ----------------------------<br />
</span><span style="color: #008000;">' Giuliano - http://www.108.bz<br />
</span><br />
<span style="color: #000080;">Set</span> objRootDSE = GetObject(<span style="color: #800000;">&quot;LDAP://RootDSE&quot;</span>)<br />
strConfigurationNC = objRootDSE.<span style="color: #000080;">Get</span>(<span style="color: #800000;">&quot;configurationNamingContext&quot;</span>)<br />
<br />
<span style="color: #000080;">Set</span> adoCommand = CreateObject(<span style="color: #800000;">&quot;ADODB.Command&quot;</span>)<br />
<span style="color: #000080;">Set</span> adoConnection = CreateObject(<span style="color: #800000;">&quot;ADODB.Connection&quot;</span>)<br />
adoConnection.Provider = <span style="color: #800000;">&quot;ADsDSOObject&quot;</span><br />
adoConnection.<span style="color: #000080;">Open</span> <span style="color: #800000;">&quot;Active Directory Provider&quot;</span><br />
adoCommand.ActiveConnection = adoConnection<br />
<br />
strBase = <span style="color: #800000;">&quot;&lt;LDAP://&quot;</span> &amp; strConfigurationNC &amp; <span style="color: #800000;">&quot;&gt;&quot;</span><br />
strFilter = <span style="color: #800000;">&quot;(objectClass=nTDSDSA)&quot;</span><br />
strAttributes = <span style="color: #800000;">&quot;AdsPath&quot;</span><br />
strQuery = strBase &amp; <span style="color: #800000;">&quot;;&quot;</span> &amp; strFilter &amp; <span style="color: #800000;">&quot;;&quot;</span> &amp; strAttributes &amp; <span style="color: #800000;">&quot;;subtree&quot;</span><br />
<br />
adoCommand.CommandText = strQuery<br />
adoCommand.Properties(<span style="color: #800000;">&quot;Page Size&quot;</span>) = 100<br />
adoCommand.Properties(<span style="color: #800000;">&quot;Timeout&quot;</span>) = 60<br />
adoCommand.Properties(<span style="color: #800000;">&quot;Cache Results&quot;</span>) = <span style="color: #000080;">False</span><br />
<br />
<span style="color: #000080;">Set</span> adoRecordset = adoCommand.Execute<br />
<br />
<span style="color: #000080;">Dim</span> dictDCtoSite<br />
<span style="color: #000080;">Set</span> dictDCtoSite = CreateObject(<span style="color: #800000;">&quot;Scripting.Dictionary&quot;</span>)<br />
<span style="color: #000080;">Dim</span> dictSites<br />
<span style="color: #000080;">Set</span> dictSites = CreateObject(<span style="color: #800000;">&quot;Scripting.Dictionary&quot;</span>)<br />
<span style="color: #000080;">Dim</span> arrLink()<br />
<br />
<span style="color: #000080;">Function</span> pp(s)<br />
&nbsp; &nbsp; pp = Replace(right(s,len(s)-3), <span style="color: #800000;">&quot;-&quot;</span>, <span style="color: #800000;">&quot;_&quot;</span>) <span style="color: #008000;">' trash the leading &quot;CN=&quot;<br />
</span><span style="color: #000080;">End</span> <span style="color: #000080;">Function</span><br />
<br />
<span style="color: #000080;">Do</span> <span style="color: #000080;">Until</span> adoRecordset.EOF<br />
&nbsp; &nbsp; <span style="color: #000080;">Set</span> objDC = _<br />
&nbsp; &nbsp; &nbsp; &nbsp; GetObject(GetObject(adoRecordset.Fields(<span style="color: #800000;">&quot;AdsPath&quot;</span>).Value).Parent)<br />
&nbsp; &nbsp; <span style="color: #000080;">Set</span> objSite = _<br />
&nbsp; &nbsp; &nbsp; &nbsp; GetObject(GetObject(objDC.Parent).Parent)<br />
&nbsp; &nbsp; dictDCtoSite.Add objDC.name, objSite.name<br />
&nbsp; &nbsp; <span style="color: #000080;">if</span> <span style="color: #000080;">not</span> dictSites.Exists(objSite.name) <span style="color: #000080;">Then</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; dictSites.Add objSite.name, 1<br />
&nbsp; &nbsp; <span style="color: #000080;">End</span> <span style="color: #000080;">If</span><br />
&nbsp; &nbsp; adoRecordset.MoveNext<br />
<span style="color: #000080;">Loop</span><br />
adoRecordset.<span style="color: #000080;">Close</span><br />
<br />
<span style="color: #000080;">For</span> <span style="color: #000080;">Each</span> strDcRDN <span style="color: #000080;">in</span> dictDCtoSite.Keys <br />
&nbsp; &nbsp; strSiteRDN = dictDCtoSite.Item(strDcRDN)<br />
<br />
&nbsp; &nbsp; strNtdsSettingsPath = <span style="color: #800000;">&quot;LDAP://cn=NTDS Settings,&quot;</span> &amp; strDcRDN &amp; _<br />
&nbsp; &nbsp; <span style="color: #800000;">&quot;,cn=Servers,&quot;</span> &amp; strSiteRDN &amp; <span style="color: #800000;">&quot;,cn=Sites,&quot;</span> &amp; strConfigurationNC<br />
<br />
&nbsp; &nbsp; <span style="color: #000080;">Set</span> objNtdsSettings = GetObject(strNtdsSettingsPath)<br />
<br />
&nbsp; &nbsp; objNtdsSettings.Filter = Array(<span style="color: #800000;">&quot;nTDSConnection&quot;</span>)<br />
<br />
&nbsp; &nbsp; <span style="color: #000080;">For</span> <span style="color: #000080;">Each</span> objConnection <span style="color: #000080;">In</span> objNtdsSettings<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008000;">'WScript.Echo strSiteRDN &amp; &quot; : &quot; &amp; Split(objConnection.fromServer, &quot;,&quot;)(1) &amp; &quot; -&gt; &quot; &amp; strDcRDN <br />
</span>&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000080;">ReDim</span> <span style="color: #000080;">Preserve</span> arrLink(2,k)<br />
&nbsp; &nbsp; &nbsp; &nbsp; arrLink(0,k) = strSiteRDN<br />
&nbsp; &nbsp; &nbsp; &nbsp; arrLink(1,k) = Split(objConnection.fromServer, <span style="color: #800000;">&quot;,&quot;</span>)(1)<br />
&nbsp; &nbsp; &nbsp; &nbsp; arrLink(2,k) = strDcRDN<br />
&nbsp; &nbsp; &nbsp; &nbsp; k = k + 1<br />
&nbsp; &nbsp; <span style="color: #000080;">Next</span><br />
<br />
&nbsp; &nbsp; <span style="color: #000080;">Set</span> strNtdsSettingsPath = <span style="color: #000080;">Nothing</span><br />
<span style="color: #000080;">Next</span><br />
<br />
<span style="color: #000080;">Dim</span> arrSubgraphs()<br />
<span style="color: #000080;">Redim</span> arrSubgraphs(dictSites.Count-1)<br />
<br />
WScript.Echo <span style="color: #800000;">&quot;Digraph AD {&quot;</span><br />
WScript.Echo <span style="color: #800000;">&quot; &nbsp;fontname=helvetica;&quot;</span><br />
WScript.Echo <span style="color: #800000;">&quot; &nbsp;node [fontname=helvetica];&quot;</span><br />
<span style="color: #008000;">' Same site links<br />
</span><span style="color: #000080;">For</span> <span style="color: #000080;">Each</span> strSiteRDN <span style="color: #000080;">in</span> dictSites<br />
&nbsp; &nbsp; nosamesitelinks = <span style="color: #000080;">True</span><br />
&nbsp; &nbsp; headerwritten = <span style="color: #000080;">False</span><br />
&nbsp; &nbsp; <span style="color: #000080;">For</span> k = 0 <span style="color: #000080;">To</span> <span style="color: #000080;">Ubound</span>(arrLink, 2)<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000080;">If</span> strSiteRDN = arrLink(0,k) <span style="color: #000080;">Then</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000080;">if</span> dictDCtoSite.Item(arrLink(1,k)) = dictDCtoSite.Item(arrLink(2,k)) <span style="color: #000080;">Then</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000080;">if</span> nosamesitelinks <span style="color: #000080;">Then</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; nosamesitelinks = <span style="color: #000080;">False</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; WScript.Echo <span style="color: #800000;">&quot; &nbsp; &nbsp;subgraph cluster_&quot;</span> &amp; pp(strSiteRDN) &amp; <span style="color: #800000;">&quot; {&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; headerwritten = <span style="color: #000080;">True</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000080;">End</span> <span style="color: #000080;">If</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; WScript.Echo <span style="color: #800000;">&quot; &nbsp; &nbsp; &nbsp; &nbsp;&quot;</span> &amp; pp(arrLink(1,k)) &amp; <span style="color: #800000;">&quot; -&gt; &quot;</span> &amp; pp(arrLink(2,k)) &amp; <span style="color: #800000;">&quot;;&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000080;">End</span> <span style="color: #000080;">If</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000080;">End</span> <span style="color: #000080;">If</span><br />
&nbsp; &nbsp; <span style="color: #000080;">Next</span><br />
&nbsp; &nbsp; <span style="color: #000080;">If</span> headerwritten <span style="color: #000080;">Then</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; WScript.Echo <span style="color: #800000;">&quot; &nbsp; &nbsp; &nbsp; &nbsp;label= &quot;</span><span style="color: #800000;">&quot;&quot;</span> &amp; pp(strSiteRDN) &amp; <span style="color: #800000;">&quot;&quot;</span><span style="color: #800000;">&quot;&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; WScript.Echo <span style="color: #800000;">&quot; &nbsp; &nbsp;}&quot;</span><br />
&nbsp; &nbsp; <span style="color: #000080;">End</span> <span style="color: #000080;">If</span><br />
<span style="color: #000080;">Next</span><br />
Wscript.Echo<br />
<span style="color: #008000;">' Inter-site links<br />
</span><span style="color: #000080;">For</span> k = 0 <span style="color: #000080;">To</span> <span style="color: #000080;">Ubound</span>(arrLink, 2)<br />
&nbsp; &nbsp; <span style="color: #000080;">if</span> dictDCtoSite.Item(arrLink(1,k)) &lt;&gt; dictDCtoSite.Item(arrLink(2,k)) <span style="color: #000080;">Then</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; WScript.Echo <span style="color: #800000;">&quot; &nbsp; &nbsp;&quot;</span> &amp; pp(arrLink(1,k)) &amp; <span style="color: #800000;">&quot; -&gt; &quot;</span> &amp; pp(arrLink(2,k)) &amp; <span style="color: #800000;">&quot;;&quot;</span><br />
&nbsp; &nbsp; <span style="color: #000080;">End</span> <span style="color: #000080;">If</span><br />
<span style="color: #000080;">Next</span><br />
WScript.Echo <span style="color: #800000;">&quot;}&quot;</span></div></div>
<div class='footnotes'>
<div class='footnotedivider'></div>
<ol>
<li id='fn-443-1'>No powerful and convenient data types, no free and ready to use debugger, no public CPAN-like module repository, unnecessarily verbose syntax; I may go on for an hour&#8230; <span class='footnotereverse'><a href='#fnref-443-1'>&#8617;</a></span></li>
</ol>
</div>
 <img src="http://www.108.bz/wp-content/plugins/wordpress-feed-statistics/feed-statistics.php?view=1&post_id=443" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://www.108.bz/posts/it/active-directory-graphs/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

