I often receive questions from people who are looking at some PowerShell examples here on Exchange Server Pro but want to know how to combine the output from different examples into a single script or report.
This is something I do in almost all of the PowerShell scripts I’ve published here, and you’re free to look at the code in them and use it elsewhere or customize it for your own needs. But I also wanted to give you a simple demonstration of the technique here.
Let’s say you want to write a script that will tell you the name, department, database name, and mailbox storage quota info for a mailbox.
Those are all pieces of information we can get from different PowerShell cmdlets:
- Name can come from Get-Mailbox, Get-Recipient, or Get-MailboxStatistics (and others for that matter)
- Department can come from Get-Recipient
- Database name can come from Get-Mailbox or Get-MailboxStatistics
- Get-Mailbox will also tell us if the mailbox is configured to use the database default quota values
- The storage limit status (above or below quota limit) comes from Get-MailboxStatistics
- The quota levels themselves can come from Get-Mailbox or Get-MailboxDatabase, depending on whether the mailbox is using database quota defaults or not
So as you can see the data we’re interested in can come from multiple cmdlets.
So now let’s build a simple script that fetches the data using those multiple PowerShell cmdlets, and then uses a PowerShell custom object to combine it all for output.
First, let’s fetch the data (my script has a parameter -Mailbox, hence the $mailbox in the example here).
#Fetch the various bits of data we're interested in $mbx = Get-Mailbox $Mailbox $recipient = Get-Recipient $mailbox $mbxstats = Get-MailboxStatistics $mailbox $database = Get-MailboxDatabase $mbx.Database
Next, we can create a custom object. Where I’m using $MailboxObject you can really use anything you like. I often simply use $ReportObj.
#Create the custom object $MailboxObject = New-Object PSObject
Now let’s start adding properties and values to the custom object.
#Begin adding the values to the custom object properties $MailboxObject | Add-Member NoteProperty -Name "Name" -Value $mbx.Name $MailboxObject | Add-Member NoteProperty -Name "Department" -Value $recipient.Department $MailboxObject | Add-Member NoteProperty -Name "Storage Limit Status" -Value $mbxstats.StorageLimitStatus $MailboxObject | Add-Member NoteProperty -Name "Database" -Value $mbx.Database $MailboxObject | Add-Member NoteProperty -Name "Uses Database Quota Defaults" -Value $mbx.UseDatabaseQuotaDefaults
As you can see it is as simple as giving each property a unique name, such as “Department”, and then assigning the value for that property such as $recipient.Department (remember that $recipient is what I fetched earlier with Get-Recipient).
You don’t need to match the property names and values precisely. I could just as easily use this instead:
$MailboxObject | Add-Member NoteProperty -Name "Dept" -Value $recipient.Department
But obviously for neatness and readability it pays to use property names that make sense.
Now comes the only “tricky” part of this script. If the mailbox is configured to use the database quota defaults, then we want to grab those values from the database. However if the mailbox is not using the default quota values, then we want to grab those values from the mailbox.
#If the mailbox is configured to use the database quota defaults, we collect those values from the database if ($($mbx.UseDatabaseQuotaDefaults) -eq $true) { $MailboxObject | Add-Member NoteProperty -Name "Warning Quota" -Value $database.IssueWarningQuota $MailboxObject | Add-Member NoteProperty -Name "Send Quota" -Value $database.ProhibitSendQuota $MailboxObject | Add-Member NoteProperty -Name "Send Receive Quota" -Value $database.ProhibitSendReceiveQuota } #Otherwise, we want the quota values from the mailbox itself else { $MailboxObject | Add-Member NoteProperty -Name "Warning Quota" -Value $mbx.IssueWarningQuota $MailboxObject | Add-Member NoteProperty -Name "Send Quota" -Value $mbx.ProhibitSendQuota $MailboxObject | Add-Member NoteProperty -Name "Send Receive Quota" -Value $mbx.ProhibitSendReceiveQuota }
Finally, output the custom object.
#Output the results $MailboxObject
Here is the complete script code, including the -Mailbox parameter that is used when running the script.
# # Check-QuotaStatus.ps1 # #requires -version 2 [CmdletBinding()] param ( [Parameter( Mandatory=$true)] [string]$Mailbox ) #Fetch the various bits of data we're interested in $mbx = Get-Mailbox $Mailbox $recipient = Get-Recipient $mailbox $mbxstats = Get-MailboxStatistics $mailbox $database = Get-MailboxDatabase $mbx.Database #Create the custom object $MailboxObject = New-Object PSObject #Begin adding the values to the custom object properties $MailboxObject | Add-Member NoteProperty -Name "Name" -Value $mbx.Name $MailboxObject | Add-Member NoteProperty -Name "Department" -Value $recipient.Department $MailboxObject | Add-Member NoteProperty -Name "Storage Limit Status" -Value $mbxstats.StorageLimitStatus $MailboxObject | Add-Member NoteProperty -Name "Database" -Value $mbx.Database $MailboxObject | Add-Member NoteProperty -Name "Uses Database Quota Defaults" -Value $mbx.UseDatabaseQuotaDefaults #If the mailbox is configured to use the database quota defaults, we collect those values from the database if ($($mbx.UseDatabaseQuotaDefaults) -eq $true) { $MailboxObject | Add-Member NoteProperty -Name "Warning Quota" -Value $database.IssueWarningQuota $MailboxObject | Add-Member NoteProperty -Name "Send Quota" -Value $database.ProhibitSendQuota $MailboxObject | Add-Member NoteProperty -Name "Send Receive Quota" -Value $database.ProhibitSendReceiveQuota } #Otherwise, we want the quota values from the mailbox itself else { $MailboxObject | Add-Member NoteProperty -Name "Warning Quota" -Value $mbx.IssueWarningQuota $MailboxObject | Add-Member NoteProperty -Name "Send Quota" -Value $mbx.ProhibitSendQuota $MailboxObject | Add-Member NoteProperty -Name "Send Receive Quota" -Value $mbx.ProhibitSendReceiveQuota } #Output the results $MailboxObject
Now let’s see the result when we run the script against some mailboxes.
[PS] C:Scripts>.Check-QuotaStatus.ps1 -Mailbox alan.reid Name : Alan.Reid Department : Finance Office Storage Limit Status : BelowLimit Database : MB-HO-04 Uses Database Quota Defaults : True Warning Quota : 18.99 GB (20,394,803,200 bytes) Send Quota : 20 GB (21,474,836,480 bytes) Send Receive Quota : 23 GB (24,693,964,800 bytes) [PS] C:Scripts>.Check-QuotaStatus.ps1 -Mailbox alex.heyne Name : Alex.Heyne Department : Storage Limit Status : BelowLimit Database : MB-BR-01 Uses Database Quota Defaults : False Warning Quota : 7.813 GB (8,388,608,000 bytes) Send Quota : 8.789 GB (9,437,184,000 bytes) Send Receive Quota : unlimited
I hope that helps you understand how you can use PowerShell custom objects in your scripting tasks. If you have any questions or would like to see this concept covered in more depth please feel free to leave a comment below.
How would you run this against all your mailboxes?
Hi Paul,
Many thanks for this, been trying to get an output that will show all shared mailboxes that haven’t been used for 30 days and longer. What would be the script for that?
Thanks,
John
This is exactly what I have been trying to find. Thanks for that. I do have one question for you. We have a bunch of test mailboxes that have not been logged into yet. Therefore, they do not return any data when we run get-mailboxstatistics. Do you know of an easy way to hit all these mailboxes so that we can export a complete list of our mailboxes that also include totalitemsize?
Something that would update the last logged in flag?
The Real Person!
Author Paul Cunningham acts as a real person and passed all tests against spambots. Anti-Spam by CleanTalk.
Send them an email. You could do it manually from Outlook, or run a Send-MailMessage command in PowerShell, or even set up an automated welcome email for your entire organization so new user mailboxes get at least one mail item after they’re created.
https://www.ucunleashed.com/175
Hi Paul, this script is great. Can you tell me how I would run this script against specific mailbox servers to get results on all mailbox recipients in a specific domain?
Thanks,
China
The Real Person!
Author Paul Cunningham acts as a real person and passed all tests against spambots. Anti-Spam by CleanTalk.
This is just a conceptual demo. But it comes from a more featured script that I’ve published, Get-MailboxReport.ps1
https://www.practical365.com/powershell-script-create-mailbox-size-report-exchange-server-2010/
Note that running against a “server” doesn’t work the same as it used to in 2007 and prior, because mailboxes are homed to databases, not servers (even in a single server deployment).
But, you can simply run the script for your entire org and filter the CSV file in Excel to get the subset of users that you’re interested in.
Paul, thank you for your valuable contributions to the Exchange world and for your swift reply!
Hi Paul,
I tested this scrip, but it does not show “Storage Limit Status”. Found the below article about the problem.
It seems by design on of exchange 2013.
http://support.microsoft.com/kb/2819389
Is there any other command we can use to get “StorageLimitStatus” ?
Cheers,
Chamara
The Real Person!
Author Paul Cunningham acts as a real person and passed all tests against spambots. Anti-Spam by CleanTalk.
You could probably achieve the same thing by comparing the mailbox size to the configured quota levels on the mailbox.
I would reccomend against using “Add-Member NoteProperty…”, its the old way of adding things to an obeject which looks ugly and its alot slower (mainly due to the pipes). Changing your PSObject style makes a huge difference when you have a lot of servers and/or users to report on.
http://blogs.msdn.com/b/powershell/archive/2009/12/05/new-object-psobject-property-hashtable.aspx
http://learn-powershell.net/2010/09/19/custom-powershell-objects-and-performance/
Hi Paul, great article. You can do properties on custom objects easily using hashtables:
New-Object -Type PSObject -Properties @{
“Send Quota” = $database.ProhibitSendQuota;
“Warning Quota” = $database.IssueWarningQuota
}
etc.
This can save a lot of typing and looks (in my opinion) a fair bit better.