ExoAliasManagement.psm1
|
#requires -Version 7.0 #requires -Modules @{ModuleName='ExchangeOnlineManagement'; ModuleVersion='3.9.2'} <# .NOTES Copyright © 2026 Air11 LLC. All rights reserved. Licensed under the MIT License. See https://opensource.org/licenses/MIT for license information. #> # ExoAliasManagement Module # PowerShell module for managing Exchange Online email aliases #region Private Functions function Connect-ExoInteractive { <# .SYNOPSIS Connects to Exchange Online using interactive authentication. .DESCRIPTION Checks if already connected to Exchange Online. If not connected, establishes a connection using interactive login. #> try { # Test if already connected by attempting a simple cmdlet $null = Get-OrganizationConfig -ErrorAction Stop Write-Verbose "Already connected to Exchange Online." } catch { # Not connected, initiate interactive login Write-Host "Connecting to Exchange Online..." -ForegroundColor Cyan Connect-ExchangeOnline -ShowBanner:$false } } function Get-ExoMailboxAddresses { <# .SYNOPSIS Retrieves all email addresses for a specified mailbox. .DESCRIPTION Queries Exchange Online for a mailbox and returns its email addresses. .PARAMETER Identity The identity of the mailbox to query. .OUTPUTS Array of email addresses from the mailbox. #> param( [Parameter(Mandatory = $true)] [string]$Identity ) $mbox = Get-EXOMailbox -Identity $Identity return $mbox.EmailAddresses } function Find-ExoAliasInAddresses { <# .SYNOPSIS Searches for an alias in a collection of email addresses. .DESCRIPTION Matches an address pattern against a collection of email addresses. .PARAMETER Addresses The collection of email addresses to search. .PARAMETER AddressPattern The address pattern to search for. .OUTPUTS Array of matching addresses or $null if no matches found. #> param( [Parameter(Mandatory = $true)] $Addresses, [Parameter(Mandatory = $true)] [string]$AddressPattern ) return $Addresses -match $AddressPattern } function Test-EmailFormat { <# .SYNOPSIS Validates that a string is in proper email format. .DESCRIPTION Tests whether a string matches the pattern user@example.com. Returns $true if valid, $false otherwise. .PARAMETER EmailAddress The email address string to validate. .OUTPUTS Boolean indicating whether the email format is valid. #> param( [Parameter(Mandatory = $true)] [string]$EmailAddress ) # Email regex pattern that matches user@example.com format $emailPattern = '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$' return $EmailAddress -match $emailPattern } #endregion #region Public Functions function Find-ExoAlias { <# .SYNOPSIS Searches for an email alias in an Exchange Online mailbox. .DESCRIPTION Connects to Exchange Online and searches for a specified email address or pattern within a mailbox's email addresses. If no search pattern is provided, returns all addresses. .PARAMETER AddressToBeSearched The email address or pattern to search for in the mailbox. If null or empty, returns all addresses. .PARAMETER MailboxToBeSearched The email address of the mailbox to search. Must be in user@example.com format. This parameter is mandatory. .EXAMPLE Find-ExoAlias -AddressToBeSearched "alias@domain.com" -MailboxToBeSearched "user@example.com" .EXAMPLE Find-ExoAlias "delete" "user@example.com" .EXAMPLE Find-ExoAlias "" "user@example.com" Returns all aliases for the mailbox. #> [CmdletBinding()] param( [Parameter(Mandatory = $false, Position = 0)] [AllowEmptyString()] [string]$AddressToBeSearched = "", [Parameter(Mandatory = $true, Position = 1, HelpMessage = "Enter the mailbox email address to search (e.g., user@example.com)")] [string]$MailboxToBeSearched ) # Validate mailbox email format if (-not (Test-EmailFormat -EmailAddress $MailboxToBeSearched)) { Write-Host "Error: '$MailboxToBeSearched' is not a valid email address format. Expected format: user@example.com" -ForegroundColor Red return } Connect-ExoInteractive $mboxAddresses = Get-ExoMailboxAddresses -Identity $MailboxToBeSearched # If AddressToBeSearched is empty, return all addresses; otherwise filter if ([string]::IsNullOrEmpty($AddressToBeSearched)) { $matchingAliases = $mboxAddresses } else { $matchingAliases = Find-ExoAliasInAddresses -Addresses $mboxAddresses -AddressPattern $AddressToBeSearched } if ($matchingAliases) { Write-Host "`nMatching aliases:" -ForegroundColor Cyan Write-Host ("-" * 50) -ForegroundColor Cyan # Sort aliases: SMTP: (primary) first, then all others alphabetically $sortedAliases = $matchingAliases | Sort-Object { if ($_ -cmatch '^SMTP:') { 0 } else { 1 } }, { $_ } foreach ($alias in $sortedAliases) { if ($alias -cmatch '^SMTP:') { # Primary SMTP address $cleanAlias = $alias -replace '^SMTP:', '' Write-Host $cleanAlias -ForegroundColor Green -NoNewline Write-Host " (This alias is the mailbox default SMTP address)" -ForegroundColor Gray } elseif ($alias -cmatch '^smtp:') { # Secondary SMTP address $cleanAlias = $alias -replace '^smtp:', '' Write-Host $cleanAlias -ForegroundColor Yellow } # Skip all other address types (SIP:, X500:, etc.) } # Output custom objects to pipeline only if being piped # Check if output is being captured/piped by inspecting pipeline position if ($PSCmdlet.MyInvocation.PipelinePosition -lt $PSCmdlet.MyInvocation.PipelineLength) { # Being piped - return objects for pipeline processing foreach ($alias in $sortedAliases) { [PSCustomObject]@{ Alias = $alias Mailbox = $MailboxToBeSearched } } } # If not piped, do nothing - user already saw the formatted Write-Host output } else { Write-Host "`nNo matching aliases found." -ForegroundColor Red } } function Add-ExoAlias { <# .SYNOPSIS Adds an email alias to an Exchange Online mailbox. .DESCRIPTION Connects to Exchange Online and adds a new email alias to the specified mailbox. Verifies that the alias was successfully added. .PARAMETER AddressToBeAdded The email address to add as an alias. Must be in user@example.com format. This parameter is mandatory. .PARAMETER MailboxToAddAlias The email address of the mailbox to modify. Must be in user@example.com format. This parameter is mandatory. .EXAMPLE Add-ExoAlias -AddressToBeAdded "newalias@domain.com" -MailboxToAddAlias "user@example.com" .EXAMPLE Add-ExoAlias "newalias@domain.com" "user@example.com" #> param( [Parameter(Mandatory = $true, Position = 0, HelpMessage = "Enter the email alias to add (e.g., newalias@domain.com)")] [string]$AddressToBeAdded, [Parameter(Mandatory = $true, Position = 1, HelpMessage = "Enter the mailbox email address to modify (e.g., user@example.com)")] [string]$MailboxToAddAlias ) # Validate mailbox email format if (-not (Test-EmailFormat -EmailAddress $MailboxToAddAlias)) { Write-Host "Error: '$MailboxToAddAlias' is not a valid email address format. Expected format: user@example.com" -ForegroundColor Red return } # Validate address email format if (-not (Test-EmailFormat -EmailAddress $AddressToBeAdded)) { Write-Host "Error: '$AddressToBeAdded' is not a valid email address format. Expected format: user@example.com" -ForegroundColor Red return } Connect-ExoInteractive Set-Mailbox -Identity $MailboxToAddAlias -EmailAddresses @{Add = "smtp:$AddressToBeAdded" } # Query Exchange Online to verify the alias was added $mboxAddresses = Get-ExoMailboxAddresses -Identity $MailboxToAddAlias $aliasFound = Find-ExoAliasInAddresses -Addresses $mboxAddresses -AddressPattern $AddressToBeAdded if ($aliasFound) { Write-Host "`nAlias successfully added and verified:" -ForegroundColor Green # Remove smtp: or SMTP: prefix before displaying $cleanAlias = $aliasFound -replace '^smtp:', '' -replace '^SMTP:', '' $cleanAlias | Write-Host -ForegroundColor Yellow } else { Write-Host "`nWarning: Alias was not found in the mailbox after adding." -ForegroundColor Red } } function Remove-ExoAlias { <# .SYNOPSIS Removes an email alias from an Exchange Online mailbox. .DESCRIPTION Connects to Exchange Online, verifies the alias exists, prompts for confirmation, and removes the specified email alias from the mailbox. Can accept pipeline input from Find-ExoAlias to remove multiple aliases. .PARAMETER AddressToBeRemoved The email address to remove from the mailbox. Can be in user@example.com format or smtp:user@example.com format (from pipeline). Accepts pipeline input. .PARAMETER MailboxToBeRemoved The email address of the mailbox to modify. Must be in user@example.com format. When piping from Find-ExoAlias, this parameter is automatically populated. .EXAMPLE Remove-ExoAlias -AddressToBeRemoved "oldalias@domain.com" -MailboxToBeRemoved "user@example.com" .EXAMPLE Remove-ExoAlias "oldalias@domain.com" "user@example.com" .EXAMPLE Find-ExoAlias "test" "user@example.com" | Remove-ExoAlias Removes all aliases matching "test" from the mailbox (mailbox is passed via pipeline). #> [CmdletBinding()] param( [Parameter(Mandatory = $true, Position = 0, ValueFromPipelineByPropertyName = $true, HelpMessage = "Enter the email alias to remove (e.g., oldalias@domain.com)")] [Alias('Alias')] [string]$AddressToBeRemoved, [Parameter(Mandatory = $false, Position = 1, ValueFromPipelineByPropertyName = $true, HelpMessage = "Enter the mailbox email address to modify (e.g., user@example.com)")] [Alias('Mailbox')] [string]$MailboxToBeRemoved ) begin { Connect-ExoInteractive # Store current mailbox to detect changes in pipeline $currentMailbox = $null $currentMailboxAddresses = $null } process { # Determine which mailbox to use $targetMailbox = if ($MailboxToBeRemoved) { $MailboxToBeRemoved } else { $null } if (-not $targetMailbox) { Write-Host "Error: Mailbox parameter is required when not using pipeline input from Find-ExoAlias." -ForegroundColor Red return } # Validate mailbox email format if (-not (Test-EmailFormat -EmailAddress $targetMailbox)) { Write-Host "Error: '$targetMailbox' is not a valid email address format. Expected format: user@example.com" -ForegroundColor Red return } # Clean the address - remove smtp: or SMTP: prefix if present (from pipeline) $cleanAddress = $AddressToBeRemoved -replace '^smtp:', '' -replace '^SMTP:', '' # Validate address email format if (-not (Test-EmailFormat -EmailAddress $cleanAddress)) { Write-Host "Error: '$cleanAddress' is not a valid email address format. Expected format: user@example.com" -ForegroundColor Red return } # Get mailbox addresses (cache if same mailbox) if ($currentMailbox -ne $targetMailbox) { $currentMailbox = $targetMailbox $currentMailboxAddresses = Get-ExoMailboxAddresses -Identity $targetMailbox } # Query Exchange Online to check if the alias exists $aliasFound = Find-ExoAliasInAddresses -Addresses $currentMailboxAddresses -AddressPattern $cleanAddress if ($aliasFound) { Write-Host "`nAlias to be deleted:" -ForegroundColor Cyan # Remove smtp: or SMTP: prefix before displaying $displayAlias = $aliasFound -replace '^smtp:', '' -replace '^SMTP:', '' $displayAlias | Write-Host -ForegroundColor Yellow # Prompt user to confirm deletion with N as default $confirmation = Read-Host "`nDo you want to remove this alias? (Y/N) [N]" if ($confirmation -eq 'Y' -or $confirmation -eq 'y') { Set-Mailbox -Identity $targetMailbox -EmailAddresses @{Remove = "smtp:$cleanAddress" } Write-Host "`nAlias removed successfully." -ForegroundColor Green } else { Write-Host "`nAlias removal cancelled." -ForegroundColor Yellow } } else { Write-Host "`nAlias '$cleanAddress' not found in mailbox. No action taken." -ForegroundColor Red } } } #endregion # Export only the public functions Export-ModuleMember -Function Find-ExoAlias, Add-ExoAlias, Remove-ExoAlias |