internal/functions/Move-Contact.ps1

Function Move-Contact {
    <#
    .SYNOPSIS
    Function to handle export and import of mail enable contacts
 
    .PARAMETER Sync
    Decide to perform the export or import of mail contacts
 
    .DESCRIPTION
    Similar to the Export-T2TAttributes, this function dumps attributes
    from the source AD but only External Contacts. We rely on the same
    CustomAttributed passed through Export-T2TAttributes to filter which
    contacts will be fetched by this function. From the Import-T2TAttributes
    user must pass through param the CSV to import the mail contacts.
 
    .EXAMPLE
    PS C:\> Move-Contacts -Sync Export
    The cmdlet above perform an export of mail contacts filtered by the custom attribute chosen.
    #>


    [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseDeclaredVarsMoreThanAssignments", "")]
    [CmdletBinding()]
    param (
        [ValidateSet('Export','Import')]
        [String[]]
        $Sync
    )

    Switch ($Sync)
    {

        Export {
            # region variables
            [int]$counter = 0
            $outArray = [System.Collections.ArrayList]::new()
            $outFile = "$home\desktop\ContactListToImport.csv"
            $ContactCustomAttribute = $CustomAttribute
            $ContactCustomAttributeValue = $CustomAttributeValue

            # region get Contacts filtering by custom attribute
            $Contacts = (Get-MailContact -ResultSize Unlimited).Where({$_.$CustomAttribute -like $CustomAttributeValue})
            Write-PSFMessage -Level Output -Message "$($Contacts.Count) Mail Contacts with $($ContactCustomAttribute) as $($ContactCustomAttributeValue) were returned"
            $ContactCount = ($Contacts | Measure-Object).count

            # region iterate objects
            ForEach ($i in $Contacts)
            {
                $counter++
                Write-Progress -Activity "Exporting Mail Contacts to CSV" -Status "Working on $($i.DisplayName)" -PercentComplete ($counter * 100 / $ContactCount)
        
                $user = get-Recipient $i.alias
                $object = [ordered]@{
                    PrimarySMTPAddress=$i.PrimarySMTPAddress
                    alias=$i.alias
                    FirstName=$User.FirstName
                    LastName=$User.LastName
                    DisplayName=$User.DisplayName
                    Name=$i.Name
                    legacyExchangeDN=$i.legacyExchangeDN
                }

                # ExternalEmailAddress should contains "SMTP:" depending on the
                # deserialization, we just try a replace to avoid that scenario
                [string]$j = $i.ExternalEmailAddress
                [void]$object.Add("ExternalEmailAddress",$j.Replace("SMTP:",""))

                # Get only non-primary smtp and X500 from proxyAddresses. If we get the primary
                # the CSV mapping domain logic will break as SMTP should be external for contacts
                $ProxyArray = [System.Collections.ArrayList]::new()
                $Proxy = $i.EmailAddresses
                foreach ($email in $Proxy)
                {
                    if ($email -clike 'smtp:*' -or $email -like 'x500:*' -and $email -notlike '*.onmicrosoft.com')
                    {
                        [void]$ProxyArray.Add($email)
                    }
                }

                # Join proxyAddresses using ";"
                $ProxyToString = $ProxyArray -Join ";"

                # Map through the CSV which source domain will become which target domain
                Foreach ($Domain in $MappingCSV)
                {
                    # Add @ before the domain to avoid issues with subdomains
                    $SourceDomain = $Domain.Source.Insert(0,"@")
                    $TargetDomain = $Domain.Target.Insert(0,"@")

                    if ($ProxyToString -match $Domain.source)
                    {
                        $ProxyToString = $ProxyToString.Replace($SourceDomain,$TargetDomain)
                    }
                }

                [void]$object.Add("EmailAddresses",$ProxyToString)

                # Connect to AD exported module only if this machine has not AD Module installed and
                # filtering based on what "Include" was passed to avoid dump too many unnecessary stuff
                if ($LocalMachineIsNotExchange.IsPresent -and $LocalAD -eq '')
                {
                    $ADUser = Get-RemoteADObject -Identity $i.DistinguishedName -Server $PreferredDC -Properties $ADProperties
                    # dump those "-Include" attributes only if we
                    # found more stuff than those junk properties
                    if ($ADProperties.Count -gt 3)
                    {
                        [void](Export-ADPersonalAttribute)
                    }
                }
                else
                {
                    $ADUser = Get-ADObject -Identity $i.DistinguishedName -Server $PreferredDC -Properties $ADProperties
                    # dump those "-Include" attributes only if we
                    # found more stuff than those junk properties
                    if ($ADProperties.Count -gt 3)
                    {
                        [void](Export-ADPersonalAttribute)
                    }
                }
                
                # Create PSObject from hashtable
                # and add PSObject to ArrayList
                $outPSObject = New-Object -TypeName PSObject -Property $object
                [void]$outArray.Add($outPSObject)
            }

            if ($outArray.Count -gt 0)
            {
                Write-PSFMessage -Level Output -Message "Saving CSV on $($outfile)"
                $outArray | Export-CSV $outfile -notypeinformation
            }
        }

        Import {
            # region local variables
            [int]$counter = 0
            $ContactsCount = ($ImportContactList | Measure-Object).count
            $CheckContactManager = ($ImportContactList[0].psobject.Properties).Where({$_.Name -eq "Manager"})

            # region iterate contacts. Variable kept as $user cause
            # the Import-ADPersonalAttribute relies on that value
            ForEach ($user in $ImportContactList)
            {
                $counter++
                Write-Progress -Activity "Creating MEU objects and importing attributes from CSV" -Status "Working on $($i.DisplayName)" -PercentComplete ($counter * 100 / $ContactsCount)
                $Replace = @{}
                $tmpContact = $null

                # region splatting paramd to be used with New-MailContact
                # PrimarySmtpAddress will be set properly down the road
                $contactparam = @{
                    ExternalEmailAddress=$user.ExternalEmailAddress
                    PrimarySmtpAddress=$user.PrimarySMTPAddress
                    FirstName=$user.FirstName
                    LastName=$user.LastName
                    Alias=$user.alias
                    Name=$user.Name
                    DisplayName=$user.DisplayName
                }
                if ($OUContacts)
                {
                    $contactparam.Add("OrganizationalUnit",$OUContacts)
                }

                # region create mail-contact
                $tmpContact = New-MailContact @contactparam
                
                # we must resolve the GUID to use Set-ADObject cmdlet further
                $ResolvedGUID = Get-MailContact -Identity $user.Alias | Select-Object GUID

                # Convert legacyDN to X500 and add all EmailAddresses to array
                $x500 = "x500:" + $user.legacyExchangeDN
                $proxy = $user.EmailAddresses.Replace(";",",")
                $ProxyArray = @()
                $ProxyArray = $proxy.Split(",") + $x500

                # region import old LegacyDN as X500 and CustomAttribute
                Set-MailContact -Identity $user.Alias -EmailAddresses @{Add=$ProxyArray}

                # region import "-Include" values
                if ($CheckContactManager -or $CheckGeneral -or $CheckAddress -or $CheckPhones -or $CheckOrganization -or $CheckCustomAttributes)
                {
                    [void](Import-ADPersonalAttribute)
                }

                # region set $replace hashtable to ADUser
                if ($LocalMachineIsNotExchange.IsPresent -and $null -eq $LocalAD -and $Replace.Count -gt 0)
                {
                    Set-RemoteADObject -Identity $ResolvedGUID.Guid -Server $PreferredDC -Replace $Replace
                }
                elseif ($Replace.Count -gt 0)
                {
                    Set-ADObject -Identity $ResolvedGUID.Guid -Server $PreferredDC -Replace $Replace
                }
            }
        }
    }
}