Creating Shadow Groups in Active Directory using Perl

Here's an Active Directory script that will maintain a shadow group in Active Directory. Wait, what's a shadow group?

We all have organizational units (OU's) in our Active Directory. OU's are usually created to group objects into a container so that you can you can delegate administrative control over those objects, apply a group policy to those objects, or simply organize them so that administrators know where to look for them. One thing that you can't do with an OU (and you might think that you would) is to grant all the users in an OU access to a file share or other resource. If you want to grant all the users in an OU access to a resource, you have to use shadow groups.

You might have OU's for each office. You might use a shadow group to grant all the users in that office access to a file share or a printer. You might use a shadow group as a distribution list to send email to everyone at that office. Shadow groups are handy.

There's nothing really special about a shadow group. A shadow group is simply a group that contains all of the users in an OU. You simply create a group, add all of the users in the OU to the group, and we call that a shadow group.

The trouble is that after you setup the group. Any users that are added to the OU after you've setup the group aren't automatically added to the group, and any users that are moved to a different OU after you've setup the group are not automatically removed from the group. So we've got to periodically update the group membership to add any new users and remove any old ones. Do that by hand? Heck no. You script it! The script below connects to the OU and the shadow group, removes any users that shouldn't be there, and adds any users that should be there.  Simply run the script nightly as a scheduled task, and the group memberships will be kept up to date.

use Win32::OLE;
$group="shadowTest";
$ou="cn=users,dc=myDomain,dc=com";
$dse=Win32::OLE->GetObject("LDAP://RootDSE");
$dnshost=$dse->Get("DNSHostName");
$root=$dse->Get("DefaultNamingContext");
$base="<LDAP://$root>";
$connection = Win32::OLE->new("ADODB.Connection");
$connection->{Provider} = "ADsDSOObject";
$connection->Open("ADSI Provider");
$command=Win32::OLE->new("ADODB.Command");
$command->{ActiveConnection}=$connection;
$command->{Properties}->{'Page Size'}=1000;
$rs = Win32::OLE->new("ADODB.RecordSet");
$rs->{LockType}=2;
$command->{CommandText}="$base;(&(objectCategory=Group)(¦(cn=$group)(samAccountName=$group)));adspath;subtree";
$rs=$command->Execute;
if($rs->{recordcount} < 1){ print "Group $group not found!\n"; }
until ($rs->EOF){
 $adspath=$rs->Fields(0)->{Value};
 if($groupObj=Win32::OLE->GetObject($adspath)){
  if($ouObj=Win32::OLE->GetObject("LDAP://$ou")){
   #remove users who are no longer in the OU
   foreach $member (@{$groupObj->{member}}){
    if(substr(lc($member),index($member,",")+1) ne lc($ou)){
     print "removing $member from group\n";
     $groupObj->Remove("LDAP://$member");
    }
   }
   #add OU users to the group
   foreach $obj (in $ouObj){
    if($obj->{objectClass}[1] eq "person"){
     print "adding $obj->{cn} to group $group\n";
     $groupObj->Add($obj->{adspath});
    }
   }
  }else{
   print "Could not connect to OU $ou!\n";
  }
 }else{
  print "Could not connect to group $group!\n";
 }
 $rs->MoveNext;
}

0 comments:

Post a Comment

Related Posts Plugin for WordPress, Blogger...