PowerShell Crescendo

repository·master·Indexed 19 days ago

https://github.com/powershell/crescendo

A development accelerator for creating PowerShell cmdlets by wrapping existing command-line tools. It transforms text-based CLI tools into object-oriented cmdlets with support for privilege elevation, integrated help, and output transformation via JSON configuration files. The Microsoft.PowerShell.Crescendo module includes tools for defining, exporting, and importing configurations, as well as experimental help parsers to automate configuration generation by scanning native tool help text.

Tokens
18.2K
Snippets
58
Records
83
Agent score
64%

What's inside PowerShell Crescendo

  1. Overview of the Microsoft.PowerShell.Crescendo Module

    master

    Crescendo is a development accelerator designed to help you rapidly build PowerShell cmdlets that wrap existing command-line tools. It transforms text-based command-line tools into robust PowerShell cmdlets by providing:

    • Object Output: Converts command-line text output into structured objects suitable for the PowerShell pipeline.
    • Privilege Elevation: Handles elevation requirements for the underlying tools.
    • Integrated Help: Provides built-in help information for the wrapped commands.

    By using Crescendo, you can replace cumbersome CLI tools with standardized, easy-to-use cmdlets that are optimized for automation and easy to distribute within a team.

  2. Overview of PowerShell Crescendo

    master

    Crescendo is a development accelerator designed to help you rapidly build PowerShell cmdlets that wrap existing command-line tools.

    Instead of manually writing complex wrapper functions, Crescendo allows you to define cmdlets using simple key/value statements in JSON files. This process amplifies the original command-line tool by providing:

    • Object Output: Converts text-based command-line output into PowerShell objects for the pipeline.
    • Privilege Elevation: Supports elevation mechanisms across Windows, Linux, and macOS.
    • Integrated Help: Provides help information for the wrapped tool.
    • Deployment Ready: Generates a PowerShell script module that is ready to be shared with team members or used in automation.
  3. What is PowerShell Crescendo and how does it work?

    master

    Crescendo is a framework used to create PowerShell cmdlets that "amplify" existing command-line tools. Instead of returning plain text (the default behavior of native executables), Crescendo-based cmdlets return structured PowerShell objects, allowing them to participate fully in the PowerShell pipeline.

    To create an amplified cmdlet, you need two components:

    1. A JSON configuration file: This file describes the cmdlets you want to create, mapping PowerShell parameters to command-line arguments.
    2. Output handler functions: You must write these functions yourself to parse the raw text output from the command-line tool and convert it into PowerShell objects.

    The Crescendo module provides helper cmdlets to assist in generating these JSON configurations and building the final module.

  4. What is PowerShell Crescendo

    master

    PowerShell Crescendo is a module that allows you to create proxy functions for native (non-PowerShell) commands using JSON configuration files.

    By using Crescendo, you can make native executables behave like PowerShell cmdlets. This provides several key benefits:

    • Pipeline Integration: Native commands can participate in the PowerShell pipeline.
    • Parameter Handling: You can interact with native command parameters using standard PowerShell parameter behaviors (e.g., switches, positional parameters, and default values).
    • Output Transformation: You can use script blocks to convert raw text output from native commands into structured PowerShell objects.
  5. How the Crescendo Help Parser architecture works

    master

    The Crescendo help parser is an experimental tool designed to automate the creation of Crescendo configurations by scanning application help text. It follows a multi-stage pipeline:

    1. Scanning: The scanner identifies the executable and its help flag (e.g., --help or -?). It then executes the command to retrieve the help text.
    2. Parsing (Object Model): The parser uses regex patterns to identify command components (sub-commands, options, arguments, usage statements, etc.) and maps them to an intermediate, 'trimmed down' object model. This model acts as a staging area before full Crescendo configuration.
    3. Recursion: For tools with sub-commands (like docker), the parser is recursive. When a sub-command pattern is detected, the parser calls itself to scan the help for that specific sub-command.
    4. Packaging: A packager takes the parsed object model and converts it into a formal Crescendo configuration. It uses the GetCrescendoCommand method on command objects to map the intermediate model to the rich Crescendo model, then serializes the result to JSON.
  6. Transform argument values for native commands

    master

    If the input provided to a Crescendo cmdlet needs to be translated before being passed to the underlying native command, use the ArgumentTransform and ArgumentTransformType properties in the Parameter class.

    Supported ArgumentTransformType values:

    • Inline: ArgumentTransform must be a string containing a scriptblock. (Default)
    • Function: ArgumentTransform must be the name of a function loaded in the current session.
    • Script: ArgumentTransform must be the path to a script file.

    The transformation code receives the parameter's value and must return the transformed value.

    "Parameters": [
        {
            "Name": "mult2",
            "OriginalName": "--p3",
            "ParameterType": "int",
            "OriginalPosition": 2,
            "ArgumentTransform": "param([int]$v) $v * 2",
            "ArgumentTransformType": "Inline"
        }
    ]
  7. Create a proxy function using JSON configuration

    master

    To create a proxy function, you author a JSON configuration file that maps PowerShell verbs and nouns to a native executable. Crescendo uses this JSON to generate a function that handles parameter mapping and output conversion.

    An annotated schema is provided as part of the module to assist in the authoring process. You can define:

    • Verb and Noun: To determine the name of the resulting proxy function (e.g., Get-FileList).
    • OriginalName: The name of the native executable to call.
    • Parameters: A mapping of PowerShell parameters to native command flags/arguments.
    • OriginalCommandElements: Static arguments that should always be passed to the native command.
    • OutputHandlers: Script blocks used to transform the command's text output into PowerShell objects.
    {
        "$schema": "https://aka.ms/PowerShell/Crescendo/Schemas/2021-11",
        "Verb": "Get",
        "Noun":"FileList",
        "OriginalName": "/bin/ls",
        "Parameters": [
            {"Name": "Path","OriginalName": "", "OriginalPosition": 1, "Position": 0, "DefaultValue": "." },
            {"Name": "Detail","OriginalName": "-l","ParameterType": "switch"}
        ]
    }
  8. Transform arguments in Crescendo

    master

    When the input format of a PowerShell parameter differs from the format required by the underlying native command, you can use ArgumentTransform and ArgumentTransformType within the Parameter class of your Crescendo configuration.

    ArgumentTransform defines the logic used to translate the value, while ArgumentTransformType determines how that logic is interpreted.

    Supported ArgumentTransformType values:

    • Inline: The ArgumentTransform value is a string evaluated as a script block. This is the default type.
    • Function: The ArgumentTransform value is the name of a function loaded in the current session.
    • Script: The ArgumentTransform value is the name of a script file found on disk.
  9. Understand Crescendo terminology

    master

    When working with Crescendo, the following terms are used to distinguish between native tools and their PowerShell wrappers:

    • command-line tool: A native executable file installed on your system (e.g., ipconfig.exe).
    • command: The full string used to invoke the executable, including its specific parameters (e.g., ipconfig.exe /all).
    • amplified command: The PowerShell cmdlet you created using Crescendo that wraps the command (e.g., Get-IpConfig -All).
  10. Configure native command proxy functions via JSON

    master

    To create a proxy function, you define a JSON configuration file that maps PowerShell verbs and nouns to a native executable.

    Key Configuration Properties:

    • Verb and Noun: Define the name of the resulting PowerShell function (e.g., Get-FileList).
    • OriginalName: The path or name of the native executable to invoke.
    • OriginalCommandElements: An array of strings representing static arguments that should always be passed to the native command.
    • Parameters: An array defining how PowerShell parameters map to native arguments. Each parameter can include:
      • Name: The PowerShell parameter name.
      • OriginalName: The actual flag used by the native command (e.g., -l). If empty, the value is treated as a positional argument.
      • OriginalPosition: Determines the order of arguments when executed. Use this to handle native commands that require unnamed arguments at specific positions.
      • ParameterType: Specifies if the parameter is a switch.
      • DefaultValue: The value used if the parameter is not provided.
    • OutputHandlers: An array of objects used to transform the command's output. Each handler includes:
      • ParameterSetName: The name of the parameter set this handler applies to.
      • Handler: A PowerShell script block (as a string) that processes the output. Use $args[0] to access the raw output.
    {
        "$schema": "../src/Microsoft.PowerShell.Crescendo.Schema.json",
        "Verb": "Get",
        "Noun":"FileList",
        "OriginalName": "/bin/ls",
        "Parameters": [
            {
                "Name": "Path",
                "OriginalName": "",
                "OriginalPosition": 1,
                "Position": 0,
                "DefaultValue": "."
            },
            {
                "Name": "Detail",
                "OriginalName": "-l",
                "ParameterType": "switch"
            }
        ]
    }
  11. Handle native command error output (stderr)

    master

    Crescendo now captures stderr from native commands. You can inspect and manage these errors within your output handler using two internal functions:

    • Push-CrescendoNativeError: Automatically called by the output handler to add an error to the queue.
    • Pop-CrescendoNativeError: Used within an output handler to inspect and remove errors from the queue. This allows you to decide whether to handle the error or pass it through to the caller.

    To return errors to the user via an Inline handler, use Pop-CrescendoNativeError -EmitAsError in the END block of your handler script.

    "OutputHandlers": [
        {
            "ParameterSetName": "Default",
            "StreamOutput": true,
            "HandlerType": "Inline",
            "Handler": "PROCESS { $_ } END { Pop-CrescendoNativeError -EmitAsError }"
        }
    ]
  12. How Crescendo captures and manages native command errors

    master

    In Crescendo v1.1 and later, error output (stderr) from native commands can be captured and managed within your output handlers.

    Error Capture Behavior

    • Default Handler: If no handler is defined, Crescendo uses a default handler that respects -ErrorVariable and -ErrorAction and adds errors to the $Error collection.
    • ByPass Mode: If you set HandlerType to ByPass, Crescendo does not capture errors; all output is streamed directly to the user.
    • Error Duplication Prevention: To prevent duplicate error records, Crescendo sets $PSNativeCommandUseErrorActionPreference to $false for the generated cmdlets. This setting is scoped only to the generated module.

    Internal Error Management Functions

    Crescendo provides two internal functions to manage the error queue within your handlers:

    1. Push-CrescendoNativeError: Automatically called by the output handler to add errors to the queue. You do not call this directly.
    2. Pop-CrescendoNativeError: Used within your handler to retrieve and inspect errors from the queue so you can process, filter, or pass them to the caller.