
<?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>Lead, Follow, or Move &#187; Active Directory</title>
	<atom:link href="http://www.leadfollowmove.com/archives/tag/active-directory/feed" rel="self" type="application/rss+xml" />
	<link>http://www.leadfollowmove.com</link>
	<description>Adam Bell on Deployment, Automation, PowerShell et al</description>
	<lastBuildDate>Thu, 22 Apr 2010 14:34:55 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>Moving and Renaming objects in Active Directory</title>
		<link>http://www.leadfollowmove.com/archives/powershell/moving-and-renaming-objects-in-active-directory</link>
		<comments>http://www.leadfollowmove.com/archives/powershell/moving-and-renaming-objects-in-active-directory#comments</comments>
		<pubDate>Tue, 04 Mar 2008 16:07:46 +0000</pubDate>
		<dc:creator>Adam Bell</dc:creator>
				<category><![CDATA[PowerShell]]></category>
		<category><![CDATA[Active Directory]]></category>

		<guid isPermaLink="false">http://www.leadfollowmove.com/archives/powershell/moving-and-renaming-objects-in-active-directory</guid>
		<description><![CDATA[I went to move some AD objects with PowerShell recently, and realised that I didn&#8217;t have any examples to hand. Despite covering AD permission delegation and GPO operations, I&#8217;d somehow missed the fairly obvious task of moving and renaming objects! So this seemed like a good time fix that &#8230; We need to bind to [...]]]></description>
			<content:encoded><![CDATA[<p>I went to move some AD objects with PowerShell recently, and realised that I didn&#8217;t have any examples to hand. Despite covering AD permission delegation and GPO operations, I&#8217;d somehow missed the fairly obvious task of <strong>moving</strong> and <strong>renaming</strong> objects! </p>
<p>So this seemed like a good time fix that &#8230;</p>
<p>We need to bind to some objects in AD, starting with the <em>Users OU</em>, and a fictional OU for our example, <em>Service Accounts</em> where we will move our objects to.</p>
<div class="quickcodenoclick"><code><br />
$root = [adsi]&quot;&quot;<br />
$users = [adsi](&quot;LDAP://cn=users,&quot;+$root.distinguishedName)<br />
$sa = [adsi](&quot;LDAP://ou=Service Accounts,&quot;+$root.distinguishedName)<br />
</code></div>
<p>Now that we have bindings to the directory locations, we need to bind to an account we&#8217;d like to move.</p>
<div class="quickcodenoclick"><code><br />
$admin = [adsi](&quot;LDAP://cn=Administrator,&quot;+$users.distinguishedName)<br />
</code></div>
<p>The actually moving of an object isn&#8217;t made available through the PowerShell wrapper from what I could see. So to achieve this we need to expose the raw .Net methods using <strong>psbase</strong>.</p>
<div class="quickcodenoclick"><code><br />
$admin.psbase | get-member | where-object {$_.Name -eq &quot;MoveTo&quot;}<br />
System.Void MoveTo(DirectoryEntry newParent), System.Void MoveTo(DirectoryEntry newParent, String newName)<br />
</code></div>
<p>I already knew the name of the method we&#8217;d need to use <em>MoveTo()</em>, so we used a <em>where-object</em> cmdlet to reduce our output to just what we needed. Looking at the above method, we can see that we can also rename the object by passing a second set of parameters.</p>
<p>Having bound to the <em>Service Accounts</em> OU, and the <em>Administrator</em> account, the only thing left to do is the actual move:</p>
<div class="quickcodenoclick"><code><br />
$admin.PSBase.MoveTo($sa)<br />
</code></div>
<p>Something to bear in mind if we want to rename an object, is that we could pass the same DirectoryEntry location as the object current exists in, or a new location. This method won&#8217;t update the <strong>sAMAccountName</strong> attribute.</p>
<p>If you want to change attributes on an object, it&#8217;s worth doing this <strong>before</strong> the move, and the binding becomes invalid. In our example of renaming the account, there&#8217;s a couple of attributes worth changing:</p>
<div class="quickcodenoclick"><code><br />
$admin.put(&quot;sAMAccountName&quot;, &quot;zNobodyHere&quot;)<br />
$admin.put(&quot;Description&quot;, &quot;Nobody Service Account&quot;)<br />
$admin.put(&quot;userPrincipalName&quot;, &quot;zNobodyHere@leadfollowmove.com&quot;)<br />
$admin.Setinfo()<br />
</code></div>
<p>Renaming, the Administrator account, and keeping it in the Users container:</p>
<div class="quickcodenoclick"><code><br />
$admin.PSBase.MoveTo($users, &quot;cn=zNobodyHere&quot;)<br />
</code></div>
<p>Renaming the Administrator account, and moving it to our <em>Service Accounts</em> OU:</p>
<div class="quickcodenoclick"><code><br />
$admin.PSBase.MoveTo($sa, &quot;cn=zNobodyHere&quot;)<br />
</code></div>
<p>Alternatively, you could use the <a href="http://www.quest.com/powershell/">Quest AD cmdlets</a> to move or rename. Sometimes, however you don&#8217;t always have the tools available that you might like!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.leadfollowmove.com/archives/powershell/moving-and-renaming-objects-in-active-directory/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Windows 2003 DNS Server rights issue</title>
		<link>http://www.leadfollowmove.com/archives/powershell/windows-2003-dns-server-rights-issue</link>
		<comments>http://www.leadfollowmove.com/archives/powershell/windows-2003-dns-server-rights-issue#comments</comments>
		<pubDate>Wed, 27 Feb 2008 14:45:11 +0000</pubDate>
		<dc:creator>Adam Bell</dc:creator>
				<category><![CDATA[PowerShell]]></category>
		<category><![CDATA[Windows Server 2003]]></category>
		<category><![CDATA[Active Directory]]></category>

		<guid isPermaLink="false">http://www.leadfollowmove.com/archives/powershell/windows-2003-dns-server-rights-issue</guid>
		<description><![CDATA[Apparently there is a permissions issue regarding hosting DNS zones in the ForestDNSZones, or DomainDNSZones partitions in Server 2003. I haven&#8217;t looked to see if this has been resolved in 2008. The issue and solution is detailed in Microsoft KB939090. This issue occurs because of the permissions that are set in the Active Directory directory [...]]]></description>
			<content:encoded><![CDATA[<p>Apparently there is a permissions issue regarding hosting DNS zones in the <strong>ForestDNSZones</strong>, or <strong>DomainDNSZones</strong> partitions in Server 2003. I haven&#8217;t looked to see if this has been resolved in 2008. The issue and solution is detailed in <a title="Microsoft Support: KB article 939090" href="http://support.microsoft.com/kb/939090">Microsoft KB939090</a>.</p>
<blockquote><p>
This issue occurs because of the permissions that are set in the Active Directory directory service&#8230;.<br />
The members of the DnsAdmins group do not have permissions on the following application partitions:<br />
CN=MicrosoftDNS,DC=ForestDNSZones,DC=Domain&#8230;<br />
CN=MicrosoftDNS,DC=DomainDNSZones,DC=Domain&#8230;
</p></blockquote>
<p>The documented solution is to edit your Active Directory with ADSIEdit and go in to fix the problem:</p>
<blockquote><p>
To resolve this issue, set permissions for the DnsAdmins group on the DomainDNSZones application partition and on the ForestDNSZones application partition.
</p></blockquote>
<p>We have taken a pretty close look at manipulating permissions in AD with PowerShell before, covering:<br />
<a title="Lead, Follow, or Move: Active Directory Standard Rights" href="http://www.leadfollowmove.com/archives/powershell/active-directory-permissions-standard-rights">Standard Rights</a><br />
<a title="Lead, Follow, or Move: Removing ACE's from Active Directory" href="http://www.leadfollowmove.com/archives/powershell/removing-aces-from-active-directory-with-powershell">Removing Rights in AD</a><br />
<a title="Lead, Follow, or Move: Inheritance and Propagation in Active Directory" href="http://www.leadfollowmove.com/archives/powershell/inheritance-and-propagation-in-active-directory-permissions">Inheritance and Propagation</a><br />
<a title="Lead, Follow, or Move:Extended Rights in Active Directory" href="http://www.leadfollowmove.com/archives/powershell/extended-rights-in-active-directory">Extended Rights</a><br />
and <a title="Lead, Follow, or Move: Control Access Rights in Active Directory" href="http://www.leadfollowmove.com/archives/powershell/control-access-rights-in-active-directory">Controlling Access Rights in AD</a></p>
<p>We&#8217;re going to build a function similar to Add-DsAce.ps1 we used in the Standard Rights post, but this time we&#8217;re going to use a slightly different constructor, so that we can apply the correct inheritance. We want this to affect &#8220;This object and all Child Objects&#8221;, which means we need to use:</p>
<div class="quickcodenoclick"><code><br />
[System.DirectoryServices.ActiveDirectorySecurityInheritance]&quot;SelfAndChildren&quot;<br />
</code></div>
<p>So, our modified function looks like this:<br />
<a class="quickcode" title="Code" href="javascript:toggleLayer('quickcode2292');">Add-DsAce2.ps1</a></p>
<div id="quickcode2292" class="quickcode"><code><br />
#&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;&#45;-<br />
function Add-DsAce<br />
#&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;&#45;-<br />
{<br />
Param (<br />
&nbsp;&nbsp;$DSobject,<br />
&nbsp;&nbsp;$Identifier,<br />
&nbsp;&nbsp;$DSrights,<br />
&nbsp;&nbsp;$AccessType = &quot;Allow&quot;,<br />
&nbsp;&nbsp;$Inheritance<br />
&nbsp;&nbsp;)<br />
&nbsp;&nbsp;# GetAccessRules: Explicit ACE&#039;s, Inherited ACE&#039;s, TargetType<br />
&nbsp;&nbsp;$account = New-Object system.security.principal.ntaccount($Identifier)<br />
&nbsp;<br />
&nbsp;&nbsp;# Retrieve the SID - as a manual step you can check it&#039;s not empty :)<br />
&nbsp;&nbsp;$sid = $account.translate([system.security.principal.securityidentifier])<br />
&nbsp;<br />
&nbsp;&nbsp;$Inheritance = [System.DirectoryServices.ActiveDirectorySecurityInheritance]&quot;SelfAndChildren&quot;<br />
&nbsp;&nbsp;$ace = New-Object System.DirectoryServices.ActiveDirectoryAccessRule($account, $DSrights, $AccessType, $Inheritance)<br />
&nbsp;&nbsp;$DSobject.psbase.get_objectsecurity().AddAccessRule($ace)<br />
&nbsp;&nbsp;$DSobject.psbase.CommitChanges()<br />
}<br />
#&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;&#45;-<br />
</code></div>
<p>Now that we have the ability to modify the AD, and presuming we dot source the newly created function we could do the following:</p>
<div class="quickcodenoclick"><code><br />
$root = [adsi]&quot;&quot;<br />
$ForestDNSZones = [adsi](&quot;LDAP://DC=ForestDNSZones,&quot;+$root.distinguishedName)<br />
$DomainDNSZones = [adsi](&quot;LDAP://CN=MicrosoftDNS, DC=DomainDNSZones,&quot;+$root.distinguishedName)<br />
&nbsp;<br />
Add-DSace $ForestDNSZones &quot;DNSAdmins&quot; &quot;GenericAll&quot;<br />
Add-DSAce $DomainDNSZones &quot;DNSAdmins&quot; &quot;GenericAll&quot;<br />
</code></div>
<p>Basically, we&#8217;ve bound to AD via ADSI so that we can dynamically provide the domain DN, and the two locations in AD we want to apply the ACE to. Then it&#8217;s just a matter of passing the created function the parameters needed.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.leadfollowmove.com/archives/powershell/windows-2003-dns-server-rights-issue/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Dynamically populating user properties in Active Directory</title>
		<link>http://www.leadfollowmove.com/archives/powershell/dynamically-populating-user-properties-in-active-directory</link>
		<comments>http://www.leadfollowmove.com/archives/powershell/dynamically-populating-user-properties-in-active-directory#comments</comments>
		<pubDate>Thu, 04 Oct 2007 11:19:51 +0000</pubDate>
		<dc:creator>Adam Bell</dc:creator>
				<category><![CDATA[Active Directory]]></category>
		<category><![CDATA[PowerShell]]></category>

		<guid isPermaLink="false">http://www.leadfollowmove.com/archives/powershell/dynamically-populating-user-properties-in-active-directory</guid>
		<description><![CDATA[Recently I was asked to help out with a small issue pertaining to rolling out MS Live Communications Server. Two SIP properties (msRTCSIP-LineServer &#038; msRTCSIP-Line) on the user object in AD were set dependent on which office the user was located in, and their Direct Dial (DDI) number. These properties needed to be set on [...]]]></description>
			<content:encoded><![CDATA[<p>Recently I was asked to help out with a small issue pertaining to rolling out MS Live Communications Server. Two SIP properties (<a title="Microsoft Office Live Communications Server 2005:Updating to Service Pack 1 and Enabling Public IM Connectivity" href="http://www.microsoft.com/technet/prodtechnol/office/livecomm/library/updatesp1/lcsusp_11.mspx">msRTCSIP-LineServer &#038; msRTCSIP-Line</a>) on the user object in AD were set dependent on which office the user was located in, and their Direct Dial (DDI) number. These properties needed to be set on the users on 3 sites, and I was asked if PowerShell could assist.</p>
<p>Seeing as I don&#8217;t have the schema extensions in my test lab, we will step through a similar scenario, but we&#8217;ll update the users description property instead.</p>
<p>In this example we have two test users:<br />
<a href='http://www.leadfollowmove.com/archives/powershell/dynamically-populating-user-properties-in-active-directory/attachment/test-users-for-setting-description-property/' rel='attachment wp-att-175' title='Test Users for setting description property'><img src='http://www.leadfollowmove.com/wp-content/uploads/accountsou.thumbnail.PNG' alt='Test Users for setting description property' /></a></p>
<p>We&#8217;re interested in the two User properties: <em>Office</em> and <em>Telephone number</em>. These would make up part of the SIP information for LCS, but in our example we just want to add them to the <em>description</em> property for easier viewing in <em>AD User&#8217;s and Computers</em>.<br />
<a href='http://www.leadfollowmove.com/archives/powershell/dynamically-populating-user-properties-in-active-directory/attachment/user1-property-page/' rel='attachment wp-att-176' title='User1 Property page'><img src='http://www.leadfollowmove.com/wp-content/uploads/user1.thumbnail.PNG' alt='User1 Property page' /></a></p>
<p>Presuming, that we want to update the description field against a large selection of users we will take advantage of how PowerShell handles CSV&#8217;s:<br />
<a href='http://www.leadfollowmove.com/archives/powershell/dynamically-populating-user-properties-in-active-directory/attachment/accountscsv/' rel='attachment wp-att-177' title='Accounts.csv'><img src='http://www.leadfollowmove.com/wp-content/uploads/accountscsv.thumbnail.PNG' alt='Accounts.csv' /></a></p>
<p><a class="quickcode" title="Code" href="javascript:toggleLayer('quickcode1741');">set-usrdesc.ps1</a></p>
<div id="quickcode1741" class="quickcode"><code><br />
# <br />
# NAME:&nbsp;&nbsp;&nbsp;&nbsp; Set-UsrDesc.ps1<br />
# <br />
# AUTHOR:&nbsp;&nbsp; Adam Bell, http://www.leadfollowmove.com<br />
# RELEASE:&nbsp;&nbsp;Contractors Creed - All care taken, no responsibility admitted. Use at your own risk.<br />
# VERSION:<br />
# 1.0.1&nbsp;&nbsp;&nbsp;&nbsp;25/09/2007&nbsp;&nbsp;Adam Bell&nbsp;&nbsp;Initial.<br />
# 1.0.2&nbsp;&nbsp;&nbsp;&nbsp;26/09/2007&nbsp;&nbsp;Adam Bell&nbsp;&nbsp;refined for live.<br />
# <br />
# COMMENT: Best viewed using Notepad2<br />
#&nbsp;&nbsp; <br />
# &#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;&#45;--<br />
# Check command-line arguments<br />
# &#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;&#45;--<br />
&nbsp;&nbsp;if ($args.count -ne 1)<br />
&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;write-host &quot;Usage: &lt;Path to CSV File&gt;&quot;<br />
&nbsp;&nbsp;&nbsp;&nbsp;write-host &quot;CSV requires a header line.&quot;<br />
&nbsp;&nbsp;&nbsp;&nbsp;write-host &quot; UserName,OU is the only data needed. No DomainDN in the OU DN.&quot;<br />
&nbsp;&nbsp;&nbsp;&nbsp;write-host &quot;&quot;<br />
&nbsp;&nbsp;&nbsp;&nbsp;exit<br />
&nbsp;&nbsp;}<br />
&nbsp;&nbsp;$InFile = $args[0]<br />
&nbsp;&nbsp;If (-not(test-path $InFile))<br />
&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;write-host &quot;Unable to locate&quot; $InFile<br />
&nbsp;&nbsp;&nbsp;&nbsp;exit<br />
&nbsp;&nbsp;}<br />
# &#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;&#45;--<br />
# Globals<br />
# &#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;&#45;--<br />
# If there are any errors,we&#039;ll handle them in code.</p>
<p>&nbsp;&nbsp; $erroractionpreference = &quot;SilentlyContinue&quot;<br />
&nbsp;&nbsp; $root = [adsi]&quot;&quot;<br />
# &#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;&#45;--<br />
function set-Desc<br />
# &#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;&#45;--<br />
{<br />
#&nbsp;&nbsp;Inputs:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1) The CN UserName of the Account object<br />
#&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2) The OU DN without the Domain DN portion included.<br />
#&nbsp;&nbsp;Objective:&nbsp;&nbsp;1) Process each user, and update the description property based on Office and DDI info.<br />
#&nbsp;&nbsp;Returns:&nbsp;&nbsp;&nbsp;&nbsp; 1) Nothing. Updates the users props.<br />
Param (<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $UserName,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $OUname<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; )<br />
&nbsp;&nbsp; $error.clear()<br />
&nbsp;&nbsp; $user = [adsi](&quot;LDAP://cn=&quot;+$UserName `<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+&quot;,&quot;+$OUname+&quot;,&quot;+$root.distinguishedName)<br />
&nbsp;&nbsp; if (!$?)<br />
&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;write-warning &quot;Unable to bind to $UserName&quot;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;write-host &quot;&quot;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;continue<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp;$office = $user.get(&quot;physicalDeliveryOfficeName&quot;)<br />
&nbsp;&nbsp;if (!$?)<br />
&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; write-warning &quot;Unable to retrieve Office Location for $UserName&quot;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; write-host &quot;&quot;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; continue<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; $ddi&nbsp;&nbsp;&nbsp;&nbsp;= $user.get(&quot;telephoneNumber&quot;)<br />
&nbsp;&nbsp; if (!$?)<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; write-warning &quot;Unable to retrieve DDI number for $UserName&quot;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; write-host &quot;&quot;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; continue<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; $user.put(&quot;description&quot;, &quot;($office) $ddi&quot;)<br />
&nbsp;&nbsp; $user.setinfo()<br />
&nbsp;&nbsp; If (!$error[0])<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; write-host &quot;$username updated.&quot; -foregroundcolor &quot;green&quot;<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; else<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; write-warning &quot;Updating $UserName failed!&quot;<br />
&nbsp;&nbsp; }<br />
&nbsp;&nbsp; write-host &quot;&quot;<br />
}<br />
# &#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;&#45;--<br />
function get-userlist<br />
# &#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;&#45;--<br />
{<br />
#&nbsp;&nbsp;Inputs:&nbsp;&nbsp;&nbsp;&nbsp; 1) Path to CSV file containing Users to process. Needs a header line: UserName, OU<br />
#&nbsp;&nbsp;Objective:&nbsp;&nbsp;1) Get the data from the CSV file and pass it to Set-Desc<br />
#&nbsp;&nbsp;Returns:&nbsp;&nbsp;&nbsp;&nbsp;1) Nothing.<br />
# Depends:&nbsp;&nbsp;&nbsp;&nbsp;1) Set-Desc<br />
Param (<br />
&nbsp;&nbsp;$PathToCSV<br />
&nbsp;&nbsp;)<br />
&nbsp;&nbsp; $accounts = Import-Csv $PathToCSV<br />
&nbsp;&nbsp; foreach ($account in $accounts)<br />
&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;$UserName = $account.UserCN<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;If ($UserName.StartsWith(&quot;#&quot;) -eq $true)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Else<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;Processing &#46;.. &quot;+$UserName<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;set-Desc $UserName $account.OU<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp; }<br />
}<br />
# &#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;&#45;--<br />
# Main<br />
# &#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;&#45;--<br />
&nbsp;&nbsp;get-userlist $InFile<br />
# &#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;&#45;--<br />
</code></div>
<p>A couple of points of interest, from the script above:<br />
The Username is the CN (usually the <em>displayName</em> property), and is added with the ouName provided in the CSV, and the distinguishedName of the domain to build the ADSI binding to the user object.</p>
<p>The <em>get()</em>,<em>put()</em> and <em>setinfo()</em> methods are pretty self explanatory, especially if you&#8217;ve done any ADSI scripting before. </p>
<p>What&#8217;s nice about PowerShell is that you can user variables &#8220;inline&#8221;. It doesn&#8217;t work when constructing the ADSI binding, but it does when constructing strings (in this case for out <em>put()</em> method).</p>
<p>The <em>(!$?)</em> <em>if</em> block is a nice error checking step that check&#8217;s if the the last command <strong>wasn&#8217;t</strong> successful.</p>
<p>The <em>!error[0]</em> <em>if</em> block tests if we have had <strong>any</strong> errors in our process, and provides feedback to the console accordingly.</p>
<p>Running the script gives us the following output:<br />
<a href='http://www.leadfollowmove.com/archives/powershell/dynamically-populating-user-properties-in-active-directory/attachment/set-usrdescps1-script-console-output/' rel='attachment wp-att-180' title='Set-UsrDesc.ps1 script console output'><img src='http://www.leadfollowmove.com/wp-content/uploads/set-userdescr-results.thumbnail.PNG' alt='Set-UsrDesc.ps1 script console output' /></a></p>
<p>And if we check the user account, we can see that the description field has been updated for easy viewing , if we had a lot of users.<br />
<a href='http://www.leadfollowmove.com/archives/powershell/dynamically-populating-user-properties-in-active-directory/attachment/user1-account-updated-by-the-set-usrdescps1-script/' rel='attachment wp-att-181' title='User1 account - updated by the set-usrdesc.ps1 script'><img src='http://www.leadfollowmove.com/wp-content/uploads/user1-descr.thumbnail.PNG' alt='User1 account - updated by the set-usrdesc.ps1 script' /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.leadfollowmove.com/archives/powershell/dynamically-populating-user-properties-in-active-directory/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Control Access Rights in Active Directory</title>
		<link>http://www.leadfollowmove.com/archives/powershell/control-access-rights-in-active-directory</link>
		<comments>http://www.leadfollowmove.com/archives/powershell/control-access-rights-in-active-directory#comments</comments>
		<pubDate>Tue, 03 Apr 2007 20:41:55 +0000</pubDate>
		<dc:creator>Adam Bell</dc:creator>
				<category><![CDATA[Active Directory]]></category>
		<category><![CDATA[PowerShell]]></category>

		<guid isPermaLink="false">http://www.leadfollowmove.com/archives/powershell/control-access-rights-in-active-directory</guid>
		<description><![CDATA[Recently we looked at Extended-Rights in Active directory, and today we&#8217;ll complete our series of posts on permissions in AD with a post on Control Access Rights, also known as Specific Rights. Control Access Rights are similar to Standard Rights in the permissions applied, however it is applied to a specific object, or property set. [...]]]></description>
			<content:encoded><![CDATA[<p>Recently we looked at <em>Extended-Rights</em> in Active directory, and today we&#8217;ll complete our series of posts on permissions in AD with a post on <em>Control Access Rights</em>, also known as <em>Specific Rights</em>.</p>
<p><em>Control Access Rights</em> are similar to <em>Standard Rights</em> in the permissions applied, however it is applied to a specific object, or <a title="TechNet:Using Scripts to Delegate Control of Active Directory" href="http://www.microsoft.com/technet/scriptcenter/topics/security/propset.mspx">property set</a>. This property is also  represented by a <em>system.guid</em> like we have previously seen with <em>Extended Rights</em>.</p>
<p>In this case however the GUID is the <em>schemaIDGUID</em> attribute on the object located in the Schema partition. Provided the <em>Common Name</em> (<em>cn</em>) is known of the object needed the function below will retrieve the GUID in question:<br />
<a class="quickcode" title="Code" href="javascript:toggleLayer('quickcode691');">Get-SchemaGUID.ps1</a></p>
<div id="quickcode691" class="quickcode"><code><br />
$dse = [adsi](&quot;LDAP://RootDSE&quot;)<br />
&nbsp;<br />
#&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;&#45;-<br />
function get-SchemaGUID<br />
#&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;&#45;-<br />
{<br />
Param (<br />
&nbsp;&nbsp;$DSobject<br />
&nbsp;&nbsp;)<br />
&nbsp;&nbsp;$guid = $null<br />
&nbsp;&nbsp;$obj = [adsi](&quot;LDAP://cn=&quot;+$DSobject+&quot;,&quot;+$dse.schemaNamingContext)<br />
&nbsp;&nbsp;[system.guid]$guid = $obj.schemaIDGUID[0]<br />
&nbsp;&nbsp;return $guid.ToString()<br />
}<br />
#&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;&#45;-<br />
get-schemaguid &quot;computer&quot;<br />
</code></div>
<p>Once we have the GUID for the object or <em>Property Set</em>, we can then start thinking about our <em>ACE</em>. For <em>Control Access Rights</em> there are two types of scenarios, and hence two constructors available. We would use the following constructor when delegating the ability to create and delete computer objects in the computers container, for example.</p>
<div class="quickcodenoclick"><code><br />
Void .ctor(<br />
Void .ctor(<br />
&nbsp;&nbsp;System.Security.Principal.IdentityReference, <br />
&nbsp;&nbsp;System.DirectoryServices.ActiveDirectoryRights, <br />
&nbsp;&nbsp;System.Security.AccessControl.AccessControlType, <br />
&nbsp;&nbsp;System.Guid,<br />
&nbsp;&nbsp;System.DirectoryServices.ActiveDirectorySecurityInheritance)<br />
</code></div>
<p>The <em>ACE</em> can be further controlled by specificing the type of object that may inherit the <em>ACE</em>. In that scenario you would use the following constructor:</p>
<div class="quickcodenoclick"><code><br />
Void .ctor(<br />
&nbsp;&nbsp;System.Security.Principal.IdentityReference, <br />
&nbsp;&nbsp;System.DirectoryServices.ActiveDirectoryRights, <br />
&nbsp;&nbsp;System.Security.AccessControl.AccessControlType, <br />
&nbsp;&nbsp;System.Guid, <br />
&nbsp;&nbsp;System.DirectoryServices.ActiveDirectorySecurityInheritance, <br />
&nbsp;&nbsp;System.Guid)<br />
</code></div>
<p>As you can see with two GUID&#8217;s in the syntax it becomes much easier to get things in the wrong order and in turn get an unexpected result. </p>
<p><a title="MSDN: ActiveDirectoryAccessRule Constructor " href="http://msdn2.microsoft.com/en-us/library/system.directoryservices.activedirectoryaccessrule.activedirectoryaccessrule.aspx">MSDN</a> has a clearer  description of the constructors, and you can see that the GUID&#8217;s are for different objects.</p>
<p>So, armed with the GUID of the object, and the rest of the of our information we can go about setting the <em>Control Access Right</em>.<br />
<a class="quickcode" title="Code" href="javascript:toggleLayer('quickcode694');">Set-CAR.ps1</a></p>
<div id="quickcode694" class="quickcode"><code><br />
$root&nbsp;&nbsp;&nbsp;&nbsp;= [adsi]&quot;&quot;<br />
$test&nbsp;&nbsp;&nbsp;&nbsp;= [adsi](&quot;LDAP://ou=Test OU,&quot;+$root.distinguishedName)<br />
&nbsp;<br />
$account&nbsp;&nbsp;= New-Object System.Security.Principal.NTAccount(&quot;bella&quot;)<br />
$inherit&nbsp;&nbsp;= [System.DirectoryServices.ActiveDirectorySecurityInheritance]&quot;All&quot;<br />
&nbsp;<br />
$rights&nbsp;&nbsp;&nbsp;&nbsp;= &quot;CreateChild, DeleteChild&quot;<br />
$gplink&nbsp;&nbsp;&nbsp;&nbsp;= &quot;f30e3bbe-9ff0-11d1-b603-0000f80367c1&quot;<br />
$ace&nbsp;&nbsp;&nbsp;&nbsp;= New-Object System.DirectoryServices.ActiveDirectoryAccessRule($acc, $rights, &quot;Allow&quot;, $gplink, $Inherit)<br />
&nbsp;<br />
$test.psbase.get_objectSecurity().AddAccessRule($ace)<br />
$test.psbase.CommitChanges()<br />
</code></div>
<p>The above example gives the <em>Bella</em> account the rights to link Group Policy objects in the <em>Test OU</em>, and any sub OU&#8217;s (due to the inheritances flag).</p>
<p>Now we&#8217;ve covered the three types of permissions within the Active Directory, you should be able to apply any combination of permissions you need to organise the delegation model within your environment. </p>
<p>It makes me smile when I think back to the old NT4 days! ;)</p>
<p>[Updated:] The paragraph describing <em>InheritedObjectTypes</em> was rewritten to try and clarify the difference between the constructors.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.leadfollowmove.com/archives/powershell/control-access-rights-in-active-directory/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Extended Rights in Active Directory</title>
		<link>http://www.leadfollowmove.com/archives/powershell/extended-rights-in-active-directory</link>
		<comments>http://www.leadfollowmove.com/archives/powershell/extended-rights-in-active-directory#comments</comments>
		<pubDate>Wed, 28 Mar 2007 20:16:42 +0000</pubDate>
		<dc:creator>Adam Bell</dc:creator>
				<category><![CDATA[Active Directory]]></category>
		<category><![CDATA[PowerShell]]></category>

		<guid isPermaLink="false">http://www.leadfollowmove.com/archives/powershell/extended-rights-in-active-directory</guid>
		<description><![CDATA[Extended Rights are one of the mechanisms behind Active Directory permissions that allow for such granular control over the delegation of tasks in your environment. There&#8217;s a Technet article that explains delegation and touches on Extended Rights (near the bottom). Extended Rights exists in AD as objects stored within the Extended-Rights container, which is located [...]]]></description>
			<content:encoded><![CDATA[<p>Extended Rights are one of the mechanisms behind Active Directory permissions that allow for such granular control over the delegation of tasks in your environment. There&#8217;s a <a href="http://www.microsoft.com/technet/prodtechnol/windowsserver2003/technologies/directory/activedirectory/actdid3.mspx">Technet</a> article that explains delegation and touches on <em>Extended Rights</em> (near the bottom).</p>
<p><em>Extended Rights</em> exists in AD as objects stored within the Extended-Rights container, which is located in the Configuration partition.</p>
<p>If you&#8217;re not sure about the different partitions within AD there is an excellent primer on <a title="TechNet: Active Directory Architecture" href="http://www.microsoft.com/technet/prodtechnol/windows2000serv/technologies/activedirectory/deploy/projplan/adarch.mspx">TechNet</a> about AD Architecture.</p>
<p>So how do we set an <em>Extended Right</em> permission? It&#8217;s actually very similiar to applying a <em>Standard Rights</em> ACE. The difference comes in the parameters we pass, and hence the constructor we use in the <em>ActiveDirectoryAccessRule</em> method.</p>
<div class="quickcodenoclick"><code><br />
Void .ctor(<br />
&nbsp;&nbsp;System.Security.Principal.IdentityReference, <br />
&nbsp;&nbsp;System.DirectoryServices.ActiveDirectoryRights, <br />
&nbsp;&nbsp;System.Security.AccessControl.AccessControlType, <br />
&nbsp;&nbsp;System.Guid, <br />
&nbsp;&nbsp;System.DirectoryServices.ActiveDirectorySecurityInheritance)<br />
</code></div>
<p>In this case the <em>ActiveDirectoryRights</em> value is the keyword &#8220;<em>ExtendedRight</em>&#8220;, and the <em>system.Guid</em> refers to an attribute of the Extended Rights object called the <em>rightsGUID</em>. </p>
<p>I&#8217;ve got a function that takes the CN of the right as input and returns the <a title="Google: Define:GUID" href="http://www.google.co.uk/search?hl=en&#038;q=define%3Aguid&#038;meta=">GUID</a>.</p>
<p>Lookup Extended-Right GUID:<br />
<a class="quickcode" title="Code" href="javascript:toggleLayer('quickcode672');">get-erGUID.ps1</a></p>
<div id="quickcode672" class="quickcode"><code><br />
$dse = [adsi](&quot;LDAP://Rootdse&quot;)<br />
&nbsp;<br />
#&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;&#45;-<br />
function Get-RightsGUID<br />
{<br />
Param (<br />
&nbsp;&nbsp;$ExtendedRight<br />
&nbsp;&nbsp;)<br />
&nbsp;&nbsp;$ER = [adsi](&quot;LDAP://cn=Extended-Rights,&quot;+$dse.configurationNamingContext)<br />
&nbsp;&nbsp;$DSobject = [adsi](&quot;LDAP://cn=&quot;+$ExtendedRight+&quot;,&quot;+$ER.distinguishedName)<br />
&nbsp;&nbsp;$ERguid = $DSobject.rightsGUID<br />
&nbsp;&nbsp;return $ERguid<br />
}<br />
#&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;&#45;-<br />
Get-RightsGUID &quot;Change-PDC&quot;<br />
</code></div>
<p>If you don&#8217;t know the right you&#8217;re looking for you have a couple of options. <a title= "TechNet: Extended Rights Reference" href="http://www.microsoft.com/technet/scriptcenter/topics/security/allrights.mspx">TechNet</a> have a reference that lists them, but we can also look them up.<br />
<a class="quickcode" title="Code" href="javascript:toggleLayer('quickcode673');">RightsTbl.ps1</a></p>
<div id="quickcode673" class="quickcode"><code><br />
$dse&nbsp;&nbsp;= [adsi](&quot;LDAP://Rootdse&quot;)<br />
&nbsp;<br />
# Build a Hashtable to translate the displayName (used by DSACL) to the objects CN.<br />
$ERtbl&nbsp;&nbsp;= @{}<br />
$ext&nbsp;&nbsp;= [adsi](&quot;LDAP://cn=Extended-rights,&quot;+$dse.configurationNamingContext)<br />
$ext.psbase.children |% { $ERtbl.Add($_.displayName.toString(), $_.cn.toString()) }<br />
</code></div>
<p>The function above enumerates through the Extended-Rights container and loads the values for the <em>displayName</em> and <em>cn</em> into an associative array (hash table). Now we can look them up by either typing</p>
<div class="quickcodenoclick"><code><br />
$ERtbl<br />
</code></div>
<p>Which will list our complete hash table, or we can lookup specific translations</p>
<div class="quickcodenoclick"><code><br />
$ERtbl[&quot;Change PDC&quot;]<br />
</code></div>
<p>So far so good. So putting it all together then. A code block to add the <em>Change PDC</em> right on the domain:<br />
<a class="quickcode" title="Code" href="javascript:toggleLayer('quickcode676');">ChangeFSMORight.ps1</a></p>
<div id="quickcode676" class="quickcode"><code><br />
$root&nbsp;&nbsp;&nbsp;&nbsp;= [adsi]&quot;&quot;<br />
&nbsp;<br />
$account&nbsp;&nbsp;= New-Object System.Security.Principal.NTAccount(&quot;bella&quot;)<br />
$inherit&nbsp;&nbsp;= [System.DirectoryServices.ActiveDirectorySecurityInheritance]&quot;All&quot;<br />
$rights&nbsp;&nbsp;&nbsp;&nbsp;= &quot;ExtendedRight&quot;<br />
&nbsp;<br />
$changepdc&nbsp;&nbsp;= &quot;bae50096-4752-11d1-9052-00c04fc2d4cf&quot;<br />
$ace&nbsp;&nbsp;&nbsp;&nbsp;= New-Object System.DirectoryServices.ActiveDirectoryAccessRule($account, $rights, &quot;Allow&quot;, $changpdc, $Inherit)<br />
&nbsp;<br />
$root.psbase.get_objectSecurity().AddAccessRule($ace)<br />
$root.psbase.CommitChanges()<br />
</code></div>
<p>Next time we&#8217;ll look at our last post in on the topic of Active Directory permissions when we look at <em>Control Access Rights</em>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.leadfollowmove.com/archives/powershell/extended-rights-in-active-directory/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Inheritance and Propagation in Active Directory permissions</title>
		<link>http://www.leadfollowmove.com/archives/powershell/inheritance-and-propagation-in-active-directory-permissions</link>
		<comments>http://www.leadfollowmove.com/archives/powershell/inheritance-and-propagation-in-active-directory-permissions#comments</comments>
		<pubDate>Thu, 22 Mar 2007 17:58:10 +0000</pubDate>
		<dc:creator>Adam Bell</dc:creator>
				<category><![CDATA[Active Directory]]></category>
		<category><![CDATA[PowerShell]]></category>

		<guid isPermaLink="false">http://www.leadfollowmove.com/archives/powershell/inheritance-and-propagation-in-active-directory-permissions</guid>
		<description><![CDATA[Disclaimer: As mentioned before I&#8217;m not a programmer, so the information in the next few posts may not be 100%. What I will pass on is what I have found in my experience, and any external links to valid sources that may help provide more detail. With this in mind if you find any inaccuracies, [...]]]></description>
			<content:encoded><![CDATA[<p><strong>Disclaimer:</strong><br />
As mentioned before I&#8217;m not a programmer, so the information in the next few posts may not be 100%. What I will pass on is what I have found in my experience, and any external links to valid sources that may help provide more detail. With this in mind if you find any inaccuracies, or just have more information to add please feel free to let me know  &#8230;. :)</p>
<p>There are three types of permissions in regards to Active Directory security: <em>Standard Rights</em>, <em>Extended Rights</em>, and <em>Control Access Rights</em>.  We&#8217;ve covered <em>Standard Rights </em>in a recent post, and in building up to the remaining two we&#8217;ll take a look at <em>Inheritance</em> and <em>Propagation</em>.</p>
<p>Now if we&#8217;re dealing with NTFs permissions, we use the System.Security.AccessControl <a Title="MSDN: System.Security.AccessControl Namespace " href="http://msdn2.microsoft.com/en-us/library/system.security.accesscontrol.aspx">namespace</a> and the <a Title="MSDN: InheritanceFlags Enumeration" href="http://msdn2.microsoft.com/en-us/library/system.security.accesscontrol.inheritanceflags.aspx">Inheritance</a> and <a title="MSDN: PropagationFlags Enumeration" href="http://msdn2.microsoft.com/en-us/library/system.security.accesscontrol.propagationflags.aspx">Propagation</a> flags. </p>
<p>In AD we use a different method, but the concept is the same. There is only one flag used, and this is <a title="MSDN: ActiveDirectorySecurityInheritance Enumeration " href="http://msdn2.microsoft.com/en-us/library/system.directoryservices.activedirectorysecurityinheritance.aspx">ActiveDirectorySecurityInheritance</a>.</p>
<p>For example in NTFS you may have used:</p>
<div class="quickcodenoclick"><code><br />
$inherit = [system.security.accesscontrol.InheritanceFlags]&quot;ContainerInherit&quot;<br />
$propagation = [system.security.accesscontrol.PropagationFlags]&quot;InheritOnly&quot;<br />
</code></div>
<p>In Active Directory the same result would be achieved by:</p>
<div class="quickcodenoclick"><code><br />
$inherit = [System.DirectoryServices.ActiveDirectorySecurityInheritance]&quot;descendents&quot;<br />
</code></div>
<p>An article that explains this subject well can be found on MSDN <a title="MSDN: Manage Access to Windows Objects with ACLs and the .NET Framework" href="http://msdn.microsoft.com/msdnmag/issues/04/11/AccessControlinNET/">here</a>. In particular the paragraph on inheritance and <strong>figure 5</strong>.</p>
<p>If we want to stop permissions being inherited from the parent <em>Organizational Unit</em> or <em>container</em>, you can use the <em>SetAccessRuleprotection</em> method. The syntax for which is available <a title="MSDN: ObjectSecurity.SetAccessRuleProtection Method " href="http://msdn2.microsoft.com/en-us/library/system.security.accesscontrol.objectsecurity.setaccessruleprotection(VS.80).aspx">here</a><br />
And a simple example:<br />
<a class="quickcode" title="Code" href="javascript:toggleLayer('quickcode653');">BlockInheritance.ps1</a></p>
<div id="quickcode653" class="quickcode"><code><br />
$root = [adsi]&quot;&quot;<br />
$test = [adsi](&quot;LDAP://ou=Test ou,&quot;+$root.distinguishedName)<br />
&nbsp;<br />
# [bool]IsProtected, [bool]PreserveInheritance<br />
# The second option decides whether the inherited ACE&#039;s are copied, or dropped.<br />
$test.psbase.get_objectsecurity().SetAccessRuleProtection($true, $false)<br />
&nbsp;<br />
$test.psbase.CommitChanges()<br />
</code></div>
<p>In the next post we&#8217;ll build a couple of useful functions for retrieving data needed for <em>Extended</em> and <em>Access Control</em> Rights.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.leadfollowmove.com/archives/powershell/inheritance-and-propagation-in-active-directory-permissions/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Removing ACE&#8217;s from Active Directory with PowerShell</title>
		<link>http://www.leadfollowmove.com/archives/powershell/removing-aces-from-active-directory-with-powershell</link>
		<comments>http://www.leadfollowmove.com/archives/powershell/removing-aces-from-active-directory-with-powershell#comments</comments>
		<pubDate>Tue, 20 Mar 2007 22:14:24 +0000</pubDate>
		<dc:creator>Adam Bell</dc:creator>
				<category><![CDATA[Active Directory]]></category>
		<category><![CDATA[PowerShell]]></category>

		<guid isPermaLink="false">http://www.leadfollowmove.com/archives/powershell/removing-aces-from-active-directory-with-powershell</guid>
		<description><![CDATA[Soon we&#8217;ll be looking into some pretty low level permission schemes that can be applied to Active Directory. For now however, following on from yesterdays post, we&#8217;ll take a look at how to remove Acccess Control Entries from the Security Descriptor in AD. Below is our function: remove-DSace.ps1 $root = [adsi]&#34;&#34; &#160; #&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;&#45;- function remove-DSace [...]]]></description>
			<content:encoded><![CDATA[<p>Soon we&#8217;ll be looking into some pretty low level permission schemes that can be applied to Active Directory. For now however, following on from yesterdays post, we&#8217;ll take a look at how to remove Acccess Control Entries from the <a title="Access control in Active Directory" href="http://technet2.microsoft.com/WindowsServer/en/library/2f98f5b2-5e7e-4ff3-83a9-c32cf23329211033.mspx?mfr=true">Security Descriptor</a> in AD.</p>
<p>Below is our function:<br />
<a class="quickcode" title="Code" href="javascript:toggleLayer('quickcode641');">remove-DSace.ps1</a></p>
<div id="quickcode641" class="quickcode"><code><br />
$root = [adsi]&quot;&quot;<br />
&nbsp;<br />
#&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;&#45;-<br />
function remove-DSace<br />
#&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;&#45;-<br />
{<br />
Param (<br />
&nbsp;&nbsp;$DSobject,<br />
&nbsp;&nbsp;$DSidentity<br />
&nbsp;&nbsp;)<br />
&nbsp;&nbsp;$sd = $DSobject.psbase.get_objectSecurity().getAccessRules($true, $false, [System.Security.Principal.NTAccount])<br />
&nbsp;&nbsp;$rar = $sd |? {$_.IdentityReference -eq $DSidentity}<br />
&nbsp;&nbsp;if ($rar -is [array])<br />
&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;foreach ($ace in $rar)<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$DSobject.psbase.get_ObjectSecurity().RemoveAccessRule($ace)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$DSobject.psbase.commitchanges()<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;}<br />
&nbsp;&nbsp;else<br />
&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;$DSobject.psbase.get_ObjectSecurity().RemoveAccessRule($rar)<br />
&nbsp;&nbsp;&nbsp;&nbsp;$DSobject.psbase.commitchanges()<br />
&nbsp;&nbsp;}<br />
}<br />
#&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;&#45;-<br />
$ou = [adsi](&quot;LDAP://ou=&quot;+$ARGS[0]+&quot;,&quot;+$root.distinguishedName)<br />
remove-DSace $ou $ARGS[1]<br />
</code></div>
<p>Points of interest then:<br />
Details on the parameters for <em>GetAccessRules</em> are <a title="MSDN: CommonObjectSecurity.GetAccessRules Method " href="http://msdn2.microsoft.com/en-us/library/system.security.accesscontrol.commonobjectsecurity.getaccessrules.aspx">here.</a> We then filter our rules to those that match our Group/Account as defined by the <em>IdentityReference</em> attribute on the object, and store these in the $rar variable. By testing if this variable is an array or not we can determine if we have one ACE or several that need removing.</p>
<p>Using an <em>If..Else</em> code block we remove the ACE or ACEs as applicable and commit our changes back to the directory. If the ACE was configured to propagate down the directory this will have the effect of completely removing that permission from everywhere.</p>
<p>Tomorrow we really will look into <em>Propagation</em> and <em>Inheritence</em> ;)</p>
]]></content:encoded>
			<wfw:commentRss>http://www.leadfollowmove.com/archives/powershell/removing-aces-from-active-directory-with-powershell/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Active Directory Permissions &#8211; Standard Rights</title>
		<link>http://www.leadfollowmove.com/archives/powershell/active-directory-permissions-standard-rights</link>
		<comments>http://www.leadfollowmove.com/archives/powershell/active-directory-permissions-standard-rights#comments</comments>
		<pubDate>Mon, 19 Mar 2007 20:46:21 +0000</pubDate>
		<dc:creator>Adam Bell</dc:creator>
				<category><![CDATA[Active Directory]]></category>
		<category><![CDATA[PowerShell]]></category>

		<guid isPermaLink="false">http://www.leadfollowmove.com/archives/powershell/active-directory-permissions-standard-rights</guid>
		<description><![CDATA[We&#8217;ve previously covered manipulating NTFS permissions, and in this post we&#8217;ll take that basis and apply it to Active Directory. Marc covered this topic on his old blog, while PowerShell was still in beta (Pre RC2). The approach is basically the same, but you need to utilise psbase in PowerShell 1.0. So, we want to [...]]]></description>
			<content:encoded><![CDATA[<p>We&#8217;ve previously covered manipulating NTFS permissions, and in this post we&#8217;ll take that basis and apply it to Active Directory.</p>
<p><a href="http://thepowershellguy.com/blogs/posh/default.aspx">Marc</a> covered this topic on his old blog, while PowerShell was still in beta (Pre RC2). The approach is basically the same, but you need to utilise <em>psbase</em> in PowerShell 1.0.</p>
<p>So, we want to give our test user <em>bella</em> full control over the <em>Test OU</em>. I would suggest not making permission changes to your AD if you don&#8217;t know what you&#8217;re doing because things can get nasty very quickly. A bit of useful reading on the subject can be found <a title="TechNet: Best practices for assigning permissions on Active Directory objects" href="http://technet2.microsoft.com/WindowsServer/en/library/373a4e2b-89a6-4ccc-9e20-be07c741f47b1033.mspx?mfr=true">here</a> and <a title="MSDN: New Ways to Manage Active Directory using the .NET Framework 2.0" href="http://msdn.microsoft.com/msdnmag/issues/05/12/DirectoryServices/">here.</a></p>
<p>Below is our basic function:<br />
<a class="quickcode" title="Code" href="javascript:toggleLayer('quickcode631');">function add-DSace.ps1</a></p>
<div id="quickcode631" class="quickcode"><code><br />
#&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;&#45;-<br />
function Add-DSace<br />
#&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;&#45;-<br />
{<br />
Param (<br />
&nbsp;&nbsp;$DSobject,<br />
&nbsp;&nbsp;$Identifier,<br />
&nbsp;&nbsp;$DSrights,<br />
&nbsp;&nbsp;$AccessType = &quot;Allow&quot;<br />
&nbsp;&nbsp;)<br />
&nbsp;&nbsp;# GetAccessRules: Explicit ACE&#039;s, Inherited ACE&#039;s, TargetType<br />
&nbsp;&nbsp;$account = New-Object system.security.principal.ntaccount($Identifier)<br />
&nbsp;<br />
&nbsp;&nbsp;# Retrieve the SID - as a manual step you can check it&#039;s not empty :)<br />
&nbsp;&nbsp;$sid = $acc.translate([system.security.principal.securityidentifier])<br />
&nbsp;&nbsp;#$sid.ToString()<br />
&nbsp;<br />
&nbsp;&nbsp;$ace = New-Object System.DirectoryServices.ActiveDirectoryAccessRule($account, $DSrights, $AccessType)<br />
&nbsp;&nbsp;$DSobject.psbase.get_objectsecurity().AddAccessRule($ace)<br />
&nbsp;&nbsp;$DSobject.psbase.CommitChanges()<br />
}<br />
#&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;-&#45;&#45;&#45;-<br />
$root = [adsi]&quot;&quot;<br />
$test = [adsi](&quot;LDAP://ou=Test OU,&quot;+$root.distinguishedName)<br />
&nbsp;<br />
Add-DSace $Test &quot;bella&quot; &quot;GenericAll&quot;<br />
</code></div>
<p>Okay, so points of interest then:</p>
<p>Once we&#8217;ve created a variable for the OU we want to add an ACE to, we then define our Security Principal. This can be either a user or a group, and we can present this in either SID format or as the account name. </p>
<p>In this example we&#8217;re targeting a user. We could have validated the account by retrieving it&#8217;s SID, but for this we&#8217;re presuming that everything exists and no checking is performed.</p>
<p>There are several constructors available for the <em>ActiveDirectoryAccessRule</em>. You can see what&#8217;s available, by looking at the <em>constructors</em>:</p>
<div class="quickcodenoclick"><code><br />
# List the constuctors available to this method:<br />
[System.DirectoryServices.ActiveDirectoryAccessRule].GetConstructors() |% {&quot;$_&quot;}<br />
</code></div>
<p>I&#8217;ve found this to be a really useful way of discovering the specific requirements for a method. Once you know what types the method is expecting you can then investigate what each element is. In this instance we are utilising the following constructor:</p>
<div class="quickcodenoclick"><code><br />
Void .ctor(<br />
&nbsp;&nbsp;System.Security.Principal.IdentityReference, <br />
&nbsp;&nbsp;System.DirectoryServices.ActiveDirectoryRights, <br />
&nbsp;&nbsp;System.Security.AccessControl.AccessControlType)<br />
</code></div>
<p>You can then either look them up on <a title="Microsoft MSDN Home Page" href="http://http://msdn2.microsoft.com/en-gb/default.aspx">MSDN</a> or feed in some false data, and see if the constructor will provide you with details on what it needs.</p>
<p>Once we have the <em>ACE</em>, the last two lines are where we add the <em>ACE</em> to the <em>Security Descriptor</em> and then commit our changes back to the directory. </p>
<p>As you can see we need to use <em>psbase</em>. This gives us the &#8220;raw&#8221; view of the object. I find using <em>psbase</em> very difficult. It&#8217;s almost a fall back, for when you can&#8217;t seem to make it work any other way. At the moment I just put it down as one of PowerShell&#8217;s little quirks ;)</p>
<p>Over the next few days we&#8217;ll take a closer look at <em> Propagation, Inheritance</em> and Active Directory <em>Extended Rights</em>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.leadfollowmove.com/archives/powershell/active-directory-permissions-standard-rights/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Two day seminar on Active Directory &#8211; 14th &amp; 15th March 2007 (London)</title>
		<link>http://www.leadfollowmove.com/archives/active-directory/two-day-seminar-on-active-directory-14th-15th-march-2007-london</link>
		<comments>http://www.leadfollowmove.com/archives/active-directory/two-day-seminar-on-active-directory-14th-15th-march-2007-london#comments</comments>
		<pubDate>Tue, 06 Mar 2007 11:58:56 +0000</pubDate>
		<dc:creator>Adam Bell</dc:creator>
				<category><![CDATA[Active Directory]]></category>
		<category><![CDATA[Seminars]]></category>

		<guid isPermaLink="false">http://www.leadfollowmove.com/?p=56</guid>
		<description><![CDATA[A couple of years ago I attended a 5 day seminar on Active Directory at the NEC in Birmingham. It was a TechNet sponsored event presented by John Craddock and Sally Storey. Now John is regarded as one of the top AD guys in the UK, and with good reason. Next week John and Sally [...]]]></description>
			<content:encoded><![CDATA[<p>A couple of years ago I attended a 5 day seminar on Active Directory at the NEC in Birmingham. It was a TechNet sponsored event presented by John Craddock and Sally Storey. Now John is regarded as one of the top AD guys in the UK, and with good reason.</p>
<p>Next week John and Sally have a two day seminar on in London. <a title="A Two Day Seminar presented by John Craddock, in association with Microsoft TechNet" href="http://www.microsoft.co.uk/Events/registermulti.aspx?event=JohnCraddockLondon">Here</a> is the link on the UK TechNet Events website. I know it&#8217;s a little late, and there may not be any places left, but I can tell you without doubt it will be a great two days.</p>
<p>A few years ago I was working on an AD project for a large environment and at the time I was struggling to achieve some of the automation mile stones. After several weeks of scouring the web and news groups I completed all my tasks. Just after this I got a copy of <a title="Amazon UK:Active Directory Forestry, Investigating and Managing Objects and Attributes for Windows 2000 and Windows Server 2003 (Paperback)" href="http://www.amazon.co.uk/Directory-Forestry-Investigating-Managing-Attributes/dp/0954421809/ref=sr_1_1/203-8628635-0858359?ie=UTF8&#038;s=books&#038;qid=1173181874&#038;sr=8-1">John and Sally&#8217;s book</a>. The pound to page ratio on this is quite high, but what I found within was all the obscure answers for the problems I&#8217;d spent weeks searching for.</p>
<p>Now before you ask, I&#8217;m not affiliated with these guys in any way, and am not being paid for this. These guys are just good, and well worth a look if AD is in any way your thing ;)</p>
]]></content:encoded>
			<wfw:commentRss>http://www.leadfollowmove.com/archives/active-directory/two-day-seminar-on-active-directory-14th-15th-march-2007-london/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Searching Active Directory for Windows 2000 and Windows NT4 Domain Controllers with PowerShell</title>
		<link>http://www.leadfollowmove.com/archives/powershell/searching-active-directory-for-windows-2000-and-windows-nt4-domain-controllers-with-powershell</link>
		<comments>http://www.leadfollowmove.com/archives/powershell/searching-active-directory-for-windows-2000-and-windows-nt4-domain-controllers-with-powershell#comments</comments>
		<pubDate>Tue, 20 Feb 2007 13:45:46 +0000</pubDate>
		<dc:creator>Adam Bell</dc:creator>
				<category><![CDATA[Active Directory]]></category>
		<category><![CDATA[PowerShell]]></category>

		<guid isPermaLink="false">http://www.leadfollowmove.com/?p=51</guid>
		<description><![CDATA[When I posted the article on raising AD functionality levels recently David Saxon pointed out that more could be done in regards to confirming the Domain Controllers are at the required level, i.e. they are Windows 2003 Domain Controllers. Since we&#8217;ve looked at searching the Directory yesterday, this seems like a good time to take [...]]]></description>
			<content:encoded><![CDATA[<p>When I posted the article on <a href="http://www.leadfollowmove.com/?p=39" target="_blank" title ="Raising Active Directory Domain and Forest functionality to Windows 2003 with PowerShell">raising AD functionality levels</a> recently David Saxon pointed out that more could be done in regards to confirming the Domain Controllers are at the required level, i.e. they are Windows 2003 Domain Controllers.</p>
<p>Since we&#8217;ve looked at searching the Directory yesterday, this seems like a good time to take a closer look into this.<br />
Microsoft have a good article <a href="http://technet2.microsoft.com/WindowsServer/en/library/b3674c9b-fab9-4c1e-a8f6-7871264712711033.mspx?mfr=true" target="_blank" title ="Domain and forest functionality">here</a> on what features are available depending on you functionality level.</p>
<p>So we&#8217;d start with:</p>
<div class="quickcodenoclick"><code><br />
$query = new-object system.directoryservices.directorysearcher<br />
$root = [adsi]&quot;&quot;<br />
</code></div>
<p>And presuming our DC&#8217;s are located in the default location, we can narrow our search down:</p>
<div class="quickcodenoclick"><code><br />
$ou = [adsi](&quot;LDAP://ou=Domain Controllers,&quot;+$root.distinguishedName)<br />
$query.SearchRoot = $ou<br />
$query.SearchScope = &quot;OneLevel&quot;<br />
</code></div>
<p>The key to our search is going to be the <em>filter()</em> that we use. If you look around there&#8217;s a few different ways of identifying what we might want to search on.</p>
<p>In KB article <a href="http://support.microsoft.com/kb/322692" target="_blank" title ="How to raise domain and forest functional levels in Windows Server 2003">322692</a> there is a good filter for finding NT4 Domain Controllers:</p>
<div class="quickcodenoclick"><code><br />
$query.filter = &quot;(&amp;(objectCategory=computer)(operatingSystem Version=4*)(userAccountControl:1.2.840.113556.1.4.803:=8192))&quot;<br />
</code></div>
<p>Here we&#8217;re filtering on the computer object, the OS version, and the UAC value. Let&#8217;s break this down a bit more. The first one is pretty obvious, the OS version is easy enough too. Anything with a 4 in the version relates to NT4. Windows 2000 is 5.0, and Windows 2003 is 5.2. So what&#8217;s with the UAC filter? The <a href="http://support.microsoft.com/kb/269181" target="_blank" title ="How to query Active Directory by using a bitwise filter">bitwise filter</a> is an Object ID (OID) that means all the flags have to be set for a match. The value of <a href="http://support.microsoft.com/kb/305144" target="_blank" title ="How to use the UserAccountControl flags to manipulate user account properties">8192</a> specifies that the account is a Domain Controller.</p>
<p>We can search for Windows 2000 Domain Controllers using the following filter, as described in KB article <a href="http://support.microsoft.com/kb/325379" target="_blank" title ="How to upgrade Windows 2000 domain controllers to Windows Server 2003">325379</a></p>
<div class="quickcodenoclick"><code><br />
$query.filter = &quot;(&amp;(objectCategory=computer)(primaryGroupID=516)(operatingSystemVersion=5.0*))&quot;<br />
</code></div>
<p>Similar to the above example, we&#8217;re filtering on the computer object again. This time rather than use the UAC approach though we&#8217;ve used the <em>PrimaryGroupID</em> which we&#8217;ve touched on previously. The OS version corresponds to the versions discussed above.</p>
<p>It seems to me that our best approach would be to filter on any computer account, that&#8217;s <strong>not</strong> Windows 2003. As we&#8217;re only searching in the Domain Controllers OU we shouldn&#8217;t need to try and check the UAC or Primary Group information, but you could just to be sure if you felt that way inclined.</p>
<div class="quickcodenoclick"><code><br />
$query.filter = &quot;(&amp;(objectCategory=computer)(!operatingSystem Version=5.2*)(userAccountControl:1.2.840.113556.1.4.803:=8192))&quot;<br />
</code></div>
<p>There&#8217;s a subtle difference between this filter and the first example. Basically we&#8217;re looking for OS version that&#8217;s <strong>not</strong> (!) equal to Windows 2003. In theory this should give us all the other Domain Controllers ;)</p>
<p>So to finish off then:</p>
<div class="quickcodenoclick"><code><br />
$result = $query.FindAll()<br />
if ($result -eq $null)<br />
{ <br />
&nbsp;&nbsp;return $null<br />
}<br />
else<br />
{<br />
&nbsp;&nbsp;foreach ($machine in $result)<br />
&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;$ADobject = $machine.GetDirectoryEntry()<br />
&nbsp;&nbsp;&nbsp;&nbsp;write-host $ADobject.distinguishedName<br />
&nbsp;&nbsp;}<br />
}<br />
</code></div>
<p>Of course just because we have accounts in AD doesn&#8217;t actually mean that there are machines still out there. You could tie this into a function that then calls a ping test against the names that are retrieved. That&#8217;s still not gospel, but if it&#8217;s a DC, it&#8217;s more likely to be up if it&#8217;s still out there!</p>
<p>If you&#8217;re new to LDAP queries and would like more information Microsoft have a good primer <a href="http://www.microsoft.com/technet/prodtechnol/exchange/2003/insider/ldapquery.mspx" target="_blank" title ="LDAP Query Basics">here</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.leadfollowmove.com/archives/powershell/searching-active-directory-for-windows-2000-and-windows-nt4-domain-controllers-with-powershell/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
