Share via

API-driven provisioning to on-premises AD: repeated accountDisabled update on identical payload, and direct accountDisabled mapping does not trigger disable

DanyilVolovyk 0 Reputation points
2026-03-19T09:17:58.5166667+00:00

We are testing Microsoft Entra API-driven provisioning to on-premises Active Directory and are trying to understand whether this behavior is expected or if we are using the status mapping incorrectly.

Scenario

We are provisioning users from a custom API into on-premises Active Directory by using API-driven provisioning. We tested two different mappings for the AD target attribute accountDisabled.

Test 1: Expression mapping

We configured: accountDisabled = Not([active])

Mapping settings:

  • Mapping type: Expression
  • Target attribute: accountDisabled
  • Apply this mapping: Always

We then sent a payload where the user should be disabled:

  [
    {
      "schemas": [
        "urn:ietf:params:scim:schemas:core:2.0:User",
        "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User",
        "urn:ietf:params:scim:schemas:extension:custom:2.0:User"
      ],
      "id": "10001234",
      "userName": "test.user",
      "externalId": "10001234",
      "accountDisabled": true,
      "active": false,
      "name": {
        "givenName": "Test",
        "familyName": "User"
      },
      "displayName": "Test User",
      "emails": [
        {
          "value": "test.user@example.com",
          "type": "work",
          "primary": true
        }
      ],
      "phoneNumbers": [
        {
          "value": "+4000000000",
          "type": "mobile"
        }
      ],
      "addresses": [
        {
          "streetAddress": "",
          "locality": "TestCity",
          "region": "",
          "postalCode": "",
          "country": "",
          "type": "work"
        }
      ],
      "title": "Engineer",
      "department": "IT",
      "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User": {
        "employeeNumber": "10001234",
        "department": "IT",
        "manager": {
          "value": "20005678",
          "displayName": "Manager User"
        },
        "division": "Example Company"
      },
      "urn:ietf:params:scim:schemas:extension:custom:2.0:User": {
        "employmentStatus": "M",
        "mobile": "+4000000000",
        "orgChartName": "Example Company;IT",
        "positionStartDate": "2021-03-01T00:00:00",
        "employmentsEndDate": null,
        "employmentsStartDate": "2021-03-01T00:00:00",
        "managerEmail": "manager.user@example.com",
        "startDateStatus": null
      }
    }
  ]

We verified in our application logs that the outbound request sent to Microsoft Graph contains:

  • active: false
  • accountDisabled: true

Result of Test 1

First request:

  • provisioning runs an Update
  • the AD user is disabled correctly
  • Modified Properties shows accountDisabled = True

Second request, later, with the exact same payload:

  • provisioning runs another Update
  • Modified Properties again shows accountDisabled = True

Expected result on the second identical payload:

  • no modified properties
  • skipped / RedundantExport

Test 2: Direct mapping

We also tested direct mapping:

  • Mapping type: Direct
  • Source attribute: accountDisabled
  • Target attribute: accountDisabled
  • Apply this mapping: Always

In that case, when we sent a payload with:

  • accountDisabled: true
  • active: false

the disable did not trigger as expected. Provisioning did not perform the AD disable in the same way as with Not([active]).

Questions

  1. For API-driven provisioning to on-premises AD, is Not([active]) -> accountDisabled the correct supported mapping?
  2. Is it expected that a second identical payload still triggers another Update for accountDisabled even when the AD account is already disabled?
  3. Is direct mapping accountDisabled -> accountDisabled supported for this scenario, or is active the only reliable source attribute for account state?
  4. Is there any known issue or limitation where Entra provisioning cannot compare the target AD disabled state correctly for accountDisabled?
  5. Is there any recommended configuration that makes the second identical payload result in RedundantExport instead of another update?

Documentation we reviewed

We reviewed these Microsoft references while testing:

  • API-driven provisioning FAQ
  • bulkUpload examples that use active: false
  • attribute mapping / expression documentation
  • examples where Active is shown as the source for AD accountDisabled

Because of that, we want to confirm the correct supported pattern for on-premises AD account disablement.

Microsoft Security | Microsoft Graph
0 comments No comments

4 answers

Sort by: Most helpful
  1. David Broggy 6,796 Reputation points MVP
    2026-04-07T19:09:12.85+00:00

    Hi @Danyil Volovyk Question 1:
    Yes — Not([active]) -> accountDisabled is the correct and recommended mapping.
    In SCIM, active=true means the account is enabled. In Active Directory, accountDisabled=true means the account is disabled. The negation is required to align them. This is the standard pattern documented for Entra inbound provisioning to on-premises AD.
    Question 2: This is a known behavior limitation in API-driven inbound provisioning. The provisioning service derives accountDisabled from the AD userAccountControl bitmask attribute. The pre-write comparison for this derived boolean is not always reliable — the service may not correctly detect that the current AD state already matches the desired state, resulting in a repeated Update export rather than RedundantExport.
    This is not expected behavior in an ideal sense, but it is a known limitation of how userAccountControl-derived attributes are handled.

    Question 3:
    Direct accountDisabled -> accountDisabled mapping is not reliable for this scenario. The SCIM active attribute is the canonical source for account lifecycle state in Entra provisioning. If your source system sends account state as something other than active, the recommended approach is either:

    1. Map your source attribute to active in your API payload, or
    2. Use an expression such as IIF([yourSourceAttr] = "disabled", False, True) mapped to active, then let Not([active]) -> accountDisabled handle the AD write. Direct accountDisabled -> accountDisabled bypasses the userAccountControl handling logic in the provisioning agent and may not consistently apply or compare correctly.
      Question 4:
      Yes, there is a known limitation here. Because accountDisabled in AD is a derived value from userAccountControl (bit 2), the provisioning agent's change-detection logic for this attribute is less reliable than for standard string or integer attributes.
      Microsoft has documented that userAccountControl-derived attributes can cause repeated exports even when the target state has not changed. This is most commonly observed in API-driven inbound provisioning scenarios.

    Question 5: There is no current configuration option that guarantees RedundantExport for accountDisabled on repeated identical payloads in API-driven provisioning. Recommendations:

    1. Ensure you are on the latest provisioning agent version — comparison logic improvements have been shipped in agent updates.
    2. Verify your active attribute is correctly set in the payload so the engine works from a clean boolean rather than a derived value.
    3. If this is causing operational issues such as audit noise or downstream triggers, open a Microsoft support case with your provisioning job ID and a sample request. I hope that helps.
    0 comments No comments

  2. Deleted

    This answer has been deleted due to a violation of our Code of Conduct. The answer was manually reported or identified through automated detection before action was taken. Please refer to our Code of Conduct for more information.


    Comments have been turned off. Learn more

  3. Deleted

    This answer has been deleted due to a violation of our Code of Conduct. The answer was manually reported or identified through automated detection before action was taken. Please refer to our Code of Conduct for more information.


    Comments have been turned off. Learn more

  4. Deleted

    This answer has been deleted due to a violation of our Code of Conduct. The answer was manually reported or identified through automated detection before action was taken. Please refer to our Code of Conduct for more information.


    Comments have been turned off. Learn more

Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.