/\/\o\/\/ PowerShelled

This blog has moved to http://ThePowerShellGuy.com Greetings /\/\o\/\/
$AtomFeed = ("Atom.xml")
$PreviousItems = (" Logging your MSH session "," MSH get-dateFormat function "," Working with a Path in MSH "," MSH MSN Instant messenger project (broken off) "," Running (Un-block) a downloaded script in MSH "," Timing the loading of your profile in MSH "," Tuning MSH in your Profile "," Einstein 2 + subtopic. "," Burn MSH ?? "," Monad and Adam (and a preview of my to-be AD provi... "," ")

Thursday, December 01, 2005

 


Get AD info into a nested HashTable from MSH



This blogItem is about a script to get all AD users and computers with the choosen properties in a nested HashTable.

This is a script I actualy used in a Production environment, to update a couple of 1000 policy groups a time ago.

there are 2 reasons i post this now,

1) I needed a nested Hashtable example
2) I had not that much AD coverage yet on my blog

as a quick introduction to the .NET 2.0 AD herplerclasses see : AD Infastructure exploring with MSH , as at home I did not have AD (I started with adam, see Monad and Adam (and a preview of my to-be AD provider) but that is not mimicing a "real" AD environment enough to test yet.

but as I had an excuse at work (policy group check, and editing), I made this script to do this action.

the first reason, was a problem I had with sorting an arraylist (" Wmi-Help Part 1 " Getting All the WMI Classes and Descriptions in a HashTable ) of WMI classes and descriptions.

MSH>$WmiClasses sort key
MSH>$WmiClasses.getEnumerator() sort key

And I did remember to have had the same problems here (using the HashTable created by this script.)

But let's start with the script first :

# Get-ADlist 
# Get's al AD users and there Groups in an HashTable
# /\/\o\/\/ 2005
Function Set-ADlist 
{
  $LDAP = "LDAP://localhost:389/dc=mow,dc=adam"
  $root = New-object System.DirectoryServices.DirectoryEntry($LDAP)
  $searcher = new-object System.DirectoryServices.DirectorySearcher($root)

  $searchItem = "CN"
  $searchValue = "*"
  $searchClass = "User"
  $SearchCat = "*"
  $PolGroups = "Pol01","Pol02"
  $PropList = "CN","ObjectClass","ObjectCategory","distinguishedName","lastLogonTimestamp"

  $searcher.Filter = "(&($($searchItem)=$($searchValue))(objectClass=$($searchClass))(objectCategory=$($SearchCat)))"
  echo "Searching on .. $($searcher.Filter)"
  $searcher.PageSize = 900
  $PropList | foreach {$searcher.PropertiesToLoad.Add($_)}
  $searcher.PropertiesToLoad

  $Global:ADList = @{}
  $ADItems = $searcher.findAll()
  $ADItems | foreach {
    $Prop = $_.properties
    $Line = @{}
    $info = @{}
    $info.add("CN",$prop.cn)
    $info.add("DN",$prop.distinguishedname)
    $info.add("Ldap",$prop.adspath)
    $info.add("Class",$($prop.objectclass | select -last 1))
    $info.add("Logon",$prop.lastlogontimestamp)
    $Groups = @{}
    $MO = $_.GetDirectoryEntry().MemberOf
    $MO | foreach {
      $Member = $_
      $found = $false
      $PolGroups | foreach {
        if ($Member -imatch $_)
        {
          $found = "True"
        }
      }
      $Groups.Add($Member.tostring(),$found)
    }
    $Line.add("Prop",$Info)
    $Line.add("Groups", $groups)
    $global:ADList.add($($prop.cn),$Line)
  }


First you have to change the $LDAP variable to your wanted AD root. (watch that I use Adam here, you don't need to specify a port or even a server, just the AD path, if you want the whole domain, you can even leave out the path, ad the DirectoryEntry will default to the RootDSE then)

The Search path I made a bit flexible by using some Helper variables :
(Makes it more easy to use it in another script, or to change this one)

the Item to search on :

$searchItem = "CN"

The Search Value :

$searchValue = "*"

The Search Class : (but User and Computer are of the "User" Class)

$searchClass = "User"

the Search Category : (here it's * as we want Both Computers as Users)

$SearchCat = "*"

This is a "special"-one I needed to "filter" the policy-groups, it will "Tag" the group as a policygroup, it is used to set a boolean to $true if the group contains one of the strings given.

$PolGroups = "Pol2","Pol1",

the $proplist Array give the properties to load.

$PropList = "CN","ObjectClass","ObjectCategory","distinguishedName","lastLogonTimestamp"

these are than used to "build" the AD searcher, so that we do not have to change that part.


the rest of the script, will use the info collected to generate an array of the found computers and users,

interisting to note may be that I use the Result to create a new directoryEntry in the loop trough the results, as to get the groups I need the DirectoryEntry (as it's not in the resultset), you can get a direct connection to the item by using the GetDirectory Method on a Search Result :

$MO = $_.GetDirectoryEntry().MemberOf

and there is an "extra" loop to check of the Group is in the PolicyGroup Collection.

After you run this script / function You can do things like this :


$ADlist.Computername.prop

$ADlist.Username.groups

etc.

but the Problem came with the more complex usages of this "AD Snapshot" hashTable.
as I could do anything I wanted on 1 line, the querying of the HashTable needed a call to the GetEnumerator that made it a bit complex to read.

I will Post a "brainstorm" session with examples below the Signature,

Watch out !!, as this examples of usage of the hashTable are from the Old session, I found them in Notepad-scrible from the actual action, and I updated them to remove the actual group names,I used part of them to update also, as my Adam is not filled enough to to make new examples at home, I used the saved commands I tryed then, I don't have the output of the command from that time.

but if you can fill the array in you own environment, you can see how powerfull this can be, especialy the walking to the User(in the Snapshot), and the fast querying and testing on the local Hashtable that is very fast, then in the end it's easy to make an action on the resultset (see also examples below) only the usage of .getEnumerator() is making the queries messy I think.

As now I had the same problem with sorting the WMI array, (at that time I was not sure if I did use the ArrayTable right), I did think as this as an good example, where the enumerating "problem" of the hashTable is handycapying a otherwise very powerfull tool.

and, i'm not sure if I did it at the time, but I will throw it up in the NG also, with the following example :

MSH>$ht = @{}
MSH>$ht.add(2,"Two")
MSH>$ht.add(1,"One")
MSH>$ht
Key Value
--- -----
2 Two
1 One
MSH>$ht | sort key
Key Value
--- -----
2 Two
1 One
MSH>$ht.getEnumerator() | sort key
Key Value
--- -----
1 One
2 Two

also this does not work :

$ht | foreach {$_} | sort key


if someone knows a better way, please feel free to leave a comment ;-)

gr /\/\o\/\/



#Computers :

($userlist.getEnumerator()) | foreach {$o = $_ ;if ($o.value.prop.class -eq "computer"){$o.key} }

#Users :

($ADlist.getEnumerator()) | foreach {$o = $_ ;if ($o.value.prop.class -eq "user"){$o.key} }

#Computers in Group:

$group = "CN=Pol1-default,OU=Groups,DC=mow,dc=adam"

($ADlist.getEnumerator()) | foreach {if ($_.value.prop.class -eq "computer"){"$($_.value.prop.cn) $($_.value.groups.ContainsKey($group))"} }

Add comps to group.

$de = New-object System.DirectoryServices.DirectoryEntry
$group = "CN=Pol1-default,OU=Groups,DC=mow,dc=adam"
$de.set_path("LDAP://$group")
($ADlist.getEnumerator()) | foreach {if ($_.value.prop.class -eq "computer"){"$($_.value.prop.cn)";if (!($_.value.groups.ContainsKey($group))){$de.member.add($($_.value.prop.dn));$de.commitchanges()} } }

# All Policy Groups

($ADlist.getEnumerator()) | foreach {$o = $_.key;$($_.value).groups.getenumerator() | where {($_.value) -eq "True"} } |Foreach {$o}

# members of One PolicyGroup
($ADlist.getEnumerator()) | foreach {$o = $_.key;$($_.value).groups.getenumerator() | where {($_.Key) -eq "CN=Pol1-default,OU=Groups,DC=mow,dc=adam"} |Foreach {$o}

$Some Other Tests :
$ADlist.mow.getEnumerator() | where {($_.Value) -eq "True"}
$ADlist.mow.getEnumerator() | where {($_.Value) -eq "True"} | forEach {($_.Key).split(",")[0]}}
$ADlist.getEnumerator() | forEach {$_.key;$_.Value.getEnumerator() | where {($_.Value) -eq "True"}}
$ADlist.getEnumerator() | forEach {$_.key;$_.Value.getEnumerator() | where {($_.Value) -eq "True"} | forEach {($_.Key).split(",")[0]}}
$ADlist.getEnumerator() | forEach {$_.Value.getEnumerator() |where {($_.Key) -eq "CN=Pol1-default,OU=Groups,DC=mow,dc=adam"} }}



Comments: Post a Comment

Links to this post:

Create a Link



<< Home

Archives

October 2005   November 2005   December 2005   January 2006   February 2006   March 2006   April 2006   May 2006   June 2006   July 2006   August 2006   September 2006   October 2006   November 2006   December 2006  

$Links = ("PowerShell RC1 Docs"," PowerShell RC1 X86"," PowerShell RC1 X64"," Monad GettingStarted guide"," Monad Progamming Guide"," Monad SDK"," Monad videos on Channel 9"," MSH Community Workspace"," scripts.readify.net "," MonadSource"," www.reskit.net"," PowerShell Blog"," Under The Stairs"," computerperformance powershell Home"," proudlyserving"," MSH on wikipedia"," MSHWiki Channel 9"," Keith Hill's Blog"," Precision Computing"," PowerShell for fun"," MSH Memo (Japanese)"," monadblog")

find-blog -about "PowerShell","Monad" | out-Technorati.
find-blog -contains "","" | out-Technorati.
Google
 
Web mow001.blogspot.com

This page is powered by Blogger. Isn't yours?