Skip to content

Add Entra Connect directory sync step pack and provider#95

Merged
blindzero merged 11 commits intomainfrom
copilot/add-entra-connect-sync-step-pack
Jan 22, 2026
Merged

Add Entra Connect directory sync step pack and provider#95
blindzero merged 11 commits intomainfrom
copilot/add-entra-connect-sync-step-pack

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Jan 21, 2026

Summary

Implements first-party step pack and provider for triggering Entra ID Connect (ADSync) sync cycles on on-premises servers via remote execution.

Motivation

Enables workflows to trigger directory sync cycles between on-premises AD and Entra ID, with optional blocking until completion. Required for JML scenarios where cloud provisioning depends on identity synchronization completing before subsequent steps can execute.

Type of Change

  • New feature
  • Refactoring / internal improvement

Changes

New Step Pack: IdLE.Steps.DirectorySync.EntraConnect

  • Step Type: IdLE.Step.TriggerDirectorySync
  • Metadata centralized in IdLE.Steps.Common catalog: RequiredCapabilities: IdLE.DirectorySync.Trigger, IdLE.DirectorySync.Status
  • Inputs: AuthSessionName (required), PolicyType (Delta/Initial), Wait (bool), TimeoutSeconds, PollIntervalSeconds, AuthSessionOptions
  • Emits events: DirectorySyncTriggered, DirectorySyncWaiting, DirectorySyncPoll, DirectorySyncCompleted, DirectorySyncFailed
  • Depends on IdLE.Steps.Common via RequiredModules for shared helper functions

New Provider: IdLE.Provider.DirectorySync.EntraConnect

  • Contract: StartSyncCycle(PolicyType, AuthSession), GetSyncCycleState(AuthSession)
  • Expects AuthSession with InvokeCommand(CommandName, Parameters) method for remote execution
  • Executes Start-ADSyncSyncCycle and Get-ADSyncScheduler on target server
  • Validates privilege/elevation and returns actionable errors on access denied
  • Complete .OUTPUTS documentation in comment-based help

AuthSession Remote Execution Contract

# Host provides elevated remote session via AuthSessionBroker
$authSession = [pscustomobject]@{
    InvokeCommand = { 
        param([string]$CommandName, [hashtable]$Parameters)
        # Execute command in elevated context on Entra Connect server
    }
}

# Step acquires and passes to provider
$step = @{
    Type = 'IdLE.Step.TriggerDirectorySync'
    With = @{
        AuthSessionName      = 'EntraConnect'
        AuthSessionOptions   = @{ Role = 'EntraConnectAdmin' }
        PolicyType           = 'Delta'
        Wait                 = $true
        TimeoutSeconds       = 300
        PollIntervalSeconds  = 10
    }
}

Module Integration & Code Consolidation

  • Added to IdLE.psd1 NestedModules
  • DirectorySync step pack depends on Common via RequiredModules for shared functionality
  • Eliminated code duplication: removed 3 duplicate files (183 lines), consolidated in IdLE.Steps.Common
  • Step metadata centralized in IdLE.Steps.Common catalog (single source of truth)
  • Updated test helpers to import new modules for test discoverability
  • Updated Generate-IdleStepReference.ps1 default modules to include IdLE.Steps.DirectorySync.EntraConnect

Code Quality Improvements

  • Refactored Test-IdleProviderMethodParameter to use guard clauses, reducing nesting depth from 4-5 levels to 2 levels
  • Updated Invoke-IdleProviderMethod to use AllowEmptyCollection for proper empty array handling
  • Applied DRY principle: helper functions (Invoke-IdleProviderMethod, Test-IdleProviderMethodParameter) now shared from Common
  • Updated example workflow to use Kind = 'Group' entitlement (currently supported) instead of licenses

Testing

  • Unit tests (19 step tests)
  • Contract tests (15 provider tests)
  • Manual testing

Coverage

  • Input validation (required/optional parameters, type validation)
  • Trigger without wait (immediate return)
  • Trigger with wait (poll loop, completion, timeout scenarios)
  • Error handling (missing provider, missing methods, privilege errors)
  • Event emission (all event types)
  • AuthSession contract validation
  • Provider capability advertisement
  • Module dependency and helper function reuse

All 230 repository tests pass (including 34 new tests). PSScriptAnalyzer clean. CI docs-step-reference check passes.

How to test & review

  1. Review provider contract: New-IdleEntraConnectDirectorySyncProvider returns object with GetCapabilities(), StartSyncCycle(PolicyType, AuthSession), GetSyncCycleState(AuthSession) and includes .OUTPUTS documentation
  2. Review AuthSession contract validation: provider methods reject objects missing InvokeCommand method
  3. Review step metadata: DirectorySync step metadata now centralized in IdLE.Steps.Common\Get-IdleStepMetadataCatalog
  4. Review code consolidation: DirectorySync imports shared helpers from Common, eliminating duplication
  5. Review example: examples/workflows/joiner-with-entraid-sync.psd1 demonstrates workflow usage with Group entitlement
  6. Tests demonstrate mock remote execution handle and step/provider interaction patterns
  7. Verify Generate-IdleStepReference.ps1 includes new step module by default and produces no diff when run

Checklist

  • Code follows STYLEGUIDE.md
  • Tests added or updated
  • Documentation updated
  • No UI/auth logic added to IdLE.Core
  • No breaking changes without discussion

Related Issues

Implements remote directory sync triggering capability for Entra Connect environments.

Original prompt

This section details on the original issue you should resolve

<issue_title>provider: trigger and wait for Entra Connect sync cycles (remote)</issue_title>
<issue_description>## Goal

Provide a first-party step pack that can trigger an Entra ID Connect (ADSync) sync cycle on an on-premises server and optionally wait until the cycle is finished.

Constraints:

  • This cannot be triggered “from Entra in the cloud”; it must run against the on-premises Entra Connect server.
  • Start-ADSyncSyncCycle typically requires an elevated/admin execution context.
  • No interactive prompts (headless engine). Elevation and authentication are the host’s responsibility via AuthSessionBroker.

Scope

In scope

  • New step pack (separate module): IdLE.Steps.DirectorySync.EntraConnect
  • New provider implementation module: IdLE.Provider.DirectorySync.EntraConnect
  • Provider contract (lightweight PowerShell object contract)
  • Auth session contract for remote execution (Wrapper / Handle)
  • Tests (unit + provider contract tests) and docs/examples

Out of scope

  • Host-side implementation details for creating an elevated remote session (that belongs to the host).
  • Running real ADSync in CI.

Design

1) Step Type and module

  • Step.Type: IdLE.Step.TriggerDirectorySync
  • Step implementation function: Invoke-IdleStepTriggerDirectorySync
  • Module: src/IdLE.Steps.DirectorySync.EntraConnect/

2) Step metadata (RequiredCapabilities)

Because #89 removes workflow RequiresCapabilities, the step pack must provide metadata for this step:

  • RequiredCapabilities = @('IdLE.DirectorySync.Trigger', 'IdLE.DirectorySync.Status')

Rationale:

  • Keeping this static avoids conditional capability logic in the engine.
  • Even when With.Wait = $false, advertising IdLE.DirectorySync.Status is acceptable and keeps planning deterministic.

3) Step inputs (With.*)

With must be a hashtable and is validated by the step.

Required:

  • With.AuthSessionName (string)
    • Routing key for the AuthSessionBroker (recommended default in examples: EntraConnect).
  • With.PolicyType (string)
    • Allowed: Delta, Initial (case-insensitive).

Optional:

  • With.Provider (string) — provider alias in Context.Providers (default: DirectorySync).
  • With.Wait (bool) — default: $false.
  • With.TimeoutSeconds (int) — default: 600.
  • With.PollIntervalSeconds (int) — default: 10.
  • With.AuthSessionOptions (hashtable, data-only) — forwarded to broker (e.g., { Role = 'EntraConnectAdmin' }).

4) Provider contract

The step calls a provider instance via Context.Providers[<ProviderAlias>].

Provider must implement:

  • StartSyncCycle(PolicyType, AuthSession)

    • Triggers a sync cycle.
    • Returns an object with at least:
      • Started (bool)
      • Message (string, optional)
  • GetSyncCycleState(AuthSession)

    • Returns an object with at least:
      • InProgress (bool)
      • State (string; e.g., Idle, InProgress, Unknown)
      • Details (hashtable or null; optional)

Notes:

  • The contract is intentionally not tied to a specific cmdlet name (e.g. Get-ADSyncScheduler). The EntraConnect provider may use Get-ADSyncScheduler or another reliable signal; the contract only cares about InProgress.

5) AuthSession contract (Wrapper / Handle)

The host’s AuthSessionBroker must return an AuthSession whose payload is a remote execution handle for the Entra Connect server.

Minimum expected shape (trusted runtime object; not part of workflow data):

  • Method: InvokeCommand(CommandName, Parameters)

    • Executes a named command on the Entra Connect server in the required privileged context.
    • CommandName is a string.
    • Parameters is a hashtable (data-only).
  • Method: Dispose() (optional but recommended)

The provider uses only this handle (via AuthSession) and does not create its own sessions.

6) Elevation requirement (explicit)

If the remote execution context is not privileged enough to call Start-ADSyncSyncCycle, the provider must fail deterministically:

  • Throw an error that is actionable and clearly indicates:
    • missing privileges / elevation
    • that the host must provide an elevated session via AuthSessionBroker

No interactive escalation (no UAC prompts, no credential prompts).

7) Step behavior

  • Validate inputs early.
  • Acquire auth session via:
    • Context.AcquireAuthSession(With.AuthSessionName, With.AuthSessionOptions)
  • Call provider StartSyncCycle(With.PolicyType, AuthSession).
  • Emit events (see below).
  • If With.Wait is $true:
    • poll GetSyncCycleState(AuthSession) until InProgress = $false or timeout
    • on timeout: fail with a clear error (TimeoutSeconds, last known state)

8) Events

Use the standard event sink:

  • DirectorySyncTriggered (after trigger call returns)
  • DirectorySyncWaiting (first poll)
  • DirectorySyncPoll (optional, only if not too chatty; include attem...

✨ 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 5 commits January 21, 2026 20:45
Co-authored-by: blindzero <13959569+blindzero@users.noreply.github.com>
Co-authored-by: blindzero <13959569+blindzero@users.noreply.github.com>
Co-authored-by: blindzero <13959569+blindzero@users.noreply.github.com>
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 first-party step pack for Entra Connect sync cycles Add Entra Connect directory sync step pack and provider Jan 21, 2026
Copilot AI requested a review from blindzero January 21, 2026 20:56
Comment thread examples/workflows/joiner-with-entraid-sync.psd1 Outdated
…ce nesting in Test-IdleProviderMethodParameter

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

@copilot steps.md need to be updated, test is red

Copilot AI and others added 2 commits January 22, 2026 13:11
…ctorySync step pack

Co-authored-by: blindzero <13959569+blindzero@users.noreply.github.com>
…y removed

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

Copilot AI commented Jan 22, 2026

@copilot steps.md need to be updated, test is red

Fixed in commits 599e75d and 7877f1f. Updated Generate-IdleStepReference.ps1 default StepModules parameter to include the new IdLE.Steps.DirectorySync.EntraConnect module, and restored the TriggerDirectorySync documentation section. The CI docs-step-reference check now passes.

@blindzero blindzero marked this pull request as ready for review January 22, 2026 13:20
Copilot AI review requested due to automatic review settings January 22, 2026 13:20
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7877f1fee5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/IdLE.Steps.DirectorySync.EntraConnect/Public/Get-IdleStepMetadataCatalog.ps1 Outdated
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 adds first-party support for triggering Entra ID Connect (ADSync) directory sync cycles on on-premises servers via remote execution. The implementation consists of a new step pack (IdLE.Steps.DirectorySync.EntraConnect) that provides the step logic, and a new provider (IdLE.Provider.DirectorySync.EntraConnect) that executes ADSync commands remotely.

Changes:

  • New step type IdLE.Step.TriggerDirectorySync for triggering sync cycles with optional blocking until completion
  • New provider contract for remote directory sync operations with AuthSession-based execution
  • Integration of the step pack into IdLE meta-module with comprehensive test coverage (34 new tests passing)

Reviewed changes

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

Show a summary per file
File Description
src/IdLE.Steps.DirectorySync.EntraConnect/IdLE.Steps.DirectorySync.EntraConnect.psd1 Module manifest for the new step pack
src/IdLE.Steps.DirectorySync.EntraConnect/IdLE.Steps.DirectorySync.EntraConnect.psm1 Module loader for public and private functions
src/IdLE.Steps.DirectorySync.EntraConnect/Public/Invoke-IdleStepTriggerDirectorySync.ps1 Step implementation with input validation, provider interaction, and wait/poll logic
src/IdLE.Steps.DirectorySync.EntraConnect/Public/Get-IdleStepMetadataCatalog.ps1 Metadata catalog advertising required capabilities
src/IdLE.Steps.DirectorySync.EntraConnect/Private/Invoke-IdleProviderMethod.ps1 Helper for invoking provider methods with AuthSession support (duplicates Common)
src/IdLE.Steps.DirectorySync.EntraConnect/Private/Test-IdleProviderMethodParameter.ps1 Helper for parameter introspection (duplicates Common, uses guard clauses)
src/IdLE.Provider.DirectorySync.EntraConnect/IdLE.Provider.DirectorySync.EntraConnect.psd1 Provider module manifest
src/IdLE.Provider.DirectorySync.EntraConnect/IdLE.Provider.DirectorySync.EntraConnect.psm1 Provider module loader
src/IdLE.Provider.DirectorySync.EntraConnect/Public/New-IdleEntraConnectDirectorySyncProvider.ps1 Provider factory implementing StartSyncCycle and GetSyncCycleState methods
tests/Invoke-IdleStepTriggerDirectorySync.Tests.ps1 Comprehensive step tests covering validation, trigger, wait, and event emission
tests/Providers/EntraConnectDirectorySyncProvider.Tests.ps1 Provider contract tests validating methods and capability advertisement
src/IdLE/IdLE.psd1 Added step pack to NestedModules (provider module not added)
tests/_testHelpers.ps1 Import both new modules for test discoverability
tools/Generate-IdleStepReference.ps1 Added new step module to default scan list
examples/workflows/joiner-with-entraid-sync.psd1 Example workflow demonstrating sync triggering with wait
docs/reference/steps.md Generated documentation for TriggerDirectorySync step

Comment thread src/IdLE.Steps.DirectorySync.EntraConnect/Private/Invoke-IdleProviderMethod.ps1 Outdated
Comment thread src/IdLE/IdLE.psd1
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Comment thread src/IdLE.Steps.DirectorySync.EntraConnect/Private/Invoke-IdleProviderMethod.ps1 Outdated
Comment thread src/IdLE.Steps.DirectorySync.EntraConnect/Public/Get-IdleStepMetadataCatalog.ps1 Outdated
… in IdLE.Steps.Common

Co-authored-by: blindzero <13959569+blindzero@users.noreply.github.com>
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

Copilot reviewed 16 out of 16 changed files in this pull request and generated no new comments.

@blindzero blindzero merged commit d33714c into main Jan 22, 2026
11 checks passed
@blindzero blindzero deleted the copilot/add-entra-connect-sync-step-pack branch January 24, 2026 23:06
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.

provider: trigger and wait for Entra Connect sync cycles (remote)

3 participants