Created
July 1, 2026 05:41
-
-
Save jborean93/f5817a480e2e461152eedec77aff6a7b to your computer and use it in GitHub Desktop.
A POC to illustrate how a binary cmdlet could change how cmdlets are defined and written in C#
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System; | |
| using System.Management.Automation; | |
| using System.Threading; | |
| using System.Threading.Tasks; | |
| using Jborean.PwshAsync.Generators; | |
| namespace SampleCmdlet.Examples; | |
| [AsyncPSCmdlet(VerbsDiagnostic.Test, "SimpleNoOutput")] | |
| public partial class SimpleCmdletNoOutput | |
| { | |
| // Parameter sets are defined by a nested record type with the | |
| // [ParameterSet] attribute. All record properties are parameters | |
| // for that parameter set. The record name is the parameter set name. | |
| // OutputType is defined by the AsyncPipeline<T> (or no T for no output) | |
| // in the *Async method signature. | |
| [ParameterSet] | |
| internal record Params( | |
| [Parameter(Mandatory)] | |
| string Message, // Parameter with custom [Parameter()] logic | |
| string? Prefix, // Just [Parameter()] explicitly | |
| int Count = 1 // Same but with default value | |
| ); | |
| protected async Task EndAsync( | |
| Params p, | |
| AsyncPipeline pipeline, // Non-generic, no output allowed | |
| CancellationToken cancellationToken) | |
| { | |
| await Task.Delay(10, cancellationToken); | |
| pipeline.WriteVerbose("Verbose and other streams still work"); | |
| // Writing output is impossible because the pipeline type is non-generic. | |
| // This won't work. | |
| // await pipeline.WriteAsync("test") | |
| } | |
| } | |
| [AsyncPSCmdlet(VerbsCommon.Get, "Greeting")] | |
| public partial class SimpleCmdletWithOutput | |
| { | |
| [ParameterSet] | |
| internal record Params(string? Name); | |
| protected async Task ProcessAsync( | |
| Params p, | |
| AsyncPipeline<string> pipeline, // AsyncPipeline<T> defines OutputType | |
| CancellationToken cancellationToken) | |
| { | |
| await Task.Delay(10, cancellationToken); | |
| await pipeline.WriteAsync($"Hello, {p.Name ?? "World"}!", cancellationToken); | |
| } | |
| } | |
| // Default parameter set is defined in the cmdlet attribute like usual. | |
| [AsyncPSCmdlet(VerbsCommon.Get, "User", DefaultParameterSetName = "ByName")] | |
| public partial class MultipleParamSetsCmdlet | |
| { | |
| [ParameterSet] | |
| internal record ByName( | |
| [Parameter(Position = 0)] | |
| string Name, | |
| SwitchParameter Detailed); | |
| [ParameterSet] | |
| internal record ById( | |
| [Parameter(Position = 0)] | |
| [ValidateRange(1, int.MaxValue)] // parameters can have normal validation attributes | |
| int Id, | |
| SwitchParameter Detailed); | |
| // Cmdlets can have their own fields to persist state between Begin/Process/End | |
| // blocks. | |
| private int UserId { get; set; } | |
| // Runs under the ByName parameter set, does not need to be defined | |
| // for all parameter sets but there has to be at least 1 block per | |
| // parameter set. | |
| protected async Task BeginAsync( | |
| ByName p, | |
| AsyncPipeline<string> pipeline, | |
| CancellationToken cancellationToken) | |
| { | |
| UserId = await LookupUserIdByNameAsync(p.Name, cancellationToken); | |
| } | |
| // End block for ByName parameter set | |
| protected async Task EndAsync( | |
| ByName p, | |
| AsyncPipeline<string> pipeline, | |
| CancellationToken cancellationToken) | |
| { | |
| if (UserId == 0) | |
| { | |
| // Begin failed to find user, skip this. | |
| return; | |
| } | |
| string result = await LookupUserInfoById(UserId, p.Detailed.IsPresent, cancellationToken); | |
| await pipeline.WriteAsync(result, cancellationToken); | |
| } | |
| // End block for ById parameter set | |
| protected async Task EndAsync( | |
| ById p, | |
| AsyncPipeline<string> pipeline, | |
| CancellationToken cancellationToken) | |
| { | |
| string result = await LookupUserInfoById(p.Id, p.Detailed.IsPresent, cancellationToken); | |
| await pipeline.WriteAsync(result, cancellationToken); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment