-
Notifications
You must be signed in to change notification settings - Fork 0
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-ADSyncSyncCycletypically 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, advertisingIdLE.DirectorySync.Statusis 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).
- Routing key for the AuthSessionBroker (recommended default in examples:
With.PolicyType(string)- Allowed:
Delta,Initial(case-insensitive).
- Allowed:
Optional:
With.Provider(string) — provider alias inContext.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)
- Returns an object with at least:
Notes:
- The contract is intentionally not tied to a specific cmdlet name (e.g.
Get-ADSyncScheduler). The EntraConnect provider may useGet-ADSyncScheduleror another reliable signal; the contract only cares aboutInProgress.
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.
CommandNameis a string.Parametersis 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.Waitis$true:- poll
GetSyncCycleState(AuthSession)untilInProgress = $falseor timeout - on timeout: fail with a clear error (
TimeoutSeconds, last known state)
- poll
8) Events
Use the standard event sink:
DirectorySyncTriggered(after trigger call returns)DirectorySyncWaiting(first poll)DirectorySyncPoll(optional, only if not too chatty; include attempt + state)DirectorySyncCompleted(when finished)DirectorySyncFailed(on any failure)
Event Data must be data-only and must not include secrets.
Implementation tasks
Step pack: IdLE.Steps.DirectorySync.EntraConnect
- Add module manifest + module loader pattern consistent with existing step packs.
- Add
Invoke-IdleStepTriggerDirectorySync. - Add a small private helper (similar to
Invoke-IdleProviderMethod) or reuse a shared helper if already available to the new module. - Provide step metadata via
Get-IdleStepMetadataCatalog(per Step types should declare their own required capabilities (metadata-driven validation) #89 design).
Provider: IdLE.Provider.DirectorySync.EntraConnect
-
Implement
GetCapabilities()returning:IdLE.DirectorySync.TriggerIdLE.DirectorySync.Status
-
Implement provider methods using the AuthSession remote execution handle:
- Ensure the ADSync module is available in the remote context (import as needed inside the remote invocation).
- Trigger:
Start-ADSyncSyncCycle -PolicyType <Delta|Initial> - Status: determine
InProgressvia a reliable signal (implementation detail).
Tests
-
Unit tests for the step:
- validates required keys
- triggers without wait
- triggers and waits (poll loop) until complete
- timeout path
- provider missing method surfaces actionable error
-
Provider contract tests:
GetCapabilities()returns the required capability idsStartSyncCycleandGetSyncCycleStateacceptAuthSessionparameter and behave with a mocked remote handle
No live ADSync / no real remoting in default CI.
Docs / examples
-
Add a minimal example workflow step using
IdLE.Step.TriggerDirectorySync. -
Example should demonstrate:
AuthSessionName = 'EntraConnect'AuthSessionOptions = @{ Role = 'EntraConnectAdmin' }(if needed)PolicyType = 'Delta'Wait = $true(optional)
-
Update relevant docs pages if provider/step contracts are introduced or changed.
-
Regenerate step reference if new step is added.
Acceptance criteria
- New step pack exists and is loadable via the IdLE meta module.
- Step triggers a sync cycle via provider and returns
IdLE.StepResultwith deterministic status. - Optional wait works via polling, with configurable timeout and poll interval.
- Step does not perform authentication; it uses AuthSessionBroker via
Context.AcquireAuthSession. - Provider only uses the provided AuthSession remote handle; no self-auth.
- Missing privilege/elevation produces a clear, actionable error.
- Pester and PSScriptAnalyzer are green.
- Examples and docs updated; generated references regenerated where required.
Definition of Done
- Pester green (
./tools/Invoke-IdlePesterTests.ps1) - PSScriptAnalyzer green (
./tools/Invoke-IdleScriptAnalyzer.ps1) - Docs/examples updated as part of the same PR
- Generated references regenerated if impacted (
./tools/Generate-IdleStepReference.ps1)
Dependencies / References
- Must be implemented after Step types should declare their own required capabilities (metadata-driven validation) #89 (Step-owned RequiredCapabilities) so workflows and tests do not need
RequiresCapabilitieskeys. - Must align with AuthSessionBroker guidance from architecture: provider authentication & session broker #77/refactor Provider.AD: Route authentication via AuthSessionBroker #91: authentication/session acquisition is host-owned; steps/providers consume sessions via
Context.AcquireAuthSession(Name, Options).