Skip to content

IdLE.Provider.AD fails at runtime because Protect-LdapFilterValue is not in scope for adapter ScriptMethods #157

@blindzero

Description

@blindzero

Description

The Active Directory identity provider fails at runtime when resolving an identity by sAMAccountName. The error indicates that the helper function Protect-LdapFilterValue is not recognized, causing identity resolution to fail and consequently breaking steps like IdLE.Step.DisableIdentity.

This is a regression/defect in the AD adapter implementation: Protect-LdapFilterValue is defined as a nested function within New-IdleADAdapter, but it is referenced from ScriptMethod members (e.g., GetUserBySam). When these ScriptMethods are invoked later, the nested function is out of scope, so PowerShell cannot resolve it.

Impact: AD-based workflows (e.g., Leaver DisableIdentity) cannot execute reliably.

Steps to Reproduce

  1. Install/import IdLE modules including the AD provider.
  2. Configure an AD identity provider and run a workflow containing IdLE.Step.DisableIdentity with an IdentityKey that resolves via sAMAccountName (e.g., foo.bar).
  3. Build and invoke the plan.

Example minimal workflow step:

@{
  Name           = 'Leave Account Test'
  LifecycleEvent = 'Leaver'
  Steps          = @(
    @{
      Name = 'Disable AD account'
      Type = 'IdLE.Step.DisableIdentity'
      With = @{
        AuthSessionName = 'AD'
        IdentityKey     = 'foo.bar'
      }
    }
  )
}

Example plan creation (provider setup omitted here, see Additional Context):

$leaverReq  = New-IdleLifecycleRequest -LifecycleEvent 'Leaver'
$leaverPlan = New-IdlePlan -WorkflowPath .\leaver.psd1 -Request $leaverReq -Providers $providers
Invoke-IdlePlan -Plan $leaverPlan

Expected Behavior

  • IdLE.Step.DisableIdentity resolves the identity using the AD provider and disables the AD account.
  • No missing-command errors occur.
  • LDAP filter values are properly escaped prior to querying AD.

Actual Behavior

The step fails with an exception chain that ends in:

The term 'Protect-LdapFilterValue' is not recognized as a name of a cmdlet, function, script file, or executable program.

Example error (truncated):

Exception calling "DisableIdentity" ... 
Exception calling "ResolveIdentity" ...
Exception calling "GetUserBySam" ...
The term 'Protect-LdapFilterValue' is not recognized ...

Environment

  • PowerShell version: (fill in)
  • OS: (fill in)
  • IdLE version / commit: (fill in; e.g., 0.9.2)
  • Execution context (CLI / Service / CI): (fill in)
  • Provider: IdLE.Provider.AD

Root Cause Analysis (Proposed)

  • Protect-LdapFilterValue is implemented as a nested function inside New-IdleADAdapter.ps1.
  • AD adapter operations are exposed as ScriptMethods (e.g., GetUserBySam) on an object created by New-IdleADAdapter.
  • When a ScriptMethod runs, it does not retain the lexical scope of New-IdleADAdapter, therefore the nested function is not visible.
  • Result: calling Protect-LdapFilterValue inside the ScriptMethod throws a command not recognized error.

Proposed Fix

Make the LDAP escaping helper available in the execution scope of the adapter ScriptMethods in a testable, non-global way.

Preferred approach (Option A):

  1. Add a ScriptMethod on the adapter object, e.g. ProtectLdapFilterValue, implemented directly on the adapter.
  2. Update all adapter ScriptMethods that need escaping (e.g., GetUserBySam, GetUserByUpn, any search methods) to call:
    • $this.ProtectLdapFilterValue($value)
  3. Remove the nested function version to avoid future scope confusion.

Alternative approach (Option B):

  • Move Protect-LdapFilterValue to a private module function file (e.g., Private/Protect-LdapFilterValue.ps1) within the AD provider module and ensure it is dot-sourced/exported appropriately for internal use (no global pollution), then reference it from ScriptMethods.

Acceptance Criteria

  • Running a workflow with IdLE.Step.DisableIdentity against AD no longer fails with missing Protect-LdapFilterValue.
  • AD identity resolution by sAMAccountName works end-to-end.
  • LDAP filter escaping is still applied and covered by tests.
  • No new global functions are introduced (no Global scope pollution).
  • Docs/examples that demonstrate AD workflows still work without additional steps.

Test Plan

Unit Tests (Pester)

  • Add/extend unit tests for the AD adapter to validate that calling GetUserBySam does not throw due to missing helper function.
  • Add tests for ProtectLdapFilterValue behavior (escape sequences for \, *, (, ), null byte).
  • Add a unit/integration-style test using the mock provider (or a minimal adapter stub) to confirm ResolveIdentity can call GetUserBySam successfully.

Regression Coverage

  • A test that simulates a full DisableIdentity step invocation path (using mocks) and asserts the call chain does not throw missing-command exceptions.

Documentation Updates

  • Ensure provider implementation details remain internal; user docs should not require workarounds.
  • If there is a troubleshooting section for providers, add an entry that this bug is fixed in version X (once released).

Example Updates

  • Verify existing AD examples and quickstart snippets that use DisableIdentity still run.
  • Add a minimal Leaver example (if not present) that demonstrates DisableIdentity with AD provider configuration.

Additional Context

User report (failure object):

@{Name=Disable AD account; Type=IdLE.Step.DisableIdentity; Status=Failed; Error=... Protect-LdapFilterValue is not recognized ...}

Notes:

  • The failure is triggered during identity resolution (ResolveIdentity) inside the AD provider.
  • This blocks basic Joiner/Mover/Leaver scenarios using AD.

Metadata

Metadata

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions