Wednesday, February 16, 2011

Removing Specific Messages from Exchange Mailboxes

In my previous blog post, "Search for Large Distribution Lists without Sending Restrictions", I talked about locking down distribution lists and mail-enabled security groups so only select employees can send to them. What do you do if you are too late and that malicious, departing employee has sent out their not-so-fond farewell to large group of recipients before their access was revoked (its all about timing!) and Human Resources has come to you to remove the message from all mailboxes that it was sent? Of course Human Resources has consulted with Legal and got their approval to have the message deleted before speaking with you. Because you have a distribution of e-mail, you have all the e-mail addresses that nasty-gram was sent.

In the code sample below, I take a text file containing those e-mail addresses and use a foreach loop to process the deletion of the e-mail using Export-Mailbox. The code itself is more than overkill as Export-Mailbox is doing all the real work but the surrounding code helps ensure that all elements you need are in place. Like any process that deletes data, I make sure I have a backup (because Legal and Human Resources will change their mind after you start) so the code will export the deleted message into a .pst file in a subfolder of the script directory using the e-mail address of the mailbox as the filename. I also store individual .xml reports in a subdirectory as well. If you have a large distribution to process, break up your list into multiple executions of the script to expedite the removals.

A few things to note about using Export-Mailbox to delete messages. One, Export-Mailbox requires a 32-bit operating system to execute. Two, if the dumpster is turned on, that content will be moved into the .pst file as well. Three, using the subject line is not the only method for discovering the messages you want to target. Review the Export-Mailbox command for other options.

And remember, this script deletes data! Use at your own risk! I might have the best of intentions but my skill may betray you. Test, test and further test before implementing this code in a production environment.
param([string]$file)
#--------------------------------------------------------------------------------------------------#
Function Load-ExchangeSnapin {
 $adminLoaded = $false
 $supportLoaded = $false
 $success = $false
 foreach($snapin in Get-PSSnapin) {
  if($snapin.name -eq "Microsoft.Exchange.Management.PowerShell.Admin") {
   $adminLoaded = $true
  }
  if($snapin.name -eq "Microsoft.Exchange.Management.PowerShell.Support") {
   $supportLoaded = $true
  }
 }
 if($adminLoaded -eq $false) {
  Add-PSSnapin -Name 'Microsoft.Exchange.Management.PowerShell.Admin'
 }
 if($supportLoaded -eq $false) {
  Add-PSSnapin -Name 'Microsoft.Exchange.Management.PowerShell.Support'
 }
 foreach($snapin in Get-PSSnapin) {
  if($snapin.name -eq "Microsoft.Exchange.Management.PowerShell.Admin") {
   $adminLoaded = $true
  }
  if($snapin.name -eq "Microsoft.Exchange.Management.PowerShell.Support") {
   $supportLoaded = $true
  }
 }
 if($adminLoaded -eq $true -and $supportLoaded -eq $true) {
  $success = $true
 }
 return $success
}
Function Unload-ExchangeSnapin {
 $adminLoaded = $false
 $supportLoaded = $false
 foreach($snapin in Get-PSSnapin) {
  if($snapin.name -eq "Microsoft.Exchange.Management.PowerShell.Admin") {
   $adminLoaded = $true
  }
  if($snapin.name -eq "Microsoft.Exchange.Management.PowerShell.Support") {
   $supportLoaded = $true
  }
 }
 if($adminLoaded -eq $true) {
  Remove-PSSnapin -Name 'Microsoft.Exchange.Management.PowerShell.Admin'
 }
 if($supportLoaded -eq $true) {
  Remove-PSSnapin -Name 'Microsoft.Exchange.Management.PowerShell.Support'
 }
}
#--------------------------------------------------------------------------------------------------#
#Modify the values here
Set-Variable -name subjectKeywords -option Constant -value "Screw you, I'm out of here!!!"
Set-Variable -name startDate -option Constant -value "02/16/2011"
Set-Variable -name endDate -option Constant -value "02/16/2011"
Set-Variable -name pstFolder -option Constant -value "$pwd\PST"
Set-Variable -name reportsFolder -option Constant -value "$pwd\Reports"
#--------------------------------------------------------------------------------------------------#
if(![bool]$file) {
 Write-Host "You are missing the `"-file`" command line argument" -foregroundColor Red
 Write-Host ""
 Write-Host "This is the file that contains the list of employee e-mail addresses"
 Write-Host ""
 while((![bool]$file)) {
  $file = Read-Host -prompt "`tFile"
 }
 Write-Host ""
}
if(!(Test-Path -path $file)) {
 Write-Host "Unable to locate: $file" -foregroundColor Red
 Write-Host ""
 Write-Host "Please review the correct path"
 Write-Host ""
 while(!(Test-Path -path $file)) {
  $file = Read-Host -prompt "`tFile"
 }
 Write-Host ""
}
  
$answer = $null
while($answer -ne "Y" -and $answer -ne "N") {
 $answer = Read-Host -prompt "Are you sure you want to use $file (Y/N)?"
}
  
if($answer -eq "N") {
 Write-Host ""
 Write-Host "Quiting..." -foregroundColor Yellow
 exit
}

if(!(Test-Path -path $pstFolder)) {
 New-Item -path $pstFolder -type directory | Out-Null
}
if(!(Test-Path -path $reportsFolder)) {
 New-Item -path $reportsFolder -type directory | Out-Null
}

if((Load-ExchangeSnapin) -eq $false) {
 Write-Warning "Could not load the Exchange Management Snapins"
 exit
}

foreach($emailAddress in (Get-Content -path $file)) {
 Export-Mailbox -Identity $emailAddress -SubjectKeywords $subjectKeywords -DeleteContent -StartDate $startDate -EndDate $endDate -Confirm:$false -PSTFolderPath "$pstFolder\$emailAddress.pst" -IncludeFolder "\Inbox" -ReportFile "$reportsFolder\$emailAddress.xml"  -BadItemLimit 10000
}

Unload-ExchangeSnapin # Remove this line if you want the Exchange Snapins to remain loaded at the conclusion of the script process

No comments:

Post a Comment