1. 記事一覧 >
  2. ブログ記事
Dataverse
category logo

Dataverse APIでsystemuserテーブルにAzure ADユーザーを同期

(更新) (公開)

はじめに

Microsoft Dataverse の systemuser テーブル に Azure AD ユーザーを同期しました。ユーザーが Dataverse(Power Apps)を使い始めたりすると、自動で同期するようですが、API でなんとかならないか、Postman を使って探ってみましたところ、なんとかなりましたので、紹介していきたいと思います。


Azure AD - Dataveser 同期 図


systemuser テーブル に Azure AD ユーザーを同期するだけの場合、Power Platform 管理センターから手動、Power Automate、Power Apps、Power Shell といろいろやり方が有るようでしたが、今回は、Microsoft Dataverse Web API で同期の方法 の話です。


Postman や Azure 準備手順については、前回記事、「Postmanを使ってMicrosoft Dataverse Web APIで部署を追加」にありますので、省略します。Postman インストール、アクセストークン準備済みとします。Azure Active Directory へのアプリ登録済みとします。

Dataverse 等の状況は、2022年10月現在の状況を元にしています。


やり方

なんと!
一行で終了します!


GET [Organization URI]/api/data/v9.2/systemusers(azureactivedirectoryobjectid=<user object ID>)
例:GET https://***********.api.crm*.dynamics.com/api/data/v9.2/systemusers(azureactivedirectoryobjectid=c74a8***-****-****-****-*******abb78)


だけです。POST ではなく、GET です。

<user object ID> は、Azure Active Directory の ユーザーのオブジェクト ID です。これに当たる人が Dataverse の ユーザー テーブル( systemuser テーブル)にまだ登録されていない場合、登録されます。
既に登録されている場合、その人の systemuser テーブルのレコード情報を返します。

<user object ID> 確認方法

[Organization URI] 確認方法


ググりまくっても、なかなか分からず、API では、できないかと思いましたが、
learn.microsoft.com にサラっと書いてありました。


Azure Active Directory グループのチームとの連携」(https://learn.microsoft.com/ja-jp/power-apps/developer/data-platform/aad-group-team
learn.microsoft.com の記述


「Azure ユーザー オブジェクト識別子 (ID) を使用してユーザー行を取得できます。 ユーザーが Dataverse に存在しない場合、ユーザーが Dataverse に自動的に追加されます。」

全く間違ったことを言っていないですが、あまりにもサラっと書いてあるので、別の話と思い、スルーしていました。

GET [Organization URI]/api/data/v9.0/SystemUser(azureactivedirectoryobjectid=<user object ID>)

は、2022年10月 時点では、誤植のようです。

GET [Organization URI]/api/data/v9.2/systemusers(azureactivedirectoryobjectid=<user object ID>)

でうまくいきました。

英語版も同じでした。(https://learn.microsoft.com/en-us/power-apps/developer/data-platform/aad-group-team


結果

PowerApps - Dataverse ユーザー テーブル( systemuser テーブル)に以下のように登録されます。


GET https://***********.api.crm*.dynamics.com/api/data/v9.2/systemusers(azureactivedirectoryobjectid=c74a8***-****-****-****-*******abb78)

Dataverse ユーザー テーブル1

Dataverse ユーザー テーブル2

Dataverse ユーザー テーブル3

PowerApps - Dataverse ユーザー テーブル( systemuser テーブル)に挿入されていることを確認できました。

Dataverse ユーザー テーブル4

表示列は適当に選別しました。


PATCH

登録したら、所属部署等は、PATCH リクエストで適宜登録情報を変更できます。


PATCH https://***********.api.crm*.dynamics.com/api/data/v9.2/systemusers(azureactivedirectoryobjectid=c74a8***-****-****-****-*******abb78)

リクエストBody
{
    "lastname": "テスト",
    "firstname": "太郎",
    "address1_telephone1": "090-0000-0000",
    "businessunitid@odata.bind": "/businessunits(c74a8***-****-****-****-*******abb78)"
}

Postman PATCHリクエスト


Dataverse ユーザー テーブル( systemuser テーブル)は、以下のようになります。 PATCH 後 Dataverse ユーザー テーブル

Azure Active Directory - <テナント> - ユーザー には反映されません。


DELETE

削除することもできました。

いきなり削除しようとすると、以下のエラーになりますので、いったん、状態 列( isdisabled 列)を true にする必要があります。

error
{
    "error": {
        "code": "0x80048356",
        "message": "User with SystemUserId=020fc***-****-****-****-*******279c8 is not disabled. Disable user before deletion.\""
    }
}

PATCH https://***********.api.crm*.dynamics.com/api/data/v9.2/systemusers(azureactivedirectoryobjectid=c74a8***-****-****-****-*******abb78)

リクエストBody
{
    "isdisabled": true
}

isdisabled PATCH


これで、削除できると思いましたが、まだ問題ありです。Azure Active Directory - <テナント> - ユーザー の方を先に削除してくださいと言ってきます。

error
{
    "error": {
        "code": "0x80048359",
        "message": "User with SystemUserId=020fc***-****-****-****-*******279c8 and AzureActiveDirectoryObjectId=c74a8***-****-****-****-*******abb78 is present in Azure Active Directory with state Exists. Please permanently delete user in Azure first."
    }
}

無効にしたのだから、実質消えたようなものですが、なにがなんでも削除したい場合、Azure Active Directory - <テナント> - ユーザー の方を先に削除すると、Dataverse ユーザー テーブル( systemuser テーブル)から削除できました。
指示通り、Azure Active Directory - <テナント> - ユーザー の方を先に削除してもまだダメでした。

error
{
    "error": {
        "code": "0x80048359",
        "message": "User with SystemUserId=020fc***-****-****-****-*******279c8 and AzureActiveDirectoryObjectId=c74a8***-****-****-****-*******abb78 is present in Azure Active Directory with state SoftDeleted. Please permanently delete user in Azure first."
    }
}

完全に削除が必要でした。

完全に削除


DELETE https://***********.api.crm*.dynamics.com/api/data/v9.2/systemusers(azureactivedirectoryobjectid=c74a8***-****-****-****-*******abb78)

Postman DELETEリクエスト


Dataverse ユーザー テーブル( systemuser テーブル)から消えます。


<user object ID> 確認方法

方法その1

PowerApps - Dataverse AAD User テーブル( aaduser テーブル)で確認できます。

A unique identifer for AAD User 列( id 列) AAD user id 列( aaduserid 列) が <user object ID> に該当します。

AAD User


方法その2

API で Get して確認できます。
GET https://***********.api.crm*.dynamics.com/api/data/v9.2/aadusers?$select=displayname

Response例
{
    "@odata.context": "https://***********.api.crm*.dynamics.com/api/data/v9.2/$metadata#aadusers(displayname)",
    "value": [
        {
            "displayname": "te st2",
            "aaduserid": "********-****-****-****-************"
        },
        {
            "displayname": "Test User1",
            "aaduserid": "c74a8***-****-****-****-*******abb78"
        },
        {
            "displayname": "test1",
            "aaduserid": "********-****-****-****-************"
        }
    ]
}

あるいは、ユーザー プリンシパル ID(サインイン ID)が分かっている場合、以下のようにもできます。

GET https://***********.api.crm*.dynamics.com/api/data/v9.2/aadusers?$select=aaduserid&$filter=userprincipalname eq 'testuser1@example.onmicrosoft.com'

Response例
{
    "@odata.context": "https://***********.api.crm*.dynamics.com/api/data/v9.2/$metadata#aadusers(aaduserid)",
    "value": [
        {
            "aaduserid": "c74a8***-****-****-****-*******abb78"
        }
    ]
}

方法その3

Azure ポータルAzure Active Directoryユーザー<該当ユーザー>
オブジェクト ID で確認できます。

Azure Active Directory → ユーザー


ユーザー → <該当ユーザー>


オブジェクト ID


[Organization URI] 確認方法

Power Apps 右上の歯車開発者リソースWeb API エンドポイント に表示される URL です。

右上歯車


開発者リソース


試したこと(同期NGケース)

POST https://***********.api.crm*.dynamics.com/api/data/v9.2/systemusers

リクエストBody
{
    "fullname": "TESTUSER1",
    "businessunitid@odata.bind": "/businessunits(********-****-****-****-************)",
    "internalemailaddress": "testuser1@example.onmicrosoft.com"
}

Response
{
    "error": {
        "code": "0x80040217",
        "message": "usersettings With Id = ********-****-****-****-************ Does Not Exist"
    }
}




POST https://***********.api.crm*.dynamics.com/api/data/v9.2/systemusers

リクエストBody
{
    "azureactivedirectoryobjectid": "c74a8***-****-****-****-*******abb78"
}

Response
{
    "error": {
        "code": "0x80040530",
        "message": "Unable to retrieve attribute=businessunitid for entityLogicalName=systemuser. Entity has Attribute Count=25. AttributeNames= preferredaddresscode, outgoingemaildeliverymethod, caltype, address1_addresstypecode, address1_shippingmethodcode, preferredphonecode, displayinserviceviews, incomingemaildeliverymethod, isdisabled, issyncwithdirectory, setupuser, accessmode, address2_addresstypecode, deletedstate, azurestate, defaultfilterspopulated, address2_shippingmethodcode, emailrouteraccessapproval, isintegrationuser, preferredemailcode, invitestatuscode, islicensed, systemuserid, isemailaddressapprovedbyo365admin, isactivedirectoryuser"
    }
}




POST https://***********.api.crm*.dynamics.com/api/data/v9.2/systemusers

リクエストBody
{
    "azureactivedirectoryobjectid": "c74a8***-****-****-****-*******abb78",
    "businessunitid@odata.bind": "/businessunits(********-****-****-****-************)"
}

Response
{
    "error": {
        "code": "0x80040200",
        "message": "Attribute 'internalemailaddress' cannot be NULL"
    }
}




POST https://***********.api.crm*.dynamics.com/api/data/v9.2/systemusers

リクエストBody
{
    "azureactivedirectoryobjectid": "c74a8***-****-****-****-*******abb78",
    "businessunitid@odata.bind": "/businessunits(********-****-****-****-************)",
    "internalemailaddress": "testuser1@example.onmicrosoft.com"
}

Response
{
    "error": {
        "code": "0x80040217",
        "message": "usersettings With Id = ********-****-****-****-************ Does Not Exist"
    }
}




POST https://***********.api.crm*.dynamics.com/api/data/v9.2/systemusers

リクエストBody
{
  "userid": "11111***-****-****-****-*******11111",
  "azureactivedirectoryobjectid": "c74a8***-****-****-****-*******abb78",
  "businessunitid@odata.bind": "/businessunits(********-****-****-****-************)",
  "internalemailaddress": "testuser1@example.onmicrosoft.com"
}

Response
{
    "error": {
        "code": "0x0",
        "message": "Error identified in Payload provided by the user for Entity :'systemusers', For more information on this error please follow this help link https://go.microsoft.com/fwlink/?linkid=2195293  ---->  InnerException : Microsoft.Crm.CrmException: Invalid property 'userid' was found in entity 'Microsoft.Dynamics.CRM.systemuser'. ---> Microsoft.OData.ODataException: Does not support untyped value in non-open type.\r\n   at System.Web.OData.Formatter.Deserialization.DeserializationHelpers.ApplyProperty(ODataProperty property, IEdmStructuredTypeReference resourceType, Object resource, ODataDeserializerProvider deserializerProvider, ODataDeserializerContext readContext)\r\n   at Microsoft.Crm.Extensibility.CrmODataEntityDeserializer.ApplyStructuralProperty(Object resource, ODataProperty structuralProperty, IEdmStructuredTypeReference structuredType, ODataDeserializerContext readContext)\r\n   --- End of inner exception stack trace ---\r\n   at Microsoft.Crm.Extensibility.CrmODataEntityDeserializer.ApplyStructuralProperty(Object resource, ODataProperty structuralProperty, IEdmStructuredTypeReference structuredType, ODataDeserializerContext readContext)\r\n   at System.Web.OData.Formatter.Deserialization.ODataResourceDeserializer.ApplyStructuralProperties(Object resource, ODataResourceWrapper resourceWrapper, IEdmStructuredTypeReference structuredType, ODataDeserializerContext readContext)\r\n   at Microsoft.Crm.Extensibility.CrmODataEntityDeserializer.ApplyStructuralProperties(Object resource, ODataResourceWrapper resourceWrapper, IEdmStructuredTypeReference structuredType, ODataDeserializerContext readContext)\r\n   at System.Web.OData.Formatter.Deserialization.ODataResourceDeserializer.ReadResource(ODataResourceWrapper resourceWrapper, IEdmStructuredTypeReference structuredType, ODataDeserializerContext readContext)\r\n   at System.Web.OData.Formatter.ODataMediaTypeFormatter.ReadFromStream(Type type, Stream readStream, HttpContent content, IFormatterLogger formatterLogger)."
    }
}




POST https://***********.api.crm*.dynamics.com/api/data/v9.2/systemusers

リクエストBody
{
  "applicationid": "22222***-****-****-****-*******22222",
  "azureactivedirectoryobjectid": "c74a8***-****-****-****-*******abb78",
  "businessunitid@odata.bind": "/businessunits(********-****-****-****-************)",
  "internalemailaddress": "testuser1@example.onmicrosoft.com"
}

Response
{
    "error": {
        "code": "0x8004f510",
        "message": "We didn’t find that application ID c74a8***-****-****-****-*******abb78 in your Azure Active Directory (Azure AD) with CorrelationID c86*****-****-****-****-*********52d. Make sure your application is registered in Azure AD."
    }
}




POST https://***********.api.crm*.dynamics.com/api/data/v9.2/systemusers

リクエストBody
{
  "applicationid": "<Azure Active Directory - アプリの登録で登録したアプリのアプリケーションID>",
  "azureactivedirectoryobjectid": "c74a8***-****-****-****-*******abb78",
  "businessunitid@odata.bind": "/businessunits(********-****-****-****-************)",
  "internalemailaddress": "testuser1@example.onmicrosoft.com"
}

エラーにならず、アプリケーションユーザーが登録されました。
が、削除すると、エラーになって、削除できなくなりました。真似して登録しないようにしてください。
消せない理由、消し方は、分かりませんでした。
削除すると、エラー


DELETE https://***********.api.crm*.dynamics.com/api/data/v9.2/systemusers(********-****-****-****-************)

Response
{
    "error": {
        "code": "0x80040203",
        "message": "MicrosoftGraphClient: Directory object Microsoft.Graph.ServicePrincipal with objectId ********-****-****-****-************ is NOT of User type."
    }
}




GET https://***********.api.crm*.dynamics.com/api/data/v9.2/SystemUser(azureactivedirectoryobjectid=c74a8***-****-****-****-*******abb78)

Response
{
    "error": {
        "code": "0x8006088a",
        "message": "Resource not found for the segment 'SystemUser'."
    }
}




GET https://***********.api.crm*.dynamics.com/api/data/v9.2/systemusers(azureactivedirectoryobjectid=デタラメのID)

Response
{
    "error": {
        "code": "0x80060891",
        "message": "A record with the specified key values does not exist in systemuser entity"
    }
}
loading...