MyPSFunctions.AD.ps1

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

#region AD
####################################################
################ Active Directory #######################
###################################################
Function Force-ADUserChangePasswordNextLogon
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$UPN
    )
    $ADUser = Get-ADUser -Filter { UserPrincipalName -eq $UPN } -Properties *
    $ADUser_DN = $ADUser.DistinguishedName
    $ADUser_PasswordExpired = $ADUser.PasswordExpired
    
    If ($ADUser_PasswordExpired)
    {
        Write-Log Warning -Message "Password Change at the next logon is already set for $UPN"
    }
    Else
    {
        Set-ADUser -Identy $ADUser_DN -ChangePasswordAtLogon:$true
        Write-Log Info -Message "Password Change at the next logon has been set for $UPN"
    }
}
Function Generate-ReportLastLogonADUsers
{
    [CmdletBinding()]
    param ()
    #Install-Module -Name MergeCsv
    $DateFull = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    # Get All Users
    Try
    {
        Write-Log warning -Message "The script will retreive all AD users"
        $ADUsers = Get-ADUser -Filter * -Properties * -ResultSetSize 5
        $UsersCount = ($ADUsers | Measure).count
        Write-Log Info -Message "The script found $UsersCount AD Users"
    }
    Catch
    {
        $ErrorMessage = $Error[0].Exception.Message
        $CMDLet = $Error[0].InvocationInfo.Line
        $FailedItem = $Error[0].Exception.ItemName
        Write-Log Error -Message "Failed to retreive all AD users"
        Write-Log Error -Message "Failed to run the following CMDLet: $CMDLet"
        Write-Log Error -Message "Failed with Error:$ErrorMessage"
        Exit
    }
    
    
    # Get All DCs
    Try
    {
        Write-Log warning -Message "The script is searching for all DCs"
        $DCs = Get-ADDomainController -Filter * | select -first 2
        $DCsCount = ($DCs | Measure).count
        Write-Log Info -Message "The script found $DCsCount DCs"
    }
    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"
        Exit
    }
    
    [Int]$i = 1
    $CSVFiles = $Null
    $CSVFiles = @()
    foreach ($DC in $DCs)
    {
        $DCHostName = $Null
        $DCHostName = $DC.HostName
        $UserTable = $Null
        $UserTable = @()
        Write-Log Warning -Message "The script is retreiving information for all users using the following DC: $DCHostName --- $i/$DCsCount"
        [Int]$ii = 1
        
        foreach ($ADUser in $ADUsers)
        {
            $UPN = $Null
            $UPN = $ADUser.UserPrincipalName
            $DisplayName = $Null
            $DisplayName = $ADUser.DisplayName
            Write-Log Warning -Message "The script is retreiving information for user: $DisplayName ($UPN) --- $ii/$UsersCount"
            $ADReplicationAttributeMetadata = $Null
            $ADReplicationAttributeMetadata = Get-ADUser -Filter { UserPrincipalName -Eq $UPN } -Properties * | Get-ADReplicationAttributeMetadata -Server $DCHostName
            $LastLogonTimeStamp = $null
            $LastLogonTimeStamp = ($ADReplicationAttributeMetadata | where { $_.AttributeName -eq "LastLogonTimeStamp" }).AttributeValue
            $LastLogonTime = $Null
            $LastLogonTime = [datetime]::FromFileTime($LastLogonTimeStamp)
            $UserTable += New-object PSobject -Property ([Ordered] @{
                    UPN            = $UPN;
                    DisplayName = $DisplayName;
                    $DCHostName = $LastLogonTime;
                })
            
            $ii++
        }
        $DCCSVFile = $null
        $DCCSVFile = "Report_" + $DCHostName + "_" + $DateFull + ".csv"
        $UserTable | export-csv $DCCSVFile -NoTypeInformation -Encoding UTF8
        Write-Log Warning -Message "The script export Data to: $DCCSVFile"
        $i++
    }
    
    Write-Log warning -Message "Please used the following CMDlet to merge the file:"
    Write-Log warning -Message "Install-Module -Name MergeCsv"
    Write-Log warning -Message "Merge-Csv -Path dc1.csv, dc2.csv -Id UPN,DisplayName | Export-Csv -notype -enc UTF8 merged.csv"
    
}
Function Expand-ADGroupMembers
{
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$GroupName,
        [Parameter(Mandatory = $false,
                   Position = 2,
                   HelpMessage = 'To be used for DomainLocal Group')]
        [Switch]$Resursive
    )
    
    If ($Resursive)
    {
        $Members = Get-ADGroupMember -Identity $GroupName -Recursive
    }
    Else
    {
        $Members = Get-ADGroupMember -Identity $GroupName
    }
    
    [Int]$i = 1
    $Users = @()
    $Count = ($Members | Measure).count
    foreach ($Member in $Members)
    {
        $UserDN = $Member.DistinguishedName
        $ADuser = Get-ADUser -Identity $UserDN -Properties DisplayName, Userprincipalname, EmailAddress, Manager, msTSExpireDate, EmployeeNumber
        $ADuserDisplayName = $ADuser.DisplayName
        Write-Log Warning -Message "Analyzing $ADuserDisplayName --- $i/$Count"
        $ManagerDN = $ADuser.Manager
        If ($ManagerDN)
        {
            $ADManager = get-ADuser -identity $ManagerDN
            $ManagerName = $ADManager.DisplayName
        }
        Else
        { $ManagerName = "NotFound" }
        $EmployeeNumber = $($ADuser.EmployeeNumber) -or $($ADuser.EmployeeID)
        # Create a PSCustomObject of the current member
        $MemberObject = [PSCustomObject] @{
            DisplayName = $ADuser.DisplayName
            Userprincipalname = $ADuser.Userprincipalname
            Email        = $ADuser.EmailAddress
            EmployeeNumber = $EmployeeNumber
            Manager        = $ManagerName
            ExpireDate  = $ADuser.msTSExpireDate
            GroupName   = $GroupName
        }
        # Store the member object to Users array
        $Users += $MemberObject
        $i++
    }
    return $Users
}
Function Update-ADUserDynamicAttribute
{
    param
    (
        [Parameter(Mandatory = $True,
                   Position = 1)]
        [String]$UserName,
        [Parameter(Mandatory = $True,
                   Position = 1)]
        [String]$ParameterName,
        [Parameter(Mandatory = $True,
                   Position = 1)]
        [String]$ParameterValue
    )
    Import-Module ActiveDirectory
    write-host "The Information for User with the following UPN : $UserName will be searched and Displayed"
    $ADUser = Get-ADUser -Filter { UserPrincipalName -eq $UserName } -Properties *
    $ADUser
    $DN = $ADUser.DistinguishedName
    
    Set-ADUser -Identity $DN -Replace @{ $($ParameterName) = $ParameterValue } -Server $DC
}
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 Manage-ADGroupMembership
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [string]$CSVFile,
        [Parameter(Mandatory = $true,
                   Position = 2)]
        [String]$DC
    )
    
    Try
    {
        Read-Host "Expected CSV Column: SamAccountName,GroupName,Action (with possible value: Add/Remove)"
        Write-Host "The script will try to import the following CSV File: $CSVFile"
        $Users = Import-Csv $CSVFile
    }
    Catch
    {
        $ErrorMessage = $Error[0].Exception.Message
        $CMDLet = $Error[0].InvocationInfo.Line
        $FailedItem = $Error[0].Exception.ItemName
        Write-Log -Level Error -Message "Failed to to import the following 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
    }
    
    
    $Count = ($Users | Measure).count
    [Int]$i = 1
    $Table = $Null
    $Table = @()
    
    Foreach ($User in $Users)
    {
        $SamAccountName = $Null
        $SamAccountName = $User.SamAccountName
        $GroupName = $Null
        $GroupName = $User.GroupName
        $Action = $Null
        $Action = $User.Action
        Write-Host "The Script is trying to $Action : $SamAccountName to the Group: $GroupName --- $i/$Count"
        $UserOutput = $Null
        $UserOutput = @()
        $Status = $Null
        switch ($action)
        {
            Add {
                Try
                {
                    Add-ADGroupMember -Identity $GroupName -Members $SamAccountName -confirm: $False -Server $DC
                    Write-Host "User: $SamAccountName - Action: $Action - Group: $GroupName" -ForegroundColor Yellow
                }
                Catch
                {
                    $ErrorMessage = $Error[0].Exception.Message
                    Write-host "Failed with Error:$ErrorMessage"
                    $Status = "Failed: $ErrorMessage"
                }
            }
            Remove{
                Try
                {
                    Remove-ADGroupMember -Identity $GroupName -Members $SamAccountName -confirm: $False -Server $DC
                    Write-Host "User: $SamAccountName - Action: $Action - Group: $GroupName" -ForegroundColor Yellow
                }
                Catch
                {
                    $ErrorMessage = $Error[0].Exception.Message
                    Write-host "Failed with Error:$ErrorMessage"
                    $Status = "Failed: $ErrorMessage"
                }
            }
            Default {
                $Status = "No Action: unsupported Action"
                Write-Host " User: $SamAccountName - Action: $Action - Group: $GroupName" -ForegroundColor red
            }
        }
        
        
        If ($Status -like "*Failed*")
        { $Color = "Red" }
        Else { $Color = "Green" }
        Write-Host "Script try to $Action : $SamAccountName to $GroupName - Status: " -NoNewline; write-host $Status -ForegroundColor $Color
        
        $Table += New-object PSobject -Property ([Ordered] @{
                SamAccountName = $SamAccountName;
                GroupName       = $GroupName;
                Action           = $Action;
                Status           = $Status;
            })
        
        $i++
    }
    $DateFull = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    $ReportFilexlsx = ".\Manage_Users_GroupMembership_" + $DateFull + ".xlsx"
    $Table | Export-Excel $ReportFilexlsx -TableName "GroupMemberships" -Title "GroupMemberships" -TitleBold -WorksheetName "GroupMemberships" -TableStyle Medium9 -AutoSize -AutoFilter
    Write-log INFO -Message "Generate the following Report: $ReportFilexlsx"
}
Function Get-ADGroupMemberwithManager
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [string]$GroupName
    )
    
    #Initiate the Hash Table
    [Int]$i = 1
    $Table = $Null
    $Table = @()
    
    Try
    {
        $Members = $Null
        
        $Members = Get-ADGroupMember -Identity $GroupName -Recursive | select -First 10
        $Count = ($Members | Measure).count
        Foreach ($Member in $Members)
        {
            $displayName = $Null
            $GivenName = $Null
            $sn = $Null
            $UserPrincipalName = $Null
            $employeeNumber = $Null
            $employeeID = $Null
            $employeeID
            $l = $Null
            $co = $Null
            $Enabled = $Null
            $Department = $Null
            $Description = $Null
            $SamAccountName = $Null
            $Manager = $Null
            $ADManager = $Null
            $ADManagerDisplayName = $Null
            $SamAccountName = $Member.SamAccountName
            Write-Host  "The script is analyzing $SamAccountName….. --- $i/$Count"
            Try
            {
                $ADUser = $Null
                $ADUser = Get-ADUser -Filter { SamAccountName -eq $SamAccountName } -Properties *
                $displayName = $ADUser.displayName
                $GivenName = $ADUser.GivenName
                $sn = $ADUser.sn
                $UserPrincipalName = $ADUser.UserPrincipalName
                $employeeNumber = $ADUser.employeeNumber
                $employeeID = $ADUser.employeeID
                $l = $ADUser.l
                $co = $ADUser.co
                $Enabled = $ADUser.Enabled
                $Department = $ADUser.Department
                $Description = $ADUser.Description
                $Manager = $ADUser.Manager
                Try
                {
                    Write-Host  "The script is searching for manager: $Manager"
                    $ADManager = Get-ADUser $Manager -Properties *
                    $ADManagerDisplayName = $ADManager.DisplayName
                }
                Catch
                {
                    $ErrorMessage = $Error[0].Exception.Message
                    #$CMDLet = $Error[0].InvocationInfo.Line
                    #$FailedItem = $Error[0].Exception.ItemName
                    $ADManagerDisplayName = "$Manager - Failed to find Manager displayName with error: $ErrorMessage"
                }
                
                
            }
            Catch
            {
                $ErrorMessage = $Error[0].Exception.Message
                #$CMDLet = $Error[0].InvocationInfo.Line
                #$FailedItem = $Error[0].Exception.ItemName
                $displayName = "not found - Error: $ErrorMessage"
                $GivenName = "not found - Error: $ErrorMessage"
                $sn = "not found - Error: $ErrorMessage"
                $UserPrincipalName = "not found - Error: $ErrorMessage"
                $employeeNumber = "not found - Error: $ErrorMessage"
                $employeeID = "not found - Error: $ErrorMessage"
                $l = "not found - Error: $ErrorMessage"
                $co = "not found - Error: $ErrorMessage"
                $Enabled = "not found - Error: $ErrorMessage"
                $Department = "not found - Error: $ErrorMessage"
                $Description = "not found - Error: $ErrorMessage"
                $Manager = "not found - Error: $ErrorMessage"
            }
            
            
            $Table += New-object PSobject -Property ([Ordered] @{
                    
                    DisplayName          = $displayName;
                    SamAccountName    = $SamAccountName;
                    GivenName          = $GivenName;
                    sn                  = $sn;
                    UserPrincipalName = $UserPrincipalName;
                    Manager              = $ADManagerDisplayName;
                    Description          = $Description;
                    Department          = $Department;
                    Enabled              = $Enabled;
                    employeeNumber    = $employeeNumber;
                    employeeID          = $employeeID;
                    location          = $l;
                    country              = $co;
                })
            $i++
        }
    }
    Catch
    {
        $ErrorMessage = $Error[0].Exception.Message
        $CMDLet = $Error[0].InvocationInfo.Line
        $FailedItem = $Error[0].Exception.ItemName
        Write-Host "Failed to retreive the Member of $GroupName"
        Write-Host "Failed to run the following CMDLet: $CMDLet"
        Write-Host "Failed with Error:$ErrorMessage"
    }
    
    $DateFull = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    $ReportFile = ".\Group_" + $GroupName + "_" + $DateFull + ".txt"
    $Table | Format-Table DisplayName, SamAccountName, GivenName, sn, UserPrincipalName, Manager, Description, Description, Department, Enabled, employeeNumber, employeeID, location, country | Out-File -Width 2000 -FilePath $ReportFile -encoding utf8
    Write-Host "Generate the following Report: $ReportFile "
    
}
Function Check-ADSchemaVersionForADandEXCH
{
    [CmdletBinding()]
    param ()
    $SchemaVersions = @()
    $SchemaPartition = (Get-ADRootDSE).NamingContexts | ? { $_.SubString(0, 9).ToLower() -eq 'cn=schema' }
    $SchemaVersionAD = (Get-ADObject $SchemaPartition -Property objectVersion).objectVersion
    $SchemaVersions += @{ 'Active Directory' = $SchemaVersionAD }
    $SchemaPathExchange = "CN=ms-Exch-Schema-Version-Pt,$SchemaPartition"
    If (Test-Path "AD:$SchemaPathExchange")
    {
        $SchemaVersionExchange = (Get-ADObject $SchemaPathExchange -Property rangeUpper).rangeUpper
    }
    Else
    {
        $SchemaVersionExchange = 0
    }
    $SchemaVersions += @{ 'Exchange' = $SchemaVersionExchange }
    Write-Output $SchemaVersions
    
}
Function Find-ADUserwithUPN
{
    param
    (
        [Parameter(Mandatory = $True,
                   Position = 1)]
        [String]$UserName
    )
    Import-Module ActiveDirectory
    write-host "The Information for User with the following UPN : $UserName will be searched and Displayed"
    $ADUser = Get-ADUser -Filter { UserPrincipalName -eq $UserName } -Properties *
    $ADUser
}
Function Find-ADUserwithSAM
{
    param
    (
        [Parameter(Mandatory = $True,
                   Position = 1)]
        [String]$Sam
    )
    Import-Module ActiveDirectory
    write-host "The Information for User with the following SamAccountName : $Sam will be searched and Displayed"
    $ADUser = Get-ADUser -Filter { SamAccountName -eq $Sam } -Properties *
    $ADUser
}
Function Find-ADOnlineDC
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$Domain,
        [Parameter(Mandatory = $true,
                   Position = 2)]
        [String]$LogFile
    )
    #$Domain has to equal to the full name of the domain
    Try
    {
        $DC = Get-ADDomainController -Discover -ForceDiscover -Service ADWS -DomainName $Domain | Select -first 1
        $OnlineDC = $DC.HostName
        Write-Log -Level Info $LogFile "Find DC $OnlineDC for Domain $Domain"
    }
    Catch
    {
        Write-Log -Level Error $LogFile "Failed to find the Online DC for the domain : $domain"
        Write-Log -Level Error $LogFile "Failed with Error: $FailedFindOnlineDC"
        $OnlineDC = $null
    }
    
    return $OnlineDC
}
Function Generate-ADDirectMemberofADGroup
{
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$Group,
        [Parameter(Mandatory = $false,
                   Position = 2)]
        [String]$CSVFolder
    )
    
    $GroupMembers = Get-ADGroupMember -Identity $Group
    $Count = $Null
    $Count = ($GroupMembers | measure).count
    $GroupTable = $Null
    $GroupTable = @()
    [Int]$i = 1
    Foreach ($GroupMember in $GroupMembers)
    {
        $MemberSamAccountName = $GroupMember.SamAccountName
        $MemberADUser = Get-aduser $MemberSamAccountName
        $MemberUserPrincipalName = $MemberADUser.UserPrincipalName
        $MemberRecipient = Get-Recipient $MemberUserPrincipalName
        $MemberRecipientTypeDetails = $MemberRecipient.RecipientTypeDetails
        if ($MemberRecipientTypeDetails -eq "UserMailbox")
        {
            $MemberMailboxStatistics = Get-MailboxStatistics $MemberUserPrincipalName
            $MemberMailbox_LastLogon = $MemberMailboxStatistics.LastLogonTime
        }
        ElseIf ($MemberRecipientTypeDetails -eq "RemoteMailbox")
        {
            $MemberMailbox_LastLogon = "Migrated"
        }
        Else
        {
            $MemberMailbox_LastLogon = "No Mailbox"
        }
        $MemberName = $MemberADUser.Name
        write-host "User: $MemberName with UPN : $MemberUserPrincipalName - $i / $Count"
        $GroupTable += New-object PSobject -Property ([Ordered] @{
            DisplayName = $MemberName;
            UserPrincipalName = $MemberUserPrincipalName;
            LastLogon = $MemberMailbox_LastLogon;
            RecipientTypeDetails = $MemberRecipientTypeDetails;
        })
        $i++
    }
    $DateFull = Get-Date -Format "ddMMyyyy_HH-mm-ss"
    If ($CSVFolder)
    {
        $CSVFile = $CSVFolder + "Members_" + $Group + "_" + $DateFull + ".csv"
    }
    Else
    {
        $CSVFile = "Members_" + $Group + "_" + $DateFull + ".csv"
    }
    
    
    $GroupTable | export-csv $CSVFile -NoTypeInformation -Encoding UTF8
    Write-Host "The Members list was exported to the following CSV: $CSVFile"
}
Function Move-ADComputer
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$ComputerName,
        [Parameter(Mandatory = $true,
                   Position = 2)]
        [String]$DestinationOU_DN
    )
    
    $ADComputer = Get-ADComputer $ComputerName
    $ADComputerDN = $ADComputer.DistinguishedName
    $ADComputerObjectGUID = $ADComputer.ObjectGUID
    Write-Host "$ADComputer has the following DN: $ADComputerDN"
    Write-Host "The Script will be move $ADComputer to $DestinationOU_DN"
    Move-ADObject -identity $ADComputerObjectGUID -TargetPath $DestinationOU_DN
}
Function Move-ADComputersCSV
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$CSVFile
    )
    Read-Host "Expected CSV Column: ComputerName,DestinationOU"
    $ADComputers = Import-Csv $CSVFile
    foreach ($ADComputer in $ADComputers)
    {
        $ComputerName = $Null
        $ComputerName = $ADComputer.ComputerName
        $Computer = $Null
        $Computer = Get-ADComputer $ComputerName
        $DestinationOU_DN = $ADComputer.DestinationOU
        $ADComputerDN = $Null
        $ADComputerDN = $Computer.DistinguishedName
        $ADComputerObjectGUID = $Null
        $ADComputerObjectGUID = $Computer.ObjectGUID
        Write-Host "$ADComputer has the following DN: $ADComputerDN"
        Try
        {
            Write-Host "The Script will move $ADComputer to $DestinationOU_DN"
            Move-ADObject -identity $ADComputerObjectGUID -TargetPath $DestinationOU_DN
            Write-Host "The script successfully Move $ADComputer"
        }
        Catch
        {
            $ErrorMessage = $Error[0].Exception.Message
            $CMDLet = $Error[0].InvocationInfo.Line
            Write-Host "Failed to run the following CMDLet: $CMDLet"
            Write-host "Failed with Error:$ErrorMessage"
        }
        Read-Host "Pause before Next"
    }
    
}
Function Update-ADUserPrimarySMTPAddressToUPN
{
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$SamAccountName
    )
    
    $ADUser = Get-ADUser -Filter { SamAccountName -eq $SamAccountName } -Properties *
    $DisplayName = $ADUser.DisplayName
    $ProxyAddress = $ADUser.ProxyAddresses
    $OldUPN = $ADUser.UserPrincipalName
    $PrimarySMTPAddress = $null
    foreach ($Address in $ProxyAddress)
    {
        # Find Primary SMTP Address
        $Prefix = $Address.Substring(0, 4)
        If ($Prefix -ceq "SMTP")
        {
            $PrimarySMTPAddress = $Address.Substring(5)
        }
        
        
    }
    Write-Host  "The user: $DisplayName , with old UPN : $OldUPN, New UPN: $PrimarySMTPAddress" -ForegroundColor red
    # Write-Log -Level info -Message "The user: $DisplayName , with old UPN : $OldUPN, New UPN: $PrimarySMTPAddress will be updated"
    Try
    {
        Set-ADUser -identity $SamAccountName -UserPrincipalName $PrimarySMTPAddress
        Write-Log -Level info -Message "The user: $DisplayName , with old UPN : $OldUPN, New UPN: $PrimarySMTPAddress has been updated"
    }
    Catch
    {
        $ErrorMessage = $Error[0].Exception.Message
        $CMDLet = $Error[0].InvocationInfo.Line
        Write-Log -Level Error -Message "Failed to Update User with Old UPN $OldUPN to New UPN $PrimarySMTPAddress"
        Write-Log -Level Error -Message "Failed to run the following CMDLet: $CMDLet"
        Write-Log -Level Error -Message "Failed with Error:$ErrorMessage"
    }
}

Function Update-ADUserUPNToPrimarySMTPAddress
{
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$SamAccountName
    )
    
    $ADUser = Get-ADUser -Filter { SamAccountName -eq $SamAccountName } -Properties *
    $DisplayName = $ADUser.DisplayName
    $ProxyAddress = $ADUser.ProxyAddresses
    $OldUPN = $ADUser.UserPrincipalName
    $Mail = $ADUser.Mail
    
    Write-Host  "The user: $DisplayName , with old UPN : $OldUPN, New UPN: $Mail" -ForegroundColor red
    # Write-Log -Level info -Message "The user: $DisplayName , with old UPN : $OldUPN, New UPN: $PrimarySMTPAddress will be updated"
    Try
    {
        Set-ADUser -identity $SamAccountName -UserPrincipalName $Mail
        Write-Log -Level info -Message "The user: $DisplayName , with old UPN : $OldUPN, New UPN: $Mail has been updated"
    }
    Catch
    {
        $ErrorMessage = $Error[0].Exception.Message
        $CMDLet = $Error[0].InvocationInfo.Line
        Write-Log -Level Error -Message "Failed to Update User with Old UPN $OldUPN to New UPN $Mail"
        Write-Log -Level Error -Message "Failed to run the following CMDLet: $CMDLet"
        Write-Log -Level Error -Message "Failed with Error:$ErrorMessage"
    }
}

Function Enable-RemoteMailboxACL
{
    [CmdletBinding()]
    Param ([Parameter(Mandatory = $true)]
        [string]$Alias
    )
    
    Read-Host "This Function need Active Module to run"
    #Convert user access shared mailbox cross premise
    $RemoteMailboxInformation_File = "C:\Temp\RemoteMailbox_Backup_Before_Conversion_" + $Alias + ".xml"
    Get-AdUser $Alias -Properties * | Export-Clixml $RemoteMailboxInformation_File
    Read-host "Check the following File:$RemoteMailboxInformation_File"
    $ADUser = Get-AdUser $Alias -Properties * | Select DisplayName, UserPrincipalName, WindowsEMailAddress, msExchRecipientDisplayType
    Write-Host "$ADUser"
    Read-host "Validate the user information,Press Enter to enable ACL features (allows Cross-Premise Permission)"
    Get-AdUser $Alias | Set-AdObject -Replace @{ msExchRecipientDisplayType = -1073741818 }
}

Function New-ADOffice365User
{
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$FirstName,
        [Parameter(Mandatory = $true,
                   Position = 2)]
        [String]$LastName,
        [Parameter(Mandatory = $true,
                   Position = 3)]
        [String]$UserPrincipalName,
        [Parameter(Mandatory = $true,
                   Position = 4)]
        [String]$SamAccountName,
        [Parameter(Mandatory = $false,
                   Position = 8)]
        [String]$Company,
        [Parameter(Mandatory = $false,
                   Position = 9)]
        [String]$EmployeeNumber,
        [Parameter(Mandatory = $true,
                   Position = 10)]
        [String]$Department,
        [Parameter(Mandatory = $true,
                   Position = 11)]
        [String]$Description,
        [Parameter(Mandatory = $false,
                   Position = 12)]
        [String]$HomeDirectory,
        [Parameter(Mandatory = $false,
                   Position = 13)]
        [String]$HomeDrive,
        [Parameter(Mandatory = $true,
                   Position = 14)]
        [String]$Manager,
        [Parameter(Mandatory = $true,
                   Position = 15)]
        [String]$Office,
        [Parameter(Mandatory = $true,
                   Position = 16)]
        [String]$Title,
        [Parameter(Mandatory = $true,
                   Position = 17)]
        [String]$Country,
        [Parameter(Mandatory = $true,
                   Position = 18)]
        [String]$ParentOU,
        [Parameter(Mandatory = $false,
                   Position = 19)]
        [String]$Template,
        [Parameter(Mandatory = $false,
                   Position = 20)]
        [switch]$E1,
        [Parameter(Mandatory = $false,
                   Position = 21)]
        [switch]$E3,
        [Parameter(Mandatory = $true,
                   Position = 22)]
        [String]$LogFile,
        [Parameter(Mandatory = $true,
                   Position = 23)]
        [String]$RoutingDomain,
        [Parameter(Mandatory = $true,
                   Position = 24)]
        [string]$Password,
        [Parameter(Mandatory = $true,
                   Position = 25)]
        [string]$DomainController,
        [Parameter(Position = 26)]
        [String]$Shared
    )
    
    $PSW = $Password | ConvertTo-SecureString -AsPlainText -Force
    $ChangePasswordAtLogon = $True
    $Enabled = $True
    
    # Create On-Premise AD Account
    Try
    {
        Import-Module ActiveDirectory
        $Name = $FirstName + " " + $LastName
        $DisplayName = $FirstName + " " + $LastName
        New-ADUser -Verbose `
                   -Name $Name `
                   -Path $ParentOU `
                   -SamAccountName $SamAccountName `
                   -UserPrincipalName $UserPrincipalName `
                   -GivenName $FirstName `
                   -Surname $LastName `
                   -AccountPassword $PSW `
                   -ChangePasswordAtLogon $ChangePasswordAtLogon `
                   -Enabled $Enabled `
                   -Company $Company `
                   -EmployeeNumber $EmployeeNumber `
                   -Department $Department `
                   -Description $Description `
                   -DisplayName $DisplayName `
                   -HomeDirectory $HomeDirectory `
                   -HomeDrive $HomeDrive `
                   -Manager $Manager `
                   -Office $Office `
                   -Title $Title `
                   -Country $Country `
                   -Server $DomainController
        Write-Log -Level Warning $LogFile "Successfully Create the User with UPN: $UserPrincipalName"
    }
    Catch
    {
        $ErrorMessage = $Error[0].Exception.Message
        $CMDLet = $Error[0].InvocationInfo.Line
        $FailedItem = $Error[0].Exception.ItemName
        Write-Log -Level Error $LogFile "Failed to Create the User with UPN: $UserPrincipalName"
        Write-Log -Level Error $LogFile "Failed to run the following CMDLet: $CMDLet"
        Write-Log -Level Error $LogFile "Failed with Error:$ErrorMessage"
        Write-Log -Level Error $LogFile "The Script will stop"
        # Exit the script
        Exit
    }
    # Create Office 365 Mailbox (Remote Mailbox)
    Try
    {
        Connect-ExchangeOnPremise
        sleep 5
        $RemoteRoutingAddress = $SamAccountName + $RoutingDomain
        $Alias = $UserPrincipalName.Substring(0, $UserPrincipalName.LastIndexOf("@"))
        If ($Shared)
        {
            Enable-RemoteMailbox $SamAccountName -RemoteRoutingAddress $RemoteRoutingAddress -PrimarySMTPAddress $UserPrincipalName -Alias $Alias -Confirm:$False -DomainController $DomainController -Shared
        }
        Else
        {
            Enable-RemoteMailbox $SamAccountName -RemoteRoutingAddress $RemoteRoutingAddress -PrimarySMTPAddress $UserPrincipalName -Alias $Alias -Confirm:$False -DomainController $DomainController
        }
        sleep 5
        $EmailAddresses_Add_RemoteRoutingAddress = "smtp:" + $RemoteRoutingAddress
        #Read-host "value is :$EmailAddresses_Add_RemoteRoutingAddress"
        Set-RemoteMailbox $SamAccountName -EmailAddresses @{ add = $EmailAddresses_Add_RemoteRoutingAddress } -DomainController $DomainController
        Write-Log -Level Warning $LogFile "Successfully create the Remote Mailbox for user with UPN: $UserPrincipalName"
    }
    Catch
    {
        $ErrorMessage = $Error[0].Exception.Message
        $CMDLet = $Error[0].InvocationInfo.Line
        $FailedItem = $Error[0].Exception.ItemName
        Write-Log -Level Error $LogFile "Failed to Create Remote Mailbox for user with UPN: $UserPrincipalName"
        Write-Log -Level Error $LogFile "Failed to run the following CMDLet: $CMDLet"
        Write-Log -Level Error $LogFile "Failed with Error:$ErrorMessage"
        Write-Log -Level Error $LogFile "The Script will stop"
        # Exit the script
        Exit
    }
}
#endregion
#region LDAP
####################################################
##################### LDAP #########################
####################################################
Function Request-ADDomainusingLDAP
{
    [CmdletBinding()]
    param ()
    $MyPC = [Environment]::MachineName
    $Domain = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()
    Write-Host "your PC $MyPC is currently on the domain: $Domain"
}

Function Request-ADUserusingLDAP
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [string]$Name
    )
    
    $search = [adsisearcher]"(&(ObjectCategory=Person)(ObjectClass=User)(cn=$Name*))"
    $users = $search.FindAll()
    $users | select Properties -ExpandProperty Properties
}

Function Request-LDAPGroupMember
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [String]$GroupDN
    )
    
    $Group = [ADSI]$GroupDN
    $Members = $Group.Member |
    ForEach-Object { [ADSI]"LDAP://$_" }
    $Members |
    Select-Object @{ N = 'Members'; e = { $_.name } }, @{ N = 'Type'; e = { $_.SchemaClassName } }, @{ N = 'Enabled'; e = { ($_.UserAccountControl[0] -band 2) -eq 2 } }
    
}

#endregion
#region DNS
####################################################
##################### DNS #########################
####################################################
Function Check-DNSPhishingSettings
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true,
                   Position = 1)]
        [string]$Domain
    )
    
    Write-log Warning -Message "the script is analyzing the following Domain: $Domain"
    #Check SPF Record
    Try
    {
        $TXTRecords = Resolve-DnsName -Name $Domain -Type TXT -ErrorAction SilentlyContinue
        $SPFRecord = $TXTRecords | where { $_.Strings -like "*spf*" }
        $SPFRecordName = $SPFRecord.Name
        $SPFRecordValue = $SPFRecord.Strings
    }
    Catch
    {
        Write-log Error -Message "Failed to find SPF record"
    }
    
    # Check DKIM
    #Google
    Try
    {
        $GoogleSelector = "google._domainkey." + $Domain
        $GoogleDKIM = Resolve-DnsName -Name $GoogleSelector -Type TXT -ErrorAction SilentlyContinue
        $GoogleDKIMName = $GoogleDKIM.Name
        $GoogleDKIMValue = $GoogleDKIM.Strings
    }
    Catch
    {
        $ErrorMessage = $Error[0].Exception.Message
        Write-log Error -Message "Failed to find Google DKIM - $ErrorMessage"
    }
    
    # Microsoft
    Try
    {
        $MicrosoftSelector1Name = "Selector1._domainkey." + $Domain
        $MicrosoftSelector2Name = "Selector2._domainkey." + $Domain
        $DKIM1 = Resolve-DnsName -Name $MicrosoftSelector1Name -Type CName -ErrorAction SilentlyContinue
        $DKIM2 = Resolve-DnsName -Name $MicrosoftSelector2Name -Type CName -ErrorAction SilentlyContinue
        $DKIM1Name = $DKIM1.Name
        $DKIM1Value = $DKIM1.NameHost
        $DKIM2Name = $DKIM2.Name
        $DKIM2Value = $DKIM2.NameHost
    }
    Catch
    {
        $ErrorMessage = $Error[0].Exception.Message
        Write-log Error -Message "Failed to find Microsoft DKIMs - $ErrorMessage"
    }
    # Check DMARC
    Try
    {
        $DMARCTXTRecordName = "_dmarc." + $Domain
        $DMARC = Resolve-DnsName -Name $DMARCTXTRecordName -Type TXT -ErrorAction SilentlyContinue
        $DMARCName = $DMARC.Name
        $DMARCValue = $DMARC.Strings
    }
    Catch
    {
        $ErrorMessage = $Error[0].Exception.Message
        Write-log Error -Message "Failed to find DMARC - $ErrorMessage"
    }
    # Check MX Record
    Try
    {
        
        $MXRecords = Resolve-DnsName -Name $Domain -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 = $Null
    $Table = @()
    $Table += New-object PSobject -Property ([Ordered] @{
            Domain            = $Domain;
            SPFRecord        = $SPFRecordValue;
            Google_DKIM        = $GoogleDKIMValue;
            Microsoft_DKIM1 = $DKIM1Value;
            Microsoft_DKIM2 = $DKIM2Value;
            DMARC            = $DMARCValue;
            MXRecord        = $MXRecordValue;
        })
    
    $Table
}
#endregion