Update-ImmutableIDAzureAD.psm1

<#
 .Synopsis
  Updates the Immutable ID of an Azure AD user based upon the user's on-premises ObjectGUID.
 
 .Description
  Allows Azure AD Global Admins to update Azure AD user's Immutable ID based upon the users
  on-premises ObjectGUID value. This change can be either to add or update the Immutable ID of
  the specified Azure AD User.
 
 .Parameter SAMAccount
  This value is the value of the on-premises SAM Account.
  Format is username not domain\username.
  Must be run in the domain in which the user resides.
 
 .Parameter UserPrincipalName
  This value is the value of the User Principal Name in Azure AD.
 
 .Parameter ChangeType
  This value is the value of the type of change you are making.
  If the ImmutableID is empty then you would select "Add".
  If the ImmutableID is populated and needs to be changed, you would select "Update".
 
 .Example
   # Add an Immutable ID to an Azure AD User.
   Update-ImmutableIDAzureAD -SAMAccount username -UserPrincipalName user@domain.com -ChangeType Add
 
 .Example
   # Update an Immutable ID to an Azure AD User.
   Update-ImmutableIDAzureAD -SAMAccount username -UserPrincipalName user@domain.com -ChangeType Update
#>


function Update-ImmutableIDAzureAD {
param(
[Parameter(Mandatory)] [string] $SAMAccount,
[Parameter(Mandatory)] [string] $UserPrincipalName,
[Parameter(Mandatory)][ValidateSet("Add","Update")] [string] $ChangeType
)
    #Check if the ChangeType value is correct
    If(($ChangeType -ne 'Update') -and ($ChangeType -ne 'Add')){
    Write-Host -Object "The ChangeType value is incorrect, the value should be either: Add or Update" -ForegroundColor Red
    throw "Incorrect ChangeType"
    }

    #Output the name of the account that is being updated
    Write-Host -Object "The account that is being updated is: $UserPrincipalName" -ForegroundColor Cyan

    #Import the Azure AD PowerShell Modules if they are installed
    Import-module -Name AzureAD  -ErrorAction SilentlyContinue
    Import-module -Name AzureADPreview  -ErrorAction SilentlyContinue
    $isAzureADInstalled = Get-Module | Where-Object -Property Name -like "*AzureAD*" -ErrorAction SilentlyContinue

    #Check if the Azure AD PowerShell module is not installed, then install AzureAD PowerShell module
    If($null -eq $isAzureADInstalled){
        Write-Host -Object "The AzureAD PowerShell module is not installed. Installing now." -ForegroundColor Yellow
        Install-module AzureAD
    }

    #Check if the ActiveDirectory PowerShell module is installed
    $isAdDsLdsInstalled = Get-WindowsCapability -Online -Name Rsat.ActiveDirectory.DS-LDS.Tools~~~~0.0.1.0 | Select-Object -ExpandProperty State

    #If the ActiveDirectory PowerShell module is not installed, then install the AzureAD PowerShell module
    If($isAdDsLdsInstalled -eq "NotPresent")
    {
        Write-Host -Object "The ActiveDirectory PowerShell Module is not installed. Installing now." -ForegroundColor Yellow
        Add-WindowsCapability -Online -Name Rsat.ActiveDirectory.DS-LDS.Tools~~~~0.0.1.0
    }

    #Check to see if the current user is signed into Azure AD via PowerShell and if not prompt for connection
    try{
        Get-AzureADCurrentSessionInfo -ErrorAction Ignore | Out-Null
        }
    catch [Microsoft.Open.Azure.AD.CommonLibrary.AadNeedAuthenticationException]{
       Write-Host -Object "PowerShell is not signed into Azure AD, prompting to sign in now." -ForegroundColor Yellow
       Connect-AzureAD | Out-Null
    }
    catch{
            throw "An unexpected error occurred"
        }

    #Check if the UserPrincipalName entered was in the correct format
    try{
        $User = Get-AzureADUser -Filter "userPrincipalName eq '$UserPrincipalName'" -ErrorAction SilentlyContinue
        }
    catch [Microsoft.Open.AzureAD16.Client.ApiException] {
        Write-Host -Object "Failure! The UPN was not found" -ForegroundColor Red
        Write-Host -Object "Please confirm that the UPN value is correct" -ForegroundColor Red
        throw "UPN Format Incorrect"
    }
    catch{
            throw "An unexpected error occurred"
        }

    #Check if the UserPrincipalName is null
    if($null -eq $User){
        Write-Host -Object "Failure! The UPN was not found" -ForegroundColor Red
        Write-Host -Object "Please confirm that the UPN value is correct" -ForegroundColor Red
        throw "UPN Incorrect"
    }

    $oldImmutableID = $User.ImmutableID

    #Check if the ImmutableID is null and the ChangeType is not an Add
    if($null -eq $oldImmutableID -and $ChangeType -ne "Add"){
        Write-Host -Object "Failure! The user's current ImmutableID cannot be empty on an Update" -ForegroundColor Red
        Write-Host -Object "Please make sure you typed the correct UPN and you are updating the correct user" -ForegroundColor Red
        throw "ImmutableID empty"
    }

    #Output the old ImmutableID
    Write-Host -Object "This value is the old Immutable ID: $oldImmutableID" -ForegroundColor Cyan

    #Get the User's ObjectGUID from AD, and then convert it to its Base64 value
    try{
        $ObjGUID = Get-ADUser -Identity $SAMAccount -ErrorAction SilentlyContinue | Select-Object -ExpandProperty ObjectGuid
    }
    catch [Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException] {
        Write-Host -Object "Failure! The SAM Account cannot be found!" -ForegroundColor Red
        Write-Host -Object "Please ensure the SAM Account is correct." -ForegroundColor Red
        Write-Host -Object "Also, confirm the SAM Account is in this format, if account is Domain\user, SAM Account is: user" -ForegroundColor Red
        throw "SAM Account Incorrect"
    }
    catch{
            throw "An unexpected error occurred"
        }

    #Convert the ObjectGUID into Base64 format and output the value as the new ImmutableID
    $base64 = [system.convert]::ToBase64String(($ObjGUID).ToByteArray())
    Write-Host -Object "This value is the new Immutable ID: $base64" -ForegroundColor Magenta

    #Confirmation the add or update is correct and the changes can be made
    $Confirm = Read-Host "Confirm you would like to proceed with updating this user's Immutable ID (y/n)"

    If($Confirm -eq 'y'){

        #Find the user and set their Immutable ID to the value from AD
        try{
            Set-AzureADUser -ObjectId $User.ObjectID -ImmutableId $base64
        }
        catch [Microsoft.Open.AzureAD16.Client.ApiException],[Microsoft.Open.AzureAD16.PowerShell.SetUser] {
           Write-Host -Object "Failure! The user's immutable ID was not updated" -ForegroundColor Red
           Write-Host -Object "Please confirm there is not a user with a duplicate Immutable ID of $base64" -ForegroundColor Red
           Write-Host -Object "Also check deleted users: https://portal.azure.com > Azure Active Directory > Users > Deleted Users" -ForegroundColor Red
           throw "Duplicate Immutable ID"
        }
        catch{
            throw "An unexpected error occurred"
        }

            $changedImmutableID = Get-AzureADUser -Filter "userPrincipalName eq '$Userprincipalname'" | Select-Object -ExpandProperty ImmutableID
            Write-Host -Object "The user $SAMAccount Immutable ID has been updated to $changedImmutableID" -ForegroundColor Green
    }
}
Export-ModuleMember -Function Update-ImmutableIDAzureAD
# SIG # Begin signature block
# MIIFsgYJKoZIhvcNAQcCoIIFozCCBZ8CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB
# gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR
# AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUj+BiByGLBYxx9gG1AkvtjlM3
# pmWgggM2MIIDMjCCAhqgAwIBAgIQGqf9kD2EYalP1tlcNlL8fDANBgkqhkiG9w0B
# AQsFADAxMS8wLQYDVQQDDCZVcGRhdGUtSW1tdXRhYmxlSURBenVyZUFEIFNpZ25p
# bmcgQ2VydDAeFw0yMTA5MjExOTE4MzNaFw0yMjA5MjExOTM4MzNaMDExLzAtBgNV
# BAMMJlVwZGF0ZS1JbW11dGFibGVJREF6dXJlQUQgU2lnbmluZyBDZXJ0MIIBIjAN
# BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvcyT6j+zSxgEmggb10+iZfOXa1sX
# E5DMsfTdEO8LO2SEO6MdbEFRl3wahhW/jio9LE+RZZgZogBH/PJsa+jrAnaceKAS
# zFxiMbu235NmUezMbqp0oOySGjwxpJd4dohK3TLIbNJ+a+M+CvVNe2asa64nj8dR
# 2POu81u+eB//VGCdUCw2R0MHHZBVkpe0X9f4scV1Fb1OhsH9gxXY6PC3/2WKuRCp
# KsoByaO+AE/Wr0KZFzVTDi0joSi1990NXqjdkr71gDrxG2A3ds+bhN27z+hINrn5
# 8VkfBt4jGzZKEY42ktb8XhTZS9k/SYL7A99LC/+FKfzNZMHxATBlVPqpuQIDAQAB
# o0YwRDAOBgNVHQ8BAf8EBAMCB4AwEwYDVR0lBAwwCgYIKwYBBQUHAwMwHQYDVR0O
# BBYEFIvwe0Gu20P3g6ib1KbYCoW1Jgq2MA0GCSqGSIb3DQEBCwUAA4IBAQAeW4Ii
# Vi6ISO4LwuA7emNDsqph7L96JxagT+Aoul1GK+E//LWsqZYuyJHAJtkyBWaBd8an
# h9sIjZzDQIbprtMTUsBw0oLkP8WmTuPC/eYW5yReAt/OgQrpQ/DNnVmwODWvfZf0
# vk/H25uijCfPnzBG2IYDHPgV/svYtQzWVXoAD9qQ/zmi8fijrLR7oDlr0n2XTbep
# XoNXK1t1hLzbFjP/Mknx4PYKJnkT6Ogn4NMfKWnO5aQLT/G5tzqqsG/PbzxzlbeW
# IJ1BnF5SsEHTrkWFSlIgHvVXcrA3woBFD6QTY5pucVIZlWPB/NCtO1EtIlQHHHSf
# T3MXEcBWnVFwB7OrMYIB5jCCAeICAQEwRTAxMS8wLQYDVQQDDCZVcGRhdGUtSW1t
# dXRhYmxlSURBenVyZUFEIFNpZ25pbmcgQ2VydAIQGqf9kD2EYalP1tlcNlL8fDAJ
# BgUrDgMCGgUAoHgwGAYKKwYBBAGCNwIBDDEKMAigAoAAoQKAADAZBgkqhkiG9w0B
# CQMxDAYKKwYBBAGCNwIBBDAcBgorBgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAj
# BgkqhkiG9w0BCQQxFgQUYteSJRh1mD8N56ixjbEWNf4O9LswDQYJKoZIhvcNAQEB
# BQAEggEAAjhcAUNCUpp+NHW3Qha8lSl718pYhd9KXsEBngCmkv6Xv+8ot/NvGILS
# 2TMWKp+iJEXMbOuYNbz2yW+zOSAII+M8tPZmH3ycxCifay8X+ujEuWv/LhgocH+U
# Z9J5Y+1Pf68T4+GICVFba8meL7NXX0kRXf9qU5tpIV+FOr9kjrXDp+pIqAFy9dZE
# jZoaYfJ4i51YwMykEe1H8mS0KnrgHXOY9OW89/2CZgM88cCIrpFtOdZB9l7quzie
# 521GNGUAzi+tTtNg7Yb+ZlibZF0rFnXgtG+uYH4xb/kp3rgRZDpPHNsYrI1aplSM
# Mx/uemytzTlD2GCMVLmN/CGIrKjY1A==
# SIG # End signature block