Menu driven account modifications (terminations)

Unfortunately terminations are part of doing business. Typically these don’t happen in groups, so having automation around the process is a nice-to-have for a lot of organizations, but nothing ever gets put in place. I usually don’t handle tasks like user creations or terminations, but I was recently brought in on a large staff reduction for the purpose of automating the tasks to make the process more efficient.

I contemplated not sharing this since it symbolized a lot of close friends and colleagues losing their jobs, and even if you are supremely confident in their ability to find another job, that’s something you never want to see. Ultimately, I thought if it helped an IT worker out there in my position, then it was worthwhile to do.

The way this reduction was being done wouldn’t allow for bulk lists to be imported and easily used. For the hundreds of people that needed to be processed, an email would be sent to a distribution group to begin the procedure. I decided a menu driven system would be the optimal choice that would prompt for a username and then use some intelligence for data validation and other tasks.

The tasks that needed to be done were:

  • Move the Active Directory account to an Organizational Unit called “Recycle Bin”
  • Generate a random 12-character password
  • Reset the account password with that random password
  • Disable all externally-facing mail protocols (EWS, EAS, MAPI/RPC, OWA, OWA for Devices)
  • Remove the user from all groups except ones around our GoToMeeting accounts because they’d need to be there to remove their meetings
  • If necessary, set their mail to forward
  • Log all of these actions and the account making these changes to a centralized file for auditing later.

Other common tasks that I didn’t need to account for, but I will provide samples for are:

  • Disabling the Active Directory account
  • Hiding the account from the Exchange GAL

Based on the region selected, it would make the changes on different domain controllers since the Exchange environment is spread across sites. It would specify a domain controller in the local site to the Exchange DAG housing that mailbox.

I contemplated not sharing this since it symbolized a lot of close friends and colleagues losing their jobs…

Also, I would not be the only one running this script. I needed to make sure that it was relatively hard to make an error. I did this by trying to catch an error in the username entered. It takes that input and does a get-aduser on it. If it doesn’t find anything, it assumes you did it wrong. Also, for the mail forwarding, I have it detect if an email address was entered (*@*). If it isn’t an address, it tries to do a name match for which it grabs that account’s primary smtp address. If it doesn’t find an account or finds multiple matches, it produces a unique notification error for each to the user. The searches take about 90 seconds each in my environment, so I advised people to just do the search themselves manually.

The finished product isn’t the most graceful thing I’ve written, but it was done under the gun over the course of an afternoon. It worked well except for not suppressing the shell error output if it couldn’t find the AD account or when it couldn’t remove the user from its primary group. Given the time frame I was working with, I’m happy with the way it worked out.

terms
This is the basic script view. That ugly error is like nails on a chalkboard, but I can live with it all things considered
terms01
This is when too many results are found when entering a name for the mail forward
terms02
Lastly, this is a search that netted no results

This isn’t for public consumption like Technet contributions I’ve made, so there aren’t friendly variables for people to use, and it’s not as polished. It should be easy enough to tailor or at least give you ideas if you know what you’re doing. With that disclaimer out of the way, here is the code.

Employee Termination

# This script is used to term employees from my company
Write-Host “`nThis script is to be run on an Exchange server or a machine that has Active Directory module `nand Exchange management tools installed. If these components are missing, then this script will not work. `n`n`nPress any key to continue or ctrl+c to cancel…” -foregroundcolor Yellow -backgroundcolor Black

$x = $host.UI.RawUI.ReadKey(“NoEcho,IncludeKeyDown”)
#……………………………………..
#Loads Exchange Shell
#……………………………………..

. $env:ExchangeInstallPath\Bin\RemoteExchange.ps1
Connect-ExchangeServer -auto

#……………………………………..
#Loads AD module
#……………………………………..

Import-Module ActiveDirectory

#……………………………………..
#Script vairables and settings
#……………………………………..

NET-USE P: /delete
NET USE P: “\\{logserver.domain.com}\rlogs”

#……………………………………..
#Sets up menu and functions to start processing users
#……………………………………..

function rifmenu
{
cls
echo “———————————————————”
echo “”
echo “”
echo ” 1. Terminate a single employee from the AMER or APAC region”
echo ” 2. Terminate a single employee from the EMEA region”
echo ” 3. Exit”
echo “”
echo “”
echo “———————————————————”
$answer = read-host “Please select the option you wish to execute”
If ($answer -eq 1)
{
$user = Read-Host -Prompt “Please enter the username to process”
$aduser = $null
$Aduser = Get-ADUser $user -ErrorAction SilentlyContinue
If ($aduser -eq $null)
{
Write-Host “That username was not found in Active Directory. Press any key to return to the menu…” -ForegroundColor Red
$x = $host.UI.RawUI.ReadKey(“NoEcho,IncludeKeyDown”)
rifMenu
}
Else
{
$currentdate = get-date
Add-Content P:\RLOG.txt “`n$CurrentDate – Termination action started on $($user) : $($aduser.name) by $($env:username)”
Write-Host “Moving user account, $($user), to the Recycle Bin…” -ForeGroundColor Yellow
Move-ADObject $aduser.distinguishedname -TargetPath “OU=Recycle Bin,dc=ADSubdomain,dc=ADDomain,dc=com” -server site1domaincontroller.domain.com
Add-Content P:\RLOG.txt “`n$CurrentDate – $($user) : $($aduser.name) moved to Recycle Bin OU by $($env:username)”
$aduser = $null
$Aduser = Get-ADUser $user -server site1domaincontroller.domain.com
Write-Host “`nGenerating random 12 character password…” -ForeGroundColor Yellow
$newpassword = $null
$newpassword = GET-Termpassword –length 12 –sourcedata $ascii
Write-Host “`nSetting new password $($newpassword) for user $($user)…” -ForegroundColor Yellow
Set-AdAccountPassword $aduser.distinguishedname -reset -NewPassword (ConvertTo-SecureString -AsPlainText $newpassword -Force) -server site1domaincontroller.domain.com
Add-Content P:\RLOG.txt “`n$CurrentDate – $($user) : $($aduser.name) password reset to $($newpassword) by $($env:username)”
Write-Host “`nDisabling ActiveSync, OWA, MAPI, and EWS for Exchange Connectivity for user $($user)…” -ForegroundColor Yellow
Set-casmailbox $user -ActiveSyncEnabled $false -EWSEnabled $false -MAPIEnabled $false -OWAEnabled $false -OWAforDevicesEnabled $false -Confirm:$false -domaincontroller site1domaincontroller.domain.com
Add-Content P:\RLOG.txt “`n$CurrentDate – $($user) : $($aduser.name) has EWS, MAPI, OWA, OWAforDevices, and ActiveSync disabled by $($env:username)”
$membership = $null
$Membership = (Get-ADPrincipalGroupMembership $User -server site1domaincontroller.domain.com).distinguishedname
$goto = $null
$Goto = $membership | where {$_ -like “*citrix_goto*”}
If ($goto -eq $null)
{
Write-Host “No GoToMeeting group membership found. Blanking out domain group membership…” -ForegroundColor Yellow
ForEach ($a in $membership)
{
Remove-adprincipalgroupmembership $user -MemberOf $a -server site1domaincontroller.domain.com -Confirm:$false -ErrorAction SilentlyContinue
}
Add-Content P:\RLOG.txt “`n$CurrentDate – $($user) : $($aduser.name) group membership cleared by $($env:username). No GotoMeeting Groups”
}
Else
{
Add-Content P:\RLOG.txt “`n$CurrentDate – $($user) : $($aduser.name) member of GotoMeeting Groups”
Write-Host “GoToMeeting group membership found. Blanking out domain group membership and re-adding the GoToMeeting groups…” -ForegroundColor Yellow
ForEach ($a in $membership)
{
Remove-adprincipalgroupmembership $user -MemberOf $a -server site1domaincontroller.domain.com -Confirm:$false -ErrorAction SilentlyContinue
}
ForEach ($b in $goto)
{
Add-ADGroupMember $b $user -Server site1domaincontroller.domain.com
}
Add-Content P:\RLOG.txt “`n$CurrentDate – $($user) : $($aduser.name) group membership cleared by $($env:username). GoToMeeting Group membership retained”
}
$mailforward = $null
function mailforwarding
{
$mailforward = read-host “Does this user have a mail forward you need to setup? (y/n)”
if ($mailforward -eq “y”)
{
$address = $null
$Address = read-host -Prompt “Enter the name or the email address you want to forward to”
If ($Address -like “*@*”)
{
Write-Host “Setting fowarding address for $($user) to $($address)…” -ForegroundColor Yellow
Set-Mailbox -Identity $user -DeliverToMailboxAndForward $true -ForwardingSMTPAddress $address -DomainController site1domaincontroller.domain.com
Add-Content P:\RLOG.txt “`n$CurrentDate – $($user) : $($aduser.name) has mailbox forwarding set to $($address) by $($env:username)”
rifMenu
}
Else
{
Write-Host “Trying to find the associated address for $($address)….” -Foregroundcolor Yellow
$search = “*”+$address+”*”
$fmailbox = $null
$Fmailbox = get-mailbox -resultsize unlimited -DomainController site1domaincontroller.domain.com | where {$_.name -like $search} -ErrorAction SilentlyContinue
If ($Fmailbox -eq $null)
{
Write-Host “Could not find a user mailbox associated with $($address). Either skip forwarding and set it manually, enter the forwarding address exactly, or try a different search. Press any key to continue…” -ForegroundColor Red
$x = $host.UI.RawUI.ReadKey(“NoEcho,IncludeKeyDown”)
mailforwarding
}
ElseIF ($fmailbox.count -ge 2)
{
Write-Host “Too many results for $($address). Either skip forwarding and set it manually, enter the forwarding address exactly, or try a different search. Press any key to continue…” -ForegroundColor Red
$x = $host.UI.RawUI.ReadKey(“NoEcho,IncludeKeyDown”)
mailforwarding
}
Else
{
Write-Host “Setting fowarding address for $($user) to $($address)…” -ForegroundColor Yellow
$address = $fmailbox.primarysmtpaddress
Set-Mailbox -Identity $user -DeliverToMailboxAndForward $true -ForwardingSMTPAddress $address -DomainController site1domaincontroller.domain.com
Add-Content P:\RLOG.txt “`n$CurrentDate – $($user) : $($aduser.name) has mailbox forwarding set to $($address) by $($env:username)”
rifMenu
}
}
}
if ($mailforward -eq “n”){rifmenu}
}
Mailforwarding
rifMenu
}
}

If ($answer -eq 2)
{
$user = Read-Host -Prompt “Please enter the username to process”
$aduser = $null
$Aduser = Get-ADUser $user -ErrorAction SilentlyContinue
If ($aduser -eq $null)
{
Write-Host “That username was not found in Active Directory. Press any key to return to the menu…” -ForegroundColor Red
$x = $host.UI.RawUI.ReadKey(“NoEcho,IncludeKeyDown”)
rifMenu
}
Else
{
$currentdate = get-date
Add-Content P:\RLOG.txt “`n$CurrentDate – Termination action started on $($user) : $($aduser.name) by $($env:username)”
Write-Host “Moving user account, $($user), to the Recycle Bin…” -ForeGroundColor Yellow
Move-ADObject $aduser.distinguishedname -TargetPath “OU=Recycle Bin,dc=ADSubdomain,dc=ADDomain,dc=com” -server site2domaincontroller.domain.com
Add-Content P:\RLOG.txt “`n$CurrentDate – $($user) : $($aduser.name) moved to Recycle Bin OU by $($env:username)”
$aduser = $null
$Aduser = Get-ADUser $user -server site2domaincontroller.domain.com
Write-Host “`nGenerating random 12 character password…” -ForeGroundColor Yellow
$newpassword = $null
$newpassword = GET-Termpassword –length 12 –sourcedata $ascii
Write-Host “`nSetting new password $($newpassword) for user $($user)…” -ForegroundColor Yellow
Set-AdAccountPassword $aduser.distinguishedname -reset -NewPassword (ConvertTo-SecureString -AsPlainText $newpassword -Force) -server nsite2domaincontroller.domain.com
Add-Content P:\RLOG.txt “`n$CurrentDate – $($user) : $($aduser.name) password reset to $($newpassword) by $($env:username)”
Write-Host “`nDisabling ActiveSync, OWA, MAPI, and EWS for Exchange Connectivity for user $($user)…” -ForegroundColor Yellow
Set-casmailbox $user -ActiveSyncEnabled $false -EWSEnabled $false -MAPIEnabled $false -OWAEnabled $false -OWAforDevicesEnabled $false -Confirm:$false -domaincontroller site2domaincontroller.domain.com
Add-Content P:\RLOG.txt “`n$CurrentDate – $($user) : $($aduser.name) has EWS, MAPI, OWA, OWAforDevices, and ActiveSync disabled by $($env:username)”
$membership = $null
$Membership = (Get-ADPrincipalGroupMembership $User -server site2domaincontroller.domain.com).distinguishedname
$goto = $null
$Goto = $membership | where {$_ -like “*citrix_goto*”}
If ($goto -eq $null)
{
Write-Host “No GoToMeeting group membership found. Blanking out domain group membership…” -ForegroundColor Yellow
ForEach ($a in $membership)
{
Remove-adprincipalgroupmembership $user -MemberOf $a -server site2domaincontroller.domain.com -Confirm:$false -ErrorAction SilentlyContinue
}
Add-Content P:\RLOG.txt “`n$CurrentDate – $($user) : $($aduser.name) group membership cleared by $($env:username). No GotoMeeting Groups”
}
Else
{
Add-Content P:\RLOG.txt “`n$CurrentDate – $($user) : $($aduser.name) member of GotoMeeting Groups”
Write-Host “GoToMeeting group membership found. Blanking out domain group membership and re-adding the GoToMeeting groups…” -ForegroundColor Yellow
ForEach ($a in $membership)
{
Remove-adprincipalgroupmembership $user -MemberOf $a -server site2domaincontroller.domain.com -Confirm:$false -ErrorAction SilentlyContinue
}
ForEach ($b in $goto)
{
Add-ADGroupMember $b $user -Server site2domaincontroller.domain.com
}
Add-Content P:\RLOG.txt “`n$CurrentDate – $($user) : $($aduser.name) group membership cleared by $($env:username). GoToMeeting Group membership retained”
}
$mailforward = $null
function mailforwarding
{
$mailforward = read-host “Does this user have a mail forward you need to setup? (y/n)”
if ($mailforward -eq “y”)
{
$address = $null
$Address = read-host -Prompt “Enter the name or the email address you want to forward to”
If ($Address -like “*@*”)
{
Write-Host “Setting fowarding address for $($user) to $($address)…” -ForegroundColor Yellow
Set-Mailbox -Identity $user -DeliverToMailboxAndForward $true -ForwardingSMTPAddress $address -DomainController site2domaincontroller.domain.com
Add-Content P:\RLOG.txt “`n$CurrentDate – $($user) : $($aduser.name) has mailbox forwarding set to $($address) by $($env:username)”
rifMenu
}
Else
{
Write-Host “Trying to find the associated address for $($address)….” -Foregroundcolor Yellow
$search = “*”+$address+”*”
$fmailbox = $null
$Fmailbox = get-mailbox -resultsize unlimited -DomainController site2domaincontroller.domain.com | where {$_.name -like $search} -ErrorAction SilentlyContinue
If ($Fmailbox -eq $null)
{
Write-Host “Could not find a user mailbox associated with $($address). Either skip forwarding and set it manually, enter the forwarding address exactly, or try a different search. Press any key to continue…” -ForegroundColor Red
$x = $host.UI.RawUI.ReadKey(“NoEcho,IncludeKeyDown”)
mailforwarding
}
ElseIF ($fmailbox.count -ge 2)
{
Write-Host “Too many results for $($address). Either skip forwarding and set it manually, enter the forwarding address exactly, or try a different search. Press any key to continue…” -ForegroundColor Red
$x = $host.UI.RawUI.ReadKey(“NoEcho,IncludeKeyDown”)
mailforwarding
}
Else
{
Write-Host “Setting fowarding address for $($user) to $($address)…” -ForegroundColor Yellow
$address = $fmailbox.primarysmtpaddress
Set-Mailbox -Identity $user -DeliverToMailboxAndForward $true -ForwardingSMTPAddress $address -DomainController site2domaincontroller.domain.com
Add-Content P:\RLOG.txt “`n$CurrentDate – $($user) : $($aduser.name) has mailbox forwarding set to $($address) by $($env:username)”
rifMenu
}
}
}
if ($mailforward -eq “n”){rifmenu}
}
Mailforwarding
RifMenu
}
}
If ($answer -eq 3)
{
VerifyExit
}
}

function VerifyExit
{
$areyousure = read-host “Are you sure you want to exit? (y/n)”
if ($areyousure -eq “y”)
{
NET USE P: /delete
exit
}
if ($areyousure -eq “n”){rifmenu}
}

Function Get-Termpassword()
{
Param(
[int]$length=10,
[string[]]$sourcedata
)
For ($loop=1; $loop –le $length; $loop++)
{
$TempPassword+=($sourcedata | GET-RANDOM)
}
return $TempPassword
}

$ascii = $NULL;For ($a=33;$a –le 126;$a++) {$ascii+=,[char][byte]$a }
#……………………………………..
#Executes menu to start processing users
#……………………………………..

rifmenu

This is what the log files look like –

Log file view

01/16/2017 17:13:39 – Termination action started on bg-pfdb02tst : BG-PFDB02 Test by myadminaccount
01/16/2017 17:13:39 – bg-pfdb02tst : BG-PFDB02 Test moved to Recycle Bin OU by myadminaccount
01/16/2017 17:13:39 – bg-pfdb02tst : BG-PFDB02 Test password reset to RAw(R#>zuMCW by myadminaccount
01/16/2017 17:13:39 – bg-pfdb02tst : BG-PFDB02 Test has EWS, MAPI, OWA, OWAforDevices, and ActiveSync disabled by myadminaccount
01/16/2017 17:13:39 – bg-pfdb02tst : BG-PFDB02 Test member of GotoMeeting Groups
1/16/2017 17:13:39 – bg-pfdb02tst : BG-PFDB02 Test group membership cleared by myadminaccount. GoToMeeting Group membership retained
1/16/2017 17:13:39 – bg-pfdb02tst : BG-PFDB02 Test has mailbox forwarding set to testme@testme.com by myadminaccount

Some other tasks that you may decide to do would be disabling the account and/or hiding it from the GAL. It would be one or both of these commands:

Additional samples
set-mailbox $user -HiddenfromAddressListsEnabled $true
Disable-ADAccount -identity $aduser.distinguishedname

There you have it. If you have a large amount of modifications coming your way, this will give you an idea how to handle it. Of course doing a bulk import would be easier if that’s an option  ($users = import-csv {csv path} / $users = get-content {text file path}) and then a ForEach. It wasn’t the case here.

 

tales01

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s