Benp’s Basic Guide to Managing Active Directory Objects with PowerShell
Guys + Gals
So here is my first post! How exciting!
The last few weeks I have been writing a private 1 day workshop entitled “Introduction to PowerShell”. This is a classroom based workshop run in the UK. As part of the workshop I decided to put in a section on how to interact with the Active Directory, and soon found it to be a bit harder than I thought. Not that working with the AD is hard; it’s just there isn’t too much documentation. I spent a day or two trawling though various blogs, but soon got pretty frustrated. So I thought I’d put together “Benp’s Basic Guide to Managing Active Directory Objects with PowerShell”. Catchy title huh .....
Agenda
People might be wondering if they can need to read this blog. Well here is a quick overview of what I will talk about:
· Active Directory manipulation in PowerShell is really powerful.
· [ADSI] is a wrapper on the DirectoryEntry class and provides its own methods.
· Full support of System.DirectoryServices.DirectoryEntry is provided. Just remember psbase is the key.
· You can interchange using [ADSI] and raw DirectoryEntry commands
PowerShell Basics
Before we start, this Blog assumes a bit of prior knowledge of PowerShell. I`m going to assume PowerShell is installed correctly, and that you have a basic understanding of Cmdlets and their use. To get up to speed with PowerShell check out the PowerShell homepage:
https://www.microsoft.com/windowsserver2003/technologies/management/powershell/default.mspx
In particular, I watched the PowerShell Week Webcasts, and found them excellent. Find them here:
https://www.microsoft.com/technet/scriptcenter/webcasts/ps.mspx
There are 5, 1 hour Webcasts that take you from absolute beginner, to PowerShell guru. Most Excellent!
Right, enough chatter – let’s get down to business!
[ADSI] and System.DirectoryServices.DirectoryEntry Overview
Firstly, there are two main ways to interact with the AD using PowerShell, and both are closely linked. Let’s get an overview and see how they relate to each other.
The basic building block is the .Net Framework Object “System.DirectoryServices.DirectoryEntry” . This is a well documented class that anyone using C# or managed code might have come across before. This object is pretty raw, and you’re allowed to feel like a hardcore dev guy when you’re using it. This class isn’t quite as easy to use as you might hope. More on that later! However, you can always use this class and its methods and properties, but in PowerShell they’re hidden from you.
Let me introduce the other player [ADSI]. [ADSI] is essentially a wrapper that we have put around the DirectoryEntry object. The question has to be asked “Why the heck have you done that?!?” The answer is as follows: this wrapper feels a bit more like the VBScript ADSI provider. You can use the same sort of syntax in PowerShell that you might use in VBScript. So, if you’re coming from a C# background the raw DirectoryEntry object will feel nicer, if you’re coming from VBScript, [ADSI] will feel nicer.
So let’s look at both methods in a bit more detail:
[ADSI]
PowerShell provides a really nice way of learning about objects. By using Get-Member you can view exactly what properties and methods are exposed for an object. Sadly, this doesn’t work with an [ADSI] object in PowerShell. Doh! The code below creates a variable $Dom that is bound to the root of your AD. Try for yourself: (For more info see the “Binding to Objects” section below)
$Dom = [ADSI]'’ $Dom| Get-Member
|
See, there’s a list of properties but no methods! Why!!!???!!
Good question, and one with a deeply technical answer. Check out this post from Arul Kumaravel, PowerShell Development Manger for a bit more info:
https://pathologicalscripter.wordpress.com/2006/09/28/invisible-methods-for-adsi/
So I guess it might be handy to list some of the key invisible methods for ADSI:
Create()
Get()
Put()
Delete()
SetInfo()
The above is not a definitive list, but certainly covers lots of things that you might want to do with the Active Directory.
System.DirectoryServices.DirectoryEntry
The other way to manipulate the AD is the DirectoryEntry class. As this is an existing .Net Framework class, there is a lot more documentation. In fact all properties and methods are documented here:
However, we saw above in the [ADSI] sections that there are no methods. Here a quick reminder:
$Dom | Get-Member |
Zero methods are returned.
Due to the wrapping of the DirectoryEntry object we need to get back to the base class properties and methods. To do this we use psbase. When we use the psbase keyword we are effectively peeling back all wrappers on the object, and getting back to the raw base object. Try this:
$Dom.psbase | Get-Member
|
Sweet! Loads of members, and looks pretty darn similar to the MSDN documentation. So now you can just add .psbase to access all DirectoryEntry methods and properties:
$Dom.psbase.get_children()
|
Code to do stuff
“Enough chatting!” I hear you cry, “Show me some code that I can rampantly plagiarize! I wanna get out of here!”.
Settle down, settle down the information you so desperately want is at hand. I`ll give some code samples, and because we can, let’s use both the [ADSI] syntax, and the DirectoryEntry syntax.
Code in the blue font is using [ADSI]
Code in the red font is using DirectoryEntry
Binding to an object
$MyVar = [ADSI] ‘<Enter Connection String Here>’
or
$MyVar = New-Object system.directoryservices.directoryentry '<Enter Connection String Here>'
$MyDom = [ADSI] ‘’ # connects to root domain |
Or
$MyDom = New-Object system.directoryservices.directoryentry'' |
Now let’s connect to a specific object.
$User = [ADSI] 'LDAP://CN=Ben Pearce,OU=London,DC=umpadom,DC=com' |
Or
$User = New-Object system.directoryservices.directoryentry ‘LDAP://CN=Ben Pearce,OU=London,DC=umpadom,DC=com’ |
Once you have bound to an object you can interchange whether you use [ADSI] commands or DirectoryEntry commands. So the result of either of the commands executing is the same. Therefore I always use the [ADSI] method. Much less typing!
Create a User
$username = ‘benp’ #Bind to OU $adminsOU = [ADSI] 'LDAP://OU=admins,DC=umpadom,DC=com' #Create the user $user = $adminsOU.create('User','CN='+ $username) #Commit Changes $user.setinfo() #Set the SAMAccountName $user.sAMAccountName = $username #Commit Changes $user.setinfo()
|
Or
$username = ‘benp’ #Bind to OU $adminsOU = New-Object System.DirectoryServices.DirectoryEntry("LDAP://OU=admins,DC=umpadom,DC=com") #Create the user $user = $adminsOU.psbase.get_children().add(‘CN=’ + $username,'User') #Commit Changes $user.psbase.CommitChanges() #Set the SAMAccountName $user.psbase.invokeset(‘sAMAccountName’,$username) #Commit Changes $user.psbase.CommitChanges()
|
Both sets of the above code do exactly the same thing. So like Binding to Objects I take the [ADSI] approach every time.
Read a Property
If the parameter is exposed by the ADSI interface it is really easy to read a parameter.
$user = [ADSI] 'LDAP://CN=Ben Pearce,OU=London,DC=umpadom,DC=com' $user.Title
|
However, not all properties of an object are exposed there. The below code can be used to get any property whether exposed in ADSI or not.
$user = [ADSI] 'LDAP://CN=Ben Pearce,OU=London,DC=umpadom,DC=com' $user.get(‘Title’) |
Or
$user = System.DirectoryServices.DirectoryEntry 'LDAP://CN=Ben Pearce,OU=London,DC=umpadom,DC=com' $user.psbase.invokeget(‘Title’) $user.psbase.commitchanges() |
Modify a Property
Again if the properties are exposed, modifying a property is really easy.
$user = [ADSI] 'LDAP://CN=Ben Pearce,OU=London,DC=umpadom,DC=com' $user.Title $user.setinfo()
|
However, not all properties of an object are exposed there. The below code can be used to set any property whether exposed in [ADSI] or not.
$user = [ADSI] 'LDAP://CN=Ben Pearce,OU=London,DC=umpadom,DC=com' $user.put(‘Title’,’IT Pro’) $user.setinfo() |
Or
$user = System.DirectoryServices.DirectoryEntry 'LDAP://CN=Ben Pearce,OU=London,DC=umpadom,DC=com' $user.psbase.invokeset(‘Title’,’IT Pro’) $user.psbase.commitchanges() |
Or
$user = [ADSI] 'LDAP://CN=Ben Pearce,OU=London,DC=umpadom,DC=com' $user.psbase.invokeset(‘Title’,’IT Pro’) $user.psbase.commitchanges() |
See, I`m mixing it up now!
Delete a User
$username = ‘benp’ # Connect to parent OU $adminsOU = [ADSI] 'LDAP://OU=admins,DC=umpadom,DC=com' # Delete user $user = $adminsOU.delete('User','CN='+ $username) |
Or
$username = 'LDAP://CN=benp,OU=Admins,DC=umpadom,DC=com' #Bind to user $user = New-Object System.DirectoryServices.DirectoryEntry $username #Delete User $user.psbase.DeleteTree()
|
Or
$username = 'LDAP://CN=benp,OU=London,DC=umpadom,DC=com' #Bind to user $user = [ADSI] ‘$username’ #Delete User $user.psbase.DeleteTree() |
Conclusion
Well that’s the end of the blog. Here’s a quick summary to consolidate today’s information:
· Active Directory manipulation in PowerShell is really powerful.
· [ADSI] is a wrapper on the DirectoryEntry class and provides its own methods.
· Full support of System.DirectoryServices.DirectoryEntry is provided. Just remember psbase is the key.
· You can interchange using [ADSI] and raw DirectoryEntry commands
Comments are welcome and any feedback much appreciated. I hope you found this useful, if so let me know. If alternatively you think it’s a big steaming pile of tosh, let me know.
That is all
BenP
Comments
Anonymous
January 01, 2003
  Windows PowerShell: Working with Active Directory One thing I will say here. I was teaching aAnonymous
January 01, 2003
Ladies + Gents This week I have had the privilege of working at TechEd 2007. I’ve been on the PowerShellAnonymous
January 01, 2003
PingBack from http://dmitrysotnikov.wordpress.com/2007/03/22/powershell-cmdlets-for-ad/Anonymous
January 01, 2003
BenP does a great job with PowerShell and giving you information on managing Active Directory using PowerShellAnonymous
January 19, 2008
Hi Ben, I just wanted to thank you for such an awesome post. I have been struggling with Powershell scripting in AD in large part due to the missing methods. Your post helped me move forward with specific problems I was having, but also gave me insight how I can do even more extensive AD scripting in Powershell. Thanks again.Anonymous
April 21, 2008
I am wondering how you would read in a file of KB numbers for microsoft patches to determine if they are installed or not, the date they were installed and also read a list of computers to check for these patches. thanksAnonymous
September 11, 2008
<a href= http://index1.koster4.com >vintage kenwood reciver kr 5030 ebay</a> <a href= http://index2.koster4.com >chihuahua viral video</a> <a href= http://index3.koster4.com >nj assoiation of school administrators</a>Anonymous
October 29, 2008
The comment has been removedAnonymous
November 10, 2008
<a href= http://lizard-masterm.angelfire.com >goldsmiths golf</a>Anonymous
November 13, 2008
<a href= http://pantere78.angelfire.com >sunset property management</a> <a href= http://azasello.angelfire.com >james joyce and dafna meltzer</a> <a href= http://veriopla.angelfire.com >torrington conn</a>Anonymous
November 13, 2008
<a href= http://pantere78.angelfire.com >sunset property management</a> <a href= http://azasello.angelfire.com >james joyce and dafna meltzer</a> <a href= http://veriopla.angelfire.com >torrington conn</a>Anonymous
November 28, 2008
<a href= http://aseeds.one.angelfire.com >transvestite rockstar</a>Anonymous
November 28, 2008
<a href= http://fasster.angelfire.com >baltimore and convention center and headquarters</a> <a href= http://gertui.angelfire.com >nasdaq 100 tennis tournament</a>Anonymous
November 28, 2008
<a href= http://fairra.angelfire.com >landls end</a> <a href= http://vonucshka.angelfire.com >chancellor internal med</a>Anonymous
November 28, 2008
<a href= http://chkola.angelfire.com >avlastkey</a> <a href= http://bustersw.angelfire.com >how to start a strawberry patch in alabama</a>Anonymous
November 29, 2008
<a href= http://kustur.angelfire.com >dad vail regatta</a> <a href= http://trututa.angelfire.com >ratings apartments eagle ridge alabama</a>Anonymous
July 17, 2009
The comment has been removedAnonymous
December 02, 2014
For me, i had to change: $DomainDN to $DomainDN.Path in this :
$Domain = New-Object -TypeName System.DirectoryServices.DirectoryEntry -ArgumentList $DomainDN.Path, $($Credential.UserName), $($Credential.GetNetworkCredential().password)Anonymous
January 13, 2016
Is there a way to check return codes from using methods like CommitChanges?