Skip to main content

Find Unused Mailbox Powershell Gui Exchange 2007


Finding unused mailboxes is one of those mind numbing tasks a Sys Admin must perform routinely in Large Exchange organizations. Many of the scripts on this blog help to show ways to tackle different issues around unused or disabled mailboxes such as removing disabled users accounts from groups or finding broken delegate forwarding rules etc. I've also posted a few scripts before that showed some methods to track down unused mailboxes by looking at the number of unread email and the last time a mailbox sent a message. Well this script puts some of these methods together in a powershell GUI script that uses Exchange Web Services and some Exchange Management Shell cmdlets to look at all mailboxes on a server and show us information about when a mailbox was logged into, how big it is, how many unread email there is and when the last sent and/or received email was. It presents all this information back to you as a GUI with data grid and also has a button that allows exporting the result to a CSV file.

How it works?

To get the information about when the mailbox was last logged onto the EMS cmdlet get-mailbox is used and also get-Mailboxstatistics is also used to get the mailbox size in MB. To get the number of unread email in a mailbox and to get the last time a mail was sent from the sent items folder Exchange Web Services is used to query the mailbox. To do this from Powershell and the EMS I’ve used my EWSUtil library which has some routine in there that will perform a finditem operation with the nessasary restrictions so it will only show Unread messages. The library will handle Autodiscover and allow for both delegate and impersonation access method. The Form allows for all of these combinations and also allows you to specify overrides for both authentication and the URL for the CAS server to use (you need to use the full url to the EWS if you going to use eg https://servername/ews/exchange.asmx). The rest of the script just builds the form elements for the GUI and adds some simple function that does a export of the data shown in the GRID.

To use this script you need to have the EwsUtil.dll in c:\temp you can download the library from https://github.com/gscales/Powershell-Scripts/raw/master/ScriptArchive/ewsutil.zip. You can download the actual script from here I've include a few other scripts in the download that show simpler examples of read the unread email from mailboxes as well (Just for fun). I've put the download of the script here the Code itself looks like


[System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")
[System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms")
$form = new-object System.Windows.Forms.form
[void][Reflection.Assembly]::LoadFile("C:\temp\EWSUtil.dll")
$mbcombCollection = @()
$Emailhash = @{ }

function ExportGrid{

$exFileName = new-object System.Windows.Forms.saveFileDialog
$exFileName.DefaultExt = "csv"
$exFileName.Filter = "csv files (*.csv)|*.csv"
$exFileName.InitialDirectory = "c:\temp"
$exFileName.Showhelp = $true
$exFileName.ShowDialog()
if ($exFileName.FileName -ne ""){
$logfile = new-object IO.StreamWriter($exFileName.FileName,$true)
$logfile.WriteLine("UserName,EmailAddress,Last_Logon,MailboxSize,
Inbox_Number_Unread,Inbox_Unread_LastRecieved,Sent_Items_LastSent")
foreach($row in $msTable.Rows){
$logfile.WriteLine("`"" + $row[0].ToString() + "`"," + $row[1].ToString() + "," + $row[2].ToString() + "," + $row[3].ToString() + "," + $row[4].ToString() + "," + $row[5].ToString() + "," + $row[6].ToString())
}
$logfile.Close()
}

}

function Getinfo(){

$mbcombCollection = @()
$Emailhash.clear()
$msTable.clear()

Get-Mailbox -server $snServerNameDrop.SelectedItem.ToString() -ResultSize Unlimited | foreach-object{
if ($Emailhash.containskey($_.ExchangeGuid) -eq $false){
$Emailhash.add($_.ExchangeGuid.ToString(),$_.windowsEmailAddress.ToString())
}
}

get-mailboxstatistics -server $snServerNameDrop.SelectedItem.ToString() | foreach-object{
$mbcomb = "" | select DisplayName,EmailAddress,Last_Logon,MailboxSize,
Inbox_Number_Unread,Inbox_Unread_LastRecieved,Sent_Items_LastSent
$mbcomb.DisplayName = $_.DisplayName.ToString()
if ($Emailhash.ContainsKey($_.MailboxGUID.ToString())){
$mbcomb.EmailAddress = $Emailhash[$_.MailboxGUID.ToString()]
}
if ($_.LastLogonTime -ne $null){
$mbcomb.Last_Logon = $_.LastLogonTime.ToString()
}
$mbcomb.MailboxSize = $_.TotalItemSize.Value.ToMB()

"Mailbox : " + $mbcomb.EmailAddress
if ($mbcomb.EmailAddress -ne $null){
$mbMailboxEmail = $mbcomb.EmailAddress
if ($unCASUrlTextBox.text -eq ""){ $casurl = $null}
else { $casurl= $unCASUrlTextBox.text}
$useImp = $false
if ($seImpersonationCheck.Checked -eq $true) {
$useImp = $true
}
if ($seAuthCheck.Checked -eq $true) {
$ewc = new-object EWSUtil.EWSConnection($mbMailboxEmail,$useImp, $unUserNameTextBox.Text, $unPasswordTextBox.Text, $unDomainTextBox.Text,$casUrl)
}
else{
$ewc = new-object EWSUtil.EWSConnection($mbMailboxEmail,$useImp, "", "", "",$casUrl)
}


$drDuration = new-object EWSUtil.EWS.Duration
$drDuration.StartTime = [DateTime]::UtcNow.AddDays(-365)
$drDuration.EndTime = [DateTime]::UtcNow

$dTypeFld = new-object EWSUtil.EWS.DistinguishedFolderIdType
$dTypeFld.Id = [EWSUtil.EWS.DistinguishedFolderIdNameType]::inbox
$dTypeFld2 = new-object EWSUtil.EWS.DistinguishedFolderIdType
$dTypeFld2.Id = [EWSUtil.EWS.DistinguishedFolderIdNameType]::sentitems

$mbMailbox = new-object EWSUtil.EWS.EmailAddressType
$mbMailbox.EmailAddress = $mbMailboxEmail
$dTypeFld.Mailbox = $mbMailbox
$dTypeFld2.Mailbox = $mbMailbox

$fldarry = new-object EWSUtil.EWS.BaseFolderIdType[] 1
$fldarry[0] = $dTypeFld
$msgList = $ewc.FindUnread($fldarry, $drDuration, $null, "")
$mbcomb.Inbox_Number_Unread = $msgList.Count
if ($msgList.Count -ne 0){
$mbcomb.Inbox_Unread_LastRecieved = $msgList[0].DateTimeSent.ToLocalTime().ToString()
}

$fldarry = new-object EWSUtil.EWS.BaseFolderIdType[] 1
$fldarry[0] = $dTypeFld2
$msgList = $ewc.FindItems($fldarry, $drDuration, $null, "")
if ($msgList.Count -ne 0){
$mbcomb.Sent_Items_LastSent = $msgList[0].DateTimeSent.ToLocalTime().ToString()
}
$msTable.Rows.add($mbcomb.DisplayName,$mbcomb.EmailAddress,$mbcomb.Last_Logon,
$mbcomb.MailboxSize,$mbcomb.Inbox_Number_Unread,
$mbcomb.Inbox_Unread_LastRecieved,$mbcomb.Sent_Items_LastSent)
$mbcombCollection += $mbcomb}
}
$dgDataGrid.DataSource = $msTable
}

$msTable = New-Object System.Data.DataTable
$msTable.TableName = "Mailbox Info"
$msTable.Columns.Add("UserName")
$msTable.Columns.Add("EmailAddress")
$msTable.Columns.Add("Last Logon Time",[DateTime])
$msTable.Columns.Add("Mailbox Size(MB)",[int64])
$msTable.Columns.Add("Inbox Number Unread",[int64])
$msTable.Columns.Add("Inbox unread Last Recieved",[DateTime])
$msTable.Columns.Add("Sent Item Last Sent",[DateTime])



# Add Server DropLable
$snServerNamelableBox = new-object System.Windows.Forms.Label
$snServerNamelableBox.Location = new-object System.Drawing.Size(10,20)
$snServerNamelableBox.size = new-object System.Drawing.Size(80,20)
$snServerNamelableBox.Text = "ServerName"
$form.Controls.Add($snServerNamelableBox)

# Add Server Drop Down
$snServerNameDrop = new-object System.Windows.Forms.ComboBox
$snServerNameDrop.Location = new-object System.Drawing.Size(90,20)
$snServerNameDrop.Size = new-object System.Drawing.Size(150,30)
get-mailboxserver | ForEach-Object{$snServerNameDrop.Items.Add($_.Name)}
$form.Controls.Add($snServerNameDrop)

# Add Export Grid Button

$exButton2 = new-object System.Windows.Forms.Button
$exButton2.Location = new-object System.Drawing.Size(250,20)
$exButton2.Size = new-object System.Drawing.Size(125,20)
$exButton2.Text = "Execute"
$exButton2.Add_Click({Getinfo})
$form.Controls.Add($exButton2)


# Add Export Grid Button

$exButton1 = new-object System.Windows.Forms.Button
$exButton1.Location = new-object System.Drawing.Size(10,610)
$exButton1.Size = new-object System.Drawing.Size(125,20)
$exButton1.Text = "Export Grid"
$exButton1.Add_Click({ExportGrid})
$form.Controls.Add($exButton1)

# Add Impersonation Clause

$esImpersonationlableBox = new-object System.Windows.Forms.Label
$esImpersonationlableBox.Location = new-object System.Drawing.Size(10,75)
$esImpersonationlableBox.Size = new-object System.Drawing.Size(130,20)
$esImpersonationlableBox.Text = "Use EWS Impersonation"
$form.controls.Add($esImpersonationlableBox)

$seImpersonationCheck = new-object System.Windows.Forms.CheckBox
$seImpersonationCheck.Location = new-object System.Drawing.Size(150,70)
$seImpersonationCheck.Size = new-object System.Drawing.Size(30,25)
$form.controls.Add($seImpersonationCheck)

# Add Auth Clause

$esAuthlableBox = new-object System.Windows.Forms.Label
$esAuthlableBox.Location = new-object System.Drawing.Size(10,105)
$esAuthlableBox.Size = new-object System.Drawing.Size(130,20)
$esAuthlableBox.Text = "Specify Credentials"
$form.controls.Add($esAuthlableBox)

$seAuthCheck = new-object System.Windows.Forms.CheckBox
$seAuthCheck.Location = new-object System.Drawing.Size(140,100)
$seAuthCheck.Size = new-object System.Drawing.Size(30,25)
$seAuthCheck.Add_Click({if ($seAuthCheck.Checked -eq $true){
$unUserNameTextBox.Enabled = $true
$unPasswordTextBox.Enabled = $true
$unDomainTextBox.Enabled = $true
}
else{
$unUserNameTextBox.Enabled = $false
$unPasswordTextBox.Enabled = $false
$unDomainTextBox.Enabled = $false}})
$form.controls.Add($seAuthCheck)

# Add UserName Box
$unUserNameTextBox = new-object System.Windows.Forms.TextBox
$unUserNameTextBox.Location = new-object System.Drawing.Size(230,100)
$unUserNameTextBox.size = new-object System.Drawing.Size(100,20)
$form.controls.Add($unUserNameTextBox)

# Add UserName Lable
$unUserNamelableBox = new-object System.Windows.Forms.Label
$unUserNamelableBox.Location = new-object System.Drawing.Size(170,105)
$unUserNamelableBox.size = new-object System.Drawing.Size(60,20)
$unUserNamelableBox.Text = "UserName"
$unUserNameTextBox.Enabled = $false
$form.controls.Add($unUserNamelableBox)

# Add Password Box
$unPasswordTextBox = new-object System.Windows.Forms.TextBox
$unPasswordTextBox.PasswordChar = "*"
$unPasswordTextBox.Location = new-object System.Drawing.Size(400,100)
$unPasswordTextBox.size = new-object System.Drawing.Size(100,20)
$form.controls.Add($unPasswordTextBox)

# Add Password Lable
$unPasswordlableBox = new-object System.Windows.Forms.Label
$unPasswordlableBox.Location = new-object System.Drawing.Size(340,105)
$unPasswordlableBox.size = new-object System.Drawing.Size(60,20)
$unPasswordlableBox.Text = "Password"
$unPasswordTextBox.Enabled = $false
$form.controls.Add($unPasswordlableBox)

# Add Domain Box
$unDomainTextBox = new-object System.Windows.Forms.TextBox
$unDomainTextBox.Location = new-object System.Drawing.Size(550,100)
$unDomainTextBox.size = new-object System.Drawing.Size(100,20)
$form.controls.Add($unDomainTextBox)

# Add Domain Lable
$unDomainlableBox = new-object System.Windows.Forms.Label
$unDomainlableBox.Location = new-object System.Drawing.Size(510,105)
$unDomainlableBox.size = new-object System.Drawing.Size(50,20)
$unDomainlableBox.Text = "Domain"
$unDomainTextBox.Enabled = $false
$form.controls.Add($unDomainlableBox)


# Add CASUrl Box
$unCASUrlTextBox = new-object System.Windows.Forms.TextBox
$unCASUrlTextBox.Location = new-object System.Drawing.Size(280,75)
$unCASUrlTextBox.size = new-object System.Drawing.Size(400,20)
$unCASUrlTextBox.text = $strRootURI
$form.Controls.Add($unCASUrlTextBox)

# Add CASUrl Lable
$unCASUrllableBox = new-object System.Windows.Forms.Label
$unCASUrllableBox.Location = new-object System.Drawing.Size(200,75)
$unCASUrllableBox.size = new-object System.Drawing.Size(50,20)
$unCASUrllableBox.Text = "CASUrl"
$form.Controls.Add($unCASUrllableBox)

# Add DataGrid View

$dgDataGrid = new-object System.windows.forms.DataGridView
$dgDataGrid.Location = new-object System.Drawing.Size(10,145)
$dgDataGrid.size = new-object System.Drawing.Size(1000,450)
$dgDataGrid.AutoSizeRowsMode = "AllHeaders"
$form.Controls.Add($dgDataGrid)



$form.Text = "Exchange 2007 Unused Mailbox Form"
$form.size = new-object System.Drawing.Size(1200,700)
$form.autoscroll = $true
$form.Add_Shown({$form.Activate()})
$form.ShowDialog()

Popular posts from this blog

The MailboxConcurrency limit and using Batching in the Microsoft Graph API

If your getting an error such as Application is over its MailboxConcurrency limit while using the Microsoft Graph API this post may help you understand why. Background   The Mailbox  concurrency limit when your using the Graph API is 4 as per https://docs.microsoft.com/en-us/graph/throttling#outlook-service-limits . This is evaluated for each app ID and mailbox combination so this means you can have different apps running under the same credentials and the poor behavior of one won't cause the other to be throttled. If you compared that to EWS you could have up to 27 concurrent connections but they are shared across all apps on a first come first served basis. Batching Batching in the Graph API is a way of combining multiple requests into a single HTTP request. Batching in the Exchange Mail API's EWS and MAPI has been around for a long time and its common, for email Apps to process large numbers of smaller items for a variety of reasons.  Batching in the Gr...

EWS-FAI Module for browsing and updating Exchange Folder Associated Items from PowerShell

Folder Associated Items are hidden Items in Exchange Mailbox folders that are commonly used to hold configuration settings for various Mailbox Clients and services that use Mailboxes. Some common examples of FAI's are Categories,OWA Signatures and WorkHours there is some more detailed documentation in the https://msdn.microsoft.com/en-us/library/cc463899(v=exchg.80).aspx protocol document. In EWS these configuration items can be accessed via the UserConfiguration operation https://msdn.microsoft.com/en-us/library/office/dd899439(v=exchg.150).aspx which will give you access to either the RoamingDictionary, XMLStream or BinaryStream data properties that holds the configuration depending on what type of FAI data is being stored. I've written a number of scripts over the years that target particular FAI's (eg this one that reads the workhours  http://gsexdev.blogspot.com.au/2015/11/finding-timezone-being-used-in-mailbox.html is a good example ) but I didn't have a gene...

Sending a MimeMessage via the Microsoft Graph using the Graph SDK, MimeKit and MSAL

One of the new features added to the Microsoft Graph recently was the ability to create and send Mime Messages (you have been able to get Message as Mime for a while). This is useful in a number of different scenarios especially when trying to create a Message with inline Images which has historically been hard to do with both the Graph and EWS (if you don't use MIME). It also opens up using SMIME for encryption and a more easy migration path for sending using SMTP in some apps. MimeKit is a great open source library for parsing and creating MIME messages so it offers a really easy solution for tackling this issue. The current documentation on Send message via MIME lacks any real sample so I've put together a quick console app that use MSAL, MIME kit and the Graph SDK to send a Message via MIME. As the current Graph SDK also doesn't support sending via MIME either there is a workaround for this in the future my guess is this will be supported.
All sample scripts and source code is provided by for illustrative purposes only. All examples are untested in different environments and therefore, I cannot guarantee or imply reliability, serviceability, or function of these programs.

All code contained herein is provided to you "AS IS" without any warranties of any kind. The implied warranties of non-infringement, merchantability and fitness for a particular purpose are expressly disclaimed.