Public/Convert-CGMMStagingMailContact.ps1

Function Convert-CGMMStagingMailContact {
    <#
    .SYNOPSIS
    Converts a staging mail contact into a production named mail contact.
 
    .DESCRIPTION
    Converts a staging mail contact into a production named mail contact by removing the staging mail contact prefix from relevant mail contact properties. Some properties such as SamAccountName and DistinguishedName are not able to be changed when renaming an Exchange Online object. Other properties, such as Name, Alias, DisplayName, and EmailAddresses, that are used in administration and visible to end users will reflect your intended name.
 
    .EXAMPLE
    Convert-CGMMStagingMailContact -Identity $Identity
 
    Converts a staged mail contact in Exchange Online. The Identity field must match a staged mail contact name.
 
    .EXAMPLE
    Convert-CGMMStagingMailContact -Identity $Identity -HiddenFromAddressListsEnabled $True
 
    Converts a staged mail contact in Exchange Online and makes the mail contact visible in address lists. Staged objects are hidden during creation by default.
 
    .EXAMPLE
    Convert-CGMMStagingMailContact -Identity $Identity -DomainController $DomainController
 
    Specify a domain controller to aid in making all on premise changes in the same location to avoid AD replication challenges.
 
    .NOTES
 
    #>

     [cmdletbinding(SupportsShouldProcess)]
    param(
        # Pipeline variable
        [Parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [ValidateScript({
            Try {$_ -match "^$($StagingGroupPrefix)"}
            Catch {
                Throw "The target contact must begin with $($StagingGroupPrefix)."
            }
        })]
        [string]$Identity,

        [Parameter()]
        [Boolean]$HiddenFromAddressListsEnabled,
        
        [Parameter()]
        [string]$DomainController
    )

    begin {}
    process    {
        Try {
            # Check for Exchange cmdlet availability in On Prem & Exchange Online
            Test-CGMMCmdletAccess -Environment OnPrem -ErrorAction Stop
            
            $EAPSaved = $Global:ErrorActionPreference
            $Global:ErrorActionPreference = 'Stop'

            # Get the target group
            Write-Verbose "Querying for mail contact $($PSBoundParameters.Identity)"
            $MailContact = Get-PremCGMMMailContact -Identity $PSBoundParameters.Identity -ErrorAction Stop

            # Validate that the intended rename is available
            $OldGroupName = ($PSBoundParameters.Identity -replace $StagingGroupPrefix)
            $GetDistributionGroupSettings = @{
                Identity    = $OldGroupName
                ErrorAction = 'SilentlyContinue'
            }
            Write-Verbose "Querying for the intended group name $OldGroupName, which shouldn't exist, for assignment to the contact."
            If ($null -ne (Get-PremCGMMDistributionGroup @GetDistributionGroupSettings)) {
                $ErrorText = "The distribution group {0} must be removed before the staging prefix may be removed from mail contact {1}." -f $GetDistributionGroupSettings['Identity'],$PSBoundParameters.Identity 
                Write-Error $ErrorText -ErrorAction Stop
            }

            # Find all properties that were prefixed.
            Write-Verbose "Identifing and processing prefixed properties"
            $PropertiesToProcess = $MailContact.PSObject.Properties | 
                Where-Object {$_.value -match $StagingGroupPrefix} | 
                Select-Object Name,Value

            # Setup a hash to be used to splat the non-prefixed values
            $SetMailContactSettings = @{}
            ForEach ($Property in $PropertiesToProcess) {
                # Skip over properties that can't or shouldn't be changed
                $SkipProperties = @('DistinguishedName','Identity','LegacyExchangeDN','PrimarySmtpAddress')
                If ($SkipProperties -contains $Property.Name) {continue}

                Switch ($Property.Value.GetType().Name) {
                    string {
                        $ReplacedPrefix = ($Property.Value -replace $StagingGroupPrefix)
                        $SetMailContactSettings.Add($Property.Name,$ReplacedPrefix)
                    }
                    arraylist {
                        $Array = ForEach ($Object in $Property.Value) {
                            $Object -replace $StagingGroupPrefix
                        }
                        $SetMailContactSettings.Add($Property.Name,$Array)
                    }
                    Default {Write-Warning "Property type not accounted for: $($Property.Name). Manual intervention required."}
                }
                
                # Reconstruct the EmailAddresses property to hash the required adds and removes
                # Any non-prefixed addresses that happen to have been assigned will remain unchanged
                If ($Property.Name -eq 'EmailAddresses') {
                    $Removals = $Property.Value | Where-Object {$_ -match $StagingGroupPrefix}
                    $Adds = $SetMailContactSettings['EmailAddresses'] | Where-Object {$Property.Value -notcontains $_}
                    $SetMailContactSettings['EmailAddresses'] = @{Add=$Adds;Remove=$Removals}
                }
            }

            # Avoid the email address policy if it's on
            If ($MailContact.EmailAddressPolicyEnabled -eq $True) {
                Write-Verbose "Temporarily disabling the email address policy"
                $SetMailContactSettings.Add('EmailAddressPolicyEnabled',$False)

                If ($null -ne $SetMailContactSettings['Alias']) {$NewIdentity = $SetMailContactSettings['Alias']}
                Else {$NewIdentity = $MailContact.Alias}
            }
            
            # Finish up the hash by adding provide parameters.
            $SetMailContactSettings.Add('Identity',$PSBoundParameters.Identity)
            If ($null -ne $PSBoundParameters.HiddenFromAddressListsEnabled) {
                Write-Verbose "Adding HiddenFromAddressListsEnabled with value $($PSBoundParameters.HiddenFromAddressListsEnabled)"
                $SetMailContactSettings.Add(
                    'HiddenFromAddressListsEnabled',$PSBoundParameters.HiddenFromAddressListsEnabled
                    )
            }
            If ($null -ne $PSBoundParameters.DomainController) {
                Write-Verbose "Adding DomainController with value $($PSBoundParameters.HiddenFromAddressListsEnabled)"
                $SetMailContactSettings.Add(
                    'DomainController',$PSBoundParameters.DomainController
                    )
            }

            If ($PSCmdlet.ShouldProcess($Identity,$MyInvocation.MyCommand)) {
                Set-PremCGMMMailContact @SetMailContactSettings
                If ($MailContact.EmailAddressPolicyEnabled -eq $True) {
                    $i = 0
                    Do {
                        Write-Verbose "Waiting for the renamed contact to be available to reenable the email address policy"
                        $i++
                        If ($i -gt 6) {Throw "Timed out waiting for contact $NewIdentity to be available for configuration. "}
                        Start-Sleep -Seconds 5  
                        $NewIdentityReady = Get-PremCGMMMailContact $NewIdentity -ErrorAction SilentlyContinue
                    }
                    While ($null -eq $NewIdentityReady)
                    Write-Verbose "Reenabling the email address policy on contact $NewIdentity"
                    Set-PremCGMMMailContact -Identity $NewIdentity -EmailAddressPolicyEnabled $True
                }
            }
        }
        Catch {
            $PsCmdlet.ThrowTerminatingError($PSItem)
        }
        Finally {
            $Global:ErrorActionPreference = $EAPSaved
        }
    }
    end {}
}