Service | Microsoft Docs article | Related commit history on GitHub | Change details |
---|---|---|---|
dev-cross-plat | Create Cmdline Predictor | https://github.com/MicrosoftDocs/PowerShell-Docs/commits/staging/reference/docs-conceptual/dev-cross-plat/create-cmdline-predictor.md | +--- +description: This article describes how to create a command-line predictor to help with command completion in PowerShell. Last updated : 03/28/2022+ Title: How to create a command-line predictor +--- +# How to create a command-line predictor ++PSReadLine 2.1.0 introduced the concept of a smart command-line predictor by implementing the +Predictive IntelliSense feature. PSReadLine 2.2.2 expanded on that feature by adding a plugin model +that allows you create your own command-line predictors. ++Predictive IntelliSense enhances tab completion by providing suggestions, on the command line, as +you type. The prediction suggestion appears as colored text following your cursor. This enables you +to discover, edit, and execute full commands based on matching predictions from your command +history or additional domain-specific plugins. ++## System requirements ++To create and use a plugin predictor, you must be using the following versions of software: ++- PowerShell 7.2 (or higher) - provides the APIs necessary for creating a command predictor +- PSReadLine 2.2.2 (or higher) - allows you to configure PSReadLine to use the plugin ++## Overview of a predictor ++A predictor is a PowerShell binary module. The module must implement the +`System.Management.Automation.Subsystem.Prediction.ICommandPredictor` interface. This interface +declares the methods used to query for prediction results and provide feedback. ++A predictor module must register a `CommandPredictor` subsystem with PowerShell's `SubsystemManager` +when loaded and unregister itself when unloaded. ++The following diagram shows the architecture of a predictor in PowerShell. ++![Architecture](mediline-predictor/predictor-architecture.png) ++## Creating the code ++To create a predictor, you must have the .NET 6 SDK installed for your platform. For more +information on the SDK, see [Download .NET 6.0](https://dotnet.microsoft.com/download/dotnet/6.0). ++Create a new PowerShell module project by following these steps: ++1. Use the `dotnet` command-line tool to create a starter classlib project. ++ ```powershell + dotnet new classlib --name SamplePredictor + ``` ++1. Edit the `SamplePredictor.csproj` to contain the following information: ++ ```xml + <Project Sdk="Microsoft.NET.Sdk"> ++ <PropertyGroup> + <TargetFramework>net6.0</TargetFramework> + </PropertyGroup> ++ <ItemGroup> + <PackageReference Include="Microsoft.PowerShell.SDK" Version="7.2.0" /> + </ItemGroup> ++ </Project> + ``` ++1. Delete the default `Class1.cs` file created by `dotnet` and copy the following code to a + `SamplePredictorClass.cs` file in your project folder. ++ ```csharp + using System; + using System.Collections.Generic; + using System.Threading; + using System.Management.Automation; + using System.Management.Automation.Subsystem; + using System.Management.Automation.Subsystem.Prediction; ++ namespace PowerShell.Sample + { + public class SamplePredictor : ICommandPredictor + { + private readonly Guid _guid; ++ internal SamplePredictor(string guid) + { + _guid = new Guid(guid); + } ++ /// <summary> + /// Gets the unique identifier for a subsystem implementation. + /// </summary> + public Guid Id => _guid; ++ /// <summary> + /// Gets the name of a subsystem implementation. + /// </summary> + public string Name => "SamplePredictor"; ++ /// <summary> + /// Gets the description of a subsystem implementation. + /// </summary> + public string Description => "A sample predictor"; ++ /// <summary> + /// Get the predictive suggestions. It indicates the start of a suggestion rendering session. + /// </summary> + /// <param name="client">Represents the client that initiates the call.</param> + /// <param name="context">The <see cref="PredictionContext"/> object to be used for prediction.</param> + /// <param name="cancellationToken">The cancellation token to cancel the prediction.</param> + /// <returns>An instance of <see cref="SuggestionPackage"/>.</returns> + public SuggestionPackage GetSuggestion(PredictionClient client, PredictionContext context, CancellationToken cancellationToken) + { + string input = context.InputAst.Extent.Text; + if (string.IsNullOrWhiteSpace(input)) + { + return default; + } ++ return new SuggestionPackage(new List<PredictiveSuggestion>{ + new PredictiveSuggestion(string.Concat(input, " HELLO WORLD")) + }); + } ++ #region "interface methods for processing feedback" ++ /// <summary> + /// Gets a value indicating whether the predictor accepts a specific kind of feedback. + /// </summary> + /// <param name="client">Represents the client that initiates the call.</param> + /// <param name="feedback">A specific type of feedback.</param> + /// <returns>True or false, to indicate whether the specific feedback is accepted.</returns> + public bool CanAcceptFeedback(PredictionClient client, PredictorFeedbackKind feedback) => false; ++ /// <summary> + /// One or more suggestions provided by the predictor were displayed to the user. + /// </summary> + /// <param name="client">Represents the client that initiates the call.</param> + /// <param name="session">The mini-session where the displayed suggestions came from.</param> + /// <param name="countOrIndex"> + /// When the value is greater than 0, it's the number of displayed suggestions from the list + /// returned in <paramref name="session"/>, starting from the index 0. When the value is + /// less than or equal to 0, it means a single suggestion from the list got displayed, and + /// the index is the absolute value. + /// </param> + public void OnSuggestionDisplayed(PredictionClient client, uint session, int countOrIndex) { } ++ /// <summary> + /// The suggestion provided by the predictor was accepted. + /// </summary> + /// <param name="client">Represents the client that initiates the call.</param> + /// <param name="session">Represents the mini-session where the accepted suggestion came from.</param> + /// <param name="acceptedSuggestion">The accepted suggestion text.</param> + public void OnSuggestionAccepted(PredictionClient client, uint session, string acceptedSuggestion) { } ++ /// <summary> + /// A command line was accepted to execute. + /// The predictor can start processing early as needed with the latest history. + /// </summary> + /// <param name="client">Represents the client that initiates the call.</param> + /// <param name="history">History command lines provided as references for prediction.</param> + public void OnCommandLineAccepted(PredictionClient client, IReadOnlyList<string> history) { } ++ /// <summary> + /// A command line was done execution. + /// </summary> + /// <param name="client">Represents the client that initiates the call.</param> + /// <param name="commandLine">The last accepted command line.</param> + /// <param name="success">Shows whether the execution was successful.</param> + public void OnCommandLineExecuted(PredictionClient client, string commandLine, bool success) { } ++ #endregion; + } ++ /// <summary> + /// Register the predictor on module loading and unregister it on module un-loading. + /// </summary> + public class Init : IModuleAssemblyInitializer, IModuleAssemblyCleanup + { + private const string Identifier = "843b51d0-55c8-4c1a-8116-f0728d419306"; ++ /// <summary> + /// Gets called when assembly is loaded. + /// </summary> + public void OnImport() + { + var predictor = new SamplePredictor(Identifier); + SubsystemManager.RegisterSubsystem(SubsystemKind.CommandPredictor, predictor); + } ++ /// <summary> + /// Gets called when the binary module is unloaded. + /// </summary> + public void OnRemove(PSModuleInfo psModuleInfo) + { + SubsystemManager.UnregisterSubsystem(SubsystemKind.CommandPredictor, new Guid(Identifier)); + } + } + } + ``` ++ The following example code returns the string "HELLO WORLD" for the prediction result for all user + input. Since the sample predictor doesn't process any feedback, the code does not implement the + feedback methods from the interface. Change the prediction and feedback code to meet the needs of + your predictor. ++1. Run `dotnet build` to produce the assembly. You can find the compiled assembly in the + `bin/Debug/net6.0` location of your project folder. ++## Using your predictor plugin ++To try out your new predictor, open a new PowerShell 7.2 session and run the following commands: ++```powershell +Set-PSReadLineOption -PredictionSource HistoryAndPlugin +Import-Module .\bin\Debug\net6.0\SamplePredictor.dll +``` ++With the assembly is loaded in the session, you will see the text "HELLO WORLD" appear as you type +in the terminal. You can press <kbd>F2</kbd> to switch between the `Inline` view and the `List` +view. ++For more information about PSReadLine options, see +[Set-PSReadLineOption](/powershell/module/psreadline/set-psreadlineoption?view=powershell-7.3&preserve-view=true). ++You can get a list of installed predictors, using the following command: ++```powershell +Get-PSSubsystem -Kind CommandPredictor +``` ++```Output +Kind SubsystemType IsRegistered Implementations +---- ------------- ------------ --------------- +CommandPredictor ICommandPredictor True {SamplePredictor} +``` |
learn | Everything About Pscustomobject | https://github.com/MicrosoftDocs/PowerShell-Docs/commits/staging/reference/docs-conceptual/learn/deep-dives/everything-about-pscustomobject.md | hashtable first. This example works because the constructor takes a hashtable fo properties. One important note is that while this method works, it isn't an exact equivalent. The biggest difference is that the order of the properties isn't preserved. +If you want to preserve the order, see [Ordered hashtables](#ordered-hashtables) below. + ### Legacy approach You may have seen people use `New-Object` to create custom objects. |