Note:  This script takes the current ManagedBy of a Group, and assigns
the proper permissions to activate the checkbox in ADUC.

It should output something like this... 

(if you were to run it twice in a row, the second time it would not do
the work).

As well, it checks to see if the ManagedBy is already populated, and
proceeds/exits accordingly and can take multiple groups for input from
the command line.

Tested in Windows 2003 Native domain, but it should have upward
compatability to Win 2008 domains as well.  Let me know offline how well
it works or doesn't in your environment.

HTH

Steven

http://www.manross.net/perl/scripts/add_perms_for_managed_by.txt

C:\Perl\Scripts>perl add_perms_for_managed_by.pl GroupCA
DNS = DC=somedomain,DC=org
Group: GroupCA
  Flags -- 1
  AccessMask -- 32
  objectType -- {BF9679C0-0DE6-11D0-A285-00AA003049E2}
  AceFlags -- 0
  AceType -- 5
  Trustee -- SOMEDOMAIN\someuser
success setting Security Descriptor access for SOMEDOMAIN\someuser on
GroupCA

C:\Perl\Scripts>perl add_perms_for_managed_by.pl GroupCA
DNS = DC=manross,DC=net
Group: GroupCA
  ACE already exists!
  nothing to do! 



> -----Original Message-----
> From: Steven Manross 
> Sent: Thursday, December 02, 2010 11:07 AM
> To: 'Joachim Thuau'; 'A F'; 
> 'perl-win32-admin@listserv.ActiveState.com'
> Subject: RE: Problem creatign group with email address using 
> Win32::OLE
> 
> That checkbox is determined by whether or not the person in 
> the "Managed By" field has an Access Control Entry 
> (permissions) that allows that person access to modify the 
> object inherently in AD (i.e. it's not a Property per se like 
> "ManagedBy", "ADsPath", etc).
> 
> I am working on perl code to add perms for the managed by of 
> an object, but in it's current form it doesn't have any logic 
> built in to verify that we are not adding an ACE that already 
> exists (duplication) and I want to get that working prior to 
> releasing the code.
> 
> I'll probably have this written later today and tested.  Not 
> that I currently have a need for this functionality 
> presently, but I thought it was a good exercise and something 
> I wanted to get working.
> 
> This Perl script is based on some VBScript to set the perms 
> found at the URL below (and some code I have cobbled together 
> through the years). 
> 
> FYI
> 
> Giving credit where credit is due (VBScript to set the 
> required perms):
> http://www.experts-exchange.com/OS/Microsoft_Operating_Systems
/Server/2003_Server/Q_22004020.html
> 
> Steven
> ________________________________
> 
>       From: Joachim Thuau [mailto:joachim.th...@heavy-iron.com] 
>       Sent: Wednesday, December 01, 2010 4:26 PM
>       To: 'A F'; Steven Manross; 
> perl-win32-admin@listserv.ActiveState.com
>       Subject: RE: Problem creatign group with email address 
> using Win32::OLE
>       
>       
> 
>       You can figure out most mapping for properties by using 
> a LDAP browser, and using a single account to figure out how 
> that works.
> 
>        
> 
>       Sysinternals also has a tool for doing "AD diffs", 
> which might help you figure it out!
> 
>        
> 
>       Thanks,
> 
>       Jok
> 
>        
> 
>       From: perl-win32-admin-boun...@listserv.activestate.com 
> [mailto:perl-win32-admin-boun...@listserv.activestate.com] On 
> Behalf Of A F
>       Sent: Wednesday, December 01, 2010 1:39 PM
>       To: Steven Manross; perl-win32-admin@listserv.ActiveState.com
>       Subject: Re: Problem creatign group with email address 
> using Win32::OLE
> 
>        
> 
>       Hi Guys,
> 
>        
> 
>       It is me again trying to keep this group alive :-)
> 
>        
> 
>       I can assign a owner to the group but I cannot figure 
> out how to enable "Manager can update Membership List" checkbox in AD?
> 
>       $group->Put("managedBy","'CN=some user,OU=some 
> ou,DC=somedomain,DC=com");
> 
>       Can someone help?
> 
>        
> 
> 
# Author: Steven Manross
# Creation date:  12/2/2010
# Summary: Grant the ManagedBy object of a group access to allow the "Manager 
can update Membership list" checkbox in Active Directory Users and Computers.
# Version: 1
# Last Updated:
#    12/2/2010 Initial revision
#
# Adapted and enhanced from VBScript source found here designed to add 
permissions necessary to manage the membership of an object:
#  
http://www.experts-exchange.com/OS/Microsoft_Operating_Systems/Server/2003_Server/Q_22004020.html

use Win32::OLE qw (in);
use Win32::OLE::Variant;

use constant ADS_RIGHT_DS_WRITE_PROP => 0x20;
use constant ADS_ACEFLAG_DONT_INHERIT_ACE => 0x0;
use constant ADS_ACETYPE_ACCESS_ALLOWED_OBJECT => 0x5;
use constant ADS_FLAG_OBJECT_TYPE_PRESENT => 0x01;
use constant ADS_OBJECT_WRITE_MEMBERS => 
"{BF9679C0-0DE6-11D0-A285-00AA003049E2}";

foreach $groupname (@ARGV) {
  $rootdse = Win32::OLE->GetObject("LDAP://RootDSE");
  print "DNS = " . $rootdse->Get("defaultNamingContext")."\n";
  query_ldap("<LDAP://" . $rootdse->Get("defaultNamingContext") . 
">;(&(objectclass=group)(samaccountname=$groupname));adspath;subtree",$groups);
  add_perms_for_managed_by($groups->Fields("adspath")->{Value});
}

sub add_perms_for_managed_by {
  my $group_path = $_[0];
  
  #stole most of this with pride from Win32::Exchange (is stealing from 
yourself really stealing?)

  my $group = Win32::OLE->GetObject($group_path);
  if (Win32::OLE->LastError() != 0) {
    print "error querying group object -> ". Win32::OLE->LastError(). "\n";
    exit 0;
  }

  my $mgbyobj = Win32::OLE->GetObject("LDAP://" . $group->{managedBy});
  if ($mgbyobj eq "") {
    print "ManagedBy is not populated.  Nothing to do!\n";
    return 0;
  }
  my $mgbyid = $mgbyobj->{samaccountname};
  
  get_netbios_domain_name_for_object($mgbyobj,$mgbydomain);
  
  my $sd = $group->{ntSecurityDescriptor};
    
  if (Win32::OLE->LastError() != 0) {
    print "error querying security descriptor -> ". Win32::OLE->LastError(). 
"\n";
    exit 0;
  }
  
  my $dacl = $sd->{DiscretionaryAcl};
  if (Win32::OLE->LastError() != 0) {
    print "error querying discretionary acl for group -> 
".Win32::OLE->LastError()."\n";
    exit 0;
  }

  my $ace = Win32::OLE->CreateObject("AccessControlEntry");
  if (Win32::OLE->LastError() != 0) {
    print "error creating access control entry for mailbox -> " . 
Win32::OLE->LastError() . "\n";
    exit 0;
  }
  
  my %properties;

  $properties{'Trustee'} = $mgbydomain."\\".$mgbyid;
  $properties{'AccessMask'} = ADS_RIGHT_DS_WRITE_PROP;
  $properties{'AceFlags'} = ADS_ACEFLAG_DONT_INHERIT_ACE;
  $properties{'AceType'} = ADS_ACETYPE_ACCESS_ALLOWED_OBJECT;
  $properties{'Flags'} = ADS_FLAG_OBJECT_TYPE_PRESENT;
  $properties{'objectType'} = ADS_OBJECT_WRITE_MEMBERS;
  
  print "Group: " . $group->{DisplayName}."\n";
 
  my $ace_exists = 0;
  foreach $old_ace (in $dacl) {
    if (lc($old_ace->{'Trustee'}) eq lc($mgbydomain."\\".$mgbyid)) {
      if ($old_ace->{AccessMask} == $properties{'AccessMask'} &&
          $old_ace->{AceFlags} == $properties{'AceFlags'} &&
          $old_ace->{Type} == $properties{'Type'} &&
          $old_ace->{Flags} == $properties{'Flags'} &&
          $old_ace->{ObjectType} == $properties{'ObjectType'}
         ) {
        print "  ACE already exists!\n";
        $ace_exists = 1;
      }
    }
  }

  if ($ace_exists == 0) {
  
    foreach my $property (keys %properties) {
      print "  " .$property . " -- " . $properties{$property}."\n";
      $ace->LetProperty($property,$properties{$property}); 
      if (Win32::OLE->LastError() != 0) {
        print "error ACE setting $property for group -> " . 
Win32::OLE->LastError() . "\n";
        exit 0;
      }
    }
  
    $dacl->AddAce($ace);
    if (Win32::OLE->LastError() != 0) {
      print "error adding access control entry to perms list -> " . 
Win32::OLE->LastError() . "\n";
      exit 0;
    }
    
    $sd->LetProperty("DiscretionaryAcl",$dacl); 
    if (Win32::OLE->LastError() != 0) {
      print "error setting  discretionary acl on security security descriptor 
-> " . Win32::OLE->LastError() . "\n";
      exit 0;
    }
    $group->Put("ntSecurityDescriptor",[$sd]);
    if (Win32::OLE->LastError() != 0) {
      print "error setting security descriptor on group object -> " . 
Win32::OLE->LastError() . "\n";
      exit 0;
    }
    $group->SetInfo();
    if (Win32::OLE->LastError() != 0) {
      print "error setting permissions on mailbox -> " . 
Win32::OLE->LastError() . "\n";
      exit 0;
    }
    print "success setting Security Descriptor access for 
".$properties{"Trustee"}." on ". $group->{DisplayName} ."\n";
  } else {
    print "  nothing to do!\n";
  }
  return 1;
}  

sub get_netbios_domain_name_for_object {
  my $userobj = $_[0];
  my $userid = $userobj->{samaccountname};
  my $parent_domain;
  get_parent_domain($userobj,$parent_domain);
  my $query = "<LDAP://CN=Configuration," . 
$parent_domain->{distinguishedName}.">;(nCName=".$parent_domain->{distinguishedname}.");NetBiosName;SubTree";
  query_ldap($query,$netbios_names);
  if ($netbios_names->{RecordCount} == 1) {
    $_[1] = $netbios_names->Fields("NetBiosName")->{Value};
    return 1;
  } else {
    print "error getting the netbos name of the object...  there wasn't just 1 
record!\n";
    return 0;
  }
}

sub get_parent_domain {
  my $child_object = $_[0];
  my $parent_object = Win32::OLE->GetObject($child_object->{Parent});
  if ($parent_object->{Class} ne "domainDNS") {
    get_parent_domain($parent_object,$parent_domain);
  } else {
    $parent_domain = $parent_object;
  }
  $_[1] = $parent_domain;
  return 1;
}

sub query_ldap {
  my $ldap_query = $_[0];

  my $error_num;
  my $error_name;
  my $RS;
  my $Conn = Win32::OLE->new("ADODB.Connection");
  if (Win32::OLE->LastError() != 0) {
    print "Failed creating ADODB.Connection object -> " . 
Win32::OLE->LastError() . "\n";
    return 0;
  }
  $Conn->{'Provider'} = "ADsDSOObject";
  if (Win32::OLE->LastError() != 0) {
      print "Failed setting ADODB.Command Provider information (E55) on 
$search_string -> " . Win32::OLE->LastError() . "\n";
      return 0;
  }
  $Conn->{Open} = "Perl Active Directory Query";

  my $Cmd = Win32::OLE->new("ADODB.Command");
  if (Win32::OLE->LastError() != 0) {
    print "Failed creating ADODB.Command object -> " . Win32::OLE->LastError() 
. "\n";
    return 0;
  }
  $Cmd->{CommandText} = $ldap_query;
  $Cmd->{Properties}->{"Page Size"} = 99;
  $Cmd->{ActiveConnection} = $Conn;
  $RS = $Cmd->Execute();
  if (Win32::OLE->LastError() != 0) {
    if ($error_num eq "0x80040e31") {
      print "Failed Due to Command timeout -> The query took too long -> 
".Win32::OLE->LastError()."\n";
    } else {
      print "Failed Executing ADODB Command object-> 
".Win32::OLE->LastError()."\n";
      print "... while executing ADODB Command -> $proc";
    }
    return 0;
  } else {
    $_[1] = $RS;
    return 1;
  }
}
_______________________________________________
Perl-Win32-Admin mailing list
Perl-Win32-Admin@listserv.ActiveState.com
To unsubscribe: http://listserv.ActiveState.com/mailman/mysubs

Reply via email to