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:

 

Properties

Methods

 

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