Saturday, September 30, 2006

Tim Mintner : Sample Powershell Active Directory Phonebook Script

Tim published an excellent PowerShell script using the Directory Searcher.  Check it out.

Link to Tim Mintner : Sample Powershell Active Directory Phonebook Script

PowerShell 1.0 RC2

The following are some experiments with the ADSI support in PowerShell RC2.  I have tested them to some degree in a small production WS2003 AD domain.  Most of the information was gleened from teh PowerShell Team Blog and the Microsoft Windows Powershell Newsgroup.  My apologies for any errors. I chose to post this because very little documentation exists and I thought others would like a "bootstrap" to save time.

PowerShell RC2 is looking very good.  It still has a couple of glitches and will definitely change before RTM but I don't believe the following will be much afected.  If anything, changes may make the code more direct than it is currently.

For a more in-depth look into using PowerShel with Active Directory see Mows blog at http://mow001.blogspot.com/.  MOW has spent considerable time developing methods and code to leverage AD in PowerShell.  If you need to perform large and complex tasks MOWs the got the code.

Get the root domain object for any domain.

 

The easy one

$root=[adsi]""

The old way

$root=[adsi]"LDAP://rootDSE"
$root|gm$ldappath="LDAP://"+$root.defaultNamingContext
$ldappath$domain=[adsi]$ldappath
$domain|gm

Alternate method for connecting to AD domain object:

$ad=[adsi]"LDAP://$env:userdomain"
$ad

Get current user object using WinNT provider

$user=[adsi]"WinNT://asp/$env:username,user"
$user|gm
# use DN to get full ADSI User object
[string]$ldappath="LDAP://"+$user.distinguishedName
$user=[adsi]$ldappath
$user

Referencing containers and the contained objects.

Getting the contained objects of ADSI can be done in the following ways.  Other variations are possible.  The use of PsBase is key.

Example 1

# get default root and connect to domain
$root=[adsi]"LDAP://rootDSE"
$ldappath="LDAP://"+$root.defaultNamingContext
$domain=[adsi]$ldappath
# Reference PsBase to access the child list
$ad_objects=([adsi]$ldappath).PsBase
$ad_objects.children

The above lists the objects (children) contained at any level.

Example 2

$ref=[adsi]"LDAP://CN=Users,DC=mydomain,DC=com"

$container=$ref.PsBase.children

$container | foreach -process {$_.objectClass}

The above lists the children of the "Users" container.  Any valid LDAP path to a container object will work similarly.

Example 3

Putting it all together - this is a no change script.  It should execute on any host in any AD domain.

$root=[adsi]"LDAP://rootDSE"

$ldappath="LDAP://"+ "CN=Users,"+$root.defaultNamingContext

$domain=[adsi]$ldappath

$container=$domain.PsBase.children

# enumerate the containers objects and hand to a "process" block for

# further processing.

$container | foreach -process {$_.objectClass}

Using    

    Where-Object
    Compare-Object
    Group-Object
    Select-Object
    Sort-Object

Should make access and management of AD objects fairly easy assuming an operational and basic structural knowledge of the AD schema.

Search Active Directory

Return user object given an OU and account name.  This is  a simple demo function.  It does not guard for errors but assumes the OU string and Sam account name  are valid.  I am posting it to show how PS can search for items in AD.  Hopefully the final version of PS will expose the directory search class so LDAP queries can be made accross the whole of AD.  This code can be easily modified to specify the type of object to retrieve.  Adding a recursive layer would allow the search to penetrate AD effectively.

function find-account( $OU, $acctname )
# usage: find-account
# returns account object
{
      $root=[adsi]"LDAP://rootDSE"
      [string]$ldappath="LDAP://" + "OU=" + $OU + "," + $root.defaultNamingContext
      $adsi=[adsi]$ldappath
      $container=$adsi.psbase.children
      $account=$container|where {$_.samAccountName -eq $acctname }
    $account
}

Using the Directory Object FInd Method

The following is most likely to get wrapped in a cmdlet by MS before RTM but here is a method for searching AD.

$root=[adsi]"LDAP://rootDSE"
[string]$ldappath="LDAP://" + "OU=" + $OU + "," + $root.defaultNamingContext
$domain=[adsi]$ldappath

$domain.psbase.get_Children().Find("CN=Users").psbase.children

# search for an OU

$domain.psbase.get_Children().Find("OU=MysubOU,CN=MyOU").psbase.children

Using the Directory Searcher with an LDAP query would be much better.

microsoft.public.windows.powershell NewsGroup

PowerShell RC2 and Active Directory

http://blogs.technet.com/tmintner/archive/2006/06/26/438935.aspx