Finding unused accepted domains in Exchange 2013

If, for some reason, you want to see which domains in your exchange organisation are not being used (not registered in the ProxyAddresses fields of your users), use below snippet in the Exchange Powershell Module.

Note: this does NOT (yet) check for domains used in Public Folders or Mail Contacts.


$mailboxes = get-mailbox -Resultsize Unlimited
$groups = get-distributiongroup -Resultsize Unlimited
$domains = Get-AcceptedDomain
$output = @()

foreach ($domain in $domains){

 $obj = New-Object PSObject
 $obj | Add-Member NoteProperty domainName($domain.DomainName)
 $obj | Add-Member NoteProperty domainType($domain.DomainType)
 $res = $mailboxes | where-object {$_.EmailAddresses -Match $domain.DomainName}
 if(-not $res){
 $res = $groups | where-object {$_.EmailAddresses -Match $domain.DomainName}
 }
 if($res){
 $obj | Add-Member NoteProperty inUse("YES")
 }else{
 $obj | Add-Member NoteProperty inUse("NO")
 }
 $output += $obj
}

Write-Output $output
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

10 Comments
Most Voted
Newest Oldest
Inline Feedbacks
View all comments
Carl Nelson
8 years ago

I tweaked your script to include contacts and display the count of mailboxes, contacts, and groups within each domain:

$mailboxes = Get-Mailbox -ResultSize Unlimited
$groups = Get-DistributionGroup -ResultSize Unlimited
$contacts = Get-MailContact -ResultSize Unlimited
$domains = Get-AcceptedDomain
$output = @()

foreach ($domain in $domains)
{
	$obj = New-Object PSObject
	$obj | Add-Member NoteProperty domainName($domain.DomainName)
	$obj | Add-Member NoteProperty domainType($domain.DomainType)
	$res = $mailboxes | where-object { $_.EmailAddresses -Match $domain.DomainName }
	$mailboxCount = $res.Count
	$res = $groups | where-object { $_.EmailAddresses -Match $domain.DomainName }
	$groupCount = $res.Count
	$res = $contacts | where-object { $_.EmailAddresses -Match $domain.DomainName }
	$contactCount = $res.Count
	if (($mailboxCount + $groupCount + $contactCount) -gt 0)
	{
		$obj | Add-Member NoteProperty inUse("YES")
	}
	else
	{
		$obj | Add-Member NoteProperty inUse("NO")
	}
	$obj | Add-Member NoteProperty mailboxes($mailboxCount)
	$obj | Add-Member NoteProperty groups($groupCount)
	$obj | Add-Member NoteProperty contacts($contactCount)
	$output += $obj
}

Write-Output $output | Format-Table
Dave Stork
9 years ago

Nice snippet!
However a little note of caution; you might want to add the domain type to your output. Although the admin should know, for instance if the domain type is external there shouldn’t be any proxyaddresses with that domain. Exchange accepts those domains, but will forward it (via an explicit Send Connector).

Joerg Hochwald
9 years ago

Hi,

great Snippet! I adopted it a bit:

function Get-UnusedDomains {
 Get-UnusedDomains -DomainType 'ALL' -Cloud

		Shows a list of used and unused domains in you Exchange Online (Office 365) organization. It search for all domain types.
	
	.EXAMPLE
				PS C:\> Get-UnusedDomains -DomainType 'Authoritative'

		Shows a list of used and unused domains in you Exchange on-premises organization. Just crawl for domains the organization is "Authoritative" for.
	
	.EXAMPLE
				PS C:\> Get-UnusedDomains

		Shows a list of used and unused domains in you Exchange on-premises organization. It search for all domain types.
	
	.NOTES
		This function is based on an idea of Jos Lieben.
	
	.LINK
		Source https://www.lieben.nu/liebensraum/2016/03/finding-unused-accepted-domains-in-exchange-2013/
#>
	
	[CmdletBinding(ConfirmImpact = 'None',
				   SupportsShouldProcess = $true)]
	param
	(
		[Parameter(ValueFromPipeline = $true,
				   Position = 1,
				   HelpMessage = 'Type of the Domain to search for? The default is ALL.')]
		[ValidateSet('Authoritative', 'InternalRelay', 'ExternalRelay', 'All')]
		[ValidateNotNullOrEmpty()]
		[System.String]$DomainType = "All",
		[Parameter(Position = 2,
				   HelpMessage = 'Search within Exchange Online / Office 365? Default is NO.')]
		[switch]$Cloud = $false
	)
	
	BEGIN {
		# Cleanup
		$Recipient = $null
		$Domains = $null
		$Result = @()
		
		if ($Cloud) {
			$Recipient = (Get-CloudRecipient -ResultSize unlimited -Filter * | Select-Object EmailAddresses)
		} else {
			$Recipient = (Get-Recipient -ResultSize unlimited -Filter * | Select-Object EmailAddresses)
		}
		
		if ($DomainType -eq "All") {
			$Domains = (Get-AcceptedDomain)
		} else {
			$Domains = (Get-AcceptedDomain | Where{ $_.DomainType -eq "$DomainType" })
		}
	}
	
	PROCESS {
		foreach ($domain in $domains) {
			$Object = New-Object PSObject
			
			$Object | Add-Member NoteProperty domainName($domain.DomainName)
			$Object | Add-Member NoteProperty domainType($domain.DomainType)
			
			$InUse = $Recipient | where-object { $_.EmailAddresses -Match $domain.DomainName }
			
			if ($InUse) {
				$Object | Add-Member NoteProperty inUse("YES")
			} else {
				$Object | Add-Member NoteProperty inUse("NO")
			}
			
			$Result += $Object
		}
	}
	
	END {
		# Dump the Result
		Write-Output $Result
		
		# Cleanup
		$Recipient = $null
		$Domains = $null
		$Result = @()
	}
}
Joerg Hochwald
9 years ago

The Format is bad… Here is a link to a Gist I just created:
https://gist.github.com/jhochwald/35607bdabea3b0fb7e29

victor
victor
7 years ago

Once again, a life safer