package Win32::AD::User; use strict; use Win32::OLE 'in'; $Win32::OLE::Warn = 3; our $VERSION = '0.03'; ###################################################################### sub new{ my $class = shift; my ($connect_string,$username) = @_; bless { _connect_string => $connect_string, _username => $username, _LDAPAdsPath => ($connect_string =~ /LDAP/) ? "CN=".$username.",".(split /\//,$connect_string)[3] : undef, _LDAPAdsSvr => ($connect_string =~ /LDAP/) ? (split /\//,$connect_string)[2] : undef, _WinNTAdsPath => ($connect_string =~ /WinNT/) ? "WinNT://" . (split /\//,$connect_string)[2] . "/$username,user" : undef, _WinNTDomain => ($connect_string =~ /WinNT/) ? (split /\//,$connect_string)[2] : (split /\./, (split /\//,$connect_string)[2])[0], _user_ref => undef}, $class; } ###################################################################### sub print_me{ my $self = shift; print "$_: $self->{$_}\n" for (keys %$self)} ###################################################################### sub create_new{ my $self = shift; my $server = Win32::OLE->GetObject($self->{_connect_string}); my $user; if ($self->_connect_type eq "LDAP"){ $user = $server->Create("user","cn=".$self->{_username}); $user->{samAccountName}=$self->{_username}; $user->SetInfo(); } else{ $user = $server->Create("user",$self->{_username}); $user->SetInfo(); }#fi $self->{_user_ref} = $user; } ###################################################################### sub get_info{ my $self = shift; my $user; if ($self->_connect_type eq "LDAP"){ $user = Win32::OLE->GetObject( join "/", ("LDAP:/",$self->{_LDAPAdsSvr},$self->{_LDAPAdsPath}) ); } else{ $user = Win32::OLE->GetObject($self->{_WinNTAdsPath}); }#fi $self->{_user_ref} = $user; } ###################################################################### sub delete{ my $self = shift; my $server = Win32::OLE->GetObject($self->{_connect_string}); if ($self->_connect_type eq "LDAP"){ $server->Delete("user","cn=".$self->{_username}); } else{ $server->Delete("user",$self->{_username}); }#fi $self->{_user_ref} = undef; } ###################################################################### sub set_password{ my $self = shift; my ($new_password) = @_; $self->{_user_ref}->SetPassword($new_password); } ###################################################################### sub lock{ my $self = shift; $self->{_user_ref}->{'AccountDisabled'} = '1'; $self->{_user_ref}->SetInfo(); } ###################################################################### sub un_lock{ my $self = shift; $self->{_user_ref}->{'AccountDisabled'} = '0'; $self->{_user_ref}->SetInfo(); } ###################################################################### sub is_locked{ my $self = shift; $self->{_user_ref}->{'AccountDisabled'}; } ###################################################################### sub set_properties{ my $self = shift; my ($properties) = @_; for my $i (keys %$properties){ $self->{_user_ref}->{$i} = $properties->{$i}; }#rof $self->{_user_ref}->SetInfo(); } ###################################################################### sub set_property{ my $self = shift; my ($property,$value) = @_; $self->{_user_ref}->{$property} = $value; $self->{_user_ref}->SetInfo(); } ###################################################################### sub get_properties{ my $self = shift; my @props = @_; my %props; $props{$_}=$self->{_user_ref}->{$_} for (@props); %props; } ###################################################################### sub get_property{ my $self = shift; my ($property) = @_; $self->{_user_ref}->{$property}; } ###################################################################### sub _connect_type{ my $self = shift; ($self->{_connect_string} =~ /^LDAP/) ? return "LDAP" : return "WinNT"; } ###################################################################### sub rename{ ## Inspiration: # http://www.rallenhome.com/books/adcookbook/src/06.06-rename_user.pls.txt my $self = shift; my ($new_name) = @_; my $old_name = $self->{_username}; my $server = Win32::OLE->GetObject($self->{_connect_string}); if ($self->_connect_type eq "LDAP"){ $self->set_property("samAccountName",$new_name); $server->MoveHere( join ("/", ("LDAP:/",$self->{_LDAPAdsSvr},$self->{_LDAPAdsPath})),"cn=".$new_name); for my $key (keys %$self){ if ($self->{$key} =~ /$old_name/){ $self->{$key} =~ s/$old_name/$new_name/g }#fi }#rof $self->get_info(); } else{ warn "The 'rename' function is not available when using \n", "a WinNT:// ADsPath... use a LDAP:// ADsPath.\n"; }#fi } ###################################################################### sub move{ #Inspiration: # http://www.rallenhome.com/books/adcookbook/src/08.04-move_computer.pls.txt my $self = shift; my ($new_connect) = @_; if ($self->_connect_type eq "LDAP"){ my $server = Win32::OLE->GetObject($new_connect); $server->MoveHere($self->{_user_ref}->{'ADsPath'},$self->{_user_ref}->{'Name'}); $self->{_connect_string} = $new_connect; $self->{_LDAPAdsPath} = "CN=".$self->{_username}.",".(split /\//,$self->{_connect_string})[3]; $self->{_LDAPAdsSvr} = (split /\//,$self->{_connect_string})[2]; $self->get_info(); } else{ warn "The 'move' function is not available when using \n", "a WinNT:// ADsPath... use a LDAP:// ADsPath.\n"; }#fi } ###################################################################### sub get_groups{ my $self = shift; my @grp; push(@grp, $_->{Name}) for (in $self->{_user_ref}->{Groups}); @grp; } ###################################################################### sub add_to_group{ #Inspiration & Reference: # http://www.rallenhome.com/books/adcookbook/src/06.15-set_primary_group.pls.txt # http://www.rallenhome.com/books/adcookbook/src/07.04-add_group_member.pls.txt my $self = shift; my ($group_ads_path) = @_; $group_ads_path = "WinNT://".$self->{_WinNTDomain}."/$group_ads_path,group" if ($group_ads_path !~ /\:\/\//); my $group = Win32::OLE->GetObject($group_ads_path); if ($self->_connect_type eq "LDAP"){ if($group_ads_path =~ /WinNT:/){ my $wintmp = "WinNT://".$self->{_WinNTDomain}."/".$self->{_username}.",user"; $group->Add($wintmp); } else{ $group->Add("LDAP://".$self->{_LDAPAdsPath}); }#fi $group->SetInfo(); $self->get_info(); } else{ $group->Add($self->{_WinNTAdsPath}); $group->SetInfo(); }#fi } ###################################################################### sub remove_from_group{ #Inspiration & Reference: # http://www.rallenhome.com/books/adcookbook/src/06.15-set_primary_group.pls.txt # http://www.rallenhome.com/books/adcookbook/src/07.04-add_group_member.pls.txt my $self = shift; my ($group_ads_path) = @_; $group_ads_path = "WinNT://".$self->{_WinNTDomain}."/$group_ads_path,group" if ($group_ads_path !~ /\:\/\//); my $group = Win32::OLE->GetObject($group_ads_path); if ($self->_connect_type eq "LDAP"){ if($group_ads_path =~ /WinNT:/){ my $wintmp = "WinNT://".$self->{_WinNTDomain}."/".$self->{_username}.",user"; $group->Remove($wintmp); } else{ $group->Remove("LDAP://".$self->{_LDAPAdsPath}); }#fi $group->SetInfo(); $self->get_info(); } else{ $group->Remove($self->{_WinNTAdsPath}); $group->SetInfo(); }#fi } 1; __END__ =head1 NAME Win32::AD::User - provides routines for Active Directory user administration. =head1 SYNOPSIS use Win32::AD::User; $user = AdUser->new( ADS_CONNECT_STRING, USER_REFERENCE_STRING ); $user->print_me(); $user->create_new(); $user->get_info(); $user->lock(); $user->un_lock(); $user->is_locked(); $user->set_properties( PROPERTY_HASH ); $user->set_property( ADS_PROPERTY_NAME, PROPERTY_VALUE ); $user->get_properties( ADS_PROPERTY_LIST ); $user->get_property( ADS_PROPERTY_NAME ); $user->delete(); $user->set_password( PASSWORD_STRING ); $user->rename( USER_REFERENCE_STRING ); $user->move( ADS_CONNECT_STRING ); $user->get_groups(); $user->add_to_group( ADS_GROUP_STRING ); $user->remove_from_group( ADS_GROUP_STRING ); =head1 ABSTRACT Administer user in Active Directory using either LDAP or WinNT AdsPath. =head1 DESCRIPTION Connect to an Active Directory (AD) Server and Administer Users. Below there is more information on each of the various functions of an Win32::AD::User object. =head2 new(); The new function returns an Win32::AD::User object. The function takes 2 scalars; ADS_CONNECT_STRING and USER_REFERENCE_STRING. The ADS_CONNECT_STRING can be a valid LDAP or WinNT ADsPath string. More information about a valid ADsPath String is available via the Win32::OLE documentation. The USER_REFERENCE_STRING is the username of the account you would like to either create or modify. =head2 print_me(); The print_me function will print the value of all object properties. =head2 create_new(); The 'create_new' function will create a new user object on the AD Server. The 'new' function does not actualy connect to the AD Server either 'create_new or 'get_info' must be used to connect to the AD Server properly. =head2 get_info(); The 'get_info' function will get the user information from the AD Server. The 'new' function does not actualy connect to the AD Server either 'create_new or 'get_info' must be used to connect to the AD Server properly. =head2 lock(); The 'lock' function will lock a user account. =head2 un_lock(); The 'un_lock' function will unlock a user account. =head2 is_locked(); The 'is_locked' function returns '0' if the account is not locked and '1' if it is locked. =head2 set_properties(); The 'set_properties' function will set all properties sent in as PROPERTY_HASH. PROPERTY_HASH is a hash where every key is a valid ADS_PROPERTY_NAME and that key's value is a valid PROPERTY_VALUE. Both of which are defined in the 'set_property' function. =head2 set_property(); The 'set_property' function will allow you to set any user property. The function take two scalars ADS_PROPERTY_NAME, and PROPERTY_VALUE. ADS_PROPERTY_NAME is the name of the property as defined in the ADSI Specification. The ADSI Browser by Toby Everett is a great tool for figuring out which ADS_PROPERTY_NAME you want to use. The PROPERTY_VALUE is what you would like to store in AD. =head2 get_properties(); The 'get_properties' function will return a hash of elements where every key is an element from the ADS_PROPERTY_LIST that is sent is to the funciton as the only argument. The ADS_PROPERTY_LIST is a list of ADS_PROPERTY_NAME elements, as defined in the 'set_property' function description. =head2 get_property(); The 'get_property' function returns a scalar that is the value of the ADS_PROPERTY_NAME which is sent in as an argument. The ADS_PROPERTY_NAME is defined in the 'set_property' function description. =head2 delete(); The 'delete' function will delete the user object from the AD Server. Note that this will not destroy any other data in the Win32::AD::User object, you can recreate user account (without any of the previous attiributes) by invoking the 'create_new' function after using the 'delete' function. =head2 set_password(); The 'set_password' function will set the password of the user. This function requires one scalar; PASSWORD_STRING. This string is what will become the user's password. =head2 rename(); The 'rename' function will change the user's name from whatever it is to the value supplied as USER_REFERENCE_STRING. USER_REFERENCE_STRING is defined in the 'new' function description. =head2 move(); The 'move' function will change the user's location in AD. The function requires an ADS_CONNECT_STRING. The ADS_CONNECT_STRING is defined in the 'new' function description. =head2 get_groups(); The 'get_groups' function will return a list of groups of which the user is a member. =head2 add_to_group(); The 'add_to_group' function will add the user to the group specified in the ADS_GROUP_STRING. The ADS_GROUP_STRING is an ADS_CONNECT_STRING for a group object. The ADS_CONNECT_STRING is defined in the 'new' function description. If a full ADS_GROUP_STRING is given it will attempt to build a WinNT:// ADS_CONNECT_STRING for your user and group (based on the string supplied) to perform the user's addition to the group. =head2 remove_from_group( ADS_GROUP_STRING ); The 'remove_from_group' function will remove the user from the group specified in the ADS_GROUP_STRING. The ADS_GROUP_STRING is an ADS_CONNECT_STRING for a group object. The ADS_CONNECT_STRING is defined in the 'new' function description. If a full ADS_GROUP_STRING is given it will attempt to build a WinNT:// ADS_CONNECT_STRING for your user and group (based on the string supplied) to perform the user's removal from the group. =head1 AUTHOR Aaron Thompson =head1 COPYRIGHT Copyright 2003, Aaron Thompson. All rights reserved. This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO Win32::OLE; ADSI Browser; perl; =cut