Introduction
This script helps reduce the time it takes to administrate Exchange users.
Background
I wrote this script to allow other people to Mail enable new accounts so they show up in the GAL. It kept expanding to include other functions too.
Using the Code
The script does the following steps:
- Enables user and contact to show up in the GAL and be part of distribution lists. (Does Not Create Mailboxes).
- Remove groups and distribution lists from
$DisabledOUDN OU
.
- Disabled mail users for
$DisabledOUDN OU
.
- Export and disabled mailbox users for
$DisabledOUDN OU
.
- Create and enable "No Longer With" Exchange rule users for
$DisabledOUWithEmailRule
.
- Export, disabled, and move Mail Box Users for
$DisabledOUWithEmailRule
Over $PSTExportTime
days.
Dependencies for this script:
Loading Modules for Power-Shell
Write-Host ("Loading Active Directory Plugins") -foregroundcolor "Green"
Import-Module "ActiveDirectory" -ErrorAction SilentlyContinue
Write-Host ("Loading Exchange WebServices Plugins") -foregroundcolor "Green"
$EWSDLL = (($(Get-ItemProperty -ErrorAction SilentlyContinue
-Path Registry::$(Get-ChildItem -ErrorAction SilentlyContinue
-Path 'Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Exchange\Web Services'
|Sort-Object Name -Descending| Select-Object -First 1 -ExpandProperty Name)).
'Install Directory') + "Microsoft.Exchange.WebServices.dll")
if (Test-Path $EWSDLL) {Import-Module $EWSDLL -ErrorAction SilentlyContinue}
Microsoft.Exchange.WebServices.dll" -ErrorAction SilentlyContinue
## Create Exchange Web Service Object
$ExchangeVersion = [Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2010_SP2
$EWSservice = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService($ExchangeVersion)
$EWSservice.UseDefaultCredentials = $true
## End Code From http://gsexdev.blogspot.in/2012/11/creating-sender-domain-auto-reply-rule.html
# Load All Exchange PSSnapins
Write-Host ("Loading Exchange Plugins") -foregroundcolor "Green"
If ($([System.Net.Dns]::GetHostByName(($env:computerName))).hostname
-eq $([System.Net.Dns]::GetHostByName(($ExchangeServer))).hostname) {
Add-PSSnapin Microsoft.Exchange.Management.PowerShell.E2010 -ErrorAction SilentlyContinue
. $env:ExchangeInstallPath\bin\RemoteExchange.ps1
Connect-ExchangeServer -auto -AllowClobber
} else {
$ERPSession = New-PSSession -ConfigurationName Microsoft.Exchange
-ConnectionUri http://$ExchangeServer/PowerShell/ -Authentication Kerberos
Import-PSSession $ERPSession -AllowClobber
}
Setting all variables in needed for script. Also, finds the default e-mail domain.
$HomeDriveShare = "\\File Server FQDN\Share"
$PSTFolder = "Outlook"
$PSTExportTime = 120
$ExchangeServer = "Exchange Server"
$Company = "Company Name"
$DisabledOUDN = "Disabled user Distinguished Name"
$DisabledOU = (Get-ADOrganizationalUnit $DisabledOUDN).Name
$DisabledOUWithEmailRule = "Disabled Users under 6 months"
$EnableEmailUsersOUs = "OU Name to Mail Enable","2nd OU Name to Mail Enable"
$ExchangeGroupsOU = "Exchange E-Mail Groups"
$ADContactOU = "AD Contacts OU Name"
$PrimaryEmailDomain = ((get-emailaddresspolicy | Where-Object
{ $_.Priority -Match "1" } ).EnabledPrimarySMTPAddressTemplate).split('@')[-1]
You need to ignore any SSL errors otherwise, cannot create or enable Exchange rules.
$Provider=New-Object Microsoft.CSharp.CSharpCodeProvider
$Compiler=$Provider.CreateCompiler()
$Params=New-Object System.CodeDom.Compiler.CompilerParameters
$Params.GenerateExecutable=$False
$Params.GenerateInMemory=$True
$Params.IncludeDebugInformation=$False
$Params.ReferencedAssemblies.Add("System.DLL") | Out-Null
$TASource=@'
namespace Local.ToolkitExtensions.Net.CertificatePolicy{
public class TrustAll : System.Net.ICertificatePolicy {
public TrustAll() {
}
public bool CheckValidationResult(System.Net.ServicePoint sp,
System.Security.Cryptography.X509Certificates.X509Certificate cert,
System.Net.WebRequest req, int problem) {
return true;
}
}
}
'@
$TAResults=$Provider.CompileAssemblyFromSource($Params,$TASource)
$TAAssembly=$TAResults.CompiledAssembly
$TrustAll=$TAAssembly.CreateInstance("Local.ToolkitExtensions.Net.CertificatePolicy.TrustAll")
[System.Net.ServicePointManager]::CertificatePolicy=$TrustAll
This section is adding AD users to GAL that have e-mail address other than the default email address for your domain.
ForEach ($EMOU in $EnableEmailUsersOUs) {
Write-Host ("")
Write-Host ("Searching for Users to Mail Enable in OU: $EMOU" )
$enablemailusers = get-user -organizationalUnit $EMOU |
where-object{$_.RecipientType -eq "User" -and $_.WindowsEmailAddress -ne $null}
$enablemailusers | ForEach-Object {
$data = $_.WindowsEmailAddress -split("@")
if (($data[0] -ne "") -and ($data[1] -ne $PrimaryEmailDomain)) {
Write-Host ("`tEnable Mail Name: " + $_.Name +
" Alias: " + $_.SamAccountName + "
Email: " + $_.WindowsEmailAddress) -foregroundcolor "Gray"
set-aduser -Identity $_.SamAccountName -clear msExchMailboxGuid,
msexchhomeservername,legacyexchangedn,mailnickname,msexchmailboxsecuritydescriptor,
msexchpoliciesincluded,msexchrecipientdisplaytype,msexchrecipienttypedetails,
msexchumdtmfmap,msexchuseraccountcontrol,msexchversion
Enable-MailUser -Identity $_.Name -ExternalEmailAddress
$_.WindowsEmailAddress -Alias $_.SamAccountName
}
}
}
This section adds AD contacts to the GAL that have e-mail addresses other than your default email addresses for your domain.
Write-Host ("Searching for Contacts to Mail Enable on OU: $ADContactOU")
$enablemailusers = Get-Contact -organizationalUnit $ADContactOU|
where-object { $_.RecipientType -NotLike "*Mail*" -and $_.WindowsEmailAddress -ne $null }
$enablemailusers | ForEach-Object {
$data = $_.WindowsEmailAddress -split("@")
if (($data[0] -ne "") -and ($data[1] -ne $PrimaryEmailDomain)) {
Write-Host ("`tEnable Contact Name: " + $_.Name +
" Alias: " + $($data[0]) + " Email: " +
$_.WindowsEmailAddress) -foregroundcolor "Gray"
Enable-MailContact -Identity $_.Name -ExternalEmailAddress $($data[0] +
"@" + $data[1]) -Alias $($data[0])
}
}
This section is removing any groups or distribution lists from users in $DisabledOUDN
.
Write-Host ("Searching for Users to Mail Disable in DN: $DisabledOUDN")
get-aduser -SearchBase $DisabledOUDN -Filter * | ForEach-Object {
$UserDN = $_.DistinguishedName
$userSAM = $_.SamAccountName
Get-ADGroup -LDAPFilter "(member=$UserDN)" | foreach-object {
if ($_.name -ne "Domain Users") {
Write-Host ("`t Removing $userSAM from
group $_.name") -foregroundcolor "magenta"
if ($_.DistinguishedName.tostring().contains("OU=" + $ExchangeGroupsOU)) {
Remove-DistributionGroupMember -identity $_.name -Member $UserDN -Confirm:$False
} else {
remove-adgroupmember -identity $_.name -member $UserDN -Confirm:$False
}
}
}
}
Now, we are exporting and disabling any mailbox users in the $DisabledOU
.
Write-Host ("Searching for Users to Disable in Exchange in OU: $DisabledOU")
$enablemailusers = get-user -organizationalUnit $DisabledOU |
where-object {$_.RecipientType -ne "User" -and $_.WindowsEmailAddress -ne $null}
ForEach ($EEUser in $enablemailusers) {
if ($EEUser.WindowsEmailAddress -ne "") {
If ($EEUser.RecipientType -eq "MailUser" ) {
Write-Host ("`tDisable Mail Name: " + $EEUser.Name +
" Alias: " + $EEUser.SamAccountName + " Email: " +
$EEUser.WindowsEmailAddress) -foregroundcolor "magenta"
Disable-MailUser -Identity $EEUser.SamAccountName -Confirm:$False
}
If ($EEUser.RecipientType -eq "UserMailbox" ) {
If ((Get-MailboxExportRequest | Where-Object { $_.Identity
-contains $EEUser.Identity -And $_.Status -ne "Completed"}) -eq $null) {
Write-Host ("`tExport Mail Name: " + $EEUser.Name +
" Alias: " + $EEUser.SamAccountName + "
Email: " + $EEUser.WindowsEmailAddress) -foregroundcolor "Blue"
if (-Not (Test-Path $($HomeDriveShare + "\" +
$EEUser.SamAccountName)))
{New-Item -ItemType directory -Path ($HomeDriveShare +
"\" + $EEUser.SamAccountName)}
if (-Not (Test-Path $($HomeDriveShare + "\" +
$EEUser.SamAccountName + "\" + $PSTFolder + "\")))
{New-Item -ItemType directory -Path ($HomeDriveShare +
"\" + $EEUser.SamAccountName + "\" + $PSTFolder + "\")}
#Export Mailbox to PST
New-MailboxExportRequest -Mailbox $EEUser.SamAccountName
-FilePath $($HomeDriveShare + "\" + $EEUser.SamAccountName +
"\" + $PSTFolder + "\" + $EEUser.SamAccountName + ".pst")
while ( (Get-MailboxExportRequestStatistics -Identity $($EEUser.SamAccountName +
"\MailboxExport")).status -ne "Completed" ) {
#View Status of Mailbox Export
Get-MailboxExportRequestStatistics -Identity $($EEUser.SamAccountName +
"\MailboxExport") | ft SourceAlias,Status,
PercentComplete,EstimatedTransferSize,BytesTransferred
Start-Sleep -Seconds 10
}
#Remove mailbox from Exchange
Disable-Mailbox -Identity $EEUser.SamAccountName -confirm:$false
} else {
Write-Host ("`t`tUser " + $EEUser.Name + " already submitted.")
while ((Get-MailboxExportRequestStatistics -Identity
($EEUser.SamAccountName + "\MailboxExport")).status -ne $("Completed")) {
#View Status of Mailbox Export
Get-MailboxExportRequestStatistics -Identity ($EEUser.SamAccountName +
"\MailboxExport") | ft SourceAlias,Status,
PercentComplete,EstimatedTransferSize,BytesTransferred
Start-Sleep -Seconds 10
}
#Remove mailbox from Exchange
Disable-Mailbox -Identity $EEUser.SamAccountName -confirm:$false
}
}
}
}
Here is where a lot of things happen. I will break them down in to smaller chunks. All if this is happening to $DisabledOUWithEmailRule
.
Getting the list of user from the OU and looping though them.
Write-Host ("Searching for Disable Users in OU: $DisabledOUWithEmailRule")
$enablemailusers = get-user -organizationalUnit $DisabledOUWithEmailRule |
where-object {$_.RecipientType -ne "User" -and $_.WindowsEmailAddress -ne $null}
ForEach ($CurrentAccount In $enablemailusers) {
$CurrentMailBox = $CurrentAccount | Get-Mailbox
When we disabled a user, we put in the AD user description the following (Date of deactivation in YYYYMMDD format) (username of person disabling account) (request/ticket number). Since we know when we disabled the user, we parse that out to know when the user has had the Exchange rule on for $PSTExportTime
time.
If ( $($CurrentAccount.WindowsEmailAddress) -ne "" ) {
$ADUser = Get-adUser $CurrentAccount.SamAccountName -Properties Description,Manager
$StrTestDate = [datetime]::ParseExact($ADUser.description.substring(0,8),"yyyyMMdd",$null)
$currentdate= GET-DATE
$TimeSpan = [DateTime]$currentdate - [DateTime]$StrTestDate
$UsersManager= get-user $CurrentAccount.Manager
Here was the hardest part to get to work. This section uses EWS Managed API Please make sure you have it installed.
We first disable all rules to make sure we do not have any conflicting rules. The mail box rule is created and applied in this section.
$AllRules = Get-InboxRule -Mailbox $CurrentAccount.SamAccountName
if ($AllRules | where-object{ $_.name -eq "Termination Auto Reply"})
{
} else {
ForEach ($Rule in $AllRules) {
Disable-InboxRule -Identity $Rule.RuleIdentity -Mailbox $CurrentAccount.WindowsEmailAddress
}
Write-Host ("`tCreating Email Rule for $CurrentAccount.SamAccountName")
-foregroundcolor "Blue"
$EWSservice.AutodiscoverUrl($CurrentAccount.WindowsEmailAddress,{$true})
$EWSservice.ImpersonatedUserId = new-object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId
([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress, $CurrentAccount.WindowsEmailAddress)
Write-Host ("`t Using CAS Server : " + $EWSservice.url)
$templateEmail = New-Object Microsoft.Exchange.WebServices.Data.EmailMessage -ArgumentList $EWSservice
$templateEmail.ItemClass = "IPM.Note.Rules.ReplyTemplate.Microsoft";
$templateEmail.IsAssociated = $true;
$templateEmail.Subject = "$($CurrentAccount.FirstName) is no longer with $Company";
$htmlBodyString = " $($CurrentAccount.FirstName) is no longer with $Company
For any business related needs please e-mail $($UsersManager.FirstName)
at $($UsersManager.WindowsEmailAddress). ";
$templateEmail.Body = New-Object Microsoft.Exchange.WebServices.Data.MessageBody($htmlBodyString);
$PidTagReplyTemplateId = New-Object Microsoft.Exchange.WebServices.Data.ExtendedPropertyDefinition
(0x65C2, [Microsoft.Exchange.WebServices.Data.MapiPropertyType]::Binary)
$templateEmail.SetExtendedProperty($PidTagReplyTemplateId, [System.Guid]::NewGuid().ToByteArray());
$templateEmail.Save([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Inbox);
$inboxRule = New-Object Microsoft.Exchange.WebServices.Data.Rule
$inboxRule.DisplayName = "Termination Auto Reply";
$inboxRule.Actions.ServerReplyWithMessage = $templateEmail.Id;
$inboxRule.Exceptions.ContainsSubjectStrings.Add("RE:");
$inboxRule.Exceptions.ContainsSubjectStrings.Add("FW:");
$createRule = New-Object Microsoft.Exchange.WebServices.Data.CreateRuleOperation[] 1
$createRule[0] = $inboxRule
$EWSservice.UpdateInboxRules($createRule,$true);
Now we are enabling email forwarding to the user's AD Manager and also keep a copy in the user mail box.
Write-Host ("`tForwarding e-mail for $CurrentAccount.SamAccountName to
$($UsersManager.Name)") -foregroundcolor "Blue"
If ($CurrentAccount.ForwardingAddress -eq $null ) {
If (-Not [string]::IsNullOrEmpty($UsersManager.WindowsEmailAddress.ToString())) {
$CurrentAccount | Set-Mailbox -DeliverToMailboxAndForward $true
-ForwardingSMTPAddress "$($UsersManager.WindowsEmailAddress.ToString())"
enabled -ExternalAudience "all" -InternalMessage
"$CurrentAccount.FirstName is no longer with $Company
For any business related needs please e-mail $UsersManager.FirstName
at $UsersManager.WindowsEmailAddress." -ExternalMessage
"$CurrentAccount.FirstName is no longer with $Company
For any business related needs please e-mail $UsersManager.FirstName
at $UsersManager.WindowsEmailAddress."
}
}
}
Now we are testing to see if we can export email to PST. If we can, we export email and disable Exchange account. After the exchange account is disabled, we move it to our $DisabledOUDN
.
"Disable Date: " + $StrTestDate + " Date Age: " + $TimeSpan.TotalDays)
If ($TimeSpan.TotalDays -ge $PSTExportTime) {
If ((Get-MailboxExportRequest | Where-Object { $_.Identity
-contains $($CurrentAccount.Identity)}) -eq $null) {
Write-Host ("`tExport Mail Name: " +
$CurrentAccount.Name + " Alias: " + $CurrentAccount.SamAccountName +
" Email: " + $CurrentAccount.WindowsEmailAddress) -foregroundcolor "Blue"
if (-Not (Test-Path $HomeDriveShare + "\" + $CurrentAccount.SamAccountName))
{New-Item -ItemType directory -Path ($HomeDriveShare +
"\" + $CurrentAccount.SamAccountName)}
if (-Not (Test-Path $HomeDriveShare + "\" +
$CurrentAccount.SamAccountName + "\" + $PSTFolder + "\"))
{New-Item -ItemType directory -Path ($HomeDriveShare + "\" +
$CurrentAccount.SamAccountName + "\" + $PSTFolder + "\")}
#Export Mailbox to PST
New-MailboxExportRequest -Mailbox $_.SamAccountName -FilePath
$($HomeDriveShare +
"\" + $CurrentAccount.SamAccountName + "\" + $PSTFolder +
"\" + $CurrentAccount.SamAccountName + ".pst")
while ( (Get-MailboxExportRequestStatistics -Identity
$($CurrentAccount.SamAccountName +
"\MailboxExport")).status -ne "Completed" ) {
#View Status of Mailbox Export
Get-MailboxExportRequestStatistics -Identity
$($CurrentAccount.SamAccountName +
"\MailboxExport") | ft SourceAlias,Status,
PercentComplete,EstimatedTransferSize,BytesTransferred
Start-Sleep -Seconds 10
}
#Remove mailbox from Exchange
Disable-Mailbox -Identity $CurrentAccount.SamAccountName -confirm:$false
#Move User to Disabled Outlook
Move-ADObject -Identity $ADUser -TargetPath $DisabledOUDN
} else {
Write-Host ("`t`tUser " + $CurrentAccount.Name + " already submitted.")
while ((Get-MailboxExportRequestStatistics -Identity
($CurrentAccount.SamAccountName + "\MailboxExport")).status -ne $("Completed")) {
#View Status of Mailbox Export
Get-MailboxExportRequestStatistics -Identity
($CurrentAccount.SamAccountName +
"\MailboxExport") | ft SourceAlias,Status,
PercentComplete,EstimatedTransferSize,BytesTransferred
Start-Sleep -Seconds 10
}
#Remove mailbox from Exchange
Disable-Mailbox -Identity $CurrentAccount.SamAccountName -confirm:$false
#Move User to Disabled Outlook
Move-ADObject -Identity $ADUser -TargetPath $DisabledOUDN
}
}
}
}
Points of Interest
I would like to thank the following sites that gave examples of code for this script:
History
Version 1.3.0 First Script Post
- Mail Enables User and Contacts
- Mail User Disabled
$DisabledOUDN
- Mail Box User Disables
$DisabledOUDN
- Remove groups and distribution lists from
$DisabledOUDN OU
- Enable "No Longer With" Exchange reply for
$DisabledOUWithEmailRule
- Disable Mail box users
$PSTExportTime
Days old (Date from Description YYYYMMDD) and Export Mail to PST. Then the users are disabled in Exchange and moved to the $DisabledOUDN