http://qs1969.pair.com?node_id=196718

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

I am trying to return the users and their home directories from a win2k domain to a text file. I can get the first piece of exmple code to work. Unfortunately, ADSI will only return 1000 records.

To get around this limitation, VB examples seem to create a command object, set the Page Size property, and execute it. There are endless VB Examples (of course!), but I'm finding it difficult to find the right syntax in Perl.

When the Non-working code is run, no records are returned whether the Page size property is set or not.

I waded through MS, google, and all the VB people I know (I didn't actually wade through the people, but you understand) and I'm still stuck.

Working Code

use strict; use Win32::OLE 'in'; my $out="accounts.tmp"; open OUT,">$out" or die "Can't open $out for write"; &get_corp_accts(); close OUT; sub get_corp_accts{ # get ADO object, set the provider, open the connection my $ADO = Win32::OLE->new("ADODB.Connection"); $ADO->{Provider} = "ADsDSOObject"; $ADO->Open("ADSI Provider"); my $ADSPath = "LDAP://OU=Users,OU=group,DC=subdomain,DC=domain,DC= +com"; # prepare and then execute the query my $users = $ADO->Execute("<$ADSPath>;(objectClass=User);samAccoun +tName,HomeDirectory;SubTree"); until ($users->EOF){ my $homeDir=lc($users->Fields(1)->{Value}); if ($homeDir=~/^\\\\mf/){ my $account=lc($users->Fields(0)->{Value}); print OUT "$account\t$homeDir\n"; } $users->MoveNext; } $users->Close; $ADO->Close; print "Wrote Accounts\n"; } sub ole_error_check{ if (Win32::OLE->LastError( )){ die Win32::OLE->LastError(); } }

Non Working Code

use strict; use Win32::OLE 'in'; my $out="accounts.tmp"; open OUT,">$out" or die "Can't open $out for write"; &get_corp_accts(); close OUT; sub get_corp_accts{ # get ADO object, set the provider, open the connection my $ADO = Win32::OLE->new("ADODB.Connection"); my $ADOCmd=Win32::OLE->new("ADODB.Command"); #new $ADO->{Provider} = "ADsDSOObject"; $ADO->Open("ADSI Provider"); $ADOCmd->Properties->{'Page Size'}=10000;#new my $ADSPath = "LDAP://OU=Users,OU=group,DC=subdomain,DC=domain,DC= +com"; $ADOCmd->{ActiveConnection}=$ADO;#new $ADOCmd->{CommandText}="<$ADSPath>;(objectClass=User);samAccountNa +me,HomeDirectory;SubTree";#new # prepare and then execute the query my $users=$ADOCmd->Execute; until ($users->EOF){ my $homeDir=lc($users->Fields(1)->{Value}); if ($homeDir=~/^\\\\mf/){ my $account=lc($users->Fields(0)->{Value}); print OUT "$account\t$homeDir\n"; } $users->MoveNext; } $users->Close; $ADO->Close; print "Wrote Accounts\n"; } sub ole_error_check{ if (Win32::OLE->LastError( )){ die Win32::OLE->LastError(); } }

-OzzyOsbourne

Replies are listed 'Best First'.
Re: ADSI: Getting a full list of users from a w2k domain
by cacharbe (Curate) on Sep 10, 2002 at 16:05 UTC
    My first thought is that the Properties object is actually a collection, so it's interface is set up like so:
    $ADOCmd->Properties('PageSize')->{Value}=10000;#new
    vs what you have in the code above.

    I'm not familiar with the ADSI interface, but that should hopefully get you on the right track with the Command interface at least.

    HTH,

    C-.

    Update: Did some research:

    Although what I wrote about the collection is true, from what I've found, you can only set the PageSize in a RecordSet object, like so:

    use Win32::OLE 'in'; my $ADO = Win32::OLE->new("ADODB.Connection"); $ADO->{Provider} = "ADsDSOObject"; $ADO->Open("ADSI Provider"); my $ADOCmd=Win32::OLE->new("ADODB.Command"); my $ADOrs = Win32::OLE->new("ADODB.RecordSet"); $ADOrs->PageSize->{Value}=10000;

    ---
    Flex the Geek

      thanks for the reply! This flexed my brain a bit, and led me to other avenues, but still didn't work. I still get 1000 lines.

      You know that feeling when you work on one line for days? That's how I feel. Does pounding one's head against something solid prodce better code? If so, I should be a master by now.

      Update

      I fiddled with the lines until I got it to work. I'm still not sure if it's the ordering of the commands, the double quotes around Page Size, or some combination thereof. the Full Orphan Script will be posted to the Code catacombs. Thanks to cacharbe for all of his suggestions

      sub get_corp_accts{ # get ADO object, set the provider, open the connection my $ADO = Win32::OLE->new("ADODB.Connection"); $ADO->{Provider} = "ADsDSOObject"; $ADO->Open("ADSI Provider"); # Create the ADO Command my $ADSPath = "LDAP://OU=group,DC=subdomain,DC=domain,DC=com"; my $ADOCmd=Win32::OLE->new("ADODB.Command"); $ADOCmd->{ActiveConnection}=$ADO; $ADOCmd->{CommandText}="<$ADSPath>;(objectClass=User);samAccountNa +me,HomeDirectory;SubTree";#new $ADOCmd->Properties->{"Page Size"}=10000; #Execute the Command my $users=$ADOCmd->Execute; #Extract the Info (AccountName, HomeDirectory) from the returned o +bject until ($users->EOF){ my $homeDir=lc($users->Fields(1)->{Value}); my $account=lc($users->Fields(0)->{Value}); print OUT "$account\t$homeDir\n"; $users->MoveNext; } $users->Close; $ADO->Close; print "Wrote Accounts\n"; }

      -OzzyOsbourne

        I know exactly how you feel.

        Check the settings on you AD Server, as per this and this, and note the caveats and limitations on the latter page regarding max number of entries in a secondary user group, and the MAX size of MaxPageSize.

        Short of it: Looks like you can set MaxPageSize in AD as well, but the MAX MaxPageSize / request is 1000...Looks like you're SOL (another microsoft link here that supports the claim).

        C-.

        ---
        Flex the Geek