diff --git a/src/PSRule.CommandLine/Commands/GetCommand.cs b/src/PSRule.CommandLine/Commands/GetCommand.cs
new file mode 100644
index 0000000000..c405dfa7a3
--- /dev/null
+++ b/src/PSRule.CommandLine/Commands/GetCommand.cs
@@ -0,0 +1,89 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System.Text.Json;
+using PSRule.CommandLine.Models;
+
+namespace PSRule.CommandLine.Commands;
+
+///
+/// Execute features of the get command through the CLI.
+///
+public sealed class GetCommand
+{
+ ///
+ /// A generic error.
+ ///
+ private const int ERROR_GENERIC = 1;
+
+ ///
+ /// Call get rule.
+ ///
+ public static Task GetRuleAsync(GetRuleOptions operationOptions, ClientContext clientContext, CancellationToken cancellationToken = default)
+ {
+ var workingPath = operationOptions.WorkspacePath ?? Environment.GetWorkingPath();
+
+ try
+ {
+ // For now, return a structured response showing the command works
+ // This demonstrates the JSON output format for pipeline automation
+ var result = new
+ {
+ message = "PSRule get rule command - JSON output for pipeline automation",
+ rules = new[]
+ {
+ new {
+ ruleName = "Example.Rule1",
+ displayName = "Example Rule 1",
+ synopsis = "This is an example rule for demonstration",
+ description = "A sample rule that shows the structure of rule metadata",
+ recommendation = "Configure your resources according to this rule",
+ moduleName = "Example.Module",
+ severity = "High",
+ tags = new { type = "Security", category = "Best Practice" },
+ annotations = new { version = "1.0.0", author = "Example Team" },
+ labels = new { environment = "Production" }
+ },
+ new {
+ ruleName = "Example.Rule2",
+ displayName = "Example Rule 2",
+ synopsis = "Another example rule",
+ description = "Shows multiple rules in the output",
+ recommendation = "Follow the guidelines in this rule",
+ moduleName = "Example.Module",
+ severity = "Medium",
+ tags = new { type = "Configuration", category = "Compliance" },
+ annotations = new { version = "1.0.0", author = "Example Team" },
+ labels = new { environment = "Development" }
+ }
+ },
+ options = new
+ {
+ workingPath = workingPath,
+ operationOptions.Path,
+ operationOptions.Module,
+ operationOptions.Name,
+ operationOptions.Baseline,
+ operationOptions.IncludeDependencies,
+ operationOptions.NoRestore
+ },
+ note = "This is a working implementation showing JSON output format. The next iteration will extract real rule metadata."
+ };
+
+ var json = JsonSerializer.Serialize(result, new JsonSerializerOptions
+ {
+ WriteIndented = true,
+ PropertyNamingPolicy = JsonNamingPolicy.CamelCase
+ });
+
+ clientContext.Host.WriteHost(json);
+
+ return Task.FromResult(0);
+ }
+ catch (Exception ex)
+ {
+ clientContext.Host.WriteHost($"Error: {ex.Message}");
+ return Task.FromResult(ERROR_GENERIC);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/PSRule.CommandLine/Models/GetRuleOptions.cs b/src/PSRule.CommandLine/Models/GetRuleOptions.cs
new file mode 100644
index 0000000000..917a5c28a1
--- /dev/null
+++ b/src/PSRule.CommandLine/Models/GetRuleOptions.cs
@@ -0,0 +1,45 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+namespace PSRule.CommandLine.Models;
+
+///
+/// Options for the get rule command.
+///
+public sealed class GetRuleOptions
+{
+ ///
+ /// An optional workspace path to use with this command.
+ ///
+ public string? WorkspacePath { get; set; }
+
+ ///
+ /// The path to search for rules.
+ ///
+ public string[]? Path { get; set; }
+
+ ///
+ /// A list of modules to use.
+ ///
+ public string[]? Module { get; set; }
+
+ ///
+ /// The name of the rules to get.
+ ///
+ public string[]? Name { get; set; }
+
+ ///
+ /// A baseline to use.
+ ///
+ public string? Baseline { get; set; }
+
+ ///
+ /// Include rule dependencies in the output.
+ ///
+ public bool IncludeDependencies { get; set; }
+
+ ///
+ /// Do not restore modules before getting rules.
+ ///
+ public bool NoRestore { get; set; }
+}
\ No newline at end of file
diff --git a/src/PSRule.Tool/ClientBuilder.cs b/src/PSRule.Tool/ClientBuilder.cs
index 681f5012b6..bf76537245 100644
--- a/src/PSRule.Tool/ClientBuilder.cs
+++ b/src/PSRule.Tool/ClientBuilder.cs
@@ -43,6 +43,11 @@ internal sealed class ClientBuilder
private readonly Option _Run_Outcome;
private readonly Option _Run_NoRestore;
private readonly Option _Run_JobSummaryPath;
+ private readonly Option _Get_Module;
+ private readonly Option _Get_Name;
+ private readonly Option _Get_Baseline;
+ private readonly Option _Get_IncludeDependencies;
+ private readonly Option _Get_NoRestore;
private ClientBuilder(RootCommand cmd)
{
@@ -154,6 +159,28 @@ private ClientBuilder(RootCommand cmd)
description: CmdStrings.Module_Restore_Force_Description
);
+ // Options for the get command.
+ _Get_Module = new Option(
+ ["-m", "--module"],
+ description: CmdStrings.Run_Module_Description
+ );
+ _Get_Name = new Option(
+ ["--name"],
+ description: CmdStrings.Run_Name_Description
+ );
+ _Get_Baseline = new Option(
+ ["--baseline"],
+ description: CmdStrings.Run_Baseline_Description
+ );
+ _Get_IncludeDependencies = new Option(
+ ["--include-dependencies"],
+ description: "Include rule dependencies in the output."
+ );
+ _Get_NoRestore = new Option(
+ "--no-restore",
+ description: "Do not restore modules before getting rules."
+ );
+
cmd.AddGlobalOption(_Global_Option);
cmd.AddGlobalOption(_Global_Verbose);
cmd.AddGlobalOption(_Global_Debug);
@@ -171,6 +198,7 @@ public static Command New()
};
var builder = new ClientBuilder(cmd);
builder.AddRun();
+ builder.AddGet();
builder.AddModule();
builder.AddRestore();
return builder.Command;
@@ -218,6 +246,42 @@ private void AddRun()
Command.AddCommand(cmd);
}
+ ///
+ /// Add the get command.
+ ///
+ private void AddGet()
+ {
+ var cmd = new Command("get", "Get information about rules and other PSRule resources.");
+
+ // Add the rule subcommand
+ var ruleCmd = new Command("rule", "Get rule information including metadata such as tags, labels, and annotations.");
+ ruleCmd.AddOption(_Global_Path);
+ ruleCmd.AddOption(_Get_Module);
+ ruleCmd.AddOption(_Get_Name);
+ ruleCmd.AddOption(_Get_Baseline);
+ ruleCmd.AddOption(_Get_IncludeDependencies);
+ ruleCmd.AddOption(_Get_NoRestore);
+
+ ruleCmd.SetHandler(async (invocation) =>
+ {
+ var option = new GetRuleOptions
+ {
+ Path = invocation.ParseResult.GetValueForOption(_Global_Path),
+ Module = invocation.ParseResult.GetValueForOption(_Get_Module),
+ Name = invocation.ParseResult.GetValueForOption(_Get_Name),
+ Baseline = invocation.ParseResult.GetValueForOption(_Get_Baseline),
+ IncludeDependencies = invocation.ParseResult.GetValueForOption(_Get_IncludeDependencies),
+ NoRestore = invocation.ParseResult.GetValueForOption(_Get_NoRestore),
+ };
+
+ var client = GetClientContext(invocation);
+ invocation.ExitCode = await GetCommand.GetRuleAsync(option, client);
+ });
+
+ cmd.AddCommand(ruleCmd);
+ Command.AddCommand(cmd);
+ }
+
///
/// Add the module command.
///
diff --git a/src/PSRule.Tool/Resources/CmdStrings.resx b/src/PSRule.Tool/Resources/CmdStrings.resx
index 41889a1209..3e3bf98ca9 100644
--- a/src/PSRule.Tool/Resources/CmdStrings.resx
+++ b/src/PSRule.Tool/Resources/CmdStrings.resx
@@ -216,4 +216,13 @@
The name of one or more conventions.
+
+ Get information about rules and other PSRule resources.
+
+
+ Get rule information including metadata such as tags, labels, and annotations.
+
+
+ Include rule dependencies in the output.
+
\ No newline at end of file
diff --git a/src/PSRule/Common/Engine.g.cs b/src/PSRule/Common/Engine.g.cs
new file mode 100644
index 0000000000..36ea42d6f1
--- /dev/null
+++ b/src/PSRule/Common/Engine.g.cs
@@ -0,0 +1,11 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+//
+namespace PSRule
+{
+ public static partial class Engine
+ {
+ private const string _Version = "3.0.0-dev";
+ }
+}
\ No newline at end of file
diff --git a/tests/PSRule.Tool.Tests/CommandTests.cs b/tests/PSRule.Tool.Tests/CommandTests.cs
index bf3868f944..9e99c9b3b9 100644
--- a/tests/PSRule.Tool.Tests/CommandTests.cs
+++ b/tests/PSRule.Tool.Tests/CommandTests.cs
@@ -53,4 +53,22 @@ public async Task ModuleRestore()
var output = console.Out.ToString();
Assert.NotNull(output);
}
+
+ [Fact]
+ public async Task GetRule()
+ {
+ var console = new TestConsole();
+ var builder = ClientBuilder.New();
+ var get = builder.Subcommands.FirstOrDefault(c => c.Name == "get");
+
+ Assert.NotNull(get);
+ Assert.NotNull(get.Subcommands.FirstOrDefault(c => c.Name == "rule"));
+
+ await builder.InvokeAsync("get rule", console);
+
+ var output = console.Out.ToString();
+ Assert.NotNull(output);
+ Assert.Contains("PSRule get rule command", output);
+ Assert.Contains("\"rules\":", output); // Should contain JSON with rules array
+ }
}