Symptoms
When you run the Get-MailboxStatistics cmdlet to verify the status of a mailbox quota in a Microsoft Exchange Server 2013 environment, the StorageLimitStatus field in the results is empty.
Cause
This behavior is by design.
Unlike versions of Exchange Server Information Store earlier than Exchange Server 2013 Information Store, the Exchange Server 2013 Information Store does not cache the values of mailbox quotas. Therefore, the Information Store makes frequent calls to Active Directory to retrieve the values of mailbox quotas for each mailbox that is specified in the Get-MailboxStatistics cmdlet. Because of the frequent calls to Active Directory, you may experience poor performance in Exchange Server. To avoid poor performance in Exchange Server, the default Get-MailboxStatistics cmdlet does not retrieve the mailbox quotas and does not display a value in the StorageLimitStatus field.
So what does this tell us? Basically if you were hoping to generate a report with accurate data on the Storage Limit Status of all mailboxes in an environment, you are out of luck. A sample examination of an Exchange 2013 Server with the issue looks like this:
Notice the multiple blank lines for the Storage Limit Status. What to do? How do we generate a report of these values? PowerShell.
$array = @() $array2 = @() $mailboxes = get-mailbox # This section gets the mailbox size and formats it to MB foreach ($line in $mailboxes) { $user = $line.alias $size2 = get-mailboxstatistics $user -erroraction silentlycontinue if ($size2 -ne $null) { $size = $size2.TotalItemSize.Value.ToMB() } $array += @(,($user,$size)) } # This section gets the Prohibit Send Receive Quota and formats it to MB foreach ($line in $array) { $user = $line[0] $size = $line[1] If ($user -notmatch 'DiscoverySearch') { $quota2 = get-mailbox $user $quotapsr = $quota2.ProhibitSendReceiveQuota if ($quotapsr -ne "unlimited") { $quotapsr = $quota2.ProhibitSendReceiveQuota.Value.ToMB() if ($size -gt $quotapsr) { $quotacheckpsr = "Over" } else { $quotacheckpsr = "Under" } } else { $quotacheckpsr = "NoChecking" } $quotaiw = $quota2.IssueWarningQuota if ($quotaiw -ne "unlimited") { $quotaiw = $quota2.IssueWarningQuota.Value.ToMB() if ($size -gt $quotaiw) { $quotacheckiw = "Over" } else { $quotacheckiw = "Under" } } else { $quotacheckiw = "NoChecking" } $quotaps = $quota2.ProhibitSendQuota if ($quotaps -ne "unlimited") { $quotaps = $quota2.ProhibitSendQuota.Value.ToMB() if ($size -gt $quotaps) { $quotacheckps = "Over" } else { $quotacheckps = "Under" } } else { $quotacheckps = "NoChecking" } $array2 += @(,($user,$size,$quotacheckiw,$quotaiw,$quotacheckps,$quotaps,$quotacheckpsr,$quotapsr)) } } # Display Over the limit for Issue Warning Quota foreach ($line in $array2) { if ($line[2] -eq "Over") { write-host "The mailbox for"$line[0]"is " -nonewline write-host "OVER the Issue Warning Quota, " -ForegroundColor red -nonewline } else { write-host "The mailbox for"$line[0]"is " -nonewline write-host "UNDER the Issue Warning Quota, " -ForegroundColor green -nonewline } if ($line[4] -eq "Over") { write-host "OVER the Prohibit Send Quota," -ForegroundColor red -nonewline } else { write-host "UNDER the Prohibit Send Quota," -ForegroundColor green -nonewline } if ($line[6] -eq "Over") { write-host " and " -nonewline write-host "OVER the Prohibit Send Receive Quota." -ForegroundColor red } else { write-host " and " -nonewline write-host "UNDER the Prohibit Send Receive Quota." -ForegroundColor green } }
The resulting report should look something like this:
Notice the users who are over the Issue Warning Quota:
Users who are over the Send Quota:
Users that are over all three quotas:
Alternatively, the script could be modified to display only those users who are over their quotas if the report needed to be simpler. Modify lines 55-76:
foreach ($line in $array2) { if ($line[2] -eq "Over" -and $line[4] -ne "Over" -and $line[6] -ne "Over") { write-host "The mailbox for"$line[0]"is " -nonewline write-host "OVER the Issue Warning Quota." -ForegroundColor red } if ($line[2] -eq "Over" -and $line[4] -eq "Over" -and $line[6] -ne "Over") { write-host "The mailbox for"$line[0]"is " -nonewline write-host "OVER the Issue Warning Quota and OVER the Prohibit Send Quota." -ForegroundColor red } if ($line[2] -eq "Over" -and $line[4] -eq "Over" -and $line[6] -eq "Over") { write-host "The mailbox for"$line[0]"is " -nonewline write-host "OVER the Issue Warning Quota, OVER the Prohibit Send Quota and OVER the Prohibit Send Receive Quota." -ForegroundColor red } if ($line[2] -ne "Over" -and $line[4] -eq "Over" -and $line[6] -ne "Over") { write-host "The mailbox for"$line[0]"is " -nonewline write-host "OVER the Prohibit Send Quota." -ForegroundColor red -nonewline } if ($line[2] -ne "Over" -and $line[4] -ne "Over" -and $line[6] -eq "Over") { write-host "The mailbox for"$line[0]"is " -nonewline write-host "OVER the Prohibit Send Receive Quota." -ForegroundColor red } if ($line[2] -ne "Over" -and $line[4] -eq "Over" -and $line[6] -eq "Over") { write-host "The mailbox for"$line[0]"is " -nonewline write-host "OVER the Prohibit Send Quota and OVER the Prohibit Send Receive Quota." -ForegroundColor red } }
Hope this helps someone looking for simple quota reports. There are some bugs, yellow warning messages, and red warnings that occur when I run the script. Look for an updated script in a week. Also, if your environment has over 1000 mailboxes, you may need the ‘-resultsize unlimited’ option on some commands in the script.
Hi
when I run the script (in 2013) I get errors below – can you help?
Is the script downloadable?
Thanks
At C:\ps\size.ps1:17 char:24
+ If ($user -notmatch "DiscoverySearch") {
+ ~
You must provide a value expression on the right-hand side of the ‘-notmatch’ operator.
At C:\ps\size.ps1:17 char:25
+ If ($user -notmatch "DiscoverySearch") {
+ ~
Unexpected token ‘&’ in expression or statement.
At C:\ps\size.ps1:17 char:25
+ If ($user -notmatch "DiscoverySearch") {
+ ~
Missing closing ‘)’ after expression in ‘If’ statement.
At C:\ps\size.ps1:17 char:46
+ If ($user -notmatch "DiscoverySearch") {
+ ~
Ampersand not allowed. The & operator is reserved for future use; use “&” to pass ampersand as a string.
At C:\ps\size.ps1:14 char:27
+ foreach ($line in $array) {
+ ~
Missing closing ‘}’ in statement block.
At C:\ps\size.ps1:17 char:52
+ If ($user -notmatch "DiscoverySearch") {
+ ~
Unexpected token ‘)’ in expression or statement.
At C:\ps\size.ps1:20 char:26
+ if ($quotapsr -ne "unlimited") {
+ ~
You must provide a value expression on the right-hand side of the ‘-ne’ operator.
At C:\ps\size.ps1:20 char:27
+ if ($quotapsr -ne "unlimited") {
+ ~
Unexpected token ‘&’ in expression or statement.
At C:\ps\size.ps1:20 char:27
+ if ($quotapsr -ne "unlimited") {
+ ~
Missing closing ‘)’ after expression in ‘if’ statement.
At C:\ps\size.ps1:20 char:42
+ if ($quotapsr -ne "unlimited") {
+ ~
Ampersand not allowed. The & operator is reserved for future use; use “&” to pass ampersand as a string.
Not all parse errors were reported. Correct the reported errors and try again.
+ CategoryInfo : ParserError: (:) [], ParseException
+ FullyQualifiedErrorId : ExpectedValueExpression
Hi
I get errors below:
Can you help? Is the script downloadable?
Thanks
At C:\ps\size.ps1:17 char:24
+ If ($user -notmatch "DiscoverySearch") {
+ ~
You must provide a value expression on the right-hand side of the ‘-notmatch’ operator.
At C:\ps\size.ps1:17 char:25
+ If ($user -notmatch "DiscoverySearch") {
+ ~
Unexpected token ‘&’ in expression or statement.
At C:\ps\size.ps1:17 char:25
+ If ($user -notmatch "DiscoverySearch") {
+ ~
Missing closing ‘)’ after expression in ‘If’ statement.
At C:\ps\size.ps1:17 char:46
+ If ($user -notmatch "DiscoverySearch") {
+ ~
Ampersand not allowed. The & operator is reserved for future use; use “&” to pass ampersand as a string.
At C:\ps\size.ps1:14 char:27
+ foreach ($line in $array) {
+ ~
Missing closing ‘}’ in statement block.
At C:\ps\size.ps1:17 char:52
+ If ($user -notmatch "DiscoverySearch") {
+ ~
Unexpected token ‘)’ in expression or statement.
At C:\ps\size.ps1:20 char:26
+ if ($quotapsr -ne "unlimited") {
+ ~
You must provide a value expression on the right-hand side of the ‘-ne’ operator.
At C:\ps\size.ps1:20 char:27
+ if ($quotapsr -ne "unlimited") {
+ ~
Unexpected token ‘&’ in expression or statement.
At C:\ps\size.ps1:20 char:27
+ if ($quotapsr -ne "unlimited") {
+ ~
Missing closing ‘)’ after expression in ‘if’ statement.
At C:\ps\size.ps1:20 char:42
+ if ($quotapsr -ne "unlimited") {
+ ~
Ampersand not allowed. The & operator is reserved for future use; use “&” to pass ampersand as a string.
Not all parse errors were reported. Correct the reported errors and try again.
+ CategoryInfo : ParserError: (:) [], ParseException
+ FullyQualifiedErrorId : ExpectedValueExpression
Seems as if my Word Press plugin for PowerShell code did not encapsulate the code correctly… all fixed now.
Hi I created email report from this example with quotas
$i=0
$imax=20 #20
foreach($MailBox in $GetMailbox)
{
$MailBoxDisplayName = $MailBox.DisplayName
$MailBoxTotalItemSize = $MailBox.TotalItemSize.Value.ToMB()
$MailBoxItemCount = $MailBox.ItemCount
#$MailBoxStorageLimitStatus = $MailBox.StorageLimitStatus
$MailBoxLastLogonTime = $MailBox.LastLogonTime
$quota = get-mailbox $MailBoxDisplayName
$quotaiw = $quota.IssueWarningQuota.Value.ToMB()
$quotaps = $quota.ProhibitSendQuota.Value.ToMB()
$quotapsr = $quota.ProhibitSendReceiveQuota.Value.ToMB()
$MailBoxStorageLimitStatus = $quotaiw
#Write-Host “$db”
#Write-Host “$MailBoxDisplayName – $MailBoxItemCount – $MailBoxTotalItemSize – $MailBoxStorageLimitStatus – $MailBoxLastLogonTime”
# Set background color to Orange if just a warning
#warning 1991680 | Prohibit Send 2097152 | Prohibit send and receive 2411520
$KBcolor = $GreenColor
if($MailBoxTotalItemSize -gt $quotaiw) # 1991680
{
$KBcolor = $YellowColor
}
if($MailBoxTotalItemSize -gt $quotaps) # 2097152
{
$KBcolor = $OrangeColor
}
if($MailBoxTotalItemSize -gt $quotapsr) # 2411520
{
$KBcolor = $RedColor
}
# Create table data rows
$dataRow = ”
$MailBoxDisplayName
$MailBoxItemCount
$MailBoxTotalItemSize
$quotaiw
$quotaps
$quotapsr
$MailBoxLastLogonTime
”
if($i -lt $imax)
{
Add-Content $diskReport $dataRow;
$i++
}
}
Hi!
I get this error when I run the Script on Exchange 2016
Method invocation failed because [Deserialized.Microsoft.Exchange.Data.ByteQuantifiedSize] does not contain a method named ‘ToMB’.
At C:\Users\shlomir\Desktop\Mailbox Quota Report.ps1:9 char:9
+ $size = $size2.TotalItemSize.Value.ToMB()
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (ToMB:String) [], RuntimeException
+ FullyQualifiedErrorId : MethodNotFound
Please help
I just ran the script on my 2016 server and there were no issues. Assume you are running this in an Exchange PowerShell window? What version of Exchange 2016 do you have?
Now, after you asked I run it on the Exchange shell and all good. But there is a lot information that not fit well to the windows. What is the parameter to export the result to CSV?
Thank you
There are a couple ways to handle this. One, you can widen the width of the PowerShell window which would allow you to copy the information on the screen. The second method is to go the CSV route like you asked. Here is one option, which is a quick rewrite the output code to output to a file like so:
$Destination = ‘QuotaOutput.csv’
Foreach ($line in $array2) {
if ($line[2] -eq “Over”) {
$Output1 = “The mailbox for ” + $line[0] + ” is OVER the Issue Warning Quota,”
} else {
$Output1 = “The mailbox for ” + $line[0] + ” is UNDER the Issue Warning Quota,”
}
if ($line[4] -eq “Over”) {
$Output2 = “OVER the Prohibit Send Quota,”
} else {
$Output2 = “UNDER the Prohibit Send Quota,”
}
if ($line[6] -eq “Over”) {
$Output3 = “and OVER the Prohibit Send Receive Quota.”
} else {
$Output3 = “and UNDER the Prohibit Send Receive Quota.”
}
$LineOut = “$Output1 $Output2 $Output3” | Out-File $Destination -Append
}
Let me know if that works.
This is Work perfectly!
God bless you.
Thank you so much!