
<?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/category/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>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>Code Samples</title>
		<link>http://www.leadfollowmove.com/archives/powershell/code-samples-page-and-get-psuguk</link>
		<comments>http://www.leadfollowmove.com/archives/powershell/code-samples-page-and-get-psuguk#comments</comments>
		<pubDate>Mon, 12 Mar 2007 14:13:27 +0000</pubDate>
		<dc:creator>Adam Bell</dc:creator>
				<category><![CDATA[Active Directory]]></category>
		<category><![CDATA[PowerShell]]></category>
		<category><![CDATA[Code Samples]]></category>

		<guid isPermaLink="false">http://www.leadfollowmove.com/archives/powershell/code-samples-page-and-get-psuguk</guid>
		<description><![CDATA[When I first started posting examples of administering Active Directory with PowerShell Richard requested if I would put my examples on the UK PowerShell Users Group site. I&#8217;m in the process of sorting them out, and will be posting them up there in the next 24 hours or so. For those that aren&#8217;t a member, [...]]]></description>
			<content:encoded><![CDATA[<p>When I first started posting examples of administering Active Directory with PowerShell <a title="Of PowerShell and Other Things" href="http://richardsiddaway.spaces.live.com/">Richard</a> requested if I would put my examples on the <a title="Home of the UK PowerShell Users Group" href="http://www.culminisconnections.com/sites/get-psuguk/default.aspx">UK PowerShell Users Group site</a>.</p>
<p>I&#8217;m in the process of sorting them out, and will be posting them up there in the next 24 hours or so. For those that aren&#8217;t a member, I&#8217;ve created a <strong>Code Sample</strong> page in the sidebar where I&#8217;ll post them also.</p>
<p>They come with the usual all care, no responsibility tag line. I hope you find them of some use!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.leadfollowmove.com/archives/powershell/code-samples-page-and-get-psuguk/feed</wfw:commentRss>
		<slash:comments>0</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>
		<item>
		<title>Searching Active Directory with PowerShell</title>
		<link>http://www.leadfollowmove.com/archives/powershell/searching-active-directory-with-powershell</link>
		<comments>http://www.leadfollowmove.com/archives/powershell/searching-active-directory-with-powershell#comments</comments>
		<pubDate>Mon, 19 Feb 2007 12:45:41 +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=49</guid>
		<description><![CDATA[Being quite the lazy admin that I am, whenever I&#8217;m scripting for AD I like to use short names when referring to objects. As an example, if I want to add the user BellA into the Domain Admins group I don&#8217;t want to provide the distinguishedName for both objects . The easy solution to this [...]]]></description>
			<content:encoded><![CDATA[<p>Being quite the lazy admin that I am, whenever I&#8217;m scripting for AD I like to use short names when referring to objects. As an example, if I want to add the user <em>BellA</em> into the <em>Domain Admins</em> group I don&#8217;t want to provide the <em>distinguishedName</em> for both objects .</p>
<p>The easy solution to this is to have enough information to hand, to allow a quick rummage through the Directory, and let the script<br />
retrieve the details it needs. In fact being able to extract information from an AD search is pretty much the corner stone of any AD scripting tool box, as you&#8217;ll see over the next couple of posts.</p>
<p>I&#8217;ll show you a couple of ways of searching and then mention a few points to be aware of regarding performance, and your impact on the servers whose workload you&#8217;re adding to.</p>
<div class="quickcodenoclick"><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;-<br />
function Find-DN<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;-<br />
{<br />
Param (<br />
&nbsp;&nbsp;$sADobjectName,<br />
&nbsp;&nbsp;$sADobjectType<br />
&nbsp;&nbsp;)<br />
&nbsp;&nbsp;$query = new-object system.directoryservices.directorysearcher<br />
&nbsp;&nbsp;$root = [adsi]&quot;&quot;<br />
&nbsp;<br />
&nbsp;&nbsp;$query.SearchRoot = $root<br />
&nbsp;&nbsp;$query.filter = &quot;(&amp;(ObjectClass=$sADobjectType)(cn=$sADobjectName))&quot;<br />
&nbsp;&nbsp;$query.SearchScope = &quot;subtree&quot;<br />
&nbsp;&nbsp;$result = $query.findOne()<br />
&nbsp;&nbsp;<br />
&nbsp;&nbsp;if ($result -eq $null)<br />
&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;return $null<br />
&nbsp;&nbsp;}<br />
&nbsp;&nbsp;else<br />
&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;$ADobject = $result.GetDirectoryEntry()<br />
&nbsp;&nbsp;&nbsp;&nbsp;return $ADobject.distinguishedName<br />
&nbsp;&nbsp;}<br />
}<br />
</code></div>
<p>There isn&#8217;t a lot of specific PowerShell code in the function above. Its pretty LDAP orientated. We have a simple function that returns you the <em>distinguishedName</em> of an object when you provide the <em>objectClass</em> and <em>cn</em>.<br />
So to find the <em>DN</em> of my test user account:</p>
<div class="quickcodenoclick"><code><br />
Find-DN &quot;BellA&quot; &quot;user&quot;<br />
</code></div>
<p>The <em>$result</em> variable is a <em>System.DirectoryServices.SearchResult</em> which we cast into <em>System.DirectoryServices.DirectoryEntry</em> with the <em>GetDirectoryEntry()</em> <a title="SearchResult.GetDirectoryEntry Method" href="http://msdn2.microsoft.com/en-us/library/system.directoryservices.searchresult.getdirectoryentry.aspx" target="_blank">method</a>. I like this as it gives us a much nicer way of retrieving the objects properties.</p>
<p>The other method of searching AD I have seen, is similar, but with a PS slant to it:</p>
<div class="quickcodenoclick"><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;-<br />
function Find-DN2<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;-<br />
{<br />
Param (<br />
&nbsp;&nbsp;$sADobjectName,<br />
&nbsp;&nbsp;$sADobjectType<br />
&nbsp;&nbsp;)<br />
&nbsp;&nbsp;$query = new-object system.directoryservices.directorysearcher<br />
&nbsp;&nbsp;$root = [adsi]&quot;&quot;<br />
&nbsp;&nbsp;<br />
&nbsp;&nbsp;$query.SearchRoot = $root<br />
&nbsp;&nbsp;$query.SearchScope = &quot;subtree&quot;<br />
&nbsp;<br />
&nbsp;&nbsp;$ADobject = $query.findAll() | where-object {$_.properties.objectclass -eq $sADobjectType `<br />
&nbsp;&nbsp;&nbsp;&nbsp;-and $_.properties.cn -eq $sADobjectName}<br />
&nbsp;&nbsp;$props = $ADobject.Properties<br />
&nbsp;&nbsp;<br />
&nbsp;&nbsp;if ($ADobject -eq $null)<br />
&nbsp;&nbsp;{ <br />
&nbsp;&nbsp;&nbsp;&nbsp;return $null<br />
&nbsp;&nbsp;}<br />
&nbsp;&nbsp;else<br />
&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;foreach ($prop in $props)<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return $prop.distinguishedname<br />
&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;<br />
&nbsp;&nbsp;}<br />
}<br />
</code></div>
<p>Straight away you can see some PowerShell in the function above. Rather then use the <em>$query.filter</em>, we pipe the results into a <em>where-object</em> and then filter for our search criteria. We also handle the properties returned differently.</p>
<p>This function would be called exactly the same as our previous example:</p>
<div class="quickcodenoclick"><code><br />
Find-DN2 &quot;BellA&quot; &quot;user&quot;<br />
</code></div>
<p>Now I&#8217;ve had problems with this function. I&#8217;ve found it worked fine for &#8220;some&#8221; objects, but I have had trouble retrieving others. Despite the <em>SearchScope</em> being set to &#8220;SubTree&#8221; I&#8217;ve had it fail to retrieve objects that are a few OU&#8217;s deep. I suspect this is a flaw with my function as apposed to anything flawed in PS ;)<br />
<br />
<strong>Search Tips</strong><br />
So now we&#8217;ve seen the basics, I thought it worth mentioning a couple of ways to improve on performance, and speed:</p>
<p><strong>[1] Scope:</strong> If you can, narrow your <em>SearchScope</em>. There&#8217;s three options: <em>&#8220;Base&#8221;</em>, <em>&#8220;OneLevel&#8221;</em>, and <em>&#8220;SubTree&#8221;</em>. If you&#8217;re not sure, there&#8217;s a good explanation on MSDN <a href="http://msdn2.microsoft.com/en-us/library/system.directoryservices.searchscope.aspx" target="_blank" title ="SearchScope Enumeration">here</a>.</p>
<p><strong>[2] Filter:</strong> Always try and provide a filter to reduce how much data you&#8217;re trying to retrieve. There&#8217;s obviously not much point retrieving every user account in your domain <strong>and</strong> enumerating through them all just for the one you want. Think about the <em>Filter()</em> method, and use the relevant <em>FindOne()</em> <em>FindAll()</em> methods.</p>
<p>I&#8217;m not sure how our second examples works with this. My hunch is that it retrieves <strong>ALL</strong> the objects and trawls through each with the <em>where-object</em>. I could be wrong here of course ;)</p>
<p><strong>[3] Properties:</strong> If you&#8217;re only after say, the <em>distinguishedName</em> it would be a good idea to reduce the properties returned by using the <em>PropertiesToLoad</em> method.</p>
<p><a href="http://www.microsoft.com/technet/scriptcenter/default.mspx" target="_blank" title ="Microsoft Script Center on TechNet">The Microsoft Scripting Guy&#8217;s</a>, have an example <a href="http://www.microsoft.com/technet/scriptcenter/resources/qanda/nov06/hey1109.mspx" target="_blank" title ="How Can I Use Windows PowerShell to Get a List of All My Computers?">here</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.leadfollowmove.com/archives/powershell/searching-active-directory-with-powershell/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>
