Scripts/Set-D365ApplicationUser.ps1

#
# Set-D365ApplicationUser.ps1
#

function Add-D365ApplicationUser {
Param(
    [Parameter(Mandatory = $true)] [string] $d365ResourceName  
    , [Parameter(Mandatory = $true)] [string] $servicePrincipal
    , [Parameter(Mandatory = $true)] [string] $roleNames
)

$securityRoleNames = $roleNames.Split(',')
$d365ResourceName = $d365ResourceName.Replace(".dynamics.com/", ".dynamics.com")
# Forcing Tls 1.2
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12

$aToken=$(az account get-access-token --resource $d365ResourceName) | ConvertFrom-Json

$accessToken = $aToken.accessToken

function Get-DefaultBusinessUnit {
    param (
        [string] [Parameter(Mandatory = $true)] $d365ResourceName,
        [string] [Parameter(Mandatory = $true)] $accessToken
    )

    $apiUrl = "$d365ResourceName/api/data/v9.1"

    $response = Invoke-RestMethod `
        -Uri "$apiUrl/businessunits?`$select=businessunitid,name&`$filter=parentbusinessunitid eq null" `
        -Method Get `
        -Headers @{"Authorization" = "Bearer $accessToken"; "Accept" = "application/json"; "OData-MaxVersion" = "4.0"; "OData-Version" = "4.0" }
  
    return $response.value[0].businessunitid
}

function Get-ApplicationUser {
    param (
        [string] [Parameter(Mandatory = $true)] $d365ResourceName,
        [string] [Parameter(Mandatory = $true)] $accessToken,
        [string] [Parameter(Mandatory = $true)] $applicationId,
        [string] [Parameter(Mandatory = $true)] $businessUnitId
    )

    $apiUrl = "$d365ResourceName/api/data/v9.1"

    $headers = @{
        "Authorization"    = "Bearer $accessToken";
        "Accept"           = "application/json";
        "OData-MaxVersion" = "4.0";
        "OData-Version"    = "4.0"
    }

    $response = Invoke-RestMethod `
        -Uri "$apiUrl/systemusers?`$select=systemuserid,applicationid&`$filter=applicationid eq '$applicationId' and businessunitid/businessunitid eq '$businessUnitId'" `
        -Method Get `
        -Headers $headers

    if ($response.value.count -gt 0) {
        return $response.value[0]
    }
}

function New-ApplicationUser {
    param (
        [string] [Parameter(Mandatory = $true)] $d365ResourceName,
        [string] [Parameter(Mandatory = $true)] $accessToken,
        [string] [Parameter(Mandatory = $true)] $applicationId,
        [string] [Parameter(Mandatory = $true)] $businessUnitId
    )

    $apiUrl = "$d365ResourceName/api/data/v9.1"

    $headers = @{
        "Authorization"    = "Bearer $accessToken";
        "Accept"           = "application/json";
        "OData-MaxVersion" = "4.0";
        "OData-Version"    = "4.0";
        "Prefer"           = "return=representation"
    }    

    $body = @{
        "applicationid"             = "$applicationId";
        "internalemailaddress"      = "$applicationId@$($([System.Uri]$d365ResourceName).Host)";
        "businessunitid@odata.bind" = "/businessunits($businessUnitId)"
    }

    $response = Invoke-RestMethod `
        -Uri "$apiUrl/systemusers" `
        -Method Post `
        -Headers $headers `
        -ContentType "application/json" `
        -Body ($body | ConvertTo-Json)
  
    return $response  
}

function Set-ApplicationUser {
    param (
        [string] [Parameter(Mandatory = $true)] $d365ResourceName,
        [string] [Parameter(Mandatory = $true)] $accessToken,
        [string] [Parameter(Mandatory = $true)] $systemUserId,
        [string] [Parameter(Mandatory = $true)] $applicationId,
        [string] [Parameter(Mandatory = $true)] $businessUnitId
    )

    $apiUrl = "$d365ResourceName/api/data/v9.1"

    $headers = @{
        "Authorization"    = "Bearer $accessToken";
        "Accept"           = "application/json";
        "OData-MaxVersion" = "4.0";
        "OData-Version"    = "4.0";
        "Prefer"           = "return=representation"
    }

    $body = @{
        "applicationid"             = "$applicationId";
        "internalemailaddress"      = "$applicationId@$($([System.Uri]$d365ResourceName).Host)";
        "businessunitid@odata.bind" = "/businessunits($businessUnitId)";
        "isdisabled"                = "$false";
    }

    $response = Invoke-RestMethod `
        -Uri "$apiUrl/systemusers($systemUserId)" `
        -Method PATCH `
        -Headers $headers `
        -ContentType "application/json" `
        -Body ($body | ConvertTo-Json)

    return $response;
}

function Get-Role {
    param (
        [string] [Parameter(Mandatory = $true)] $d365ResourceName,
        [string] [Parameter(Mandatory = $true)] $accessToken,
        [string] [Parameter(Mandatory = $true)] $roleName,
        [string] [Parameter(Mandatory = $true)] $businessUnitId
    )

    $apiUrl = "$d365ResourceName/api/data/v9.1"

    $headers = @{
        "Authorization"    = "Bearer $accessToken";
        "Accept"           = "application/json";
        "OData-MaxVersion" = "4.0";
        "OData-Version"    = "4.0"
    }

    $response = Invoke-RestMethod `
        -Uri "$apiUrl/roles?`$select=roleid&`$filter= name eq '$roleName' and businessunitid/businessunitid eq '$businessUnitId'" `
        -Method Get `
        -Headers $headers

    if ($response.value.count -gt 0) {
        return $response.value[0]
    }
}

function Set-ApplicationUserRole {
    param (
        [string] [Parameter(Mandatory = $true)] $d365ResourceName,
        [string] [Parameter(Mandatory = $true)] $accessToken,
        [string] [Parameter(Mandatory = $true)] $systemUserId,
        [string] [Parameter(Mandatory = $true)] $roleId
    )

    $apiUrl = "$d365ResourceName/api/data/v9.1"

    $headers = @{
        "Authorization"    = "Bearer $accessToken";
        "Accept"           = "application/json";
        "OData-MaxVersion" = "4.0";
        "OData-Version"    = "4.0";
    }

    $body = @{
        '@odata.id' = "$apiUrl/roles($roleId)"
    }

    Invoke-RestMethod `
        -Uri "$apiUrl/systemusers($systemUserId)/systemuserroles_association/`$ref" `
        -Method Post `
        -Headers $headers `
        -ContentType "application/json" `
        -Body ($body | ConvertTo-Json) `
    | Out-Null
}
    

$businessUnitId = Get-DefaultBusinessUnit `
    -d365ResourceName $d365ResourceName `
    -accessToken $accessToken
    
$applicationUser = Get-ApplicationUser `
    -d365ResourceName $d365ResourceName `
    -accessToken $accessToken `
    -applicationId $servicePrincipal `
    -businessUnitId $businessUnitId
    
if (!$applicationUser) {
    Write-Host "`nCreating application user..."
    Write-Host $businessUnitId
    $applicationUser = New-ApplicationUser `
        -d365ResourceName $d365ResourceName `
        -accessToken $accessToken `
        -applicationId $servicePrincipal `
        -businessUnitId $businessUnitId
    Write-Host "Application user created..."
}
else {
    Write-Host "`nUpdating application user..."
    $applicationUser = Set-ApplicationUser `
        -d365ResourceName $d365ResourceName `
        -accessToken $accessToken `
        -systemUserId $applicationUser.systemuserid `
        -applicationId $servicePrincipal `
        -businessUnitId $businessUnitId    
    Write-Host "Application user updated..."
}
    
foreach ($securityRoleName in $securityRoleNames) {
    Write-Host "`nChecking if the security role $securityRoleName exists..."
    $securityRole = Get-Role `
        -d365ResourceName $d365ResourceName `
        -accessToken $accessToken `
        -roleName $securityRoleName `
        -businessUnitId $businessUnitId
        
    if (!$securityRole) {
        Write-Host "$securityRoleName does not exist."
        return
    }
    
    Write-Host "Assigning role $securityRoleName to application user $($servicePrincipal)..."
    Set-ApplicationUserRole `
        -d365ResourceName $d365ResourceName `
        -accessToken $accessToken `
        -systemUserId $applicationUser.systemuserid `
        -roleId $securityRole.roleid
    Write-Host "Role $securityRoleName assigned to application user $($servicePrincipal)."
}    

}