This blog has moved to http://ThePowerShellGuy.com
Greetings /\/\o\/\/
In my 200th post already (as I did just see) as promised here the start of the Active Directory Management series.
In this first Part I will show how to make a Active Directory Object in Powershell,
connect to a domain, list Properties and Methods of the Object, and how to get the child Objects and store them in a Variable again.We will do all of this interactive from the commandline,
there are no CMDlets yet for Active directory management in PowerShell for version 1,
but as we can use .NET objects from powershell we are still able to manage Activedirectory from Powershell.
the .NET Classes we need are in the namespace system.directoryservices..
(This naming is because as you can connect not only to AD but to an other directoryservices using LDAP as well. )
in .net 2.0 we also have a activedirectory namespace for infrastructure management but more about that later in the Series.
The object we are going to use for this is called a Directoryentry.
So let's start by making a connection to Active Directory. by creating an DirectoryEntry object,
as you might have seen before, to get a .NET object we need the command new-object :
*Warning* As you have RC2 Installed all my AD posts will not work anymore, it is verry confusing, but fixable if you read explaination here PowerShell RC2 and Active Directory :
As I did switch back on all my work PC's (I did call all my colleagues not to upgrade as all our AD tools are messed up, I will not update them, as I would not recommend to upgrade to RC2 of you work with AD a lot.
PoSH> New-Object System.DirectoryServices.DirectoryEntry
distinguishedName
-----------------
{DC=mow,DC=local}
and as you can see as a result we get back the distinguishedName of the domain,
there are 2 things to note here,
you can see that the directoryentry constructed without parameters defaults to the default naming context, that is the current domain, in this case mow.local .
second thing to note is that as we just throw the object to the pipeline, so it gets the default formatting and after that its gone.
as I want to use it a bit more, I will put it into a variable so we can keep using it. I just use the arrow-up to get the previous line again, and Home to get to the beginning of the line and type '[variablename] = '. in front of it.
I like to work this way to first check if I get back the object, and then if it is OK I put it into a variable, otherwise I need to check the variable everytime to see if the command succeeded.
as this is connecting us to the root namespace of the domain, I will call the variable $root.
PoSH>$root = New-Object System.DirectoryServices.DirectoryEntry
PoSH>$root
distinguishedName
-----------------
{DC=mow,DC=local}
You can see we now have the Object in a Variable and can start using it
next, as the default formatter only displays the distinguishedName of the directoryentry object.
I use Format-List * ( by the Alias FL )to show all properties.
# Get all Properties
$root | fl *
you can also get the Methods and Properties of the Object by Using Get-Member :
so next lets ask the directoryEntry Object what more it can do :
# Get All Members
$root | get-Member
# Or to get only the Methods :
PoSH> $root | get-member -MemberType method
TypeName: System.DirectoryServices.DirectoryEntry
Name MemberType Definition
---- ---------- ----------
add_Disposed Method System.Void add_Disposed(EventHandler value)
Close Method System.Void Close()
CommitChanges Method System.Void CommitChanges()
CopyTo Method System.DirectoryServices.DirectoryEntry CopyTo(DirectoryEntry newParent), Syste...
CreateObjRef Method System.Runtime.Remoting.ObjRef CreateObjRef(Type requestedType)
DeleteTree Method System.Void DeleteTree()
Dispose Method System.Void Dispose()
Equals Method System.Boolean Equals(Object obj)
get_AuthenticationType Method System.DirectoryServices.AuthenticationTypes get_AuthenticationType()
get_Children Method System.DirectoryServices.DirectoryEntries get_Children()
.....
.....
and hmmm, this get_children method looks handy,
let's try : $root.get_Children()
PoSH> $root.get_Children()
distinguishedName
-----------------
{CN=Builtin,DC=mow,DC=local}
{CN=Computers,DC=mow,DC=local}
{OU=Domain Controllers,DC=mow,DC=local}
{CN=ForeignSecurityPrincipals,DC=mow,DC=local}
{CN=Infrastructure,DC=mow,DC=local}
{CN=LostAndFound,DC=mow,DC=local}
{OU=MowOu,DC=mow,DC=local}
{CN=NTDS Quotas,DC=mow,DC=local}
{CN=Program Data,DC=mow,DC=local}
{CN=System,DC=mow,DC=local}
{CN=Users,DC=mow,DC=local}
Nice just what I needed as there is not much to do in the root of the ActiveDirectory, so lets look if we can connect to one of the SubOU's
You would expext that you can just use the indexer to get to the wanted OU from the Array returned like this :
PoSH> $root.get_Children()[6]
Unable to index into an object of type System.DirectoryServices.DirectoryEntries.
At line:1 char:22
This does not work, you can see the reason for this in the Errormessage,
we did not get back a collection of DirectoryEntry Objects, but one instance of another .NET class : System.DirectoryServices.DirectoryEntries
You can also check on this by asking it for it's type :
# Check the type
$root.get_Children().GetType()
Note that normaly GM (Get_member) will not show this as it does enumerate the Object ( ?? and you just said that it was not a collection.. nope it is not and it has no indexer but it has a GetEnumerator() Method, so the pipeline of PowerShell does Enumerate on it, and get-member will show the members of the Items that got enumerated, but will show them only one for every type thrown to the pipeline)
PoSH> $root.get_Children() | gm
TypeName: System.DirectoryServices.DirectoryEntry
Name MemberType Definition
---- ---------- ----------
add_Disposed Method System.Void add_Disposed(EventHandler value)
Close Method System.Void Close()
CommitChanges Method System.Void CommitChanges()
you can also give the object as a parameter to get-member to avoid this
Get-Member -inputObject $root
or a workaround I like is put a comma before the object (again as I can use "Arrow Up" to get the last line this change is much easier in interactive use when you need members of the collection not the instances):
,$root.get_Children() | gm
TypeName: System.DirectoryServices.DirectoryEntries
Name MemberType Definition
---- ---------- ----------
Add Method System.DirectoryServices.DirectoryEntry Add(String name, String schemaClassName)
Equals Method System.Boolean Equals(Object obj)
Find Method System.DirectoryServices.DirectoryEntry Find(String name), System.DirectoryServices.Dire...
get_SchemaFilter Method System.DirectoryServices.SchemaNameCollection get_SchemaFilter()
GetEnumerator Method System.Collections.IEnumerator GetEnumerator()
GetHashCode Method System.Int32 GetHashCode()
GetType Method System.Type GetType()
Remove Method System.Void Remove(DirectoryEntry entry)
ToString Method System.String ToString()
SchemaFilter Property System.DirectoryServices.SchemaNameCollection SchemaFilter {get;}
Now we can see its not an array, but we can workaround this lack of an by explicitly making it an array by casting it like this :
@($root.get_Children())[6]
distinguishedName
-----------------
{OU=MowOu,DC=mow,DC=local}
but as you also might have seen in the get-member output, the directoryentries class also has a find method, that has a name as a parameter and.
that will find and return a specific child
$root.get_Children().find('ou=mowOu')
distinguishedName
-----------------
{OU=MowOu,DC=mow,DC=local}
# and store in a variable again for later usage
$mowOU = $root.get_Children().find('ou=mowOu')
# and list all properties again.
Posh> $MowOu | fl *
objectClass : {top, organizationalUnit}
ou : {MowOu}
distinguishedName : {OU=MowOu,DC=mow,DC=local}
instanceType : {4}
whenCreated : {5/18/2006 7:15:13 PM}
whenChanged : {5/18/2006 7:15:13 PM}
uSNCreated : {System.__ComObject}
uSNChanged : {System.__ComObject}
name : {MowOu}
objectGUID : {139 153 183 252 115 3 24 73 145 12 14 36 64 30 237 202}
objectCategory : {CN=Organizational-Unit,CN=Schema,CN=Configuration,DC=mow,DC=local}
nTSecurityDescriptor : {System.__ComObject}
note that this is also a DirectoryEntry Object but it will have other properties as it as a OU Object not the domain.
and from here we can use the some method to list the objects (Users / Computers / Sub-OU's)
$mowou.get_children()
# and for example get a user into a variable to edit it etc :
$mow = $mowou.get_children().find('cn=mow')
note that this is not the only way to get to the sub-OU, If you know the LDAP Path you can pass it in the constructor and connect to the OU directly :
(also note that you can leave away the system namespace as PowerShell will append it)
# connect directly to an LDAP path :
$mowOu = New-Object DirectoryServices.DirectoryEntry("LDAP://OU=MowOu,DC=mow,DC=local")
In the next part of this series we will create a User, and see how to create a loop to make more as 1 user at a time,
and fill some more properties.
later in this series we will use the DirectorySearcher to do searches in AD
But for now by creating one .NET Object and only the 3 most basic PowerShell Cmdlets (new-object / format-(List/Table) / get-member ) we already can :
Connect to AD
List properties of AD Objects
List methods of AD Objects
Walk to the Domain structure to wanted OU
Connect directly to SubOU's
List members of OU's
and the only thing we have to remember is that we need a directoryServices.DirectoryEntry Object.
It will find out the domain / LDAP path for us if we do not know it, and we can use get-member to remember / learn us what the object can do.and to explore the objects we get back.
So as you see it is not as hard as i might seem being without Cmdlets.
More in next post, till then try walking to different parts of AD this way and look at Computer / Users Objects,and do Format-List * and get-Member on the returned objects, to get used to the DirectoryObject and learn for the output you get back,
(for a preview of the next part Creating a user as in the Demo, note the Add() method on the directoryEntries class)
Feel free to leave remarks or questions in the remarks.
Enjoy,
Greetings /\/\o\/\/
Tags : Monad msh PowerShell