3dbc has asked for the wisdom of the Perl Monks concerning the following question:

Perl Monks,

In an effort to gain better control over the AD and to diminish the overall ambiguity within ADODB after having added users with the NT modules win32::lanman::NetUserAdd - I am now reorganizing win2000 user attributes in order to gain greater clarity. I have compiled sub programs SearchAD and GetProperties however, I would like to programmatically iterate through users within particular OU’s specifically the nested students OU’s. I need to transcribe the attribute “displayName” to the attribute “userPrincipalName” where displayName =~ s/ /_/; displayName .= “\” foreach of the students.


use Win32::OLE; use Win32::OLE::Const; my $name = "Microsoft ActiveX Data Objects 2\\.0 Library"; $ado_consts = Win32::OLE::Const->Load($name) || die "Unable to load Win32::OLE::Const ``$name'' ".Win32::OLE->LastE +rror; $dn = SearchAD( "$username" );#cw0831 print $dn; #LDAP://CN=$username,OU=$ou,OU=$parent_ou,OU=$parent_ou,OU= +$parent_ou,DC=domain,DC=net sub SearchAD { ($Account) = @_; undef $AdsPath; $Root = Win32::OLE->GetObject("LDAP://RootDSE"); $DefaultDomainNC = $Root->Get("DefaultNamingContext"); undef $Root; if ("" eq $DefaultDomainNC) { Win32::MsgBox("Error. Did not get the Default Naming C +ontext", MB_ICONSTOP , "Source User Error +"); return; } $ADOConn = Win32::OLE->new("ADODB.Connection"); $ADOConn->{Provider} = ("ADsDSOObject"); $ADOConn->{ConnectionString} = ($DefaultDomainNC); $ADOConn->Open("Active Directory Provider"); $ADOCommand = Win32::OLE->new("ADODB.Command"); $ADOCommand->{ActiveConnection} = $ADOConn; $ADSQuery = "SELECT AdsPath FROM \'LDAP://$DefaultDomainNC\' W +HERE samAccountName = \'$Account\'"; $ADOCommand->{CommandText} = $ADSQuery; $ResultSet = Win32::OLE->new("ADODB.Recordset"); $ResultSet = $ADOConn->Execute($ADSQuery); $AdsPath = $ResultSet->Fields(0)->{Value}; $ResultSet->Close; $ADOConn->Close; return($AdsPath); } $ADSIObj = Win32::OLE ->GetObject( "$dn" ); #$ADSIObj->{$attrib} = "value"; #$ADSIObj->SetInfo; # Don't forget to set the values my $PropertyList = GetProperties( $ADSIObj ); print "\n\n$ADSIObj->{Name}\n\n"; foreach ( sort( @{$PropertyList} ) ) { next if( " " eq $_ ); print "\t $_: $ADSIObj->{$_}\n"; } sub GetProperties { my( $Obj ) = @_; my @Properties; if ( my $Schema = Win32::OLE->GetObject( $Obj->{Schema} ) ) { foreach ( $Schema->{MandatoryProperties}, $Schema->{OptionalProperties} ) { push( @Properties, @{$_} ) if( defined $_ ); } } return ( \@Properties ); }

janitored by ybiC: Balanced <readmore> tags around codeblock

Replies are listed 'Best First'.
Re: Win32::OLE ADODB
by SquireJames (Monk) on Dec 16, 2003 at 00:59 UTC
    Essentially, you need to perform a couple of tasks to be able to get and validate the data that you want to.

    First, you need to identify the users within the OU that you are checking by using a search string like the one below.

    sub ad_search { # To search AD and return a pre-determined value my $search_base = $_[0]; # This is the base for our searches my $filter = $_[1]; # This is the valid LDAP filter that we will b +e applying my $attribute = $_[2]; # This is the attribute that we will be ret +urning my $search_scope = $_[3]; # This is the scope for our search to fo +llow my ($conn, $res, @result, $succ_search); # Variables that we are u +sing as we go $conn = Win32::OLE->new('ADODB.Connection'); # New connection $conn->{Provider} = "ADsDSOObject"; # OLE provider $conn->Open; $res = $conn->Execute($search_base . $filter . $attribute . $searc +h_scope); # This is our search if ($res->EOF) { # If we have found 0 records that match our searc +h $succ_search = 0; # Set our no records found item and return i +t } else { $succ_search = 1; # So our records found item $res->MoveFirst; # Go to the first record while (not $res->EOF) { # Whie we still have records push (@result, $res->Fields(0)->Value); # Push them to our + array $res->MoveNext; # Go to the next one } } return ($succ_search, @result); # Return our success and our array + of results }
    Basically, you'll want to apply an LDAP filter of (SamAccountName=*), and your base for the search should be the OU that you're looking in. For example: ou=users,dc=xyz,dc=com. Just make sure that the value that you receive is the objects DN. This will return every user that has been setup in that particular OU.

    Next, you need to iterate for each DN that has been returned and push the Display name into another array. You can use a subroutine like this to return the attributes.

    sub ad_get_attrib { # For returning Attribute Values.... my $dn = $_[0]; # The object DN my $attrib = $_[1]; # The attribute in question my ($object,$result); $object = Win32::OLE->GetObject("$dn"); if ($object->{$attrib}) { # If this Attribute actually exists.... $result = $object->Get("$attrib"); } return $result; }
    Once you have these details, loop once for each DN that has been returned and evaluate it to see if it matches the Regex. If it does, then modify the userPrincipalName with the following code
    sub ad_modify { # To change a single value in AD my $dn = $_[0]; # The object DN my $attrib = $_[1]; # The attribute to change my $value = $_[2]; # The attributes new value my ($object); $object = Win32::OLE->GetObject("$dn"); $object->{$attrib} = "$value"; $object->SetInfo; # Don't forget to set the values }
    And that should just about do it....
    There are a couple of different ways to approach this problem, but I reckont that this would be about the fastest way to do it.