I thought of a workaround, so I used AI to create a script that may help you out. When the script runs, if the number of messages in an account exceeds the threshold passed to it, it will enable quota restrictions and set the limit to 1. Forcing the account into an over quota situation. When the script runs and there are less messages in the account than the threshold, it will turn off quotas for the account. The script has had very limited testing, so I would highly reccomend that you test it in your environment before deploying into production. The current script does not offer any way to exempt an account, it applies to all users of all domains. Please feel free to modify the script to work in your environment.
<#
.SYNOPSIS
Enforces or releases per-account "over quota" state on MDaemon mailboxes
based on the current on-disk message count.
.DESCRIPTION
For every MDaemon user account, this script reads the current stored-message
count via the MDaemon XML Management API (GetDomainList + GetDomainInfo with
<Get><Users><Quotas/></Users></Get>). When the count exceeds -Threshold the
account is forced into over-quota state by calling UpdateUser with
ApplyQuotas=Yes and MaxMessageCount=1. When the count is at or below the
threshold, ApplyQuotas is set to No to release the account.
The on-disk count is read via the API rather than Hiwater.mrk directly so
that any user whose cache is missing or stale is silently refreshed on the
server side as a side effect of the GetDomainInfo call.
.PARAMETER Threshold
Message-count threshold X. Any user with count > X is enforced; <= X
releases.
.PARAMETER ServerUrl
Base URL of the MDaemon XML API. Defaults to http://localhost:5480.
.PARAMETER Credential
Admin credentials for the initial Logon call. If omitted, Get-Credential
prompts.
.PARAMETER LogPath
Append-only log file. Defaults to .\Set-MdaemonOverQuota.log.
.PARAMETER DryRun
Report intended changes without calling UpdateUser.
.PARAMETER NoSkipUnchanged
By default, users whose current ApplyQuotas already matches the desired
state are skipped. Pass this switch to issue UpdateUser unconditionally.
.EXAMPLE
.\Set-MdaemonOverQuota.ps1 -Threshold 5000 -DryRun
.EXAMPLE
.\Set-MdaemonOverQuota.ps1 -X 5000 -ServerUrl http://mail.example.com:5480
#>
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[Alias('X')]
[int]$Threshold,
[string]$ServerUrl = 'http://localhost:5480',
[System.Management.Automation.PSCredential]$Credential,
[string]$LogPath = (Join-Path -Path (Get-Location) -ChildPath 'Set-MdaemonOverQuota.log'),
[switch]$DryRun,
[switch]$NoSkipUnchanged
)
$ErrorActionPreference = 'Stop'
$SkipUnchanged = -not $NoSkipUnchanged
function Write-Log {
param([string]$Message, [string]$Level = 'INFO')
$line = '{0} {1,-5} {2}' -f (Get-Date -Format 'yyyy-MM-dd HH:mm:ss'), $Level, $Message
Add-Content -Path $LogPath -Value $line
Write-Host $line
}
function Invoke-MdApi {
param(
[Parameter(Mandatory)] [string]$BodyXml,
[string]$Token,
[System.Management.Automation.PSCredential]$BasicCredential
)
$headers = @{}
if ($BasicCredential) {
$pair = '{0}:{1}' -f $BasicCredential.UserName, $BasicCredential.GetNetworkCredential().Password
$b64 = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes($pair))
$headers['Authorization'] = "Basic $b64"
}
if ($Token) {
$headers['X-MDAPI-TOKEN'] = $Token
}
$uri = ($ServerUrl.TrimEnd('/')) + '/MdMgmtWS'
try {
$response = Invoke-WebRequest -Uri $uri -Method Post -Headers $headers `
-ContentType 'text/xml' -Body $BodyXml -UseBasicParsing
}
catch {
throw "HTTP error calling $uri : $($_.Exception.Message)"
}
try {
[xml]$xml = $response.Content
}
catch {
throw "Server returned non-XML response: $($response.Content)"
}
$status = $xml.MDaemon.API.Response.Status
if (-not $status) {
throw "Server response had no <Status> element. Body: $($response.Content)"
}
if ([int]$status.id -ne 0) {
throw "API error: id=$($status.id) value=$($status.value) message=$($status.message)"
}
return $xml
}
function New-RequestEnvelope {
param([string]$Operation, [string]$ParametersXml = '<Parameters/>')
@"
<?xml version="1.0" encoding="utf-8"?>
<MDaemon>
<API>
<Request version="25.0">
<Operation>$Operation</Operation>
$ParametersXml
</Request>
</API>
</MDaemon>
"@
}
# ----- Begin -----
if (-not $Credential) {
$Credential = Get-Credential -Message 'Enter MDaemon administrator credentials'
}
Write-Log "Starting quota sweep. Threshold=$Threshold ServerUrl=$ServerUrl DryRun=$($DryRun.IsPresent)"
# 1. Logon
Write-Log 'Logging on…'
$logonBody = New-RequestEnvelope -Operation 'Logon'
$logonXml = Invoke-MdApi -BodyXml $logonBody -BasicCredential $Credential
$Token = [string]$logonXml.MDaemon.API.Response.Result.Token
if (-not $Token) { throw 'Logon succeeded but no token was returned.' }
Write-Log "Logon successful. Session timeout: $($logonXml.MDaemon.API.Response.Result.Timeout)s"
$enforced = 0
$released = 0
$unchanged = 0
$errors = 0
try {
# 2. Enumerate domains
Write-Log 'Fetching domain list…'
$domainListBody = New-RequestEnvelope -Operation 'GetDomainList' `
-ParametersXml '<Parameters><Get><Users/></Get></Parameters>'
$domainListXml = Invoke-MdApi -BodyXml $domainListBody -Token $Token
$domains = @($domainListXml.MDaemon.API.Response.Result.Domains.Domain)
Write-Log "Found $($domains.Count) domain(s)."
# 3. Per-domain quota fetch + per-user evaluation
foreach ($d in $domains) {
$domainName = [string]$d.id
Write-Log "Processing domain '$domainName'…"
$infoBody = New-RequestEnvelope -Operation 'GetDomainInfo' -ParametersXml @"
<Parameters>
<Domain>$domainName</Domain>
<Get><Users><Quotas/></Users></Get>
</Parameters>
"@
try {
$infoXml = Invoke-MdApi -BodyXml $infoBody -Token $Token
}
catch {
Write-Log "GetDomainInfo failed for '$domainName': $_" 'ERROR'
$errors++
continue
}
$users = @($infoXml.MDaemon.API.Response.Result.Domain.Users.User)
Write-Log " $($users.Count) user(s) in '$domainName'."
foreach ($u in $users) {
$mailbox = [string]$u.id
if (-not $mailbox) { continue } # skip the <MailboxRoot/> sentinel
$quotas = $u.Quotas
if (-not $quotas) {
Write-Log " ${mailbox}@${domainName}: no <Quotas> element returned, skipping." 'WARN'
continue
}
$currentApply = [string]$quotas.ApplyQuotas
$itemsRaw = [string]$quotas.Usage.Items
if ([string]::IsNullOrWhiteSpace($itemsRaw)) {
Write-Log " ${mailbox}@${domainName}: no <Usage><Items> value, skipping." 'WARN'
continue
}
$msgCount = [int]$itemsRaw
$desired = if ($msgCount -gt $Threshold) { 'Yes' } else { 'No' }
if ($SkipUnchanged -and ($currentApply -eq $desired)) {
Write-Log " ${mailbox}@${domainName}: count=$msgCount ApplyQuotas=$currentApply (no change)"
$unchanged++
continue
}
$action = if ($desired -eq 'Yes') { 'ENFORCE' } else { 'RELEASE' }
Write-Log " ${mailbox}@${domainName}: count=$msgCount $action (was ApplyQuotas=$currentApply)"
if ($DryRun) {
if ($desired -eq 'Yes') { $enforced++ } else { $released++ }
continue
}
$updateBody = New-RequestEnvelope -Operation 'UpdateUser' -ParametersXml @"
<Parameters>
<Domain>$domainName</Domain>
<Mailbox>$mailbox</Mailbox>
<Quotas>
<ApplyQuotas>$desired</ApplyQuotas>
<MaxMessageCount>1</MaxMessageCount>
</Quotas>
</Parameters>
"@
try {
Invoke-MdApi -BodyXml $updateBody -Token $Token | Out-Null
if ($desired -eq 'Yes') { $enforced++ } else { $released++ }
}
catch {
Write-Log " ${mailbox}@${domainName}: UpdateUser failed: $_" 'ERROR'
$errors++
}
}
}
}
finally {
# 4. Logoff (best effort)
try {
$logoffBody = New-RequestEnvelope -Operation 'Logoff'
Invoke-MdApi -BodyXml $logoffBody -Token $Token | Out-Null
Write-Log 'Logged off.'
}
catch {
Write-Log "Logoff failed: $_" 'WARN'
}
}
$prefix = if ($DryRun) { '[DRY RUN] ' } else { '' }
Write-Log "${prefix}Summary: enforced=$enforced released=$released unchanged=$unchanged errors=$errors"