Public/UserManagement.ps1

<#
.SYNOPSIS
    Creates a new user in Azure AD.
.DESCRIPTION
    This function creates a new user in Azure AD with the specified properties. It can also assign a license and send a notification email to administrators.
.PARAMETER UserPrincipalName
    The User Principal Name (UPN) of the new user.
.PARAMETER DisplayName
    The display name of the new user.
.PARAMETER FirstName
    The first name of the new user.
.PARAMETER LastName
    The last name of the new user.
.PARAMETER Department
    The department of the new user.
.PARAMETER JobTitle
    The job title of the new user.
.PARAMETER UsageLocation
    The usage location of the new user (2-letter country code).
.PARAMETER LicenseSkuId
    The SKU ID of the license to assign to the new user.
.PARAMETER SendNotification
    If specified, a notification email will be sent to administrators.
.PARAMETER NotificationFromAddress
    The 'From' address for the notification email.
.PARAMETER ForceChangePasswordNextSignIn
    If specified, the user will be required to change their password on next sign-in.
.PARAMETER City
    The city of the new user.
.PARAMETER CompanyName
    The company name of the new user.
.PARAMETER Country
    The country of the new user.
.PARAMETER BusinessPhones
    The business phone number of the new user.
.PARAMETER MobilePhone
    The mobile phone number of the new user.
.PARAMETER OfficeLocation
    The office location of the new user.
.PARAMETER StreetAddress
    The street address of the new user.
.PARAMETER State
    The state of the new user.
.EXAMPLE
    New-O365User -UserPrincipalName 'jeff.atkinson@office365itpros.com' -DisplayName 'Jeff Atkinson' -FirstName 'Jeff' -LastName 'Atkinson' -UsageLocation 'US' -LicenseSkuId '6fd2c87f-b296-42f0-b197-1e91e994b900' -SendNotification -NotificationFromAddress 'admin@office365itpros.com'
.NOTES
    You must be connected to the Microsoft Graph with the 'User.ReadWrite.All' and 'Directory.ReadWrite.All' scopes before running this function.
#>

function New-O365User {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true)]
        [string]$UserPrincipalName,
        [Parameter(Mandatory=$true)]
        [string]$DisplayName,
        [Parameter(Mandatory=$true)]
        [string]$FirstName,
        [Parameter(Mandatory=$true)]
        [string]$LastName,
        [string]$Department,
        [string]$JobTitle,
        [Parameter(Mandatory=$true)]
        [string]$UsageLocation,
        [string]$LicenseSkuId,
        [switch]$SendNotification,
        [string]$NotificationFromAddress,
        [bool]$ForceChangePasswordNextSignIn = $true,
        [string]$City,
        [string]$CompanyName,
        [string]$Country,
        [string]$BusinessPhones,
        [string]$MobilePhone,
        [string]$OfficeLocation,
        [string]$StreetAddress,
        [string]$State
    )

    Add-Type -AssemblyName 'System.Web'
    $NewPassword = [System.Web.Security.Membership]::GeneratePassword(10, 3)
    $NewPasswordProfile = @{
        "Password"                      = $NewPassword
        "ForceChangePasswordNextSignIn" = $ForceChangePasswordNextSignIn
    }

    $MailNickname = "$FirstName.$LastName"

    $NewUserParameters = @{
        UserPrincipalName = $UserPrincipalName
        DisplayName       = $DisplayName
        PasswordProfile   = $NewPasswordProfile
        AccountEnabled    = $true
        MailNickName      = $MailNickname
        Surname           = $LastName
        GivenName         = $FirstName
        UsageLocation     = $UsageLocation
    }
    if ($Department) { $NewUserParameters.Add("Department", $Department) }
    if ($JobTitle) { $NewUserParameters.Add("JobTitle", $JobTitle) }
    if ($City) { $NewUserParameters.Add("City", $City) }
    if ($CompanyName) { $NewUserParameters.Add("CompanyName", $CompanyName) }
    if ($Country) { $NewUserParameters.Add("Country", $Country) }
    if ($BusinessPhones) { $NewUserParameters.Add("BusinessPhones", @($BusinessPhones)) }
    if ($MobilePhone) { $NewUserParameters.Add("MobilePhone", $MobilePhone) }
    if ($OfficeLocation) { $NewUserParameters.Add("OfficeLocation", $OfficeLocation) }
    if ($StreetAddress) { $NewUserParameters.Add("StreetAddress", $StreetAddress) }
    if ($State) { $NewUserParameters.Add("State", $State) }

    $NewUser = New-MgUser @NewUserParameters
    if ($NewUser) {
        Write-Verbose ("Successfully added the {0} account" -f $NewUser.DisplayName)
    }
    else {
        Write-Warning ("Failure adding the {0} account" -f $DisplayName)
        return
    }

    if ($LicenseSkuId) {
        $License = Set-MgUserLicense -UserId $NewUser.Id -AddLicenses @{SkuId = $LicenseSkuId } -RemoveLicenses @()
        if ($License) {
            Write-Verbose ("Successfully assigned license {0} to {1}" -f $LicenseSkuId, $NewUser.DisplayName)
        }
        else {
            Write-Warning ("Failed to assign license {0} to {1}" -f $LicenseSkuId, $NewUser.DisplayName)
        }
    }

    if ($SendNotification) {
        if (-not $NotificationFromAddress) {
            Write-Warning "NotificationFromAddress is required when SendNotification is specified."
            return
        }

        $Admins = Get-O365Admin
        $HtmlBody = ("A new user account for {0} ({1}) has been added. The account password is <b>{2}</b>. An Office 365 E3 license has been assigned to the account. Please inform the user and inform them that they must reset their password when they sign into Office 365." -f $NewUser.DisplayName, $NewUser.UserPrincipalName, $NewPassword)
        $MsgSubject = ("New Azure AD account added for {0} ({1})" -f $NewUser.DisplayName, $NewUser.UserPrincipalName)
        
        $MsgToRecipients = foreach($Admin in $Admins) {
            @{
                emailAddress = @{address = $Admin.Mail}
            }
        }

        Write-Verbose "Sending notification message to tenant admins"
        $MsgBody = @{
            Content     = $HtmlBody
            ContentType = 'html'
        }
        $Message = @{
            subject      = $MsgSubject
            toRecipients = $MsgToRecipients
            body         = $MsgBody
        }
        
        Send-MgUserMail -UserId $NotificationFromAddress -Message $Message -SaveToSentItems:$true
    }

    # Add password to the returned object. This is sensitive, so be careful.
    $NewUser | Add-Member -MemberType NoteProperty -Name "Password" -Value $NewPassword -PassThru
    
    return $NewUser
}

<#
.SYNOPSIS
    Clones a user account.
.DESCRIPTION
    This function creates a new user by cloning attributes from a template user.
.PARAMETER TemplateUserId
    The UPN or Id of the template user.
.PARAMETER NewUserPrincipalName
    The User Principal Name (UPN) of the new user.
.PARAMETER NewDisplayName
    The display name of the new user.
.PARAMETER NewFirstName
    The first name of the new user.
.PARAMETER NewLastName
    The last name of the new user.
.EXAMPLE
    Clone-O365User -TemplateUserId 'template.user@office365itpros.com' -NewUserPrincipalName 'new.user@office365itpros.com' -NewDisplayName 'New User' -NewFirstName 'New' -NewLastName 'User'
.NOTES
    You must be connected to the Microsoft Graph with the 'User.ReadWrite.All' and 'Directory.Read.All' scopes before running this function.
#>

function Clone-O365User {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true)]
        [string]$TemplateUserId,
        [Parameter(Mandatory=$true)]
        [string]$NewUserPrincipalName,
        [Parameter(Mandatory=$true)]
        [string]$NewDisplayName,
        [Parameter(Mandatory=$true)]
        [string]$NewFirstName,
        [Parameter(Mandatory=$true)]
        [string]$NewLastName
    )

    $TemplateUser = Get-MgUser -UserId $TemplateUserId
    if (-not $TemplateUser) {
        Write-Warning "Template user not found: $TemplateUserId"
        return
    }

    $NewUser = New-O365User -UserPrincipalName $NewUserPrincipalName -DisplayName $NewDisplayName -FirstName $NewFirstName -LastName $NewLastName `
        -Department $TemplateUser.Department `
        -JobTitle $TemplateUser.JobTitle `
        -UsageLocation $TemplateUser.UsageLocation `
        -City $TemplateUser.City `
        -CompanyName $TemplateUser.CompanyName `
        -Country $TemplateUser.Country `
        -BusinessPhones $TemplateUser.BusinessPhones `
        -MobilePhone $TemplateUser.MobilePhone `
        -OfficeLocation $TemplateUser.OfficeLocation `
        -StreetAddress $TemplateUser.StreetAddress `
        -State $TemplateUser.State

    if ($NewUser) {
        Add-O365UserToGroupsFromTemplate -UserId $NewUser.Id -TemplateUserId $TemplateUser.Id
    }

    return $NewUser
}

<#
.SYNOPSIS
    Manages guest users.
.DESCRIPTION
    This function allows you to invite and remove guest users.
.PARAMETER Action
    The action to perform. Valid values are 'Invite', 'Remove'.
.PARAMETER EmailAddress
    The email address of the guest user.
.PARAMETER RedirectUrl
    The URL to redirect the user to after they accept the invitation.
.EXAMPLE
    Manage-O365GuestUser -Action Invite -EmailAddress 'guest@example.com' -RedirectUrl 'https://myapps.microsoft.com'
.EXAMPLE
    Manage-O365GuestUser -Action Remove -EmailAddress 'guest@example.com'
.NOTES
    You must be connected to the Microsoft Graph with the 'User.Invite.All' and 'User.ReadWrite.All' scopes before running this function.
#>

function Manage-O365GuestUser {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true)]
        [ValidateSet('Invite', 'Remove')]
        [string]$Action,
        [Parameter(Mandatory=$true)]
        [string]$EmailAddress,
        [string]$RedirectUrl = 'https://myapps.microsoft.com'
    )

    switch ($Action) {
        'Invite' {
            Write-Verbose "Inviting guest user: $EmailAddress"
            $Invitation = New-MgInvitation -InvitedUserEmailAddress $EmailAddress -InviteRedirectUrl $RedirectUrl -SendInvitationMessage:$true
            return $Invitation
        }
        'Remove' {
            Write-Verbose "Removing guest user: $EmailAddress"
            $User = Get-MgUser -Filter "mail eq '$EmailAddress'"
            if ($User) {
                Remove-MgUser -UserId $User.Id
            }
            else {
                Write-Warning "Guest user not found: $EmailAddress"
            }
        }
    }
}