|
Posted by aemaeth9 on June 20, 2006, 10:28 am
Please log in for more thread options
Thomas Kratz wrote:
> aemaeth9@gmail.com wrote:
> > hello,
> >
> > i'm curious, could anyone direct me to a half-decent article regarding
> > the Win32::OLE module, and using it to interact with active directory?
> > i've seen very little on it. the only articles i've come across that
> > discuss Win23::OLE where tips/tricks and tutorials on interacting with
> > miscellaneous objects in windows (e.g. opening a URL in IE). I've seen
> > a very small amount of articles, none of which where of any quality,
> > and they mentioned using LDAP as a bridge to AD. is this true? if not,
> > is there a better way? - any help would be much appreciated.
> >
>
> There are at least 2 modules on CPAN dealing with Active Directory or LDAP.
>
> Win32::AD::User
> Net::LDAP
>
> I have attached a module I wrote to simplify ADSI queries. You should be
> able to get the basics of ADSI over Win32::OLE by looking at the code.
> But the main information sources are the ADSI-API docs from M$.
>
> Thomas
>
> --
> $/=$,,$_=<DATA>,s,(.*),$1,see;__END__
> s,^(.*3),,mg,@_=mapsplit;{#>J~.>_an~>>e~......>r~
> $_=$_[$%][$"];y,<~>^,-++-,?{$/=--$|?'"':#..u.t.^.o.P.r.>ha~.e..
> '%',s,(.),$$/$1=1,,$;=$_}:/\w/?{y,_, ,,#..>s^~ht<._..._..c....
> print}:y,.,,||last,,,,,,$_=$;;eval,redo}#.....>.e.r^.>l^..>k^.-
>
> --------------040908070706000808060303
> Content-Type: text/plain
> Content-Disposition: inline;
> filename="ADSI.pm"
> X-Google-AttachSize: 6069
>
> package Local::ADSI;
>
> use strict;
> use warnings;
>
> our $VERSION = "1.01";
> our @ISA = qw(Exporter);
>
> our @EXPORT = qw(
> ADSIGetGroupMembersRecursive
> ADSIQuery
> ADSISetParam
> $ADSILastErr
> );
>
> use Win32::OLE qw/in/;
> Win32::OLE->Option(Warn => 1);
>
> use Data::Dumper;
> $Data::Dumper::Indent = 1;
>
> our $ADSILastErr = '';
>
> =head1 NAME
>
> Local::ADSI - ADSI utility functions
>
> =head1 VERSION
>
> This document refers to version 1.01 of Local::ADSI,
> released 04/2006
>
> =head1 SYNOPSIS
>
> use Local::ADSI;
> use Data::Dumper;
>
> my $all_users = ADSIQuery(
> 'MY.DOMAIN.NAME',
> {qw/objectClass user/},
> [qw/ADsPath Name displayName/],
> 1,
> ) or die $ADSILastErr;
>
> print Dumper($all_users);
>
>
> =head1 DESCRIPTION
>
> Local::ADSI defines a few utility funtions that should make
> common tasks easier to accomplish.
>
> All Funtions return undef on error and set $ADSILastErr.
>
> =head2 ADSIQuery($domain_ou, \%filter, \@outfields, $subtree);
>
> Run an ADSI query. Simplyfies access to ADODB.Connection and ADODB.Command.
> The filter hash takes properties to search for. Desired output fields can
> be specified in the outfields array. Set subtree to true to search in the
> entire domain or OU.
>
> $domain_ou can be specified as MY.DOMAIN.NAME/OU/SUB_OU
>
> Returns a reference to an array of hashes, each hash having the
> selected output fields as keys.
>
> =cut
>
> sub ADSIQuery {
> my($Domain, $filter_hash, $outfields, $subtree) = @_;
>
> my($dom, $ou) = split('/', $Domain, 2);
>
> my $ADsPath = 'LDAP://';
> $ADsPath .= join(',', map { "OU=" . $_ } split('/', $ou)) . ',' if $ou;
> $ADsPath .= join(',', map { "DC=" . uc } split(/\./, $dom));
>
> my $filter = '(&';
> $filter .= join(
> '',
> map {
> "($_=" . $filter_hash-> . ')'
> } keys(%$filter_hash)
> );
> $filter .= ')';
>
> my $fields = join(',', @$outfields);
> my $cmd = join(';', "<$ADsPath>", $filter, $fields, $subtree ? 'subtree' : ());
>
> my $o_conn = Win32::OLE->new("ADODB.Connection") or do {
> $ADSILastErr = "Cannot create ADODB object!";
> return;
> };
> my $o_cmd = Win32::OLE->new("ADODB.Command") or do {
> $ADSILastErr = "Cannot create ADODB command!";
> return;
> };
>
> $o_conn-> = "ADsDSOObject";
> $o_conn-> = "Active Directory Provider";
> $o_conn->Open();
> $o_cmd-> = $o_conn;
> $o_cmd-> = $cmd;
>
> my $o_rec = $o_cmd->Execute() or do {
> $ADSILastErr = "Cannot execute ADODB command!";
> return;
> };
>
> unless ( $o_rec ) {
> $ADSILastErr = join("\n", values(%));
> return;
> }
>
> my @records;
>
> while ( ! $o_rec->EOF ) {
> push( @records, { map { $_ => $o_rec->Fields($_)->value } @$outfields });
> $o_rec->MoveNext;
> }
>
> $o_rec->Close;
> $o_conn->Close;
>
> return(\@records);
> }
>
>
> =head2 ADSISetParam($path, %param_hash);
>
> sets and saves a set of parameters for the ADSI object at $path;
>
> Returns true on success or undef on error.
>
> =cut
>
> sub ADSISetParam {
> my $path = shift;
>
> unless ( 0 == @_ % 2 ) {
> $ADSILastErr = 'ADSISetParam: odd number of params';
> return;
> }
>
> my %params = @_;
>
> my $obj = Win32::OLE->GetObject($path) or do {
> $ADSILastErr = Win32::FormatMessage(Win32::LastErr());
> return;
> };
>
> foreach my $p ( keys(%params) ) {
> $obj->Put($p, $params);
> }
>
> $obj->SetInfo() && do {
> $ADSILastErr = Win32::FormatMessage(Win32::GetLastError());
> return;
> };
>
> return(1);
> }
>
>
> =head2 ADSIGetGroupMembersRecursive($path);
>
> Gets all members of a group, including those that get membership
> through another group. Also lists users who have this group as
> primary group (It is a M$ "feature" not to treat those users as
> members of the group).
>
> Returns a reference to a hash with the member name as the key and the
> displayName as value.
>
> =cut
>
> sub ADSIGetGroupMembersRecursive {
> my($group_path) = @_;
>
> # retrieving the group object
> my $grp_obj = Win32::OLE->GetObject($group_path) or do {
> $ADSILastErr = Win32::FormatMessage(Win32::GetLastError());
> return;
> };
>
> my @group_stack = ($grp_obj);
>
> my(%members, %seen);
> while ( @group_stack ) {
>
> my $obj = shift(@group_stack);
> my $name = $obj->Get('Name');
>
> # avoid endless recursion
> next if $seen;
> $seen = 1;
>
> my $users_with_pg = ADSIGetUsersWithPrimaryGroup($obj) || [];
>
> $members} = $_ for @$users_with_pg;
>
> foreach my $mem ( in($obj->Members) ) {
>
> my $name = $mem->Get('Name');
> my $class = $mem->Class;
> my $path = $mem->AdsPath;
>
> if ( $class eq 'group' ) {
>
> push @group_stack, $mem;
>
> }
> else {
>
> $members = {
> displayName => $mem->Get('displayName') || '',
> ADsPath => $path,
> };
>
> }
>
> }
>
> }
>
> return(\%members);
> }
>
>
> =head2 ADSIGetUsersWithPrimaryGroup($grp_obj);
>
> Gets all users who have set the group as primary group.
>
> $grp_obj is a ADSI group object. It can be created for example by:
>
> $grp_obj = Win32::OLE->GetObject(<LDAP_PATH>);
>
> Returns a reference to a hash with the member name as the key and the
> displayName as value.
>
> =cut
>
> sub ADSIGetUsersWithPrimaryGroup {
> my($grp_obj) = @_;
>
> $grp_obj->GetInfoEx(['canonicalName', 'primaryGroupToken'], 0);
> my $cn = $grp_obj->GetEx('canonicalName')->[0];
> my $domain = (split('/', $cn, 2))[0];
> my $pg = $grp_obj->GetEx('primaryGroupToken')->[0];
>
> my $users_with_pg = ADSIQuery(
> $domain,
> {qw/objectClass user/, primaryGroupID => $pg},
> [qw/ADsPath Name displayName/],
> 1,
> ) or do {
> $ADSILastErr = Win32::FormatMessage(Win32::GetLastError());
> return;
> };
>
> return($users_with_pg);
> }
>
>
>
> =head1 AUTHOR
>
>
> Copyright (c) 2006 Thomas Kratz. All rights reserved.
> This program is free software; you can redistribute it and/or
> modify it under the same terms as Perl itself.
>
> =cut
>
>
> 1;
>
> --------------040908070706000808060303--
Thanks Thomas, i appreciate your help :)
|