Public/Lifecycle.ps1

<#
.SYNOPSIS
    Offboards a user from Microsoft 365.
.DESCRIPTION
    This function performs a series of actions to offboard a user from Microsoft 365.
.PARAMETER UserId
    The UPN or Id of the user to offboard.
.PARAMETER ArchiveOneDrivePath
    The local path to archive the user's OneDrive for Business files.
.PARAMETER ConvertToSharedMailbox
    If specified, the user's mailbox will be converted to a shared mailbox.
.PARAMETER DisableAccount
    If specified, the user's account will be disabled.
.PARAMETER RemoveFromGroups
    If specified, the user will be removed from all Microsoft 365 groups.
.PARAMETER SetOutOfOfficeMessage
    An Out of Office message to set on the user's mailbox.
.EXAMPLE
    Offboard-O365User -UserId 'jeff.atkinson@office365itpros.com' -DisableAccount -ConvertToSharedMailbox -SetOutOfOfficeMessage "Jeff Atkinson is no longer with the company."
.NOTES
    You must be connected to the Microsoft Graph and Exchange Online with the appropriate scopes before running this function.
    Required scopes: User.ReadWrite.All, Group.ReadWrite.All, MailboxSettings.ReadWrite, Files.Read.All
#>

function Offboard-O365User {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true)]
        [string]$UserId,
        [string]$ArchiveOneDrivePath,
        [switch]$ConvertToSharedMailbox,
        [switch]$DisableAccount = $true,
        [switch]$RemoveFromGroups,
        [string]$SetOutOfOfficeMessage
    )

    $User = Get-MgUser -UserId $UserId
    if (-not $User) {
        Write-Warning "User not found: $UserId"
        return
    }

    Write-Verbose "Starting offboarding process for user: $($User.DisplayName)"

    if ($DisableAccount) {
        Write-Verbose "Disabling account..."
        Update-MgUser -UserId $User.Id -AccountEnabled:$false
        Write-Verbose "Account disabled."
    }

    if ($SetOutOfOfficeMessage) {
        Write-Verbose "Setting Out of Office message..."
        try {
            Set-MailboxAutomaticReplyConfiguration -Identity $User.Id -AutoReplyState Enabled -InternalMessage $SetOutOfOfficeMessage -ExternalMessage $SetOutOfOfficeMessage
            Write-Verbose "Out of Office message set."
        }
        catch {
            Write-Warning "Failed to set Out of Office message. Error: $_"
        }
    }

    if ($ArchiveOneDrivePath) {
        Write-Verbose "Archiving OneDrive files to: $ArchiveOneDrivePath"
        try {
            if (-not (Test-Path -Path $ArchiveOneDrivePath)) {
                New-Item -ItemType Directory -Path $ArchiveOneDrivePath
            }
            $OneDriveRoot = Get-MgUserDrive -UserId $User.Id
            $Files = Get-O365UserOneDriveFilesRecursive -UserId $User.Id -FolderId $OneDriveRoot.Root.Id
            foreach ($File in $Files) {
                Write-Verbose "Downloading $($File.Name) to $(Join-Path $ArchiveOneDrivePath $File.RelativePath)"
                Download-O365File -UserId $User.Id -DriveItemId $File.Id -LocalPath $ArchiveOneDrivePath -RelativePath $File.RelativePath
            }
            Write-Verbose "OneDrive files archived."
        }
        catch {
            Write-Warning "Failed to archive OneDrive files. Error: $_"
        }
    }

    if ($ConvertToSharedMailbox) {
        Write-Verbose "Converting mailbox to shared mailbox..."
        try {
            Set-Mailbox -Identity $User.Id -Type Shared
            Write-Verbose "Mailbox converted."
        }
        catch {
            Write-Warning "Failed to convert mailbox. Error: $_"
        }
    }

    if ($RemoveFromGroups) {
        Write-Verbose "Removing user from all groups..."
        try {
            Remove-O365UserFromGroups -UserId $User.Id
            Write-Verbose "User removed from all groups."
        }
        catch {
            Write-Warning "Failed to remove user from groups. Error: $_"
        }
    }

    Write-Verbose "Offboarding process complete for user: $($User.DisplayName)"
}

<#
.SYNOPSIS
    Onboards a new user to Microsoft 365.
.DESCRIPTION
    This function automates the process of creating a new user and getting them set up.
.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 UsageLocation
    The usage location of the new user (2-letter country code).
.PARAMETER TemplateUserId
    The UPN or Id of a template user to clone group memberships from.
.PARAMETER LicenseSkuId
    The SKU ID of the license to assign to the new user.
.PARAMETER Manager
    The UPN or Id of the user's manager.
.PARAMETER PersonalEmailAddress
    The personal email address of the new user to send a welcome email to.
.EXAMPLE
    Onboard-O365User -UserPrincipalName 'new.user@office365itpros.com' -DisplayName 'New User' -FirstName 'New' -LastName 'User' -UsageLocation 'US' -TemplateUserId 'template.user@office365itpros.com' -LicenseSkuId '6fd2c87f-b296-42f0-b197-1e91e994b900' -Manager 'manager@office365itpros.com' -PersonalEmailAddress 'new.user@personal.com'
.NOTES
    You must be connected to the Microsoft Graph with the appropriate scopes before running this function.
#>

function Onboard-O365User {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true)]
        [string]$UserPrincipalName,
        [Parameter(Mandatory=$true)]
        [string]$DisplayName,
        [Parameter(Mandatory=$true)]
        [string]$FirstName,
        [Parameter(Mandatory=$true)]
        [string]$LastName,
        [Parameter(Mandatory=$true)]
        [string]$UsageLocation,
        [string]$TemplateUserId,
        [string]$LicenseSkuId,
        [string]$Manager,
        [string]$PersonalEmailAddress
    )

    Write-Verbose "Starting onboarding process for user: $DisplayName"

    $NewUser = New-O365User -UserPrincipalName $UserPrincipalName -DisplayName $DisplayName -FirstName $FirstName -LastName $LastName -UsageLocation $UsageLocation -LicenseSkuId $LicenseSkuId
    if (-not $NewUser) {
        Write-Warning "Failed to create new user."
        return
    }

    if ($TemplateUserId) {
        Write-Verbose "Cloning group memberships from template user: $TemplateUserId"
        Add-O365UserToGroupsFromTemplate -UserId $NewUser.Id -TemplateUserId $TemplateUserId
    }

    if ($Manager) {
        Write-Verbose "Setting manager to: $Manager"
        Set-MgUserManagerByRef -UserId $NewUser.Id -AdditionalProperties @{ "@odata.id" = "https://graph.microsoft.com/v1.0/users/$Manager" }
    }

    if ($PersonalEmailAddress) {
        Write-Verbose "Sending welcome email to: $PersonalEmailAddress"
        $WelcomeSubject = "Welcome to the company!"
        $WelcomeBody = "Welcome to the company! Your new account has been created. Your username is $($NewUser.UserPrincipalName) and your temporary password is $($NewUser.Password). Please sign in and change your password."
        
        $Message = @{
            subject = $WelcomeSubject
            body = @{
                contentType = "Text"
                content = $WelcomeBody
            }
            toRecipients = @(
                @{
                    emailAddress = @{
                        address = $PersonalEmailAddress
                    }
                }
            )
        }
        Send-MgUserMail -UserId (Get-MgContext).Account -Message $Message
    }

    Write-Verbose "Onboarding process complete for user: $DisplayName"
    return $NewUser
}

<#
.SYNOPSIS
    Sets up a new project in Microsoft 365.
.DESCRIPTION
    This function automates the creation of a new Microsoft 365 Group and Team, a SharePoint site, and a Planner plan for a new project.
.PARAMETER ProjectName
    The name of the new project.
.PARAMETER ProjectDescription
    A description for the new project.
.PARAMETER ProjectMembers
    An array of user UPNs to add as members to the project group.
.PARAMETER ProjectOwners
    An array of user UPNs to add as owners to the project group.
.EXAMPLE
    New-O365Project -ProjectName 'New Client Engagement' -ProjectDescription 'Project for new client' -ProjectMembers 'user1@contoso.com' -ProjectOwners 'admin@contoso.com'
.NOTES
    You must be connected to the Microsoft Graph and SharePoint Online with the appropriate scopes before running this function.
#>

function New-O365Project {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true)]
        [string]$ProjectName,
        [string]$ProjectDescription,
        [string[]]$ProjectMembers,
        [string[]]$ProjectOwners
    )

    Write-Verbose "Starting project setup for: $ProjectName"

    # Create Microsoft 365 Group and Team
    Write-Verbose "Creating Microsoft 365 Group and Team..."
    $Group = Manage-O365Group -Action Create -GroupName $ProjectName -GroupAlias ($ProjectName -replace '\s','').ToLower() -Members $ProjectMembers -Owners $ProjectOwners
    if (-not $Group) {
        Write-Warning "Failed to create Microsoft 365 Group and Team."
        return
    }
    Write-Verbose "Microsoft 365 Group and Team created: $($Group.DisplayName)"

    # Create SharePoint site
    Write-Verbose "Creating SharePoint site..."
    $SiteUrl = "https://$($global:O365ToolkitConnection.TenantId.Split('.')[0]).sharepoint.com/sites/$(($ProjectName -replace '\s','').ToLower())"
    try {
        New-PnPSite -Type TeamSite -Title $ProjectName -Url $SiteUrl -Description $ProjectDescription -Owners $ProjectOwners
        Write-Verbose "SharePoint site created: $SiteUrl"
    }
    catch {
        Write-Warning "Failed to create SharePoint site. Error: $_"
    }

    # Create Planner plan
    Write-Verbose "Creating Planner plan..."
    try {
        New-MgGroupPlannerPlan -GroupId $Group.Id -Title "$ProjectName Plan"
        Write-Verbose "Planner plan created."
    }
    catch {
        Write-Warning "Failed to create Planner plan. Error: $_"
    }

    Write-Verbose "Project setup complete for: $ProjectName"
}