Uwaga
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Program PowerShell 7.4 wprowadził koncepcję dostawców opinii. Dostawca opinii to moduł programu PowerShell, który implementuje interfejs IFeedbackProvider w celu udostępnienia sugestii poleceń opartych na próbach wykonywania poleceń użytkownika. Dostawca jest wyzwalany, gdy wystąpi sukces lub niepowodzenie wykonania. Dostawcy opinii używają informacji z powodzenia lub niepowodzenia przekazywania opinii.
Warunki wstępne
Aby utworzyć dostawcę opinii, musisz spełnić następujące wymagania wstępne:
- Instalowanie programu PowerShell w wersji 7.4 lub nowszej
- Należy włączyć funkcję eksperymentalną
PSFeedbackProvider, aby umożliwić obsługę dostawców opinii i predyktorów. Aby uzyskać więcej informacji, zobacz Korzystanie z funkcji eksperymentalnych.
- Należy włączyć funkcję eksperymentalną
- Instalowanie zestawu .NET 8 SDK — 8.0.0 lub nowszego
- Aby uzyskać najnowszą wersję zestawu SDK, odwiedź stronę pobierania .NET 8.0.
Omówienie źródła opinii zwrotnej
Dostawca opinii to moduł binarny programu PowerShell, który implementuje interfejs System.Management.Automation.Subsystem.Feedback.IFeedbackProvider. Ten interfejs deklaruje metody uzyskiwania opinii na podstawie danych wejściowych wiersza polecenia. Interfejs opinii może udostępniać sugestie na podstawie powodzenia lub niepowodzenia polecenia wywoływanego przez użytkownika. Sugestie mogą być dowolne. Możesz na przykład zasugerować sposoby rozwiązania błędu lub lepszych rozwiązań, takich jak unikanie używania aliasów. Aby uzyskać więcej informacji, zobacz wpis na blogu Co to są dostawcy opinii?.
Na poniższym diagramie przedstawiono architekturę dostawcy opinii:
W poniższych przykładach przedstawiono proces tworzenia prostego dostawcy opinii. Ponadto możesz zarejestrować dostawcę za pomocą interfejsu predykcji poleceń, aby dodać sugestie opinii użytkownika do doświadczenia z predyktorem poleceń. Aby uzyskać więcej informacji na temat predyktorów, zobacz Korzystanie z predyktorów w PSReadLine i Jak stworzyć predyktor wiersza poleceń.
Krok 1. Tworzenie nowego projektu biblioteki klas
Użyj następującego polecenia, aby utworzyć nowy projekt w katalogu projektu:
dotnet new classlib --name MyFeedbackProvider
Dodaj odwołanie do pakietu System.Management.Automation do pliku .csproj. W poniższym przykładzie pokazano zaktualizowany plik .csproj:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.Management.Automation" Version="7.4.0-preview.3">
<ExcludeAssets>contentFiles</ExcludeAssets>
<PrivateAssets>All</PrivateAssets>
</PackageReference>
</ItemGroup>
</Project>
Notatka
Należy zmienić wersję zestawu System.Management.Automation, aby odpowiadała wersji zapoznawczej programu PowerShell, na którą się ukierunkowujesz. Minimalna wersja to 7.4.0-preview.3.
Krok 2. Dodawanie definicji klasy dla dostawcy
Zmień nazwę pliku Class1.cs, aby był zgodny z nazwą dostawcy. W tym przykładzie użyto myFeedbackProvider.cs. Ten plik zawiera dwie główne klasy definiujące dostawcę opinii.
W poniższym przykładzie przedstawiono podstawowy szablon definicji klas.
using System.Management.Automation;
using System.Management.Automation.Subsystem;
using System.Management.Automation.Subsystem.Feedback;
using System.Management.Automation.Subsystem.Prediction;
using System.Management.Automation.Language;
namespace myFeedbackProvider;
public sealed class myFeedbackProvider : IFeedbackProvider, ICommandPredictor
{
}
public class Init : IModuleAssemblyInitializer, IModuleAssemblyCleanup
{
}
Krok 3. Implementowanie klasy Init
Klasa Init rejestruje i wyrejestrowuje dostawcę opinii za pomocą menedżera podsystemu. Metoda OnImport() jest uruchamiana po załadowaniu modułu binarnego. Metoda OnRemove() jest uruchamiana po usunięciu modułu binarnego. W tym przykładzie zarejestrowano zarówno dostawcę opinii, jak i podsystem predyktora poleceń.
public class Init : IModuleAssemblyInitializer, IModuleAssemblyCleanup
{
private const string Id = "<ADD YOUR GUID HERE>";
public void OnImport()
{
var feedback = new myFeedbackProvider(Id);
SubsystemManager.RegisterSubsystem(SubsystemKind.FeedbackProvider, feedback);
SubsystemManager.RegisterSubsystem(SubsystemKind.CommandPredictor, feedback);
}
public void OnRemove(PSModuleInfo psModuleInfo)
{
SubsystemManager.UnregisterSubsystem<ICommandPredictor>(new Guid(Id));
SubsystemManager.UnregisterSubsystem<IFeedbackProvider>(new Guid(Id));
}
}
Zastąp wartość symbolu zastępczego <ADD YOUR GUID HERE> unikatowym identyfikatorem GUID. Możesz wygenerować identyfikator GUID za pomocą cmdletu New-Guid.
New-Guid
Identyfikator GUID jest unikatowym identyfikatorem twojego dostawcy. Dostawca musi mieć unikatowy identyfikator do zarejestrowania w podsystemie.
Krok 4. Dodawanie składowych klasy i definiowanie konstruktora
Poniższy kod implementuje właściwości zdefiniowane w interfejsach, dodaje potrzebne składowe klasy i tworzy konstruktor dla klasy myFeedbackProvider.
/// <summary>
/// Gets the global unique identifier for the subsystem implementation.
/// </summary>
private readonly Guid _guid;
public Guid Id => _guid;
/// <summary>
/// Gets the name of a subsystem implementation, this will be the name displayed when triggered
/// </summary>
public string Name => "myFeedbackProvider";
/// <summary>
/// Gets the description of a subsystem implementation.
/// </summary>
public string Description => "This is very simple feedback provider";
/// <summary>
/// Default implementation. No function is required for a feedback provider.
/// </summary>
Dictionary<string, string>? ISubsystem.FunctionsToDefine => null;
/// <summary>
/// Gets the types of trigger for this feedback provider.
/// </summary>
/// <remarks>
/// The default implementation triggers a feedback provider by <see cref="FeedbackTrigger.CommandNotFound"/> only.
/// </remarks>
public FeedbackTrigger Trigger => FeedbackTrigger.All;
/// <summary>
/// List of candidates from the feedback provider to be passed as predictor results
/// </summary>
private List<string>? _candidates;
/// <summary>
/// PowerShell session used to run PowerShell commands that help create suggestions.
/// </summary>
private PowerShell _powershell;
internal myFeedbackProvider(string guid)
{
_guid = new Guid(guid); // Save guid
_powershell = PowerShell.Create(); // Create PowerShell instance
}
Krok 5. Tworzenie metody GetFeedback()
Metoda GetFeedback przyjmuje dwa parametry, context i token. Parametr context odbiera informacje o wyzwalaczu, dzięki czemu możesz zdecydować, jak odpowiedzieć sugestiami. Parametr token jest używany do anulowania. Ta funkcja zwraca FeedbackItem zawierającą sugestię.
/// <summary>
/// Gets feedback based on the given commandline and error record.
/// </summary>
/// <param name="context">The context for the feedback call.</param>
/// <param name="token">The cancellation token to cancel the operation.</param>
/// <returns>The feedback item.</returns>
public FeedbackItem? GetFeedback(FeedbackContext context, CancellationToken token)
{
// Target describes the different kinds of triggers to activate on,
var target = context.Trigger;
var commandLine = context.CommandLine;
var ast = context.CommandLineAst;
// defining the header and footer variables
string header;
string footer;
// List of the actions
List<string>? actions = new List<string>();
// Trigger on success code goes here
// Trigger on error code goes here
return null;
}
Na poniższej ilustracji przedstawiono sposób użycia tych pól w sugestiach wyświetlanych użytkownikowi.
Tworzenie sugestii dotyczących wyzwalacza powodzenia
W przypadku pomyślnego wywołania chcemy rozwinąć wszystkie aliasy używane w ostatnim wykonaniu. Korzystając z CommandLineAst, identyfikujemy wszystkie aliasy poleceń i zamiast tego tworzymy sugestię użycia w pełni kwalifikowanej nazwy polecenia.
// Trigger on success
if (target == FeedbackTrigger.Success)
{
// Getting the commands from the AST and only finding those that are Commands
var astCmds = ast.FindAll((cAst) => cAst is CommandAst, true);
// Inspect each of the commands
foreach(var command in astCmds)
{
// Get the command name
var aliasedCmd = ((CommandAst) command).GetCommandName();
// Check if its an alias or not, if so then add it to the list of actions
if(TryGetAlias(aliasedCmd, out string commandString))
{
actions.Add($"{aliasedCmd} --> {commandString}");
}
}
// If no alias was found return null
if(actions.Count == 0)
{
return null;
}
// If aliases are found, set the header to a description and return a new FeedbackItem.
header = "You have used an aliased command:";
// Copy actions to _candidates for the predictor
_candidates = actions;
return new FeedbackItem(header, actions);
}
Implementowanie metody TryGetAlias()
Metoda TryGetAlias() jest prywatną funkcją pomocnika, która zwraca wartość logiczną, aby wskazać, czy polecenie jest aliasem. W konstruktorze klasy utworzyliśmy wystąpienie programu PowerShell, którego możemy użyć do uruchamiania poleceń programu PowerShell. Metoda TryGetAlias() używa tego wystąpienia programu PowerShell do wywołania metody GetCommand w celu określenia, czy polecenie jest aliasem. Obiekt AliasInfo zwrócony przez GetCommand zawiera pełną nazwę aliasowanego polecenia.
/// <summary>
/// Checks if a command is an alias.
/// </summary>
/// <param name="command">The command to check if alias</param>
/// <param name="targetCommand">The referenced command by the aliased command</param>
/// <returns>True if an alias and false if not</returns>
private bool TryGetAlias(string command, out string targetCommand)
{
// Create PowerShell runspace as a session state proxy to run GetCommand and check
// if its an alias
AliasInfo? pwshAliasInfo =
_powershell.Runspace.SessionStateProxy.InvokeCommand.GetCommand(command, CommandTypes.Alias) as AliasInfo;
// if its null then it is not an aliased command so just return false
if(pwshAliasInfo is null)
{
targetCommand = String.Empty;
return false;
}
// Set targetCommand to referenced command name
targetCommand = pwshAliasInfo.ReferencedCommand.Name;
return true;
}
Przygotuj sugestie dla wyzwalacza błędu
Gdy wykonanie polecenia zakończy się niepowodzeniem, chcemy zasugerować, aby użytkownik Get-Help uzyskać więcej informacji o sposobie używania polecenia.
// Trigger on error
if (target == FeedbackTrigger.Error)
{
// Gets the command that caused the error.
var erroredCommand = context.LastError?.InvocationInfo.MyCommand;
if (erroredCommand is null)
{
return null;
}
header = $"You have triggered an error with the command {erroredCommand}. Try using the following command to get help:";
actions.Add($"Get-Help {erroredCommand}");
footer = $"You can also check online documentation at https://learn.microsoft.com/en-us/powershell/module/?term={erroredCommand}";
// Copy actions to _candidates for the predictor
_candidates = actions;
return new FeedbackItem(header, actions, footer, FeedbackDisplayLayout.Portrait);
}
Krok 6. Wyślij sugestie do prognozatora wiersza poleceń
Inny sposób, w jaki dostawca opinii może poprawić doświadczenie użytkownika, to dostarczanie sugestii poleceń do interfejsu ICommandPredictor. Aby uzyskać więcej informacji na temat tworzenia predyktora wiersza polecenia, zobacz Jak utworzyć predyktor wiersza polecenia.
Poniższy kod implementuje niezbędne metody z interfejsu ICommandPredictor, aby dodać funkcjonalność predykcyjną do dostawcy opinii.
-
CanAcceptFeedback()— ta metoda zwraca wartość logiczną wskazującą, czy predyktor akceptuje określony typ opinii. -
GetSuggestion()— ta metoda zwraca obiektSuggestionPackagezawierający sugestie, które mają być wyświetlane przez predyktor. -
OnCommandLineAccepted()— ta metoda jest wywoływana, gdy wiersz polecenia jest akceptowany do wykonania.
/// <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)
{
return feedback switch
{
PredictorFeedbackKind.CommandLineAccepted => true,
_ => false,
};
}
/// <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)
{
if (_candidates is not null)
{
string input = context.InputAst.Extent.Text;
List<PredictiveSuggestion>? result = null;
foreach (string c in _candidates)
{
if (c.StartsWith(input, StringComparison.OrdinalIgnoreCase))
{
result ??= new List<PredictiveSuggestion>(_candidates.Count);
result.Add(new PredictiveSuggestion(c));
}
}
if (result is not null)
{
return new SuggestionPackage(result);
}
}
return default;
}
/// <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)
{
// Reset the candidate state once the command is accepted.
_candidates = null;
}
Krok 7. Tworzenie dostawcy opinii
Teraz możesz przystąpić do tworzenia i rozpoczynania korzystania z dostawcy opinii. Aby skompilować projekt, uruchom następujące polecenie:
dotnet build
To polecenie umożliwia utworzenie modułu programu PowerShell jako pliku DLL w następującej ścieżce folderu projektu: bin/Debug/net8.0/myFeedbackProvider
Podczas kompilowania na maszynach z systemem Windows może wystąpić błąd error NU1101: Unable to find package System.Management.Automation.. Aby rozwiązać ten problem, dodaj plik nuget.config do katalogu projektu i dodaj następujące elementy:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<clear />
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
</packageSources>
<disabledPackageSources>
<clear />
</disabledPackageSources>
</configuration>
Korzystanie z dostawcy opinii
Aby przetestować nowego dostawcę opinii, zaimportuj skompilowany moduł do sesji programu PowerShell. Można to zrobić, importując folder wspomniany po zakończeniu budowania.
Import-Module ./bin/Debug/net8.0/myFeedbackProvider
Gdy jesteś zadowolony z modułu, należy utworzyć manifest modułu, opublikować go w Galerii PowerShell i zainstalować go w $Env:PSModulePath. Aby uzyskać więcej informacji, zobacz Jak utworzyć manifest modułu. Możesz dodać polecenie Import-Module do skryptu $PROFILE, aby moduł był dostępny w sesji programu PowerShell.
Listę zainstalowanych dostawców opinii można uzyskać przy użyciu następującego polecenia:
Get-PSSubsystem -Kind FeedbackProvider
Kind SubsystemType IsRegistered Implementations
---- ------------- ------------ ---------------
FeedbackProvider IFeedbackProvider True {general}
Notatka
Get-PSSubsystem to eksperymentalne polecenie cmdlet wprowadzone w programie PowerShell 7.1 Aby użyć tego polecenia cmdlet, musisz włączyć funkcję eksperymentalną PSSubsystemPluginModel. Aby uzyskać więcej informacji, zobacz Korzystanie z funkcji eksperymentalnych.
Poniższy zrzut ekranu przedstawia kilka przykładowych sugestii od nowego dostawcy.
Poniżej przedstawiono plik GIF pokazujący, jak działa integracja predyktora z nowego dostawcy.
Inni dostawcy opinii
Utworzyliśmy alternatywne źródło opinii, które można użyć jako dobry punkt odniesienia do głębszych przykładów.
polecenie nie znaleziono
Udostępniający informacje zwrotne command-not-found korzysta z narzędzia command-not-found w systemach Linux, aby dostarczać sugestii przy próbie uruchomienia poleceń natywnych, które są niedostępne. Kod można znaleźć w repozytorium GitHub lub pobrać samodzielnie z PowerShell Gallery .
PowerShell Adapter
Microsoft.PowerShell.PowerShellAdapter to dostawca opinii, który ułatwia konwertowanie danych wyjściowych tekstu z natywnych poleceń na obiekty programu PowerShell. Wykrywa ona "adaptery" w systemie i sugeruje ich użycie, gdy korzystasz z natywnego polecenia. Więcej informacji na temat adapterów programu PowerShell można znaleźć we wpisie na blogu dotyczącym opinii o adapterze programu PowerShell. Kod można również znaleźć w repozytorium GitHub lub pobrać go samodzielnie w galerii PowerShell .
Dodatek — pełny kod implementacji
Poniższy kod łączy poprzednie przykłady w celu znalezienia pełnej implementacji klasy dostawcy.
using System.Management.Automation;
using System.Management.Automation.Subsystem;
using System.Management.Automation.Subsystem.Feedback;
using System.Management.Automation.Subsystem.Prediction;
using System.Management.Automation.Language;
namespace myFeedbackProvider;
public sealed class myFeedbackProvider : IFeedbackProvider, ICommandPredictor
{
/// <summary>
/// Gets the global unique identifier for the subsystem implementation.
/// </summary>
private readonly Guid _guid;
public Guid Id => _guid;
/// <summary>
/// Gets the name of a subsystem implementation, this will be the name displayed when triggered
/// </summary>
public string Name => "myFeedbackProvider";
/// <summary>
/// Gets the description of a subsystem implementation.
/// </summary>
public string Description => "This is very simple feedback provider";
/// <summary>
/// Default implementation. No function is required for a feedback provider.
/// </summary>
Dictionary<string, string>? ISubsystem.FunctionsToDefine => null;
/// <summary>
/// Gets the types of trigger for this feedback provider.
/// </summary>
/// <remarks>
/// The default implementation triggers a feedback provider by <see cref="FeedbackTrigger.CommandNotFound"/> only.
/// </remarks>
public FeedbackTrigger Trigger => FeedbackTrigger.All;
/// <summary>
/// List of candidates from the feedback provider to be passed as predictor results
/// </summary>
private List<string>? _candidates;
/// <summary>
/// PowerShell session used to run PowerShell commands that help create suggestions.
/// </summary>
private PowerShell _powershell;
// Constructor
internal myFeedbackProvider(string guid)
{
_guid = new Guid(guid); // Save guid
_powershell = PowerShell.Create(); // Create PowerShell instance
}
#region IFeedbackProvider
/// <summary>
/// Gets feedback based on the given commandline and error record.
/// </summary>
/// <param name="context">The context for the feedback call.</param>
/// <param name="token">The cancellation token to cancel the operation.</param>
/// <returns>The feedback item.</returns>
public FeedbackItem? GetFeedback(FeedbackContext context, CancellationToken token)
{
// Target describes the different kinds of triggers to activate on,
var target = context.Trigger;
var commandLine = context.CommandLine;
var ast = context.CommandLineAst;
// defining the header and footer variables
string header;
string footer;
// List of the actions
List<string>? actions = new List<string>();
// Trigger on success
if (target == FeedbackTrigger.Success)
{
// Getting the commands from the AST and only finding those that are Commands
var astCmds = ast.FindAll((cAst) => cAst is CommandAst, true);
// Inspect each of the commands
foreach(var command in astCmds)
{
// Get the command name
var aliasedCmd = ((CommandAst) command).GetCommandName();
// Check if its an alias or not, if so then add it to the list of actions
if(TryGetAlias(aliasedCmd, out string commandString))
{
actions.Add($"{aliasedCmd} --> {commandString}");
}
}
// If no alias was found return null
if(actions.Count == 0)
{
return null;
}
// If aliases are found, set the header to a description and return a new FeedbackItem.
header = "You have used an aliased command:";
// Copy actions to _candidates for the predictor
_candidates = actions;
return new FeedbackItem(header, actions);
}
// Trigger on error
if (target == FeedbackTrigger.Error)
{
// Gets the command that caused the error.
var erroredCommand = context.LastError?.InvocationInfo.MyCommand;
if (erroredCommand is null)
{
return null;
}
header = $"You have triggered an error with the command {erroredCommand}. Try using the following command to get help:";
actions.Add($"Get-Help {erroredCommand}");
footer = $"You can also check online documentation at https://learn.microsoft.com/en-us/powershell/module/?term={erroredCommand}";
// Copy actions to _candidates for the predictor
_candidates = actions;
return new FeedbackItem(header, actions, footer, FeedbackDisplayLayout.Portrait);
}
return null;
}
/// <summary>
/// Checks if a command is an alias.
/// </summary>
/// <param name="command">The command to check if alias</param>
/// <param name="targetCommand">The referenced command by the aliased command</param>
/// <returns>True if an alias and false if not</returns>
private bool TryGetAlias(string command, out string targetCommand)
{
// Create PowerShell runspace as a session state proxy to run GetCommand and check
// if its an alias
AliasInfo? pwshAliasInfo =
_powershell.Runspace.SessionStateProxy.InvokeCommand.GetCommand(command, CommandTypes.Alias) as AliasInfo;
// if its null then it is not an aliased command so just return false
if(pwshAliasInfo is null)
{
targetCommand = String.Empty;
return false;
}
// Set targetCommand to referenced command name
targetCommand = pwshAliasInfo.ReferencedCommand.Name;
return true;
}
#endregion IFeedbackProvider
#region ICommandPredictor
/// <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)
{
return feedback switch
{
PredictorFeedbackKind.CommandLineAccepted => true,
_ => false,
};
}
/// <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)
{
if (_candidates is not null)
{
string input = context.InputAst.Extent.Text;
List<PredictiveSuggestion>? result = null;
foreach (string c in _candidates)
{
if (c.StartsWith(input, StringComparison.OrdinalIgnoreCase))
{
result ??= new List<PredictiveSuggestion>(_candidates.Count);
result.Add(new PredictiveSuggestion(c));
}
}
if (result is not null)
{
return new SuggestionPackage(result);
}
}
return default;
}
/// <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)
{
// Reset the candidate state once the command is accepted.
_candidates = null;
}
#endregion;
}
public class Init : IModuleAssemblyInitializer, IModuleAssemblyCleanup
{
private const string Id = "<ADD YOUR GUID HERE>";
public void OnImport()
{
var feedback = new myFeedbackProvider(Id);
SubsystemManager.RegisterSubsystem(SubsystemKind.FeedbackProvider, feedback);
SubsystemManager.RegisterSubsystem(SubsystemKind.CommandPredictor, feedback);
}
public void OnRemove(PSModuleInfo psModuleInfo)
{
SubsystemManager.UnregisterSubsystem<ICommandPredictor>(new Guid(Id));
SubsystemManager.UnregisterSubsystem<IFeedbackProvider>(new Guid(Id));
}
}