C# and Remote PowerShell - Lookup Smallest Mailbox Database

The following example can be used to return the smallest available mailbox database with a given name pattern. This might be useful if you're running multiple mailbox databases with similar names: Database 1, Database 2, Database 3, etc.. You can pass in a search for "Database*" and it will find all matches with that name, using * as the wildcard and return the smallest of the databases. This could be useful for migration of mailboxes or during new mailbox account creations.

When creating multiple new accounts at once, this might not be the best approach as it could put multiple 0 sized mailboxes on the same database. An alternative approach would be to have it sort by the number of mailboxes on the database, as well as the size to determine new mailbox placement.

/// <summary>
// Returns the next available mailbox database for account creation (smallest DB).
/// </summary>
/// <param name="mailboxName">The name or pattern of the mailbox databases</param>
/// <param name="exchangeRemoteServer">The exchange server address: https://exchange.domain.org</param>
/// <returns></returns>
public string GetNextMailboxDatabase(string mailboxName, string exchangeRemoteServer)
{
 string nextMailboxDatabase = string.Empty;
 try
 {
  WSManConnectionInfo connectionInfo = new WSManConnectionInfo(
     new Uri(exchangeRemoteServer),
     "http://schemas.microsoft.com/powershell/Microsoft.Exchange", // This shouldn't change
     PSCredential.Empty
     );
  // Skip Certificate Verification
  connectionInfo.SkipCACheck = true;
  connectionInfo.SkipCNCheck = true;
  connectionInfo.SkipRevocationCheck = true;
  connectionInfo.AuthenticationMechanism = AuthenticationMechanism.NegotiateWithImplicitCredential;
  
  using (Runspace runspace = RunspaceFactory.CreateRunspace(connectionInfo))
  {
   using (PowerShell powershell = PowerShell.Create())
   {
    StringBuilder psScript = new StringBuilder();
    psScript.AppendLine("Set-ADServerSettings -ViewEntireForest $true");
    psScript.AppendLine("function NextMailboxDB() {{");
    // Searches for a mailbox database by name pattern: "Mailbox*"
    psScript.AppendLine("$DB = Get-MailboxDatabase | Where {{ $_.Name -like \"{0}\" }}");
    psScript.AppendLine("$dbArr = foreach ($mDB in $DB) {{");
    psScript.AppendLine("$dbPath = $mDB.EdbFilePath -replace \"\\\\\",\"\\\\\"");
    // Gets the size of the mailbox database
    psScript.AppendLine("$dbSize = (get-wmiobject cim_logicalfile -computer $mDB.Server -filter \"name='$dbPath'\" -property filesize).filesize");
    psScript.AppendLine("$retObj = new-object psobject");
    psScript.AppendLine("$retObj | add-member noteproperty -name \"Size\" -value (\"{{0:n2}}\" -f ($dbSize/1MB))");
    psScript.AppendLine("$retObj | add-member noteproperty -name \"DN\" -value $mDB.DistinguishedName");
    psScript.AppendLine("$retObj");
    psScript.AppendLine("}}");
    // Sorts the result by mailbox database size, ascending order
    psScript.AppendLine("$arrSize = $dbArr | sort-object {{[decimal] $_.\"Size\"}}");
    // Returns the first result (smallest database)
    psScript.AppendLine("return [string]$arrSize[0].\"DN\"");
    psScript.AppendLine("}}");
    psScript.AppendLine("NextMailboxDB");
    
    powershell.AddScript(string.Format(psScript.ToString(), mailboxName));
 
    runspace.Open();
    powershell.Runspace = runspace;

    Collection<PSObject> results = powershell.Invoke();
      
    if (results != null)
    {
     if (results.Count > 0)
     {
      nextMailboxDatabase = (string)results[0].ToString();
     }
     else
     {
      nextMailboxDatabase = string.Empty;
     }
    }
   }
  }
 }
 catch (Exception ex)
 {
  // Log your exceptions!
 }
 return nextMailboxDatabase;
}

Special thanks to Kris Becan for the logic behind the mailbox database size query.

Mastodon: @[email protected]