MyPSFunctions.EXO.ps1

<#
    ===========================================================================
     Created with: SAPIEN Technologies, Inc., PowerShell Studio 2021 v5.8.196
     Created on: 10/26/2023 7:12 PM
     Created by: John@MyPSFunctions.com
     Organization: MyPSFunctions
     Filename: MyPSFunctions.EXO.psm1
    -------------------------------------------------------------------------
     Module Name: MyPSFunctions.EXO
    ===========================================================================
#>

#region EXO
####################################################
################# Exchange Online (EXO) ####################
###################################################
Function Generate-EXOSharedMailboxesSendAsPermission
{
    [CmdletBinding()]
    param ()
    
    # Get all shared mailboxes
    $sharedMailboxes = Get-Mailbox -RecipientTypeDetails SharedMailbox
    #Initiate the Hash Table
    [Int]$i = 1
    $Table = $Null
    $Table = @()
    $Count = ($sharedMailboxes | Measure).count
    # Loop through each shared mailbox and get SendAs permissions
    foreach ($mailbox in $sharedMailboxes)
    {
        $SharedDisplayName = $Null
        $SharedDisplayName = $Mailbox.DisplayName
        $SharedPrimarySmtpAddress = $Null
        $SharedPrimarySmtpAddress = $Mailbox.PrimarySmtpAddress
        Write-log Warning -message "The script is analyzing $SharedDisplayName ….. --- $i/$Count"
        $sendAsPermissions = $Null
        $sendAsPermissions = Get-RecipientPermission -Identity $mailbox.Identity | Where-Object { $_.AccessRights -eq "SendAs" }
        
        foreach ($permission in $sendAsPermissions)
        {
            $SharedDelegate = $null
            $SharedDelegate = $permission.Trustee
            $DelegateAccessRights = $Null
            $DelegateAccessRights = $permission.AccessRights -join ";"
            If ($SharedDelegate -ne "NT AUTHORITY\SELF")
            {
                $Table += New-object PSobject -Property ([Ordered] @{
                        SharedDisplayName         = $SharedDisplayName;
                        SharedPrimarySmtpAddress = $SharedPrimarySmtpAddress;
                        Delegate                 = $SharedDelegate;
                        DelegateAccessRights     = $DelegateAccessRights;
                    })
            }
        }
    }
    
    $DateFull = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    $ReportFilexlsx = ".\Report_SharedMailboxesSendAsPermissions_" + $DateFull + ".xlsx"
    $Table | Export-Excel $ReportFilexlsx -TableName "SharedMailboxesSendAsPermissions" -Title "Shared Mailboxes SendAs Permissions" -TitleBold -WorksheetName "SendAsPermissions" -TableStyle Medium9 -AutoSize -AutoFilter
    Write-log INFO -Message "Generate the following Report: $ReportFilexlsx"
}
Function Create-EXOMigrationBatch
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$Name,
        [Parameter(Mandatory = $true,
                   Position = 2)]
        [String]$CSVFile,
        [Parameter(Mandatory = $true,
                   Position = 3)]
        [String]$TargetDeliveryDomain,
        [Parameter(Mandatory = $true,
                   Position = 4)]
        [String]$NotificationEmails
    )
    
    # Select Migration Endpoint
    $MigrationEndPoints = Get-MigrationEndPoint
    $SelectedMigrationEndPoint = $MigrationEndPoints | Select Identity,RemoteServer | Out-GridView -PassThru -Title 'Select one MigrationEndpoint then click on OK to validate your selection'
    $SelectedMigrationEndPoint_Identity = $SelectedMigrationEndPoint.Identity
    
    
    Try
    {
        $CrossForestBatch = New-MigrationBatch -Name $Name -SourceEndpoint $SelectedMigrationEndPoint_Identity -TargetDeliveryDomain $TargetDeliveryDomain -CSVData ([System.IO.File]::ReadAllBytes($CSVFile)) -NotificationEmails $NotificationEmails
        sleep 5
        Start-MigrationBatch -Identity $CrossForestBatch.Identity
        Write-Host "Migration Batch has been started" -ForegroundColor Green
    }
    Catch
    {
        $ErrorMessage = $Error[0].Exception.Message
        $CMDLet = $Error[0].InvocationInfo.Line
        $FailedItem = $Error[0].Exception.ItemName
        Write-Host "Failed to create & Start the Migration Batch" -ForegroundColor Red
        Write-Host "Failed to run the following CMDLet: $CMDLet" -ForegroundColor Red
        Write-Host "Failed with Error:$ErrorMessage" -ForegroundColor Red
    }
    

}

Function Grant-EXOApplicationAccessToMailboxUsingGroup
{
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$Mailbox,
        [Parameter(Mandatory = $true,
                   Position = 2)]
        [String]$AppRegistrationName
    )
    
    # Find Application
    $AllMgApps = Get-MgServicePrincipal -All
    $FoundMgApp = $AllMgApps | where { $_.DisplayName -eq $AppRegistrationName }
    If ($FoundMgApp)
    {
        $MgAppID = $FoundMgApp.AppId
        $MgAppObjectID = $FoundMgApp.ID
        Write-Log Warning -Message "Found AppRegistration: $AppRegistrationName"
        
        # Grant Application FullAccess to Mailbox
        New-ServicePrincipal -AppId $MgAppID -ObjectId $MgAppObjectID
        Add-MailboxPermission -identity $Mailbox -user $MgAppID -AccessRights FullAccess
        # Create Security Group
        $DG = Get-DistributionGroup $AppRegistrationName
        If (!($DG))
        {
            $DG = New-DistributionGroup -Name $AppRegistrationName -Type security
            
        }
        $DG_Primary = $DG.PrimarySmtpAddress
        $DG_Alias = $DG.Alias
        # Add Mailbox to DG
        Add-DistributionGroupMember -Identity $DG_Primary -Member $Mailbox
        # Create Application Access Policy
        $Description = "Application Restriction for AppRegistration: $AppRegistrationName to $DG_Alias"
        New-ApplicationAccessPolicy -AppId $MgAppID -PolicyScopeGroupId $DG_Primary -AccessRight RestrictAccess -Description $Description
        
        # Set Authentication Policy
        Write-Log Warning -Message "The script will provide a list of available Authentication Policy allows Basic Authentication for SMTP"
        $AuthenticationPolicyAllowBasicSMTPs = Get-AuthenticationPolicy | where { $_.AllowBasicAuthSmtp -eq $True }
        $SelectedAuthenticationPolicyAllowBasicSMTP = $AuthenticationPolicyAllowBasicSMTPs | select Name, AllowBasicauthSmtp | Out-GridView -PassThru
        $SelectedAuthenticationPolicyAllowBasicSMTPName = $SelectedAuthenticationPolicyAllowBasicSMTP.Name
        Write-Log Info -Message "The script selected the following Authentication Policy: $SelectedAuthenticationPolicyAllowBasicSMTPName"
        
        # Assign Authentication Policy
        $BeforeUser = Get-User $Mailbox
        $BeforeAuthenticationPolicy = $BeforeUser.AuthenticationPolicy
        Write-Log Warning -Message "$Mailbox is currently using the following Authentication Policy: $BeforeAuthenticationPolicy"
        Read-Host "Please press enter to change the Authentication policy to $SelectedAuthenticationPolicyAllowBasicSMTPName"
        Set-User $Mailbox -AuthenticationPolicy $SelectedAuthenticationPolicyAllowBasicSMTPName -Confirm: $False
        Write-Log Warning -Message "$Mailbox is set with the following Authentication Policy: $BeforeAuthenticationPolicy"
        
        #Enable SMTP Client Authentication
        $BeforeCASMailbox = Get-CASMailbox $Mailbox
        $BeforeSmtpClientAuthenticationDisabled = $BeforeCASMailbox.SmtpClientAuthenticationDisabled
        $BeforeImapEnabled = $BeforeCASMailbox.ImapEnabled
        Write-Log Warning -Message "The $Mailbox SmtpClientAuthenticationDisabled is: $BeforeSmtpClientAuthenticationDisabled & ImapEnabled $BeforeImapEnabled"
        Set-CASMailbox $Mailbox -SmtpClientAuthenticationDisabled $false -Confirm: $False
        Set-CASMailbox $Mailbox -ImapEnabled $true -Confirm: $False
        $AfterCASMailbox = Get-CASMailbox $Mailbox
        $AfterSmtpClientAuthenticationDisabled = $AfterCASMailbox.SmtpClientAuthenticationDisabled
        $AfterImapEnabled = $AfterCASMailbox.ImapEnabled
        Write-Log Warning -Message "The $Mailbox SmtpClientAuthenticationDisabled is: $AfterSmtpClientAuthenticationDisabled & ImapEnabled $AfterImapEnabled"
        
        Set-MailboxRegionalConfiguration -Identity $Mailbox -Language en-us -LocalizeDefaultFolderName
        Get-MailboxRegionalConfiguration -Identity $Mailbox | fl Language, *date*, *folder*
        Write-Log Error -Message "Please add the $Mailbox to Conditional Access policy MFA Exclusion"
    }
    Else
    {
        Write-Log Error -Message "App Registration None Found : $AppRegistrationName"
    }
}

Function Generate-EXOUsersCustodianHoldReport
{
    ###############################################################################################################################################################################
    #################################################################### Variable #####################################################################
    ###############################################################################################################################################################################
    $Date = get-date -UFormat %d%m%Y
    $DateFull = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    $ServerName = [Environment]::MachineName
    ###### Create Root Folder
    $RootFolder = $psscriptRoot + "\CasesHolds_Reports"
    
    ###### Create folder Variable
    $LogPathFolder = $RootFolder + "\Log\"
    $LogFile = $LogPathFolder + "Progress_" + $Date + ".log"
    
    
    $ReportPathFolder = $RootFolder + "\Reports\"
    
    ###### Create Folder
    Create-Folder $RootFolder
    Create-Folder $LogPathFolder
    Create-Folder $ReportPathFolder
    
    $Transcript_File = $LogPathFolder + "Transcript_" + $Date + ".txt"
    $ReportFile = $ReportPathFolder + "UsersCustodianHolds_" + $DateFull + ".xlsx"
    Start-Transcript -Path $Transcript_File -Append -Force
    ########### Initiate the Process log file when the script started ############
    $Initiat_LogA = "#################### starting the Script #####################"
    $Startat = "### The Script has been launch at $(Get-Date -Format "yyyy-MM-dd HH:mm:ss")"
    $Startwith = "The Script has been start with the following Account:" + [Environment]::UserName
    $Starton = "The Script has been start on the following Computer:" + [Environment]::MachineName
    $Initiat_LogB = "##############################################################"
    $Initiat_LogB | Out-File -FilePath $LogFile -Append
    $Initiat_LogB | Out-File -FilePath $LogFile -Append
    $Initiat_LogA | Out-File -FilePath $LogFile -Append
    $Startat | Out-File -FilePath $LogFile -Append
    $Startwith | Out-File -FilePath $LogFile -Append
    $Starton | Out-File -FilePath $LogFile -Append
    $Initiat_LogB | Out-File -FilePath $LogFile -Append
    $Initiat_LogB | Out-File -FilePath $LogFile -Append
    
    ###############################################################################################################################################################################
    #################################################################### Main Script #####################################################################
    ###############################################################################################################################################################################
    
    # Connecting to Security & Compliance Center
    Read-Host "Are you connected to Security & Compliance Center module?"
    
    # Retreive all Ediscovery Cases
    Try
    {
        Write-Log warning -Message "The script will retreive all Ediscovery Cases (Standard)"
        $eDiscoveryCases = Get-ComplianceCase -ErrorAction SilentlyContinue
        Write-Log warning -Message "The script will retreive all Ediscovery Cases (Premium)"
        $eDiscoveryCases += Get-ComplianceCase -CaseType Advanced -ErrorAction SilentlyContinue
    }
    Catch
    {
        $ErrorMessage = $Error[0].Exception.Message
        $CMDLet = $Error[0].InvocationInfo.Line
        $FailedItem = $Error[0].Exception.ItemName
        Write-Log Error -Message "Failed to retreive all Ediscovery Cases (Standard & Premium)"
        Write-Log Error -Message "Failed to run the following CMDLet: $CMDLet"
        Write-Log Error -Message "Failed with Error:$ErrorMessage"
        Read-Host "Exit the script"
        Exit
    }
    
    #Initiate the Hash Table
    [Int]$i = 1
    $Table = $Null
    $Table = @()
    $Count = ($eDiscoveryCases | Measure).count
    Write-Log Info -Message "The script retreived all Ediscovery Cases (Standard & Premium): $Count Cases"
    ForEach ($eDiscoveryCase in $eDiscoveryCases)
    {
        $eDiscoveryCase_Name = $Null
        $eDiscoveryCase_Status = $Null
        $eDiscoveryCase_Members = $Null
        $eDiscoveryCase_CaseType = $Null
        $eDiscoveryCase_ClosedDateTime = $Null
        $eDiscoveryCase_Enabled = $Null
        $eDiscoveryCase_CreatedDateTime = $Null
        $eDiscoveryCase_Policy_Name = "No Policy found"
        $eDiscoveryCase_Policy_Enabled = "No Policy found"
        $eDiscoveryCase_Policy_CreatedBy = "No Policy found"
        $eDiscoveryCase_Policy_LastModifiedBy = "No Policy found"
        $eDiscoveryCase_Policy_WhenCreatedUTC = "No Policy found"
        $eDiscoveryCase_Policy_WhenChangedUTC = "No Policy found"
        $eDiscoveryCase_Policy_DistributionStatus = "No Policy found"
        $eDiscoveryCase_Policy_DistributionResults = "No Policy found"
        $eDiscoveryCase_Policy_ExchangeLocations = "No Policy found"
        $eDiscoveryCase_Policy_SharepointLocations = "No Policy found"
        $eDiscoveryCase_Policy_ExchangeLocations_Count = "No Policy found"
        $eDiscoveryCase_Policy_SharepointLocations_Count = "No Policy found"
        $eDiscoveryCase_Policy_Rule_ContentMatchQuery = "No Rule Policy found"
        $eDiscoveryCase_Name = $eDiscoveryCase.Name
        $eDiscoveryCase_Status = $eDiscoveryCase.Status
        $eDiscoveryCase_CaseType = $eDiscoveryCase.CaseType
        $eDiscoveryCase_ClosedDateTime = $eDiscoveryCase.ClosedDateTime
        $eDiscoveryCase_Members = ((Get-ComplianceCaseMember -Case $eDiscoveryCase_Name).windowsLiveID) -join ';'
        Write-log Warning -message "The script is analyzing $eDiscoveryCase_Name ….. --- $i/$Count"
        
        if ($eDiscoveryCase_Status -eq 'Closed')
        {
            Write-log Warning -message "$eDiscoveryCase_Name is closed"
            $Table += New-object PSobject -Property ([Ordered] @{
                    eDiscoveryCase_Name                                = $eDiscoveryCase_Name;
                    eDiscoveryCase_Members                            = $eDiscoveryCase_Members;
                    eDiscoveryCase_CaseType                            = $eDiscoveryCase_CaseType;
                    eDiscoveryCase_Status                            = $eDiscoveryCase_Status;
                    eDiscoveryCase_CreatedDateTime                    = $eDiscoveryCase_CreatedDateTime;
                    eDiscoveryCase_ClosedDateTime                    = $eDiscoveryCase_ClosedDateTime;
                    eDiscoveryCase_Enabled                            = $eDiscoveryCase_Enabled;
                    eDiscoveryCase_Policy_Name                        = $eDiscoveryCase_Policy_Name;
                    eDiscoveryCase_Policy_Enabled                    = $eDiscoveryCase_Policy_Enabled;
                    eDiscoveryCase_Policy_CreatedBy                    = $eDiscoveryCase_Policy_CreatedBy;
                    eDiscoveryCase_Policy_LastModifiedBy            = $eDiscoveryCase_Policy_LastModifiedBy;
                    eDiscoveryCase_Policy_WhenCreatedUTC            = $eDiscoveryCase_Policy_WhenCreatedUTC;
                    eDiscoveryCase_Policy_WhenChangedUTC            = $eDiscoveryCase_Policy_WhenChangedUTC;
                    eDiscoveryCase_Policy_DistributionStatus        = $eDiscoveryCase_Policy_DistributionStatus;
                    eDiscoveryCase_Policy_DistributionResults        = $eDiscoveryCase_Policy_DistributionResults;
                    eDiscoveryCase_Policy_ExchangeLocations            = $eDiscoveryCase_Policy_ExchangeLocations;
                    eDiscoveryCase_Policy_ExchangeLocations_Count   = $eDiscoveryCase_Policy_ExchangeLocations_Count;
                    eDiscoveryCase_Policy_SharepointLocations        = $eDiscoveryCase_Policy_SharepointLocations;
                    eDiscoveryCase_Policy_SharepointLocations_Count = $eDiscoveryCase_Policy_SharepointLocations_Count;
                    eDiscoveryCase_Policy_Rule_ContentMatchQuery    = $eDiscoveryCase_Policy_Rule_ContentMatchQuery;
                })
            
        }
        else
        {
            Write-log Warning -message "$eDiscoveryCase_Name is $eDiscoveryCase_Status"
            $eDiscoveryCase_Policies = $Null
            $eDiscoveryCase_Policies = Get-CaseHoldPolicy -Case $eDiscoveryCase_Name | % { Get-CaseHoldPolicy $_.Name -Case $_.CaseId -DistributionDetail }
            
            if ($eDiscoveryCase_Policies -ne $Null)
            {
                foreach ($eDiscoveryCase_Policy in $eDiscoveryCase_Policies)
                {
                    $eDiscoveryCase_Policy_Name = $Null
                    $eDiscoveryCase_Policy_Name = $eDiscoveryCase_Policy.Name
                    $eDiscoveryCase_Policy_Rule = $Null
                    $eDiscoveryCase_Policy_Rule = Get-CaseHoldRule -Policy $eDiscoveryCase_Policy_Name
                    $eDiscoveryCase_Enabled = $eDiscoveryCase.Enabled
                    $eDiscoveryCase_CreatedDateTime = $eDiscoveryCase.CreatedDateTime
                    $eDiscoveryCase_Policy_Name = $eDiscoveryCase_Policy.Name
                    $eDiscoveryCase_Policy_Enabled = $eDiscoveryCase_Policy.Enabled
                    $eDiscoveryCase_Policy_CreatedBy = $eDiscoveryCase_Policy.CreatedBy
                    $eDiscoveryCase_Policy_LastModifiedBy = $eDiscoveryCase_Policy.LastModifiedBy
                    $eDiscoveryCase_Policy_ExchangeLocations = (($eDiscoveryCase_Policy.exchangelocation.name) -join ';')
                    $eDiscoveryCase_Policy_SharepointLocations = (($eDiscoveryCase_Policy.sharePointlocation.name) -join ';')
                    $eDiscoveryCase_Policy_ExchangeLocations_Count = (($eDiscoveryCase_Policy.exchangelocation.name) | Measure).count
                    $eDiscoveryCase_Policy_SharepointLocations_Count = (($eDiscoveryCase_Policy.sharePointlocation.name) | Measure).count
                    $eDiscoveryCase_Policy_WhenCreatedUTC = $eDiscoveryCase_Policy.WhenCreatedUTC
                    $eDiscoveryCase_Policy_WhenChangedUTC = $eDiscoveryCase_Policy.WhenChangedUTC
                    $eDiscoveryCase_Policy_DistributionStatus = $eDiscoveryCase_Policy.DistributionStatus
                    $eDiscoveryCase_Policy_DistributionResults = $eDiscoveryCase_Policy.DistributionResults.ResultCode.Value
                    $Table += New-object PSobject -Property ([Ordered] @{
                            eDiscoveryCase_Name                                = $eDiscoveryCase_Name;
                            eDiscoveryCase_Members                            = $eDiscoveryCase_Members;
                            eDiscoveryCase_CaseType                            = $eDiscoveryCase_CaseType;
                            eDiscoveryCase_Status                            = $eDiscoveryCase_Status;
                            eDiscoveryCase_CreatedDateTime                    = $eDiscoveryCase_CreatedDateTime;
                            eDiscoveryCase_ClosedDateTime                    = $eDiscoveryCase_ClosedDateTime;
                            eDiscoveryCase_Enabled                            = $eDiscoveryCase_Enabled;
                            eDiscoveryCase_Policy_Name                        = $eDiscoveryCase_Policy_Name;
                            eDiscoveryCase_Policy_Enabled                    = $eDiscoveryCase_Policy_Enabled;
                            eDiscoveryCase_Policy_CreatedBy                    = $eDiscoveryCase_Policy_CreatedBy;
                            eDiscoveryCase_Policy_LastModifiedBy            = $eDiscoveryCase_Policy_LastModifiedBy;
                            eDiscoveryCase_Policy_WhenCreatedUTC            = $eDiscoveryCase_Policy_WhenCreatedUTC;
                            eDiscoveryCase_Policy_WhenChangedUTC            = $eDiscoveryCase_Policy_WhenChangedUTC;
                            eDiscoveryCase_Policy_DistributionStatus        = $eDiscoveryCase_Policy_DistributionStatus;
                            eDiscoveryCase_Policy_DistributionResults        = $eDiscoveryCase_Policy_DistributionResults;
                            eDiscoveryCase_Policy_ExchangeLocations            = $eDiscoveryCase_Policy_ExchangeLocations;
                            eDiscoveryCase_Policy_ExchangeLocations_Count   = $eDiscoveryCase_Policy_ExchangeLocations_Count;
                            eDiscoveryCase_Policy_SharepointLocations        = $eDiscoveryCase_Policy_SharepointLocations;
                            eDiscoveryCase_Policy_SharepointLocations_Count = $eDiscoveryCase_Policy_SharepointLocations_Count;
                            eDiscoveryCase_Policy_Rule_ContentMatchQuery    = $eDiscoveryCase_Policy_Rule_ContentMatchQuery;
                        })
                    
                }
            }
            else
            {
                Write-log Warning -message "No hold policies found in case: $eDiscoveryCase_Name"
                $Table += New-object PSobject -Property ([Ordered] @{
                        eDiscoveryCase_Name                                = $eDiscoveryCase_Name;
                        eDiscoveryCase_Members                            = $eDiscoveryCase_Members;
                        eDiscoveryCase_CaseType                            = $eDiscoveryCase_CaseType;
                        eDiscoveryCase_Status                            = $eDiscoveryCase_Status;
                        eDiscoveryCase_CreatedDateTime                    = $eDiscoveryCase_CreatedDateTime;
                        eDiscoveryCase_ClosedDateTime                    = $eDiscoveryCase_ClosedDateTime;
                        eDiscoveryCase_Enabled                            = $eDiscoveryCase_Enabled;
                        eDiscoveryCase_Policy_Name                        = $eDiscoveryCase_Policy_Name;
                        eDiscoveryCase_Policy_Enabled                    = $eDiscoveryCase_Policy_Enabled;
                        eDiscoveryCase_Policy_CreatedBy                    = $eDiscoveryCase_Policy_CreatedBy;
                        eDiscoveryCase_Policy_LastModifiedBy            = $eDiscoveryCase_Policy_LastModifiedBy;
                        eDiscoveryCase_Policy_WhenCreatedUTC            = $eDiscoveryCase_Policy_WhenCreatedUTC;
                        eDiscoveryCase_Policy_WhenChangedUTC            = $eDiscoveryCase_Policy_WhenChangedUTC;
                        eDiscoveryCase_Policy_DistributionStatus        = $eDiscoveryCase_Policy_DistributionStatus;
                        eDiscoveryCase_Policy_DistributionResults        = $eDiscoveryCase_Policy_DistributionResults;
                        eDiscoveryCase_Policy_ExchangeLocations            = $eDiscoveryCase_Policy_ExchangeLocations;
                        eDiscoveryCase_Policy_ExchangeLocations_Count   = $eDiscoveryCase_Policy_ExchangeLocations_Count;
                        eDiscoveryCase_Policy_SharepointLocations        = $eDiscoveryCase_Policy_SharepointLocations;
                        eDiscoveryCase_Policy_SharepointLocations_Count = $eDiscoveryCase_Policy_SharepointLocations_Count;
                        eDiscoveryCase_Policy_Rule_ContentMatchQuery    = $eDiscoveryCase_Policy_Rule_ContentMatchQuery;
                    })
                
            }
        }
        
        
        $i++
        
        
    }
    
    $Table | Export-Excel $ReportFile -TableName "EdiscoveryCasesReport" -Title "Ediscovery Cases Report" -TitleBold -WorksheetName "EdiscoveryCasesReport" -TableStyle Medium9 -AutoSize -AutoFilter
    Write-log INFO -Message "Generate the following Report: $ReportFile"
}

Function Generate-EXOBasicSMTPSettingsAllMailboxes
{
    
    $DateFull = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    $ExcelFile = ".\Report_Settings_Allowing_BasicAuth_SMTP_" + $DateFull + ".xlsx"
    
    # Check Tenant SmtpClientAuthenticationDisabled
    Try
    {
        Write-Log warning -Message "The script is checking the SMTP authentication settings at the tenant level"
        $TransportConfig_SmtpClientAuthenticationDisabled = (Get-TransportConfig).SmtpClientAuthenticationDisabled
        Write-Log Info -Message "SmtpClientAuthenticationDisabled is set to: $TransportConfig_SmtpClientAuthenticationDisabled"
    }
    Catch
    {
        $ErrorMessage = $Error[0].Exception.Message
        $CMDLet = $Error[0].InvocationInfo.Line
        $FailedItem = $Error[0].Exception.ItemName
        Write-Log Error -Message "Failed to check the SMTP authentication settings at the tenant level"
        Write-Log Error -Message "Failed to run the following CMDLet: $CMDLet"
        Write-Log Error -Message "Failed with Error:$ErrorMessage"
        $TransportConfig_SmtpClientAuthenticationDisabled = "Failed with Error:$ErrorMessage"
    }
    
    # Search for Authentication Policy allowing Basic SMTP:
    Try
    {
        Write-Log warning -Message "The script is searching for Authentication Policy Allowing Basic Authentication for SMTP"
        $AuthenticationPolicyAllowBasicSMTPs = Get-AuthenticationPolicy | where { $_.AllowBasicAuthSmtp -eq $True }
        $Count = ($AuthenticationPolicyAllowBasicSMTPs | Measure).count
        Write-Log Info -Message "The script found $Count Authentication Policies allowing Basic SMTP"
        if ($Count -gt 1)
        {
            $FoundAuthenticationPolicyAllowBasicSMTPs = $AuthenticationPolicyAllowBasicSMTPs.Name -join ","
        }
        Else
        { $FoundAuthenticationPolicyAllowBasicSMTPs = $AuthenticationPolicyAllowBasicSMTPs.Name }
    }
    Catch
    {
        $ErrorMessage = $Error[0].Exception.Message
        $CMDLet = $Error[0].InvocationInfo.Line
        $FailedItem = $Error[0].Exception.ItemName
        Write-Log Error -Message "Failed to find Authentication Policy Allowing Basic Authentication for SMTP"
        Write-Log Error -Message "Failed to run the following CMDLet: $CMDLet"
        Write-Log Error -Message "Failed with Error:$ErrorMessage"
        $FoundAuthenticationPolicyAllowBasicSMTPs = "Failed with Error:$ErrorMessage"
    }
    
    $TenantSMTPSettings = $Null
    $TenantSMTPSettings = @()
    $TenantSMTPSettings += New-object PSobject -Property ([Ordered] @{
            TransportConfig_SmtpClientAuthenticationDisabled = $TransportConfig_SmtpClientAuthenticationDisabled;
            AuthenticationPolicyAllowBasicSMTPs                 = $FoundAuthenticationPolicyAllowBasicSMTPs;
        })
    $TenantSMTPSettings | Export-Excel -Path $ExcelFile -Append -WorksheetName "Tenant SMTP Settings" -Title "Tenant Level SMTP Settings" -TitleBold -TableName "TenantSMTPSettings" -TableStyle Medium9 -AutoSize
    # Check CAS Mailboxes SmtpClientAuthenticationDisabled
    Try
    {
        Write-Log warning -Message "The script is checking the SmtpClientAuthenticationDisabled for all Mailboxes"
        $CASMailboxes = Get-CASMailbox -ResultSize unlimited
        $CASMailboxesCount = ($CASMailboxes | Measure).count
        
    }
    Catch
    {
        
        $ErrorMessage = $Error[0].Exception.Message
        $CMDLet = $Error[0].InvocationInfo.Line
        $FailedItem = $Error[0].Exception.ItemName
        Write-Log Error -Message "Failed to check the SmtpClientAuthenticationDisabled for all Mailboxes"
        Write-Log Error -Message "Failed to run the following CMDLet: $CMDLet"
        Write-Log Error -Message "Failed with Error:$ErrorMessage"
    }
    #Report
    Write-Log Info -Message "Found CAS Mailboxes: $CASMailboxesCount"
    $CASMailboxes = $CASMailboxes | Select DisplayName, PrimarySmtpAddress, SmtpClientAuthenticationDisabled
    $CASMailboxes | Export-Excel -Path $ExcelFile -Append -WorksheetName "AllCASMailboxes" -Title "All CAS Mailboxes" -TitleBold -TableName "AllCASMailboxes" -TableStyle Medium9 -AutoSize
    $CASMailboxes | Group-Object -Property SmtpClientAuthenticationDisabled | Sort-Object -Property Count -Descending
    $ExcelChart = New-ExcelChartDefinition -XRange Name -YRange Count -ChartType Pie -Title "SmtpClientAuthenticationDisabled Usage"
    $CASMailboxes | Group-Object -Property SmtpClientAuthenticationDisabled | Sort-Object -Property Count -Descending | Select Count, Name | Export-Excel -Path $ExcelFile -Append -WorksheetName "PieChart-SmtpClientAuthenticationDisabled" -ExcelChartDefinition $ExcelChart -AutoNameRange -Title "SmtpClientAuthenticationDisabled Usage" -AutoSize
    
    # Check for Authentication Policy for all Users
    Try
    {
        Write-Log warning -Message "The script is checking AuthenticationPolicy for all Mailboxes"
        $Users = Get-User -ResultSize unlimited
        $UsersCount = ($Users | Measure).count
        
    }
    Catch
    {
        
        $ErrorMessage = $Error[0].Exception.Message
        $CMDLet = $Error[0].InvocationInfo.Line
        $FailedItem = $Error[0].Exception.ItemName
        Write-Log Error -Message "Failed to check AuthenticationPolicy for all Mailboxes"
        Write-Log Error -Message "Failed to run the following CMDLet: $CMDLet"
        Write-Log Error -Message "Failed with Error:$ErrorMessage"
        
    }
    
    # Reports:
    Write-Log Info -Message "Found Users: $UsersCount"
    $Users = $Users | Select DisplayName, UserPrincipalName, AuthenticationPolicy
    $Users | Export-Excel -Path $ExcelFile -Append -WorksheetName "AuthenticationPolicy AllUsers" -Title "AuthenticationPolicy AllUsers" -TitleBold -TableName "AuthenticationPolicy AllUsers" -TableStyle Medium9 -AutoSize
    $Users | Group-Object -Property AuthenticationPolicy | Sort-Object -Property Count -Descending
    $ExcelChart = New-ExcelChartDefinition -XRange Name -YRange Count -ChartType Pie -Title "AuthenticationPolicy Usage"
    $Users | Group-Object -Property AuthenticationPolicy | Sort-Object -Property Count -Descending | Select Count, Name | Export-Excel -Path $ExcelFile -Append -WorksheetName "PieChart-AuthenticationPolicy" -ExcelChartDefinition $ExcelChart -AutoNameRange -Title "AuthenticationPolicy Usage" -AutoSize
    
    
    Write-Log Info -Message "The script generate the following report: $ExcelFile "
}

Function Check-EXOMailboxSMTPBasicAuthSettings
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$PrimarySmtpAddress
    )
    
    # Check Tenant SmtpClientAuthenticationDisabled
    Try
    {
        Write-Log warning -Message "The script is checking the SMTP authentication settings at the tenant level"
        $TransportConfig_SmtpClientAuthenticationDisabled = (Get-TransportConfig).SmtpClientAuthenticationDisabled
        Write-Log Info -Message "SmtpClientAuthenticationDisabled is set to: $TransportConfig_SmtpClientAuthenticationDisabled"
    }
    Catch
    {
        $ErrorMessage = $Error[0].Exception.Message
        $CMDLet = $Error[0].InvocationInfo.Line
        $FailedItem = $Error[0].Exception.ItemName
        Write-Log Error -Message "Failed to check the SMTP authentication settings at the tenant level"
        Write-Log Error -Message "Failed to run the following CMDLet: $CMDLet"
        Write-Log Error -Message "Failed with Error:$ErrorMessage"
        $TransportConfig_SmtpClientAuthenticationDisabled = "Failed with Error:$ErrorMessage"
    }
    
    # Check User Mailbox SmtpClientAuthenticationDisabled
    Try
    {
        Write-Log warning -Message "The script is checking the SmtpClientAuthenticationDisabled for: $PrimarySmtpAddress"
        $CASMailbox_SmtpClientAuthenticationDisabled = (Get-CASMailbox $PrimarySmtpAddress).SmtpClientAuthenticationDisabled
        Write-Log Info -Message "$PrimarySmtpAddress SmtpClientAuthenticationDisabled is set:$CASMailbox_SmtpClientAuthenticationDisabled"
    }
    Catch
    {
        
        $ErrorMessage = $Error[0].Exception.Message
        $CMDLet = $Error[0].InvocationInfo.Line
        $FailedItem = $Error[0].Exception.ItemName
        Write-Log Error -Message "Failed to check the SmtpClientAuthenticationDisabled for: $PrimarySmtpAddress"
        Write-Log Error -Message "Failed to run the following CMDLet: $CMDLet"
        Write-Log Error -Message "Failed with Error:$ErrorMessage"
        $CASMailbox_SmtpClientAuthenticationDisabled = "Failed with Error:$ErrorMessage"
    }
    
    # Search for Authentication Policy allowing Basic SMTP:
    Try
    {
        Write-Log warning -Message "The script is searching for Authentication Policy Allowing Basic Authentication for SMTP"
        $AuthenticationPolicyAllowBasicSMTPs = Get-AuthenticationPolicy | where { $_.AllowBasicAuthSmtp -eq $True }
        $Count = ($AuthenticationPolicyAllowBasicSMTPs | Measure).count
        Write-Log Info -Message "The script found $Count Authentication Policies allowing Basic SMTP"
        if ($Count -gt 1)
        {
            $FoundAuthenticationPolicyAllowBasicSMTPs = $AuthenticationPolicyAllowBasicSMTPs.Name -join ","
        }
        Else
        { $FoundAuthenticationPolicyAllowBasicSMTPs = $AuthenticationPolicyAllowBasicSMTPs.Name }
    }
    Catch
    {
        $ErrorMessage = $Error[0].Exception.Message
        $CMDLet = $Error[0].InvocationInfo.Line
        $FailedItem = $Error[0].Exception.ItemName
        Write-Log Error -Message "Failed to find Authentication Policy Allowing Basic Authentication for SMTP"
        Write-Log Error -Message "Failed to run the following CMDLet: $CMDLet"
        Write-Log Error -Message "Failed with Error:$ErrorMessage"
        $FoundAuthenticationPolicyAllowBasicSMTPs = "Failed with Error:$ErrorMessage"
    }
    
    # Check for Authentication Policy assign to User Mailbox
    Try
    {
        Write-Log warning -Message "The script is check AuthenticationPolicy for $PrimarySmtpAddress"
        $UserAuthenticationPolicy = (Get-User $PrimarySmtpAddress).AuthenticationPolicy
        if ($UserAuthenticationPolicy -eq $Null) { $UserAuthenticationPolicy = "Using Tenant Setting" }
        Write-Log Info -Message "$PrimarySmtpAddress AuthenticationPolicy is set: $UserAuthenticationPolicy"
    }
    Catch
    {
        $ErrorMessage = $Error[0].Exception.Message
        $CMDLet = $Error[0].InvocationInfo.Line
        $FailedItem = $Error[0].Exception.ItemName
        Write-Log Error -Message "Failed to check AuthenticationPolicy for $PrimarySmtpAddress"
        Write-Log Error -Message "Failed to run the following CMDLet: $CMDLet"
        Write-Log Error -Message "Failed with Error:$ErrorMessage"
        $UserAuthenticationPolicy = "Failed with Error:$ErrorMessage"
    }
    
    # Check Conditional Access Policy
    Write-Log warning -Message "Please check if $PrimarySmtpAddress is allow to use legacy/Basic Authentication in Conditional access or Secure Default is disabled"
    
    $UserMailboxData = $Null
    $UserMailboxData = @()
    $UserMailboxData += New-object PSobject -Property ([Ordered] @{
            PrimarySmtpAddress                                 = $PrimarySmtpAddress;
            TransportConfig_SmtpClientAuthenticationDisabled = $TransportConfig_SmtpClientAuthenticationDisabled;
            CASMailbox_SmtpClientAuthenticationDisabled         = $CASMailbox_SmtpClientAuthenticationDisabled;
            TenantAuthenticationPolicyAllowBasicSMTPs         = $AuthenticationPolicyAllowBasicSMTPs;
            UserAuthenticationPolicy                         = $UserAuthenticationPolicy;
            ConditionalAccessPolicy                             = "Review Conditional Access Policy for Exception";
        })
    
    
    Return $UserMailboxData
    
}

Function Generate-EXOMailboxesRetentionReport
{
    [CmdletBinding()]
    param ()
    
    $DateFull = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    $ExcelFile = ".\Report_AllMailboxes_RetentionPolicies_" + $DateFull + ".xlsx"
    $Mailboxes = Get-Mailbox -ResultSize Unlimited
    $Mailboxes = $Mailboxes | Select DisplayName, PrimarySmtpAddress, RetentionPolicy, LitigationHoldEnabled, LitigationHoldDate, LitigationHoldOwner, LitigationHoldDuration
    $Mailboxes | Export-Excel -Path $ExcelFile -WorksheetName "AllMailboxes" -Title "Retention All Mailboxes" -TitleBold -TableName "AllMailboxes" -TableStyle Medium9
    $Mailboxes | Group-Object -Property RetentionPolicy | Sort-Object -Property Count -Descending
    $ExcelChart = New-ExcelChartDefinition -XRange Name -YRange Count -ChartType Pie -Title "Retention Policy Usage"
    $Mailboxes | Group-Object -Property RetentionPolicy | Sort-Object -Property Count -Descending | Select Count, Name | Export-Excel -Path $ExcelFile -Append -WorksheetName "PieChart-Retention" -ExcelChartDefinition $ExcelChart -AutoNameRange -Title "Retention Policy Usage"
    $ExcelChart = New-ExcelChartDefinition -XRange Name -YRange Count -ChartType Pie -Title "Litigation Hold Enabled"
    $Mailboxes | Group-Object -Property LitigationHoldEnabled | Sort-Object -Property Count -Descending | Select Count, Name | Export-Excel -Path $ExcelFile -Append -WorksheetName "PieChart-LitigationHoldEnabled" -ExcelChartDefinition $ExcelChart -AutoNameRange -Title "Litigation Hold Enabled"
    $ExcelChart = New-ExcelChartDefinition -XRange Name -YRange Count -ChartType Pie -Title "Litigation Hold Owner"
    $Mailboxes | Group-Object -Property LitigationHoldOwner | Sort-Object -Property Count -Descending | Select Count, Name | Export-Excel -Path $ExcelFile -Append -WorksheetName "PieChart-LitigationHoldOwner" -ExcelChartDefinition $ExcelChart -AutoNameRange -Title "Litigation Hold Owner"
    
    Write-log INFO -Message "Generate the following Report: $ExcelFile"
}

Function Generate-EXORecipientReportBySMTPDomain
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$Domain
    )
    $Filter = '{ EmailAddresses -like "*' + $Domain + '*" }'
    $FilteredRecipients = Get-Recipient -Filter $Filter | select  Name, DisplayName, SamAccountName, PrimarySmtpAddress, WindowsLiveID, WhenMailboxCreated, RecipientType, RecipientTypeDetails, SKUAssigned
    $FilteredRecipients | group  RecipientType | ft Count, Name
    $DateFull = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    $ExcelFile = "Report_AllRecipients_" + $Domain + "_" + $DateFull + ".xlsx"
    $FilteredRecipients | Export-Excel $ExcelFile -TableName "AllRecipients" -Title "All Recipients" -TitleBold -WorksheetName "AllRecipients" -TableStyle Medium9 -AutoSize -AutoFilter
    Write-Log Warning -Message "The CSV File has been generated: $ExcelFile"
}

Function Find-UserMailboxUsingEmailFromCSV
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$CSVFile
    )
    
    Try
    {
        Read-Host "Expected CSV Column: Mail"
        $Users = Import-Csv $CSVFile
        Write-Log -Level INFO -Message "The script import successfully :$CSVFile"
        $ImportStatus = "Yes"
    }
    Catch
    {
        $ErrorMessage = $Error[0].Exception.Message
        $CMDLet = $Error[0].InvocationInfo.Line
        $FailedItem = $Error[0].Exception.ItemName
        Write-Log -Level Error -Message "Failed to import $CSVFile "
        Write-Log -Level Error -Message "Failed to run the following CMDLet: $CMDLet"
        Write-Log -Level Error -Message "Failed with Error:$ErrorMessage"
        Write-Log -Level Error -Message "The Script will stop"
        $ImportStatus = "No"
    }
    
    If ($ImportStatus -eq "Yes")
    {
        
        #Initiate the Hash Table
        [Int]$i = 1
        $Table = $Null
        $Table = @()
        $Count = ($Users | Measure).count
        
        ForEach ($User in $Users)
        {
            $EmailAddress = $Null
            $EmailAddress = $User.Mail
            $RecipientTypeDetails = $Null
            $WhenSoftDeleted = $Null
            $WhenCreated = $Null
            $PrimarySmtpAddress = $Null
            $LitigationHoldEnabled = $Null
            $FoundStatus = "No"
            Write-log Warning -message "The script is analyzing $EmailAddress ….. --- $i/$Count"
            Try
            {
                Write-log Warning -message "The script is searching for $EmailAddress as recipient"
                $Recipient = $Null
                $Recipient = Get-Recipient $EmailAddress -IncludeSoftDeletedRecipients -ErrorAction Stop
                Write-Log -Level INFO -Message "The script found $EmailAddress as recipient in EXO"
                $FoundStatus = "Yes"
                $RecipientTypeDetails = $Recipient.RecipientTypeDetails
                $WhenSoftDeleted = $Recipient.WhenSoftDeleted
                $WhenCreated = $Recipient.WhenCreated
                $PrimarySmtpAddress = $Recipient.PrimarySmtpAddress
                $LitigationHoldEnabled = $Recipient.LitigationHoldEnabled
                
            }
            Catch
            {
                $ErrorMessage = $Error[0].Exception.Message
                $CMDLet = $Error[0].InvocationInfo.Line
                $FailedItem = $Error[0].Exception.ItemName
                Write-Log -Level Error -Message "Failed to find $EmailAddress"
                Write-Log -Level Error -Message "Failed to run the following CMDLet: $CMDLet"
                Write-Log -Level Error -Message "Failed with Error:$ErrorMessage"
                $FoundStatus = "No"
                $RecipientTypeDetails = "Not Found"
                $RecipientTypeDetails = "Not Found"
                $WhenSoftDeleted = "Not Found"
                $WhenCreated = "Not Found"
                $PrimarySmtpAddress = "Not Found"
                $LitigationHoldEnabled = "Not Found"
            }
            
            
            
            $Table += New-object PSobject -Property ([Ordered] @{
                    EmailAddress         = $EmailAddress;
                    PrimarySmtpAddress   = $PrimarySmtpAddress;
                    RecipientTypeDetails = $RecipientTypeDetails;
                    WhenCreated             = $WhenCreated;
                    WhenSoftDeleted         = $WhenSoftDeleted;
                    LitigationHoldEnabled = $LitigationHoldEnabled;
                })
            
            $i++
        }
        
        $DateFull = Get-Date -Format "ddMMyyyy_HH-mm-ss"
        $ReportFilexlsx = ".\Report_Recipients_" + $DateFull + ".xlsx"
        $Table | Export-Excel $ReportFilexlsx -TableName "Recipients" -Title "Recipients" -TitleBold -WorksheetName "Recipients" -TableStyle Medium9 -AutoSize -AutoFilter
        Write-log INFO -Message "Generate the following Report: $ReportFilexlsx"
    }
    
}
Function Find-UserUsingEmailFromCSV
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$CSVFile
    )
    
    Try
    {
        Read-Host "Expected CSV Column: EmailAddress"
        $Users = Import-Csv $CSVFile
        Write-Log -Level INFO -Message "The script import successfully :$CSVFile"
        $ImportStatus = "Yes"
    }
    Catch
    {
        $ErrorMessage = $Error[0].Exception.Message
        $CMDLet = $Error[0].InvocationInfo.Line
        $FailedItem = $Error[0].Exception.ItemName
        Write-Log -Level Error -Message "Failed to import $CSVFile "
        Write-Log -Level Error -Message "Failed to run the following CMDLet: $CMDLet"
        Write-Log -Level Error -Message "Failed with Error:$ErrorMessage"
        Write-Log -Level Error -Message "The Script will stop"
        $ImportStatus = "No"
    }
    
    If ($ImportStatus -eq "Yes")
    {
        
        #Initiate the Hash Table
        [Int]$i = 1
        $Table = $Null
        $Table = @()
        $Count = ($Users | Measure).count
        
        ForEach ($User in $Users)
        {
            $EmailAddress = $Null
            $EmailAddress = $User.EmailAddress
            $FirstName = $Null
            $LastName = $Null
            $DisplayName = $Null
            $WindowsLiveID = $Null
            $DistinguishedName = $Null
            $RecipientTypeDetails = $Null
            $AuthenticationType = $Null
            $Capabilities = $Null
            $WhenCreated = $Null
            $WhenMailboxCreated = $Null
            $Title = $Null
            $Department = $Null
            $IsDirSynced = $Null
            $Office = $Null
            $Manager = $Null
            $CountryOrRegion = $Null
            $City = $Null
            $Alias = $Null
            Write-log Warning -message "The script is analyzing $EmailAddress ….. --- $i/$Count"
            Try
            {
                Write-log Warning -message "The script is searching for $EmailAddress as recipient"
                $Recipient = $Null
                $Recipient = Get-Recipient $EmailAddress -ErrorAction Stop
                Write-Log -Level INFO -Message "The script found $EmailAddress as recipient in EXO"
                $FoundStatus = "Yes"
                $FirstName = $Recipient.FirstName
                $LastName = $Recipient.LastName
                $DisplayName = $Recipient.DisplayName
                $WindowsLiveID = $Recipient.WindowsLiveID
                $DistinguishedName = $Recipient.DistinguishedName
                $RecipientTypeDetails = $Recipient.RecipientTypeDetails
                $AuthenticationType = $Recipient.AuthenticationType
                $Capabilities = $Recipient.Capabilities
                $WhenCreated = $Recipient.WhenCreated
                $WhenMailboxCreated = $Recipient.WhenMailboxCreated
                $Title = $Recipient.Title
                $Department = $Recipient.Department
                $IsDirSynced = $Recipient.IsDirSynced
                $Office = $Recipient.Office
                $Manager = $Recipient.Manager
                $CountryOrRegion = $Recipient.CountryOrRegion
                $City = $Recipient.City
                $Alias = $Recipient.Alias
            }
            Catch
            {
                $ErrorMessage = $Error[0].Exception.Message
                $CMDLet = $Error[0].InvocationInfo.Line
                $FailedItem = $Error[0].Exception.ItemName
                Write-Log -Level Error -Message "Failed to find $EmailAddress"
                Write-Log -Level Error -Message "Failed to run the following CMDLet: $CMDLet"
                Write-Log -Level Error -Message "Failed with Error:$ErrorMessage"
                $FoundStatus = "No"
                $FirstName = "Not Found"
                $LastName = "Not Found"
                $DisplayName = "Not Found"
                $WindowsLiveID = "Not Found"
                $DistinguishedName = "Not Found"
                $RecipientTypeDetails = "Not Found"
                $AuthenticationType = "Not Found"
                $Capabilities = "Not Found"
                $WhenCreated = "Not Found"
                $WhenMailboxCreated = "Not Found"
                $Title = "Not Found"
                $Department = "Not Found"
                $IsDirSynced = "Not Found"
                $Office = "Not Found"
                $Manager = "Not Found"
                $CountryOrRegion = "Not Found"
                $City = "Not Found"
                $Alias = "Not Found"
            }
            
            
            
            $Table += New-object PSobject -Property ([Ordered] @{
                    EmailAddress         = $EmailAddress;
                    FirstName             = $FirstName;
                    LastName             = $LastName;
                    DisplayName             = $DisplayName;
                    Title                 = $Title;
                    Department             = $Department;
                    Office                 = $Office;
                    City                 = $City;
                    CountryOrRegion         = $CountryOrRegion;
                    Manager                 = $Manager;
                    WindowsLiveID         = $WindowsLiveID;
                    Alias                 = $Alias;
                    DistinguishedName    = $DistinguishedName;
                    RecipientTypeDetails = $RecipientTypeDetails;
                    AuthenticationType   = $AuthenticationType;
                    IsDirSynced             = $IsDirSynced;
                    Capabilities         = $Capabilities;
                    WhenCreated             = $WhenCreated;
                    WhenMailboxCreated   = $WhenMailboxCreated;
                })
            
            $i++
        }
        
    $DateFull = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    $ReportFilexlsx = ".\Report_Recipients_" + $DateFull + ".xlsx"
    $Table | Export-Excel $ReportFilexlsx -TableName "AllRecipients" -Title "All Recipients" -TitleBold -WorksheetName "AllRecipients" -TableStyle Medium9 -AutoSize -AutoFilter
    Write-log INFO -Message "Generate the following Report: $ReportFilexlsx"
    }
    
}

Function Generate-AllAcceptedDomainsDMARCReport
{
    [CmdletBinding()]
    param ()
    
    $Domains = Get-AcceptedDomain
    #Initiate the Hash Table
    [Int]$i = 1
    $Table = $Null
    $Table = @()
    $Count = ($Domains | Measure).count
    
    Foreach ($Domain in $Domains)
    {
        $Identity = $Null
        $Identity = $Domain.Identity
        Write-log Warning -message "The script is analyzing The domain: $Identity ….. --- $i/$Count"
        #Check SPF Record
        Try
        {
            $TXTRecords = $Null
            $TXTRecords = $Null
            $TXTRecords = Resolve-DnsName -Name $Identity -Type TXT -ErrorAction SilentlyContinue
            $SPFRecord = $TXTRecords | where { $_.Strings -like "*spf*" }
            $SPFRecordName = $Null
            $SPFRecordName = $SPFRecord.Name
            $SPFRecordValue = $Null
            $SPFRecordValue = $SPFRecord.Strings -join ";"
        }
        Catch
        {
            Write-log Error -Message "Failed to find SPF record"
        }
        # Check DMARC
        Try
        {
            $DMARCTXTRecordName= $Null
            $DMARC = $Null
            $DMARCName = $Null
            $DMARCValue = $Null
            $DMARCTXTRecordName = "_dmarc." + $Identity
            $DMARC = Resolve-DnsName -Name $DMARCTXTRecordName -Type TXT -ErrorAction SilentlyContinue
            $DMARCName = $DMARC.Name
            $DMARCValue = $DMARC.Text -join ";"
        }
        Catch
        {
            $ErrorMessage = $Error[0].Exception.Message
            Write-log Error -Message "Failed to find DMARC - $ErrorMessage"
        }
        # Check MX Record
        Try
        {
            $MXRecords = $Null
            $MXRecords = Resolve-DnsName -Name $Identity -Type MX -ErrorAction SilentlyContinue
            $MXRecords = $MXRecords | where { $_.Type -eq "MX" }
            $MXRecordValue = $Null
            $MXRecordValue = @()
            foreach ($MXRecord in $MXRecords)
            {
                $MXRecordName = $MXRecord.NameExchange
                $MXRecordPreference = $MXRecord.Preference
                $MXRecordValue += $MXRecordName + ':' + $MXRecordPreference
            }
            $MXRecordValue = $MXRecordValue -Join " - "
            
        }
        Catch
        {
            $ErrorMessage = $Error[0].Exception.Message
            Write-log Error -Message "Failed to find MX Record - $ErrorMessage"
        }
        
        $Table += New-object PSobject -Property ([Ordered] @{
                Domain = $Identity;
                MXRecord = $MXRecordValue;
                SPFRecord = $SPFRecordValue;
                DMARC    = $DMARCValue;
                
            })
        
        $i++
        
    }
    $DateFull = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    $ReportFilexlsx = "AllAcceptedDomains_DMARCReports_" + $DateFull + ".xlsx"
    $Table | Export-Excel $ReportFilexlsx -TableName "DMARCAcceptedDomains" -Title "DMARC Accepted Domains" -TitleBold -WorksheetName "DMARCAcceptedDomains" -TableStyle Medium9 -AutoSize -AutoFilter
    Write-log INFO -Message "Generate the following Report: $ReportFilexlsx"
}

Function Get-EXODDGroupMembership
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$EmailAddress
    )
    $DDG = Get-DynamicDistributionGroup -Identity $EmailAddress
    $Members = Get-Recipient -RecipientPreviewFilter ($DDG.RecipientFilter) | Select DisplayName, PrimarySmtpAddress
    $LocalPart = $EmailAddress.Substring(0, $EmailAddress.LastIndexOf("@"))
    $DateFull = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    $ExcelFile = "Members_Of_" + $LocalPart + "_" + $DateFull + ".xlsx"
    $Members | Export-Excel $ExcelFile -TableName "MemberOf" -Title "MemberOf" -TitleBold -WorksheetName "MemberOf" -TableStyle Medium9 -AutoSize -AutoFilter
    $Members | Ft
    Write-Log Warning -Message "The following file was generated: $ExcelFile"
}

Function Change-EXORetentionPolicy
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$Email,
        [Parameter(Mandatory = $true,
                   Position = 2)]
        [String]$RetentionPolicy
    )
    
    # Check if the mailbox has a Online Archive
    $ArchiveName = $Null
    $Mailbox = $Null
    $ArchiveName2 = $Null
    $Mailbox2 = $Null
    $CurrentRetentionPolicy = $Null
    $CurrentRetentionPolicy2 = $Null
    $Mailbox = Get-Mailbox $Email
    $ArchiveName = $Mailbox.ArchiveName
    $CurrentRetentionPolicy = $Mailbox.RetentionPolicy
    Write-Log -Level Warning -Message "$Email has the following settings:"
    Write-Log -Level Warning -Message "--- Online Archive Name: $ArchiveName"
    Write-Log -Level Warning -Message "--- RetentionPolicy: $CurrentRetentionPolicy"
    
    if ($ArchiveName)
    {
        Write-Log -Level Warning -Message "The script will assign the following Retention policy: $RetentionPolicy"
        # Assign Retention
        Set-Mailbox $Email -RetentionPolicy $RetentionPolicy
        #sleep 10
        Start-ManagedFolderAssistant -Identity $Email
        #sleep 10
        $Mailbox2 = Get-Mailbox $Email
        $ArchiveName2 = $Mailbox2.ArchiveName
        $CurrentRetentionPolicy2 = $Mailbox2.RetentionPolicy
        Write-Log -Level Warning -Message "$Email has the following settings:"
        Write-Log -Level Warning -Message "--- Online Archive Name: $ArchiveName2"
        Write-Log -Level Warning -Message "--- RetentionPolicy: $CurrentRetentionPolicy2"
        
    }
    Else
    {
        Write-Log -Level -Level Error -Message "Online Archive was NOT found"
        Write-Log -Level Warning -Message "Online Archive maiblox will be enabled for $Email"
        Enable-Mailbox -Identity $Email -Archive
        
    }
    
}

Function Create-EXOSharedMailboxWithSG
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$LocalPart,
        [Parameter(Mandatory = $true,
                   Position = 2)]
        [String]$Domain
    )
    
    #Variable
    $SecurityGroupName = "MBX_" + $LocalPart + "_FP"
    $SecurityGroupEmailAddress = $SecurityGroupName + "@" + $Domain
    $PrimaryEmailAddress = $LocalPart + "@" + $Domain
    $CreateSharedMBXStatus = "Failed"
    $CreateSGStatus = "Failed"
    $GrantSendAsStatus = "Failed"
    # Create Security Group
    Try
    {
        Write-Log -Level Info -Message "The script will try to create the Mail-Enabled Security Group $SecurityGroupName ($SecurityGroupEmailAddress)"
        New-DistributionGroup -Name $SecurityGroupName -Alias $SecurityGroupName -Type security -PrimarySmtpAddress $SecurityGroupEmailAddress
        Write-Log -Level warning -Message "The script successfully created the Mail-Enabled Security Group $SecurityGroupName ($SecurityGroupEmailAddress)"
        $CreateSGStatus = "Success"
        
        # Create Shared Mailbox
        Try
        {
            Write-Log -Level Info -Message "The script will try to create the Shared Mailbox $LocalPart ($PrimaryEmailAddress)"
            New-Mailbox -Shared -Name $LocalPart -DisplayName $LocalPart -Alias $LocalPart -PrimarySmtpAddress $PrimaryEmailAddress
            Write-Log -Level warning -Message "The script successfully created the Shared Mailbox $LocalPart ($PrimaryEmailAddress)"
            $CreateSharedMBXStatus = "Success"
            #Assign SendAs Permission to Security Group
            Try
            {
                Write-Log -Level Info -Message "The script will try to grant SendAs Permission $PrimaryEmailAddress to $SecurityGroupEmailAddress" 
                Add-RecipientPermission -Identity $PrimaryEmailAddress -Trustee $SecurityGroupEmailAddress -AccessRights SendAs -confirm:$false
                Write-Log -Level warning -Message "The script successfully grant SendAs Permission $PrimaryEmailAddress to $SecurityGroupEmailAddress"
                $GrantSendAsStatus = "Success"
            }
            Catch
            {
                $ErrorMessage = $Error[0].Exception.Message
                $CMDLet = $Error[0].InvocationInfo.Line
                $FailedItem = $Error[0].Exception.ItemName
                Write-Log -Level Error -Message "Failed to grant SendAs Permission $PrimaryEmailAddress to $SecurityGroupEmailAddress"
                Write-Log -Level Error -Message "Failed to run the following CMDLet: $CMDLet"
                Write-Log -Level Error -Message "Failed with Error:$ErrorMessage"
                
            }
            
            #Assign FullAccess Permission to Security Group
            Try
            {
                Write-Log -Level Info -Message "The script will try to grant FullAccess $PrimaryEmailAddress to $SecurityGroupEmailAddress"
                Add-MailboxPermission -Identity $PrimaryEmailAddress -User $SecurityGroupEmailAddress -AccessRights FullAccess -InheritanceType All
                Write-Log -Level warning -Message "The script successfully grant FullAccess $PrimaryEmailAddress to $SecurityGroupEmailAddress"
                $GrantFullAccessStatus = "Success"
                
                
            }
            Catch
            {
                $ErrorMessage = $Error[0].Exception.Message
                $CMDLet = $Error[0].InvocationInfo.Line
                $FailedItem = $Error[0].Exception.ItemName
                Write-Log -Level Error -Message "Failed to grant FullAccess $PrimaryEmailAddress to $SecurityGroupEmailAddress"
                Write-Log -Level Error -Message "Failed to run the following CMDLet: $CMDLet"
                Write-Log -Level Error -Message "Failed with Error:$ErrorMessage"
                $GrantFullAccessStatus = "Failed"
            }
        }
        Catch
        {
            $ErrorMessage = $Error[0].Exception.Message
            $CMDLet = $Error[0].InvocationInfo.Line
            $FailedItem = $Error[0].Exception.ItemName
            Write-Log -Level Error -Message "Failed to create the Shared Mailbox $LocalPart ($PrimaryEmailAddress)"
            Write-Log -Level Error -Message "Failed to run the following CMDLet: $CMDLet"
            Write-Log -Level Error -Message "Failed with Error:$ErrorMessage"
            
        }
    }
    Catch
    {
        $ErrorMessage = $Error[0].Exception.Message
        $CMDLet = $Error[0].InvocationInfo.Line
        $FailedItem = $Error[0].Exception.ItemName
        Write-Log -Level Error -Message "Failed to create the Mail-Enabled Security Group $SecurityGroupName ($SecurityGroupEmailAddress)"
        Write-Log -Level Error -Message "Failed to run the following CMDLet: $CMDLet"
        Write-Log -Level Error -Message "Failed with Error:$ErrorMessage"
        
    }

    # Output
    $OutPut = $null
    $OutPut = @()
    $OutPut += New-object PSobject -Property ([Ordered] @{
            SharedMailboxPrimaryEmailAddress = $PrimaryEmailAddress;
            SecurityGroupName                 = $SecurityGroupName;
            CreateSharedMBXStatus             = $CreateSharedMBXStatus;
            GrantSendAsStatus                 = $GrantSendAsStatus;
            GrantFullAccessStatus             = $GrantFullAccessStatus;
        })
    Return $OutPut
}

Function Get-EXODynamicDGMembers
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [string]$EmailAddress
    )
    
    $DateFull = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    $LocalPart = $EmailAddress.Substring(0, $EmailAddress.LastIndexOf("@"))
    $ReportFile = ".\Membership_Of_" + $LocalPart + "_" + $DateFull + ".csv"
    $DL = Get-DynamicDistributionGroup -Identity $EmailAddress
    $DLMembers = Get-Recipient -RecipientPreviewFilter ($DL.RecipientFilter)
    $DLMembers | Select DisplayName, PrimarySmtpAddress
    $DLMembers | Select DisplayName, PrimarySmtpAddress | Export-csv $ReportFile -NoTypeInformation -Encoding UTF8
    sleep 1
    Write-host "Generate the following Report: $ReportFile" -ForegroundColor Yellow
    
}

Function Check-SharedMailboxPermission
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [string]$SharedAddress
    )
    $Mailbox = $Null
    $Mailbox = Get-Mailbox $SharedAddress
    If ($Mailbox)
    {
        $DisplayName = $Mailbox.DisplayName
        $PrimarySMTPAddress = $Mailbox.PrimarysmtpAddress
        Write-host "Mailbox found $DisplayName ($PrimarySMTPAddress)"
        $Permissions = $Null
        $Permissions = Get-MailboxPermission $PrimarySMTPAddress
        Write-host "Current Mailbox Permission:"
        $Permissions | ft User, AccessRights
        If ($Permissions)
        {
            
            $FoundGroups = $Permissions | where { ($_.User -notlike "*@*") -and ($_.User -notlike "*\*") }
            
            If ($FoundGroups)
            {
                Foreach ($FoundGroup in $FoundGroups)
                {
                    $Securitygroup = $Null
                    $Securitygroup = $FoundGroup.User
                    Write-host "groupName is: $Securitygroup "
                    Get-DistributionGroupMember $Securitygroup | Select DisplayName, PrimarySmtpAddress
                }
            }
            
        }
        
    }
    Else
    {
        Write-host "Mailbox NOT found $SharedAddress"
    }
    
}

Function Generate-EXOMailboxesUsingAcceptedDomain
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$SMTPDomain
    )
    # Get all mailboxes with the specified SMTP domain
    $SMTPDomain = "@" + $SMTPDomain
    $Mailboxes = Get-Mailbox -ResultSize Unlimited -Filter "EmailAddresses -like '*$SMTPDomain'" | select  DisplayName, WindowsEmailAddress, PrimarySmtpAddress
    
    # Output the results
    
    $DateFull = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    $ReportFilexlsx = ".\Report_" + $SMTPDomain +"_" + $DateFull + ".xlsx"
    $Mailboxes | Export-Excel $ReportFilexlsx -TableName $SMTPDomain -Title $SMTPDomain -TitleBold -WorksheetName $SMTPDomain -TableStyle Medium9 -AutoSize -AutoFilter
    Write-log INFO -Message "Generate the following Report: $ReportFilexlsx"
    $Mailboxes
    
}

Function Restrict-EXOUnifiedGroupbySender
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$Identity,
        [Parameter(Mandatory = $false,
                   Position = 2)]
        [String]$AuthorizedSenders,
        [Parameter(Position = 3)]
        [String]$RejectedSenders
    )
    
    If ($AuthorizedSenders)
    {
        
        Try
        {
            Write-Log -Level INFO -Message "The script will configure the Office 365 to only accept messages from the following sender: $AuthorizedSenders"
            Write-Log -Level warning -Message "--- Current Permission:"
            $UnifiedGroup = $Null
            $UnifiedGroup = Get-UnifiedGroup -Identity $Identity
            $UnifiedGroup | select -ExpandProperty AcceptMessagesOnlyFromSendersOrMembers
            Read-Host "Are you sure you want to add $AuthorizedSenders Press <Enter> to continue or <Ctrl+C> to Cancel"
            Set-UnifiedGroup -Identity $Identity -AcceptMessagesOnlyFromSendersOrMembers @{ add = $AuthorizedSenders }
            Write-Log -Level Warning -Message "The script successfully configured the Office 365 to only accept messages from the following sender: $AuthorizedSenders"
            Write-Log -Level warning -Message "--- Current Permission:"
            $UnifiedGroup = $Null
            $UnifiedGroup = Get-UnifiedGroup -Identity $Identity
            $UnifiedGroup | select -ExpandProperty AcceptMessagesOnlyFromSendersOrMembers
        }
        Catch
        {
            $ErrorMessage = $Error[0].Exception.Message
            $CMDLet = $Error[0].InvocationInfo.Line
            $FailedItem = $Error[0].Exception.ItemName
            Write-Log -Level Error -Message "Failed to Add Authorized Sender: $AuthorizedSenders"
            Write-Log -Level Error -Message "Failed to run the following CMDLet: $CMDLet"
            Write-Log -Level Error -Message "Failed with Error:$ErrorMessage"
            $Status = "Failed"
        }
        
    }
    If ($RejectedSenders)
    {
        
        Try
        {
            Write-Log -Level INFO -Message "The script will configure the Office 365 to Reject messages from the following sender: $RejectedSenders"
            Write-Log -Level warning -Message "--- Current Permission:"
            $UnifiedGroup = $Null
            $UnifiedGroup = Get-UnifiedGroup -Identity $Identity
            $UnifiedGroup | select -ExpandProperty RejectMessagesFromSendersOrMembers
            Read-Host "Are you sure you want to add $RejectedSenders Press <Enter> to continue or <Ctrl+C> to Cancel"
            Set-UnifiedGroup -Identity $Identity -RejectMessagesFromSendersOrMembers @{ add = $RejectedSenders }
            Write-Log -Level Warning -Message "The script successfully configured the Office 365 to Reject messages from the following sender: $RejectedSenders "
            Write-Log -Level warning -Message "--- Current Permission:"
            $UnifiedGroup = $Null
            $UnifiedGroup = Get-UnifiedGroup -Identity $Identity
            $UnifiedGroup | select -ExpandProperty RejectMessagesFromSendersOrMembers
        }
        Catch
        {
            $ErrorMessage = $Error[0].Exception.Message
            $CMDLet = $Error[0].InvocationInfo.Line
            $FailedItem = $Error[0].Exception.ItemName
            Write-Log -Level Error -Message "Failed to Add Authorized Sender: $AuthorizedSenders"
            Write-Log -Level Error -Message "Failed to run the following CMDLet: $CMDLet"
            Write-Log -Level Error -Message "Failed with Error:$ErrorMessage"
            $Status = "Failed"
        }
        
    }
    
    
}

Function Get-EXOAllDGRoomList
{
    [CmdletBinding()]
    param ()
    
    Get-DistributionGroup -RecipientTypeDetails Roomlist | Select Name, PrimarySMTPAddress
}

Function Add-EXORoomToRoomList
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$RoomListName,
        [Parameter(Mandatory = $true,
                   Position = 2)]
        [String]$RoomName
    )
    Write-Host "Check for Room list Members before change: " -ForegroundColor Yellow
    Get-DistributionGroupMember -identity $RoomListName | Ft Name, PrimarySmtpAddress
    Add-DistributionGroupMember -Identity $RoomListName -Member $RoomName
    sleep 10
    Write-Host "Check for Room list Members after change: " -ForegroundColor Green
    Get-DistributionGroupMember -identity $RoomListName | Ft Name, PrimarySmtpAddress
}

Function Cleanup-EXORecipientsUsingSMTPDomain
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$SMTPDomain
    )
    
    $DateFull = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    Try
    {
        $AADObjects = Get-AzureADDomainNameReference -Name $SMTPDomain
        $DomainIsFederated = "Not"
        $Count = ($AADObjects | Measure).count
        Write-Log -Level Info -Message "The script found $Count of Object using $SMTPDomain"
        
    }
    Catch
    {
        $ErrorMessage = $Error[0].Exception.Message
        $CMDLet = $Error[0].InvocationInfo.Line
        $FailedItem = $Error[0].Exception.ItemName
        Write-Log -Level Error -Message "The domain is federated"
        Write-Log -Level Error -Message "Failed to run the following CMDLet: $CMDLet"
        Write-Log -Level Error -Message "Failed with Error:$ErrorMessage"
        $DomainIsFederated = $Null
        Write-Log -Level Error -Message "Do you want to continue and update only the EmailAddresses for Cloud Only accounts"
        Read-Host "Press <Enter> to continue or <CTRL +C> to cancel"
    }
    
    Write-Log -Level warning -Message "The script is searching for Recipients using $SMTPDomain (which is $DomainIsFederated federated)"
    $Filter = "(EmailAddresses -like " + '"*@' + $SMTPDomain + '"' + ")"
    $Recipients = Get-Recipient -ResultSize unlimited -filter $Filter
    $OnMicrosoftDefaultDomain = (Get-AcceptedDomain | where { ($_.domainName -like "*.onmicrosoft.com") -and ($_.domainName -notlike "*mail.onmicrosoft.com") } | select -First 1).DomainName
    #Initiate the Hash Table
    [Int]$i = 1
    $Table = $Null
    $Table = @()
    $Count = ($Recipients | Measure).count
    ForEach ($Recipient in $Recipients)
    {
        $PrimarySmtpAddress = $Null
        $PrimarySmtpAddress = $Recipient.PrimarySmtpAddress
        $Alias = $Null
        $Alias = $Recipient.Alias
        $DisplayName = $Null
        $DisplayName = $Recipient.DisplayName
        $RecipientTypeDetails = $Null
        $RecipientTypeDetails = $Recipient.RecipientTypeDetails
        $RecipientType = $Null
        $RecipientType = $Recipient.RecipientType
        $WindowsLiveID = $Null
        $WindowsLiveID = $Recipient.WindowsLiveID
        $EmailAddresses = $Null
        $EmailAddresses = $Recipient.EmailAddresses
        $RecipientStatus = $Null
        $RecipientStatus = @()
        
        Write-Log -Level Warning -message "The script is analyzing $DisplayName ($RecipientTypeDetails : $PrimarySmtpAddress) ….. --- $i/$Count"
        
        #Find Onmicrosoft Email Address
        $OnMicrosoft = $Null
        $OnMicrosoft = $EmailAddresses | where { $_ -match "onmicrosoft.com" } | where { $_ -match "smtp:" } | select -First 1
        If ($OnMicrosoft)
        {
            $OnMicrosoft = $OnMicrosoft.Substring(5)
        }
        else
        {
            $OnMicrosoft = $Null
            $OnMicrosoft = $Alias + "@" + $OnMicrosoftDefaultDomain
        }
        $UpdatePrimarySMTPAddress = $Null
        Write-Log -Level Info -message "Checking if UPN $WindowsLiveID is using the $SMTPDomain"
        If (($RecipientType -eq "UserMailbox") -and ($WindowsLiveID -match $SMTPDomain))
        {
            
            Write-Log -Level warning -message "UPN $WindowsLiveID is using the $SMTPDomain"
            Write-Log -Level Info -message "Try to update UserPrincipalName From $WindowsLiveID to $OnMicrosoft"
            Set-MsolUserPrincipalName -UserPrincipalName $WindowsLiveID -NewUserPrincipalName $OnMicrosoft
            Write-Log -Level Warning -message "Updated UserPrincipalName From $WindowsLiveID to $OnMicrosoft"
            sleep 2
            
        }
        $i++
        
    }
    
    Write-Log -Level warning -Message "After UPN changes, the script will pause for 15 mins, then update remove proxy address"
    sleep 900
    #Read-Host "Continue"
    ForEach ($Recipient in $Recipients)
    {
        $PrimarySmtpAddress = $Null
        $PrimarySmtpAddress = $Recipient.PrimarySmtpAddress
        $Alias = $Null
        $Alias = $Recipient.Alias
        $DisplayName = $Null
        $DisplayName = $Recipient.DisplayName
        $RecipientTypeDetails = $Null
        $RecipientTypeDetails = $Recipient.RecipientTypeDetails
        $RecipientType = $Null
        $RecipientType = $Recipient.RecipientType
        $WindowsLiveID = $Null
        $WindowsLiveID = $Recipient.WindowsLiveID
        $EmailAddresses = $Null
        $EmailAddresses = $Recipient.EmailAddresses
        $RecipientStatus = $Null
        $RecipientStatus = @()
        
        Write-Log -Level Warning -message "The script is analyzing $DisplayName ($RecipientTypeDetails : $PrimarySmtpAddress) ….. --- $i/$Count"
        
        #Find Onmicrosoft Email Address
        $OnMicrosoft = $Null
        $OnMicrosoft = $EmailAddresses | where { $_ -match "onmicrosoft.com" } | where { $_ -match "smtp:" } | select -First 1
        If ($OnMicrosoft)
        {
            $OnMicrosoft = $OnMicrosoft.Substring(5)
        }
        else
        {
            $OnMicrosoft = $Null
            $OnMicrosoft = $Alias + "@" + $OnMicrosoftDefaultDomain
        }
        $UpdatePrimarySMTPAddress = $Null
        switch ($RecipientType)
        {
            UserMailbox
            {
                # Update PrimarySMTPAddress
                Try
                {
                    
                    Write-Log -Level Info -message "Try to update the WindowsEmailAddress and PrimarySMTPAddress with $OnMicrosoft"
                    Set-mailbox -Identity $Alias -WindowsEmailAddress $OnMicrosoft -MicrosoftOnlineServicesID $OnMicrosoft
                    Write-Log -Level Warning -message "Updated the WindowsEmailAddress and PrimarySMTPAddress with $OnMicrosoft"
                    $UpdatePrimarySMTPAddress = "Updated with: $OnMicrosoft"
                }
                Catch
                {
                    $ErrorMessage = $Error[0].Exception.Message
                    $CMDLet = $Error[0].InvocationInfo.Line
                    $FailedItem = $Error[0].Exception.ItemName
                    Write-Log -Level Error -Message "Failed to update the WindowsEmailAddress and PrimarySMTPAddress with $OnMicrosoft"
                    Write-Log -Level Error -Message "Failed to run the following CMDLet: $CMDLet"
                    Write-Log -Level Error -Message "Failed with Error:$ErrorMessage"
                    $UpdatePrimarySMTPAddress = "Fail to update with: $OnMicrosoft"
                }
                
                $DomainEmailAddresses = $EmailAddresses | where { $_ -match $SMTPDomain }
                foreach ($DomainEmailAddress in $DomainEmailAddresses)
                {
                    # Remove ProxyAddress
                    Try
                    {
                        Write-Log -Level Info -Message "Try to remove ProxyAddress: $DomainEmailAddress"
                        Set-Mailbox -identity $Alias -EmailAddresses @{ Remove = $DomainEmailAddress }
                        Write-Log -Level Warning -Message "Removed ProxyAddress: $DomainEmailAddress"
                        $RemoveProxyAddress = "Removed : $DomainEmailAddress"
                    }
                    Catch
                    {
                        $ErrorMessage = $Error[0].Exception.Message
                        $CMDLet = $Error[0].InvocationInfo.Line
                        $FailedItem = $Error[0].Exception.ItemName
                        Write-Log -Level Error -Message "Failed to remove ProxyAddress: $DomainEmailAddress"
                        Write-Log -Level Error -Message "Failed to run the following CMDLet: $CMDLet"
                        Write-Log -Level Error -Message "Failed with Error:$ErrorMessage"
                        $RemoveProxyAddress = "Fail to remove : $DomainEmailAddress"
                    }
                    $Table += New-object PSobject -Property ([Ordered] @{
                            DisplayName                 = $DisplayName;
                            Alias                     = $Alias;
                            RecipientTypeDetails     = $RecipientTypeDetails;
                            RecipientType             = $RecipientType;
                            PrimarySmtpAddress         = $PrimarySmtpAddress;
                            WindowsLiveID             = $WindowsLiveID;
                            UpdatePrimarySMTPAddress = $UpdatePrimarySMTPAddress;
                            RemoveProxyAddress         = $RemoveProxyAddress;
                        })
                    
                }
            }
            DynamicDistributionGroup
            {
                # Update PrimarySMTPAddress
                Try
                {
                    Write-Log -Level Info -message "Try to update the PrimarySMTPAddress with $OnMicrosoft"
                    Set-DynamicDistributionGroup -Identity $Alias -PrimarySmtpAddress $OnMicrosoft
                    Write-Log -Level Warning -message "Updated the WindowsEmailAddress and PrimarySMTPAddress with $OnMicrosoft"
                    $UpdatePrimarySMTPAddress = "Updated with: $OnMicrosoft"
                }
                Catch
                {
                    $ErrorMessage = $Error[0].Exception.Message
                    $CMDLet = $Error[0].InvocationInfo.Line
                    $FailedItem = $Error[0].Exception.ItemName
                    Write-Log -Level Error -Message "Failed to update PrimarySMTPAddress with $OnMicrosoft"
                    Write-Log -Level Error -Message "Failed to run the following CMDLet: $CMDLet"
                    Write-Log -Level Error -Message "Failed with Error:$ErrorMessage"
                    $UpdatePrimarySMTPAddress = "Fail to update with: $OnMicrosoft"
                }
                
                $DomainEmailAddresses = $EmailAddresses | where { $_ -match $SMTPDomain }
                foreach ($DomainEmailAddress in $DomainEmailAddresses)
                {
                    # Remove ProxyAddress
                    Try
                    {
                        Write-Log -Level Info -Message "Try to remove ProxyAddress: $DomainEmailAddress"
                        Set-DynamicDistributionGroup -identity $Alias -EmailAddresses @{ Remove = $DomainEmailAddress }
                        Write-Log -Level Warning -Message "Removed ProxyAddress: $DomainEmailAddress"
                        $RemoveProxyAddress = "Removed : $DomainEmailAddress"
                    }
                    Catch
                    {
                        $ErrorMessage = $Error[0].Exception.Message
                        $CMDLet = $Error[0].InvocationInfo.Line
                        $FailedItem = $Error[0].Exception.ItemName
                        Write-Log -Level Error -Message "Failed to remove ProxyAddress: $DomainEmailAddress"
                        Write-Log -Level Error -Message "Failed to run the following CMDLet: $CMDLet"
                        Write-Log -Level Error -Message "Failed with Error:$ErrorMessage"
                        $RemoveProxyAddress = "Fail to remove : $DomainEmailAddress"
                    }
                    $Table += New-object PSobject -Property ([Ordered] @{
                            DisplayName                 = $DisplayName;
                            Alias                     = $Alias;
                            RecipientTypeDetails     = $RecipientTypeDetails;
                            RecipientType             = $RecipientType;
                            PrimarySmtpAddress         = $PrimarySmtpAddress;
                            WindowsLiveID             = $WindowsLiveID;
                            UpdatePrimarySMTPAddress = $UpdatePrimarySMTPAddress;
                            RemoveProxyAddress         = $RemoveProxyAddress;
                        })
                    
                }
            }
            MailNonUniversalGroup
            {
                # Update PrimarySMTPAddress
                Try
                {
                    Write-Log -Level Info -Message "Try to update the PrimarySMTPAddress with $OnMicrosoft"
                    Set-DistributionGroup -Identity $Alias -PrimarySmtpAddress $OnMicrosoft
                    Write-Log -Level Warning -Message "Updated PrimarySMTPAddress with $OnMicrosoft"
                    $UpdatePrimarySMTPAddress = "Updated with: $OnMicrosoft"
                }
                Catch
                {
                    $ErrorMessage = $Error[0].Exception.Message
                    $CMDLet = $Error[0].InvocationInfo.Line
                    $FailedItem = $Error[0].Exception.ItemName
                    Write-Log -Level Error -Message "Failed to update PrimarySMTPAddress with $OnMicrosoft"
                    Write-Log -Level Error -Message "Failed to run the following CMDLet: $CMDLet"
                    Write-Log -Level Error -Message "Failed with Error:$ErrorMessage"
                    $UpdatePrimarySMTPAddress = "Fail to update with: $OnMicrosoft"
                }
                
                $DomainEmailAddresses = $EmailAddresses | where { $_ -match $SMTPDomain }
                foreach ($DomainEmailAddress in $DomainEmailAddresses)
                {
                    # Remove ProxyAddress
                    Try
                    {
                        Write-Log -Level Info -Message "Try to remove ProxyAddress: $DomainEmailAddress"
                        Set-DistributionGroup -identity $Alias -EmailAddresses @{ Remove = $DomainEmailAddress }
                        Write-Log -Level Warning -Message "Removed ProxyAddress: $DomainEmailAddress"
                        $RemoveProxyAddress = "Removed : $DomainEmailAddress"
                    }
                    Catch
                    {
                        $ErrorMessage = $Error[0].Exception.Message
                        $CMDLet = $Error[0].InvocationInfo.Line
                        $FailedItem = $Error[0].Exception.ItemName
                        Write-Log -Level Error -Message "Failed to remove ProxyAddress: $DomainEmailAddress"
                        Write-Log -Level Error -Message "Failed to run the following CMDLet: $CMDLet"
                        Write-Log -Level Error -Message "Failed with Error:$ErrorMessage"
                        $RemoveProxyAddress = "Fail to remove : $DomainEmailAddress"
                    }
                    $Table += New-object PSobject -Property ([Ordered] @{
                            DisplayName                 = $DisplayName;
                            Alias                     = $Alias;
                            RecipientTypeDetails     = $RecipientTypeDetails;
                            RecipientType             = $RecipientType;
                            PrimarySmtpAddress         = $PrimarySmtpAddress;
                            WindowsLiveID             = $WindowsLiveID;
                            UpdatePrimarySMTPAddress = $UpdatePrimarySMTPAddress;
                            RemoveProxyAddress         = $RemoveProxyAddress;
                        })
                    
                }
            }
            MailUniversalDistributionGroup
            {
                # Update PrimarySMTPAddress
                Try
                {
                    Write-Log -Level Info -message "Try to update the PrimarySMTPAddress with $OnMicrosoft"
                    Set-DistributionGroup -Identity $Alias -PrimarySmtpAddress $OnMicrosoft
                    Write-Log -Level Warning -message "Updated PrimarySMTPAddress with $OnMicrosoft"
                    $UpdatePrimarySMTPAddress = "Updated with: $OnMicrosoft"
                }
                Catch
                {
                    $ErrorMessage = $Error[0].Exception.Message
                    $CMDLet = $Error[0].InvocationInfo.Line
                    $FailedItem = $Error[0].Exception.ItemName
                    Write-Log -Level Error -Message "Failed to update PrimarySMTPAddress with $OnMicrosoft"
                    Write-Log -Level Error -Message "Failed to run the following CMDLet: $CMDLet"
                    Write-Log -Level Error -Message "Failed with Error:$ErrorMessage"
                    $UpdatePrimarySMTPAddress = "Fail to update with: $OnMicrosoft"
                }
                
                $DomainEmailAddresses = $EmailAddresses | where { $_ -match $SMTPDomain }
                foreach ($DomainEmailAddress in $DomainEmailAddresses)
                {
                    # Remove ProxyAddress
                    Try
                    {
                        Write-Log -Level Info -message "Try to remove ProxyAddress: $DomainEmailAddress"
                        Set-DistributionGroup -identity $Alias -EmailAddresses @{ Remove = $DomainEmailAddress }
                        Write-Log -Level Warning -message "Removed ProxyAddress: $DomainEmailAddress"
                        $RemoveProxyAddress = "Removed : $DomainEmailAddress"
                    }
                    Catch
                    {
                        $ErrorMessage = $Error[0].Exception.Message
                        $CMDLet = $Error[0].InvocationInfo.Line
                        $FailedItem = $Error[0].Exception.ItemName
                        Write-Log -Level Error -Message "Failed to remove ProxyAddress: $DomainEmailAddress"
                        Write-Log -Level Error -Message "Failed to run the following CMDLet: $CMDLet"
                        Write-Log -Level Error -Message "Failed with Error:$ErrorMessage"
                        $RemoveProxyAddress = "Fail to remove : $DomainEmailAddress"
                    }
                    $Table += New-object PSobject -Property ([Ordered] @{
                            DisplayName                 = $DisplayName;
                            Alias                     = $Alias;
                            RecipientTypeDetails     = $RecipientTypeDetails;
                            RecipientType             = $RecipientType;
                            PrimarySmtpAddress         = $PrimarySmtpAddress;
                            WindowsLiveID             = $WindowsLiveID;
                            UpdatePrimarySMTPAddress = $UpdatePrimarySMTPAddress;
                            RemoveProxyAddress         = $RemoveProxyAddress;
                        })
                    
                }
            }
            MailUniversalSecurityGroup
            {
                # Update PrimarySMTPAddress
                Try
                {
                    Write-Log -Level Info -message "Try to update the PrimarySMTPAddress with $OnMicrosoft"
                    Set-DistributionGroup -Identity $Alias -PrimarySmtpAddress $OnMicrosoft
                    Write-Log -Level Warning -message "Updated PrimarySMTPAddress with $OnMicrosoft"
                    $UpdatePrimarySMTPAddress = "Updated with: $OnMicrosoft"
                }
                Catch
                {
                    $ErrorMessage = $Error[0].Exception.Message
                    $CMDLet = $Error[0].InvocationInfo.Line
                    $FailedItem = $Error[0].Exception.ItemName
                    Write-Log -Level Error -Message "Failed to update PrimarySMTPAddress with $OnMicrosoft"
                    Write-Log -Level Error -Message "Failed to run the following CMDLet: $CMDLet"
                    Write-Log -Level Error -Message "Failed with Error:$ErrorMessage"
                    $UpdatePrimarySMTPAddress = "Fail to update with: $OnMicrosoft"
                }
                
                $DomainEmailAddresses = $EmailAddresses | where { $_ -match $SMTPDomain }
                foreach ($DomainEmailAddress in $DomainEmailAddresses)
                {
                    # Remove ProxyAddress
                    Try
                    {
                        Write-Log -Level Info -message "Try to remove ProxyAddress: $DomainEmailAddress"
                        Set-DistributionGroup -identity $Alias -EmailAddresses @{ Remove = $DomainEmailAddress }
                        Write-Log -Level Warning -message "Removed ProxyAddress: $DomainEmailAddress"
                        $RemoveProxyAddress = "Removed : $DomainEmailAddress"
                    }
                    Catch
                    {
                        $ErrorMessage = $Error[0].Exception.Message
                        $CMDLet = $Error[0].InvocationInfo.Line
                        $FailedItem = $Error[0].Exception.ItemName
                        Write-Log -Level Error -Message "Failed to remove ProxyAddress: $DomainEmailAddress"
                        Write-Log -Level Error -Message "Failed to run the following CMDLet: $CMDLet"
                        Write-Log -Level Error -Message "Failed with Error:$ErrorMessage"
                        $RemoveProxyAddress = "Fail to remove : $DomainEmailAddress"
                    }
                    $Table += New-object PSobject -Property ([Ordered] @{
                            DisplayName                 = $DisplayName;
                            Alias                     = $Alias;
                            RecipientTypeDetails     = $RecipientTypeDetails;
                            RecipientType             = $RecipientType;
                            PrimarySmtpAddress         = $PrimarySmtpAddress;
                            WindowsLiveID             = $WindowsLiveID;
                            UpdatePrimarySMTPAddress = $UpdatePrimarySMTPAddress;
                            RemoveProxyAddress         = $RemoveProxyAddress;
                        })
                    
                }
            }
            MailUser
            {
                # Update PrimarySMTPAddress
                Try
                {
                    Write-Log -Level Info -message "Try to update PrimarySMTPAddress with $OnMicrosoft"
                    Set-MailUser -Identity $Alias -PrimarySmtpAddress $OnMicrosoft
                    Write-Log -Level Warning -message "Updated PrimarySMTPAddress with $OnMicrosoft"
                    $UpdatePrimarySMTPAddress = "Updated with: $OnMicrosoft"
                }
                Catch
                {
                    $ErrorMessage = $Error[0].Exception.Message
                    $CMDLet = $Error[0].InvocationInfo.Line
                    $FailedItem = $Error[0].Exception.ItemName
                    Write-Log -Level Error -Message "Failed to update PrimarySMTPAddress with $OnMicrosoft"
                    Write-Log -Level Error -Message "Failed to run the following CMDLet: $CMDLet"
                    Write-Log -Level Error -Message "Failed with Error:$ErrorMessage"
                    $UpdatePrimarySMTPAddress = "Fail to update with: $OnMicrosoft"
                }
                
                $DomainEmailAddresses = $EmailAddresses | where { $_ -match $SMTPDomain }
                foreach ($DomainEmailAddress in $DomainEmailAddresses)
                {
                    # Remove ProxyAddress
                    Try
                    {
                        Write-Log -Level Info -message "Try to remove ProxyAddress: $DomainEmailAddress"
                        Set-MailUser -identity $Alias -EmailAddresses @{ Remove = $DomainEmailAddress }
                        Write-Log -Level Warning -message "Removed ProxyAddress: $DomainEmailAddress"
                        $RemoveProxyAddress = "Removed : $DomainEmailAddress"
                    }
                    Catch
                    {
                        $ErrorMessage = $Error[0].Exception.Message
                        $CMDLet = $Error[0].InvocationInfo.Line
                        $FailedItem = $Error[0].Exception.ItemName
                        Write-Log -Level Error -Message "Failed to remove ProxyAddress: $DomainEmailAddress"
                        Write-Log -Level Error -Message "Failed to run the following CMDLet: $CMDLet"
                        Write-Log -Level Error -Message "Failed with Error:$ErrorMessage"
                        $RemoveProxyAddress = "Fail to remove : $DomainEmailAddress"
                    }
                    $Table += New-object PSobject -Property ([Ordered] @{
                            DisplayName                 = $DisplayName;
                            Alias                     = $Alias;
                            RecipientTypeDetails     = $RecipientTypeDetails;
                            RecipientType             = $RecipientType;
                            PrimarySmtpAddress         = $PrimarySmtpAddress;
                            WindowsLiveID             = $WindowsLiveID;
                            UpdatePrimarySMTPAddress = $UpdatePrimarySMTPAddress;
                            RemoveProxyAddress         = $RemoveProxyAddress;
                        })
                    
                }
            }
            PublicFolder
            {
                # Update PrimarySMTPAddress
                Try
                {
                    Write-Log -Level Info -message "Try to update PrimarySMTPAddress with $OnMicrosoft"
                    Set-MailPublicFolder -Identity $Alias -PrimarySmtpAddress $OnMicrosoft
                    Write-Log -Level Warning -message "Updated PrimarySMTPAddress with $OnMicrosoft"
                    $UpdatePrimarySMTPAddress = "Updated with: $OnMicrosoft"
                }
                Catch
                {
                    $ErrorMessage = $Error[0].Exception.Message
                    $CMDLet = $Error[0].InvocationInfo.Line
                    $FailedItem = $Error[0].Exception.ItemName
                    Write-Log -Level Error -Message "Failed to update PrimarySMTPAddress with $OnMicrosoft"
                    Write-Log -Level Error -Message "Failed to run the following CMDLet: $CMDLet"
                    Write-Log -Level Error -Message "Failed with Error:$ErrorMessage"
                    $UpdatePrimarySMTPAddress = "Fail to update with: $OnMicrosoft"
                }
                
                $DomainEmailAddresses = $EmailAddresses | where { $_ -match $SMTPDomain }
                foreach ($DomainEmailAddress in $DomainEmailAddresses)
                {
                    # Remove ProxyAddress
                    Try
                    {
                        Write-Log -Level Info -message "Try to remove ProxyAddress: $DomainEmailAddress"
                        Set-MailPublicFolder -identity $Alias -EmailAddresses @{ Remove = $DomainEmailAddress }
                        Write-Log -Level Warning -message "Removed ProxyAddress: $DomainEmailAddress"
                        $RemoveProxyAddress = "Removed : $DomainEmailAddress"
                    }
                    Catch
                    {
                        $ErrorMessage = $Error[0].Exception.Message
                        $CMDLet = $Error[0].InvocationInfo.Line
                        $FailedItem = $Error[0].Exception.ItemName
                        Write-Log -Level Error -Message "Failed to remove ProxyAddress: $DomainEmailAddress"
                        Write-Log -Level Error -Message "Failed to run the following CMDLet: $CMDLet"
                        Write-Log -Level Error -Message "Failed with Error:$ErrorMessage"
                        $RemoveProxyAddress = "Fail to remove : $DomainEmailAddress"
                    }
                    $Table += New-object PSobject -Property ([Ordered] @{
                            DisplayName                 = $DisplayName;
                            Alias                     = $Alias;
                            RecipientTypeDetails     = $RecipientTypeDetails;
                            RecipientType             = $RecipientType;
                            PrimarySmtpAddress         = $PrimarySmtpAddress;
                            WindowsLiveID             = $WindowsLiveID;
                            UpdatePrimarySMTPAddress = $UpdatePrimarySMTPAddress;
                            RemoveProxyAddress         = $RemoveProxyAddress;
                        })
                    
                }
            }
        }
        
        
        
        $i++
        
    }
    
    Write-Log -Level warning -Message "After updating the proxyAddresses, the script will pause for 15 mins, then run a second check"
    sleep 900
    If ($DomainIsFederated -eq "Not")
    {
        $AADObjects = $Null
        $AADObjects = Get-AzureADDomainNameReference -Name $SMTPDomain
        $Count = ($AADObjects | Measure).count
        Write-Log -Level Info -Message "The script found $Count of Objects still using $SMTPDomain"
        If ($Count -gt 0)
        {
            foreach ($AADObject in $AADObjects)
            {
                $AAD_ObjectType = $Null
                $AAD_ObjectType = $AADObject.ObjectType
                $AAD_UserPrincipalName = $Null
                $AAD_UserPrincipalName = $AADObject.UserPrincipalName
                $AAD_Mail = $Null
                $AAD_Mail = $AADObject.Mail
                $AAD_MailNickName = $Null
                $AAD_MailNickName = $AADObject.MailNickName
                $AAD_OnMicrosoft = $Null
                $AAD_OnMicrosoft = $AAD_MailNickName + "@" + $OnMicrosoftDefaultDomain
                If (($AAD_UserPrincipalName -match $SMTPDomain) -and ($AAD_ObjectType -eq "User"))
                {
                    Write-Log -Level warning -message "UPN $AAD_UserPrincipalName is using the $SMTPDomain"
                    Write-Log -Level Info -message "Try to update UserPrincipalName From $AAD_UserPrincipalName to $AAD_OnMicrosoft"
                    Set-MsolUserPrincipalName -UserPrincipalName $AAD_UserPrincipalName -NewUserPrincipalName $AAD_OnMicrosoft
                    Write-Log -Level Warning -message "Updated UserPrincipalName From $AAD_UserPrincipalName to $AAD_OnMicrosoft"
                }
                
            }
            Write-Log -Level warning -Message "After second cleanup, the script will pause for 15 mins, then run the last check"
            sleep 900
            $AADObjects2 = $Null
            $AADObjects2 = Get-AzureADDomainNameReference -Name $SMTPDomain
            $Count = ($AADObjects | Measure).count
            Write-Log -Level Info -Message "The script found $Count of Objects still using $SMTPDomain"
            $RemainingReportFile = ".\RemainingObjects_withDomain_" + $SMTPDomain + "_" + $DateFull + ".csv"
            $AADObjects2 | Select DisplayName, Mail, UserPrincipalName, MailNickName, ObjectType, ProxyAddresses | Export-Csv $RemainingReportFile -NoTypeInformation -Encoding UTF8
            Write-Log -Level INFO -Message "Generate the following Report: $RemainingReportFile "
            
        }
        
    }
    
    $ReportFile = ".\Domain_Recipients_CleanUp_" + $SMTPDomain + "_" + $DateFull + ".csv"
    $Table | Export-Csv $ReportFile -NoTypeInformation -Encoding UTF8
    Write-Log -Level INFO -Message "Generate the following Report: $ReportFile "
}

Function Enable-EXOMailboxForwardingusingCSVFile
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$CSVFile
    )
    
    Try
    {
        Read-Host "Expected CSV Column: MailboxEmailAddress,ForwardingSMTPEmailAddress"
        $Mailboxes = Import-Csv $CSVFile
        Write-Log -Level INFO -Message "The script import successfully :$CSVFile"
    }
    Catch
    {
        $ErrorMessage = $Error[0].Exception.Message
        $CMDLet = $Error[0].InvocationInfo.Line
        $FailedItem = $Error[0].Exception.ItemName
        Write-Log -Level Error -Message "Failed to import $CSVFile "
        Write-Log -Level Error -Message "Failed to run the following CMDLet: $CMDLet"
        Write-Log -Level Error -Message "Failed with Error:$ErrorMessage"
        Write-Log -Level Error -Message "The Script will stop"
        # Exit the script
        Exit
    }
    
    #Initiate the Hash Table
    [Int]$i = 1
    $Table = $Null
    $Table = @()
    $MailboxesCount = ($Mailboxes | Measure).count
    
    ForEach ($Mailbox in $Mailboxes)
    {
        $MailboxEmailAddress = $Null
        $MailboxEmailAddress = $Mailbox.MailboxEmailAddress
        $ForwardingSMTPAddress = $Null
        $ForwardingSMTPAddress = $Mailbox.ForwardingSMTPEmailAddress
        Try
        {
            Write-Log -Level INFO -Message "The script will try to Enable automatic forwarding from $MailboxEmailAddress to $ForwardingSMTPAddress….. --- $i/$MailboxesCount"
            Set-Mailbox -Identity $MailboxEmailAddress -ForwardingSmtpAddress $ForwardingSMTPAddress -DeliverToMailboxAndForward $True
            Write-Log -Level warning -Message "The script Enable automatic forwarding from $MailboxEmailAddress to $ForwardingSMTPAddress"
            $Status = "Success"
        }
        Catch
        {
            $ErrorMessage = $Error[0].Exception.Message
            $CMDLet = $Error[0].InvocationInfo.Line
            $FailedItem = $Error[0].Exception.ItemName
            Write-Log -Level Error -Message "Failed to Enable automatic forwarding from $MailboxEmailAddress to $ForwardingSMTPAddress"
            Write-Log -Level Error -Message "Failed to run the following CMDLet: $CMDLet"
            Write-Log -Level Error -Message "Failed with Error:$ErrorMessage"
            $Status = "Failed - Error $ErrorMessage"
        }
        $Table += New-object PSobject -Property ([Ordered] @{
                MailboxEmailAddress    = $MailboxEmailAddress;
                $ForwardingSMTPAddress = $ForwardingSMTPAddress;
                Status                   = $Status;
            })
        
        $i++
    }
    
    $DateFull = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    $ReportFilexlsx = ".\Report_UserMailboxesForwarding_" + $DateFull + ".xlsx"
    $Table | Export-Excel $ReportFilexlsx -TableName "UserMailboxesForwarding" -Title "UserMailboxes Forwarding" -TitleBold -WorksheetName "UserMailboxesForwarding" -TableStyle Medium9 -AutoSize -AutoFilter
    Write-log INFO -Message "Generate the following Report: $ReportFilexlsx"
    
}

Function Update-EXOPrimarySMTPAddressForUnifiedGroup
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$Identity,
        [Parameter(Mandatory = $true,
                   Position = 2)]
        [String]$NewPrimarySMTPAddress
    )
    
    $O365Group1 = Get-UnifiedGroup -Identity $Identity
    Write-Log -Level Warning -Message "$Identity Emailaddresses are: "
    $EmailAddresses1 = $O365Group1.EmailAddresses
    $EmailAddresses1 | ft
    # Update Office 365 group
    Set-UnifiedGroup -Identity $Identity -PrimarySMTPAddress $NewPrimarySMTPAddress
    # Check New Primary SMTP Address
    $O365Group2 = Get-UnifiedGroup -Identity $Identity
    Write-Log -Level Warning -Message "$Identity Emailaddresses are: "
    $EmailAddresses2 = $O365Group2.EmailAddresses
    $EmailAddresses2 | ft
}

Function Add-EXOUsersToOneDGCSV
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$GroupEmailAddress,
        [Parameter(Mandatory = $true,
                   Position = 2)]
        [String]$CSVFile
    )
    Read-Host "Expected CSV Column: EmailAddress"
    $Users = Import-Csv $CSVFile
    $Count = ($Users | Measure).count
    [Int]$i = 1
    $Table = $Null
    $Table = @()
    Foreach ($User in $Users)
    {
        $UserEmailAddress = $Null
        $UserEmailAddress = $User.EmailAddress
        Write-Host "User $UserEmailAddress will be added to Group $GroupEmailAddress --- $i/$Count"
        Try
        {
            Add-DistributionGroupMember -Identity $GroupEmailAddress -Member $UserEmailAddress -ErrorAction Stop
            $Status = "Success"
            
        }
        Catch
        {
            $ErrorMessage = $Error[0].Exception.Message
            If ($ErrorMessage -like "*member*")
            { $Status = "Failed - already members" }
            Else { $Status = "Failed - $ErrorMessage" }
        }
        $Table += New-object PSobject -Property ([Ordered] @{
                GroupEmailAddress = $GroupEmailAddress;
                UserName          = $UserEmailAddress;
                Action              = "Add";
                Status              = $Status;
            })
        $i++
    }
    $DateFull = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    $ReportFilexlsx = ".\Report_Users_Added_To_" + $DateFull + ".xlsx"
    $Table | Export-Excel $ReportFilexlsx -TableName "AddedUsers" -Title "Added Users" -TitleBold -WorksheetName "AddedUsers" -TableStyle Medium9 -AutoSize -AutoFilter
    Write-log INFO -Message "Generate the following Report: $ReportFilexlsx"
}

Function Update-EXODGMemberwithRepsUsingCSV
{
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$CSVFile
    )
    Read-Host "Expected CSV Column: DGName,Email"
    Try
    {
        
        Write-Log -Level Warning -Message "Trying to import $CSVFile"
        $Members = $Null
        $Members = Import-Csv $CsvFile
        Write-Log -Level INFO -Message "Successfully import $CSVFile"
    }
    Catch
    {
        $ErrorMessage = $Error[0].Exception.Message
        $CMDLet = $Error[0].InvocationInfo.Line
        $FailedItem = $Error[0].Exception.ItemName
        Write-Log -Level Error -Message "Failed to Import $CSVFile"
        Write-Log -Level Error -Message "Failed to run the following CMDLet: $CMDLet"
        Write-Log -Level Error -Message "Failed with Error:$ErrorMessage"
        #Exit
    }
    
    Read-Host "Are you sure you want to clear the Distribituion group? - <Enter> to Continue or Ctrl+C to Cancel"
    # Rep
    $All_Reps = Get-Recipient -resultsize unlimited -Filter { (RecipientTypeDetails -eq "UserMailbox") -and (Title -like "*repre*") }
    $OUs = $null
    $OUs = @()
    $Reps = $null
    $Reps = @()
    $Table = $Null
    $Table = @()
    foreach ($Rep in $All_Reps)
    {
        $Reps_Customattribute13 = $Null
        $Reps_Customattribute13 = $Rep.Customattribute13
        $Customattribute13 = $Null
        $Customattribute13 = $Reps_Customattribute13 -replace ("CEECIS", "ECAR") -replace ("TACR", "LACR")
        $OUs += $Customattribute13
        $Reps_PrimarySmtpAddress = $Null
        $Reps_PrimarySmtpAddress = $Rep.primarysmtpaddress
        $Reps += New-object PSobject -Property ([Ordered] @{
                PrimarySmtpAddress = $Reps_PrimarySmtpAddress;
                CustomAttribute13  = $Customattribute13;
            })
        
    }
    # Remove duplicates
    $OUs = $OUs | select -Unique
    # Loop with all OUs
    foreach ($OU in $OUs)
    {
        $Office = $Null
        $Office = ($OU.split(","))[0]
        $Region = $Null
        $Region = ($OU.split(","))[1]
        $ML_Name = $Null
        $ML_Name = "ML-CM-$Region-$Office"
        $ML_Members = $Null
        $CurrentML_Members = Get-DistributionGroupMember $ML_Name
        
        #Remove Members
        ForEach ($CurrentML_Member in $CurrentML_Members)
        {
            $CurrentPrimarySMTPAddress = $Null
            $CurrentPrimarySMTPAddress = $CurrentML_Member.primarysmtpaddress
            Write-Log -Level INFO -Message "Removing user $CurrentPrimarySMTPAddress from $ML_Name"
            Try
            {
                Remove-DistributionGroupMember $ML_Name -Member $CurrentPrimarySMTPAddress -Confirm:$false -ErrorAction Stop
                $RemoveStatus = "Successful"
            }
            Catch
            {
                $ErrorMessage = $Error[0].Exception.Message
                $RemoveStatus = "Failed with Error:$ErrorMessage "
            }
            $Table += New-object PSobject -Property ([Ordered] @{
                    Email  = $CurrentPrimarySMTPAddress;
                    Action = "Removed - " + $RemoveStatus;
                    DGName = $ML_Name;
                })
            
            
        }
        # Add Reps
        $OUFilter = $Null
        $OUFilter = '*' + $OU + '*'
        
        Write-Log -Level INFO -Message " The filter is : $OUFilter"
        $NewML_Reps = $Null
        $NewML_Reps = $Reps | Where-Object { $_.CustomAttribute13 -like $OUFilter }
        $NewML_Reps_Count = $Null
        $NewML_Reps_Count = ($NewML_Reps | Measure).count
        Write-Log -Level INFO -Message " Number of Reps: $NewML_Reps_Count for $ML_Name"
        foreach ($NewML_Rep in $NewML_Reps)
        {
            $NewPrimarySMTPAddress = $Null
            $NewPrimarySMTPAddress = $NewML_Rep.primarysmtpaddress
            Write-Log -Level INFO -Message "adding user $NewPrimarySMTPAddress from $ML_Name"
            Try
            {
                Add-DistributionGroupMember -Identity $ML_Name -Member $NewPrimarySMTPAddress -ErrorAction Stop
                $AddStatus = "Successful"
            }
            Catch
            {
                $ErrorMessage = $Error[0].Exception.Message
                $AddStatus = "Failed with Error:$ErrorMessage "
                
            }
            
            $Table += New-object PSobject -Property ([Ordered] @{
                    Email  = $NewPrimarySMTPAddress;
                    Action = "Added - " + $AddStatus;
                    DGName = $ML_Name;
                })
        }
        
        
        # Add members from CSV
        $NewML_Members = $Null
        $NewML_Members = $Members | Where-Object { $_.DGName -eq $ML_Name }
        $NewML_Members_Count = $Null
        $NewML_Members_Count = ($NewML_Members | Measure).count
        Write-Log -Level INFO -Message " Number of Members: $NewML_Members_Count for $ML_Name"
        
        # Add members
        foreach ($NewML_Member in $NewML_Members)
        {
            $NewPrimarySMTPAddress = $Null
            $NewPrimarySMTPAddress = $NewML_Member.Email
            Write-Log -Level INFO -Message "adding user $NewPrimarySMTPAddress from $ML_Name"
            Try
            {
                Add-DistributionGroupMember -Identity $ML_Name -Member $NewPrimarySMTPAddress -ErrorAction Stop
                $AddStatus = "Successful"
            }
            Catch
            {
                $ErrorMessage = $Error[0].Exception.Message
                $AddStatus = "Failed with Error:$ErrorMessage "
            }
            
            $Table += New-object PSobject -Property ([Ordered] @{
                    Email  = $NewPrimarySMTPAddress;
                    Action = "Added - " + $AddStatus;
                    DGName = $ML_Name;
                })
        }
        #Read-Host "Break"
    }
    $DateFull = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    $ReportFilexlsx = ".\Report_Groups_Members_" + $DateFull + ".xlsx"
    $Table | Export-Excel $ReportFilexlsx -TableName "GroupMembers" -Title "Group Members" -TitleBold -WorksheetName "GroupMembers" -TableStyle Medium9 -AutoSize -AutoFilter
    Write-log INFO -Message "Generate the following Report: $ReportFilexlsx"
    
}

Function Add-EXOUsersToDGsusingCSV
{
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$CSVFile
    )
    $Table = $Null
    $Table = @()
    Read-Host "Expected CSV Column: DGName,Email"
    Try
    {
        
        Write-Log -Level Warning -Message "Trying to import $CSVFile"
        $Members = $Null
        $Members = Import-Csv $CsvFile
        Write-Log -Level INFO -Message "Successfully import $CSVFile"
        $Count = ($Members | Measure).count
    }
    Catch
    {
        $ErrorMessage = $Error[0].Exception.Message
        $CMDLet = $Error[0].InvocationInfo.Line
        $FailedItem = $Error[0].Exception.ItemName
        Write-Log -Level Error -Message "Failed to Import $CSVFile"
        Write-Log -Level Error -Message "Failed to run the following CMDLet: $CMDLet"
        Write-Log -Level Error -Message "Failed with Error:$ErrorMessage"
        #Exit
    }
    
    
    # Add members
    [Int]$i = 1
    foreach ($Member in $Members)
    {
        $NewPrimarySMTPAddress = $Null
        $NewPrimarySMTPAddress = $Member.Email
        $ML_Name = $Null
        $ML_Name = $Member.DGName
        Write-Log -Level INFO -Message "adding user $NewPrimarySMTPAddress to $ML_Name --- $i/$Count"
        Try
        {
            Add-DistributionGroupMember -Identity $ML_Name -Member $NewPrimarySMTPAddress -ErrorAction Stop
            $AddStatus = "Successful"
        }
        Catch
        {
            $ErrorMessage = $Error[0].Exception.Message
            $AddStatus = "Failed with Error:$ErrorMessage "
        }
        
        $Table += New-object PSobject -Property ([Ordered] @{
                Email  = $NewPrimarySMTPAddress;
                Action = "Added - " + $AddStatus;
                DGName = $ML_Name;
            })
        $i++
    }
    #Read-Host "Break"
    
    $DateFull = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    $ReportFilexlsx = ".\Report_Groups_Members_" + $DateFull + ".xlsx"
    $Table | Export-Excel $ReportFilexlsx -TableName "GroupMembers" -Title "Group Members" -TitleBold -WorksheetName "GroupMembers" -TableStyle Medium9 -AutoSize -AutoFilter
    Write-log INFO -Message "Generate the following Report: $ReportFilexlsx"
}

Function Create-EXOMailContactUsingCSV
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$CSVFile
    )
    Read-Host "Expected CSV Column: EmailAddress,Name"
    $MailContacts = Import-Csv $CSVFile
    $Count = ($MailContacts | Measure).count
    [Int]$i = 1
    $Table = $Null
    $Table = @()
    Foreach ($MailContact in $MailContacts)
    {
        $UserEmailAddress = $Null
        $UserEmailAddress = $MailContact.EmailAddress
        $UserName = $Null
        $UserName = $MailContact.Name
        Write-Host "User $UserName ($UserEmailAddress) --- $i/$Count"
        Try
        {
            Write-Host "The script will try to create the following user: $UserName ($UserEmailAddress) --- $i/$Count"
            New-MailContact -Name $UserName -ExternalEmailAddress $UserEmailAddress
            Write-Host "The script created the following user: $UserName ($UserEmailAddress)"
            $Status = "Success"
            
        }
        Catch
        {
            $ErrorMessage = $Error[0].Exception.Message
            Write-Log -Level Error -Message "Failed to Create Contact with error: $ErrorMessage "
            $Status = "Failed"
        }
        
        $Table += New-object PSobject -Property ([Ordered] @{
                Name         = $UserName;
                EmailAddress = $UserEmailAddress;
                Status         = $Status;
            })
        $i++
    }
    $DateFull = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    $ReportFilexlsx = ".\Report_CreatedContacts_" + $DateFull + ".xlsx"
    $Table | Export-Excel $ReportFilexlsx -TableName "CreatedContacts" -Title "Created Contacts" -TitleBold -WorksheetName "CreatedContacts" -TableStyle Medium9 -AutoSize -AutoFilter
    Write-log INFO -Message "Generate the following Report: $ReportFilexlsx"
}

Function Check-EXOMessageMaxSize
{
    [CmdletBinding()]
    param ()
    
    Write-Log -Level Info -Message "--- Transport Configuration:"
    Get-TransportConfig | ft maxreceivesize, maxsendsize
    Write-Log -Level Info -Message "--- Mailbox Plan:"
    Get-MailboxPlan | ft name, maxsendsize, maxreceivesize, isdefault
    Write-Log -Level Warning -Message "Transport Configuration cannot be updated"
    Write-Log -Level Warning -Message "Mailbox Plan can be increase to 150MB"
    Write-Log -Level Warning -Message "Base64 encoding increases the size of messages by approximately 33%, so specify a value that's 33% larger than the actual maximum message size that you want to enforce. For example, the value 64 MB results in a maximum message size of approximately 48 MB."
    
}

Function Add-EXOUnifiedGroupMemberusingCSV
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$GroupEmailAddress,
        [Parameter(Mandatory = $true,
                   Position = 2)]
        [String]$CSVFile
    )
    
    Read-Host "Expected CSV Column: EmailAddress"
    # Import CSV File
    Try
    {
        
        Write-Log -Level warning -Message "The script will try to import the CSV File $CSVFile"
        $Members = Import-Csv $CSVFile
        Write-Log -Level warning -Message "The script successfully Import the CSV File : $CSVFile"
        #Initiate the Hash Table
        [Int]$i = 1
        $Table = $Null
        $Table = @()
        $Count = ($Members | Measure).count
    }
    Catch
    {
        $ErrorMessage = $Error[0].Exception.Message
        $CMDLet = $Error[0].InvocationInfo.Line
        $FailedItem = $Error[0].Exception.ItemName
        Write-Log -Level Error -Message "Failed to Import CSV File: $CSVFile "
        Write-Log -Level Error -Message "Failed to run the following CMDLet: $CMDLet"
        Write-Log -Level Error -Message "Failed with Error:$ErrorMessage"
        Exit
    }
    # Disable Welcome Message notification on the group
    Try
    {
        Write-Log -Level Warning -Message "The script will disable Unified Group Welcome message"
        Set-UnifiedGroup $GroupEmailAddress -UnifiedGroupWelcomeMessageEnabled:$false
        Write-Log -Level Warning -Message "The script disabled Unified Group Welcome message"
        sleep 10
    }
    Catch
    {
        $ErrorMessage = $Error[0].Exception.Message
        $CMDLet = $Error[0].InvocationInfo.Line
        $FailedItem = $Error[0].Exception.ItemName
        Write-Log -Level Error -Message "Failed to disable Group Welcome Message"
        Write-Log -Level Error -Message "Failed to run the following CMDLet: $CMDLet"
        Write-Log -Level Error -Message "Failed with Error:$ErrorMessage"
        Exit
    }
    
    Foreach ($Member in $Members)
    {
        # add member to the group
        $MemberID = $null
        $MemberID = $Member.EmailAddress
        Try
        {
            Write-Log -Level Warning -Message "The script will try to add $MemberID to $GroupEmailAddress - $i/$Count"
            Add-UnifiedGroupLinks -Identity $GroupEmailAddress -LinkType Members -Links $MemberID
            Write-Log -Level Warning -Message "The script added $MemberID to $GroupEmailAddress"
            $Status = "Added"
        }
        Catch
        {
            $ErrorMessage = $Error[0].Exception.Message
            $CMDLet = $Error[0].InvocationInfo.Line
            $FailedItem = $Error[0].Exception.ItemName
            Write-Log -Level Error -Message "Failed to disable Group Welcome Message"
            Write-Log -Level Error -Message "Failed to run the following CMDLet: $CMDLet"
            Write-Log -Level Error -Message "Failed with Error:$ErrorMessage"
            $Status = "Failed - Error: $ErrorMessage"
        }
        $Table += New-object PSobject -Property ([Ordered] @{
                GroupEmailAddress = $GroupEmailAddress;
                Member              = $MemberID;
                Status              = $Status;
            })
        
        $i++
    }
    sleep 10
    Try
    {
        Write-Log -Level Warning -Message "The script will enable Unified Group Welcome message"
        Set-UnifiedGroup $GroupEmailAddress -UnifiedGroupWelcomeMessageEnabled
        Write-Log -Level Warning -Message "The script enabled Unified Group Welcome message"
    }
    Catch
    {
        $ErrorMessage = $Error[0].Exception.Message
        $CMDLet = $Error[0].InvocationInfo.Line
        $FailedItem = $Error[0].Exception.ItemName
        Write-Log -Level Error -Message "Failed to enable Group Welcome Message"
        Write-Log -Level Error -Message "Failed to run the following CMDLet: $CMDLet"
        Write-Log -Level Error -Message "Failed with Error:$ErrorMessage"
        Exit
    }
    $DateFull = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    $ReportFilexlsx = ".\Add_Office365groupMembers_" + $GroupEmailAddress + "_" + $DateFull + ".xlsx"
    $Table | Export-Excel $ReportFilexlsx -TableName "O365GroupMembers" -Title "O365 Group Members" -TitleBold -WorksheetName "O365GroupMembers" -TableStyle Medium9 -AutoSize -AutoFilter
    Write-log INFO -Message "Generate the following Report: $ReportFilexlsx"
    
    
}

Function Generate-EXOUnifiedGroupsStorageReportInMB
{
    [CmdletBinding()]
    param ()
    Write-Log -Level Warning -Message "Are you connect to EXO Module and SPO Module?"
    Try
    {
        Write-Log -Level INFO -Message "The script will retreive the information for all Office 365 Groups"
        $Office365Groups = Get-UnifiedGroup -Resultsize Unlimited
        $Count = ($Office365Groups | Measure).count
        Write-Log -Level INFO -Message "The Script found $Count Office 365 Groups on the tenant"
    }
    Catch
    {
        $ErrorMessage = $Error[0].Exception.Message
        $CMDLet = $Error[0].InvocationInfo.Line
        $FailedItem = $Error[0].Exception.ItemName
        Write-Log -Level Error -Message "Failed to retrieve Office 365 groups information"
        Write-Log -Level Error -Message "Failed to run the following CMDLet: $CMDLet"
        Write-Log -Level Error -Message "Failed with Error:$ErrorMessage"
        Exit
    }
    [Int]$i = 1
    $Table = $Null
    $Table = @()
    ForEach ($Office365Group in $Office365Groups)
    {
        $PrimarySmtpAddress = $Null
        $PrimarySmtpAddress = $Office365Group.PrimarySmtpAddress
        $DisplayName = $Null
        $DisplayName = $Office365Group.DisplayName
        Write-Host "============================================================"
        Write-Log -Level INFO -Message "The script is analysis the Office 365 Group : $DisplayName --- $i/$Count"
        $ManagedBy = $Null
        $ManagedBy = $Office365Group.ManagedBy
        $GroupMemberCount = $Null
        $GroupMemberCount = $Office365Group.GroupMemberCount
        $Alias = $Null
        $Alias = $Office365Group.Alias
        $SharePointSiteUrl = $Null
        $SharePointSiteUrl = $Office365Group.SharePointSiteUrl
        
        #Mailbox Statistics
        Write-Log -Level Warning -Message "The script is analysis the Office 365 Group Mailbox Usage : $DisplayName ($PrimarySmtpAddress) "
        Try
        {
            $MailboxStatistics = Get-MailboxStatistics -Identity $PrimarySmtpAddress
            $TotalItemSize = $Null
            $TotalItemSize = ConvertTo-MB -size $MailboxStatistics.TotalItemSize.ToString().Split("(")[0]
        }
        Catch
        {
            $ErrorMessage = $Error[0].Exception.Message
            $CMDLet = $Error[0].InvocationInfo.Line
            $FailedItem = $Error[0].Exception.ItemName
            Write-Log -Level Error -Message "Failed to retrieve Office 365 group Mailbox Statistics"
            Write-Log -Level Error -Message "Failed to run the following CMDLet: $CMDLet"
            Write-Log -Level Error -Message "Failed with Error:$ErrorMessage"
            $TotalItemSize = "Failed to retrieve info"
        }
        
        
        #Sharepoint Statistic
        Write-Log -Level Warning -Message "The script is analysis the Office 365 Group Sharepoint Usage : $DisplayName ($SharePointSiteUrl) "
        If ($SharePointSiteUrl -ne $Null)
        {
            Try
            {
                $SPOSite = Get-SPOSite $SharePointSiteUrl
                $StorageUsageCurrentInMB = $Null
                $StorageUsageCurrentInMB = $SPOSite.StorageUsageCurrent
            }
            Catch
            {
                $ErrorMessage = $Error[0].Exception.Message
                $CMDLet = $Error[0].InvocationInfo.Line
                $FailedItem = $Error[0].Exception.ItemName
                Write-Log -Level Error -Message "Failed to retrieve Office 365 group Sharepoint usage"
                Write-Log -Level Error -Message "Failed to run the following CMDLet: $CMDLet"
                Write-Log -Level Error -Message "Failed with Error:$ErrorMessage"
                $StorageUsageCurrentInGB = "Failed to retrieve info"
            }
        }
        Else
        {
            $StorageUsageCurrentInGB = "No Sharepoint Site"
        }
        
        Write-Log -Level Warning -Message "The script is compiling Office 365 Group information : $DisplayName"
        $Table += New-object PSobject -Property ([Ordered] @{
                DisplayName                   = $DisplayName;
                Owner                       = $ManagedBy;
                GroupMemberCount           = $GroupMemberCount;
                PrimarySmtpAddress           = $PrimarySmtpAddress;
                MailboxSize                   = $TotalItemSize;
                SharePointSiteUrl           = $SharePointSiteUrl;
                SharepointStorageUsageInGB = $StorageUsageCurrentInMB;
            })
        Write-Host "============================================================"
        Write-Host ""
        $i++
    }
    
    $DateFull = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    $ReportFilexlsx = ".\Report_Office365Group_StorageUsage_" + $DateFull + ".xlsx"
    $Table | Export-Excel $ReportFilexlsx -TableName "O365GroupStorageUsage" -Title "O365 Group Storage Usage" -TitleBold -WorksheetName "O365GroupStorageUsage" -TableStyle Medium9 -AutoSize -AutoFilter
    Write-log INFO -Message "Generate the following Report: $ReportFilexlsx"
    
    
}

Function Generate-EXOUnifiedGroupsStorageReportInGB
{
    [CmdletBinding()]
    param ()
    Write-Log -Level Warning -Message "Are you connect to EXO Module and SPO Module?"
    Try
    {
        Write-Log -Level INFO -Message "The script will retreive the information for all Office 365 Groups"
        $Office365Groups = Get-UnifiedGroup -Resultsize Unlimited
        $Count = ($Office365Groups | Measure).count
        Write-Log -Level INFO -Message "The Script found $Count Office 365 Groups on the tenant"
    }
    Catch
    {
        $ErrorMessage = $Error[0].Exception.Message
        $CMDLet = $Error[0].InvocationInfo.Line
        $FailedItem = $Error[0].Exception.ItemName
        Write-Log -Level Error -Message "Failed to retrieve Office 365 groups information"
        Write-Log -Level Error -Message "Failed to run the following CMDLet: $CMDLet"
        Write-Log -Level Error -Message "Failed with Error:$ErrorMessage"
        Exit
    }
    [Int]$i = 1
    $Table = $Null
    $Table = @()
    ForEach ($Office365Group in $Office365Groups)
    {
        $PrimarySmtpAddress = $Null
        $PrimarySmtpAddress = $Office365Group.PrimarySmtpAddress
        $DisplayName = $Null
        $DisplayName = $Office365Group.DisplayName
        Write-Host "============================================================"
        Write-Log -Level INFO -Message "The script is analysis the Office 365 Group : $DisplayName --- $i/$Count"
        $ManagedBy = $Null
        $ManagedBy = $Office365Group.ManagedBy
        $GroupMemberCount = $Null
        $GroupMemberCount = $Office365Group.GroupMemberCount
        $Alias = $Null
        $Alias = $Office365Group.Alias
        $SharePointSiteUrl = $Null
        $SharePointSiteUrl = $Office365Group.SharePointSiteUrl
        
        #Mailbox Statistics
        Write-Log -Level Warning -Message "The script is analysis the Office 365 Group Mailbox Usage : $DisplayName ($PrimarySmtpAddress) "
        Try
        {
            $MailboxStatistics = Get-MailboxStatistics -Identity $PrimarySmtpAddress
            $TotalItemSize = $Null
            $TotalItemSize = ConvertTo-Gb -size $MailboxStatistics.TotalItemSize.ToString().Split("(")[0]
        }
        Catch
        {
            $ErrorMessage = $Error[0].Exception.Message
            $CMDLet = $Error[0].InvocationInfo.Line
            $FailedItem = $Error[0].Exception.ItemName
            Write-Log -Level Error -Message "Failed to retrieve Office 365 group Mailbox Statistics"
            Write-Log -Level Error -Message "Failed to run the following CMDLet: $CMDLet"
            Write-Log -Level Error -Message "Failed with Error:$ErrorMessage"
            $TotalItemSize = "Failed to retrieve info"
        }
        
        
        #Sharepoint Statistic
        Write-Log -Level Warning -Message "The script is analysis the Office 365 Group Sharepoint Usage : $DisplayName ($SharePointSiteUrl) "
        If ($SharePointSiteUrl -ne $Null)
        {
            Try
            {
                $SPOSite = Get-SPOSite $SharePointSiteUrl
                $StorageUsageCurrentInMB = $Null
                $StorageUsageCurrentInMB = $SPOSite.StorageUsageCurrent
                $StorageUsageCurrentInGB = ($StorageUsageCurrentInMB/ 1024)
                $StorageUsageCurrentInGB = [Math]::Round($StorageUsageCurrentInGB, 4, [MidPointRounding]::AwayFromZero)
            }
            Catch
            {
                $ErrorMessage = $Error[0].Exception.Message
                $CMDLet = $Error[0].InvocationInfo.Line
                $FailedItem = $Error[0].Exception.ItemName
                Write-Log -Level Error -Message "Failed to retrieve Office 365 group Sharepoint usage"
                Write-Log -Level Error -Message "Failed to run the following CMDLet: $CMDLet"
                Write-Log -Level Error -Message "Failed with Error:$ErrorMessage"
                $StorageUsageCurrentInGB = "Failed to retrieve info"
            }
        }
        Else
        {
            $StorageUsageCurrentInGB = "No Sharepoint Site"
        }
        
        Write-Log -Level Warning -Message "The script is compiling Office 365 Group information : $DisplayName"
        $Table += New-object PSobject -Property ([Ordered] @{
                DisplayName                   = $DisplayName;
                Owner                       = $ManagedBy;
                GroupMemberCount           = $GroupMemberCount;
                PrimarySmtpAddress           = $PrimarySmtpAddress;
                MailboxSize                   = $TotalItemSize;
                SharePointSiteUrl           = $SharePointSiteUrl;
                SharepointStorageUsageInGB = $StorageUsageCurrentInGB;
            })
        Write-Host "============================================================"
        Write-Host ""
        $i++
    }
    
    $DateFull = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    $ReportFilexlsx = ".\Report_Office365Group_StorageUsage_" + $DateFull + ".xlsx"
    $Table | Export-Excel $ReportFilexlsx -TableName "O365GroupStorageUsage" -Title "O365Group Storage Usage" -TitleBold -WorksheetName "O365GroupStorageUsage" -TableStyle Medium9 -AutoSize -AutoFilter
    Write-log INFO -Message "Generate the following Report: $ReportFilexlsx"
    
    
}

Function Enable-EXORetentionFeatures
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$EmailAddress
    )
    
    Try
    {
        Write-Log -Level -Level INFO -Message "Retreiving mailbox data for: $EmailAddress"
        $Mailbox = Get-Mailbox $EmailAddress
        $FindMailbox = "True"
    }
    Catch
    {
        $ErrorMessage = $Error[0].Exception.Message
        Write-Log -Level -Level Error -Message "Failed to find the mailbox: $EmailAddress with the following error: $ErrorMessage"
        $FindMailbox = "Failed to find the mailbox: $EmailAddress with the following error: $ErrorMessage"
    }
    
    Try
    {
        $ArchiveStatus = $Mailbox.ArchiveStatus
        If ($ArchiveStatus -eq "Active")
        {
            $EnableArchive = "True"
            Write-Log -Level -Level INFO -Message "Archive mailbox alread enabled for $EmailAddress"
        }
        Else
        {
            Enable-Mailbox -identity $EmailAddress -Archive
            Write-Log -Level -Level INFO -Message "Successfully Enable Archive mailbox for $EmailAddress"
            $EnableArchive = "True"
        }
        
    }
    Catch
    {
        $ErrorMessage = $Error[0].Exception.Message
        Write-Log -Level -Level Error -Message "Failed to enable Archive mailbox for $EmailAddress with the following error: $ErrorMessage"
        $EnableArchive = "Failed to enable Archive mailbox for $EmailAddress with the following error: $ErrorMessage"
    }
    Try
    {
        $LitigationHoldEnabled = $Mailbox.LitigationHoldEnabled
        $LitigationHoldDuration = $Mailbox.LitigationHoldDuration
        If (($LitigationHoldEnabled -eq $true) -and ($LitigationHoldDuration -eq "1825.00:00:00"))
        {
            $EnableLigitationHold = "True"
            Write-Log -Level -Level INFO -Message "Litigation Hold (1825 days) is already enabled for $EmailAddress"
        }
        Else
        {
            Set-Mailbox $EmailAddress -LitigationHoldEnabled $True -LitigationHoldDuration 1825
            Write-Log -Level -Level INFO -Message "Successfully Enable Litigation Hold (1825 days) for $EmailAddress"
            $EnableLigitationHold = "True"
        }
        
        
    }
    Catch
    {
        $ErrorMessage = $Error[0].Exception.Message
        Write-Log -Level -Level Error -Message "Failed to enable Litigation Hold (1825 days) for $EmailAddress with the following error: $ErrorMessage"
        $EnableLigitationHold = "Failed to enable Litigation Hold (1825 days) for $EmailAddress with the following error: $ErrorMessage"
    }
    
    $OutPutMessage = $null
    $OutPutMessage = @()
    $OutPutMessage += New-object PSobject -Property ([Ordered] @{
            EmailAddress         = $EmailAddress;
            FindMailbox             = $FindMailbox;
            EnableArchive         = $EnableArchive;
            EnableLitigationHold = $EnableLitigationHold;
        })
    Return $OutPutMessage
}

Function Enable-EXOMailboxesRetentionUsingCSV
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$CSVFile
    )
    Read-Host "Expected CSV Column: PrimarySmtpAddress"
    $Mailboxes = Import-Csv $CSVFile
    $Count = ($Mailboxes | Measure).count
    [Int]$i = 1
    $Table = $Null
    $Table = @()
    Foreach ($Mailbox in $Mailboxes)
    {
        $UserEmailAddress = $Null
        $UserEmailAddress = $Mailbox.PrimarySmtpAddress
        Write-Log -Level Warning -Message "Enabling Retention feature for $UserEmailAddress --- $i/$Count"
        $UserOutput = $Null
        $UserOutput = @()
        $UserOutput = Enable-RetentionFeatures -EmailAddress $UserEmailAddress
        $Table += New-object PSobject -Property ([Ordered] @{
                EmailAddress = $UserOutput.EmailAddress;
                FindMailbox  = $UserOutput.FindMailbox;
                EnableArchive = $UserOutput.EnableArchive;
                EnableLigitationHold = $UserOutput.EnableLigitationHold;
            })
        
        $i++
    }
    $DateFull = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    $ReportFilexlsx = ".\Report_Mailboxes_RetentionFeatures_" + $DateFull + ".xlsx"
    $Table | Export-Excel $ReportFilexlsx -TableName "MailboxRetentionFeatures" -Title "Mailbox Retention Features" -TitleBold -WorksheetName "MailboxRetentionFeatures" -TableStyle Medium9 -AutoSize -AutoFilter
    Write-log INFO -Message "Generate the following Report: $ReportFilexlsx"
}

Function Add-EXOTrustedSenderToAllMailboxes
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$TrustedSenderEmailAddress
    )
    
    $mailboxes = Get-Mailbox -Filter { RecipientTypeDetails -eq "UserMailbox" } -ResultSize unlimited
    
    [Int]$i = 1
    $Table = $Null
    $Table = @()
    $Count = ($mailboxes | Measure).count
    Foreach ($Mailbox in $mailboxes)
    {
        $DisplayName = $Mailbox.displayname
        $PrimarySMTPAddress = $Mailbox.PrimarySMTPAddress
        Write-Log -Level Warning -message "The script is updating Trusted domain for $DisplayName ($PrimarySMTPAddress) ….. --- $i/$Count"
        try
        {
            Set-MailboxJunkEmailConfiguration $PrimarySMTPAddress -TrustedSendersAndDomains @{ Add = $TrustedSenderEmailAddress } -ErrorAction Stop
            $Status = "Success"
        }
        Catch { $Status = "Failed" }
        
        $Table += New-object PSobject -Property ([Ordered] @{
                DisplayName           = $DisplayName;
                PrimarySMTPAddress = $PrimarySMTPAddress;
                Status               = $Status;
            })
        
        $i++
        
    }
    $DateFull = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    $ReportFilexlsx = ".\Report_User_Mailboxes_JunkConfiguration_Add_" + $DateFull + ".xlsx"
    $Table | Export-Excel $ReportFilexlsx -TableName "MailboxJunkConfiguration" -Title "Mailbox JunkConfiguration" -TitleBold -WorksheetName "MailboxJunkConfiguration" -TableStyle Medium9 -AutoSize -AutoFilter
    Write-log INFO -Message "Generate the following Report: $ReportFilexlsx"
    
}

Function Remove-EXOTrustedSenderToAllMailboxes
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$TrustedSenderEmailAddress
    )
    
    $mailboxes = Get-Mailbox -Filter { RecipientTypeDetails -eq "UserMailbox" } -ResultSize unlimited
    #$mailboxes = Get-Mailbox -Filter { RecipientTypeDetails -eq "UserMailbox" } -ResultSize 10
    [Int]$i = 1
    $Table = $Null
    $Table = @()
    $Count = ($mailboxes | Measure).count
    Foreach ($Mailbox in $mailboxes)
    {
        $DisplayName = $Mailbox.displayname
        $PrimarySMTPAddress = $Mailbox.PrimarySMTPAddress
        Write-Log -Level Warning -message "The script is updating Trusted domain for $DisplayName ($PrimarySMTPAddress) ….. --- $i/$Count"
        try
        {
            Set-MailboxJunkEmailConfiguration $PrimarySMTPAddress -TrustedSendersAndDomains @{ Remove = $TrustedSenderEmailAddress } -ErrorAction Stop
            $Status = "Success"
        }
        Catch { $Status = "Failed" }
        
        $Table += New-object PSobject -Property ([Ordered] @{
                DisplayName           = $DisplayName;
                PrimarySMTPAddress = $PrimarySMTPAddress;
                Status               = $Status;
            })
        
        $i++
        
    }
    $DateFull = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    $ReportFilexlsx = ".\Report_User_Mailboxes_JunkConfiguration_Remove_" + $DateFull + ".xlsx"
    $Table | Export-Excel $ReportFilexlsx -TableName "MailboxJunkConfigurationRemove" -Title "Mailbox JunkConfiguration Removal" -TitleBold -WorksheetName "MailboxJunkConfigurationRemove" -TableStyle Medium9 -AutoSize -AutoFilter
    Write-log INFO -Message "Generate the following Report: $ReportFilexlsx"
    
}

Function Get-EXOUserAllMembership
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$EmailAddress
    )
    
    #Find user DistinguishedName
    $Recipients = Get-Recipient $EmailAddress
    $Count = ($Recipients | Measure).count
    Write-Log -Level Warning -Message "Found $Count Object(s) with $EmailAddress"
    foreach ($Recipient in $Recipients)
    {
        #Initiate the Hash Table
        [Int]$i = 0
        $Table = $Null
        $Table = @()
        $DistinguishedName = $Null
        $EXO_Membership = $Null
        $EXO_DynamicGroup = $Null
        $AAD_Membership = $Null
        $RecipientTypeDetails = $Null
        $ExternalDirectoryObjectId = $Null
        $DistinguishedName = $Recipient.DistinguishedName
        $RecipientTypeDetails = $Recipient.RecipientTypeDetails
        $ExternalDirectoryObjectId = $Recipient.ExternalDirectoryObjectId
        Write-Log -Level Warning -Message "$EmailAddress ($RecipientTypeDetails) DistinguishedName is: $DistinguishedName"
        $EXO_Membership = Get-Recipient -Filter "Members -eq '$DistinguishedName'" -RecipientTypeDetails GroupMailbox, MailUniversalDistributionGroup, MailUniversalSecurityGroup
        ForEach ($EXO_Group in $EXO_Membership)
        {
            $EXO_displayName = $Null
            $EXO_PrimarySmtpAddress = $Null
            $EXO_RecipientTypeDetails = $Null
            $EXO_displayName = $EXO_Group.DisplayName
            $EXO_PrimarySmtpAddress = $EXO_Group.PrimarySmtpAddress
            $EXO_RecipientTypeDetails = $EXO_Group.RecipientTypeDetails
            $Table += New-object PSobject -Property ([Ordered] @{
                    DisplayName           = $EXO_displayName;
                    PrimarySmtpAddress = $EXO_PrimarySmtpAddress;
                    Type               = $EXO_RecipientTypeDetails;
                })
            $i++
        }
        
        $EXO_DynamicGroup = Get-Group -Filter "Members -eq '$DistinguishedName'"
        ForEach ($EXO_DGroup in $EXO_DynamicGroup)
        {
            $EXO_DdisplayName = $Null
            $EXO_DPrimarySmtpAddress = $Null
            $EXO_DRecipientTypeDetails = $Null
            $EXO_DdisplayName = $EXO_DGroup.Name
            $EXO_DPrimarySmtpAddress = $EXO_DGroup.WindowsEmailAddress
            $EXO_DRecipientTypeDetails = $EXO_DGroup.GroupType
            $Table += New-object PSobject -Property ([Ordered] @{
                    DisplayName = $EXO_DdisplayName;
                    B            = $EXO_DPrimarySmtpAddress;
                    Type        = $EXO_DRecipientTypeDetails;
                })
            $i++
        }
        
        If ($RecipientTypeDetails -ne "MailContact")
        {
            #$AAD_Membership = Get-AzureADUser -SearchString $UPN | Get-AzureADUserMembership | ? { $_.ObjectType -ne "Role" } | % { Get-AzureADGroup -ObjectId $_.ObjectId | select DisplayName, ObjectType, MailEnabled, SecurityEnabled, ObjectId } | ft
            #$AAD_Membership = Get-AzureADUser -SearchString $UPN | Get-AzureADUserMembership | % { Get-AzureADGroup -ObjectId $_.ObjectId | select DisplayName, ObjectType, MailEnabled, SecurityEnabled, ObjectId } | ft
            $AAD_Membership = Get-AzureADUser -ObjectID $ExternalDirectoryObjectId | Get-AzureADUserMembership | % { Get-AzureADGroup -ObjectId $_.ObjectId }
            
            ForEach ($EXO_AADGroup in $AAD_Membership)
            {
                $AAD_displayName = $Null
                $ADD_PrimarySmtpAddress = $Null
                $ADD_RecipientTypeDetails = $Null
                $AAD_displayName = $EXO_AADGroup.DisplayName
                $ADD_PrimarySmtpAddress = $EXO_AADGroup.Mail
                $ADD_RecipientTypeDetails = $EXO_AADGroup.ObjectType
                $Table += New-object PSobject -Property ([Ordered] @{
                        DisplayName           = $AAD_displayName;
                        PrimarySmtpAddress = $ADD_PrimarySmtpAddress;
                        Type               = $ADD_RecipientTypeDetails;
                    })
                $i++
            }
        }
        $Table | ft
        Write-Log -Level Warning -Message "$UPN ($RecipientTypeDetails) is member of: $i Groups"
    }
    
}

Function Get-EXORecipientInformationFromCSV
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [string]$CsvFile
    )
    Read-Host "Expected CSV Column: UPN"
    Try
    {
        Write-Log -Level warning -Message "Trying to import $CSVFile"
        $Users = Import-Csv $CsvFile
        Write-Log -Level INFO -Message "Successfully import $CSVFile"
    }
    Catch
    {
        $ErrorMessage = $Error[0].Exception.Message
        $CMDLet = $Error[0].InvocationInfo.Line
        $FailedItem = $Error[0].Exception.ItemName
        Write-Log -Level Error -Message "Failed to Import $CsvFile"
        Write-Log -Level Error -Message "Failed to run the following CMDLet: $CMDLet"
        Write-Log -Level Error -Message "Failed with Error:$ErrorMessage"
        Exit
    }
    
    #Initiate the Hash Table
    [Int]$i = 1
    $Table = $Null
    $Table = @()
    $Count = ($Users | Measure).count
    
    ForEach ($User in $Users)
    {
        $UserPrincipalName = $null
        $UserPrincipalName = $User.UPN
        Write-Log -Level INFO -Message "The script is analyzing $UserPrincipalName….. --- $i/$Count"
        $Recipient = $Null
        $Recipient = Get-Recipient $UserPrincipalName
        $City = $Recipient.City
        $Department = $Recipient.Department
        $FirstName = $Null
        $FirstName = $Recipient.FirstName
        $LastName = $Null
        $LastName = $Recipient.LastName
        $Office = $Null
        $Office = $Recipient.Office
        $Title = $Null
        $Title = $Recipient.Title
        $CustomAttribute5 = $Null
        $CustomAttribute5 = $Recipient.CustomAttribute5
        $CustomAttribute7 = $Null
        $CustomAttribute7 = $Recipient.CustomAttribute7
        $CustomAttribute13 = $Null
        $CustomAttribute13 = $Recipient.CustomAttribute13
        $CustomAttribute14 = $Null
        $CustomAttribute14 = $Recipient.CustomAttribute14
        $CustomAttribute15 = $Null
        $CustomAttribute15 = $Recipient.CustomAttribute15
        $Table += New-object PSobject -Property ([Ordered] @{
                UserPrincipalName = $UserPrincipalName;
                FirstName          = $FirstName;
                LastName          = $LastName;
                Office              = $Office;
                City              = $City;
                Title              = $Title;
                CustomAttribute5  = $CustomAttribute5;
                CustomAttribute7  = $CustomAttribute7;
                CustomAttribute13 = $CustomAttribute13;
                CustomAttribute14 = $CustomAttribute14;
                CustomAttribute15 = $CustomAttribute15;
            })
        
        $i++
    }
    
    $DateFull = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    $ReportFilexlsx = ".\Report_Recipient_Users_Details_" + $DateFull + ".xlsx"
    $Table | Export-Excel $ReportFilexlsx -TableName "Recipients" -Title "Recipients" -TitleBold -WorksheetName "Recipients" -TableStyle Medium9 -AutoSize -AutoFilter
    Write-log INFO -Message "Generate the following Report: $ReportFilexlsx"
}

Function Get-EXOMailContactGroupMembership
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$EmailAddress
    )
    
    $ContactDN = (Get-MailContact $EmailAddress).DistinguishedName
    $Groups = Get-Recipient -Filter "Members -eq '$ContactDN'"
    $Groups | ft DisplayName, PrimarySmtpAddress, RecipientTypeDetails
}

Function Find-EXOAllDisconnectedMailboxes
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [string]$Folder
    )
    
    # Find Every Disconnected Mailboxes
    $Folder = "H:\PST\RecoverySharedMailbox\"
    $DateFull = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    $ExchangeServers = $Null
    $ExchangeServers = Get-ExchangeServer | where { $_.ServerRole -like "*Mailbox*" }
    $Mailboxes = $Null
    $FullMailboxes = $Null
    foreach ($ExchangeServer in $ExchangeServers)
    {
        $ServerName = $null
        $ServerName = $ExchangeServer.Name
        $CSVFile = $null
        $CSVFile = $Folder + "Disconnected_Mailboxes_" + $ServerName + "_" + $DateFull + ".csv"
        $Mailboxes = $Null
        $Mailboxes = Get-MailboxStatistics -Server $ServerName | Where { $_.DisconnectDate -ne $null } | select DisplayName, ItemCount, DeletedItemCount, DisconnectDate, DisconnectReason, LastLoggedOnUserAccount, LastLogoffTime, LastLogonTime, LegacyDN, MailboxGuid, TotalItemSize, Database, ServerName
        $Mailboxes | Export-Csv $CSVFile -NoTypeInformation -Encoding UTF8
        $FullMailboxes += $Mailboxes
    }
    $GlobalCSVFile = $Folder + "All_Disconnected_Mailboxes_" + $DateFull + ".csv"
    $FullMailboxes | Export-Csv $GlobalCSVFile -NoTypeInformation -Encoding UTF8
    
}

Function Retreive-EXOMailboxPermission
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [string]$Mailbox
    )
    
    $MailboxPermissions = Get-MailboxPermission $Mailbox | where { $_.User -like "*@*" } | select User
    $Permissions = $MailboxPermissions.user -join ";"
    Write-Host $Mailbox -NoNewline -ForegroundColor Red; Write-Host " --- " -NoNewline; Write-Host $Permissions -ForegroundColor Yellow
}

Function Add-EXOCalendarPermission
{
    [CmdletBinding()]
    Param ([Parameter(Mandatory = $true)]
        [string]$Ressource,
        [Parameter(Mandatory = $true)]
        [string]$Delegate,
        [Parameter(Mandatory = $true)]
        [string]$Permission)
    
    Write-host "Checking the Calendar permission currenlty assigned to $Ressource "
    $Calendar = $Null
    $Calendar = $Ressource + ":\Calendar"
    Get-MailboxFolderPermission $Calendar
    
    Write-Host "Give $Delegate permission: $Permission to $Ressource "
    
    Add-MailboxFolderPermission -identity $Calendar -User $Delegate -AccessRights $Permission
    
    Write-host "Checking the Calendar permission currenlty assigned to $Ressource "
    Get-MailboxFolderPermission -Identity $Calendar -User $Delegate
}

Function Move-EXOMailboxContent
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [string]$SourceAlias,
        [Parameter(Mandatory = $true,
                   Position = 2)]
        [string]$TargetAlias,
        [Parameter(Mandatory = $false,
                   Position = 3)]
        [string]$TargetFolder,
        [Parameter(Position = 4)]
        [string]$StartDate,
        [Parameter(Position = 5)]
        [string]$EndDate
    )
    $BatchName = "Move_From_" + $SourceAlias + "_To_" + $TargetAlias
    If ($StartDate -and $EndDate)
    {
        Write-Host "The Script will copy mail contents from $SourceAlias using Date Range: from $StartDate to $EndDate"
        Read-Host "Press Enter to Continue or CTRL + C to Cancel"
        If ($TargetFolder)
        {
            Write-Host "The Script will Export contents from $SourceAlias to $TargetAlias but to the specific Folder: $TargetFolder"
            Search-Mailbox -Identity $SourceAlias -TargetMailbox $TargetAlias -TargetFolder $TargetFolder -SearchQuery "(sent>=$StartDate AND Sent<=$EndDate) OR (received>=$StartDate AND received<=$EndDate)"
        }
        Else
        {
            Write-Host "The Script will Export contents from $SourceAlias to $TargetAlias"
            Search-Mailbox -Identity $SourceAlias -TargetMailbox $TargetAlias -SearchQuery "(sent>=$StartDate AND Sent<=$EndDate) OR (received>=$StartDate AND received<=$EndDate)"
            
        }
    }
    ElseIf ($StartDate)
    {
        Write-Host "The Script will copy mail contents from $SourceAlias Received\Sent After: $StartDate"
        Read-Host "Press Enter to Continue or CTRL + C to Cancel"
        If ($TargetFolder)
        {
            Write-Host "The Script will Export contents from $SourceAlias to $TargetAlias but to the specific Folder: $TargetFolder"
            Search-Mailbox -Identity $SourceAlias -TargetMailbox $TargetAlias -TargetFolder $TargetFolder -SearchQuery "sent>=$StartDate OR received>=$StartDate"
        }
        Else
        {
            Write-Host "The Script will Export contents from $SourceAlias to $TargetAlias"
            Search-Mailbox -Identity $SourceAlias -TargetMailbox $TargetAlias -SearchQuery "sent>=$StartDate OR received>=$StartDate"
        }
    }
    ElseIf ($EndDate)
    {
        Write-Host "The Script will copy mail contents from $SourceAlias old than: $EndDate"
        Read-Host "Press Enter to Continue or CTRL + C to Cancel"
        If ($TargetFolder)
        {
            Write-Host "The Script will Export contents from $SourceAlias to $TargetAlias but to the specific Folder: $TargetFolder"
            Search-Mailbox -Identity $SourceAlias -TargetMailbox $TargetAlias -TargetFolder $TargetFolder -SearchQuery "sent<=$EndDate OR received<=$EndDate"
        }
        Else
        {
            Write-Host "The Script will Export contents from $SourceAlias to $TargetAlias"
            Search-Mailbox -Identity $SourceAlias -TargetMailbox $TargetAlias -SearchQuery "sent<=$EndDate OR received<=$EndDate"
        }
    }
    Else
    {
        Write-Host "No Date Range has been provide"
        Write-Host "The Script will stop"
        Exit
    }
}

Function Add-EXOMembersToDistributionGroupUsingCSV
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [string]$DG_EmailAddress,
        [Parameter(Mandatory = $true,
                   Position = 2)]
        [string]$CSVFile
    )
    
    Try
    {
        Read-Host "Expected CSV Column: EmailAddress"
        $Members = Import-Csv $CSVFile
        Write-Log -Level Info -Message "The script imported $CSVFile"
    }
    Catch
    {
        $ErrorMessage = $Error[0].Exception.Message
        $CMDLet = $Error[0].InvocationInfo.Line
        $FailedItem = $Error[0].Exception.ItemName
        Write-Log -Level Error -Message "Failed to Import $CSVFile"
        Write-Log -Level Error -Message "Failed to run the following CMDLet: $CMDLet"
        Write-Log -Level Error -Message "Failed with Error:$ErrorMessage"
        Exit
    }
    #Initiate the Hash Table
    [Int]$i = 1
    $Table = $Null
    $Table = @()
    $Count = ($Members | Measure).count
    
    foreach ($Member in $Members)
    {
        Try
        {
            $MemberEmailAddress = $Null
            $MemberEmailAddress = $Member.EmailAddress
            Write-Log -Level warning -Message "The script will try to add $MemberEmailAddress --- $i/$Count"
            Add-DistributionGroupMember -Identity $DG_EmailAddress -Member $MemberEmailAddress
            Write-Log -Level Info -Message "The script added $MemberEmailAddress --- $i/$Count"
            $Status = "Added"
        }
        Catch
        {
            $ErrorMessage = $Error[0].Exception.Message
            $CMDLet = $Error[0].InvocationInfo.Line
            $FailedItem = $Error[0].Exception.ItemName
            Write-Log -Level Error -Message "Failed to add $MemberEmailAddress to $DG_EmailAddress"
            Write-Log -Level Error -Message "Failed to run the following CMDLet: $CMDLet"
            Write-Log -Level Error -Message "Failed with Error:$ErrorMessage"
            $Status = "Failed to Add with Error: $ErrorMessage"
        }
        
        $Table += New-object PSobject -Property ([Ordered] @{
                MemberEmailAddress = $MemberEmailAddress;
                Status               = $Status;
            })
        
        $i++
    }
    $DateFull = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    $ReportFile = ".\adding_Members_" + $DG_EmailAddress + "_" + $DateFull + ".csv"
    $Table | Export-Csv $ReportFile -NoTypeInformation -Encoding UTF8
    Write-Log -Level INFO -Message "Generate the following Report: $ReportFile"
}

Function Remove-EXOCalendarInvite
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [string]$EmailAddress,
        [Parameter(Mandatory = $true,
                   Position = 2)]
        [datetime]$Date,
        [Parameter(Mandatory = $true,
                   Position = 3)]
        [int]$DurationInDays
    )
    
    Remove-CalendarEvents -Identity $EmailAddress -CancelOrganizedMeetings -QueryStartDate $Date -QueryWindowInDays $DurationInDays -PreviewOnly -confirm: $False
    Write-Host "Are you sure you want to remove all these meetings? - all recurrent meetings during this period will be cancelled" -NoNewline -ForegroundColor Red; Read-Host "<Press Enter to continue> or <ctrl + c> To cancel"
    Remove-CalendarEvents -Identity $EmailAddress -CancelOrganizedMeetings -QueryStartDate $Date -QueryWindowInDays $DurationInDays
}

Function Create-EXORestrictedSharedMailbox
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$DisplayName,
        [Parameter(Mandatory = $true,
                   Position = 2)]
        [String]$EmailAddress
    )
    $LocalPart = $EmailAddress.Substring(0, $EmailAddress.LastIndexOf("@"))
    $UserName = $LocalPart + $TenantOnMicrosoft
    
    # Create & Update Shared Mailbox Settings
    New-Mailbox -Shared -DisplayName $DisplayName -Name $DisplayName -Alias $LocalPart -PrimarySmtpAddress $UserName
    Write-Host " $DisplayName - $EmailAddress was " -NoNewline; Write-host "created" -ForegroundColor Green
    $PrimarySMTPAddress = 'SMTP:' + $EmailAddress
    Set-Mailbox -identity $UserName -EmailAddresses $PrimarySMTPAddress
    Set-CASMailbox -Identity $UserName -ActiveSyncEnabled $False -EwsEnabled $False -ImapEnabled $False -MacOutlookEnabled $False -MAPIEnabled $False -OutlookMobileEnabled $False -OWAEnabled $False -OWAforDevicesEnabled $False -PopEnabled $False -SmtpClientAuthenticationDisabled $False -UniversalOutlookEnabled $False
    Write-Host "$DisplayName - $EmailAddress Settings was " -NoNewline; Write-host "updated - Restriction" -ForegroundColor Green
    $UserNameFilter = "'" + $UserName + "'"
    Write-Host "The script will wait 30 seconds for replication between EXO & AAD" -ForegroundColor Yellow
    sleep 30
    $AADSharedMailbox = Get-AzureADUser -Filter "UserPrincipalName eq $UserNameFilter"
    $AADSharedMailboxObjectId = $AADSharedMailbox.ObjectId
    Write-Host "$DisplayName - $EmailAddress : ObjectID is: " -NoNewline; Write-host "$AADSharedMailboxObjectId" -ForegroundColor Green
    # Add user back to exclusion group:
    # MFA exclusion using SG-MFA-Special-Accounts (AAD Group)
    $MFAExclusionGroup = $Null
    $MFAExclusionGroup = Get-AzureADGroup -SearchString "SG-MFA-Special-Accounts"
    $MFAExclusionGroup_ObjectId = $Null
    $MFAExclusionGroup_ObjectId = $MFAExclusionGroup.ObjectId
    Add-AzureADGroupMember -ObjectId $MFAExclusionGroup_ObjectId -RefObjectId $AADSharedMailboxObjectId
    Write-Host "$DisplayName - $EmailAddress was added to the group :" -NoNewline; Write-host "SG-MFA-Special-Accounts" -ForegroundColor Green
    # Legacy authentication exclusion using SG-BlockLegacyAuth-Exceptions (AAD Group)
    $LegacyExclusionGroup = Get-AzureADGroup -SearchString "SG-BlockLegacyAuth-Exceptions"
    $LegacyExclusionGroup_ObjectId = $Null
    $LegacyExclusionGroup_ObjectId = $LegacyExclusionGroup.ObjectId
    Add-AzureADGroupMember -ObjectId $LegacyExclusionGroup_ObjectId -RefObjectId $AADSharedMailboxObjectId
    Write-Host "$DisplayName - $EmailAddress was added to the group :" -NoNewline; Write-host "SG-BlockLegacyAuth-Exceptions" -ForegroundColor Green
}

Function Convert-EXOUserMailboxToRestrictedSharedMailbox
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$EmailAddress
    )
    
    
    # Create & Update Shared Mailbox Settings
    Set-Mailbox $EmailAddress -Type Shared
    $Mailbox = $Null
    $Mailbox = Get-Mailbox $EmailAddress
    $DisplayName = $Null
    $DisplayName = $Mailbox.DisplayName
    Set-CASMailbox -Identity $EmailAddress -ActiveSyncEnabled $False -EwsEnabled $False -ImapEnabled $False -MacOutlookEnabled $False -MAPIEnabled $False -OutlookMobileEnabled $False -OWAEnabled $False -OWAforDevicesEnabled $False -PopEnabled $False -SmtpClientAuthenticationDisabled $False -UniversalOutlookEnabled $False
    Write-Host "$DisplayName - $EmailAddress Settings was " -NoNewline; Write-host "updated - Restriction" -ForegroundColor Green
    $UserNameFilter = "'" + $EmailAddress + "'"
    Write-Host "The script will wait 30 seconds for replication between EXO & AAD" -ForegroundColor Yellow
    sleep 30
    $AADSharedMailbox = Get-AzureADUser -Filter "UserPrincipalName eq $UserNameFilter"
    $AADSharedMailboxObjectId = $AADSharedMailbox.ObjectId
    Write-Host "$DisplayName - $EmailAddress : ObjectID is: " -NoNewline; Write-host "$AADSharedMailboxObjectId" -ForegroundColor Green
    # Add user back to exclusion group:
    # MFA exclusion using SG-MFA-Special-Accounts (AAD Group)
    $MFAExclusionGroup = $Null
    $MFAExclusionGroup = Get-AzureADGroup -SearchString "SG-MFA-Special-Accounts"
    $MFAExclusionGroup_ObjectId = $Null
    $MFAExclusionGroup_ObjectId = $MFAExclusionGroup.ObjectId
    Add-AzureADGroupMember -ObjectId $MFAExclusionGroup_ObjectId -RefObjectId $AADSharedMailboxObjectId
    Write-Host "$DisplayName - $EmailAddress was added to the group :" -NoNewline; Write-host "SG-MFA-Special-Accounts" -ForegroundColor Green
    # Legacy authentication exclusion using SG-BlockLegacyAuth-Exceptions (AAD Group)
    $LegacyExclusionGroup = Get-AzureADGroup -SearchString "SG-BlockLegacyAuth-Exceptions"
    $LegacyExclusionGroup_ObjectId = $Null
    $LegacyExclusionGroup_ObjectId = $LegacyExclusionGroup.ObjectId
    Add-AzureADGroupMember -ObjectId $LegacyExclusionGroup_ObjectId -RefObjectId $AADSharedMailboxObjectId
    Write-Host "$DisplayName - $EmailAddress was added to the group :" -NoNewline; Write-host "SG-BlockLegacyAuth-Exceptions" -ForegroundColor Green
}

Function Open-EXOConferenceRoom
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$Identity
    )
    Write-Host "Checking for configuration before change ( $Identity) :"
    Get-CalendarProcessing -Identity $Identity | fl AutomateProcessing, DeleteComments, DeleteSubject, ResourceDelegates, BookInPolicy, AllBookInPolicy
    Set-CalendarProcessing -Identity $Identity -AutomateProcessing AutoAccept -DeleteSubject:$False -DeleteComments:$false -AllBookInPolicy $True -BookInPolicy $Null -ResourceDelegates $Null
    sleep 10
    Write-Host "Checking for configuration post change ( $Identity) :"
    Get-CalendarProcessing -Identity $Identity | fl AutomateProcessing, DeleteComments, DeleteSubject, ResourceDelegates, BookInPolicy, AllBookInPolicy
}

Function Update-EXOCalendarProcessingSettingsForConferenceRoom
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$EmailAddress
    )
    Write-Host "Settings before the change:"
    Get-CalendarProcessing $EmailAddress | fl AutomateProcessing, DeleteComments, DeleteSubject
    Set-CalendarProcessing $EmailAddress -DeleteSubject:$False -DeleteComments:$False
    sleep 2
    Write-Host "Settings after the change:"
    Get-CalendarProcessing $EmailAddress | fl AutomateProcessing, DeleteComments, DeleteSubject
    #$Calendar = $EmailAddress + ":\Calendar"
    #Write-Host "Updating permission for $Calendar :"
    #Add-MailboxFolderPermission -Identity $Calendar -User "User1@company.com" -AccessRights "Reviewer"
}

Function Get-EXOUnifiedGroupMembers
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$Identity
    )
    
    Get-UnifiedGroupLinks -Identity $Identity -LinkType Members -ResultSize unlimited
}

Function Expand-EXOGroup
{
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$GroupName
    )
    $Users = $Null
    $Users = @()
    $Members = Get-DistributionGroupMember -Identity $GroupName
    foreach ($Member in $Members)
    {
        $RecipientType = $Member.RecipientType
        #$member.Name + "`t`t`t" + $RecipientType
        if ($RecipientType -like "*DistributionGroup*")
        {
            # Found an child group - calling myself to expand the group
            Expand-Group -GroupName $member.Alias
        }
        # Create a PSCustomObject of the current member
        $MemberObject = [PSCustomObject] @{
            FirstName = "$($member.FirstName)"
            LastName  = "$($member.LastName)"
            Name      = "$($member.Name)"
            Title      = "$($member.Title)"
            Department = "$($member.Department)"
            Email      = "$($member.PrimarySMTPAddress)"
            Memberof  = "$GroupName"
            RecipientType = "$RecipientType"
        }
        # Store the member object to Users array
        $Users += $MemberObject
    }
    Return $Users
}

Function Expand-EXODirectADGroup
{
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$GroupName
    )
    $Users = $Null
    $Users = @()
    $Members = Get-ADGroupMember -Identity $GroupName
    foreach ($Member in $Members)
    {
        $UserDN = $Member.DistinguishedName
        $ADuser = $Null
        $ADuser = Get-ADUser -Identity $UserDN -Properties *
        # Create a PSCustomObject of the current member
        $MemberObject = [PSCustomObject] @{
            FirstName = "$($ADuser.FirstName)"
            LastName  = "$($ADuser.LastName)"
            Name      = "$($ADuser.Name)"
            Title      = "$($ADuser.Title)"
            Department = "$($ADuser.Department)"
            Email      = "$($ADuser.PrimarySMTPAddress)"
            Memberof  = "$GroupName"
        }
        # Store the member object to Users array
        $Users += $MemberObject
    }
    Return $Users
}

Function Replace-EXODistributionListMembers
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$EmailAddress,
        [Parameter(Mandatory = $true,
                   Position = 2)]
        [String]$File
    )
    Update-DistributionGroupMember -Identity $EmailAddress -Members $Null -confirm:$False
    $Members = Get-Content $File
    foreach ($Member in $Members)
    {
        Add-DistributionGroupMember -Identity $EmailAddress -Member $Member -confirm:$False
    }
    
}

Function Count-EXOForwardToRecipientOfInboxRules
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [string]$EmailAddress
    )
    [Int]$i = 1
    $Table = $Null
    $Table = @()
    $InboxRules = $Null
    $InboxRules = Get-inboxRule -Mailbox $EmailAddress
    $Count = ($InboxRules | Measure).count
    foreach ($InboxRule in $InboxRules)
    {
        $RuleName = $Null
        $RuleName = $InboxRule.Name
        $ForwardTo = $Null
        $ForwardTo = $InboxRule.ForwardTo
        $Priority = $Null
        $Priority = $InboxRule.Priority
        $ForwardToCount = ($ForwardTo | Measure).count
        #Write-Log -Level INFO -message "Checking Rule $RuleName --- $i/$Count "
        
        $Table += New-object PSobject -Property ([Ordered] @{
                RuleName       = $RuleName;
                Priority       = $Priority;
                ForwardToCount = $ForwardToCount;
            })
        
        $i++
        
    }
    $Table | Ft
}

Function Create-EXOTransportRuleforBlockingIncomingMessagewithException
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [string]$RecipientEmailAddress,
        [Parameter(Mandatory = $true,
                   Position = 2)]
        [String]$Exception
    )
    $DateFull = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    $Name = "Block Incoming Messages: " + $RecipientEmailAddress
    $RejectMessageEnhancedStatusCode = "5.7.1"
    $RejectMessageReasonText = "Your message has been blocked"
    $Comments = "Block Incoming Messages with Exceptions for $RecipientEmailAddress - Date: $DateFull"
    
    New-TransportRule -Name $Name -FromScope "NotInOrganization" -RejectMessageEnhancedStatusCode $RejectMessageEnhancedStatusCode -RejectMessageReasonText $RejectMessageReasonText -ExceptIfFrom $Exception -AnyOfToHeader $RecipientEmailAddress -Comments $Comments -Enabled $False
}

Function Run-EXOMessageTraceLast2Days
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $false,
                   Position = 1)]
        [String]$Sender,
        [Parameter(Position = 1)]
        [String]$Recipient
    )
    
    $DateFull = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    
    if ($Sender)
    {
        $MessageTraceFile = $Sender + "_Last2Days_MessageTrace_Sender_Search_" + $DateFull + ".csv"
    }
    
    if ($Recipient)
    {
        $MessageTraceFile = $Recipient + "_Last2Days_MessageTrace_Recipient_Search_" + $DateFull + ".csv"
    }
    $Table = $Null
    $Table = @()
    $StartDate = (Get-Date).AddDays(-2)
    $EndDate = Get-Date
    $Messages = $null
    $Messages = @()
    
    [Int]$i = 1
    [Int]$MessageCount = 1
    Do
    {
        If ($Sender)
        {
            $AllMessages = Get-MessageTrace -SenderAddress $Sender -EndDate $EndDate -StartDate $StartDate -PageSize 5000 -Page $i
        }
        If ($Recipient)
        {
            $AllMessages = Get-MessageTrace -RecipientAddress $Recipient -EndDate $EndDate -StartDate $StartDate -PageSize 5000 -Page $i
        }
        $MessageCount = ($AllMessages | Measure).count
        $Messages += $AllMessages
        $i++
    }
    While ($MessageCount -ne 0)
    foreach ($Message in $Messages)
    {
        
        $MessageTraceID = $Null
        $MessageTraceID = $Message.MessageTraceId.Guid
        $SenderAddress = $Null
        $SenderAddress = $Message.SenderAddress
        $Received = $Null
        $Received = $Message.Received
        $RecipientAddress = $Null
        $RecipientAddress = $Message.RecipientAddress
        $Subject = $Null
        $Subject = $Message.Subject
        $Status = $Null
        $Status = $Message.Status
        $Table += New-object PSobject -Property ([Ordered] @{
                SenderAddress    = $SenderAddress;
                RecipientAddress = $RecipientAddress;
                Subject             = $Subject;
                ReceivedDate     = $Received;
                Status             = $Status;
                MessageTraceID   = $MessageTraceID;
            })
        
        
    }
    $Table | Export-Csv $MessageTraceFile -NoTypeInformation -Encoding UTF8
    Write-Host "The following CSV File was generated:" -NoNewline; Write-Host -ForegroundColor Green "$MessageTraceFile"
    # Open File
    $Openfile = Read-Host "Do you want to open the file? Y for Yes and N for No"
    If ($Openfile -eq "Y")
    { Invoke-Item $MessageTraceFile }
    Else { Write-Log -Level Warning -Message "End of the script" }
    
}

Function Run-EXOMessageTraceLast7Days
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $false,
                   Position = 1)]
        [String]$Sender,
        [Parameter(Position = 1)]
        [String]$Recipient
    )
    
    $DateFull = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    
    if ($Sender)
    {
        $MessageTraceFile = $Sender + "_Last7Days_MessageTrace_Sender_Search_" + $DateFull + ".csv"
    }
    
    if ($Recipient)
    {
        $MessageTraceFile = $Recipient + "_Last7Days_MessageTrace_Recipient_Search_" + $DateFull + ".csv"
    }
    $Table = $Null
    $Table = @()
    $StartDate = (Get-Date).AddDays(-7)
    $EndDate = Get-Date
    $Messages = $null
    $Messages = @()
    
    [Int]$i = 1
    [Int]$MessageCount = 1
    Do
    {
        If ($Sender)
        {
            $AllMessages = Get-MessageTrace -SenderAddress $Sender -EndDate $EndDate -StartDate $StartDate -PageSize 5000 -Page $i
        }
        If ($Recipient)
        {
            $AllMessages = Get-MessageTrace -RecipientAddress $Recipient -EndDate $EndDate -StartDate $StartDate -PageSize 5000 -Page $i
        }
        $MessageCount = ($AllMessages | Measure).count
        $Messages += $AllMessages
        $i++
    }
    While ($MessageCount -ne 0)
    foreach ($Message in $Messages)
    {
        
        $MessageTraceID = $Null
        $MessageTraceID = $Message.MessageTraceId.Guid
        $SenderAddress = $Null
        $SenderAddress = $Message.SenderAddress
        $Received = $Null
        $Received = $Message.Received
        $RecipientAddress = $Null
        $RecipientAddress = $Message.RecipientAddress
        $Subject = $Null
        $Subject = $Message.Subject
        $Status = $Null
        $Status = $Message.Status
        $Table += New-object PSobject -Property ([Ordered] @{
                SenderAddress    = $SenderAddress;
                RecipientAddress = $RecipientAddress;
                Subject             = $Subject;
                ReceivedDate     = $Received;
                Status             = $Status;
                MessageTraceID   = $MessageTraceID;
            })
        
        
    }
    $Table | Export-Csv $MessageTraceFile -NoTypeInformation -Encoding UTF8
    Write-Host "The following CSV File was generated:" -NoNewline; Write-Host -ForegroundColor Green "$MessageTraceFile"
    
    # Open File
    $Openfile = Read-Host "Do you want to open the file? Y for Yes and N for No"
    If ($Openfile -eq "Y")
    { Invoke-Item $MessageTraceFile }
    Else { Write-Log -Level Warning -Message "End of the script" }
}

Function Run-EXOMessageTraceLast10Days
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $false,
                   Position = 1)]
        [String]$Sender,
        [Parameter(Position = 1)]
        [String]$Recipient
    )
    
    $DateFull = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    
    if ($Sender)
    {
        $MessageTraceFile = $Sender + "_Last10Days_MessageTrace_Sender_Search_" + $DateFull + ".csv"
    }
    
    if ($Recipient)
    {
        $MessageTraceFile = $Recipient + "_Last10Days_MessageTrace_Recipient_Search_" + $DateFull + ".csv"
    }
    $Table = $Null
    $Table = @()
    $StartDate = (Get-Date).AddDays(-10)
    $EndDate = Get-Date
    $Messages = $null
    $Messages = @()
    
    [Int]$i = 1
    [Int]$MessageCount = 1
    Do
    {
        If ($Sender)
        {
            $AllMessages = Get-MessageTrace -SenderAddress $Sender -EndDate $EndDate -StartDate $StartDate -PageSize 5000 -Page $i
        }
        If ($Recipient)
        {
            $AllMessages = Get-MessageTrace -RecipientAddress $Recipient -EndDate $EndDate -StartDate $StartDate -PageSize 5000 -Page $i
        }
        $MessageCount = ($AllMessages | Measure).count
        $Messages += $AllMessages
        $i++
    }
    While ($MessageCount -ne 0)
    foreach ($Message in $Messages)
    {
        
        $MessageTraceID = $Null
        $MessageTraceID = $Message.MessageTraceId.Guid
        $SenderAddress = $Null
        $SenderAddress = $Message.SenderAddress
        $Received = $Null
        $Received = $Message.Received
        $RecipientAddress = $Null
        $RecipientAddress = $Message.RecipientAddress
        $Subject = $Null
        $Subject = $Message.Subject
        $Status = $Null
        $Status = $Message.Status
        $Table += New-object PSobject -Property ([Ordered] @{
                SenderAddress    = $SenderAddress;
                RecipientAddress = $RecipientAddress;
                Subject             = $Subject;
                ReceivedDate     = $Received;
                Status             = $Status;
                MessageTraceID   = $MessageTraceID;
            })
        
        
    }
    $Table | Export-Csv $MessageTraceFile -NoTypeInformation -Encoding UTF8
    Write-Host "The following CSV File was generated:" -NoNewline; Write-Host -ForegroundColor Green "$MessageTraceFile"
    # Open File
    $Openfile = Read-Host "Do you want to open the file? Y for Yes and N for No"
    If ($Openfile -eq "Y")
    { Invoke-Item $MessageTraceFile }
    Else { Write-Log -Level Warning -Message "End of the script" }
    
}

function Run-EXOMessageTraceLast90Days
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $false,
                   Position = 1)]
        [String]$Recipient,
        [Parameter(Mandatory = $false,
                   Position = 2)]
        [String]$SenderAddress
    )
    
    $EndDate = (Get-Date).AddDays(+ 1)
    $StartDate = (Get-Date).AddDays(-90)
    Read-Host "Are you connected to Exchange Online? - Enter to Continue or CTRL+C to Cancel"
    
    
    If ($SenderAddress -and $Recipient)
    {
        $SearchName = "MessageTrace_90days_Sender_" + $SenderAddress + "_Recipient_" + $Recipient
        Start-HistoricalSearch -ReportTitle $SearchName -RecipientAddress $Recipient -SenderAddress $SenderAddress -StartDate $StartDate -EndDate $EndDate -ReportType MessageTraceDetail
        Write-Host "Generating a Report for Recipient : $Recipient --- Sender: $SenderAddress --- From : $StartDate To: $EndDate ...."
    }
    Elseif ($SenderAddress -and !($Recipient))
    {
        $SearchName = "MessageTrace_90days_Sender_" + $SenderAddress
        Start-HistoricalSearch -ReportTitle $SearchName -SenderAddress $SenderAddress -StartDate $StartDate -EndDate $EndDate -ReportType MessageTraceDetail
        Write-Host "Generating a Report for Sender : $SenderAddress From : $StartDate To: $EndDate ...."
    }
    Elseif ($Recipient -and !($SenderAddress))
    {
        $SearchName = "MessageTrace_90days_Recipient_" + $Recipient
        Start-HistoricalSearch -ReportTitle $SearchName -RecipientAddress $Recipient -StartDate $StartDate -EndDate $EndDate -ReportType MessageTraceDetail
        Write-Host "Generating a Report for Recipient : $Recipient From : $StartDate To: $EndDate ...."
    }
    Write-Host "The Report $SearchName request is generated"
    Get-HistoricalSearch | where { $_.ReportTitle -eq $SearchName } | fl
}

Function Investigate-EXOUserInboxRules
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$EmailAddress,
        [Parameter(Mandatory = $true,
                   Position = 2)]
        [datetime]$StartDate,
        [Parameter(Mandatory = $true,
                   Position = 3)]
        [datetime]$EndDate
    )
    
    # Inbox Rules
    $DateFull = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    $InboxRulesFile = $EmailAddress + "_InboxRules_" + $DateFull + ".csv"
    Write-host 'Searching Inbox Rules...' -ForegroundColor Yellow
    $InboxRules = Get-InboxRule -Mailbox $EmailAddress | Select Name, Description, Enabled, Identity, From, ForwardTo, ForwardAsAttachmentTo, SentTo, MoveToFolder | Export-csv $InboxRulesFile -NoTypeInformation -Encoding UTF8
    $InboxRulesCount = ($InboxRules | Measure).Count
    Write-Host "Found" -NoNewline; Write-Host -ForegroundColor Green  "$InboxRulesCount" -NoNewline; Write-Host  "Outlook Rules - Export the report to:" -NoNewline; Write-Host -ForegroundColor Green "$InboxRulesFile"
    # Mailbox Audit Log Search
    $MailboxAuditLogSearch = Run-MailboxAuditLogSearch -Mailbox $EmailAddress -StartDate $StartDate -EndDate $EndDate
    # Unified Log Check for Outlook Rules History
    $UnifiedAuditLogsFile = $EmailAddress + "_UnifiedAuditLogs_InboxRules_" + $DateFull + ".csv"
    Write-Host -ForegroundColor Yellow "Analyzing Unified Audit Logs for Inbox Rules changes...."
    $UnifiedAuditLogs = Search-UnifiedAuditLog -StartDate $StartDate -EndDate $EndDate -Operations New-InboxRule, Set-InboxRule, UpdateInboxRules -UserIds $EmailAddress | Select Userids, RecordType, CreationDate, OPerations, AuditData | Export-csv $UnifiedAuditLogsFile -NoTypeInformation -Encoding UTF8
    Write-Host "The script export Unified Audit Logs to:" -NoNewline; Write-Host -ForegroundColor Green "$UnifiedAuditLogsFile"
    # Open File
    $Openfile = Read-Host "Do you want to open the file? Y for Yes and N for No"
    If ($Openfile -eq "Y")
    {
        Invoke-Item $UnifiedAuditLogsFile
        Invoke-Item $InboxRulesFile
    }
    Else { Write-Log -Level Warning -Message "End of the script" }
    
}

Function Investigate-EXOBlockedMailbox
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$Sender
    )
    $StartDate = (Get-Date).AddDays(-30)
    $EndDate = (Get-Date).AddDays(+ 1)
    Try
    {
        Write-Host "Script is checking if the user is Restricted from sending message (Sender: $Sender)...."
        $BlockSender = Get-BlockedSenderAddress -SenderAddress $Sender
        $Reason = $Null
        $Reason = $BlockSender.Reason
        # Convert Variable to Table
        $ReasonTable = $Reason.split("{;}")
        
        $OutboundSpamLast24Hours = $ReasonTable[0]
        $OutboundSpamLast24HoursValue = $OutboundSpamLast24Hours.Substring($OutboundSpamLast24Hours.IndexOf("="))
        $OutboundSpamLast24HoursValue = $OutboundSpamLast24HoursValue.Substring(1)
        
        $OutboundMailLast24Hours = $ReasonTable[1]
        $OutboundMailLast24HoursValue = $OutboundMailLast24Hours.Substring($OutboundMailLast24Hours.IndexOf("="))
        $OutboundMailLast24HoursValue = $OutboundMailLast24HoursValue.Substring(1)
        
        $OutboundSpamPercent = $ReasonTable[2]
        $OutboundSpamPercentValue = $OutboundSpamPercent.Substring($OutboundSpamPercent.IndexOf("="))
        $OutboundSpamPercentValue = $OutboundSpamPercentValue.Substring(1)
        
        $LastMessageSent_MessageTraceID = $ReasonTable[3]
        $LastMessageSent_MessageTraceIDValue = $LastMessageSent_MessageTraceID.Substring($LastMessageSent_MessageTraceID.IndexOf(":"))
        $LastMessageSent_MessageTraceIDValue = $LastMessageSent_MessageTraceIDValue.Substring(1)
        
        $CreatedDateTime = $Null
        $CreatedDateTime = $BlockSender.CreatedDateTime
        $ChangedDateTime = $Null
        $ChangedDateTime = $BlockSender.ChangedDateTime
        #Searching Messages using MessageTraceID
        Try
        {
            $Messages = Get-MessageTrace -MessageTraceID $LastMessageSent_MessageTraceIDValue
            $MessageSubject = $Messages[0].Subject
            $MessageDate = $Messages[0].Received
            $MessagesFound = "Yes"
        }
        Catch
        {
            $MessagesFound = "No"
        }
        
        Write-Host "The script found $Sender was blocked" -ForegroundColor Red
        Write-Host "Please run the following CMDLet to remove the blocked:" -NoNewline; Write-Host -ForegroundColor Green "Remove-BlockedSenderAddress -SenderAddress $Sender"
        Write-Host "--- When: Created Date: $CreatedDateTime - Change Date:$ChangedDateTime"
        Write-Host "--- Reason: " -ForegroundColor Yellow
        Write-Host "------ Outbound Spam Last 24 Hours (Sent):" -NoNewline; Write-Host -ForegroundColor Green "$OutboundSpamLast24HoursValue "
        Write-Host "------ Outbound Mail Last 24 Hours(Sent):" -NoNewline; Write-Host -ForegroundColor Green " $OutboundMailLast24HoursValue"
        Write-Host "------ Outbound Spam Percent:" -NoNewline; Write-Host -ForegroundColor Green " $OutboundSpamPercentValue"
        
        If ($MessagesFound -ne "No")
        {
            Write-Host "------ Last Message Sent was (older than 10 days):"
            Write-Host "--------- Message Trace ID (Network MessageID):" -NoNewline; Write-Host -ForegroundColor Green " $LastMessageSent_MessageTraceIDValue"
            Write-Host "--------- Message Subject:" -NoNewline; Write-Host -ForegroundColor Green " $MessageSubject"
            Write-Host "--------- Message Sent Date:" -NoNewline; Write-Host -ForegroundColor Green " $MessageDate"
        }
        Else
        {
            Write-Host "------ Last Message Sent (Message Trace ID/Network MessageID) =" -NoNewline; Write-Host -ForegroundColor Green " $LastMessageSent_MessageTraceIDValue"
        }
        
    }
    Catch
    {
        Write-Host "Failed to find the user as restricted user" -ForegroundColor Green
    }
    
    
    
    # Check for mailbox forwarding option
    $Mailbox = $Null
    $Mailbox = Get-Mailbox $Sender
    $ForwardingAddress = $Null
    $ForwardingAddress = $Mailbox.ForwardingAddress
    If ($ForwardingAddress -eq $Null)
    { $ForwardingAddress = "Not Set" }
    $ForwardingSmtpAddress = $Null
    $ForwardingSmtpAddress = $Mailbox.ForwardingSmtpAddress
    If ($ForwardingSmtpAddress -eq $Null)
    { $ForwardingSmtpAddress = "Not Set" }
    Write-Host "The script is checking for Forwarding enable on $Sender :" -ForegroundColor Yellow
    Write-Host "------ ForwardingAddress (User):" -NoNewline; Write-Host -ForegroundColor Green "$ForwardingAddress"
    Write-Host "------ ForwardingSMTPAddress (Admin):" -NoNewline; Write-Host -ForegroundColor Green "$ForwardingSmtpAddress"
    # Check Delegate
    $DelegateInbox = $Sender + ":\Inbox"
    $Delegate = Get-MailboxFolderPermission $DelegateInbox | select Identity, FolderName, User, AccessRights
    Write-Host "The script is checking for delegate access on $Sender :" -ForegroundColor Yellow
    $Delegate | ft
    # Inbox Rules
    Write-Host "The script is checking for Inbox Rules for: $Sender :" -ForegroundColor Yellow
    $InboxRules = Get-InboxRule -Mailbox $Sender | Select Name, Description, Enabled, Identity, From, ForwardTo, ForwardAsAttachmentTo, SentTo, MoveToFolder
    $InboxRulesCount = ($InboxRules | measure).count
    if ($InboxRulesCount -gt 1)
    {
        $InboxRules | ft
    }
    Else
    {
        Write-Host "The script did NOT found any Inbox Rules for: $Sender" -ForegroundColor Green
    }
    
    # Unified Log Check for Outlook Rules History
    Write-Host 'The script is checking the Unified Logs for Inbox Rules changes (30 days)' -ForegroundColor Yellow
    $UnifiedAuditLogs = Search-UnifiedAuditLog -StartDate $StartDate -EndDate $EndDate -Operations New-InboxRule, Set-InboxRule, UpdateInboxRules -UserIds $Sender | Select Userids, RecordType, CreationDate, OPerations, AuditData
    $UnifiedAuditLogsCount = ($UnifiedAuditLogs | measure).count
    if ($UnifiedAuditLogsCount -gt 1)
    {
        $UnifiedAuditLogs | ft
    }
    Else
    {
        Write-Host "The script did NOT found any Inbox Rules changes (unified Audit Logs) for (last 30 days)" -ForegroundColor Green
    }
    
    #Mailbox Audit Logs
    $MailboxAuditLogs = $Null
    Write-Host "The script is checking Mailbox Audit Log for:" -ForegroundColor Yellow
    $MailboxAuditLogs = Run-MailboxAuditLogSearch -Mailbox $Sender -StartDate $StartDate -EndDate $EndDate
}

Function Run-EXOMailboxAuditLogSearch
{
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [string]$Mailbox,
        [Parameter(Mandatory = $true,
                   Position = 2)]
        [string]$StartDate,
        [Parameter(Mandatory = $true,
                   Position = 3)]
        [string]$EndDate,
        [Parameter(Mandatory = $false,
                   Position = 4)]
        [string]$Subject,
        [Parameter(Mandatory = $false,
                   Position = 5)]
        [switch]$IncludeFolderBind
    )
    
    $DateFull = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    $ReportFile = $Mailbox + "_Report_MailboxAuditLog_" + $DateFull + ".csv"
    
    $Table = $Null
    $Table = @()
    $SearchResults = $Null
    $SearchResults = @()
    
    Try
    {
        Write-Log -Level Warning -Message 'Searching Mailbox Audit Logs...'
        $SearchResults = Search-MailboxAuditLog $Mailbox -StartDate $StartDate -EndDate $EndDate -LogonTypes Owner, Admin, Delegate -ShowDetails -resultsize 50000
        if (-not $IncludeFolderBind)
        {
            Write-Log -Level Warning -Message 'Removing FolderBind operations.'
            $SearchResults = $SearchResults | Where { $_.Operation -notlike 'FolderBind' }
            $SearchResultsCount = ($SearchResults | measure).count
            Write-Log -Level -Level INFO -Message "The script found $SearchResultsCount entries Found"
        }
        Else
        {
            $SearchResultsCount = ($SearchResults | measure).count
            Write-Log -Level -Level INFO -Message "The script found $SearchResultsCount entries Found"
        }
        
        
    }
    Catch
    {
        $ErrorMessage = $Error[0].Exception.Message
        $CMDLet = $Error[0].InvocationInfo.Line
        $FailedItem = $Error[0].Exception.ItemName
        Write-Log -Level -Level Error -Message "Failed to Retreive Mailbox Audit Log for $Mailbox"
        Write-Log -Level -Level Error -Message "Failed to run the following CMDLet: $CMDLet"
        Write-Log -Level -Level Error -Message "Failed with Error:$ErrorMessage"
        Write-Log -Level Error -Message "The Script will stop"
        # Exit the script
        Exit
    }
    
    foreach ($SearchResult in $SearchResults)
    {
        
        $Operation = $Null
        $Operation = $SearchResult.Operation
        $LogonUserDisplayName = $Null
        $LogonUserDisplayName = $SearchResult.LogonUserDisplayName
        $LastAccessed = $Null
        $LastAccessed = $SearchResult.LastAccessed
        $DestFolderPathName = $Null
        $DestFolderPathName = $SearchResult.DestFolderPathName
        $FolderPathName = $Null
        $FolderPathName = $SearchResult.FolderPathName
        $ClientInfoString = $Null
        $ClientInfoString = $SearchResult.ClientInfoString
        $ClientIPAddress = $Null
        $ClientIPAddress = $SearchResult.ClientIPAddress
        $ClientMachineName = $Null
        $ClientMachineName = $SearchResult.ClientMachineName
        $ClientProcessName = $Null
        $ClientProcessName = $SearchResult.ClientProcessName
        $ClientVersion = $Null
        $ClientVersion = $SearchResult.ClientVersion
        $LogonType = $Null
        $LogonType = $SearchResult.LogonType
        $MailboxResolvedOwnerName = $Null
        $MailboxResolvedOwnerName = $SearchResult.MailboxResolvedOwnerName
        $OperationResult = $Null
        $OperationResult = $SearchResult.OperationResult
        $Operation = $Null
        $Operation = $SearchResult.Operation
        $CrossMailboxOperation = $Null
        $CrossMailboxOperation = $SearchResult.CrossMailboxOperation
        
        $SourceItems = $Null
        $SourceItems = $SearchResult.SourceItems
        $SubjectItems = $Null
        if (($SourceItems.Count -eq 0) -or ($SourceItems.Count -eq $null)) { $SubjectItems = $SearchResult.ItemSubject }
        else { $SubjectItems = $SearchResult.SourceItemSubjectsList }
        
        if ($Operation -contains 'SendAs' -or $Operation -contains 'Create' -or $Operation -contains 'Update') { $CrossMailboxOperation = 'N/A' }
        
        
        if ($Subject)
        {
            if ($SubjectItems -match $Subject)
            {
                $Table += New-object PSobject -Property ([Ordered] @{
                        Subject                     = $SubjectItems;
                        Operation                 = $Operation;
                        LogonUserDisplayName     = $LogonUserDisplayName;
                        LastAccessed             = $LastAccessed;
                        DestFolderPathName         = $DestFolderPathName;
                        FolderPathName             = $FolderPathName;
                        ClientInfoString         = $ClientInfoString;
                        ClientIPAddress             = $ClientIPAddress;
                        ClientMachineName         = $ClientMachineName;
                        ClientProcessName         = $ClientProcessName;
                        ClientVersion             = $ClientVersion;
                        LogonType                 = $LogonType;
                        MailboxResolvedOwnerName = $MailboxResolvedOwnerName;
                        OperationResult             = $OperationResult;
                        CrossMailboxOperation    = $CrossMailboxOperation;
                    })
            }
        }
        Else
        {
            $Table += New-object PSobject -Property ([Ordered] @{
                    Subject                     = $SubjectItems;
                    Operation                 = $Operation;
                    LogonUserDisplayName     = $LogonUserDisplayName;
                    LastAccessed             = $LastAccessed;
                    DestFolderPathName         = $DestFolderPathName;
                    FolderPathName             = $FolderPathName;
                    ClientInfoString         = $ClientInfoString;
                    ClientIPAddress             = $ClientIPAddress;
                    ClientMachineName         = $ClientMachineName;
                    ClientProcessName         = $ClientProcessName;
                    ClientVersion             = $ClientVersion;
                    LogonType                 = $LogonType;
                    MailboxResolvedOwnerName = $MailboxResolvedOwnerName;
                    OperationResult             = $OperationResult;
                    CrossMailboxOperation    = $CrossMailboxOperation;
                })
        }
        
    }
    
    # Export Report
    $Table | export-csv $ReportFile -NoTypeInformation -Encoding UTF8
    Write-Log -Level Warning -Message "The Script has generate the following Report: $ReportFile"
}

Function Duplicate-EXODistributionGroupMembers
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$SourceDG,
        [Parameter(Mandatory = $true,
                   Position = 2)]
        [String]$DestinationDG
    )
    $DateFull = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    #Backup Distribution Groups
    $SourceDGMembers = Get-DistributionGroupMember $SourceDG
    $SourceDGXMLFile = "Backup_DG_Members_Of_" + $SourceDG + "_" + $DateFull + ".xml"
    $SourceDGMembers | Export-Clixml $SourceDGXMLFile
    Write-Host "a backup of Distribution Group $SourceDG was created : $SourceDGXMLFile"
    
    $BeforeDestinationDGMembers = Get-DistributionGroupMember $DestinationDG
    $DestinationDGXMLFile = "Backup_DG_Members_Of_" + $DestinationDG + "_" + $DateFull + ".xml"
    $BeforeDestinationDGMembers | Export-Clixml $DestinationDGXMLFile
    Write-Host "a backup of Distribution Group $DestinationDG was created : $DestinationDGXMLFile"
    # Update Distribution Group
    $SourceDGMembers | foreach{ Add-DistributionGroupMember $DestinationDG -Member $_.WindowsLiveID }
    $SourceDGMembersCount = ($SourceDGMembers | measure).count
    Write-Host "Member of Source Distribution Group has $SourceDGMembersCount members" -ForegroundColor Yellow
    $DestinationDGMembers = Get-DistributionGroupMember $DestinationDG
    $DestinationDGMembersCount = ($DestinationDGMembers | measure).count
    Write-Host "Member of Destination Distribution Group has $DestinationDGMembersCount members" -ForegroundColor Green
}

Function Search-EXOAdminRolebyCMDlet
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$CMDLet
    )
    $TableRole = $Null
    $TableRole = @()
    
    $ManagementRoles = Get-ManagementRole -Cmdlet $CMDLet
    $ManagementRolesCount = ($ManagementRoles | Measure).count
    Foreach ($ManagementRole in $ManagementRoles)
    {
        $ManagementRoleName = $ManagementRole.Name
        $ManagementRoleAssignment = Get-ManagementRoleAssignment -Role $ManagementRoleName
        $RoleAssigneeName = $Null
        $RoleAssigneeName = $ManagementRoleAssignment.RoleAssigneeName
        $TableRole += New-object PSobject -Property ([Ordered] @{
                CMDLet               = $CMDLet;
                ManagementRoleName = $ManagementRoleName;
                AdminRoles           = $RoleAssigneeName;
            })
        
    }
    $TableRole | ft
}

Function Add-EXOMailboxPermissionSendAs
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$SharedMailbox,
        [Parameter(Mandatory = $true,
                   Position = 2)]
        [String]$User,
        [Parameter(Mandatory = $false,
                   Position = 3)]
        [String]$LogFolder
    )
    $DateSendAs = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    
    If ($LogFolder) { Create-Folder $LogFolder }
    Else { $LogFolder = (get-location).path }
    $SendAsLog = $LogFolder + "\Assign_SendAs_Permission_" + $SharedMailbox + "_" + $DateSendAs + ".log"
    
    Try
    {
        #Assign Send As Permission
        Write-Log -Level Warning $SendAsLog "Attempt to assign Send As Permission - Mailbox : $SharedMailbox - Trustee: $User"
        Add-RecipientPermission $SharedMailbox -AccessRights SendAs -Trustee $User -Confirm:$False
        Write-Log -Level Warning $SendAsLog "Successfully Assign Send As Permission - Mailbox : $SharedMailbox - Trustee: $User"
        # Check Send As Permission
        Write-Log -Level Warning $SendAsLog "Attempt to check Send As Permission - Mailbox : $SharedMailbox - Trustee: $User"
        $SendAsPermissionData = Get-RecipientPermission $SharedMailbox -AccessRights SendAs | where { $_.Trustee -ne "NT AUTHORITY\SELF" } | select Identity, Trustee, AccessRights, AccessControlType
        Write-Log -Level Warning $SendAsLog "SendAs Permission assign to $SharedMailbox is: "
        $SendAsPermissionData | Out-File $SendAsLog -Append
        $SendAsPermissionData | ft
    }
    
    Catch
    {
        Write-Log -Level Error $SendAsLog "Failed to assign Send As Permission - Mailbox : $SharedMailbox - Trustee: $User"
    }
}

Function Remove-EXOMailboxPermissionSendAs
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$SharedMailbox,
        [Parameter(Mandatory = $true,
                   Position = 2)]
        [String]$User,
        [Parameter(Mandatory = $false,
                   Position = 3)]
        [String]$LogFolder
    )
    $DateRemoveSendAs = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    If ($LogFolder) { Create-Folder $LogFolder }
    Else { $LogFolder = (get-location).path }
    $RemoveSendAsLog = $LogFolder + "\Remove_SendAs_Permission_" + $SharedMailbox + "_" + $DateRemoveSendAs + ".log"
    
    Try
    {
        #Remove Send As Permission
        Write-Log -Level Warning $RemoveSendAsLog "Attempt to Remove Send As Permission - Mailbox : $SharedMailbox - Trustee: $User"
        Remove-RecipientPermission $SharedMailbox -AccessRights SendAs -Trustee $User -Confirm:$False
        Write-Log -Level Warning $RemoveSendAsLog "Successfully Remove Send As Permission - Mailbox : $SharedMailbox - Trustee: $User"
        # Check Send As Permission
        Write-Log -Level Warning $RemoveSendAsLog "Attempt to check Send As Permission - Mailbox : $SharedMailbox - Trustee: $User"
        $SendAsPermissionData = Get-RecipientPermission $SharedMailbox -AccessRights SendAs | where { $_.Trustee -ne "NT AUTHORITY\SELF" } | select Identity, Trustee, AccessRights, AccessControlType
        Write-Log -Level Warning $RemoveSendAsLog "SendAs Permission assign to $SharedMailbox is: "
        $SendAsPermissionData | Out-File $RemoveSendAsLog -Append
        $SendAsPermissionData | ft
    }
    
    Catch
    {
        Write-Log -Level Error $RemoveSendAsLog "Failed to Remove Send As Permission - Mailbox : $SharedMailbox - Trustee: $User"
    }
}

Function Add-EXOMailboxPermissionFullAccess
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$SharedMailbox,
        [Parameter(Mandatory = $true,
                   Position = 2)]
        [String]$User,
        [Parameter(Mandatory = $false,
                   Position = 3)]
        [String]$LogFolder
    )
    $DateFullAccess = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    If ($LogFolder) { Create-Folder $LogFolder }
    Else { $LogFolder = (get-location).path }
    $FolderFullAccessLog = $LogFolder + "\Assign_FullAccess_Permission_" + $SharedMailbox + "_" + $DateFullAccess + ".log"
    
    Try
    {
        #Assign Full Access Permission
        Write-Log -Level Warning $FolderFullAccessLog "Attempt to assign Full Access Permission - Mailbox : $SharedMailbox - User : $User"
        Add-MailboxPermission -Identity $SharedMailbox -User $User -AccessRights FullAccess -InheritanceType All -AutoMapping $false
        Write-Log -Level Warning $FolderFullAccessLog "Successfully Assign Full Access Permission - Mailbox : $SharedMailbox - User: $User"
        # Check Full Access Permission
        Write-Log -Level Warning $FolderFullAccessLog "Attempt to check Full Access Permission - Mailbox : $SharedMailbox - User: $User"
        $FullAccessPermissionData = Get-MailboxPermission $SharedMailbox | where { ($_.AccessRights -like "*FullAccess*") -and ($_.User -notlike "NT *") -and ($_.User -notlike "*Admin*") -and ($_.User -notlike "*Exchange*") -and ($_.User -notlike "*Organization Management") } | select Identity, User, AccessRights, Deny
        Write-Log -Level Warning $FolderFullAccessLog "Full Access Permission assign to $SharedMailbox is: "
        $FullAccessPermissionData | Out-File $FolderFullAccessLog -Append
        $FullAccessPermissionData | ft
    }
    
    Catch
    {
        Write-Log -Level Error $FolderFullAccessLog "Failed to assign Full Access Permission - Mailbox : $SharedMailbox - User: $User"
    }
}

Function Remove-EXOMailboxPermissionFullAccess
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$SharedMailbox,
        [Parameter(Mandatory = $true,
                   Position = 2)]
        [String]$User,
        [Parameter(Mandatory = $false,
                   Position = 3)]
        [String]$LogFolder
    )
    $DateRemoveFullAccess = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    If ($LogFolder) { Create-Folder $LogFolder }
    Else { $LogFolder = (get-location).path }
    $FolderRemoveFullAccessLog = $LogFolder + "\Remove_FullAccess_Permission_" + $SharedMailbox + "_" + $DateRemoveFullAccess + ".log"
    
    Try
    {
        # Remove Full Access Permission
        Write-Log -Level Warning $FolderRemoveFullAccessLog "Remove to assign Full Access Permission - Mailbox : $SharedMailbox - User : $User"
        Remove-MailboxPermission -Identity $SharedMailbox -User $User -AccessRights FullAccess -InheritanceType All -confirm:$False
        Write-Log -Level Warning $FolderRemoveFullAccessLog "Successfully Remove Full Access Permission - Mailbox : $SharedMailbox - User: $User"
        # Check Full Access Permission
        Write-Log -Level Warning $FolderRemoveFullAccessLog "Attempt to check Full Access Permission - Mailbox : $SharedMailbox - User: $User"
        $RemoveFullAccessPermissionData = Get-MailboxPermission $SharedMailbox | where { ($_.AccessRights -like "*FullAccess*") -and ($_.User -notlike "NT *") -and ($_.User -notlike "*Admin*") -and ($_.User -notlike "*Exchange*") -and ($_.User -notlike "*Organization Management") } | select Identity, User, AccessRights, Deny
        Write-Log -Level Warning $FolderRemoveFullAccessLog "Full Access Permission assign to $SharedMailbox is: "
        $RemoveFullAccessPermissionData | Out-File $FolderRemoveFullAccessLog -Append
        $RemoveFullAccessPermissionData | ft
    }
    
    Catch
    {
        Write-Log -Level Error $FolderRemoveFullAccessLog "Failed to assign Full Access Permission - Mailbox : $SharedMailbox - User: $User"
    }
}

Function Add-EXOMailboxPermissionSendOnBehalf
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$SharedMailbox,
        [Parameter(Mandatory = $true,
                   Position = 2)]
        [String]$User,
        [Parameter(Mandatory = $false,
                   Position = 3)]
        [String]$LogFolder
    )
    $DateSendOnBehalf = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    If ($LogFolder) { Create-Folder $LogFolder }
    Else { $LogFolder = (get-location).path }
    $FolderSendOnBehalfLog = $LogFolder + "\Assign_SendOnBehalf_Permission_" + $SharedMailbox + "_" + $DateSendOnBehalf + ".log"
    
    Try
    {
        #Assign Send On Behalf Permission
        Write-Log -Level Warning $FolderSendOnBehalfLog "Attempt to assign Send On Behalf Permission - Mailbox : $SharedMailbox - User : $User"
        Set-Mailbox -Identity $SharedMailbox -GrantSendOnBehalfTo @{ Add = $User }
        Write-Log -Level Warning $FolderSendOnBehalfLog "Successfully Assign Send On Behalf Permission - Mailbox : $SharedMailbox - User: $User"
        # Check Send On Behalf Permission
        Write-Log -Level Warning $FolderSendOnBehalfLog "Attempt to check Send On Behalf Permission - Mailbox : $SharedMailbox - User: $User"
        $SendOnBehalfPermissionData = Get-Mailbox $SharedMailbox | Select -ExpandProperty GrantSendOnBehalfTo
        Write-Log -Level Warning $FolderSendOnBehalfLog "Send On Behalf Permission assign to $SharedMailbox is: "
        $SendOnBehalfPermissionData | Out-File $FolderSendOnBehalfLog -Append
        $SendOnBehalfPermissionData | ft
    }
    
    Catch
    {
        Write-Log -Level Error $FolderSendOnBehalfLog "Failed to assign Full Access Permission - Mailbox : $SharedMailbox - User: $User"
    }
}

Function Remove-EXOMailboxPermissionSendOnBehalf
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$SharedMailbox,
        [Parameter(Mandatory = $true,
                   Position = 2)]
        [String]$User,
        [Parameter(Mandatory = $false,
                   Position = 3)]
        [String]$LogFolder
    )
    $DateRemoveSendOnBehalf = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    If ($LogFolder) { Create-Folder $LogFolder }
    Else { $LogFolder = (get-location).path }
    $FolderRemoveSendOnBehalfLog = $LogFolder + "\Assign_SendOnBehalf_Permission_" + $SharedMailbox + "_" + $DateRemoveSendOnBehalf + ".log"
    
    Try
    {
        #Remove Send On Behalf Permission
        Write-Log -Level Warning $FolderRemoveSendOnBehalfLog "Attempt to Remove Send On Behalf Permission - Mailbox : $SharedMailbox - User : $User"
        Set-Mailbox -Identity $SharedMailbox -GrantSendOnBehalfTo @{ Remove = $User }
        Write-Log -Level Warning $FolderRemoveSendOnBehalfLog "Successfully Remove Send On Behalf Permission - Mailbox : $SharedMailbox - User: $User"
        # Check Send On Behalf Permission
        Write-Log -Level Warning $FolderRemoveSendOnBehalfLog "Attempt to check Send On Behalf Permission - Mailbox : $SharedMailbox - User: $User"
        $SendOnBehalfPermissionData = Get-Mailbox $SharedMailbox | Select -ExpandProperty GrantSendOnBehalfTo
        Write-Log -Level Warning $FolderRemoveSendOnBehalfLog "Send On Behalf Permission assign to $SharedMailbox is: "
        $SendOnBehalfPermissionData | Out-File $FolderRemoveSendOnBehalfLog -Append
        $SendOnBehalfPermissionData | ft
    }
    
    Catch
    {
        Write-Log -Level Error $FolderRemoveSendOnBehalfLog "Failed to Remove Full Access Permission - Mailbox : $SharedMailbox - User: $User"
    }
}

Function Search-EXOMailEnabledPublicFolder
{
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$Search
    )
    
    
    $PublicFolders = Get-PublicFolder -Recurse | where { $_.Identity -like "*$Search*" }
    $Table = $null
    $Table = @()
    ForEach ($PublicFolder in $PublicFolders)
    {
        $Identity = $PublicFolder.Identity
        $MailEnabledPublicFolder = Get-MailPublicFolder $Identity
        $PublicFolderClientPermissions = Get-PublicFolderClientPermission $Identity -User Anonymous
        $AnonymousPermission = $PublicFolderClientPermissions.AccessRights
        $Name = $MailEnabledPublicFolder.Name
        $MailEnabled = $PublicFolder.MailEnabled
        $Alias = $MailEnabledPublicFolder.Alias
        $PrimarySmtpAddress = $MailEnabledPublicFolder.PrimarySmtpAddress
        $EmailAddressPolicyEnabled = $MailEnabledPublicFolder.EmailAddressPolicyEnabled
        $Table += New-object PSobject -Property ([Ordered] @{
                Name                      = $Name;
                Identity                  = $Identity;
                Alias                      = $Alias;
                MailEnabled                  = $MailEnabled;
                PrimarySmtpAddress          = $PrimarySmtpAddress;
                EmailAddressPolicyEnabled = $EmailAddressPolicyEnabled;
                AnonymousPermission          = $AnonymousPermission;
            })
    }
    $Table | ft
}

Function Fix-EXOAutoMappingMailbox
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [string]$SharedMailbox,
        [Parameter(Mandatory = $true,
                   Position = 2)]
        [String]$Delegate
    )
    Write-Host "The Script will remove FullAccess permission - From: " -NoNewline; Write-Host "$SharedMailbox" -NoNewline -ForegroundColor Yellow; Write-Host " - For: " -NoNewline; Write-Host "$Delegate" -ForegroundColor Red
    Remove-MailboxPermission -Identity $SharedMailbox -User $Delegate -AccessRights FullAccess -confirm:$False
    Write-Host "The Script will add the FullAccess permission back - From: " -NoNewline; Write-Host "$SharedMailbox" -NoNewline -ForegroundColor Yellow; Write-Host " - For: " -NoNewline; Write-Host "$Delegate" -ForegroundColor Green
    Add-MailboxPermission -Identity $SharedMailbox -User $Delegate -AccessRights FullAccess -AutoMapping:$false
}

Function Fix-EXORecipientDisplayType
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [string]$Mailbox,
        [Parameter(Mandatory = $true,
                   Position = 2)]
        [String]$DC
    )
    Write-Host "The Script will Check msExchRecipientDisplayType (Before Change) for: " -NoNewline; Write-Host "$Mailbox" -NoNewline -ForegroundColor Yellow;
    $ADUser = Get-ADUser -Filter { UserPrincipalName -eq $Mailbox } -Server $DC -properties *
    $msExchRecipientDisplayType = $ADUser.msExchRecipientDisplayType
    $UPN = $ADUser.UserPrincipalName
    $DisplayName = $ADUser.DisplayName
    $SAM = $ADUser.SamAccountName
    Write-Host "The Script find the following information: "
    Write-Host " --- DisplayName: $DisplayName"
    Write-Host " --- SamAccountName $SAM"
    Write-Host " --- UPN: $UPN"
    Write-Host " --- msExchRecipientDisplayType: " -NowNewline; Write-Host "$msExchRecipientDisplayType" -ForegroundColor Red
    Write-Host "The Script will update msExchRecipientDisplayType for: " -NoNewline; Write-Host "$Mailbox" -ForegroundColor Yellow;
    Get-ADUser -Filter { UserPrincipalName -eq $Mailbox } -Server $DC | Set-AdObject -Replace @{ msExchRecipientDisplayType = -1073741818 } -Server $DC
    Write-Host "The Script will Check msExchRecipientDisplayType (After Change) for: " -NoNewline; Write-Host "$Mailbox" -ForegroundColor Yellow;
    $ADUser1 = Get-ADUser -Filter { UserPrincipalName -eq $Mailbox } -Server $DC -properties *
    $msExchRecipientDisplayType1 = $ADUser1.msExchRecipientDisplayType
    $UPN1 = $ADUser1.UserPrincipalName
    $DisplayName1 = $ADUser1.DisplayName
    $SAM1 = $ADUser1.SamAccountName
    Write-Host "The Script find the following information: "
    Write-Host " --- DisplayName: $DisplayName1"
    Write-Host " --- SamAccountName $SAM1"
    Write-Host " --- UPN: $UPN1"
    Write-Host " --- msExchRecipientDisplayType: " -NowNewline; Write-Host "$msExchRecipientDisplayType1" -ForegroundColor Green
    
}

Function Convert-EXOUserMailboxToSharedMailbox
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [string]$Mailbox,
        [Parameter(Mandatory = $False,
                   Position = 2)]
        [String]$DC
    )
    $Recipient = Get-Recipient $Mailbox -DomainController $DC
    $RecipientTypeDetails = $Null
    $RecipientTypeDetails = $Recipient.RecipientTypeDetails
    If ($RecipientTypeDetails -eq "UserMailbox")
    {
        Write-Host "$Mailbox is a " -NoNewline; Write-Host "$RecipientTypeDetails" -ForegroundColor Red
        Write-Host "The script will convert the mailbox to Shared Mailbox"
        Read-Host "Press Enter to continue or CTRL+C to Cancel"
        Set-Mailbox $Mailbox -Type Shared -DomainController $DC
        $Mailbox = Get-Mailbox $Mailbox -DomainController $DC
        $RecipientTypeDetails1 = $Mailbox.RecipientTypeDetails
        Write-Host "$Mailbox has been converted to: " -NoNewline; Write-Host "$RecipientTypeDetails1" -ForegroundColor Green
    }
    Else
    {
        Write-Host "$Mailbox is a " -NoNewline; Write-Host "$RecipientTypeDetails" -ForegroundColor Red
        Write-Host "The script will not apply any change" -ForegroundColor Yellow
    }
    
}

Function Fix-EXOMissingOnMicrosoft
{
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [string]$UPN,
        [Parameter(Mandatory = $true,
                   Position = 2)]
        [string]$TenantName
        
    )
    
    $Mailbox = Get-Mailbox $UPN -DomainController $DC
    Write-host "Proxy Email Addresses are (Before): "
    $EmailAddresses = $Mailbox | select -ExpandProperty EmailAddresses
    $EmailAddresses | ft | Out-String | Write-Host -ForegroundColor Green
    $Alias = $Mailbox.Alias
    $OnMicrosoftAddress = $Alias + '@' + $TenantName + '.mail.onmicrosoft.com'
    Write-host "will try to add the following Address: $OnMicrosoftAddress"
    Read-host "Pause before change"
    Set-Mailbox $UPN -EmailAddresses @{ add = $OnMicrosoftAddress } -DomainController $DC
    Write-Host "Update User Mailbox $UPN with $OnMicrosoftAddress"
    $Mailbox1 = Get-Mailbox $UPN -DomainController $DC
    Write-host "Proxy Email Addresses are (After): "
    $EmailAddresses1 = $Mailbox1 | select -ExpandProperty EmailAddresses
    $EmailAddresses1 | ft | Out-String | Write-Host -ForegroundColor Yellow
}

Function Enable-EXOMaibloxOOFMessage
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [string]$EmailAddress,
        [Parameter(Mandatory = $true,
                   Position = 2)]
        [String]$Message
    )
    # message Should be in HTML with single quote
    Get-MailboxAutoReplyConfiguration $EmailAddress | fl MailboxOwnerID, AutoReplyState, ExternalMessage, InternalMessage
    Set-MailboxAutoReplyConfiguration -Identity $EmailAddress -AutoReplyState Enabled -InternalMessage $Message -ExternalMessage $Message
    Get-MailboxAutoReplyConfiguration $EmailAddress | fl MailboxOwnerID, AutoReplyState, ExternalMessage, InternalMessage
}

Function Get-EXORecipientStatistics
{
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [string]$Name
    )
    $Recipient = Get-Recipient $Name
    $PrimarySmtpAddress = $Recipient.PrimarySmtpAddress
    Write-host "Primary SMTP address is:$PrimarySmtpAddress"
    Get-MailboxStatistics $PrimarySmtpAddress | ft DisplayName, ItemCount, TotalItemSize
}
Function Check-EXOLastMailboxAccess
{
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [string]$Identity
    )
    Get-MailboxPermission $Identity | where { ($_.User -notlike "*PRD*") -and ($_.User -notlike "NT*") } | ft User, AccessRights
    Get-MailboxStatistics $Identity | fl LastInteractionTime, LastLogonTime, LastUserActionTime
}

Function Add-EXOTransportRuleSubjectOrBodyContainsWords
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$Identity,
        [Parameter(Mandatory = $true,
                   Position = 2)]
        [String]$CSVFile
    )
    
    Read-Host "Expected CSV Column:Name"
    $AddSpecificWordOrPhrases = Import-CSV $CSVFile
    $AddSpecificWordOrPhrasesCount = ($AddSpecificWordOrPhrases | Measure).count
    $TransportRule = Get-TransportRule $Identity
    $SubjectOrBodyContainsWords = $Null
    $SubjectOrBodyContainsWords = @()
    $SubjectOrBodyContainsWords = $TransportRule.SubjectOrBodyContainsWords
    [int]$i = 1
    Foreach ($AddSpecificWordOrPhrase in $AddSpecificWordOrPhrases)
    {
        
        $Name = $Null
        $Name = $AddSpecificWordOrPhrase.Name
        Write-Host "The script will add the following SubjectOrBodyContainsWords: $Name - $i / $AddSpecificWordOrPhrasesCount"
        $SubjectOrBodyContainsWords += $Name
        $i++
    }
    Set-TransportRule $Identity -SubjectOrBodyContainsWords $SubjectOrBodyContainsWords
}

Function Add-EXOTransportRuleSubjectContainsWords
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$Identity,
        [Parameter(Mandatory = $true,
                   Position = 2)]
        [String]$CSVFile
    )
    
    Read-Host "Expected CSV Column: Name"
    $AddSpecificWordOrPhrases = Import-CSV $CSVFile
    $AddSpecificWordOrPhrasesCount = ($AddSpecificWordOrPhrases | Measure).count
    $TransportRule = Get-TransportRule $Identity
    $SubjectContainsWords = $Null
    $SubjectContainsWords = @()
    $SubjectContainsWords = $TransportRule.SubjectContainsWords
    [int]$i = 1
    Foreach ($AddSpecificWordOrPhrase in $AddSpecificWordOrPhrases)
    {
        
        $Name = $Null
        $Name = $AddSpecificWordOrPhrase.Name
        Write-Host "The script will add the following SubjectOrBodyContainsWords: $Name - $i / $AddSpecificWordOrPhrasesCount"
        $SubjectContainsWords += $Name
        $i++
    }
    Set-TransportRule $Identity -SubjectContainsWords $SubjectContainsWords
}

Function Test-EXOSendO365Mail
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$Sender,
        [Parameter(Mandatory = $true,
                   Position = 2)]
        [String]$Recipient
    )
    $DateFull = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    $ServerName = [Environment]::MachineName
    $Subject = "Test Message from :" + $ServerName + " --- " + $DateFull
    $Body = "Hi,`r`n"
    $Body += "This is a test Message at $DateFull`r`n"
    $Body += "Thank you`r`n"
    $Body += "Regards`r`n"
    Send-MailMessage -SmtpServer $Office365MXRecord -Subject $Subject -From $Sender -To $Recipient -Body $Body -UseSsl -Port 25
}

Function Test-EXOSendMail
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$Sender,
        [Parameter(Mandatory = $true,
                   Position = 2)]
        [String]$Recipient,
        [Parameter(Mandatory = $true,
                   Position = 3)]
        [String]$SMTPServer,
        [Parameter(Position = 4)]
        [switch]$UseSSL
    )
    
    $DateFull = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    $Subject = "Test Message from :$Sender - To: $Recipient - Server(From): $SMTPServer --- $DateFull"
    $Body = "Hi,`r`n"
    $Body += "This is a test Message at $DateFull`r`n"
    $Body += "Thank you`r`n"
    $Body += "Regards`r`n"
    If ($UseSSL)
    {
        Send-MailMessage -SmtpServer $SMTPServer -Subject $Subject -From $Sender -To $Recipient -Body $Body -UseSsl -port 25
    }
    else
    {
        Send-MailMessage -SmtpServer $SMTPServer -Subject $Subject -From $Sender -To $Recipient -Body $Body -Port 25
    }
    
}


Function Allow-EXOQuarantineMobileDevices
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [string]$Mailbox
    )
    
    # Check mobile quarantine status:
    Get-MobileDevice -Mailbox $Mailbox | ft FriendlyName, DeviceOS, DeviceUserAgent, DeviceAccessState, DeviceId, Identity
    
    # Search for quarantine Device
    $MobileDevice = Get-MobileDevice -Mailbox $Mailbox -Filter { DeviceAccessState -eq 'Quarantined' }
    
    # Retreive the list of Allows Devices
    $CASMailbox = Get-CasMailbox $Mailbox
    $AllowedDeviceIDs = $CASMailbox.ActiveSyncAllowedDeviceIDs
    
    # Allow the device
    $AllowedDevicesToAdd = $MobileDevice.DeviceId
    If (!($AllowedDevicesToAdd)) { $AllowedDeviceIDs }
    Else { $AllowedDeviceIDs += $AllowedDevicesToAdd }
    
    Set-CASMailbox -Identity $Mailbox -ActiveSyncAllowedDeviceIDs $AllowedDeviceIDs
    
    # Check mobile quarantine status:
    Get-MobileDevice -Mailbox $Mailbox | ft FriendlyName, DeviceOS, DeviceUserAgent, DeviceAccessState, DeviceId, Identity
    
}

Function Allow-EXOQuarantineIphone
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [string]$Mailbox
    )
    
    # Check mobile quarantine status:
    Get-MobileDevice -Mailbox $Mailbox | ft FriendlyName, DeviceOS, DeviceUserAgent, DeviceAccessState, DeviceId, Identity
    
    # Search for quarantine Device
    $MobileDevice = Get-MobileDevice -Mailbox $Mailbox -Filter "DeviceType -eq 'iPhone' -and DeviceAccessState -eq 'Quarantined'"
    
    # Retreive the list of Allows Devices
    $CASMailbox = Get-CasMailbox $Mailbox
    $AllowedDeviceIDs = $CASMailbox.ActiveSyncAllowedDeviceIDs
    
    # Allow the device
    $AllowedDevicesToAdd = $MobileDevice.DeviceId
    If (!($AllowedDevicesToAdd)) { $AllowedDeviceIDs }
    Else { $AllowedDeviceIDs += $AllowedDevicesToAdd }
    
    Set-CASMailbox -Identity $Mailbox -ActiveSyncAllowedDeviceIDs $AllowedDeviceIDs
    
    # Check mobile quarantine status:
    Get-MobileDevice -Mailbox $Mailbox | ft FriendlyName, DeviceOS, DeviceUserAgent, DeviceAccessState, DeviceId, Identity
    
}

Function Show-EXOQuarantineIphones
{
    [CmdletBinding()]
    param ()
    Get-MobileDevice -Filter "DeviceType -eq 'iPhone' -and DeviceAccessState -eq 'Quarantined'" | ft FriendlyName, DeviceOS, DeviceUserAgent, DeviceAccessState, DeviceId, Identity
}

Function Show-EXOQuarantineDevices
{
    [CmdletBinding()]
    param ()
    Get-MobileDevice -Filter "DeviceAccessState -eq 'Quarantined'" | ft FriendlyName, DeviceOS, DeviceUserAgent, DeviceAccessState, DeviceId, Identity
}

Function Block-EXOMobileDevice
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$Mailbox
    )
    
    # Check mobiles Device for $Mailbox
    $MobilesDevices = $Null
    $MobilesDevices = @()
    $MobilesDevices = Get-MobileDevice -Mailbox $Mailbox | Select FriendlyName, DeviceOS, DeviceUserAgent, DeviceAccessState, DeviceId, Identity
    $MobilesDevices | ft
    [Int]$Number = Read-Host "Select the device you want to block, using 1 for first line and 2 for second line and so on"
    Try
    {
        [int]$i = $Number - 1
        $MobileDeviceIdentity = $null
        $MobileDeviceIdentity = $MobilesDevices.Identity[$i]
        $MobileDeviceUserAgent = $null
        $MobileDeviceUserAgent = $MobilesDevices.DeviceUserAgent[$i]
        Write-Host "[$(Get-Date -Format "yyyy-MM-dd HH:mm:ss")]" -nonewline; Write-host " WARNING: " -ForegroundColor Yellow -NoNewline; Write-Host "Blocking the Device with the following Identity:" -NoNewline; Write-Host "$MobileDeviceUserAgent - $MobileDeviceIdentity" -ForegroundColor Yellow
        Read-Host "Press Enter to continue"
    }
    Catch
    {
        $ErrorMessage = $Error[0].Exception.Message
        $CMDLet = $Error[0].InvocationInfo.Line
        Write-Host "The script failed to block the mobile device with Identity $MobileDeviceIdentity"
        Write-Host "Failed to run the following CMDLet: $CMDLet"
        Write-host "Failed with Error:$ErrorMessage"
        Exit
    }
    
    # Retreive the list of Allows Devices
    $CASMailbox = Get-CasMailbox $Mailbox
    $BlockedDeviceIDs = $Null
    $BlockedDeviceIDs = @()
    $BlockedDeviceIDs = $CASMailbox.ActiveSyncBlockedDeviceIDs
    $BlockedDeviceIDs | ft
    # Allow the device
    If (!($MobileDeviceIdentity))
    { $BlockedDeviceIDs }
    Else { $BlockedDeviceIDs += $MobileDeviceIdentity }
    $BlockedDeviceIDs | ft
    Set-CASMailbox -Identity $Mailbox -ActiveSyncBlockedDeviceIDs $BlockedDeviceIDs
    # Check mobile quarantine status:
    Get-MobileDevice -Mailbox $Mailbox | ft FriendlyName, DeviceOS, DeviceUserAgent, DeviceAccessState, DeviceId, Identity
}

Function Clear-EXOCASMobileDevicesList
{
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$Mailbox,
        [Parameter(Mandatory = $False,
                   Position = 2)]
        [Switch]$Allowed,
        [Parameter(Mandatory = $False,
                   Position = 3)]
        [Switch]$Blocked
    )
    
    If ($Allowed)
    {
        Set-CASMailbox $Mailbox -ActiveSyncAllowedDeviceIDs $Null
        Write-Host "The ActiveSyncAllowedDeviceID list was cleared"
    }
    If ($Blocked)
    {
        Set-CASMailbox $Mailbox -ActiveSyncBlockedDeviceIDs $Null
        Write-Host "The ActiveSyncBlockedDeviceID list was cleared"
    }
}

Function Check-EXOMobileDevices
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [string]$Mailbox
    )
    
    Get-MobileDevice -Mailbox $Mailbox | ft FriendlyName, DeviceOS, DeviceUserAgent, DeviceAccessState, DeviceId, Identity
}

Function Check-EXOMobileDeviceByState
{
    [CmdletBinding()]
    param
    (
        [switch]$Quarantined,
        [switch]$Allowed,
        [switch]$Blocked
    )
    
    If ($Quarantined)
    {
        Get-MobileDevice -Filter { DeviceAccessState -eq "quarantined" } | ft UserDisplayName, Deviceid, DeviceOS, DeviceType, DeviceModel, FriendlyName, DeviceAccessState, DeviceAccessStateReason
    }
    If ($Allowed)
    {
        Get-MobileDevice -Filter { DeviceAccessState -eq "Allowed" } | ft UserDisplayName, Deviceid, DeviceOS, DeviceType, DeviceModel, FriendlyName, DeviceAccessState, DeviceAccessStateReason
    }
    If ($Blocked)
    {
        Get-MobileDevice -Filter { DeviceAccessState -eq "Blocked" } | ft UserDisplayName, Deviceid, DeviceOS, DeviceType, DeviceModel, FriendlyName, DeviceAccessState, DeviceAccessStateReason
    }
}

Function Release-EXOMyQuarantineMessageDomain
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [string]$Domain
    )
    $DomainFilter = "*@" + $Domain
    $QuarantineMessagesFound = Get-QuarantineMessage | ? { $_.Senderaddress -like $DomainFilter }
    Write-Host "Script Found the following messages in quarantine with the following domain :$Domain"
    $QuarantineMessagesFound | ft SenderAddress, RecipientAddress, Subject, ReceivedTime, Direction, Type, PolicyName, ReleaseStatus, RecipientCount, Expires
    Read-Host 'Please Press <Enter> to release all messages or <CTRL+C to Cancel>'
    $QuarantineMessagesFound | Release-QuarantineMessage -ReleaseToAll
}

Function Generate-EXOSafeLinkReport
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$UrlOrDomain
    )
    $DateFull = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    $StartDate = (Get-Date).AddDays(-7)
    $EndDate = Get-Date
    $ReportURLTrace = Get-UrlTrace -UrlOrDomain $UrlOrDomain -StartDate $StartDate -EndDate $EndDate
    $Location = (Get-Location).path
    $ReportCSVFile = $Location + "\Report_URLTrace_" + $DateFull + ".csv"
    $ReportURLTrace | Export-Csv $ReportCSVFile -NoTypeInformation -Encoding UTF8
    Write-Host "The Script has Generate the following Report:" -NoNewline; Write-Host "$ReportCSVFile" -ForegroundColor Green
    
}

Function Generate-EXOAllSafeLinkReport
{
    $DateFull = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    $StartDate = (Get-Date).AddDays(-7)
    $EndDate = Get-Date
    $ReportURLTrace = Get-UrlTrace -StartDate $StartDate -EndDate $EndDate
    $Location = (Get-Location).path
    $ReportCSVFile = $Location + "\Report_AllURLTrace_" + $DateFull + ".csv"
    $ReportURLTrace | Export-Csv $ReportCSVFile -NoTypeInformation -Encoding UTF8
    Write-Host "The Script has Generate the following Report:" -NoNewline; Write-Host "$ReportCSVFile" -ForegroundColor Green
    
}

Function Search-EXOMessageBySubject
{
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$Subject
    )
    # $Subject = "RE: Reporte de Reprocesos de Teñido Mayan Agosto Semana 3"
    $Now = (Get-Date)
    $Yesterday = (Get-Date).AddDays(-1)
    $MessagesFound = $Null
    $MessagesFound = @()
    [Int]$i = 1
    [Int]$MessageCount = 1
    Do
    {
        $AllMessages = Get-MessageTrace -EndDate $Now -StartDate $Yesterday -PageSize 5000 -Page $i
        $MessageCount = ($AllMessages | Measure).count
        $MessagesFound += $AllMessages | where { $_.Subject -eq $Subject }
        $i++
    }
    While ($MessageCount -ne 0)
    $MessagesFound | Out-GridView
}


Function Display-EXORecoverableItems
{
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [string]$Mailbox
    )
    $RecoverableItems = $Null
    $RecoverableItems = Get-RecoverableItems -Identity $Mailbox -Resultsize unlimited | select LastParentPath, ItemClass, Subject, SourceFolder, LastModifiedTime
    Write-Host "using Get-RecoverableItems CMDLet: " -ForegroundColor Yellow
    $RecoverableItems | Group SourceFolder | ft Count, name
    
    Write-Host "Using Mailbox Statistics CMDLet:" -ForegroundColor Yellow
    $RecoverableItemsMailboxStatistics = $Null
    $RecoverableItemsMailboxStatistics = Get-MailboxFolderStatistics -Identity $Mailbox -FolderScope recoverableItems | Select Identity, ItemsInFolderAndSubfolders, FolderAndSubfolderSize
    $RecoverableItemsMailboxStatistics | Ft
}

Function Find-EXODeletedItems
{
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [string]$Mailbox
    )
    $RecoverableItems = $Null
    $RecoverableItems = Get-RecoverableItems -Identity $Mailbox | select LastParentPath, ItemClass, Subject, SourceFolder, LastModifiedTime
    $RecoverableItems | Group SourceFolder | ft Count, name
    $DateFull = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    $Location = (Get-Location).path
    $CSVFile = $Location + "\Report_" + $Mailbox + "_" + $DateFull + ".csv"
    $RecoverableItems | Export-Csv $CSVFile -NoTypeInformation -Encoding UTF8
    Write-Host "The Script has Generate the following Report:" -NoNewline; Write-Host "$CSVFile" -ForegroundColor Green
}

Function Find-EXODeletedItemsTime
{
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [string]$Mailbox,
        [Parameter(Mandatory = $true,
                   Position = 2)]
        [string]$StartTime,
        [Parameter(Mandatory = $true,
                   Position = 3)]
        [string]$EndTime
    )
    $RecoverableItems = $Null
    $RecoverableItems = Get-RecoverableItems -Identity $Mailbox -FilterStartTime $StartTime -FilterEndTime $EndTime
    $RecoverableItems | ft LastParentPath, ItemClass, Subject, SourceFolder, LastModifiedTime
    $DateFull = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    $Location = (Get-Location).path
    $CSVFile = $Location + "\Report_" + $Mailbox + "_" + $DateFull + ".csv"
    $RecoverableItems | Export-Csv $CSVFile -NoTypeInformation -Encoding UTF8
    Write-Host "The Script has Generate the following Report:" -NoNewline; Write-Host "$CSVFile" -ForegroundColor Green
}

Function Recover-EXORecoverableItems
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [string]$PrimarySMTPAddress,
        [Parameter(Mandatory = $true,
                   Position = 2)]
        [String]$AdminUserName
    )
    
    Connect-MyEXO -AlternateID $AdminUserName
    $Items = $Null
    $Items = Get-RecoverableItems $PrimarySMTPAddress -ResultSize 500 -SourceFolder PurgedItems
    $ItemsCount = $Null
    $ItemsCount = ($Items | measure).count
    Write-Host "The script found for $PrimarySMTPAddress : $itemsCount Items to recover from Purges Folders" -ForegroundColor Red
    while ($ItemsCount -ge 1)
    {
        Write-Host "The function found: $ItemsCount for $PrimarySMTPAddress"
        $DateFull = Get-Date -Format "ddMMyyyy_HH-mm-ss"
        $LocalPart = $PrimarySMTPAddress.Substring(0, $PrimarySMTPAddress.LastIndexOf("@"))
        if (!$LocalPart)
        { $LocalPart = $PrimarySMTPAddress }
        $500PurgedItems_XMLFile = $LocalPart + "_500_PurgedItems_" + $DateFull + ".xml"
        $Items | Export-Clixml $500PurgedItems_XMLFile
        $Items | -RecoverableItems
        $Items = $Null
        Connect-MyEXO -AlternateID $AdminUserName
        $Items = Get-RecoverableItems $PrimarySMTPAddress -ResultSize 500 -SourceFolder PurgedItems
        $ItemsCount = $Null
        $ItemsCount = ($Items | measure).count
    }
    
}

Function Restore-EXOInactiveMailbox
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$InactiveMailboxPrimaryAddress,
        [Parameter(Mandatory = $true,
                   Position = 2)]
        [String]$TargetMailbox,
        [Parameter(Position = 3)]
        [String]$TargetRootFolderName
    )
    Try
    {
        #Retreive Active mailbox Data
        $ActiveMailbox = Get-Mailbox -Identity $TargetMailbox
        $ActiveMailboxExchangeGUID = $ActiveMailbox.ExchangeGuid
        $ActiveMailboxGUID = $ActiveMailbox.Guid
        $ActiveMailboxDistinguishedName = $ActiveMailbox.DistinguishedName
        #Retreive Inactive mailbox Data
        $InactiveMailbox = Get-Mailbox -InactiveMailboxOnly -Identity $InactiveMailboxPrimaryAddress
        $Identity = $InactiveMailbox.Identity
        $PrimarySMTPAddress = $InactiveMailbox.PrimarySMTPAddress
        $ExchangeGuid = $InactiveMailbox.ExchangeGuid
        $Guid = $InactiveMailbox.Guid
        $DistinguishedName = $InactiveMailbox.DistinguishedName
        $LegacyExchangeDN = $InactiveMailbox.LegacyExchangeDN
        $AccountDisabled = $InactiveMailbox.AccountDisabled
        $WhenSoftDeleted = $InactiveMailbox.WhenSoftDeleted
        $WhenMailboxCreated = $InactiveMailbox.WhenMailboxCreated
        $LitigationHoldDate = $InactiveMailbox.LitigationHoldDate
        Write-Log -Level Warning -Message "The inactive mailbox was found"
        Write-Log -Level INFO -Message "--- Identity: $Identity"
        Write-Log -Level INFO -Message "--- PrimarySMTPAddress: $PrimarySMTPAddress"
        Write-Log -Level INFO -Message "--- Guid: $ExchangeGuid"
        Write-Log -Level INFO -Message "--- Guid: $Guid"
        Write-Log -Level INFO -Message "--- DistinguishedName: $DistinguishedName"
        Write-Log -Level INFO -Message "--- LegacyExchangeDN: $LegacyExchangeDN"
        Write-Log -Level INFO -Message "--- AccountDisabled: $AccountDisabled"
        Write-Log -Level INFO -Message "--- WhenSoftDeleted: $WhenSoftDeleted"
        Write-Log -Level INFO -Message "--- WhenMailboxCreated: $WhenMailboxCreated"
        Write-Log -Level INFO -Message "--- LitigationHoldDate: $LitigationHoldDate"
        
        # Set-Mailbox $ActiveMailboxDistinguishedName -EmailAddresses @{Add="X500:$LegacyExchangeDN"}
    }
    Catch
    {
        $ErrorMessage = $Error[0].Exception.Message
        $CMDLet = $Error[0].InvocationInfo.Line
        $FailedItem = $Error[0].Exception.ItemName
        Write-Log -Level Error -Message "Failed to retreive inactive mailbox:$InactiveMailboxPrimaryAddress"
        Write-Log -Level Error -Message "Failed to run the following CMDLet: $CMDLet"
        Write-Log -Level Error -Message "Failed with Error:$ErrorMessage"
        Exit
    }
    $DateFull = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    If ($DistinguishedName)
    { $SourceMailbox = $DistinguishedName }
    Else
    { $SourceMailbox = $Guid }
    If ($ActiveMailboxDistinguishedName)
    {
        $LocalPart = $TargetMailbox.Substring(0, $TargetMailbox.LastIndexOf("@"))
        If ($TargetRootFolderName)
        {
            #Restore the inactive mailbox content to TargetFolder
            $MailboxRestoreRequestName = "Restore Inactive Mailbox - " + $LocalPart + "_" + $DateFull
            Read-Host "Are sure you want to restore the content of inactive mailbox $InactiveMailboxPrimaryAddress into $TargetMailbox (Folder: $TargetRootFolderName)? Press <Enter> to contine or <CTRL+C> to Cancel"
            $New_MailboxRestoreRequest = New-MailboxRestoreRequest -SourceMailbox $SourceMailbox -TargetMailbox $ActiveMailboxDistinguishedName -TargetRootFolder $TargetRootFolderName -AllowLegacyDNMismatch -Name $MailboxRestoreRequestName
            $RequestGuid = $New_MailboxRestoreRequest.RequestGuid
        }
        Else
        {
            #Restore inactive mailbox to existing mailbox
            $MailboxRestoreRequestName = "Merge Inactive Mailbox - " + $LocalPart + "_" + $DateFull
            Read-Host "Are sure you want to restore (Merge) the content of inactive mailbox $InactiveMailboxPrimaryAddress into $TargetMailbox? Press <Enter> to contine or <CTRL+C> to Cancel"
            $New_MailboxRestoreRequest = New-MailboxRestoreRequest -SourceMailbox $SourceMailbox -TargetMailbox $ActiveMailboxDistinguishedName -AllowLegacyDNMismatch -Name $MailboxRestoreRequestName
            $RequestGuid = $New_MailboxRestoreRequest.RequestGuid
        }
        sleep 10
        Get-MailboxRestoreRequest -Name $MailboxRestoreRequestName
        Write-Log -Level Warning -Message "Please find the Command to check the status: Get-MailboxRestoreRequest -Name $MailboxRestoreRequestName"
        Write-Log -Level Warning -Message "Please find the Command to check the status: Get-MailboxRestoreRequestStatistics -identity $RequestGuid | fl Name,StatusDetail,PercentComplete,BytesTransferred,SyncedItemCount,EstimatedTransferSize"
    }
    Else
    {
        Write-Log -Level Error -Message "Failed to retreive Active mailbox ($TargetMailbox) GUID"
    }
}
Function Restore-EXOInactiveOnlineArchiveMailbox
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$InactiveMailboxPrimaryAddress,
        [Parameter(Mandatory = $true,
                   Position = 2)]
        [String]$TargetMailbox,
        [Parameter(Mandatory = $true,
                   Position = 3)]
        [String]$TargetRootFolderName
    )
    Try
    {
        #Retreive Active mailbox Data
        $ActiveMailbox = Get-Mailbox -Identity $TargetMailbox
        $ActiveMailboxExchangeGUID = $ActiveMailbox.ExchangeGuid
        $ActiveMailboxGUID = $ActiveMailbox.Guid
        $ActiveMailboxDistinguishedName = $ActiveMailbox.DistinguishedName
        #Retreive Inactive mailbox Data
        $InactiveMailbox = Get-Mailbox -InactiveMailboxOnly -Identity $InactiveMailboxPrimaryAddress
        $Identity = $InactiveMailbox.Identity
        $PrimarySMTPAddress = $InactiveMailbox.PrimarySMTPAddress
        $ExchangeGuid = $InactiveMailbox.ExchangeGuid
        $Guid = $InactiveMailbox.Guid
        $DistinguishedName = $InactiveMailbox.DistinguishedName
        $LegacyExchangeDN = $InactiveMailbox.LegacyExchangeDN
        $AccountDisabled = $InactiveMailbox.AccountDisabled
        $WhenSoftDeleted = $InactiveMailbox.WhenSoftDeleted
        $WhenMailboxCreated = $InactiveMailbox.WhenMailboxCreated
        $LitigationHoldDate = $InactiveMailbox.LitigationHoldDate
        Write-Log -Level Warning -Message "The inactive mailbox was found"
        Write-Log -Level INFO -Message "--- Identity: $Identity"
        Write-Log -Level INFO -Message "--- PrimarySMTPAddress: $PrimarySMTPAddress"
        Write-Log -Level INFO -Message "--- Guid: $ExchangeGuid"
        Write-Log -Level INFO -Message "--- Guid: $Guid"
        Write-Log -Level INFO -Message "--- DistinguishedName: $DistinguishedName"
        Write-Log -Level INFO -Message "--- LegacyExchangeDN: $LegacyExchangeDN"
        Write-Log -Level INFO -Message "--- AccountDisabled: $AccountDisabled"
        Write-Log -Level INFO -Message "--- WhenSoftDeleted: $WhenSoftDeleted"
        Write-Log -Level INFO -Message "--- WhenMailboxCreated: $WhenMailboxCreated"
        Write-Log -Level INFO -Message "--- LitigationHoldDate: $LitigationHoldDate"
        
        # Set-Mailbox $ActiveMailboxDistinguishedName -EmailAddresses @{Add="X500:$LegacyExchangeDN"}
    }
    Catch
    {
        $ErrorMessage = $Error[0].Exception.Message
        $CMDLet = $Error[0].InvocationInfo.Line
        $FailedItem = $Error[0].Exception.ItemName
        Write-Log -Level Error -Message "Failed to retreive inactive mailbox:$InactiveMailboxPrimaryAddress"
        Write-Log -Level Error -Message "Failed to run the following CMDLet: $CMDLet"
        Write-Log -Level Error -Message "Failed with Error:$ErrorMessage"
        Exit
    }
    $DateFull = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    If ($DistinguishedName)
    { $SourceMailbox = $DistinguishedName }
    Else
    { $SourceMailbox = $Guid }
    If ($ActiveMailboxDistinguishedName)
    {
        $LocalPart = $TargetMailbox.Substring(0, $TargetMailbox.LastIndexOf("@"))
        
        #Restore the inactive mailbox content to TargetFolder
        $MailboxRestoreRequestName = "Restore Inactive Online Archive Mailbox - " + $LocalPart + "_" + $DateFull
        Read-Host "Are sure you want to restore the content of inactive mailbox $InactiveMailboxPrimaryAddress into $TargetMailbox (Folder: $TargetRootFolderName)? Press <Enter> to contine or <CTRL+C> to Cancel"
        $New_MailboxRestoreRequest = New-MailboxRestoreRequest -SourceMailbox $SourceMailbox -TargetMailbox $ActiveMailboxDistinguishedName -TargetRootFolder $TargetRootFolderName -AllowLegacyDNMismatch -Name $MailboxRestoreRequestName -SourceIsArchive -TargetIsArchive
        $RequestGuid = $New_MailboxRestoreRequest.RequestGuid
        sleep 10
        Get-MailboxRestoreRequest -Name $MailboxRestoreRequestName
        Write-Log -Level Warning -Message "Please find the Command to check the status: Get-MailboxRestoreRequest -Name $MailboxRestoreRequestName"
        Write-Log -Level Warning -Message "Please find the Command to check the status: Get-MailboxRestoreRequestStatistics -identity $RequestGuid | fl Name,StatusDetail,PercentComplete,BytesTransferred,SyncedItemCount,EstimatedTransferSize"
    }
    Else
    {
        Write-Log -Level Error -Message "Failed to retreive Active mailbox ($TargetMailbox) GUID"
    }
}
Function Restore-EXOSoftDeletedMailbox
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$SoftDeletedMailboxPrimaryAddress,
        [Parameter(Mandatory = $true,
                   Position = 2)]
        [String]$TargetMailbox,
        [Parameter(Position = 3)]
        [String]$TargetRootFolderName
    )
    Try
    {
        #Retreive Active mailbox Data
        $ActiveMailbox = Get-Mailbox -Identity $TargetMailbox
        $ActiveMailboxExchangeGUID = $ActiveMailbox.ExchangeGuid
        $ActiveMailboxGUID = $ActiveMailbox.Guid
        $ActiveMailboxDistinguishedName = $ActiveMailbox.DistinguishedName
        
        #Retreive Inactive mailbox Data
        $SoftDeletedMailbox = Get-Mailbox -SoftDeletedMailbox -Identity $SoftDeletedMailboxPrimaryAddress
        $Identity = $SoftDeletedMailbox.Identity
        $PrimarySMTPAddress = $SoftDeletedMailbox.PrimarySMTPAddress
        $ExchangeGuid = $SoftDeletedMailbox.ExchangeGuid
        $Guid = $SoftDeletedMailbox.Guid
        $DistinguishedName = $SoftDeletedMailbox.DistinguishedName
        $AccountDisabled = $SoftDeletedMailbox.AccountDisabled
        $WhenSoftDeleted = $SoftDeletedMailbox.WhenSoftDeleted
        $WhenMailboxCreated = $SoftDeletedMailbox.WhenMailboxCreated
        $LitigationHoldDate = $SoftDeletedMailbox.LitigationHoldDate
        Write-Log -Level Warning -Message "The inactive mailbox was found"
        Write-Log -Level INFO -Message "--- Identity: $Identity"
        Write-Log -Level INFO -Message "--- PrimarySMTPAddress: $PrimarySMTPAddress"
        Write-Log -Level INFO -Message "--- Guid: $ExchangeGuid"
        Write-Log -Level INFO -Message "--- Guid: $Guid"
        Write-Log -Level INFO -Message "--- DistinguishedName: $DistinguishedName"
        Write-Log -Level INFO -Message "--- AccountDisabled: $AccountDisabled"
        Write-Log -Level INFO -Message "--- WhenSoftDeleted: $WhenSoftDeleted"
        Write-Log -Level INFO -Message "--- WhenMailboxCreated: $WhenMailboxCreated"
        Write-Log -Level INFO -Message "--- LitigationHoldDate: $LitigationHoldDate"
    }
    Catch
    {
        $ErrorMessage = $Error[0].Exception.Message
        $CMDLet = $Error[0].InvocationInfo.Line
        $FailedItem = $Error[0].Exception.ItemName
        Write-Log -Level Error -Message "Failed to retreive inactive mailbox:$SoftDeletedMailboxPrimaryAddress"
        Write-Log -Level Error -Message "Failed to run the following CMDLet: $CMDLet"
        Write-Log -Level Error -Message "Failed with Error:$ErrorMessage"
        Exit
    }
    
    If ($DistinguishedName)
    { $SourceMailbox = $DistinguishedName }
    Else
    { $SourceMailbox = $Guid }
    $DateFull = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    If ($ActiveMailboxDistinguishedName)
    {
        $LocalPart = $SoftDeletedMailboxPrimaryAddress.Substring(0, $SoftDeletedMailboxPrimaryAddress.LastIndexOf("@"))
        If ($TargetRootFolderName)
        {
            #Restore the inactive mailbox content to TargetFolder
            $MailboxRestoreRequestName = "Restore Soft Deleted Mailbox - " + $LocalPart + "_" + $DateFull
            Read-Host "Are sure you want to restore the content of Soft Deleted mailbox $SoftDeletedMailboxPrimaryAddress into $TargetMailbox (Folder: $TargetRootFolderName)? Press <Enter> to contine or <CTRL+C> to Cancel"
            New-MailboxRestoreRequest -SourceMailbox $SourceMailbox -TargetMailbox $ActiveMailboxDistinguishedName -TargetRootFolder $TargetRootFolderName -AllowLegacyDNMismatch -Name $MailboxRestoreRequestName
        }
        Else
        {
            #Restore inactive mailbox to existing mailbox
            
            $MailboxRestoreRequestName = "Merge Soft Deleted Mailbox - " + $LocalPart + "_" + $DateFull
            Read-Host "Are sure you want to restore (Merge) the content of Soft Deleted mailbox $SoftDeletedMailboxPrimaryAddress into $TargetMailbox? Press <Enter> to contine or <CTRL+C> to Cancel"
            New-MailboxRestoreRequest -SourceMailbox $SourceMailbox -TargetMailbox $ActiveMailboxDistinguishedName -AllowLegacyDNMismatch -Name $MailboxRestoreRequestName
        }
        sleep 10
        Get-MailboxRestoreRequest -Name $MailboxRestoreRequestName
    }
    Else
    {
        Write-Log -Level Error -Message "Failed to retreive Active mailbox ($TargetMailbox) GUID"
    }
}
Function Recover-EXOInactiveMailbox
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$EmailAddress
    )
    
    # Retreive User Information
    $InactiveMailbox = Get-Mailbox $EmailAddress -IncludeInactiveMailbox | sort -Descending WhenSoftDeleted | Select -first 1
    $OnMicrosoft = $InactiveMailbox.EmailAddresses | where { ($_ -like "*.onmicrosoft.com") -and ($_ -notlike "*mail.onmicrosoft.com") } | select -First 1
    Write-Log -Level Warning -Message "The script found the following onMicrosoft: $OnMicrosoft"
    $MicrosoftOnlineServicesID = $OnMicrosoft.Substring(5)
    Read-Host "Are you sure you want to recovery the Inactive mailbox with the following $MicrosoftOnlineServicesID - Press Enter to Continue or Ctrl+C to Cancel"
    New-Mailbox -InactiveMailbox $InactiveMailbox.DistinguishedName -Name $InactiveMailbox.Name -DisplayName $InactiveMailbox.DisplayName -MicrosoftOnlineServicesID $MicrosoftOnlineServicesID -Password (ConvertTo-SecureString -String '!!P@ssw0rd##' -AsPlainText -Force) -ResetPasswordOnNextLogon $true
    sleep 5
    Write-Log -Level Warning -Message "The script recover the mailbox to $MicrosoftOnlineServicesID"
    sleep 5
    Write-Log -Level INFO -Message "waiting for the Mailbox creation to complete"
    sleep 5
    Write-Log -Level Warning -Message "The script is search for $MicrosoftOnlineServicesID"
    Get-mailbox $MicrosoftOnlineServicesID
    Write-Log -Level Warning -Message "Assign location + License"
    
}
Function Add-EXOX500EmailAddress
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$EmailAddress
    )
    
    # Display Current Email Addresses of the mailbox
    $Mailbox = $Null
    $Mailbox = Get-Mailbox $EmailAddress
    $EmailAddresses = $Null
    $EmailAddresses = $Mailbox.emailaddresses
    $DisplayName = $Null
    $DisplayName = $Mailbox.DisplayName
    $LegacyExchangeDN = $Null
    $LegacyExchangeDN = $Mailbox.LegacyExchangeDN
    $X500 = 'X500:' + $LegacyExchangeDN
    Write-Log -Level INFO -message "The mailbox ($DisplayName) Email Addresses are:"
    $EmailAddresses | ft
    Write-Log -Level INFO -message "The mailbox ($DisplayName) LegacyExchangeDN is: $LegacyExchangeDN"
    Write-Log -Level INFO -message "The mailbox ($DisplayName) Calculated X500 is: $X500"
    # Add the X500 Email address
    Read-Host "Pause"
    Set-Mailbox -Identity $EmailAddress -EmailAddresses @{ Add = $X500 }
    
    # Review
    $Mailbox2 = Get-Mailbox $EmailAddress
    $EmailAddresses2 = $Null
    $EmailAddresses2 = $Mailbox2.emailaddresses
    Write-Log -Level INFO -message "The mailbox ($DisplayName) Email Addresses (After adding X500) are:"
    $EmailAddresses2 | ft
}

Function Check-EXOPhishingComplianceSearchActionToday
{
    $DateFilter = Get-Date -Format "ddMMyyyy"
    $Filter = "*_PhishingMessage_Investigation_" + $DateFilter + "*"
    Get-ComplianceSearchAction | Where { $_.Name -like $Filter } | sort Name | ft
}

Function Check-EXOPhishingComplianceSearchActionDate
{
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [datetime]$Date
    )
    
    $DateFilter = Get-Date $Date -Format "ddMMyyyy"
    $Filter = "*_PhishingMessage_Investigation_" + $DateFilter + "*"
    Get-ComplianceSearchAction | Where { $_.Name -like $Filter } | sort Name | ft
}

Function Check-EXOPhishingComplianceSearchToday
{
    $DateFilter = Get-Date -Format "ddMMyyyy"
    $Filter = "*_PhishingMessage_Investigation_" + $DateFilter + "*"
    Get-ComplianceSearch | Where { $_.Name -like $Filter } | sort Name | ft
}

Function Check-EXOPhishingComplianceSearchDate
{
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [datetime]$Date
    )
    
    $DateFilter = Get-Date $Date -Format "ddMMyyyy"
    $Filter = "*_PhishingMessage_Investigation_" + $DateFilter + "*"
    Get-ComplianceSearch | Where { $_.Name -like $Filter } | sort Name | ft
}

Function Check-EXOPhishingContentSearch
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$ContentSearchName
    )
    
    Get-ComplianceSearch -Identity $ContentSearchName | ft Name, Runby, JobEndTime, Status, Items
    
    Try
    {
        # Search for Compliance Search Action Purge
        $ComplianceSearchActionName = $ContentSearchName + "_Purge"
        $ComplianceAction = Get-ComplianceSearchAction $ComplianceSearchActionName -ErrorAction Stop | fl Name, SearchName, Action, Status, ExchangeLocation, RunBy, CreateBy
    }
    Catch [System.Management.Automation.RemoteException]
    {
        Write-Log -Level Warning -message "No compliance Search action was created to purge"
    }
    Catch
    {
        $ErrorMessage = $Error[0].Exception.Message
        $CMDLet = $Error[0].InvocationInfo.Line
        $FailedItem = $Error[0].Exception.ItemName
        Write-Log -Level Error -Message "Failed to Check Status of Compliance Search "
        Write-Log -Level Error -Message "Failed to run the following CMDLet: $CMDLet"
        Write-Log -Level Error -Message "Failed with Error:$ErrorMessage"
    }
    
    
}

Function New-EXOPhishingContentSearch
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [string]$Sender,
        [Parameter(Position = 2)]
        [String]$Subject
    )
    
    $DateFull = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    $Name = $Sender + "_PhishingMessage_Investigation_" + $DateFull
    
    If ($Subject)
    {
        $ContentMatchQuery = "(from:" + $Sender + ") and (Subject:" + $Subject + ")"
        New-ComplianceSearch -Name $Name -ExchangeLocation All -ContentMatchQuery $ContentMatchQuery
    }
    Else
    {
        $ContentMatchQuery = "(from:" + $Sender + ")"
        New-ComplianceSearch -Name $Name -ExchangeLocation All -ContentMatchQuery $ContentMatchQuery
    }
    Sleep 10
    Start-ComplianceSearch -Identity $Name
    Sleep 10
    Get-ComplianceSearch -Identity $Name | ft Name, RunBy, Status, ContentMatchQuery
}

Function Purge-EXOPhishingContentSearch
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$ContentSearchName
    )
    
    New-ComplianceSearchAction -SearchName $ContentSearchName -Purge -PurgeType HardDelete
    $ComplianceSearchActionName = $ContentSearchName + "_Purge"
    Get-ComplianceSearchAction $ComplianceSearchActionName | fl Name, SearchName, Results, Action, Status, ExchangeLocation, RunBy, CreateBy
    
}

Function Update-EXOPhishingTransportRule
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$Sender
    )
    
    #Add Phishing Email Address to Transport Rule: Phishing_Blocked_Senders
    $TransportRule = Get-TransportRule -identity Phishing_Blocked_Senders_7
    $From = $Null
    $From = $TransportRule.From
    $From += $Sender
    Set-TransportRule -identity Phishing_Blocked_Senders_7 -From $From
    Write-Log -Level Warning -Message "The Transport Rule Phishing_Blocked_Senders: was updated with $Sender"
    Write-Log -Level warning -Message "The update list is:"
    Get-TransportRule -identity Phishing_Blocked_Senders_7 | select -ExpandProperty From
}

Function Check-EXORetentionExclusion
{
    param
    (
        [Parameter(Mandatory = $False,
                   Position = 1)]
        [String]$InputFile
    )
    Read-Host "Expected CSV Column: UserPrincipalName"
    $Table = $Null
    $Table = @()
    [int]$i = 1
    $Date = get-date -UFormat %d%m%Y
    $DateFull = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    $ServerName = [Environment]::MachineName
    ###### Create Root Folder
    $Location = $Null
    $Location = (Get-Location).Path
    $RootFolder = $Location + "\Check_RetentionExclusion\"
    
    ###### Create folder Variable
    $LogPathFolder = $RootFolder + "\Log\"
    $LogFile = $LogPathFolder + "Progress_" + $Date + ".log"
    
    $ReportPathFolder = $RootFolder + "\Reports\"
    
    ###### Create Folder
    Create-Folder $RootFolder
    Create-Folder $LogPathFolder
    Create-Folder $ReportPathFolder
    
    ########### Initiate the Process log file when the script started ############
    $Initiat_LogA = "#################### starting the Script #####################"
    $Startat = "### The Script has been launch at $(Get-Date -Format "yyyy-MM-dd HH:mm:ss")"
    $Startwith = "The Script has been start with the following Account:" + [Environment]::UserName
    $Starton = "The Script has been start on the following Computer:" + [Environment]::MachineName
    $Initiat_LogB = "##############################################################"
    $Initiat_LogB | Out-File -FilePath $LogFile -Append
    $Initiat_LogB | Out-File -FilePath $LogFile -Append
    $Initiat_LogA | Out-File -FilePath $LogFile -Append
    $Startat | Out-File -FilePath $LogFile -Append
    $Startwith | Out-File -FilePath $LogFile -Append
    $Starton | Out-File -FilePath $LogFile -Append
    $Initiat_LogB | Out-File -FilePath $LogFile -Append
    $Initiat_LogB | Out-File -FilePath $LogFile -Append
    
    
    ########### Main Script ###########
    Try
    {
        $ExceptionMailboxes = Import-Csv $InputFile
        Write-Host "CSV File Imported $InputFile"
    }
    Catch
    {
        $ErrorMessage = $Error[0].Exception.Message
        $CMDLet = $Error[0].InvocationInfo.Line
        $FailedItem = $Error[0].Exception.ItemName
        Write-Log -Level Error $LogFile -Message "Failed to Import CSV File : $InputFile"
        Write-Log -Level Error $LogFile-Message "Failed to run the following CMDLet: $CMDLet"
        Write-Log -Level Error $LogFile -Message "Failed with Error:$ErrorMessage"
        Write-Log -Level Error $LogFile -Message "The Script will stop"
        # Exit the script
        Exit
    }
    
    $ExceptionMailboxesCount = ($ExceptionMailboxes | Measure).Count
    forEach ($ExceptionMailbox in $ExceptionMailboxes)
    {
        $UPN = $Null
        $UPN = $ExceptionMailbox.UserPrincipalName
        $Mailbox = $Null
        $Recipient = $Null
        $Recipient = Get-Recipient $UPN
        $DisplayName = $Null
        $DisplayName = $Recipient.DisplayName
        $RecipientType = $Null
        $RecipientType = $Recipient.RecipientType
        Write-Log -Level INFO $LogFile -Message "Checking User: $DisplayName - $UPN - $RecipientType"
        If ($RecipientType -eq "UserMailbox")
        {
            Try
            {
                $Mailbox = Get-Mailbox $UPN
                $Retention = $Null
                $RetentionPolicy = $Mailbox.RetentionPolicy
                Write-Log -Level Warning $LogFile -Message 'Is Mailbox: $DisplayName - $UPN - $RecipientType'
                $Table += New-object PSobject -Property ([Ordered] @{
                        DisplayName        = $DisplayName;
                        UPN                = $UPN;
                        RetentionPolicy = $RetentionPolicy;
                    })
            }
            Catch
            {
                Write-Log -Level Error $LogFile -Message "Not a Mailbox"
                $Table += New-object PSobject -Property ([Ordered] @{
                        DisplayName        = $DisplayName;
                        UPN                = $UPN;
                        RetentionPolicy = "Not Migrated";
                    })
            }
        }
        Else
        {
            Write-Log -Level Error $LogFile -Message '$UPN is Not a Mailbox - $RecipientType'
            $Table += New-object PSobject -Property ([Ordered] @{
                    DisplayName        = $DisplayName;
                    UPN                = $UPN;
                    RetentionPolicy = "Not Migrated";
                })
        }
        $i++
    }
    $ExportCSVFile = $ReportPathFolder + "RetentionExclusion_" + $DateFull + ".csv"
    $Table | Export-csv $ExportCSVFile -NoTypeInformation -Encoding UTF8
    Write-Log -Level Error $LogFile -Message 'the Data has been exported to $ExportCSVFile'
}

Function Get-EXOBookingMailboxOwner
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [string]$BookingEmailAddress
    )
    
    $MailboxPermission = Get-MailboxPermission $BookingEmailAddress | where { $_.User -ne "NT AUTHORITY\SELF" }
    return $MailboxPermission
}

Function Check-EXOBookingMailboxSettings
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [string]$EmailAddress
    )
    $BookingMailboxSettingsTable = $Null
    $BookingMailboxSettingsTable = @()
    $Owners = Get-BookingMailboxOwner $EmailAddress
    $Owners = $Owners.user -join ";"
    $Calendar = $Null
    $Calendar = Get-Mailbox $EmailAddress | Get-MailboxFolderStatistics -FolderScope calendar | select Name
    $CalendarName = $Null
    $CalendarName = $Calendar.Name
    $BookingURL = $Null
    $BookingURL = "https://outlook.office365.com/owa/" + $CalendarName + "/" + $EmailAddress + "/bookings/"
    $Response = $Null
    Try
    {
        $Response = Invoke-WebRequest -URI $BookingURL
        $SuccessfullConnection = "Yes"
    }
    Catch
    {
        $ErrorMessage = $Error[0].Exception.Message
        $SuccessfullConnection = $ErrorMessage
    }
    
    $SigninRedirection = $Null
    If ($Response | where { $_.Content -like '*<title>Sign in to Outlook</title>*' })
    { $SigninRedirection = "Yes" }
    Else { $SigninRedirection = "No" }
    $BookingMailboxSettingsTable += New-object PSobject -Property ([Ordered] @{
            EmailAddress          = $EmailAddress;
            Owners                  = $Owners;
            CalendarName          = $CalendarName;
            SigninRedirection      = $SigninRedirection;
            BookingURL              = $BookingURL;
            SuccessfullConnection = $SuccessfullConnection;
        })
    
    return $BookingMailboxSettingsTable
}

Function Create-EXOSharedMailboxWithSG
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$LocalPart,
        [Parameter(Mandatory = $true,
                   Position = 2)]
        [String]$Domain
    )
    
    #Variable
    $SecurityGroupName = "MBX_" + $LocalPart + "_FP"
    $SecurityGroupEmailAddress = $SecurityGroupName + "@" + $Domain
    $PrimaryEmailAddress = $LocalPart + "@" + $Domain
    $CreateSharedMBXStatus = "Failed"
    $CreateSGStatus = "Failed"
    $GrantSendAsStatus = "Failed"
    # Create Security Group
    Try
    {
        Write-Log Info -Message "The script will try to create the Mail-Enabled Security Group $SecurityGroupName ($SecurityGroupEmailAddress)"
        New-DistributionGroup -Name $SecurityGroupName -Alias $SecurityGroupName -Type security -PrimarySmtpAddress $SecurityGroupEmailAddress
        Write-Log warning -Message "The script successfully created the Mail-Enabled Security Group $SecurityGroupName ($SecurityGroupEmailAddress)"
        $CreateSGStatus = "Success"
        
        # Create Shared Mailbox
        Try
        {
            Write-Log Info -Message "The script will try to create the Shared Mailbox $LocalPart ($PrimaryEmailAddress)"
            New-Mailbox -Shared -Name $LocalPart -DisplayName $LocalPart -Alias $LocalPart -PrimarySmtpAddress $PrimaryEmailAddress
            Write-Log warning -Message "The script successfully created the Shared Mailbox $LocalPart ($PrimaryEmailAddress)"
            $CreateSharedMBXStatus = "Success"
            #Assign SendAs Permission to Security Group
            Try
            {
                Write-Log Info -Message "The script will try to grant SendAs Permission $PrimaryEmailAddress to $SecurityGroupEmailAddress"
                Add-RecipientPermission -Identity $PrimaryEmailAddress -Trustee $SecurityGroupEmailAddress -AccessRights SendAs -confirm:$false
                Write-Log warning -Message "The script successfully grant SendAs Permission $PrimaryEmailAddress to $SecurityGroupEmailAddress"
                $GrantSendAsStatus = "Success"
            }
            Catch
            {
                $ErrorMessage = $Error[0].Exception.Message
                $CMDLet = $Error[0].InvocationInfo.Line
                $FailedItem = $Error[0].Exception.ItemName
                Write-Log Error -Message "Failed to grant SendAs Permission $PrimaryEmailAddress to $SecurityGroupEmailAddress"
                Write-Log Error -Message "Failed to run the following CMDLet: $CMDLet"
                Write-Log Error -Message "Failed with Error:$ErrorMessage"
                
            }
            
            #Assign FullAccess Permission to Security Group
            Try
            {
                Write-Log Info -Message "The script will try to grant FullAccess $PrimaryEmailAddress to $SecurityGroupEmailAddress"
                Add-MailboxPermission -Identity $PrimaryEmailAddress -User $SecurityGroupEmailAddress -AccessRights FullAccess -InheritanceType All
                Write-Log warning -Message "The script successfully grant FullAccess $PrimaryEmailAddress to $SecurityGroupEmailAddress"
                $GrantFullAccessStatus = "Success"
                
                
            }
            Catch
            {
                $ErrorMessage = $Error[0].Exception.Message
                $CMDLet = $Error[0].InvocationInfo.Line
                $FailedItem = $Error[0].Exception.ItemName
                Write-Log Error -Message "Failed to grant FullAccess $PrimaryEmailAddress to $SecurityGroupEmailAddress"
                Write-Log Error -Message "Failed to run the following CMDLet: $CMDLet"
                Write-Log Error -Message "Failed with Error:$ErrorMessage"
                $GrantFullAccessStatus = "Failed"
            }
        }
        Catch
        {
            $ErrorMessage = $Error[0].Exception.Message
            $CMDLet = $Error[0].InvocationInfo.Line
            $FailedItem = $Error[0].Exception.ItemName
            Write-Log Error -Message "Failed to create the Shared Mailbox $LocalPart ($PrimaryEmailAddress)"
            Write-Log Error -Message "Failed to run the following CMDLet: $CMDLet"
            Write-Log Error -Message "Failed with Error:$ErrorMessage"
            
        }
    }
    Catch
    {
        $ErrorMessage = $Error[0].Exception.Message
        $CMDLet = $Error[0].InvocationInfo.Line
        $FailedItem = $Error[0].Exception.ItemName
        Write-Log Error -Message "Failed to create the Mail-Enabled Security Group $SecurityGroupName ($SecurityGroupEmailAddress)"
        Write-Log Error -Message "Failed to run the following CMDLet: $CMDLet"
        Write-Log Error -Message "Failed with Error:$ErrorMessage"
        
    }
    
    # Output
    $OutPut = $null
    $OutPut = @()
    $OutPut += New-object PSobject -Property ([Ordered] @{
            SharedMailboxPrimaryEmailAddress = $PrimaryEmailAddress;
            SecurityGroupName                 = $SecurityGroupName;
            CreateSharedMBXStatus             = $CreateSharedMBXStatus;
            GrantSendAsStatus                 = $GrantSendAsStatus;
            GrantFullAccessStatus             = $GrantFullAccessStatus;
        })
    Return $OutPut
}

Function Generate-EXOInactiveMailboxPermissionXML
{
    [CmdletBinding()]
    param ()
    
    
    $InactiveMailboxes = Get-Mailbox -InactiveMailboxOnly -resultsize unlimited
    
    $Table = $Null
    $Table = @()
    Foreach ($InactiveMailbox in $InactiveMailboxes)
    {
        $PrimarySmtpAddress = $Null
        $PrimarySmtpAddress = $InactiveMailbox.PrimarySmtpAddress
        $Permissions = $Null
        $Permissions = @()
        $Permissions = Get-MailboxPermission -identity $PrimarySmtpAddress -SoftDeletedMailbox
        $Permissions | Add-Member -NotePropertyName Email -NotePropertyValue $PrimarySmtpAddress
        
        $Table += $Permissions
        
    }
    $Table | Out-GridView
    $DateFull = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    $ReportFile = "Report_ExportAllInactiveMailboxesPermission_" + $DateFull + ".xml"
    $Table | Export-clixml $ReportFile
    Write-Log Warning -Message "The script generated the following $ReportFile"
}

Function Replace-EXOSMTPDomain
{
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$DomainToRemoved,
        [Parameter(Position = 2)]
        [string]$ReplaceDomain,
        [Parameter(Position = 3)]
        [switch]$Cloud,
        [Parameter(Position = 4)]
        [switch]$Onpremise
    )
    
    If (!$ReplaceDomain)
    { $ReplaceDomain = (Get-AcceptedDomain | where { ($_.DomainName -like "*.onmicrosoft.com") -and ($_.DomainName -notlike "*.mail.onmicrosoft.com") } | select -First 1).DomainName }
    
    If ($Onpremise)
    {
        # Backup
        Try
        {
            Write-Log Info -Message "The script will try to backupt all Recipients"
            $DateFull = Get-Date -Format "ddMMyyyy_HH-mm-ss"
            $AllRecipients = Get-Recipient -ResultSize unlimited -DomainController $DC -ErrorAction Silentlycontinue -ErrorVariable CMDLetFailed
            $AllRecipientFile = "All_recipients_" + $DateFull + ".xml"
            $AllRecipients | Export-Clixml $AllRecipientFile
            $Recipients = $AllRecipients | where { $_.IsDirsynced -eq $False }
            
            If ($CMDLetFailed)
            {
                $ErrorMessage = $CMDLetFailed.Exception.Message
                $CMDLet = $CMDLetFailed.InvocationInfo.Line
                Write-Log Error -Message "Failed to backup all recipients"
                Write-Log Error -Message "Failed to run the following CMDLet: $CMDLet"
                Write-Log Error -Message "Failed with Error:$ErrorMessage"
                $Status = "Failed"
                $CMDLetFailed.clear()
            }
            Else
            {
                $Status = "Success"
                Write-Log Info -Message "The script successfully backup all recipients"
            }
            
        }
        Catch
        {
            $ErrorMessage = $Error[0].Exception.Message
            $CMDLet = $Error[0].InvocationInfo.Line
            $FailedItem = $Error[0].Exception.ItemName
            Write-Log Error -Message "Failed to "
            Write-Log Error -Message "Failed to run the following CMDLet: $CMDLet"
            Write-Log Error -Message "Failed with Error:$ErrorMessage"
            $Status = "Failed"
        }
        If ($Status -eq "Failed")
        {
            Write-Log Error -Message "Failed to backup all Recipients - The script will stop"
            Exit
        }
        
        # Processing
        #Initiate the Hash Table
        [Int]$i = 1
        $Table = $Null
        $Table = @()
        $RecipientsToUpdates = $Recipients | where { $_.EmailAddresses -match $DomainToRemoved }
        $RecipientsToUpdateFile = ".\RecipientsToUpdate_" + $DateFull + ".xml"
        $RecipientsToUpdates | select Alias, DisplayName, CustomAttribute12, PrimarySMTPAddress, EmailAddresses | Export-Clixml $RecipientsToUpdateFile
        $Count = ($RecipientsToUpdates | Measure).count
        foreach ($RecipientsToUpdate in $RecipientsToUpdates)
        {
            $RecipientTypeDetails = $Null
            $RecipientTypeDetails = $RecipientsToUpdate.RecipientTypeDetails
            $Alias = $Null
            $Alias = $RecipientsToUpdate.Alias
            $Identity = $Null
            $Identity = $RecipientsToUpdate.Identity
            $DisplayName = $Null
            $DisplayName = $RecipientsToUpdate.DisplayName
            $CustomAttribute12 = $Null
            $CustomAttribute12 = $RecipientsToUpdate.CustomAttribute12
            $EmailAddresses = $Null
            $EmailAddresses = $RecipientsToUpdate.EmailAddresses
            $PrimarySMTPAddress = $Null
            $PrimarySMTPAddress = $RecipientsToUpdate.PrimarySMTPAddress
            $Localpart = $Null
            $LocalPart = $PrimarySMTPAddress.Substring(0, $PrimarySMTPAddress.LastIndexOf("@"))
            $NewPrimarySMTPAddress = $Null
            $NewPrimarySMTPAddress = $LocalPart + "@" + $ReplaceDomain
            
            # Search for onMicrosoft email Address
            $OnMicrosoft = $Null
            $Onmicrosoft = $Emailaddresses | where { $_ -match ".onmicrosoft.com" } | select -First 1
            $Onmicrosoft = $Onmicrosoft.Substring(5)
            switch ($RecipientTypeDetails)
            {
                RemoteUserMailbox
                {
                    Write-Log warning -Message "The script will analyze the following Remote User Mailbox (Alias:$Alias - Primary : $PrimarySMTPAddress - Onmicrosoft: $Onmicrosoft - RecipientTypeDetails: $RecipientTypeDetails)"
                    $User = $Null
                    $User = Get-User $PrimarySMTPAddress -DomainController $DC
                    $UPN = $Null
                    $UPN = $User.UserPrincipalName
                    
                    if ($UPN -match $DomainToRemoved)
                    {
                        Set-User $PrimarySMTPAddress -UserPrincipalName $NewPrimarySMTPAddress
                        Write-Log info -Message "The script will update the UPN from $UPN to $NewPrimarySMTPAddress"
                        $Table += New-object PSobject -Property ([Ordered] @{
                                DisplayName             = $DisplayName;
                                PrimarySMTPAddress   = $PrimarySMTPAddress;
                                UPN                     = $UPN;
                                Onmicrosoft             = $Onmicrosoft;
                                Alias                 = $Alias;
                                RecipientTypeDetails = $RecipientTypeDetails;
                                CustomAttribute12    = $CustomAttribute12;
                                Identity             = $Identity;
                                Action                 = "Upate UPN $PrimarySMTPAddress to $NewPrimarySMTPAddress";
                            })
                    }
                    # Update Primary SMTP Addresss
                    If ($PrimarySMTPAddress -match $DomainToRemoved)
                    {
                        Write-Log info -Message "The script will update the PrimarySMTPAddress from $PrimarySMTPAddress to $NewPrimarySMTPAddress"
                        Set-RemoteMailbox -identity $PrimarySMTPAddress -PrimarySmtpAddress $NewPrimarySMTPAddress -DomainController $DC
                        $Table += New-object PSobject -Property ([Ordered] @{
                                DisplayName             = $DisplayName;
                                PrimarySMTPAddress   = $PrimarySMTPAddress;
                                UPN                     = $UPN;
                                Onmicrosoft             = $Onmicrosoft;
                                Alias                 = $Alias;
                                RecipientTypeDetails = $RecipientTypeDetails;
                                CustomAttribute12    = $CustomAttribute12;
                                Identity             = $Identity;
                                Action                 = "Upate Primary $PrimarySMTPAddress to $NewPrimarySMTPAddress";
                            })
                        
                    }
                    # Search for Email Addresses to remove
                    foreach ($EmailAddress in $EmailAddresses)
                    {
                        $EmailAddressToRemove = $Null
                        $EmailAddressToRemove = $EmailAddress
                        $EmailAddressToRemove = $EmailAddressToRemove.Substring(5)
                        if ($EmailAddress -match $DomainToRemoved)
                        {
                            Write-Log warning -Message "The script will remove the email addresse $EmailAddressToRemove"
                            Set-RemoteMailbox -Identity $NewPrimarySMTPAddress -EmailAddresses @{ Remove = $EmailAddressToRemove } -DomainController $DC
                            Write-Log Info -Message "The script removed the email addresse $EmailAddressToRemove"
                            $Table += New-object PSobject -Property ([Ordered] @{
                                    DisplayName             = $DisplayName;
                                    PrimarySMTPAddress   = $PrimarySMTPAddress;
                                    UPN                     = $UPN;
                                    Onmicrosoft             = $Onmicrosoft;
                                    Alias                 = $Alias;
                                    RecipientTypeDetails = $RecipientTypeDetails;
                                    CustomAttribute12    = $CustomAttribute12;
                                    Identity             = $Identity;
                                    Action                 = "Remove $EmailAddressToRemove";
                                })
                            
                            
                            
                        }
                        Else
                        {
                            Write-Log Info -Message "The script will NOT remove the email addresse $EmailAddressToRemove"
                        }
                        
                    }
                    $i++
                }
                RemoteSharedMailbox
                {
                    Write-Log warning -Message "The script will analyze the following Remote Shared Mailbox (Alias:$Alias - Primary : $PrimarySMTPAddress - Onmicrosoft: $Onmicrosoft - RecipientTypeDetails: $RecipientTypeDetails)"
                    $User = $Null
                    $User = Get-User $PrimarySMTPAddress -DomainController $DC
                    $UPN = $Null
                    $UPN = $User.UserPrincipalName
                    
                    if ($UPN -match $DomainToRemoved)
                    {
                        Set-User $PrimarySMTPAddress -UserPrincipalName $NewPrimarySMTPAddress
                        Write-Log info -Message "The script will update the UPN from $UPN to $NewPrimarySMTPAddress"
                        $Table += New-object PSobject -Property ([Ordered] @{
                                DisplayName             = $DisplayName;
                                PrimarySMTPAddress   = $PrimarySMTPAddress;
                                UPN                     = $UPN;
                                Onmicrosoft             = $Onmicrosoft;
                                Alias                 = $Alias;
                                RecipientTypeDetails = $RecipientTypeDetails;
                                CustomAttribute12    = $CustomAttribute12;
                                Identity             = $Identity;
                                Action                 = "Upate UPN $PrimarySMTPAddress to $NewPrimarySMTPAddress";
                            })
                    }
                    # Update Primary SMTP Addresss
                    If ($PrimarySMTPAddress -match $DomainToRemoved)
                    {
                        Write-Log info -Message "The script will update the PrimarySMTPAddress from $PrimarySMTPAddress to $NewPrimarySMTPAddress"
                        Set-RemoteMailbox -identity $PrimarySMTPAddress -PrimarySmtpAddress $NewPrimarySMTPAddress -DomainController $DC
                        $Table += New-object PSobject -Property ([Ordered] @{
                                DisplayName             = $DisplayName;
                                PrimarySMTPAddress   = $PrimarySMTPAddress;
                                UPN                     = $UPN;
                                Onmicrosoft             = $Onmicrosoft;
                                Alias                 = $Alias;
                                RecipientTypeDetails = $RecipientTypeDetails;
                                CustomAttribute12    = $CustomAttribute12;
                                Identity             = $Identity;
                                Action                 = "Upate Primary $PrimarySMTPAddress to $NewPrimarySMTPAddress";
                            })
                        
                    }
                    # Search for Email Addresses to remove
                    foreach ($EmailAddress in $EmailAddresses)
                    {
                        $EmailAddressToRemove = $Null
                        $EmailAddressToRemove = $EmailAddress
                        $EmailAddressToRemove = $EmailAddressToRemove.Substring(5)
                        if ($EmailAddress -match $DomainToRemoved)
                        {
                            Write-Log warning -Message "The script will remove the email addresse $EmailAddressToRemove"
                            Set-RemoteMailbox -Identity $NewPrimarySMTPAddress -EmailAddresses @{ Remove = $EmailAddressToRemove } -DomainController $DC
                            Write-Log Info -Message "The script removed the email addresse $EmailAddressToRemove"
                            $Table += New-object PSobject -Property ([Ordered] @{
                                    DisplayName             = $DisplayName;
                                    PrimarySMTPAddress   = $PrimarySMTPAddress;
                                    UPN                     = $UPN;
                                    Onmicrosoft             = $Onmicrosoft;
                                    Alias                 = $Alias;
                                    RecipientTypeDetails = $RecipientTypeDetails;
                                    CustomAttribute12    = $CustomAttribute12;
                                    Identity             = $Identity;
                                    Action                 = "Remove $EmailAddressToRemove";
                                })
                            
                            
                            
                        }
                        Else
                        {
                            Write-Log Info -Message "The script will NOT remove the email addresse $EmailAddressToRemove"
                        }
                        
                    }
                    $i++
                }
                RemoteRoomMailbox
                {
                    Write-Log warning -Message "The script will analyze the following Remote Room Mailbox (Alias:$Alias - Primary : $PrimarySMTPAddress - Onmicrosoft: $Onmicrosoft - RecipientTypeDetails: $RecipientTypeDetails)"
                    $User = $Null
                    $User = Get-User $PrimarySMTPAddress -DomainController $DC
                    $UPN = $Null
                    $UPN = $User.UserPrincipalName
                    
                    if ($UPN -match $DomainToRemoved)
                    {
                        Set-User $PrimarySMTPAddress -UserPrincipalName $NewPrimarySMTPAddress
                        Write-Log info -Message "The script will update the UPN from $UPN to $NewPrimarySMTPAddress"
                        $Table += New-object PSobject -Property ([Ordered] @{
                                DisplayName             = $DisplayName;
                                PrimarySMTPAddress   = $PrimarySMTPAddress;
                                UPN                     = $UPN;
                                Onmicrosoft             = $Onmicrosoft;
                                Alias                 = $Alias;
                                RecipientTypeDetails = $RecipientTypeDetails;
                                CustomAttribute12    = $CustomAttribute12;
                                Identity             = $Identity;
                                Action                 = "Upate UPN $PrimarySMTPAddress to $NewPrimarySMTPAddress";
                            })
                    }
                    # Update Primary SMTP Addresss
                    If ($PrimarySMTPAddress -match $DomainToRemoved)
                    {
                        Write-Log info -Message "The script will update the PrimarySMTPAddress from $PrimarySMTPAddress to $NewPrimarySMTPAddress"
                        Set-RemoteMailbox -identity $PrimarySMTPAddress -PrimarySmtpAddress $NewPrimarySMTPAddress -DomainController $DC
                        $Table += New-object PSobject -Property ([Ordered] @{
                                DisplayName             = $DisplayName;
                                PrimarySMTPAddress   = $PrimarySMTPAddress;
                                UPN                     = $UPN;
                                Onmicrosoft             = $Onmicrosoft;
                                Alias                 = $Alias;
                                RecipientTypeDetails = $RecipientTypeDetails;
                                CustomAttribute12    = $CustomAttribute12;
                                Identity             = $Identity;
                                Action                 = "Upate Primary $PrimarySMTPAddress to $NewPrimarySMTPAddress";
                            })
                        
                    }
                    # Search for Email Addresses to remove
                    foreach ($EmailAddress in $EmailAddresses)
                    {
                        $EmailAddressToRemove = $Null
                        $EmailAddressToRemove = $EmailAddress
                        $EmailAddressToRemove = $EmailAddressToRemove.Substring(5)
                        if ($EmailAddress -match $DomainToRemoved)
                        {
                            Write-Log warning -Message "The script will remove the email addresse $EmailAddressToRemove"
                            Set-RemoteMailbox -Identity $NewPrimarySMTPAddress -EmailAddresses @{ Remove = $EmailAddressToRemove } -DomainController $DC
                            Write-Log Info -Message "The script removed the email addresse $EmailAddressToRemove"
                            $Table += New-object PSobject -Property ([Ordered] @{
                                    DisplayName             = $DisplayName;
                                    PrimarySMTPAddress   = $PrimarySMTPAddress;
                                    UPN                     = $UPN;
                                    Onmicrosoft             = $Onmicrosoft;
                                    Alias                 = $Alias;
                                    RecipientTypeDetails = $RecipientTypeDetails;
                                    CustomAttribute12    = $CustomAttribute12;
                                    Identity             = $Identity;
                                    Action                 = "Remove $EmailAddressToRemove";
                                })
                            
                            
                            
                        }
                        Else
                        {
                            Write-Log Info -Message "The script will NOT remove the email addresse $EmailAddressToRemove"
                        }
                        
                    }
                    $i++
                }
                MailUser
                {
                    Write-Log warning -Message "The script will analyze the following MailUser (Alias:$Alias - Primary : $PrimarySMTPAddress - Onmicrosoft: $Onmicrosoft - RecipientTypeDetails: $RecipientTypeDetails)"
                    $User = $Null
                    $User = Get-User $PrimarySMTPAddress -DomainController $DC
                    $UPN = $Null
                    $UPN = $User.UserPrincipalName
                    
                    if ($UPN -match $DomainToRemoved)
                    {
                        Set-User $PrimarySMTPAddress -UserPrincipalName $NewPrimarySMTPAddress
                        Write-Log info -Message "The script will update the UPN from $UPN to $NewPrimarySMTPAddress"
                        $Table += New-object PSobject -Property ([Ordered] @{
                                DisplayName             = $DisplayName;
                                PrimarySMTPAddress   = $PrimarySMTPAddress;
                                UPN                     = $UPN;
                                Onmicrosoft             = $Onmicrosoft;
                                Alias                 = $Alias;
                                RecipientTypeDetails = $RecipientTypeDetails;
                                CustomAttribute12    = $CustomAttribute12;
                                Identity             = $Identity;
                                Action                 = "Upate UPN $PrimarySMTPAddress to $NewPrimarySMTPAddress";
                            })
                    }
                    # Update Primary SMTP Addresss
                    If ($PrimarySMTPAddress -match $DomainToRemoved)
                    {
                        Write-Log info -Message "The script will update the PrimarySMTPAddress from $PrimarySMTPAddress to $NewPrimarySMTPAddress"
                        Set-MailUser -identity $PrimarySMTPAddress -PrimarySmtpAddress $NewPrimarySMTPAddress -DomainController $DC
                        $Table += New-object PSobject -Property ([Ordered] @{
                                DisplayName             = $DisplayName;
                                PrimarySMTPAddress   = $PrimarySMTPAddress;
                                UPN                     = $UPN;
                                Onmicrosoft             = $Onmicrosoft;
                                Alias                 = $Alias;
                                RecipientTypeDetails = $RecipientTypeDetails;
                                CustomAttribute12    = $CustomAttribute12;
                                Identity             = $Identity;
                                Action                 = "Upate Primary $PrimarySMTPAddress to $NewPrimarySMTPAddress";
                            })
                        
                    }
                    # Search for Email Addresses to remove
                    foreach ($EmailAddress in $EmailAddresses)
                    {
                        $EmailAddressToRemove = $Null
                        $EmailAddressToRemove = $EmailAddress
                        $EmailAddressToRemove = $EmailAddressToRemove.Substring(5)
                        if ($EmailAddress -match $DomainToRemoved)
                        {
                            Write-Log warning -Message "The script will remove the email addresse $EmailAddressToRemove"
                            Set-MailUser -Identity $NewPrimarySMTPAddress -EmailAddresses @{ Remove = $EmailAddressToRemove } -DomainController $DC
                            Write-Log Info -Message "The script removed the email addresse $EmailAddressToRemove"
                            $Table += New-object PSobject -Property ([Ordered] @{
                                    DisplayName             = $DisplayName;
                                    PrimarySMTPAddress   = $PrimarySMTPAddress;
                                    UPN                     = $UPN;
                                    Onmicrosoft             = $Onmicrosoft;
                                    Alias                 = $Alias;
                                    RecipientTypeDetails = $RecipientTypeDetails;
                                    CustomAttribute12    = $CustomAttribute12;
                                    Identity             = $Identity;
                                    Action                 = "Remove $EmailAddressToRemove";
                                })
                            
                            
                            
                        }
                        Else
                        {
                            Write-Log Info -Message "The script will NOT remove the email addresse $EmailAddressToRemove"
                        }
                        
                    }
                    $i++
                }
                Default
                {
                    Write-Log warning -Message "The script will Not take any action against this object (Alias:$Alias - Primary : $PrimarySMTPAddress - Onmicrosoft: $Onmicrosoft - RecipientTypeDetails: $RecipientTypeDetails)"
                }
            }
            $i++
        }
        
    }
    
    If ($Cloud)
    {
        # Backup
        Try
        {
            Write-Log Info -Message "The script will try to backupt all Recipients"
            $DateFull = Get-Date -Format "ddMMyyyy_HH-mm-ss"
            $AllRecipients = Get-Recipient -ResultSize unlimited -ErrorAction Silentlycontinue -ErrorVariable CMDLetFailed
            $AllRecipientFile = "All_recipients_" + $DateFull + ".xml"
            $AllRecipients | Export-Clixml $AllRecipientFile
            $Recipients = $AllRecipients | where { $_.IsDirsynced -eq $False }
            
            If ($CMDLetFailed)
            {
                $ErrorMessage = $CMDLetFailed.Exception.Message
                $CMDLet = $CMDLetFailed.InvocationInfo.Line
                Write-Log Error -Message "Failed to backup all recipients"
                Write-Log Error -Message "Failed to run the following CMDLet: $CMDLet"
                Write-Log Error -Message "Failed with Error:$ErrorMessage"
                $Status = "Failed"
                $CMDLetFailed.clear()
            }
            Else
            {
                $Status = "Success"
                Write-Log Info -Message "The script successfully backup all recipients"
            }
            
        }
        Catch
        {
            $ErrorMessage = $Error[0].Exception.Message
            $CMDLet = $Error[0].InvocationInfo.Line
            $FailedItem = $Error[0].Exception.ItemName
            Write-Log Error -Message "Failed to "
            Write-Log Error -Message "Failed to run the following CMDLet: $CMDLet"
            Write-Log Error -Message "Failed with Error:$ErrorMessage"
            $Status = "Failed"
        }
        If ($Status -eq "Failed")
        {
            Write-Log Error -Message "Failed to backup all Recipients - The script will stop"
            Exit
        }
        
        # Processing
        #Initiate the Hash Table
        [Int]$i = 1
        $Table = $Null
        $Table = @()
        $RecipientsToUpdates = $Recipients | where { $_.EmailAddresses -match $DomainToRemoved }
        $RecipientsToUpdateFile = ".\RecipientsToUpdate_" + $DateFull + ".xml"
        $RecipientsToUpdates | select Alias, DisplayName, CustomAttribute12, PrimarySMTPAddress, EmailAddresses | Export-Clixml $RecipientsToUpdateFile
        $Count = ($RecipientsToUpdates | Measure).count
        foreach ($RecipientsToUpdate in $RecipientsToUpdates)
        {
            $RecipientTypeDetails = $Null
            $RecipientTypeDetails = $RecipientsToUpdate.RecipientTypeDetails
            $Alias = $Null
            $Alias = $RecipientsToUpdate.Alias
            $DisplayName = $Null
            $DisplayName = $RecipientsToUpdate.DisplayName
            $CustomAttribute12 = $Null
            $CustomAttribute12 = $RecipientsToUpdate.CustomAttribute12
            $EmailAddresses = $Null
            $EmailAddresses = $RecipientsToUpdate.EmailAddresses
            $PrimarySMTPAddress = $Null
            $PrimarySMTPAddress = $RecipientsToUpdate.PrimarySMTPAddress
            $Localpart = $Null
            $LocalPart = $PrimarySMTPAddress.Substring(0, $PrimarySMTPAddress.LastIndexOf("@"))
            $NewPrimarySMTPAddress = $Null
            $NewPrimarySMTPAddress = $LocalPart + "@" + $ReplaceDomain
            
            # Search for onMicrosoft email Address
            $OnMicrosoft = $Null
            $Onmicrosoft = $Emailaddresses | where { $_ -match "onmicrosoft.com" } | select -First 1
            $Onmicrosoft = $Onmicrosoft.Substring(5)
            
            switch ($RecipientTypeDetails)
            {
                UserMailbox
                {
                    # Update Primary SMTP Addresss
                    Set-Mailbox -identity $PrimarySMTPAddress -WindowsEmailAddress $NewPrimarySMTPAddress
                    $Table += New-object PSobject -Property ([Ordered] @{
                            DisplayName             = $DisplayName;
                            PrimarySMTPAddress   = $PrimarySMTPAddress;
                            Onmicrosoft             = $Onmicrosoft;
                            Alias                 = $Alias;
                            RecipientTypeDetails = $RecipientTypeDetails;
                            CustomAttribute12    = $CustomAttribute12;
                            Action                 = "Upate Primary $PrimarySMTPAddress to $NewPrimarySMTPAddress";
                        })
                    Write-Log warning -Message "The script will analyze the following user (Alias:$Alias - Primary : $PrimarySMTPAddress - Onmicrosoft: $Onmicrosoft - RecipientTypeDetails: $RecipientTypeDetails)"
                    
                    # Search for Email Addresses to remove
                    foreach ($EmailAddress in $EmailAddresses)
                    {
                        $EmailAddressToRemove = $Null
                        $EmailAddressToRemove = $EmailAddress
                        $EmailAddressToRemove = $EmailAddressToRemove.Substring(5)
                        if ($EmailAddress -match $DomainToRemoved)
                        {
                            Write-Log warning -Message "The script will remove the email addresse $EmailAddressToRemove"
                            Set-Mailbox -Identity $Onmicrosoft -EmailAddresses @{ Remove = $EmailAddressToRemove }
                            Write-Log Info -Message "The script removed the email addresse $EmailAddressToRemove"
                            $Table += New-object PSobject -Property ([Ordered] @{
                                    DisplayName             = $DisplayName;
                                    PrimarySMTPAddress   = $PrimarySMTPAddress;
                                    Onmicrosoft             = $Onmicrosoft;
                                    Alias                 = $Alias;
                                    RecipientTypeDetails = $RecipientTypeDetails;
                                    CustomAttribute12    = $CustomAttribute12;
                                    Action                 = "Remove $EmailAddressToRemove";
                                })
                            
                            
                            
                        }
                        Else
                        {
                            Write-Log Info -Message "The script will NOT remove the email addresse $EmailAddressToRemove"
                        }
                        
                    }
                    $i++
                }
                SharedMailbox
                {
                    # Update Primary SMTP Addresss
                    Set-Mailbox -identity $PrimarySMTPAddress -WindowsEmailAddress $NewPrimarySMTPAddress
                    $Table += New-object PSobject -Property ([Ordered] @{
                            DisplayName             = $DisplayName;
                            PrimarySMTPAddress   = $PrimarySMTPAddress;
                            Onmicrosoft             = $Onmicrosoft;
                            Alias                 = $Alias;
                            RecipientTypeDetails = $RecipientTypeDetails;
                            CustomAttribute12    = $CustomAttribute12;
                            Action                 = "Upate Primary $PrimarySMTPAddress to $NewPrimarySMTPAddress";
                        })
                    Write-Log warning -Message "The script will analyze the following shared (Alias:$Alias - Primary : $PrimarySMTPAddress - Onmicrosoft: $Onmicrosoft - RecipientTypeDetails: $RecipientTypeDetails)"
                    
                    # Search for Email Addresses to remove
                    foreach ($EmailAddress in $EmailAddresses)
                    {
                        $EmailAddressToRemove = $Null
                        $EmailAddressToRemove = $EmailAddress
                        $EmailAddressToRemove = $EmailAddressToRemove.Substring(5)
                        if ($EmailAddress -match $DomainToRemoved)
                        {
                            Write-Log warning -Message "The script will remove the email addresse $EmailAddressToRemove"
                            Set-Mailbox -Identity $Onmicrosoft -EmailAddresses @{ Remove = $EmailAddressToRemove }
                            Write-Log Info -Message "The script removed the email addresse $EmailAddressToRemove"
                            $Table += New-object PSobject -Property ([Ordered] @{
                                    DisplayName             = $DisplayName;
                                    PrimarySMTPAddress   = $PrimarySMTPAddress;
                                    Onmicrosoft             = $Onmicrosoft;
                                    Alias                 = $Alias;
                                    RecipientTypeDetails = $RecipientTypeDetails;
                                    Action                 = "Remove $EmailAddressToRemove";
                                })
                            
                            
                            
                        }
                        Else
                        {
                            Write-Log Info -Message "The script will NOT remove the email addresse $EmailAddressToRemove"
                        }
                        
                    }
                    $i++
                }
                MailUser
                { }
                MailUniversalDistributionGroup
                { }
                GroupMailbox
                { }
                Default
                { }
            }
            $i++
        }
        
    }
}

Function Add-EXOUsersToOneDGCSV
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$GroupEmailAddress,
        [Parameter(Mandatory = $true,
                   Position = 2)]
        [String]$CSVFile
    )
    Read-Host "Expected CSV Column:EmailAddress"
    $Users = Import-Csv $CSVFile
    $Count = ($Users | Measure).count
    [Int]$i = 1
    $Table = $Null
    $Table = @()
    Foreach ($User in $Users)
    {
        $UserEmailAddress = $Null
        $UserEmailAddress = $User.EmailAddress
        Write-Host "User $UserEmailAddress will be added to Group $GroupEmailAddress --- $i/$Count"
        Try
        {
            Add-DistributionGroupMember -Identity $GroupEmailAddress -Member $UserEmailAddress -ErrorAction Stop
            $Status = "Success"
            
        }
        Catch
        {
            $ErrorMessage = $Error[0].Exception.Message
            If ($ErrorMessage -like "*member*")
            { $Status = "Failed - already members" }
            Else { $Status = "Failed - $ErrorMessage" }
        }
        $Table += New-object PSobject -Property ([Ordered] @{
                GroupEmailAddress = $GroupEmailAddress;
                UserName          = $UserEmailAddress;
                Action              = "Add";
                Status              = $Status;
            })
        $i++
    }
    $DateFull = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    $ReportFile = ".\Report_Users_Added_To_" + $GroupEmailAddress + "_" + $DateFull + ".csv"
    $Table | Export-Csv $ReportFile -NoTypeInformation -Encoding UTF8
    Write-Host "Generate the following Report: $ReportFile "
}

Function Add-EXOUserToSDG
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$GroupEmailAddress,
        [Parameter(Mandatory = $true,
                   Position = 2)]
        [String]$UserEmailAddress
    )
    
    Try
    {
        Write-log info -Message "The script will try to add $UserEmailAddress to $GroupEmailAddress"
        Add-DistributionGroupMember -Identity $GroupEmailAddress -Member $UserEmailAddress -ErrorAction Stop
        $Status = "Success"
        Write-log warning -Message "The script Status of the change: $Status"
        
    }
    Catch
    {
        $ErrorMessage = $Error[0].Exception.Message
        If ($ErrorMessage -like "*member*")
        { $Status = "Failed - already members" }
        Else { $Status = "Failed - $ErrorMessage" }
        Write-log Error -Message "The script Status of the change: $Status"
    }
    
}

#endregion

#region ExchangeOnpremise
####################################################
################# Exchange OnPremise ####################
###################################################

Function Clear-msExchRemoteRecipientType
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$SamAccountName
    )
    
    # Source: https://learn.microsoft.com/en-us/exchange/troubleshoot/administration/mail-user-who-has-proxy-addresses-that-use-non-verified-domains-not-synced
    Get-ADUser -Identity $SamAccountName -Properties * | ft UserprincipalName, msExchRemoteRecipientType
    
    Read-Host "Press Enter to Clear msExchRemoteRecipientType Attribute"
    
    Set-ADUser -Identity $SamAccountName -Clear msExchRemoteRecipientType
    
    Get-ADUser -Identity $SamAccountName -Properties * | ft UserprincipalName, msExchRemoteRecipientType
}


Function Fix-EXOArchiveMailboxGUID
{
    [CmdletBinding()]
    param
    (
        [Parameter(Position = 1)]
        [string]$DC,
        [Parameter(Mandatory = $true,
                   Position = 2)]
        [String]$UPN
    )
    
    #Backup
    $DateFull = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    $UPNName = $UPN.replace('@', '_').replace('.', '_')
    $ADUserXMLFile = ".\Backup_ADUser_" + $UPNName + "_" + $DateFull + ".xml"
    $RemoteMailboxXMLFile = ".\Backup_RemoteMailbox_" + $UPNName + "_" + $DateFull + ".xml"
    $OnlineMailboxXMLFile = ".\Backup_OnlineMailbox_" + $UPNName + "_" + $DateFull + ".xml"
    $Table = @()
    $FoundADUserStatus = "No"
    $FoundRemoteMailboxStatus = "No"
    $FoundOnlineMailboxStatus = "No"
    $DisableArchiveStatus = "No"
    $ManualADConnectDeltaSyncStatus = "No"
    $EnableArchiveStatus = "No"
    Try
    {
        Write-log warning -Message "Searching for ADUser $UPN"
        $ADUser = Get-ADUser -Filter { UserPrincipalName -eq $UPN } -Properties * -Server $DC
        $ADUser | Export-Clixml $ADUserXMLFile
        Write-log Info -Message "Generate the following backup File for $ADUserXMLFile"
        $msExchDisabledArchiveGUID = $ADUser.msExchDisabledArchiveGUID
        $msExchArchiveGUID = $ADUser.msExchArchiveGUID
        $SamAccountName = $ADUser.SamAccountName
        $FoundADUserStatus = "Yes"
        # Backup RemoteMailbox
        Try
        {
            Write-log warning -Message "Searching for RemoteMailbox: $UPN"
            $RemoteMailbox = Get-RemoteMailbox $UPN -DomainController $DC
            $RemoteMailboxDisabledArchiveGuid = $RemoteMailbox.DisabledArchiveGuid
            $RemoteMailbox | Export-Clixml $RemoteMailboxXMLFile
            Write-log INFO -Message "Generate the following backup File $RemoteMailboxXMLFile"
            $FoundRemoteMailboxStatus = "Yes"
            # Backup RemoteMailbox
            Try
            {
                Write-log warning -Message "Searching for Online Mailbox: $UPN"
                Connect-exchangeonline -Prefix OL
                $OnlineMailbox = Get-OLMailbox $UPN
                $OnlineMailboxArchiveGuid = $OnlineMailbox.ArchiveGuid
                $OnlineMailbox | Export-Clixml $OnlineMailboxXMLFile
                Write-log INFO -Message "Generate the following backup File for Online Mailbox $UPN : $OnlineMailboxXMLFile"
                $FoundOnlineMailboxStatus = "Yes"
                # Disable Archive for Remote Mailbox
                Try
                {
                    Write-log warning -Message "Disabling Archive and clear msExchDisabledArchiveGUID Attribute for RemoteMailbox: $UPN"
                    Disable-RemoteMailbox -Identity $UPN -Archive -DomainController $DC
                    Set-ADUser -Identity $SamAccountName -Clear msExchDisabledArchiveGUID -Server $DC
                    Write-log INFO -Message "Disabled Archive and clear msExchDisabledArchiveGUID Attribute for RemoteMailbox: $UPN"
                    $DisableArchiveStatus = "Yes"
                    # Pause for AD Connect Sync
                    Write-Log warning -Message "Please run a delta sync on you AD Connect Server using the following CMDLet: Start-ADSyncSyncCycle -PolicyType Delta"
                    Read-Host "Please press <Enter> to continue"
                    $ManualADConnectDeltaSyncStatus = "Yes"
                    # Enable Archive for Remote Mailbox
                    Try
                    {
                        Write-log warning -Message "Enable Archive and clear msExchDisabledArchiveGUID Attribute for RemoteMailbox: $UPN"
                        Enable-Remotemailbox -Identity $UPN -Archive -DomainController $DC
                        Set-RemoteMailbox -Identity $UPN -ArchiveGUID $OnlineMailboxArchiveGuid -DomainController $DC
                        Write-log INFO -Message "Disabled Archive and clear msExchDisabledArchiveGUID Attribute for RemoteMailbox: $UPN"
                        $EnableArchiveStatus = "Yes"
                    }
                    Catch
                    {
                        $ErrorMessage = $Error[0].Exception.Message
                        $CMDLet = $Error[0].InvocationInfo.Line
                        $FailedItem = $Error[0].Exception.ItemName
                        Write-Log Error -Message "Failed to Disable Archive and clear msExchDisabledArchiveGUID Attribute for RemoteMailbox: $UPN"
                        Write-Log Error -Message "Failed to run the following CMDLet: $CMDLet"
                        Write-Log Error -Message "Failed with Error:$ErrorMessage"
                        $EnableArchiveStatus = "Failed with Error:$ErrorMessage"
                    }
                }
                Catch
                {
                    $ErrorMessage = $Error[0].Exception.Message
                    $CMDLet = $Error[0].InvocationInfo.Line
                    $FailedItem = $Error[0].Exception.ItemName
                    Write-Log Error -Message "Failed to Disable Archive and clear msExchDisabledArchiveGUID Attribute for RemoteMailbox: $UPN"
                    Write-Log Error -Message "Failed to run the following CMDLet: $CMDLet"
                    Write-Log Error -Message "Failed with Error:$ErrorMessage"
                    $DisableArchiveStatus = "Failed with Error:$ErrorMessage"
                }
            }
            Catch
            {
                $ErrorMessage = $Error[0].Exception.Message
                $CMDLet = $Error[0].InvocationInfo.Line
                $FailedItem = $Error[0].Exception.ItemName
                Write-Log Error -Message "Failed to Backup RemoteMailbox: $UPN"
                Write-Log Error -Message "Failed to run the following CMDLet: $CMDLet"
                Write-Log Error -Message "Failed with Error:$ErrorMessage"
                $FoundOnlineMailboxStatus = "Failed with Error:$ErrorMessage"
            }
        }
        Catch
        {
            $ErrorMessage = $Error[0].Exception.Message
            $CMDLet = $Error[0].InvocationInfo.Line
            $FailedItem = $Error[0].Exception.ItemName
            Write-Log Error -Message "Failed to Backup RemoteMailbox: $UPN"
            Write-Log Error -Message "Failed to run the following CMDLet: $CMDLet"
            Write-Log Error -Message "Failed with Error:$ErrorMessage"
            $FoundRemoteMailboxStatus = "Failed with Error:$ErrorMessage"
        }
    }
    Catch
    {
        $ErrorMessage = $Error[0].Exception.Message
        $CMDLet = $Error[0].InvocationInfo.Line
        $FailedItem = $Error[0].Exception.ItemName
        Write-Log Error -Message "Failed to Backup ADUser: $UPN"
        Write-Log Error -Message "Failed to run the following CMDLet: $CMDLet"
        Write-Log Error -Message "Failed with Error:$ErrorMessage"
        $FoundADUserStatus = "Failed with Error:$ErrorMessage"
    }
    
    $Table += New-object PSobject -Property ([Ordered] @{
            UPN                                 = $UPN;
            FoundADUser                         = $FoundADUserStatus;
            msExchDisabledArchiveGUID         = $msExchDisabledArchiveGUID;
            msExchArchiveGUID                 = $msExchArchiveGUID;
            SamAccountName                     = $SamAccountName;
            ADUserXMLFile                     = $ADUserXMLFile;
            FoundRemoteMailbox                 = $FoundRemoteMailboxStatus;
            RemoteMailboxDisabledArchiveGuid = $RemoteMailboxDisabledArchiveGuid;
            FoundOnlineMailbox                 = $FoundOnlineMailboxStatus;
            OnlineMailboxArchiveGuid         = $OnlineMailboxArchiveGuid;
            DisableArchive                     = $DisableArchiveStatus;
            ManualADConnectDeltaSync         = $ManualADConnectDeltaSyncStatus;
            EnableArchive                     = $EnableArchiveStatus;
        })
    
    Return $Table
}

Function Fix-EXOArchiveMailboxGUIDv1
{
    [CmdletBinding()]
    param
    (
        [Parameter(Position = 1)]
        [string]$DC,
        [Parameter(Mandatory = $true,
                   Position = 2)]
        [String]$UPN
    )
    
    
    #Backup
    $ADUser = Get-ADUser -Filter { UserPrincipalName -eq $UPN } -Properties *
    $msExchDisabledArchiveGUID = $ADUser.msExchDisabledArchiveGUID
    $msExchArchiveGUID = $ADUser.msExchArchiveGUID
    $SamAccountName = $ADUser.SamAccountName
    
    $RemoteMailbox = Get-RemoteMailbox $UPN -DomainController $DC
    $RemoteMailboxDisabledArchiveGuid = $RemoteMailbox.DisabledArchiveGuid
    
    Connect-exchangeonline -Prefix OL
    $OnlineMailbox = Get-OLMailbox $UPN
    $OnlineMailboxArchiveGuid = $OnlineMailbox.ArchiveGuid
    
    If ($msExchArchiveGUID -ne $OnlineMailboxArchiveGuid)
    {
        Write-Log Warning -Message "Onpremise Archive GUID: $msExchArchiveGUID is NOT equal to Online Archive GUID:$OnlineMailboxArchiveGuid"
        Disable-RemoteMailbox -Identity $UPN -Archive -DomainController $DC
        Set-ADUser -Identity $SamAccountName -Clear msExchDisabledArchiveGUID -Server $DC
        Enable-Remotemailbox -Identity $UPN -Archive -DomainController $DC
        Set-RemoteMailbox -Identity $UPN -ArchiveGUID $OnlineMailboxArchiveGuid -DomainController $DC
        Write-Log Info -Message "Please run a Delta Sync (AD Connect)"
    }
    Else { Write-Log Warning -Message "The Onpremise Archive GUID $msExchArchiveGUID is equal to Online Archive GUID: $OnlineMailboxArchiveGuid" }
    
}

Function Update-EXORemoteMailboxPrimary
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [string]$EmailAddress,
        [Parameter(Mandatory = $true,
                   Position = 2)]
        [string]$NewPrimaryEmailAddress,
        [Parameter(Mandatory = $false,
                   Position = 3)]
        [switch]$Confirm
    )
    # Update Primary
    $RemoteMailbox = Get-RemoteMailbox $EmailAddress -DomainController $DC
    
    $DisplayName = $RemoteMailbox.DisplayName
    $PrimarySmtpAddress = $RemoteMailbox.PrimarySmtpAddress
    $UserPrincipalName = $RemoteMailbox.UserPrincipalName
    Write-host "RemoteMailbox info - $DisplayName (UPN: $UserPrincipalName - Primary : $PrimarySmtpAddress)"
    $RemoteMailbox | select -ExpandProperty EmailAddresses
    If (!$Confirm) { Read-Host "Are you sure you want to update the Primary Email Address from $PrimarySmtpAddress to $NewPrimaryEmailAddress" }
    Set-RemoteMailbox -Identity $PrimarySmtpAddress -EmailAddressPolicyEnabled $False -PrimarySmtpAddress $NewPrimaryEmailAddress -DomainController $DC
    
    $RemoteMailbox1 = Get-RemoteMailbox $EmailAddress -DomainController $DC
    
    $DisplayName1 = $RemoteMailbox1.DisplayName
    $PrimarySmtpAddress1 = $RemoteMailbox1.PrimarySmtpAddress
    $UserPrincipalName1 = $RemoteMailbox1.UserPrincipalName
    Write-host "RemoteMailbox info - $DisplayName1 (UPN: $UserPrincipalName1 - Primary : $PrimarySmtpAddress1)"
}

Function Add-EXORemoteMailboxSecondary
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [string]$EmailAddress,
        [Parameter(Mandatory = $true,
                   Position = 2)]
        [string]$NewSecondaryEmailAddress,
        [Parameter(Mandatory = $false,
                   Position = 3)]
        [switch]$Confirm
    )
    # Update Primary
    $RemoteMailbox = Get-RemoteMailbox $EmailAddress -DomainController $DC
    
    $DisplayName = $RemoteMailbox.DisplayName
    $PrimarySmtpAddress = $RemoteMailbox.PrimarySmtpAddress
    $UserPrincipalName = $RemoteMailbox.UserPrincipalName
    Write-host "RemoteMailbox info - $DisplayName (UPN: $UserPrincipalName - Primary : $PrimarySmtpAddress)"
    $RemoteMailbox | select -ExpandProperty EmailAddresses
    If (!$Confirm) { Read-Host "Are you sure you want to add $NewSecondaryEmailAddress" }
    Get-RemoteMailbox $PrimarySmtpAddress -DomainController $DC | Set-RemoteMailbox -EmailAddresses @{ Add = "$NewSecondaryEmailAddress" } -EmailAddressPolicyEnabled $False -DomainController $DC
    
    $RemoteMailbox1 = Get-RemoteMailbox $EmailAddress -DomainController $DC
    $DisplayName1 = $RemoteMailbox1.DisplayName
    $PrimarySmtpAddress1 = $RemoteMailbox1.PrimarySmtpAddress
    $UserPrincipalName1 = $RemoteMailbox1.UserPrincipalName
    Write-host "RemoteMailbox info - $DisplayName1 (UPN: $UserPrincipalName1 - Primary : $PrimarySmtpAddress1)"
    $RemoteMailbox1 | select -ExpandProperty EmailAddresses
}

Function Update-EXOPrimaryRemoteMailboxusingCSV
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$CSVFile,
        [Parameter(Mandatory = $false,
                   Position = 2)]
        [switch]$Check
    )
    Read-Host "Expected CSV Column: Email,NewEmail"
    $RemoteMailboxes = Import-Csv $CSVFile
    
    [Int]$i = 1
    $Table = $Null
    $Table = @()
    $Count = ($RemoteMailboxes | Measure).count
    foreach ($RemoteMailbox in $RemoteMailboxes)
    {
        $Email = $Null
        $Email = $RemoteMailbox.Email
        $NewEmail = $Null
        $NewEmail = $RemoteMailbox.NewEmail
        
        Write-Log warning -Message "The script will try update the RemoteMailbox $Email with New primary Email Address: $NewEmail .... --- $i/$Count"
        
        $RemoteMailbox = $Null
        Try
        {
            $RemoteMailbox = Get-RemoteMailbox -identity $Email -DomainController $DC -ErrorAction Stop
            $CurrentPrimaryRemoteMailbox = $Null
            $CurrentPrimaryRemoteMailbox = $RemoteMailbox.PrimarySmtpAddress
            $FoundRemoteMailbox = "Yes"
        }
        Catch
        {
            $ErrorMessage = $Error[0].Exception.Message
            If ($ErrorMessage -like "*couldn't be found*") { $FoundRemoteMailbox = "No - Not a RemoteMailbox" }
            Else { $FoundRemoteMailbox = "No - $ErrorMessage" }
        }
        
        If (!($Check)) { Update-EXORemoteMailboxPrimary -EmailAddress $Email -NewPrimaryEmailAddress $NewEmail -confirm }
        
        
        $NewRemoteMailbox = $Null
        $NewRemoteMailbox = Get-RemoteMailbox -identity $Email -DomainController $DC
        $NewRemoteMailboxPrimary = $Null
        $NewRemoteMailboxPrimary = $NewRemoteMailbox.PrimarySmtpAddress
        $Table += New-object PSobject -Property ([Ordered] @{
                Email                        = $Email;
                NewEmail                    = $NewEmail;
                FoundRemoteMailbox            = $FoundRemoteMailbox;
                CurrentPrimaryRemoteMailbox = $CurrentPrimaryRemoteMailbox;
                NewRemoteMailboxPrimary        = $NewRemoteMailboxPrimary;
            })
        $i++
    }
    $Table | Out-GridView
    $DateFull = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    $ReportFilexlsx = "UpdatePrimaryEmailAddress_RemoteMailboxes_" + $DateFull + ".xlsx"
    $Table | Export-Excel $ReportFilexlsx -TableName "UpdatePrimary" -Title "Update Primary Remote Mailbox" -TitleBold -WorksheetName "UpdatePrimary" -TableStyle Medium9 -AutoSize -AutoFilter
    Write-log INFO -Message "Generate the following Report: $ReportFilexlsx"
}

Function Add-EXOSendAsOnPremiseMailbox
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$SharedMailbox,
        [Parameter(Mandatory = $true,
                   Position = 2)]
        [String]$User
    )
    
    
    Try
    {
        #Assign Send As Permission
        Write-Host  "INFO:Attempt to assign Send As Permission to On-premise Recipient Object: $SharedMailbox - Trustee: $User" -ForegroundColor White
        Get-Mailbox $SharedMailbox | Add-ADPermission -User $User -ExtendedRights "Send As" -Confirm:$False
        Write-host "Warning: Successfully to assign Send As Permission to On-premise Recipient Object: $SharedMailbox - Trustee: $User" -ForegroundColor Yellow
    }
    
    Catch
    {
        Write-host "Error: Failed to assign Send As Permission to On-premise Recipient Object : $SharedMailbox - Trustee: $User" -ForegroundColor Red
    }
}

Function Convert-EXORemoteUserToSharedMailbox
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$UPN,
        [Parameter(Mandatory = $true,
                   Position = 2)]
        [String]$DC
    )
    
    # Connect-ExchangeOnPremise
    $Recipient = $Null
    $Recipient = Get-Recipient $UPN
    $Name = $Null
    $Name = $Recipient.Name
    $Alias = $Null
    $Alias = $Recipient.Alias
    $SamAccountName = $Null
    $SamAccountName = $Recipient.SamAccountName
    $RecipientTypeDetails = $Null
    $RecipientTypeDetails = $Recipient.RecipientTypeDetails
    
    Write-host "The user:" -NoNewline; Write-host "$Name  (Alias:$Alias) " -NoNewline -ForegroundColor Red; Write-Host "RecipientTypeDetails is: $RecipientTypeDetails"
    $ADUser = $Null
    $ADUser = Get-ADUser -Filter { UserPrincipalName -eq $UPN } -Properties * -Server $DC
    $msExchRemoteRecipientType = $Null
    $msExchRemoteRecipientType = $ADUser.msExchRemoteRecipientType
    Write-host "Before - msExchRemoteRecipientType value is :" -NoNewline; Write-Host "$msExchRemoteRecipientType" -ForegroundColor Yellow
    Set-ADUser -Identity $SamAccountName -Replace @{ msExchRemoteRecipientType = "100" }
    #Sleep 5
    $ADUser2 = $Null
    $ADUser2 = Get-ADUser -Filter { UserPrincipalName -eq $UPN } -Properties * -Server $DC
    $msExchRemoteRecipientType2 = $Null
    $msExchRemoteRecipientType2 = $ADUser2.msExchRemoteRecipientType
    Write-host "After - msExchRemoteRecipientType value is :" -NoNewline; Write-Host "$msExchRemoteRecipientType2" -ForegroundColor Green
}

Function Enable-EXORemoteMailbox
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$TenantName,
        [Parameter(Mandatory = $true,
                   Position = 2)]
        [String]$Domain,
        [Parameter(Mandatory = $true,
                   Position = 3)]
        [String]$DC,
        [Parameter(Mandatory = $true,
                   Position = 4)]
        [String]$SamAccountName
    )
    
    $ADUser = $Null
    $ADUser = Get-ADUser -Identity $SamAccountName -properties * -server $DC
    $mail = $Null
    $mail = $ADUser.mail
    $UserPrincipalName = $Null
    $UserPrincipalName = $ADUser.UserPrincipalName
    $RemoteRoutingAddress = $Null
    $RemoteRoutingAddress = $SamAccountName + "@" + $TenantName + ".mail.onmicrosoft.com"
    Enable-Remotemailbox -Identity $UserPrincipalName -RemoteRoutingAddress $RemoteRoutingAddress -PrimarySmtpAddress $UserPrincipalName -DomainController $DC
    Sleep 2
    Set-RemoteMailbox -Identity $UserPrincipalName -EmailAddressPolicyEnabled $True -DomainController $DC
    Sleep 2
    $RemoteMailbox = Get-RemoteMailbox -Identity $UserPrincipalName -DomainController $DC
    $Primary = $RemoteMailbox.PrimarySmtpAddress
    $LocalPart = $Primary.Substring(0, $Primary.LastIndexOf("@"))
    $NewPrimary = $LocalPart + "@" + $Domain
    Set-RemoteMailbox -Identity $UserPrincipalName -RemoteRoutingAddress $RemoteRoutingAddress -PrimarySmtpAddress $NewPrimary -EmailAddressPolicyEnabled $False -DomainController $DC
}




#endregion