MyPSFunctions.AAD.ps1

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

#region MSOLService
####################################################
################ MSOL Service #######################
###################################################

Function Generate-MSOLServicePrincipalReport
{
    [CmdletBinding()]
    param ()
    
    $ServicePrincipals = Get-MsolServicePrincipal -All
    $Table = $Null
    $Table = @()
    
    foreach ($ServicePrincipal in $ServicePrincipals)
    {
        $ServicePrincipal_Address = $Null
        $ServicePrincipal_Address = $ServicePrincipal.addresses.Address
        $Addresses = $Null
        $Addresses = $ServicePrincipal_Address -join ";"
        $DisplayName = $Null
        $DisplayName = $ServicePrincipal.DisplayName
        $AppPrincipalId = $Null
        $AppPrincipalId = $ServicePrincipal.AppPrincipalId
        $ObjectId = $Null
        $ObjectId = $ServicePrincipal.ObjectId
        $ServicePrincipal_ServicePrincipalNames = $Null
        $ServicePrincipalNames = $Null
        $ServicePrincipal_ServicePrincipalNames = $ServicePrincipal.ServicePrincipalNames
        $ServicePrincipalNames = $ServicePrincipal_ServicePrincipalNames -join ";"
        $TrustedForDelegation = $Null
        $TrustedForDelegation = $ServicePrincipal.TrustedForDelegation
        $Table += New-object PSobject -Property ([Ordered] @{
                DisplayName              = $DisplayName;
                AppPrincipalId          = $AppPrincipalId;
                ObjectId              = $ObjectId;
                Addresses              = $Addresses;
                ServicePrincipalNames = $ServicePrincipalNames;
                TrustedForDelegation  = $TrustedForDelegation;
            })
        
    }
    
    $DateFull = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    $ReportFile = ".\MSOL_ServicesPrincipales_" + $DateFull + ".xlsx"
    $Table | Export-Excel $ReportFile -TableName "MSOLServicePrincipals" -Title "MSOL Service Principals" -TitleBold -WorksheetName "MSOLServicePrincipals" -TableStyle Medium9 -AutoSize -AutoFilter
    Write-log INFO -Message "Generate the following Report: $ReportFile"
    
}

Function Check-MSOLUserMFAEnrolledDevices
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$UPN
    )
    
    $User = Get-MSolUser -UserPrincipalName $UPN
    $User.StrongAuthenticationMethods | Ft MethodType, IsDefault
}

Function Generate-MSOLMFAEnrollmentStatusReport
{
    [CmdletBinding()]
    param ()
    
    $MSOLUsers = Get-MsolUser -All
    [Int]$i = 1
    $Table = $Null
    $Table = @()
    $Count = ($MSOLUsers | Measure).count
    ForEach ($MSOLUser in $MSOLUsers)
    {
        $DisplayName = $Null
        $DisplayName = $MSOLUser.DisplayName
        $UserPrincipalName = $Null
        $UserPrincipalName = $MSOLUser.UserPrincipalName
        $StrongAuthenticationMethods = $Null
        $StrongAuthenticationMethods = $MSOLUser.StrongAuthenticationMethods.methodType -join ","
        
        Write-Log -Level Warning -Message "Analyzing User: --- $i/$Count"
        $Table += New-object PSobject -Property ([Ordered] @{
                DisplayName                    = $DisplayName;
                UserPrincipalName            = $UserPrincipalName;
                StrongAuthenticationMethods = $StrongAuthenticationMethods;
            })
        $i++
    }
    $Table | ft
}

Function Export-MSOLAllLicensedUsers
{
    [CmdletBinding()]
    param ()
    
    # Backup all MSOLUsers
    $MSOLUsers = Get-MsolUser -All
    
    # Backup all Licensed Users
    $MSOLUsers_Licensed = $MSOLUsers | where { $_.IsLicensed -eq "True" }
    
    # Generate Table for licensed Users
    #Initiate the Hash Table
    [Int]$i = 1
    $Table = $Null
    $Table = @()
    $Count = ($MSOLUsers_Licensed | Measure).count
    
    ForEach ($MSOLUser_Licensed in $MSOLUsers_Licensed)
    {
        
        $DisplayName = $Null
        $DisplayName = $MSOLUser_Licensed.DisplayName
        $signinName = $Null
        $signinName = $MSOLUser_Licensed.signinName
        $Title = $Null
        $Title = $MSOLUser_Licensed.Title
        $Department = $Null
        $Department = $MSOLUser_Licensed.Department
        $Office = $Null
        $Office = $MSOLUser_Licensed.Office
        $City = $Null
        $City = $MSOLUser_Licensed.City
        $Country = $Null
        $Country = $MSOLUser_Licensed.Country
        $islicensed = $Null
        $islicensed = $MSOLUser_Licensed.islicensed
        $lastDirsynctime = $Null
        $lastDirsynctime = $MSOLUser_Licensed.lastDirsynctime
        $licenses = $Null
        $licenses = $MSOLUser_Licensed.licenses.AccountSkuId -join ";"
        Write-Log -Level Warning -message "The script is analyzing $DisplayName ($signinName)….. --- $i/$Count"
        
        $Table += New-object PSobject -Property ([Ordered] @{
                DisplayName        = $DisplayName;
                UserName        = $signinName;
                Title            = $Title;
                Department        = $Department;
                Office            = $Office;
                City            = $City;
                Country            = $Country;
                islicensed        = $islicensed;
                lastDirsynctime = $lastDirsynctime;
                licenses        = $licenses;
            })
        
        $i++
    }
    
    $DateFull = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    $ReportFilexlsx = ".\Report_Licensed_Users_" + $DateFull + ".xlsx"
    $Table | Export-Excel $ReportFilexlsx -TableName "LicensedUsers" -Title "Licensed Users" -TitleBold -WorksheetName "LicensedUsers" -TableStyle Medium9 -AutoSize -AutoFilter
    Write-log INFO -Message "Generate the following Report: $ReportFilexlsx"
}
#endregion

#region AAD
####################################################
################ Azure AD ###########################
###################################################

Function Get-AADUserGroupMembership
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$UPN
    )
    
    $AADGroups = Get-AzureADUser -SearchString $UPN | Get-AzureADUserMembership
    
    [Int]$i = 1
    $Table = $Null
    $Table = @()
    $Count = ($AADGroups | Measure).count
    
    ForEach ($AADGroup in $AADGroups)
    {
        $DisplayName = $Null
        $ObjectType = $Null
        $MailEnabled = $Null
        $SecurityEnabled = $Null
        $Mail = $Null
        $DirSyncEnabled = $Null
        $GroupMailenabled = $Null
        $RecipientTypeDetails = $Null
        $GroupMailenabled = $Null
        $DisplayName = $AADGroup.DisplayName
        $ObjectType = $AADGroup.ObjectType
        $MailEnabled = $AADGroup.MailEnabled
        $SecurityEnabled = $AADGroup.SecurityEnabled
        $DirSyncEnabled = $AADGroup.DirSyncEnabled
        $Mail = $AADGroup.Mail
        
        If ($MailEnabled)
        {
            $GroupMailenabled = Get-Recipient $Mail
            $RecipientTypeDetails = $GroupMailenabled.RecipientTypeDetails
        }
        $Table += New-object PSobject -Property ([Ordered] @{
                DisplayName        = $DisplayName;
                ObjectType        = $ObjectType;
                MailEnabled        = $MailEnabled;
                GroupType        = $RecipientTypeDetails;
                SecurityEnabled = $SecurityEnabled;
                DirSyncEnabled  = $DirSyncEnabled;
                Mail            = $Mail;
                
            })
        
        
    }
    $Table | ft
}

Function Check-AADO365GroupCreationSettings
{
    [CmdletBinding()]
    param ()
    
    $GroupUnifiedSetttings = (Get-AzureADDirectorySetting | where { $_.DisplayName -eq "Group.Unified" }).values
    $GroupCreationAllowedGroupId = ($GroupUnifiedSetttings | where { $_.Name -eq "GroupCreationAllowedGroupId" }).Value
    $EnableGroupCreation = ($GroupUnifiedSetttings | where { $_.Name -eq "EnableGroupCreation" }).Value
    $AADGroupName = (Get-AzureADGroup -ObjectId $GroupCreationAllowedGroupId).DisplayName
    Write-Host "Allowed Office 365 Group Creation Name is: " -NoNewline; Write-host "$AADGroupName" -ForegroundColor Yellow
    Write-Host "Office 365 Group creation is enabled: " -NoNewline; Write-host "$EnableGroupCreation" -ForegroundColor Yellow
}

Function Block-AADOffice365GroupCreation
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $false,
                   Position = 1)]
        [String]$AADGroupName
    )
    
    if ($AADGroupName)
    {
        # Check if group exist
        $FoundAADGroup = Get-AzureADGroup -SearchString $AADGroupName
        if (!$FoundAADGroup)
        {
            # Create Group if does not exist
            $NewADGroup = New-AzureADGroup -DisplayName $AADGroupName -MailNickName $AADGroupName -MailEnabled $False -SecurityEnabled $True
            $AADGroupObjectID = $NewADGroup.objectid        
        }        
    }
    Else
    {
        # Check if group exist
        $FoundAADGroup = Get-AzureADGroup -SearchString GroupCreationAllowedGroup
        if (!$FoundAADGroup)
        {
            # Create Group if does not exist
            $NewADGroup = New-AzureADGroup -DisplayName GroupCreationAllowedGroup -MailNickName GroupCreationAllowedGroup -MailEnabled $False -SecurityEnabled $True
            $AADGroupObjectID = $NewADGroup.objectid
            If ($NewADGroup) { Write-Host "The Following Azure AD Group has been created: GroupCreationAllowedGroup" }
        }
        Else { $AADGroupObjectID = $FoundAADGroup.objectid }    
    }
    
    # Update Settings
    $AllowGroupCreation = "False"
    $settingsObjectID = (Get-AzureADDirectorySetting | Where-object -Property Displayname -Value "Group.Unified" -EQ).id
    if (!$settingsObjectID)
    {
        $template = Get-AzureADDirectorySettingTemplate | Where-object { $_.displayname -eq "group.unified" }
        $settingsCopy = $template.CreateDirectorySetting()
        New-AzureADDirectorySetting -DirectorySetting $settingsCopy
        $settingsObjectID = (Get-AzureADDirectorySetting | Where-object -Property Displayname -Value "Group.Unified" -EQ).id
    }
    $settingsCopy = Get-AzureADDirectorySetting -Id $settingsObjectID
    $settingsCopy["EnableGroupCreation"] = $AllowGroupCreation
    
    if ($GroupName)
    {
        $settingsCopy["GroupCreationAllowedGroupId"] = $AADGroupObjectID
    }
    else
    {
        $settingsCopy["GroupCreationAllowedGroupId"] = $GroupName
    }
    Set-AzureADDirectorySetting -Id $settingsObjectID -DirectorySetting $settingsCopy
    
    Check-O365GroupCreationSettings
}

Function Validate-AADCloudOnlyAllOffice365Admins
{
    [CmdletBinding()]
    param ()
    
    $Table = $Null
    $Table = @()
    
    #List of Admins Roles
    $AzureADRoles = $Null
    Try
    {
        $AzureADRoles = Get-AzureADDirectoryRole
        $Status = "Success"
    }
    Catch
    {
        $ErrorMessage = $Error[0].Exception.Message
        $CMDLet = $Error[0].InvocationInfo.Line
        $FailedItem = $Error[0].Exception.ItemName
        Write-Host "Failed to Find the Azure AD Directory Roles" -ForegroundColor Red
        Write-Host "Failed to run the following CMDLet: $CMDLet"
        Write-Host "Failed with Error:$ErrorMessage"
        $Status = "Failed"
    }
    #Analyzing AAD Role members
    Foreach ($AzureADRole in $AzureADRoles)
    {
        $AzureADRole_ObjectID = $Null
        $AzureADRole_ObjectID = $AzureADRole.ObjectID
        $AzureADRole_DisplayName = $Null
        $AzureADRole_DisplayName = $AzureADRole.DisplayName
        $AzureADRoleMembers = $Null
        Try
        {
            $AzureADRoleMembers = Get-AzureADDirectoryRoleMember -objectID $AzureADRole_ObjectID
            foreach ($AzureADRoleMember in $AzureADRoleMembers)
            {
                $AzureADRoleMember_DisplayName = $Null
                $AzureADRoleMember_DisplayName = $AzureADRoleMember.DisplayName
                $AzureADRoleMember_UserPrincipalName = $Null
                $AzureADRoleMember_UserPrincipalName = $AzureADRoleMember.UserPrincipalName
                $AzureADRoleMember_DirSyncEnabled = $Null
                $AzureADRoleMember_DirSyncEnabled = $AzureADRoleMember.DirSyncEnabled
                $AzureADRoleMember_ImmutableId = $Null
                $AzureADRoleMember_ImmutableId = $AzureADRoleMember.ImmutableId
                $AzureADRoleMember_LastDirSyncTime = $Null
                $AzureADRoleMember_LastDirSyncTime = $AzureADRoleMember.LastDirSyncTime
                $AzureADRoleMember_UserType = $Null
                $AzureADRoleMember_UserType = $AzureADRoleMember.UserType
                $CloudOnly = "No"
                # Check if the user is Cloud Only
                If (($AzureADRoleMember_DirSyncEnabled -eq $Null) -and ($AzureADRoleMember_ImmutableId -eq $Null) -and ($AzureADRoleMember_LastDirSyncTime -eq $Null))
                { $CloudOnly = "Yes" }
                $Table += New-object PSobject -Property ([Ordered] @{
                        AzureADRole          = $AzureADRole_DisplayName;
                        DisplayName          = $AzureADRoleMember_DisplayName;
                        UserPrincipalName = $AzureADRoleMember_UserPrincipalName;
                        UserType          = $AzureADRoleMember_UserType;
                        DirSyncEnabled    = $AzureADRoleMember_DirSyncEnabled;
                        ImmutableId          = $AzureADRoleMember_ImmutableId;
                        LastDirSyncTime   = $AzureADRoleMember_LastDirSyncTime;
                        CloudOnly          = $CloudOnly;
                        Status              = "Member found"
                    })
                
            }
        }
        Catch
        {
            $ErrorMessage = $Error[0].Exception.Message
            $CMDLet = $Error[0].InvocationInfo.Line
            $FailedItem = $Error[0].Exception.ItemName
            Write-Host "Failed to get member of the role $AzureADRole_DisplayName" -ForegroundColor Red
            Write-Host "Failed to run the following CMDLet: $CMDLet" -ForegroundColor Red
            Write-Host "Failed with Error:$ErrorMessage" -ForegroundColor Red
            $Table += New-object PSobject -Property ([Ordered] @{
                    AzureADRole          = "Failed to get member";
                    DisplayName          = "Failed to get member";
                    UserPrincipalName = "Failed to get member";
                    DirSyncEnabled    = "Failed to get member";
                    ImmutableId          = "Failed to get member";
                    LastDirSyncTime   = "Failed to get member";
                    CloudOnly          = "Failed to get member";
                    Status              = "Failed to get member";
                })
        }
        
    }
    Return $Table
}

Function Generate-AADRegisteredDevicesReport
{
        Try
        {
            $AllAADUsers = Get-AzureADUser -All:$True
            $AADUsers = $AllAADUsers | Where { ($_.Mail -ne $Null) -and ($_.UserType -eq "Member") }
            $Status = "Successful"
        }
        Catch
        {
            $ErrorMessage = $Error[0].Exception.Message
            $CMDLet = $Error[0].InvocationInfo.Line
            $FailedItem = $Error[0].Exception.ItemName
        Write-Log -Level Error -Message "Failed to Find All Azure AD users"
        Write-Log -Level Error -Message "Failed to run the following CMDLet: $CMDLet"
        Write-Log -Level Error -Message "Failed with Error:$ErrorMessage"
            $Status = "Failed"
        }
        
        If ($Status -eq "Successful")
        {
            #Initiate the Hash Table
            [Int]$i = 1
            $Table = $Null
            $Table = @()
            $Count = ($AADUsers | Measure).count
            
            ForEach ($AADUser in $AADUsers)
            {
                
                $UserPrincipalName = $Null
                $UserPrincipalName = $AADUser.UserPrincipalName
                $ObjectId = $Null
                $ObjectId = $AADUser.ObjectId
                $DisplayName = $Null
                $DisplayName = $AADUser.DisplayName
                $Mail = $Null
                $Mail = $AADUser.Mail
                $UserType = $Null
                $UserType = $AADUser.UserType
                
                Write-Log -Level Warning -message "The script is analyzing $DisplayName ($UserPrincipalName)….. --- $i/$Count"
                #Get Registered Device
                
                Try
                {
                    $RegisteredDevices = $Null
                    $RegisteredDevices = Get-AzureADUserRegisteredDevice -All:$true -ObjectId $ObjectId
                    $StatusDevices = "Successful"
                }
                Catch
                {
                    $ErrorMessage = $Error[0].Exception.Message
                    $CMDLet = $Error[0].InvocationInfo.Line
                    $FailedItem = $Error[0].Exception.ItemName
                Write-Log -Level Error -Message "Failed to Find All Registered Devices"
                Write-Log -Level Error -Message "Failed to run the following CMDLet: $CMDLet"
                Write-Log -Level Error -Message "Failed with Error:$ErrorMessage"
                    $StatusDevices = "Failed"
                }
                
                If ($StatusDevices -eq "Successful")
                {
                    ForEach ($RegisteredDevice in $RegisteredDevices)
                    {
                        $DeviceObjectType = $Null
                        $DeviceObjectType = $RegisteredDevice.ObjectType
                        $ApproximateLastLogonTimeStamp = $Null
                        $ApproximateLastLogonTimeStamp = $RegisteredDevice.ApproximateLastLogonTimeStamp
                        $DeviceDeviceId = $Null
                        $DeviceDeviceId = $RegisteredDevice.DeviceId
                        $DeviceOSVersion = $Null
                        $DeviceOSVersion = $RegisteredDevice.DeviceOSVersion
                        $DeviceOSType = $Null
                        $DeviceOSType = $RegisteredDevice.DeviceOSType
                        $DeviceTrustType = $Null
                        $DeviceTrustType = $RegisteredDevice.DeviceTrustType
                        $DeviceDisplayName = $Null
                        $DeviceDisplayName = $RegisteredDevice.DisplayName
                        $DeviceProfileType = $Null
                        $DeviceProfileType = $RegisteredDevice.ProfileType
                        $Table += New-object PSobject -Property ([Ordered] @{
                                DisplayName          = $DisplayName;
                                UserPrincipalName = $UserPrincipalName;
                                ObjectId          = $ObjectId;
                                Mail              = $Mail;
                                UserType          = $UserType;
                                DeviceDisplayName = $DeviceDisplayName;
                                DeviceObjectType  = $DeviceObjectType;
                                DeviceOSType      = $DeviceOSType;
                                DeviceOSVersion   = $DeviceOSVersion;
                                DeviceTrustType   = $DeviceTrustType;
                                DeviceProfileType = $DeviceProfileType;
                            })
                    }
                }
                
                $i++
            }
        }
    $DateFull = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    $ReportFilexlsx = ".\Report_AADRegistedDevices_" + $DateFull + ".xlsx"
    $Table | Export-Excel $ReportFilexlsx -TableName "AADRegisteredDevices" -Title "AAD Registered Devices" -TitleBold -WorksheetName "AADRegisteredDevices" -TableStyle Medium9 -AutoSize -AutoFilter
    Write-log INFO -Message "Generate the following Report: $ReportFilexlsx"

}

Function Generate-AADServicePrincipalsReport
{
    [CmdletBinding()]
    param ()
    
    Try
    {
        # Retreive list of Service Principal
        $AllServicePrincipals = Get-AzureADServicePrincipal -All:$true
        #Initiate the Hash Table
        $Table = $Null
        $Table = @()
        
        Foreach ($ServicePrincipal in $AllServicePrincipals)
        {
            
            $ServicePrincipal_ObjectID = $Null
            $ServicePrincipal_ObjectID = $ServicePrincipal.ObjectID
            $ServicePrincipal_AppRoleAssignmentRequired = $Null
            $ServicePrincipal_AppRoleAssignmentRequired = $ServicePrincipal.AppRoleAssignmentRequired
            $ServicePrincipal_ObjectType = $Null
            $ServicePrincipal_ObjectType = $ServicePrincipal.ObjectType
            $ServicePrincipal_ServicePrincipalType = $Null
            $ServicePrincipal_ServicePrincipalType = $ServicePrincipal.ServicePrincipalType
            $ServicePrincipal_AccountEnabled = $Null
            $ServicePrincipal_AccountEnabled = $ServicePrincipal.AccountEnabled
            $ServicePrincipal_ReplyUrls = $Null
            $ServicePrincipal_ReplyUrls = $ServicePrincipal.ReplyUrls
            $ServicePrincipal_ReplyUrls = $ServicePrincipal_ReplyUrls -join ";"
            $ServicePrincipal_AppDisplayName = $Null
            $ServicePrincipal_AppDisplayName = $ServicePrincipal.AppDisplayName
            $ServicePrincipal_Oauth2Permissions = $Null
            $ServicePrincipal_Oauth2Permissions = $ServicePrincipal.Oauth2Permissions.Value
            $ServicePrincipal_Oauth2Permissions = $ServicePrincipal_Oauth2Permissions -join ";"
            $ServicePrincipalRoleAssignments = Get-AzureADServiceAppRoleAssignment -ObjectId $ServicePrincipal_ObjectID
            
            Foreach ($ServicePrincipalRoleAssignment in $ServicePrincipalRoleAssignments)
            {
                $ServicePrincipalRoleAssignment_CreationTime = $Null
                $ServicePrincipalRoleAssignment_CreationTime = $ServicePrincipalRoleAssignment.CreationTimestamp
                $ServicePrincipalRoleAssignment_PrincipalDisplayName = $Null
                $ServicePrincipalRoleAssignment_PrincipalDisplayName = $ServicePrincipalRoleAssignment.PrincipalDisplayName
                $ServicePrincipalRoleAssignment_PrincipalID = $Null
                $ServicePrincipalRoleAssignment_PrincipalID = $ServicePrincipalRoleAssignment.PrincipalID
                $ServicePrincipalRoleAssignment_PrincipalType = $Null
                $ServicePrincipalRoleAssignment_PrincipalType = $ServicePrincipalRoleAssignment.PrincipalType
                
                Try
                {
                    $AADObject = $Null
                    $AADObject = Get-AzureADObjectByObjectId -ObjectIds $ServicePrincipalRoleAssignment_PrincipalID
                    $ServicePrincipalRoleAssignment_PrincipalUPN = $Null
                    $ServicePrincipalRoleAssignment_PrincipalUPN = $AADObject.USerPrincipalName
                    
                }
                Catch
                {
                    $ErrorMessage = $Error[0].Exception.Message
                    $CMDLet = $Error[0].InvocationInfo.Line
                    $FailedItem = $Error[0].Exception.ItemName
                    Write-Log -Level Error -Message "Failed to Find Service Principal UPN"
                    Write-Log -Level Error -Message "Failed to run the following CMDLet: $CMDLet"
                    Write-Log -Level Error -Message "Failed with Error:$ErrorMessage"
                    $ServicePrincipalRoleAssignment_PrincipalUPN = "Failed to Find forObjectID: $ServicePrincipalRoleAssignment_PrincipalID "
                }
                
                
                
                
                
                $Table += New-object PSobject -Property ([Ordered] @{
                        ServicePrincipal_AppDisplayName                        = $ServicePrincipal_AppDisplayName;
                        ServicePrincipal_ObjectID                            = $ServicePrincipal_ObjectID;
                        ServicePrincipal_ObjectType                            = $ServicePrincipal_ObjectType;
                        ServicePrincipal_ServicePrincipalType                = $ServicePrincipal_ServicePrincipalType;
                        ServicePrincipal_AccountEnabled                        = $ServicePrincipal_AccountEnabled;
                        ServicePrincipal_AppRoleAssignmentRequired            = $ServicePrincipal_AppRoleAssignmentRequired;
                        ServicePrincipal_ReplyUrls                            = $ServicePrincipal_ReplyUrls;
                        ServicePrincipal_Oauth2Permissions                    = $ServicePrincipal_Oauth2Permissions;
                        ServicePrincipalRoleAssignment_CreationTime            = $ServicePrincipalRoleAssignment_CreationTime;
                        ServicePrincipalRoleAssignment_PrincipalDisplayName = $ServicePrincipalRoleAssignment_PrincipalDisplayName;
                        ServicePrincipalRoleAssignment_PrincipalUPN            = $ServicePrincipalRoleAssignment_PrincipalUPN;
                        ServicePrincipalRoleAssignment_PrincipalID            = $ServicePrincipalRoleAssignment_PrincipalID;
                        ServicePrincipalRoleAssignment_PrincipalType        = $ServicePrincipalRoleAssignment_PrincipalType;
                    })
                
            }
            
        }
        
    $DateFull = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    $ReportFilexlsx = ".\AzureADServicePrincipals_Report_" + $DateFull + ".xlsx"
    $Table | Export-Excel $ReportFilexlsx -TableName "AADServicePrincipals" -Title "AAD Service Principals" -TitleBold -WorksheetName "AADServicePrincipals" -TableStyle Medium9 -AutoSize -AutoFilter
    Write-log INFO -Message "Generate the following Report: $ReportFilexlsx"
    }
    Catch
    {
        $ErrorMessage = $Error[0].Exception.Message
        $CMDLet = $Error[0].InvocationInfo.Line
        $FailedItem = $Error[0].Exception.ItemName
        Write-Log -Level Error -Message "Failed to Find Azure AD Service Principals"
        Write-Log -Level Error -Message "Failed to run the following CMDLet: $CMDLet"
        Write-Log -Level Error -Message "Failed with Error:$ErrorMessage"
        Exit
    }
    
}

Function Get-AADUserMembership
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$EmailAddress
    )
    
    # Find User DN
    $DN = (Get-Mailbox $EmailAddress).DistinguishedName
    
    # Find Mailbox FullAccess
    Write-Log -Level Warning -Message "Check for FullAccess permission on all Mailboxes:"
    $AllMailboxes = Get-Mailbox -ResultSize Unlimited
    $AllMailboxes | Get-MailboxPermission -User $EmailAddress | ft Identity, User, Trustee, AccessControlType, AccessRights
    # Find Mailbox SendAs
    Write-Log -Level Warning -Message "Check for SendAs permission on all Mailboxes:"
    $AllMailboxes | Get-RecipientPermission -Trustee $EmailAddress | ft Identity, Trustee, AccessControlType, AccessRights
    # Find Mailbox SendOnBehalf
    Write-Log -Level Warning -Message "Check for SendOnBehalf permission on all Mailboxes:"
    $AllMailboxes | Where { $_.GrantSendOnBehalfTo -match "'$EmailAddress'" } | ft DisplayName,PrimarySMTPAddress
    
    # Find DG managedBy
    Write-Log -Level Warning -Message "Check for FullAccess permission on all DGs:"
    Get-DistributionGroup -Filter "ManagedBy -eq '$DN'"
}

Function Validate-AADUserMembership
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [string]$UPN,
        [Parameter(Mandatory = $true,
                   Position = 2)]
        [string]$GroupName
    )
    
    $AADUser = Get-AzureADUser -Filter "userPrincipalName eq '$UPN'"
    $AADUser_DisplayName = $AADUser.DisplayName
    $AADUser_ObjectID = $AADUser.ObjectID
    $AADGroup = Get-AzureADGroup -Filter "DisplayName eq '$($Name)'"
    $AADGroupID = $AADGroup.ObjectID
    $GroupMembership = Get-AzureADUserMembership -ObjectId $AADUser_ObjectID
    
    # check if member:
    $FoundGroupMembershipCount = (($GroupMembership | where { $_.ObjectId -like $AADGroupID }) | Measure).count
    If ($FoundGroupMembershipCount -eq 1)
    {
        Write-Log -Level Warning -Message "The user $AADUser_DisplayName ($UPN) is member of $GroupName"
    }
    Else
    {
        Write-Log -Level Error -Message "The user $AADUser_DisplayName ($UPN) is NOT member of $GroupName"
    }
}

Function Get-AADGroupMember
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$Name
    )
    
    $AADGroup = $Null
    $AADGroupID = $Null
    $AADGroup = Get-AzureADGroup -Filter "DisplayName eq '$($Name)'" 
    $AADGroupID = $AADGroup.ObjectID
    Write-Host "Search for the Member of the following group:$Name ($AADGroupID) "
    Get-AzureADGroupMember -ObjectId $AADGroupID -All $true
}

Function Compare-AADGroupMembershipOfTwoGroups
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [string]$GroupName1,
        [Parameter(Mandatory = $true,
                   Position = 2)]
        [string]$GroupName2
    )
    [Int]$i = 1
    $Table = $Null
    $Table = @()
    
    
    $AADGroup1 = Get-AzureADGroup -SearchString $groupName1
    $AADGroup1_ObjectID = $AADGroup1.ObjectID
    $AADGroup1Members = Get-AzureADGroupMember -ObjectId $AADGroup1_ObjectID -All:$True
    
    $AADGroup2 = Get-AzureADGroup -SearchString $GroupName2
    $AADGroup2_ObjectID = $AADGroup2.ObjectID
    $Count = ($AADGroup1Members | Measure).count
    
    foreach ($AADGroup1Member in $AADGroup1Members)
    {
        $UserprincipalName = $Null
        $UserprincipalName = $AADGroup1Member.UserprincipalName
        Write-Log -Level Warning -message "The script is analyzing $UserprincipalName….. --- $i/$Count"
        $AADUserMembership = $Null
        $AADUserMembership = Get-AzureADUserMembership -ObjectId $UserprincipalName
        $MembershipFound = $Null
        $MembershipFound = $AADUserMembership | where{ $_.ObjectID -eq $AADGroup2_ObjectID }
        
        if ($MembershipFound) { $Found = $True }
        Else { $Found = $False }
        
        $Table += New-object PSobject -Property ([Ordered] @{
                UserprincipalName = $UserprincipalName;
                Members              = $Found;
            })
        
        $i++
        
    }
    Return $Table
}

Function HardMatch-AADDuplicateCloudAccount
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$OnpremiseUPN,
        [Parameter(Mandatory = $true,
                   Position = 2)]
        [String]$CloudUPN
    )
    Read-Host "Please validate you are connect to Azure AD powershell module"
    #Retreive AAD users Info
    Write-Log -Level INFO -message "The Hard Match need to happens between to AD connect Sync cycle, please find the next:"
    Check-ADConnectLastSync
    Read-Host "Pause to check Last and Next AD Connect Sync"
    
    Try
    {
        Write-Log -Level INFO -message "Retreiving AAD information about $OnpremiseUPN & $CloudUPN from AAD"
        $Cloud_AADUser = Get-azureaduser -SearchString $CloudUPN
        $Onpremise_AADUser = Get-azureaduser -SearchString $OnpremiseUPN
        Write-Log -Level warning -message "Retreived AAD information about $OnpremiseUPN & $CloudUPN from AAD"
    }
    Catch
    {
        $ErrorMessage = $Error[0].Exception.Message
        $CMDLet = $Error[0].InvocationInfo.Line
        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 "Failed to retreive AAD Users information"
        Exit
    }
    # Variable
    $OnpremiseObjectID = $Onpremise_AADUser.Objectid
    $OnpremiseImmutableID = $Onpremise_AADUser.immutableID
    $CloudObjectID = $Cloud_AADUser.Objectid
    Write-Log -Level INFO -message "$CloudUPN has the following ObjectID: $CloudObjectID"
    Write-Log -Level INFO -message "$OnpremiseUPN has the following ObjectID: $OnpremiseObjectID"
    Write-Log -Level INFO -message "$OnpremiseUPN has the following immutableID: $OnpremiseImmutableID"
    Read-Host "Pause after collecting required data - Continue to permanent deleted Onpremise Account $OnpremiseUPN"
    
    # Delete OnpremiseAccount
    Try
    {
        Write-Log -Level INFO -message "Removing $OnpremiseUPN from AAD"
        Remove-AzureADUser -ObjectId $OnpremiseObjectID
        Sleep 10
        Remove-AzureADMSDeletedDirectoryObject -Id $OnpremiseObjectID
        Sleep 10
        Write-Log -Level warning -message "Removed $OnpremiseUPN from AAD"
    }
    Catch
    {
        $ErrorMessage = $Error[0].Exception.Message
        $CMDLet = $Error[0].InvocationInfo.Line
        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 "Failed to remove $OnpremiseUPN from AAD"
        Exit
    }
    #Update ImmutableID
    Try
    {
        Write-Log -Level INFO -message "updating ImmutableID for $OnpremiseUPN"
        Set-AzureADUser -ObjectId $CloudObjectID -ImmutableId $OnpremiseImmutableID
        Write-Log -Level warning -message "updated ImmutableID for $OnpremiseUPN"
    }
    Catch
    {
        $ErrorMessage = $Error[0].Exception.Message
        $CMDLet = $Error[0].InvocationInfo.Line
        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 "Failed to update ImmutableID for $OnpremiseUPN"
    }
    Sleep 10
    # Set immutableID
    Try
    {
        Write-Log -Level INFO -message "Update Cloud User UPN ($CloudUPN) to $OnpremiseUPN"
        Set-AzureADUser -ObjectId $CloudObjectID -UserPrincipalName $OnpremiseUPN
        Write-Log -Level warning -message "Updated Cloud User UPN ($CloudUPN) to $OnpremiseUPN"
    }
    Catch
    {
        $ErrorMessage = $Error[0].Exception.Message
        $CMDLet = $Error[0].InvocationInfo.Line
        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 "Failed to Update Cloud User UPN ($CloudUPN) to $OnpremiseUPN"
    }
    
    # Display Immutable ID:
    $AADUserAfter = Get-azureaduser -SearchString $OnpremiseUPN
    $AADUser_ObjectID = $AADUserAfter.Objectid
    $AADUser_ImmutableID = $AADUserAfter.immutableID
    Write-Log -Level warning -message "The Onpremise User: UPN:$OnpremiseUPN - ObjectID: $OnpremiseObjectID - ImmutableID: $OnpremiseImmutableID"
    Write-Log -Level warning -message "The Cloud User: UPN:$OnpremiseUPN (old UPN: $CloudUPN) - ObjectID: $AADUser_ObjectID - ImmutableID: $AADUser_ImmutableID"
}

Function Find-AADApplication
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$Name
    )
    
    Get-AzureADApplication -All:$True | where { $_.DisplayName -like "*$Name*" } | select DisplayName, ReplyUrls, ObjectId, AppId
}

Function Update-ADDynamicGroupMember
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$Name
    )
    
    $AzureADGroup = Get-AzureADGroup -SearchString $Name
    $AzureADGroupID = $AzureADGroup.ObjectId
    Get-AzureADMSGroup -Id $AzureADGroupID | select DisplayName, MembershipRuleProcessingState, GroupTypes, MembershipRule
    Write-Host "The Function will paused the Rule Processing" -ForegroundColor Red
    Set-AzureADMSGroup -Id $AzureADGroupID -MembershipRuleProcessingState "Paused"
    Get-AzureADMSGroup -Id $AzureADGroupID | select DisplayName, MembershipRuleProcessingState
    Write-Host "The Function will paused the Rule Processing" -ForegroundColor Green
    Set-AzureADMSGroup -Id $AzureADGroupID -MembershipRuleProcessingState "On"
    Get-AzureADMSGroup -Id $AzureADGroupID | select DisplayName, MembershipRuleProcessingState
    Write-Host "Wait 15 min for Azure AD to process the Rule Membership of this Group" -ForegroundColor Yellow
}

Function Update-ADUserPasswordNeverExpires
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$UPN,
        [Parameter(Position = 2)]
        [switch]$Enable,
        [Parameter(Position = 3)]
        [switch]$Disable
    )
    # Check Status before :
    $BeforePasswordNeverExpires = $Null
    $BeforePasswordNeverExpires = Get-AzureADUser -ObjectId $UPN | Select-Object UserprincipalName, @{ N = "PasswordNeverExpires"; E = { $_.PasswordPolicies -contains "DisablePasswordExpiration" } }
    Write-Host "Password Never Expires settings for " -NoNewline; Write-Host "$UPN " -ForegroundColor Red -NoNewline; Write-Host "(After):" -ForegroundColor Green
    $BeforePasswordNeverExpires | ft
    
    If ($Enable)
    { Set-AzureADUser -ObjectId $UPN -PasswordPolicies DisablePasswordExpiration }
    If ($Disable)
    { Set-AzureADUser -ObjectId $UPN -PasswordPolicies None }
    # Check Status After:
    $AfterPasswordNeverExpires = $Null
    $AfterPasswordNeverExpires = Get-AzureADUser -ObjectId $UPN | Select-Object UserprincipalName, @{ N = "PasswordNeverExpires"; E = { $_.PasswordPolicies -contains "DisablePasswordExpiration" } }
    Write-Host "Password Never Expires settings for " -NoNewline; Write-Host "$UPN " -ForegroundColor Red -NoNewline; Write-Host "(After):" -ForegroundColor Yellow
    $AfterPasswordNeverExpires | ft
}

Function Get-AADUserDirectReport
{
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [string]$Identity
    )
    #Search for Azure AD Connect
    $AzureADUser = Get-AzureADUser -SearchString $Identity | select -First 1
    $ObjectID = $Null
    $ObjectID = $AzureADUser.ObjectID
    $DisplayName = $Null
    $DisplayName = $AzureADUser.DisplayName
    $UPN = $Null
    $UPN = $AzureADUser.UserPrincipalName
    Write-Host "The script found user with: DisplayName: $DisplayName and with UPN: $UPN - ObjectID: $ObjectID"
    
    # Check User Direct Report
    $DirectReport = $Null
    $DirectReport = Get-AzureADUserDirectReport -ObjectId $ObjectID
    $DirectReport | Ft DisplayName, UserPrincipalName, ObjectID
}

Function Get-AADGroupMembersDetails
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$GroupName
    )
    
    $AAGroup = Get-AzureADGroup -SearchString $GroupName
    $AADGroup_ObjectID = $AAGroup.ObjectID
    $AADGroupMembers = Get-AzureADGroupMember -ObjectId $AADGroup_ObjectID -All:$true
    [Int]$i = 1
    $Table = $Null
    $Table = @()
    $Count = ($AADGroupMembers | Measure).count
    
    
    ForEach ($AADGroupMember in $AADGroupMembers)
    {
        $UserPrincipalName = $Null
        $UserPrincipalName = $AADGroupMember.UserPrincipalName
        $DisplayName = $Null
        $DisplayName = $AADGroupMember.DisplayName
        $Recipient = $Null
        $Recipient = Get-Recipient $UserPrincipalName
        Write-Log -Level Warning -message "The script is analyzing $DisplayName ($UserPrincipalName)….. --- $i/$Count"
        $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] @{
            FirstName = $FirstName;
            LastName = $LastName;
            UserPrincipalName = $UserPrincipalName;
            Department = $Department;
            City = $City;
            Office = $Office;
            Title = $Title;
            CustomAttribute5 = $CustomAttribute5;
            CustomAttribute7 = $CustomAttribute7;
            CustomAttribute13 = $CustomAttribute13;
            CustomAttribute14 = $CustomAttribute14;
            CustomAttribute15 = $CustomAttribute15;
        })
        
        $i++
    }
    $DateFull = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    $ReportFilexlsx = ".\Report_Users_" + $DateFull + ".xlsx"
    $Table | Export-Excel $ReportFilexlsx -TableName "Users" -Title "Users" -TitleBold -WorksheetName "Users" -TableStyle Medium9 -AutoSize -AutoFilter
    Write-log INFO -Message "Generate the following Report: $ReportFilexlsx"
}

Function Add-AADUserToAADGroup
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$GroupName,
        [Parameter(Mandatory = $true,
                   Position = 2)]
        [String]$UserEmailAddress
    )
    
    $AADGroup = Get-AzureADGroup -SearchString $GroupName
    $AADGroup = $AADGroup | where { $_.DisplayName -eq $GroupName }
    $AADGroup_ObjectID = $AADGroup.ObjectID
    $AADUser = Get-AzureADUser -Filter "userPrincipalName eq '$UserEmailAddress'"
    $AADUser_DisplayName = $AADUser.DisplayName
    $AADUser_ObjectID = $AADUser.ObjectID
    Try
    {
        Add-AzureADGroupMember -ObjectId $AADGroup_ObjectID -RefObjectId $AADUser_ObjectID
        $Status = "Success"
    }
    Catch
    {
        $ErrorMessage = $Error[0].Exception.Message
        If ($ErrorMessage -like "*members*")
        { $Status = "Failed - already members" }
        Else { $Status = "Failed - $ErrorMessage " }
        
    }
    
    $OutPutMessage = $null
    $OutPutMessage = @()
    $OutPutMessage += New-object PSobject -Property ([Ordered] @{
        EmailAddress = $UserEmailAddress;
        Group = $GroupName;
        Action = "Add";
        Status = $Status;
    })
    Return $OutPutMessage
    
}

Function Add-AADUserToAADGroupCSV
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [string]$GroupName,
        [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 $GroupName --- $i/$Count"
        $UserOutput = $Null
        $UserOutput = @()
        $UserOutput = Add-AADUserToAADGroup -GroupName $GroupName -UserEmailAddress $UserEmailAddress
        If ($UserOutput.Status -like "*Failed*")
        { $Color = "Red" }
        Else { $Color = "Green" }
        Write-Host "Script try to add: $UserEmailAddress to $GroupName - Status: " -NoNewline; write-host $UserOutput.Status -ForegroundColor $Color
        $Table += New-object PSobject -Property ([Ordered] @{
            GroupName = $GroupName;
            UserName = $UserEmailAddress;
            Action = $UserOutput.Action;
            Status = $UserOutput.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 Remove-AADUserToAADGroup
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$GroupName,
        [Parameter(Mandatory = $true,
                   Position = 2)]
        [String]$UserEmailAddress
    )
    
    $AADGroup = Get-AzureADGroup -SearchString $GroupName
    $AADGroup = $AADGroup | where { $_.DisplayName -eq $GroupName }
    $AADGroup_ObjectID = $AADGroup.ObjectID
    $AADUser = Get-AzureADUser -Filter "userPrincipalName eq '$UserEmailAddress'"
    $AADUser_DisplayName = $AADUser.DisplayName
    $AADUser_ObjectID = $AADUser.ObjectID
    Try
    {
        Remove-AzureADGroupMember -ObjectId $AADGroup_ObjectID -MemberId $AADUser_ObjectID
        $Status = "Success"
    }
    Catch
    {
        $ErrorMessage = $Error[0].Exception.Message
        If ($ErrorMessage -like "*Request_ResourceNotFound*")
        { $Status = "Failed - Not member" }
        Else { $Status = "Failed - $ErrorMessage " }
        
    }
    
    $OutPutMessage = $null
    $OutPutMessage = @()
    $OutPutMessage += New-object PSobject -Property ([Ordered] @{
        EmailAddress = $UserEmailAddress;
        Group = $GroupName;
        Action = "Remove";
        Status = $Status;
    })
    Return $OutPutMessage
    
}

Function Remove-AADUserToAADGroupCSV
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [string]$GroupName,
        [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 removed to Group $GroupName --- $i/$Count"
        $UserOutput = $Null
        $UserOutput = @()
        $UserOutput = Remove-AADUserToAADGroup -GroupName $GroupName -UserEmailAddress $UserEmailAddress
        If ($UserOutput.Status -like "*Failed*")
        { $Color = "Red" }
        Else { $Color = "Green" }
        
        Write-Host "Script try to remove: $UserEmailAddress to $GroupName - Status: " -NoNewline; write-host $UserOutput.Status -ForegroundColor $Color
        $Table += New-object PSobject -Property ([Ordered] @{
            GroupName = $GroupName;
            UserName = $UserEmailAddress;
            Action = $UserOutput.Action;
            Status = $UserOutput.Status;
        })
        
        $i++
    }

    $DateFull = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    $ReportFilexlsx = ".\Report_Users_Removed_To_" + $GroupName + "_" + $DateFull + ".xlsx"
    $Table | Export-Excel $ReportFilexlsx -TableName "RemovedUsers" -Title "Removed Users" -TitleBold -WorksheetName "RemovedUsers" -TableStyle Medium9 -AutoSize -AutoFilter
    Write-log INFO -Message "Generate the following Report: $ReportFilexlsx"
}

Function Add-AADUsersToAADGroupFromCSV
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$GroupName,
        [Parameter(Mandatory = $true,
                   Position = 2)]
        [String]$CSVfile
    )
    Read-Host "Expected CSV Column: PrimaryEmailAddress"
    $Users = Import-Csv $CSVfile
    Foreach ($User in $Users)
    {
        $Primary = $Null
        $Primary = $User.PrimaryEmailAddress
        $Recipient = Get-recipient $Primary
        $WindowsLiveID = $Null
        $WindowsLiveID = $Recipient.WindowsLiveID
        Add-AADUserToAADGroup -GroupName $GroupName -UserEmailAddress $WindowsLiveID
    }
}

Function Export-AADGroupMembers
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$SourceGroupName
    )
    
    $SourceAADGroup = Get-AzureADGroup -SearchString $SourceGroupName
    $SourceGroupID = $SourceAADGroup.ObjectID
    $SourceGroupMembers = Get-AzureADGroupMember -ObjectId $SourceGroupID -All:$True
    $DateFull = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    $SourceGroupMembersFile = ".\Report_Members_Of_" + $SourceGroupName + "_" + $DateFull + ".xlsx"
    $SourceGroupMembers | select DisplayName, UserPrincipalName | Export-Excel $SourceGroupMembersFile -TableName "MemberOf" -Title "MemberOf" -TitleBold -WorksheetName "MemberOf" -TableStyle Medium9 -AutoSize -AutoFilter
    Write-Host "Generate the following Report: $SourceGroupMembersFile"
}

Function Get-AADUserPasswordNeverExpires
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [string]$UPN
    )
    $PasswordNeverExpires = $Null
    $PasswordNeverExpires = Get-AzureADUser -ObjectId $UPN | Select-Object UserprincipalName, @{ N = "PasswordNeverExpires"; E = { $_.PasswordPolicies -contains "DisablePasswordExpiration" } }
    $PasswordNeverExpires | ft
}

Function Revoke-AADToken
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [string]$UPN
    )
    $User = Get-AzureADUser -ObjectId $UPN
    $DisplayName = $User.DisplayName
    $ObjectID = $User.ObjectID
    Write-Host "the script find the user: $DisplayName (UPN:$UPN) with the following ObjectID: $ObjectID"
    Read-Host "Are you sure you want to revoke all Azure Tokens of $DisplayName? Press Any Key to continue or CTRL+C to Cancel"
    Revoke-AzureADUserAllRefreshToken -ObjectId $ObjectID
    Write-Host "The script Revoke the Token for $UPN "
}

Function Disable-AADAccount
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [string]$UPN
    )
    # Find User
    Try
    {
        $User = Get-AzureADUser -ObjectId $UPN
        $DisplayName = $User.DisplayName
        $ObjectID = $User.ObjectID
        Write-Host "The script find the user: $DisplayName (UPN:$UPN) with the following ObjectID: $ObjectID" -ForegroundColor Green
        Read-Host "Are you sure you want to Disable the AAD Account & revoke all Azure Tokens of $DisplayName? Press Any Key to continue or CTRL+C to Cancel"
    }
    Catch
    { $ErrorMessage = $Error[0].Exception.Message; Write-Host "Failed with Error:$ErrorMessage" -ForegroundColor Red }
    
    # Disable AAD Account
    Try
    {
        Set-AzureADUser -ObjectId $UPN -AccountEnabled $false
        Write-Host "The script disabled AAD Account $UPN" -ForegroundColor green
    }
    Catch
    { $ErrorMessage = $Error[0].Exception.Message; Write-Host "Failed with Error:$ErrorMessage" -ForegroundColor Red }
    
    # Revoke AAD Tokens
    Try
    {
        Revoke-AzureADUserAllRefreshToken -ObjectId $ObjectID
        Write-Host "The script revoke all tokens for $UPN" -ForegroundColor Green
    }
    Catch
    { $ErrorMessage = $Error[0].Exception.Message; Write-Host "Failed with Error:$ErrorMessage" -ForegroundColor Red }
    
    
}

Function Report-AADLicenseM365E3Group
{
    [CmdletBinding()]
    param ()
    
    Try
    {
        # Get All users who has M365E3 licenses
        $AllLicensedAADUsersCount = $Null
        $AllAzureADUsers = $Null
        $AllLicensedAADUsers = Get-AzureADUser -All: $True | where { $_.AssignedLicenses.Skuid -eq "05e9a617-0261-4cee-bb44-138d3ef5d965" }
        $AllLicensedAADUsersCount = ($AllLicensedAADUsers | Measure).count
        Write-Log -Level info -Message "AAD Users Found: $AllLicensedAADUsersCount"
        # Collect members of SG-ICTD-LIC-M365 Baseline
        $Members_Of_SG_ICTD_LIC_M365_Baseline = Get-AzureADGroupMember -All:$True -ObjectId "3c7418ca-5e15-495d-95ec-203c996e3551"
        $Members_Of_SG_ICTD_LIC_M365_BaselineCount = ($Members_Of_SG_ICTD_LIC_M365_Baseline | Measure).count
        Write-Log -Level info -Message "Members Of SG_ICTD_LIC_M365_Baseline Found: $Members_Of_SG_ICTD_LIC_M365_BaselineCount"
        # Collect members of SG-ICTD-LIC-M365 Baseline No MyAnalitics
        $Members_Of_SG_ICTD_LIC_M365_Baseline_No_MyAnalitics = Get-AzureADGroupMember -All:$True -ObjectId "0c17c388-60c2-401e-b624-98ad10e10084"
        $Members_Of_SG_ICTD_LIC_M365_Baseline_No_MyAnaliticsCount = ($Members_Of_SG_ICTD_LIC_M365_Baseline_No_MyAnalitics | Measure).count
        Write-Log -Level info -Message "Members Of SG_ICTD_LIC_M365_Baseline_No_MyAnalitics Found: $Members_Of_SG_ICTD_LIC_M365_Baseline_No_MyAnaliticsCount"
        # Collect members of SG-ICTD-M365 Rooms
        $Members_Of_SG_ICTD_LIC_M365_Rooms = Get-AzureADGroupMember -All:$True -ObjectId "1eb5c497-be2e-4413-9ed4-1da20e9e58ac"
        $Members_Of_SG_ICTD_LIC_M365_RoomsCount = ($Members_Of_SG_ICTD_LIC_M365_Rooms | Measure).count
        Write-Log -Level info -Message "Members Of SG_ICTD_LIC_M365_Rooms Found: $Members_Of_SG_ICTD_LIC_M365_RoomsCount"
    }
    Catch
    {
        $ErrorMessage = $Error[0].Exception.Message
        $CMDLet = $Error[0].InvocationInfo.Line
        $FailedItem = $Error[0].Exception.ItemName
        Write-Log -Level Error -Message "Failed to collect information about all Azure AD Users"
        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 ($LicensedAADUser in $AllLicensedAADUsers)
    {
        $UPN = $Null
        $UPN = $LicensedAADUser.UserPrincipalName
        Write-Log -Level Warning -message "The script is analyzing $UPN….. --- $i/$AllLicensedAADUsersCount"
        # Check if the user is licensed for E1:
        If ($LicensedAADUser.AssignedLicenses.Skuid -eq "18181a46-0d4e-45cd-891e-60aabd171b4e") { $LicensedOffice365E1 = $True }
        Else { $LicensedOffice365E1 = $False }
        
        # Check member of SG_ICTD_LIC_M365_Baseline
        Try
        {
            $Member_Of_SG_ICTD_LIC_M365_Baseline = $false
            $M365_BaselineFounds = $Null
            $M365_BaselineCount = $Null
            $M365_BaselineFounds = $Members_Of_SG_ICTD_LIC_M365_Baseline | where { $_.UserPrincipalName -eq $UPN }
            $M365_BaselineCount = ($M365_BaselineFounds | Measure).count
            If ($M365_BaselineCount -ge 1)
            {
                Write-Log -Level Warning -Message "$UPN is member of SG_ICTD_LIC_M365_Baseline"
                $Member_Of_SG_ICTD_LIC_M365_Baseline = $True
            }
        }
        Catch
        {
            $ErrorMessage = $Error[0].Exception.Message
            $CMDLet = $Error[0].InvocationInfo.Line
            $FailedItem = $Error[0].Exception.ItemName
            Write-Log -Level Error -Message "Failed to Get Member"
            Write-Log -Level Error -Message "Failed to run the following CMDLet: $CMDLet"
            Write-Log -Level Error -Message "Failed with Error:$ErrorMessage"
            $Member_Of_SG_ICTD_LIC_M365_Baseline = "Failed - $ErrorMessage"
            
        }
        # Check member of SG_ICTD_LIC_M365_Baseline_No_MyAnalitics
        Try
        {
            $Member_Of_SG_ICTD_LIC_M365_Baseline_No_MyAnalitics = $false
            $M365_Baseline_No_MyAnaliticsFounds = $Null
            $M365_Baseline_No_MyAnaliticsCount = $Null
            $M365_Baseline_No_MyAnaliticsFounds = $Members_Of_SG_ICTD_LIC_M365_Baseline_No_MyAnalitics | where { $_.UserPrincipalName -eq $UPN }
            $M365_Baseline_No_MyAnaliticsCount = ($M365_Baseline_No_MyAnaliticsFounds | Measure).count
            If ($M365_Baseline_No_MyAnaliticsCount -ge 1)
            {
                Write-Log -Level Warning -Message "$UPN is member of SG_ICTD_LIC_M365_Baseline_No_MyAnalitics"
                $Member_Of_SG_ICTD_LIC_M365_Baseline_No_MyAnalitics = $True
            }
        }
        Catch
        {
            $ErrorMessage = $Error[0].Exception.Message
            $CMDLet = $Error[0].InvocationInfo.Line
            $FailedItem = $Error[0].Exception.ItemName
            Write-Log -Level Error -Message "Failed to Get Member"
            Write-Log -Level Error -Message "Failed to run the following CMDLet: $CMDLet"
            Write-Log -Level Error -Message "Failed with Error:$ErrorMessage"
            $Member_Of_SG_ICTD_LIC_M365_Baseline_No_MyAnalitics = "Failed - $ErrorMessage"
            
        }
        # Check member of SG_ICTD_LIC_M365_Rooms
        Try
        {
            $Member_Of_SG_ICTD_LIC_M365_Rooms = $false
            $M365_RoomsFounds = $Null
            $M365_RoomsCount = $Null
            $M365_RoomsFounds = $Members_Of_SG_ICTD_LIC_M365_Rooms | where { $_.UserPrincipalName -eq $UPN }
            $M365_RoomsCount = ($M365_RoomsFounds | Measure).count
            If ($M365_RoomsCount -ge 1)
            {
                Write-Log -Level Warning -Message "$UPN is member of SG_ICTD_LIC_M365_Baseline"
                $Member_Of_SG_ICTD_LIC_M365_Rooms = $True
            }
        }
        Catch
        {
            $ErrorMessage = $Error[0].Exception.Message
            $CMDLet = $Error[0].InvocationInfo.Line
            $FailedItem = $Error[0].Exception.ItemName
            Write-Log -Level Error -Message "Failed to Get Member"
            Write-Log -Level Error -Message "Failed to run the following CMDLet: $CMDLet"
            Write-Log -Level Error -Message "Failed with Error:$ErrorMessage"
            $Member_Of_SG_ICTD_LIC_M365_Rooms = "Failed - $ErrorMessage"
            
        }
        
        
        $Table += New-object PSobject -Property ([Ordered] @{
                UPN                                                   = $UPN;
                Member_Of_SG_ICTD_LIC_M365_Baseline                   = $Member_Of_SG_ICTD_LIC_M365_Baseline;
                Member_Of_SG_ICTD_LIC_M365_Baseline_No_MyAnalitics = $Member_Of_SG_ICTD_LIC_M365_Baseline_No_MyAnalitics;
                Member_Of_SG_ICTD_LIC_M365_Rooms                   = $Member_Of_SG_ICTD_LIC_M365_Rooms;
                LicensedOffice365E1                                   = $LicensedOffice365E1;
            })
        
        $i++
    }
    # Generate a Table based check if user are members of any Baseline Group
    $DateFull = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    $ReportFilexlsx = ".\Report_Licensed_Users_" + $DateFull + ".xlsx"
    $Table | Export-Excel $ReportFilexlsx -TableName "LicensedUsers" -Title "Licensed Users" -TitleBold -WorksheetName "LicensedUsers" -TableStyle Medium9 -AutoSize -AutoFilter
    Write-log INFO -Message "Generate the following Report: $ReportFilexlsx"
}

Function Collect-AADLicensedUsersDetails_fromGroup
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$GroupName
    )
    
    # Find GroupID
    Try
    {
        Write-Log -Level Info -Message "Searching for group with Name: $GroupName"
        $GroupNames = $Null
        $GroupNames = Get-AzureADGroup -SearchString $GroupName
        $GroupID = $Null
        $GroupID = ($GroupNames | where { $_.DisplayName -eq $GroupName }).ObjectId
        Write-Log -Level warning -Message "Find the group with Name: $GroupName (ObjectID: $GroupID)"
        
        # Retrieve Group Members
        Try
        {
            Write-Log -Level Info -Message "Retrieving Group member of $GroupName (ObjectID: $GroupID)"
            $GroupMembers = $Null
            $GroupMembers = Get-AzureADGroupMember -ObjectId $GroupID -All $True
            $GroupMembersCount = ($GroupMembers | Measure).count
            Write-Log -Level info -Message "Number of Group member of $GroupName (ObjectID: $GroupID): $GroupMembersCount"
            #Initiate the Hash Table
            [Int]$i = 1
            $Table = $Null
            $Table = @()
            
        }
        Catch
        {
            $ErrorMessage = $Error[0].Exception.Message
            $CMDLet = $Error[0].InvocationInfo.Line
            $FailedItem = $Error[0].Exception.ItemName
            Write-Log -Level Error -Message "Failed to find AAD Group with the following Name : $GroupName"
            Write-Log -Level Error -Message "Failed to run the following CMDLet: $CMDLet"
            Write-Log -Level Error -Message "Failed with Error:$ErrorMessage"
            
        }
        # format Data
        Foreach ($GroupMember in $GroupMembers)
        {
            #Clear Variable
            $Mail = $Null
            $DisplayName = $Null
            $JobTitle = $Null
            $Country = $Null
            $Department = $Null
            $City = $Null
            $CompanyName = $Null
            $UsageLocation = $Null
            $UserPrincipalName = $Null
            $PERNR = $Null
            $StaffLevel = $Null
            $StaffCategory = $Null
            $IndexNumber = $Null
            $DutyStationCountryName = $Null
            $UserType = $Null
            
            # Set variable
            $Mail = $GroupMember.Mail
            $DisplayName = $GroupMember.DisplayName
            $JobTitle = $GroupMember.JobTitle
            $Country = $GroupMember.Country
            $Department = $GroupMember.Department
            $City = $GroupMember.City
            $CompanyName = $GroupMember.CompanyName
            $UsageLocation = $GroupMember.UsageLocation
            $UserPrincipalName = $GroupMember.UserPrincipalName
            
            #
            Write-Log -Level Warning -message "The script is analyzing $DisplayName ($UserPrincipalName) ….. --- $i/$Count"
            
            $Table += New-object PSobject -Property ([Ordered] @{
                    DisplayName               = $DisplayName;
                    Mail                   = $Mail;
                    UserPrincipalName       = $UserPrincipalName;
                    UserType               = $UserType;
                    JobTitle               = $JobTitle;
                    Department               = $Department;
                    StaffLevel               = $StaffLevel;
                    StaffCategory           = $StaffCategory;
                    IndexNumber               = $IndexNumber;
                    CompanyName               = $CompanyName;
                    City                   = $City;
                    Country                   = $Country;
                    DutyStationCountryName = $DutyStationCountryName;
                    UsageLocation           = $UsageLocation;
                    PERNR                   = $PERNR;
                })
            
            $i++
            
        }
        
        $DateFull = Get-Date -Format "ddMMyyyy_HH-mm-ss"
        $ReportFile = ".\LicensedUsersDetailed_fromGroup_" + $GroupName + "_" + $DateFull + ".xlsx"
        $Table | Export-Excel $ReportFile -TableName "LicensedUsers" -Title "Licensed Users" -TitleBold -WorksheetName "LicensedUsers" -TableStyle Medium9 -AutoSize -AutoFilter
        Write-log INFO -Message "Generate the following Report: $ReportFile"
    }
    Catch
    {
        $ErrorMessage = $Error[0].Exception.Message
        $CMDLet = $Error[0].InvocationInfo.Line
        $FailedItem = $Error[0].Exception.ItemName
        Write-Log -Level Error -Message "Failed to find AAD Group with the following Name : $GroupName"
        Write-Log -Level Error -Message "Failed to run the following CMDLet: $CMDLet"
        Write-Log -Level Error -Message "Failed with Error:$ErrorMessage"
    }
    
    
}

Function Check-AADLicenseForUser
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$UserPrincipalName
    )
    
    $AssignedLicenses = $Null
    $AssignedLicenses = @()
    $AzureADUser = Get-AzureADUser -ObjectId $UserPrincipalName
    $LicenseSkuId = $AzureADUser.AssignedLicenses.SkuId
    $AllSKUs = Get-AzureADSubscribedSku # Skuid -eq SkuPartNumber
    Foreach ($LicenseFound in $LicenseSkuId)
    {
        foreach ($Sku in $AllSKUs)
        {
            $SkuID = $Sku.SkuID
            if ($SkuID -eq $LicenseFound)
            {
                $SkuPartNumber = $Sku.SkuPartNumber
                $License = $Sku | select SkuID, SkuPartNumber
                $AssignedLicenses += $License
                
            }
        }
        
    }
    Return $AssignedLicenses
}

Function Add-AADLicenseToUser
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$UserPrincipalName,
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$SKUPartName,
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$UsageLocation
    )
    
    Set-AzureADUser -ObjectId $UserPrincipalName -UsageLocation $UsageLocation
    # Create the objects we'll need to add and remove licenses
    $license = New-Object -TypeName Microsoft.Open.AzureAD.Model.AssignedLicense
    $licenses = New-Object -TypeName Microsoft.Open.AzureAD.Model.AssignedLicenses
    
    # Find the SkuID of the license we want to add - in this example we'll use the O365_BUSINESS_PREMIUM license
    $license.SkuId = (Get-AzureADSubscribedSku | Where-Object -Property SkuPartNumber -Value $SKUPartName -EQ).SkuID
    
    # Set the Office license as the license we want to add in the $licenses object
    $licenses.AddLicenses = $license
    
    # Call the Set-AzureADUserLicense cmdlet to set the license.
    Set-AzureADUserLicense -ObjectId $UserPrincipalName -AssignedLicenses $licenses
    
}

Function Remove-AADLicenseToUser
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$UserPrincipalName,
        [Parameter(Mandatory = $true,
                   Position = 2)]
        [String]$SkuPartName
    )
    
    $Licenses.AddLicenses = @()
    $Licenses.RemoveLicenses = (Get-AzureADSubscribedSku | Where-Object -Property SkuPartNumber -Value $SkuPartName -EQ).SkuID
    Set-AzureADUserLicense -ObjectId $UserPrincipalName -AssignedLicenses $licenses
}

Function Generate-AADLicensesSKUsTable
{
    $Table = $Null
    $Table = @()
    $SKUs = Get-AzureADSubscribedSku
    [int]$i = 0
    ForEach ($SKU in $SKUs)
    {
        #$MaxLicence =$null
        $MaxLicence = $SKU.PrepaidUnits.Enabled
        #$LicenceUsed = $null
        $LicenceUsed = $SKU.ConsumedUnits
        #$Name = $Null
        $Name = $SKU.SkuPartNumber
        $RemainingLicence = $MaxLicence - $LicenceUsed
        $Table += New-object PSobject -Property ([Ordered] @{
                DisplayName         = $Name;
                MaxLicence         = $MaxLicence;
                LicenceUsed         = $LicenceUsed;
                RemainingLicence = $RemainingLicence;
            })
        $i++
    }
    $Table
    
}
#endregion

#region ADConnect
####################################################
################ AD Connect ##########################
###################################################


Function Start-AADConnectSync
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$Server,
        [Switch]$Full,
        [Parameter(HelpMessage = 'To be use if your Current User does NOT have permission to open a Remote PS session')]
        [String]$AlternateID
    )
    
    Write-Log warning -Message "Establishing a Remote PSSession to $Server"
    If ($AlternateID)
    {
        $ADConnectCredential = Get-Credential -Credential $AlternateID
        $ADConnectPSSession = New-PSSession -ComputerName $Server -Credential $ADConnectCredential -ErrorVariable ADConnectPSSessionErrorVariable -ErrorAction SilentlyContinue
    }
    Else
    {
        $ADConnectPSSession = New-PSSession -ComputerName $Server -ErrorVariable ADConnectPSSessionErrorVariable -ErrorAction SilentlyContinue
    }
    If ($ADConnectPSSessionErrorVariable)
    {
        Write-Log Error -Message "Fail to create the PSSession to $Server" 
    }
    Else
    {
        Write-Log Info -Message "Succesfully create the PSSession to $Server"
        
        If ($Full)
        {
            Invoke-Command -Session $ADConnectPSSession -ScriptBlock { Start-ADSyncSyncCycle -PolicyType initial } -ErrorVariable ADConnectErrorVariable -ErrorAction SilentlyContinue
            If ($ADConnectErrorVariable)
            {
                If ($ADConnectErrorVariable -like "*busy*")
                {
                    Write-Log warning -Message "Sync already running"
                }
                Else
                {
                    Write-Log Error -Message "Failed to run AD ConnectFull Sync"
                    Write-Log Error -Message "Failed with Error:"
                    $ADConnectErrorVariable
                }
            }
            Else
            {
                Write-Log Info -Message "The Full Sync is running"
            }
        }
        Else
        {
            Invoke-Command -Session $ADConnectPSSession -ScriptBlock { Start-ADSyncSyncCycle -PolicyType Delta } -ErrorVariable ErrorVariable -ErrorAction SilentlyContinue
            
            If ($ErrorVariable)
            {
                If ($ErrorVariable -like "*busy*")
                {
                    Write-Log Error -Message "Sync already running" 
                }
                Else
                {
                    Write-Log Error -Message "Failed to run AD Connect Delta Sync" 
                    Write-Log Error -Message "Failed with Error:"
                    $ErrorVariable
                }
            }
            Else
            {
                Write-Log Info -Message "Delta Sync is running"
            }
        }
    }
}

Function Check-AADConnectLastSync
{
    $AzureAdTenantDetails = Get-AzureADTenantDetail | select CompanyLastDirSyncTime
    $Time = $AzureAdTenantDetails.CompanyLastDirSyncTime
    $NextTime = $Time.Addminutes(30)
    $ToTimeZoneObj = [system.timezoneinfo]::GetSystemTimeZones() | Where-Object { $_.id -eq "Eastern Standard Time" }
    $TargetZoneTime = [system.timezoneinfo]::ConvertTime($Time, $ToTimeZoneObj)
    $NextTargetZoneTime = [system.timezoneinfo]::ConvertTime($NextTime, $ToTimeZoneObj)
    Write-host "The Last Synchronization was : " -NoNewline; Write-host "$TargetZoneTime" -ForegroundColor Green
    Write-host "The Next Synchronization will be at : " -NoNewline; Write-host "$NextTargetZoneTime" -ForegroundColor Yellow
}

Function Check-AADUserLastSync
{
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [string]$UserName
    )
    $AzureADUserLastSync = Get-AzureADUser -ObjectId $UserName | Select DisplayName, Mail, MailNickName, LastDirSyncTime
    $AzureADUserLastSync
}

#endregion