Win32::Exchange - Exchange 5.5 and Exchange 2000 functions
|
Win32::Exchange - Exchange 5.5 and Exchange 2000 functions
$provider = Win32::Exchange->new($info_store_server)) ||
die " - error creating new object\n';
#--- Exchange 5.5
$mailbox = $provider->CreateMailbox($info_store_server,$mailbox_alias_name);
if (!$mailbox) {
die "Error creating mailbox\n";
}
print "Create successful\n";
$mailbox->SetAttributes(\%Attributes);
$mailbox->SetOwner("$domain\\$mailbox_alias_name");
#--- Exchange 2000
$mailbox_user = $provider->CreateMailbox($info_store_server,
$pdc,
$mailbox_alias_name,
"domainname.com") ||
print 'Mailbox create failed\n';
$mailbox_user->Win32::Exchange::SetAttributes(\%Attributes) ||
print 'Set Attributes failed\n';
This module creates and modifies Exchange 5.5 and 2000 Mailboxes, has growing support
for Distribution lists, and some server API queries.
(eventually it will do more, but for now, that's it.)
Win32::Exchange uses Win32::OLE exclusively (and technically is just a wrapper for the
underlying OLE calls).
All methods return 0 on failure and 1 for success unless otherwise noted.
- $provider = Win32::Exchange->new($server_name,[ $version]);
- $provider = Win32::Exchange::new($server_name,[ $version]);
-
The
new()
class method starts a new instance of an Exchange provider object.
It returns a reference to this object or 0 if the creation fails.
The SERVER_NAME argument must not be prepended with backslashes. The optional VERSION argument can be 5.5 or
6.0.
5.5 would create a Win32::OLE object of type AdsNamespaces for use with Exchange 5.5
6.0 would create a Win32::OLE object of type CDO.Person for use with Exchange 2000.
GetVersion can return an acceptable version number for your Exchange server.
- $provider->
AddDLMembers($info_store_server,$dl_name,\@new_dl_members);#Exchange 5.5
-
The
AddDLMembers()
function is only implemented for Exchange 5.5. I'll look at modifying Distribution lists
in Exchange 2000, but I think it's just an AD group with special properties. In any case, it's not implemented for Exchange 2000. Sorry.
if ($provider->AddDLMembers($info_store_server,$dl_name,/@new_dl_members)) {
print "Added members successfully\n";
}
#Exchange 5.5 only
- $provider->
CreateMailbox($server_name,$mailbox_name,[$org,$ou]);#Exchange 5.5
- $provider->
CreateMailbox($server_name,$dc_name,$mailbox_name,$mail_domain,[$storage_group,$mailbox_store]);#Exchange 2000
- $provider->
CreateMailbox($server_name,$dc_name,$mailbox_name,$mail_domain,[$mailbox_store_dn]);#Exchange 2000 using dn
-
The
CreateMailbox()
function behaves differently depending on
which type of provider it is passed (CDO.Person [E2K] or ADsNamespaces[5.5]). As well, the arguments for the Exchange
5.5 and 2000 functions are different.
When making Exchange 2000 Mailboxes, it should be noted that if you are using multiple "storage groups",
or multiple "mailbox stores" on the Exchange Server, the presence of $storage_group and $mailbox_store are not optional (unless replaced by a valid mailbox store distinguished name as the fifth parameter),
as the function will fail because it doesn't know where to put your new mailbox.
Lastly, if you plan on running LocateMailboxStore before
the CreateMailbox, you can pass the distinguished name of the "located" mailbox store instead of the "storage group"
and "mailbox store" names.
- Win32::Exchange::GetDistinguishedName($server_name,$serach_object,$result);
-
The GetDistinguishedName function takes the Server name you want to query, an object type (or properly formatted ADODB filter, see below) and returns
the distinguished name of the object on that server. This function is cross-compatible within Exchange versions, but not tested in Exchange 2000 (but
would probably be useful in querying Active Directory Server attributes.
This function opens LDAP on the $server_name, applies the $filter, and then performs an ADODB search on the entire sub-tree. Once it finds values that
meet your search criteria, it performs a pattern-match to see if $server_name is found anywhere in the distinguished name of search results. If it finds the server
name in the results, it returns the first match.
if (Wi32::Exchange::GetDistinguishedName($info_store_server,'Home-MTA',$result)) {
print 'result = $result\n';
} else {
print 'Error Returning from GetDistinguishedName\n';
}
Currently this type of "pre-declaration" of a filter is available for 'Home-MTA' and 'Home-MDB' (case sensitive), but the function also accepts ADODB stype
filters such as (objectClass=MTA) or (objectClass=MHS-Message-Store), which is the same as declaring 'Home-MTA' or 'Home-MDB'
Get familiar with the ADSVW program found in the ADSI 2.5 SDK. If you can find something helpful in ADSVW, chances are you can come up with an ADODB
filter to meet your needs.
- $provider->
GetLDAPPath($server_name,$org,$ou);#Exchange 5.5
-
The GetLDAPPath method takes a server name (Exchange 5.5) and returns the Organization and OU for the Server.
The function has no corresponding Exchange 2000 function, but performs the same objective (of determinig where to
eventually create a mailbox) as provided by LocateMailboxStore.
if ($provider->GetLDAPPath($info_store_server,$org,$ou)) {
print 'returned -> o='.$org.',ou='.$ou.'\n';
} else {
print 'Error Returning from GetLDAPPath\n';
}
- $provider->
GetMailbox($server_name,$mailbox_name,[$org,$ou]);
-
The
GetMailbox()
function is only implemented for Exchange 5.5.
It didn't make sense to have GetMailbox for Exchange 2000, since the underlying object for mailbox creation in
Exchange 2000 is an NT User account, and you have to query the Interface on the User Account ever y time to manipulate Exchange related data, anyway.
$mailbox = $provider->GetMailbox($info_store_server,$mailbox_alias_name,$org,$ou);
if ($mailbox) {
print "Mailbox exists\n";
}
#Exchange 5.5 only
- Win32::Exchange::
GetVersion($server_name,\%version)
-
This function returns a HASH of version information in the form of:
ver=5.5
build=2653.23
sp=4
if (!Win32::Exchange::GetVersion($info_store_server,\%ver)) {
die "$rtn - Error returning from GetVersion\n";
}
print "version = $ver{ver}\n";
print "build = $ver{build}\n";
print "service pack = $ver{sp}\n";
- $provider->
LocateMailboxStore($info_store_server,$storage_group,$mailbox_store,$store_name,[\@counts])
-
This method allows you to query the Exchange 2000 server to determine:
- the default store name (if there is only 1 storage group and 1 mailbox store on the server)
- the Mailbox Store distinguished name (if passed a valid storage group and mailbox store name)
- the number of Storage Groups and Mailbox Stores a given server has (optionally)
if (Win32::Exchange::LocateMailboxStore($info_store_server,$storage_group,$mailbox_store,$store_name,\@counts)) {
print "storage group = $storage_group\n";
print "mailbox store = $mailbox_store\n";
print "located store distinguished name= $store_name\n";
print "$info_store_server\n";
print " Total:\n";
print " storage groups = @counts[0]\n";
print " mailbox stores = @counts[1]\n";
}
In this example, @counts is an optional parameter and should be populated providing the function is able to query the:
- CDOEXM.ExchangeServer,
- CDOEXM.MailboxStore, and
- CDOEXM.StorageGroup
classes, and even if the function is unable to locate $storage_group and $mailbox_store, either because these variables are
null strings and there is more than 1 mailbox store or storage group, or because they were not found as a valid storage group
and mailbox store (useful for debugging purposes).
-
- $mailbox->
SetAttributes(\%attrs);Exchange 5.5
- $ad_user_object->
SetAttributes(\%attrs);Exchange 2000
-
The
SetAttributes()
method takes a specially formed hash structure,
and is different depending on which version of Exchange you are trying to set attributes for:
Exchange 5.5:
$Exchange_Info{'Deliv-Cont-Length'}='6000';
$Exchange_Info{'Submission-Cont-Length'}='6000';
$Exchange_Info{'givenName'}="This";
$Exchange_Info{'sn'}="Isatest";
$Exchange_Info{'cn'}=$mailbox_full_name;
$Exchange_Info{'mail'}="$mailbox_alias_name\@manross.net";
$Exchange_Info{'rfc822Mailbox'}="$mailbox_alias_name\@manross.net";
push (@$Other_MBX,"RFAX:$Exchange_Info{'cn'}\@");
push (@$Other_MBX,"smtp:secondary\@$mail_domain");
push (@$Other_MBX,"smtp:tertiary\@$mail_domain");
$Exchange_Info{'otherMailbox'}=$Other_MBX;
Note:
- Setting the sn, cn, mail, givenname and rfc822Mailbox are required. If the create succeeds and you do not set these attributes, your mailbox will have a fulname of "Exchange username Mailbox" (where username is the $mailbox_name that you pased to SetOwner
See Also (Exchange 5.5):
Exchange 5.5 and ADSI (ADSI Exchange)
Exchange 2000:
push (@$proxies,'SMTP:'.$mailbox_alias_name.'@manross.net');
push (@$proxies,'smtp:secondary@manross.net');
push (@$proxies,'smtp:tertiary@manross.net');
$Attributes{"IMailRecipient"}{ProxyAddresses} = $proxies;
$Attributes{"IMailRecipient"}{IncomingLimit} = 6000;
$Attributes{"IMailRecipient"}{OutgoingLimit} = 6000;
$Attributes{"IMailboxStore"}{EnableStoreDefaults} = 0;
$Attributes{"IMailboxStore"}{StoreQuota} = 100;
$Attributes{"IMailboxStore"}{OverQuotaLimit} = 120;
$Attributes{"IMailboxStore"}{HardLimit} = 130;
See Also (Exchange 2000):
Interfaces and attributes
- $mailbox->SetOwner($user)
-
The
SetOwner()
method takes a string reference
(ex. "DOMAIN\USERNAME") and is currently only applicable for use in setting the owner on
Exchange 5.5 mailboxes.
$mailbox->SetPerms("DOMAIN\username") || print 'Error setting owner\n'
- $mailbox->SetPerms(\@USERS)
-
The
SetPerms()
method takes an array reference of user or
group names, and is currently only applicable for use in setting permissions on Exchange 5.5 mailboxes.
push (@PermsUsers,"$domain\\$mailbox_name");
push (@PermsUsers,"$domain\\Some Group");
$mailbox->SetPerms(\@PermsUsers) || print 'Error setting perms\n'
Currently there are none, but I intend to make DEBUG a passable parameter as it is currently hard-coded to 1 (enabled).
use Win32::Exchange;
use Win32::AdminMisc;
$domain = Win32::DomainName();
$pdc = Win32::AdminMisc::GetPDC($domain);
$mailbox_alias_name='thisisatest';
$mailbox_full_name="This $mailbox_alias_name Isatest";
$info_store_server="HOMEEXCH2";
if (!Win32::Exchange::GetVersion($info_store_server,\%ver) ) {
die "$rtn - Error returning into main from GetVersion\n";
}
print "version = $ver{ver}\n";
print "build = $ver{build}\n";
print "service pack = $ver{sp}\n";
if (!($provider = Win32::Exchange::new($info_store_server,$ver{'ver'}))) {
die "$rtn - Error returning into main from new ($Win32::Exchange::VERSION)\n";
}
if ($ver{ver} eq "5.5") {
if (!Win32::Exchange::GetLDAPPath($info_store_server,$org,$ou)) {
print "Error returning into main from GetLDAPPath\n";
exit 1;
}
print "GetLDAPPath succeeded\n";
if ($mailbox = $provider->GetMailbox($info_store_server,$mailbox_alias_name,$org,$ou)) {
print "Mailbox already existed\n";
if ($mailbox->SetOwner("$domain\\$mailbox_alias_name")) {
print "SetOwner in GetMailbox worked!\n";
}
} else {
$mailbox = $provider->CreateMailbox($info_store_server,$mailbox_alias_name,$org,$ou);
if (!$mailbox) {
die "error creating mailbox\n";
}
print "We created a mailbox!\n";
}
$Exchange_Info{'Deliv-Cont-Length'}='6000';
$Exchange_Info{'Submission-Cont-Length'}='6000';
$Exchange_Info{'givenName'}="This";
$Exchange_Info{'sn'}="Isatest";
$Exchange_Info{'cn'}=$mailbox_full_name;
$Exchange_Info{'mail'}="$mailbox_alias_name\@insight.com";
$Exchange_Info{'rfc822Mailbox'}="$mailbox_alias_name\@insight.com";
$smtp="smtp:another_name_to_send_to\@$mail_domain";
push (@$Other_MBX,$smtp);
#be careful with 'otherMailbox'es.. You are deleting any addresses that may exist already
#if you set them via 'otherMailbox' and don't get them first (you are now forewarned).
$Exchange_Info{'otherMailbox'}=$Other_MBX;
$mailbox->SetAttributes(\%Exchange_Info);
$mailbox->SetOwner("$domain\\$mailbox_alias_name");
my @PermsUsers;
push (@PermsUsers,"$domain\\$mailbox_alias_name");
push (@PermsUsers,"$domain\\Exchange Perm Users"); #Group that needs perms to the mailbox...
$mailbox->SetPerms(\@PermsUsers);
my @new_dl_members;
push (@new_dl_members,$mailbox_alias_name);
$provider->AddDLMembers($info_store_server,"newdltest",\@new_dl_members);
} elsif ($ver{ver} eq "6.0") {
$storage_group = ""; #you'd need to define this if you had more than 1 storage group on 1 server.
$mailbox_store = ""; #you'd need to define this if you had more than 1 mailbox store on 1 or more storage groups.
if (Win32::Exchange::LocateMailboxStore($info_store_server,$storage_group,$mailbox_store,$store_name,\@counts)) {
print "storage group = $storage_group\n";
print "mailbox store = $mailbox_store\n";
print "located store distinguished name= $store_name\n";
print "$info_store_server\n";
print " Total:\n";
print " storage groups = @counts[0]\n";
print " mailbox stores = @counts[1]\n";
}
if ($new_mailbox_user = $provider->CreateMailbox($info_store_server,
$pdc,
$mailbox_alias_name,
"insight.com"
)
) {
print "Mailbox create succeeded\n";
} else {
die "Failure is the option that you have selected!\n";
}
#be careful with proxy addresses.. You are deleting any addresses that may exist already
#if you set them via ProxyAddresses (you are now forewarned).
push (@$proxies,'SMTP:'.$mailbox_alias_name.'@manross.net');
push (@$proxies,'smtp:secondary@manross.net');
push (@$proxies,'smtp:primary@manross.net');
push (@$proxies,'smtp:tertiary@manross.net');
$Attributes{"IMailRecipient"}{ProxyAddresses} = $proxies;
$Attributes{"IMailRecipient"}{IncomingLimit} = 6000;
$Attributes{"IMailRecipient"}{OutgoingLimit} = 6000;
$Attributes{"IMailboxStore"}{EnableStoreDefaults} = 0;
$Attributes{"IMailboxStore"}{StoreQuota} = 100; #at 100KB starts getting warnings
$Attributes{"IMailboxStore"}{OverQuotaLimit} = 120; #at 120KB can't send...
$Attributes{"IMailboxStore"}{HardLimit} = 130; #at 130KB, can't do anything...
if (!$new_mailbox_user->Win32::Exchange::SetAttributes(\%Attributes)) {
die "Error setting 2K Attributes\n";
} else {
print "Set Attributes correctly\n";
}
exit 1;
}
- NT4 clients talking to Exchange servers will need the following software from Microsoft installed:
- ADSI 2.5
- ADSI SDK (Software Development Kit)
- ADsSecurity.dll -- this dll must be registered on your system using the command 'regsvr32 adssecurity.dll' (This dll is found in the ADSI SDK)
- Any NT client trying to manipulate Exchange 2000 objects will need to load the Exchange System Manager (from the Exchange 2000 Server CD)
- The Exchange 5.5 Admin program is optional, but helpful in viewing data related to Exchange 5.5 and 2000.
- If I ever got real ambitious, I'd probably start subclassing Mailbox, DistributionList and more for a more contiguous namespace.
- NT4 clients installed with the software mentioned in the notes section, will work, but are prone to breaking intermittently. Microsoft has explained this by saying that there is minimal dependency checking in this toolset, please see the readme.txt provided with this PPM distribution for further rants on this topic.
- I have done no testing with free-standing Exchange 2000 servers or Exchange 2000 Servers connected to NT4 Domains. Something will probably break in this environment.
- Currently there is no implementation for a SetPerms type function for Exchange 2000. That should change shortly :).
- Mailbox creation will fail on Exchange 2000 if you do not pass a storage group and mailbox store when there are more than one of either on the server that you have selected in your CreateMailbox.
- Because I use GetObject in the GetMailbox and CreateMailbox sub, it's possible that a hidden Recipient may exist for the name you have chosen to get/create and the get/create may fail. This is easily fixed by changing the underlying GetObject call to an OpenDSObject call, but this call, needs an administrative name sent with it so for now, the GetObject works in most cases, and eventually I'll add another function that allows for use of the OpenDSObject, so live with it until I implement a new function for it or by all means, create your own function. This only pertains to Exchange 5.5.
This module is based on an Exchange 5.5 Creation script that has been traveling around the Internet and Activestate's mailing list archives for years.
I picked up on the thread in 1999, and have been modifying it ever since. With the advent of Exchange 2000, another
script came to light, that tried to parse the Storage Group name and Mailbox Store names into an incredibly long string to allow for Exchange 2000 mailbox creation (circa 2001?).
I thought that there had to be a better way to do it.
As it turns out, there was; LocateMailboxStore is an implementation of
that idea.
I'd like to thank the following people:
Please send questions, comments or suggestions about this module to Steven Manross <steven@manross.net>.
Version 0.0.0.022 August 22, 2002
Microsoft, Active Directory, Windows, Windows NT and Exchange are either registered trademarks or trademarks of Microsoft Corporation in the United States and/or other countries.
Win32::Exchange - Microsoft Exchange related functions
|