Skip to content

AD Provider: Derive SamAccountName and UPN from IdentityKey in CreateIdentity#173

Merged
blindzero merged 6 commits intomainfrom
copilot/derive-samaccountname-from-identitykey
Feb 10, 2026
Merged

AD Provider: Derive SamAccountName and UPN from IdentityKey in CreateIdentity#173
blindzero merged 6 commits intomainfrom
copilot/derive-samaccountname-from-identitykey

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Feb 9, 2026

Implementation Complete: AD Provider - Derive SamAccountName and optionally UPN from IdentityKey

Summary of Changes

This PR implements smart derivation behavior in the AD Provider's CreateIdentity operation to improve usability for AD joiner workflows while maintaining provider-agnostic step contracts.

Key Features Implemented

SamAccountName Derivation

  • Automatically derives SamAccountName from IdentityKey when IdentityKey is SamAccountName-like
  • Fails fast with clear error when IdentityKey is UPN or GUID without explicit SamAccountName
  • Never overrides explicitly provided SamAccountName

UserPrincipalName Auto-Set

  • Automatically sets UserPrincipalName from IdentityKey when IdentityKey is a UPN
  • Never overrides explicitly provided UserPrincipalName

CN/RDN Name Derivation

  • Uses priority order: Name > DisplayName > GivenName+Surname > IdentityKey
  • Ensures friendly display names by default without coupling to IdentityKey
  • Falls back gracefully to IdentityKey with verbose logging

Path Pass-Through

  • Continues to respect explicit Path attribute with no changes

No Hashtable Mutation

  • Clones input $Attributes hashtable to avoid mutating caller's data
  • All derivations performed on local copy ($effectiveAttributes)
  • Prevents plan mutation and cross-step leakage

Files Changed

  • src/IdLE.Provider.AD/Private/New-IdleADAdapter.ps1 (+70 lines)

    • Added IdentityKey classification logic
    • Implemented SamAccountName, UPN, and Name derivation
    • Added Write-Verbose logging for all derivations
    • Fixed hashtable mutation by cloning input Attributes
  • tests/Providers/ADIdentityProvider.Tests.ps1 (+240 lines)

    • Simplified fake adapter to avoid duplicating production logic
    • Updated tests to work with simplified fake adapter
    • All 61 AD provider tests passing
  • docs/reference/providers/provider-ad.md (+88 lines)

    • Added "CreateIdentity Derivation Behavior" section
    • Updated examples to show both scenarios
    • Documented all derivation rules and priority orders
    • Clarified DeleteIdentity requires -AllowDelete switch for initialization

Test Results

AD Provider Tests: 61/61 passing (0 failures)
Full Test Suite: 421/421 passing (0 failures)
Script Analyzer: 0 errors
Code Review: Addressed all review comments

Backward Compatibility

  • Low risk: Only fills missing/empty attributes; never overrides explicit values
  • Existing workflows: Continue to work unchanged if they already specify attributes
  • Breaking change: UPN IdentityKey without SamAccountName now fails fast (was undefined behavior)
  • No side effects: Input hashtables are no longer mutated

Example Usage

Before (required explicit SamAccountName):

With = @{
  IdentityKey = 'jdoe'
  Attributes  = @{
    SamAccountName = 'jdoe'  # Required duplication
    GivenName = 'John'
    Surname = 'Doe'
  }
}

After (SamAccountName derived automatically):

With = @{
  IdentityKey = 'jdoe'
  Attributes  = @{
    # SamAccountName automatically derived as 'jdoe'
    GivenName = 'John'
    Surname = 'Doe'
    # CN/RDN will be 'John Doe' from GivenName+Surname
  }
}

UPN scenario (explicit SamAccountName required):

With = @{
  IdentityKey = 'john.doe@contoso.com'
  Attributes  = @{
    SamAccountName = 'jdoe'  # Required for UPN IdentityKey
    # UserPrincipalName automatically set to 'john.doe@contoso.com'
    DisplayName = 'John Doe'
    # CN/RDN will be 'John Doe' from DisplayName
  }
}
Original prompt

This section details on the original issue you should resolve

<issue_title>AD Provider: Derive SamAccountName and optionally UPN from IdentityKey in CreateIdentity</issue_title>
<issue_description>## Problem Statement

When using the provider-agnostic step IdLE.Step.CreateIdentity together with IdLE.Provider.AD, authoring a first simple joiner workflow is unnecessarily error-prone:

  • New-ADUser requires -SamAccountName, but IdLE currently does not derive it from IdentityKey. Users must duplicate the same value in both With.IdentityKey and With.Attributes.SamAccountName.
  • If IdentityKey is provided as a UPN (user@domain) it is intuitive to treat this as the UPN, but IdLE currently does not auto-set Attributes.UserPrincipalName when missing.
  • The AD object CN/RDN name (New-ADUser -Name) should not be coupled to IdentityKey. Users want the directory object name to follow explicit values (e.g., DisplayName or GivenName Surname) without needing AD-specific steps.
  • Path must be reliably passed through to the AD RSAT cmdlets (New-ADUser -Path ...) to avoid default-container placement (and frequent “Access is denied” due to ACL differences).

Goal: Improve usability for AD joiner workflows while keeping IdLE.Step.CreateIdentity provider-agnostic (changes must be in the AD provider/adapter only).

Proposed Solution

Implement AD-specific convenience behavior in IdLE.Provider.AD (and/or its adapter) for CreateIdentity(IdentityKey, Attributes):

1) Derive SamAccountName from IdentityKey (conservative)

If Attributes.SamAccountName is missing/empty:

  • Classify IdentityKey using the same/consistent logic as AD identity resolution (GUID vs UPN vs SamAccountName-like).
  • If IdentityKey is SamAccountName-like:
    • Set Attributes.SamAccountName = IdentityKey.
  • If IdentityKey is a UPN (user@domain):
    • Fail fast (B1) with an actionable error explaining that SamAccountName is mandatory for New-ADUser and must be provided explicitly when IdentityKey is a UPN.

Never override explicitly provided Attributes.SamAccountName.

2) Auto-set UserPrincipalName when IdentityKey is a UPN

If IdentityKey is a UPN and Attributes.UserPrincipalName is missing/empty:

  • Set Attributes.UserPrincipalName = IdentityKey.

Never override explicitly provided Attributes.UserPrincipalName.

3) Derive the AD object CN/RDN -Name independently of IdentityKey

When calling New-ADUser -Name ..., determine the name with this priority order:

  1. Attributes.Name (explicit CN/RDN)
  2. Attributes.DisplayName
  3. If Attributes.GivenName and Attributes.Surname are present: "<GivenName> <Surname>"
  4. Fallback: IdentityKey (with a warning/debug event to highlight the fallback)

This ensures Name != IdentityKey by default in typical joiner workflows, while remaining deterministic.

4) Ensure Path is passed through to RSAT

Continue to accept Attributes.Path and ensure it is consistently passed through to New-ADUser -Path ... (no additional derivation required).

5) Logging / events

When any derivation occurs (SamAccountName, UserPrincipalName, CN/RDN Name):

  • Emit a structured provider/engine event (or debug log) indicating what was derived and why.
  • Avoid logging sensitive values (e.g., do not log full credentials; attribute values may be logged only if safe per existing logging rules).

Alternatives Considered

  • Document-only approach (require users to always specify SamAccountName and manage -Name themselves).

    • Rejected: leads to repetitive workflows and confusing first-time experience.
  • Make IdLE.Step.CreateIdentity AD-aware.

    • Rejected: step must remain provider-agnostic by design.
  • Automatically derive SamAccountName from UPN left-part (truncate/sanitize/collision handling).

    • Rejected for now: introduces org-specific policy decisions and risk of unexpected collisions. The chosen approach is B1 fail-fast for UPN identity keys.

Impact

  • Does this affect existing workflows?

    • Intended to be additive. If workflows already specify Attributes.SamAccountName, Attributes.UserPrincipalName, Attributes.Name, no behavior changes.
    • Workflows that omitted SamAccountName may start working automatically when IdentityKey is samAccountName-like.
  • Any backward compatibility concerns?

    • Low risk: only fill missing/empty attributes; never override explicit values.
    • IdentityKey as UPN and missing SamAccountName will now fail fast with a clearer, earlier error (explicitly guiding users to set SamAccountName).

Additional Context

Acceptance Criteria

  • SamAccountName derivation

    • If Attributes.SamAccountName is missing/empty and IdentityKey is samAccountName-like, SamAccountName is set to IdentityKey.
    • If IdentityKey is a UPN and SamAccountName is missing/empty, creation fails fast with a clear error.
  • *UPN convenience...


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Copilot AI and others added 2 commits February 9, 2026 22:21
Co-authored-by: blindzero <13959569+blindzero@users.noreply.github.com>
Co-authored-by: blindzero <13959569+blindzero@users.noreply.github.com>
Copilot AI changed the title [WIP] Add SamAccountName and UPN derivation from IdentityKey AD Provider: Derive SamAccountName and UPN from IdentityKey in CreateIdentity Feb 9, 2026
Copilot AI requested a review from blindzero February 9, 2026 22:27
Comment thread docs/reference/providers/provider-ad.md Outdated
Co-authored-by: blindzero <13959569+blindzero@users.noreply.github.com>
@blindzero blindzero marked this pull request as ready for review February 10, 2026 07:44
Copilot AI review requested due to automatic review settings February 10, 2026 07:44
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the Active Directory provider adapter to derive AD-specific required fields during CreateIdentity, reducing workflow boilerplate while keeping the IdLE.Step.CreateIdentity contract provider-agnostic.

Changes:

  • Added IdentityKey classification and derivation logic in the AD adapter to infer SamAccountName, optionally set UserPrincipalName, and derive CN/RDN -Name.
  • Expanded AD provider test suite with new scenarios for derivation behavior.
  • Updated AD provider reference documentation to describe the new derivation rules and examples.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.

File Description
src/IdLE.Provider.AD/Private/New-IdleADAdapter.ps1 Implements IdentityKey classification and derives SamAccountName/UserPrincipalName/CN Name before calling New-ADUser.
tests/Providers/ADIdentityProvider.Tests.ps1 Updates fake adapter signature/behavior and adds test cases for the new derivation rules.
docs/reference/providers/provider-ad.md Documents CreateIdentity derivation behavior and updates usage examples accordingly.

Comment thread src/IdLE.Provider.AD/Private/New-IdleADAdapter.ps1 Outdated
Comment thread tests/Providers/ADIdentityProvider.Tests.ps1 Outdated
Comment thread tests/Providers/ADIdentityProvider.Tests.ps1 Outdated
Comment thread src/IdLE.Provider.AD/Private/New-IdleADAdapter.ps1
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@blindzero
Copy link
Copy Markdown
Owner

@copilot apply changes based on the comments in this thread

- Clone $Attributes hashtable to avoid mutating caller's data
- Use $effectiveAttributes for all derivation and parameter building
- Simplify fake adapter to avoid duplicating production logic
- Update tests to work with simplified fake adapter
- All 421 tests passing

Co-authored-by: blindzero <13959569+blindzero@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Feb 10, 2026

@copilot apply changes based on the comments in this thread

All review comments addressed:

  • Fixed hashtable mutation by cloning input Attributes
  • Simplified fake adapter to avoid logic duplication
  • All 421 tests passing

Changes in commit 87459a6

@blindzero blindzero merged commit d5f99f8 into main Feb 10, 2026
8 checks passed
@blindzero blindzero deleted the copilot/derive-samaccountname-from-identitykey branch February 15, 2026 19:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

AD Provider: Derive SamAccountName and optionally UPN from IdentityKey in CreateIdentity

3 participants