en-US/about_Import_Completers.help.txt

TOPIC
    about_Import_Completers
 
SYNOPSIS
    Explains how to import standalone completer scripts into this module.
 
LONG DESCRIPTION
 
    CompleterActions can import an existing standalone completer script without
    registering it immediately in the live session. `Import-CompleterScript`
    parses the script, validates that it uses a supported shape, executes it in
    a temporary capture module, and emits one or more
    `CompleterActions.ImportedCompleterRegistration` objects.
 
    Those output objects are designed to pipe directly into
    `Register-CompleterRegistration -InputObject`. This lets you move an
    existing script into the module's managed workflow while keeping the live
    runtime unchanged until you explicitly register the imported definitions.
 
    The import path is intentionally strict. The cmdlet only accepts
    self-contained completer scripts that it can analyze and replay safely.
    Unsupported top-level behavior is rejected before the imported completer can
    affect the session.
 
WHEN TO USE IMPORT-COMPLETERSCRIPT
 
    Use `Import-CompleterScript` when you already have a `.ps1` file that calls
    `Register-ArgumentCompleter` and you want to:
 
    - inspect what the script would register before changing the session
    - convert old standalone completer scripts into managed registrations
    - preserve helper functions and script-scope state used by the completer
    - register the imported definitions later with
      `Register-CompleterRegistration`
 
    Do not use `Import-CompleterScript` if you only need to create a new
    completer from a script block you already have in memory. In that case, call
    `Register-CompleterRegistration` directly.
 
HOW IMPORT-COMPLETERSCRIPT WORKS
 
    `Import-CompleterScript` performs four steps for each input file:
 
    1. Resolve the input path to a single `.ps1` file.
    2. Parse the file and validate that the script uses a supported
       `Register-ArgumentCompleter` shape.
    3. Execute the script inside a temporary module that shadows
       `Register-ArgumentCompleter`, so the script can declare its completers
       without modifying the live runtime tables.
    4. Emit normalized import objects for each resolved target.
 
    A single `Register-ArgumentCompleter` call can produce more than one output
    object. For example, a script that registers one native completer for both
    `tool` and `tool.exe` produces two imported registrations, one per command
    target.
 
PARAMETERS
 
    `Import-CompleterScript` has two path parameters:
 
    - `-Path`
      Accepts one or more paths. Wildcards are resolved. This parameter accepts
      pipeline input and property-name binding from `FullName`.
 
    - `-LiteralPath`
      Accepts one or more literal file paths. Wildcards are not expanded. This
      parameter accepts property-name binding from `PSPath`.
 
    Both parameters require `.ps1` files. Directories and non-`.ps1` files are
    rejected.
 
OUTPUT OBJECTS
 
    Each imported object is a
    `CompleterActions.ImportedCompleterRegistration` record with properties that
    are ready for `Register-CompleterRegistration -InputObject`.
 
    The most useful properties are:
 
    - `Key` and `RegistrationKey`
      The module's normalized key for the target.
 
    - `RuntimeKey`
      The target key as PowerShell runtime registration logic expects it.
 
    - `CommandName`
      The command or native executable name.
 
    - `ParameterName`
      The parameter name for parameter completers. Native completers leave this
      empty.
 
    - `Native` and `IsNative`
      Indicate whether the target is a native completer.
 
    - `CompleterType`
      Either `Parameter` or `Native`.
 
    - `Path` and `SourcePath`
      The source file that produced the imported registration.
 
    - `ScriptBlock`
      The imported script block. It preserves the temporary module context that
      contains helper functions and script-scope state from the source script.
 
    - `ScriptText`
      The script block text, which is useful for inspection and debugging.
 
BASIC WORKFLOW
 
    The normal workflow is:
 
    1. Import the module.
    2. Import one or more completer scripts.
    3. Inspect the emitted objects if needed.
    4. Pipe them into `Register-CompleterRegistration`.
    5. Verify the registration with `Get-CompleterRegistration`.
 
EXAMPLE 1
 
    Import a single parameter completer script and register it:
 
        Import-CompleterScript -Path .\MyTool.Completer.ps1 |
            Register-CompleterRegistration -PassThru
 
    `-PassThru` returns the managed registration records so you can inspect the
    final registrations that were created.
 
EXAMPLE 2
 
    Inspect imported definitions before registering them:
 
        $imported = Import-CompleterScript -Path .\MyTool.Completer.ps1
 
        $imported | Format-List CommandName, ParameterName, CompleterType, Path
        $imported.ScriptText
 
    This is useful when you want to verify the discovered targets and the
    imported script text before you mutate the runtime.
 
EXAMPLE 3
 
    Import multiple script files by wildcard:
 
        Import-CompleterScript -Path .\Completers\*.ps1 |
            Register-CompleterRegistration
 
    `-Path` resolves wildcards first, then imports each matching `.ps1` file.
 
EXAMPLE 4
 
    Import files from `Get-ChildItem` pipeline output:
 
        Get-ChildItem -Path .\Completers -Filter *.ps1 -File |
            Import-CompleterScript |
            Register-CompleterRegistration
 
    `Import-CompleterScript` accepts property-name binding from `FullName`, so
    `FileInfo` objects from `Get-ChildItem` work directly.
 
EXAMPLE 5
 
    Use `-LiteralPath` when the file name contains wildcard characters:
 
        Import-CompleterScript -LiteralPath '.\Completers\[demo].ps1'
 
    `-LiteralPath` treats the path exactly as written and does not expand `[]`,
    `*`, or `?`.
 
SUPPORTED SCRIPT SHAPE
 
    To remain import-compatible, a standalone completer script should follow
    these rules:
 
    - Keep the script self-contained. Do not dot-source other scripts.
    - Keep script-scope statements limited to:
      - `Set-StrictMode`
      - function definitions
      - importer-safe `if` statements
      - script-scope `Register-ArgumentCompleter` calls
    - Call the built-in `Register-ArgumentCompleter` command directly.
      Do not wrap it in a custom function.
    - Use only these registration parameters:
      - `-CommandName`
      - `-ParameterName`
      - bare `-Native`
      - `-ScriptBlock`
    - Use explicit parameter names only. Positional arguments and splatting are
      not supported.
    - Keep target metadata literal:
      - `-CommandName` may be a literal string, a literal string array, or a
        literal `@('tool', 'tool.exe')` expression
      - `-ParameterName` may be a literal string, a literal string array, or a
        literal array expression
    - Keep `-ScriptBlock` literal.
    - Keep registration calls at script scope, not inside nested functions or
      nested script blocks.
    - Move cache initialization, alias bootstrap, tool discovery, generated
      completion loading, and other setup into helper functions that run lazily
      from inside the registered script block.
 
PARAMETER COMPLETER EXAMPLE
 
    This is a supported parameter completer shape:
 
        Register-ArgumentCompleter `
            -CommandName 'Invoke-DemoTool' `
            -ParameterName 'Name' `
            -ScriptBlock {
                param(
                    $commandName,
                    $parameterName,
                    $wordToComplete,
                    $commandAst,
                    $fakeBoundParameters
                )
 
                $null = $commandName, $parameterName, $commandAst,
                    $fakeBoundParameters
 
                'alpha', 'beta' |
                    Where-Object { $_ -like "$wordToComplete*" } |
                    ForEach-Object {
                        [System.Management.Automation.CompletionResult]::new(
                            $_,
                            $_,
                            'ParameterValue',
                            $_
                        )
                    }
            }
 
NATIVE COMPLETER EXAMPLE
 
    This is a supported native completer shape with helper functions and
    script-scope state:
 
        Set-StrictMode -Version 2.0
 
        if (-not (Get-Variable -Name DemoState -Scope Script -ErrorAction
            SilentlyContinue))
        {
            $script:DemoState = @{
                Values = @('alpha', 'beta')
            }
        }
 
        function Complete-DemoTool
        {
            param(
                [string] $WordToComplete
            )
 
            foreach ($value in $script:DemoState.Values)
            {
                if ($value -like "$WordToComplete*")
                {
                    [System.Management.Automation.CompletionResult]::new(
                        $value,
                        $value,
                        'ParameterValue',
                        $value
                    )
                }
            }
        }
 
        Register-ArgumentCompleter `
            -Native `
            -CommandName @('demo', 'demo.exe') `
            -ScriptBlock {
                param($wordToComplete, $commandAst, $cursorPosition)
 
                $null = $commandAst, $cursorPosition
 
                Complete-DemoTool -WordToComplete $wordToComplete
            }
 
    The helper function and `$script:DemoState` remain available because the
    imported script block keeps the temporary module context created during
    import.
 
COMMON FAILURES
 
    Import fails when the script uses patterns that the module cannot analyze or
    replay safely. Common examples include:
 
    - top-level commands such as `Get-Date`
    - top-level assignments or loops
    - `try`/`catch` blocks at script scope
    - dot-sourcing another script
    - `#requires -Modules`, `#requires -Assembly`, `using module`, or
      `using assembly`
    - a variable instead of a literal `-ScriptBlock`
    - dynamic expressions for `-CommandName` or `-ParameterName`
    - positional `Register-ArgumentCompleter` arguments
    - argument splatting
    - registering from inside a nested function or nested script block
 
    When import fails, fix the source script so that registration metadata stays
    literal and any expensive or dynamic behavior runs lazily inside helper
    functions that are called from the completion script block.
 
VERIFYING THE RESULT
 
    After registration, verify the result with the module's discovery command:
 
        Get-CompleterRegistration -CommandName 'Invoke-DemoTool' `
            -ParameterName 'Name'
 
    You can also validate real completion behavior with `TabExpansion2`:
 
        $inputScript = 'Invoke-DemoTool -Name a'
        $completion = TabExpansion2 `
            -InputScript $inputScript `
            -CursorColumn $inputScript.Length
 
        $completion.CompletionMatches
 
    For completer work, verifying the registered runtime behavior is more useful
    than only invoking the imported script block in isolation.
 
SEE ALSO
 
    Get-Help Import-CompleterScript -Full
    Get-Help Register-CompleterRegistration -Full
    Get-Help Get-CompleterRegistration -Full
    Register-ArgumentCompleter