public/New-UcmOffice365User.ps1

#PerformScriptSigning
Function New-UcmOffice365User
{
    <#
            .SYNOPSIS
            Checks for and creates a new blank Office 365 user
 
            .DESCRIPTION
            Checks for and creates a new blank Office 365 user
            Handy for some situations where you need to create a user account for things that cant be sorted by a resource account.
 
            .EXAMPLE
            PS> New-Office365User -UPN button.mash@contoso.com -Password "Passw0rd1!" -FirstName Caleb -LastName Sills -Country AU -DisplayName "Button Mash"
 
            .PARAMETER UPN
            The UPN of the user you wish to create, eg: "button.mash@contoso.com"
 
            .PARAMETER Password
            The Password for the user you wish to create, eg: "%%32/young/PRESS/road/86%%"
 
            .PARAMETER FirstName
            The first name of the user you wish to create eg: "Button"
 
            .PARAMETER LastName
            The first name of the user you wish to create eg: "Mash"
 
            .PARAMETER DisplayName
            The Display Name of the user you wish to create, eg: "Button Mash"
 
            .INPUTS
            This function accepts both parameter and pipline input
 
            .OUTPUTS
            This Cmdet returns a PSCustomObject with multiple keys to indicate status
            $Return.Status
            $Return.Message
 
            Return.Status can return one of four values
            "OK" : Created User
            "Warning" : User already exists, creation was skipped
            "Error" : Something happend when attempting to create the user, check $return.message for more information
            "Unknown" : Cmdlet reached the end of the function without returning anything, this shouldnt happen, if it does please log an issue on Github
 
            Return.Message returns descriptive text showing the connected tenant, mainly for logging or reporting
 
            .LINK
            https://www.UcMadScientist.com
            https://github.com/Atreidae/UcmPSTools
 
            .ACKNOWLEDGEMENTS
 
            .NOTES
            Version: 1.2
            Date: 18/11/2021
 
            .VERSION HISTORY
            1.2: Documentation updates
 
            1.1: Updated to "Ucm" naming convention
            Better inline documentation
            Optmized Try, Catch blocks to neaten code
 
            1.0: Initial Public Release
 
            .REQUIRED FUNCTIONS/MODULES
            Modules
            AzureAD (Install-Module AzureAD)
            MSOnline (Install-Module MSOnline)
            UcmPSTools (Install-Module UcmPsTools) Includes Cmdlets below.
 
            Cmdlets
            Write-UcmLog: https://github.com/Atreidae/UcmPsTools/blob/main/public/Write-UcmLog.ps1
            Test-UcmMSOLConnection https://github.com/Atreidae/UcmPsTools/blob/main/public/Test-UcmMSOLConnection.ps1
            New-UcmMSOLConnection https://github.com/Atreidae/UcmPsTools/blob/main/public/New-UcmMSOLConnection.ps1
 
            .REQUIRED PERMISIONS
            'Office 365 User Administrator' or better
 
    #>

    [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseProcessBlockForPipelineCommand', '', Scope='Function')]
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingPlainTextForPassword', '', Scope='Function')] #Todo https://github.com/Atreidae/UcmPSTools/issues/24
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '', Scope='Function')] #Todo https://github.com/Atreidae/UcmPSTools/issues/27

    Param
    (
        [Parameter(ValueFromPipelineByPropertyName=$true, Mandatory, Position=1,HelpMessage='The UPN of the user you wish to create, eg: button.mash@contoso.com')] [string]$UPN,
        [Parameter(ValueFromPipelineByPropertyName=$true, Mandatory, Position=2,HelpMessage='The Password for the user you wish to create, eg: %%32/young/PRESS/road/86%%')] [string]$Password,
        [Parameter(ValueFromPipelineByPropertyName=$true, Mandatory, Position=3,HelpMessage='The first name of the user you wish to create eg: Button')] [string]$FirstName,
        [Parameter(ValueFromPipelineByPropertyName=$true, Mandatory, Position=4,HelpMessage='The last name of the user you wish to create eg: Mash')] [string]$LastName,
        [Parameter(ValueFromPipelineByPropertyName=$true, Mandatory, Position=6,HelpMessage='The display name of the user you wish to create eg: Button Mash')] [string]$DisplayName,
        [Parameter(ValueFromPipelineByPropertyName=$true, Mandatory, Position=5,HelpMessage='The 2 letter country code for the users country, must be in capitals. eg: AU')] [String]$Country #TODO Add country validation.
    )


    #region FunctionSetup, Set Default Variables for HTML Reporting and Write Log
    $function = 'New-UcmOffice365User'
    [hashtable]$Return = @{}
    $return.Function = $function
    $return.Status = "Unknown"
    $return.Message = "Function did not return a status message"

    # Log why we were called
    Write-UcmLog -Message "$($MyInvocation.InvocationName) called with $($MyInvocation.Line)" -Severity 1 -Component $function
    Write-UcmLog -Message "Parameters" -Severity 1 -Component $function -LogOnly
    Write-UcmLog -Message "$($PsBoundParameters.Keys)" -Severity 1 -Component $function -LogOnly
    Write-UcmLog -Message "Parameters Values" -Severity 1 -Component $function -LogOnly
    Write-UcmLog -Message "$($PsBoundParameters.Values)" -Severity 1 -Component $function -LogOnly
    Write-UcmLog -Message "Optional Arguments" -Severity 1 -Component $function -LogOnly
    Write-UcmLog -Message "$Args" -Severity 1 -Component $function -LogOnly


    #endregion FunctionSetup

    #region FunctionWork

    #Check to see if we are connected to MSOL
    $Test = (Test-UcmMSOLConnection) #Todo need to update to support auto reconnect
    If ($Test.Status -ne "OK")
    {
        Write-UcmLog -Message "Something went wrong creating user $UPN" -Severity 3 -Component $function
        Write-UcmLog -Message "Test-UcmMSOLConnection could not locate an MSOL connection" -Severity 2 -Component $function
        $Return.Status = "Error"
        $Return.Message = "No MSOL Connection"
        Return $Return
    }

    #Check to see if the user already exists
    Try
    {
        Write-UcmLog -Message "Checking for Existing User $UPN ..." -Severity 2 -Component $function
        [void] (Get-MsolUser -UserPrincipalName $UPN -ErrorAction Stop)#Returns an error if the user doesnt exist

        #User must exist, otherwise we would have hit the catch block by now. Return a warning
        Write-UcmLog -Message "User Exists, Skipping" -Severity 3 -Component $function
        $Return.Status = "Warning"
        $Return.Message = "User Already Exists"
        Return $Return
    }
    Catch
    {
        #User doesnt exist, let's make themaap)o
        Write-UcmLog -Message "Existing user Not Found. Creating user $UPN" -Severity 2 -Component $function
    }

#Removed from catch block above to neaten code
    Try
    {
        [Void] (New-MsolUser -UserPrincipalName $UPN -DisplayName $DisplayName -FirstName $Firstname -LastName $LastName -UsageLocation $Country -Password $Password -ErrorAction Stop)

        #User was created, return OK
        Write-UcmLog -Message "User Created Sucessfully" -Severity 2 -Component $function
        $Return.Status = "OK"
        $Return.Message = "User Created"
        Return $Return
    }
    Catch
    {
        #Something went wrong creating the user, return an error
        Write-UcmLog -Message "Something went wrong creating user $UPN" -Severity 3 -Component $function
        Write-UcmLog -Message $Error[0] -Severity 3 -Component $Function
        $Return.Status = "Error"
        $Return.Message = $Error[0]
        Return $Return
    }
    #endregion FunctionWork


    #region FunctionReturn

    #Default Return Variable for my HTML Reporting Fucntion
    Write-UcmLog -Message "Reached end of $function without a Return Statement" -Severity 3 -Component $function
    $return.Status = "Unknown"
    $return.Message = "Function did not encounter return statement"
    Return $Return
    #endregion FunctionReturn
}
# SIG # Begin signature block
# MIIRwgYJKoZIhvcNAQcCoIIRszCCEa8CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB
# gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR
# AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUGaJNzWrQ8WOM7kkqQFs/e/lu
# Ic+ggg4OMIIGsDCCBJigAwIBAgIQCK1AsmDSnEyfXs2pvZOu2TANBgkqhkiG9w0B
# AQwFADBiMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD
# VQQLExB3d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVk
# IFJvb3QgRzQwHhcNMjEwNDI5MDAwMDAwWhcNMzYwNDI4MjM1OTU5WjBpMQswCQYD
# VQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xQTA/BgNVBAMTOERpZ2lD
# ZXJ0IFRydXN0ZWQgRzQgQ29kZSBTaWduaW5nIFJTQTQwOTYgU0hBMzg0IDIwMjEg
# Q0ExMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA1bQvQtAorXi3XdU5
# WRuxiEL1M4zrPYGXcMW7xIUmMJ+kjmjYXPXrNCQH4UtP03hD9BfXHtr50tVnGlJP
# DqFX/IiZwZHMgQM+TXAkZLON4gh9NH1MgFcSa0OamfLFOx/y78tHWhOmTLMBICXz
# ENOLsvsI8IrgnQnAZaf6mIBJNYc9URnokCF4RS6hnyzhGMIazMXuk0lwQjKP+8bq
# HPNlaJGiTUyCEUhSaN4QvRRXXegYE2XFf7JPhSxIpFaENdb5LpyqABXRN/4aBpTC
# fMjqGzLmysL0p6MDDnSlrzm2q2AS4+jWufcx4dyt5Big2MEjR0ezoQ9uo6ttmAaD
# G7dqZy3SvUQakhCBj7A7CdfHmzJawv9qYFSLScGT7eG0XOBv6yb5jNWy+TgQ5urO
# kfW+0/tvk2E0XLyTRSiDNipmKF+wc86LJiUGsoPUXPYVGUztYuBeM/Lo6OwKp7AD
# K5GyNnm+960IHnWmZcy740hQ83eRGv7bUKJGyGFYmPV8AhY8gyitOYbs1LcNU9D4
# R+Z1MI3sMJN2FKZbS110YU0/EpF23r9Yy3IQKUHw1cVtJnZoEUETWJrcJisB9IlN
# Wdt4z4FKPkBHX8mBUHOFECMhWWCKZFTBzCEa6DgZfGYczXg4RTCZT/9jT0y7qg0I
# U0F8WD1Hs/q27IwyCQLMbDwMVhECAwEAAaOCAVkwggFVMBIGA1UdEwEB/wQIMAYB
# Af8CAQAwHQYDVR0OBBYEFGg34Ou2O/hfEYb7/mF7CIhl9E5CMB8GA1UdIwQYMBaA
# FOzX44LScV1kTN8uZz/nupiuHA9PMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAK
# BggrBgEFBQcDAzB3BggrBgEFBQcBAQRrMGkwJAYIKwYBBQUHMAGGGGh0dHA6Ly9v
# Y3NwLmRpZ2ljZXJ0LmNvbTBBBggrBgEFBQcwAoY1aHR0cDovL2NhY2VydHMuZGln
# aWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZFJvb3RHNC5jcnQwQwYDVR0fBDwwOjA4
# oDagNIYyaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZFJv
# b3RHNC5jcmwwHAYDVR0gBBUwEzAHBgVngQwBAzAIBgZngQwBBAEwDQYJKoZIhvcN
# AQEMBQADggIBADojRD2NCHbuj7w6mdNW4AIapfhINPMstuZ0ZveUcrEAyq9sMCcT
# Ep6QRJ9L/Z6jfCbVN7w6XUhtldU/SfQnuxaBRVD9nL22heB2fjdxyyL3WqqQz/WT
# auPrINHVUHmImoqKwba9oUgYftzYgBoRGRjNYZmBVvbJ43bnxOQbX0P4PpT/djk9
# ntSZz0rdKOtfJqGVWEjVGv7XJz/9kNF2ht0csGBc8w2o7uCJob054ThO2m67Np37
# 5SFTWsPK6Wrxoj7bQ7gzyE84FJKZ9d3OVG3ZXQIUH0AzfAPilbLCIXVzUstG2MQ0
# HKKlS43Nb3Y3LIU/Gs4m6Ri+kAewQ3+ViCCCcPDMyu/9KTVcH4k4Vfc3iosJocsL
# 6TEa/y4ZXDlx4b6cpwoG1iZnt5LmTl/eeqxJzy6kdJKt2zyknIYf48FWGysj/4+1
# 6oh7cGvmoLr9Oj9FpsToFpFSi0HASIRLlk2rREDjjfAVKM7t8RhWByovEMQMCGQ8
# M4+uKIw8y4+ICw2/O/TOHnuO77Xry7fwdxPm5yg/rBKupS8ibEH5glwVZsxsDsrF
# hsP2JjMMB0ug0wcCampAMEhLNKhRILutG4UI4lkNbcoFUCvqShyepf2gpx8GdOfy
# 1lKQ/a+FSCH5Vzu0nAPthkX0tGFuv2jiJmCG6sivqf6UHedjGzqGVnhOMIIHVjCC
# BT6gAwIBAgIQDyLHeeRvkUFg5QtSFTT8FjANBgkqhkiG9w0BAQsFADBpMQswCQYD
# VQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xQTA/BgNVBAMTOERpZ2lD
# ZXJ0IFRydXN0ZWQgRzQgQ29kZSBTaWduaW5nIFJTQTQwOTYgU0hBMzg0IDIwMjEg
# Q0ExMB4XDTIzMDIyMzAwMDAwMFoXDTI2MDIyMzIzNTk1OVowXjELMAkGA1UEBhMC
# QVUxETAPBgNVBAgTCFZpY3RvcmlhMRAwDgYDVQQHEwdCZXJ3aWNrMRQwEgYDVQQK
# EwtKYW1lcyBBcmJlcjEUMBIGA1UEAxMLSmFtZXMgQXJiZXIwggIiMA0GCSqGSIb3
# DQEBAQUAA4ICDwAwggIKAoICAQC47oExh25TrxvApIYdMRYvjOdZCb8WwgeTemm3
# ZY7BElIWu6+gzRGqQe8RFsN7oIgin5pvjTYIToxt1CCag2A5o8L0NtULmxJEegc+
# VaF24DZQqI4qGQGH/Qnglqys6+yPkwLnfeSxpeWe4u49HUUGDFIxHCh42MlCLp/f
# fHT49QhhpO+LyeLnDoUs6DmahyIb6NeE2cW5AYRXEesW7GRNfXzygBSlVWJOgvcy
# V5Y4IvAZVx2hKKMTjYFIz4/RYMg7fwYZEJ2LRJ/GnVazobKAvh6ZBet5KwVNI9EI
# 29DtWQyK/RoPOguTRcB5VuiZVlv0xjBYM7iJuH2Soa3StQYVxL/5gjZCC9WOs4NR
# EIGU3XmHoogFDvoT1vf1izMPFQzdZfgPvy/XXsbgTVo5ncesJ6WtZwqwCXG1K0XW
# IPZqTHolc1MyU6K1bEHO+7YWLpKgM9THl644G7PEhcKpNDsHlfvLVQdYhI55UJtc
# iyMrTw11CNECvk3GK1mrluvKsrxdaH6G3Sp9VVHRtef6OZ5SlzkM5ID4egB2bXRb
# R/69bEuZr5hhm+v2lBSWIbZj/Mva6i/a/TAvy4vvPLo3DRcASkYZDC4T8gDMzmpG
# Xs4jAc9sfTL9z+o5u1PLJHFGRjJ+Wa2CgSftCdbKLjn+AY9m8ipc8jmOBKNY9yGI
# pQWapQIDAQABo4ICAzCCAf8wHwYDVR0jBBgwFoAUaDfg67Y7+F8Rhvv+YXsIiGX0
# TkIwHQYDVR0OBBYEFOBsg1xudlbXVSql8pWbiHoTyZS/MA4GA1UdDwEB/wQEAwIH
# gDATBgNVHSUEDDAKBggrBgEFBQcDAzCBtQYDVR0fBIGtMIGqMFOgUaBPhk1odHRw
# Oi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkRzRDb2RlU2lnbmlu
# Z1JTQTQwOTZTSEEzODQyMDIxQ0ExLmNybDBToFGgT4ZNaHR0cDovL2NybDQuZGln
# aWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZEc0Q29kZVNpZ25pbmdSU0E0MDk2U0hB
# Mzg0MjAyMUNBMS5jcmwwPgYDVR0gBDcwNTAzBgZngQwBBAEwKTAnBggrBgEFBQcC
# ARYbaHR0cDovL3d3dy5kaWdpY2VydC5jb20vQ1BTMIGUBggrBgEFBQcBAQSBhzCB
# hDAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMFwGCCsGAQUF
# BzAChlBodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVk
# RzRDb2RlU2lnbmluZ1JTQTQwOTZTSEEzODQyMDIxQ0ExLmNydDAJBgNVHRMEAjAA
# MA0GCSqGSIb3DQEBCwUAA4ICAQBOh5vRXqTCQzv0T1F2EgDkq5VnljlHsa7Ov/d/
# lpOvr8NebBiatxbhfhPCnToY7BD2f7YVsUuQ+VDdcIYsskcU5spBHcFYidg2jGu4
# 59FGMaS765XStDwGGTN/360gEsNYSnKWYL4+8jYWHlzRO0jHloyWz+gF5dYWzdDJ
# u1dudLIJ0RgrEVJeLSgIBWygLL5EyIzOPlrxztsILMSbdPTQLeBIm7ipOk4EACx1
# hhBVUsUoCAlASH+yCKDU4v2HFd7SzrkRUrf7XJ2Na2YsiHjiTGqHIE86KyvxGDhT
# 3n2/jX23Nh/bkWHurHwTfaTCOQ44ZlAbnZQjBlmrFn5hPMXRpciiQFmrKTPD/nuo
# 9MVnCciHEpHJ63/JZNF/eno1122/wVkL7MuRlCVHN7L/wuNQxQk3ARdIju6OD/Gi
# Mwg0Qih6HVWJtkHK3ExoUKKKUZCOvIeHxzp+K6FWUupPZKUgWzn4AHMxm6zr+Sde
# laIAACqAkxYsDYKbM7WlNi3uIH2HeXqU9uSDt5tgPpImrog/ab4HrhpDfITRgT1c
# cxaWQezpJEPC+kqVD41T3wlEie1Qm4vYWg+oBVEMBxVLh6CYbeppCRTEXRGnAiCH
# /Ma1uwyWnNCWxrhd1uSi6sj4ISzgnFyGCvsI0gavKpS5AQhapJgk6/fULTFeS+Ee
# kRH9FDGCAx4wggMaAgEBMH0waTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lD
# ZXJ0LCBJbmMuMUEwPwYDVQQDEzhEaWdpQ2VydCBUcnVzdGVkIEc0IENvZGUgU2ln
# bmluZyBSU0E0MDk2IFNIQTM4NCAyMDIxIENBMQIQDyLHeeRvkUFg5QtSFTT8FjAJ
# BgUrDgMCGgUAoHgwGAYKKwYBBAGCNwIBDDEKMAigAoAAoQKAADAZBgkqhkiG9w0B
# CQMxDAYKKwYBBAGCNwIBBDAcBgorBgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAj
# BgkqhkiG9w0BCQQxFgQUOzX5r1nLuwmYoBetP4TkOj5bGg8wDQYJKoZIhvcNAQEB
# BQAEggIAmMxqVjvBfhPtWx0a41nvetBoj66+F3NeaQuKQV/xbKzboz5IwEnUZN5z
# TBzLOuNOIjjlw+qdR+bWEoaioRSa/FBQfizq8ruisDgN+rjWBLKYRupJBwUy7u0m
# t889D/6i/Y8l+JnIfA+0o+bGrNjKhtDx+/1o7iiBg8VKSaA+fu3nwgBJyWoxNDY/
# qNa9J6ICvX+VyGS/xdKNhV4D/DfjnwxpJGwOpZbD1+JCJDlsE6Q50FnhJLS+gcvi
# N0aU7fC5euoDebOrJY9j+Cm5Axn/itRqLjjo6hJuf0B/twA93gzjGzgKHEfPTmYz
# jhoMy3Ly23mxF071zid3tOZT5HKv++3NNUAC9vJYDNKqQsdQfAs/5U/P7butDT75
# 46j9OJEfiN8KmYkd/N9GEt3CvllMRAgh0SyRojd8alTeBrvBFs7VT8RcbYFOULmc
# TSzspLlZDrbDB1a7xxQouwH63Q3JAMeufVhnP8I8Mp9I4GtrOrVI2YZzSkGKojXq
# 33VuIXVrpFEWlsPFFR/dROpz2JwAhHPw55mUmbbRfj2hDLGFAmguHnYweVtCzkmV
# dIqn9ODKc0AYkiYVoQygstEHMztfDtb1bamdg7F/oJVofuAS89WWyNZKCrWmgYOZ
# GcI9WeC+R6+DgGL533PNGbisDJ9245jYE1Ff2NBDJicVlxLtRt8=
# SIG # End signature block