mirror of
https://github.com/PowerShell/PowerShell
synced 2026-06-08 12:12:50 +00:00
Specifying an alias and -Syntax to Get-Command returns the aliased commands syntax (#10784)
@ChrisLGardner Thank you for your contribution and your patience.
This commit is contained in:
@@ -531,9 +531,7 @@ namespace Microsoft.PowerShell.Commands
|
||||
{
|
||||
if (!string.IsNullOrEmpty(result.Syntax))
|
||||
{
|
||||
PSObject syntax = PSObject.AsPSObject(result.Syntax);
|
||||
|
||||
syntax.IsHelpObject = true;
|
||||
PSObject syntax = GetSyntaxObject(result);
|
||||
|
||||
WriteObject(syntax);
|
||||
}
|
||||
@@ -571,6 +569,81 @@ namespace Microsoft.PowerShell.Commands
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the syntax output based on if the command is an alias, script, application or command.
|
||||
/// </summary>
|
||||
/// <param name="command">
|
||||
/// CommandInfo object containing the syntax to be output.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// Syntax string cast as a PSObject for outputting.
|
||||
/// </returns>
|
||||
private PSObject GetSyntaxObject(CommandInfo command)
|
||||
{
|
||||
PSObject syntax = PSObject.AsPSObject(command.Syntax);
|
||||
|
||||
// This is checking if the command name that's been passed in is one that was specified by a user,
|
||||
// if not then we have to assume they specified an alias or a wildcard and do some extra formatting for those,
|
||||
// if it is then just go with the default formatting.
|
||||
// So if a user runs Get-Command -Name del -Syntax the code will find del and the command it resolves to as Remove-Item
|
||||
// and attempt to return that, but as the user specified del we want to fiddle with the output a bit to make it clear
|
||||
// that's an alias but still give the Remove-Item syntax.
|
||||
if (this.Name != null && !Array.Exists(this.Name, name => name.Equals(command.Name, StringComparison.InvariantCultureIgnoreCase)))
|
||||
{
|
||||
string aliasName = _nameContainsWildcard ? command.Name : this.Name[0];
|
||||
|
||||
IDictionary<string, AliasInfo> aliasTable = SessionState.Internal.GetAliasTable();
|
||||
foreach (KeyValuePair<string, AliasInfo> tableEntry in aliasTable)
|
||||
{
|
||||
if ((Array.Exists(this.Name, name => name.Equals(tableEntry.Key, StringComparison.InvariantCultureIgnoreCase)) &&
|
||||
tableEntry.Value.Definition == command.Name) ||
|
||||
(_nameContainsWildcard && tableEntry.Value.Definition == command.Name))
|
||||
{
|
||||
aliasName = tableEntry.Key;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
string replacedSyntax = string.Empty;
|
||||
switch (command)
|
||||
{
|
||||
case ExternalScriptInfo externalScript:
|
||||
replacedSyntax = string.Format(
|
||||
"{0} (alias) -> {1}{2}{3}",
|
||||
aliasName,
|
||||
string.Format("{0}{1}", externalScript.Path, Environment.NewLine),
|
||||
Environment.NewLine,
|
||||
command.Syntax.Replace(command.Name, aliasName));
|
||||
break;
|
||||
case ApplicationInfo app:
|
||||
replacedSyntax = app.Path;
|
||||
break;
|
||||
default:
|
||||
if (aliasName.Equals(command.Name))
|
||||
{
|
||||
replacedSyntax = command.Syntax;
|
||||
}
|
||||
else
|
||||
{
|
||||
replacedSyntax = string.Format(
|
||||
"{0} (alias) -> {1}{2}{3}",
|
||||
aliasName,
|
||||
command.Name,
|
||||
Environment.NewLine,
|
||||
command.Syntax.Replace(command.Name, aliasName));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
syntax = PSObject.AsPSObject(replacedSyntax);
|
||||
}
|
||||
|
||||
syntax.IsHelpObject = true;
|
||||
|
||||
return syntax;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The comparer to sort CommandInfo objects in the result list.
|
||||
/// </summary>
|
||||
@@ -1229,33 +1302,37 @@ namespace Microsoft.PowerShell.Commands
|
||||
|
||||
if (isCommandMatch)
|
||||
{
|
||||
if (ArgumentList != null)
|
||||
if (Syntax.IsPresent && current is AliasInfo ai)
|
||||
{
|
||||
AliasInfo ai = current as AliasInfo;
|
||||
if (ai != null)
|
||||
// If the matching command was an alias, then use the resolved command
|
||||
// instead of the alias...
|
||||
current = ai.ResolvedCommand ?? CommandDiscovery.LookupCommandInfo(
|
||||
ai.UnresolvedCommandName,
|
||||
this.MyInvocation.CommandOrigin,
|
||||
this.Context);
|
||||
|
||||
// there are situations where both ResolvedCommand and UnresolvedCommandName
|
||||
// are both null (often due to multiple versions of modules with aliases)
|
||||
// therefore we need to exit early.
|
||||
if (current == null)
|
||||
{
|
||||
// If the matching command was an alias, then use the resolved command
|
||||
// instead of the alias...
|
||||
current = ai.ResolvedCommand;
|
||||
if (current == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (!(current is CmdletInfo || current is IScriptCommandInfo))
|
||||
{
|
||||
// If current is not a cmdlet or script, we need to throw a terminating error.
|
||||
ThrowTerminatingError(
|
||||
new ErrorRecord(
|
||||
PSTraceSource.NewArgumentException(
|
||||
"ArgumentList",
|
||||
DiscoveryExceptions.CommandArgsOnlyForSingleCmdlet),
|
||||
"CommandArgsOnlyForSingleCmdlet",
|
||||
ErrorCategory.InvalidArgument,
|
||||
current));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (ArgumentList != null && !(current is CmdletInfo || current is IScriptCommandInfo))
|
||||
{
|
||||
// If current is not a cmdlet or script, we need to throw a terminating error.
|
||||
ThrowTerminatingError(
|
||||
new ErrorRecord(
|
||||
PSTraceSource.NewArgumentException(
|
||||
"ArgumentList",
|
||||
DiscoveryExceptions.CommandArgsOnlyForSingleCmdlet),
|
||||
"CommandArgsOnlyForSingleCmdlet",
|
||||
ErrorCategory.InvalidArgument,
|
||||
current));
|
||||
}
|
||||
|
||||
// If the command implements dynamic parameters
|
||||
// then we must make a copy of the CommandInfo which merges the
|
||||
// dynamic parameter metadata with the statically defined parameter
|
||||
|
||||
@@ -103,3 +103,80 @@ Describe "Get-Command Feature tests" -Tag Feature {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Describe "Get-Command" -Tag CI {
|
||||
BeforeAll {
|
||||
Import-Module Microsoft.PowerShell.Management
|
||||
}
|
||||
Context "-Syntax tests" {
|
||||
It "Should return a string object when -Name is an alias and -Syntax is specified" {
|
||||
$Result = Get-Command -Name del -Syntax
|
||||
|
||||
$Result | Should -BeOfType [String]
|
||||
$Result | Should -Match 'del \[-Path\]'
|
||||
}
|
||||
|
||||
It "Should replace commands with aliases in matching commands when using a wildcard search" {
|
||||
$Result = Get-Command -Name sp* -Syntax
|
||||
|
||||
$Result | Should -BeOfType [String]
|
||||
$Result -join '' | Should -Match 'sp \(alias\) -> Set-ItemProperty'
|
||||
$Result -join '' | Should -Match 'sp \[-Path\]'
|
||||
}
|
||||
|
||||
It "Should not add the alias (alias) -> command decorator for non-alias commands" {
|
||||
$Result = Get-Command -Name sp* -Syntax
|
||||
|
||||
$Result -join '' | Should -Not -Match 'Split-Path \(alias\) -> Split-Path'
|
||||
$Result -join '' | Should -Match 'Split-Path \[-Path\]'
|
||||
}
|
||||
|
||||
It "Should only replace aliases when given multiple entries including a command and an alias" {
|
||||
$Result = Get-Command -Name get-help, del -Syntax
|
||||
|
||||
$Result -join '' | Should -Match 'del \(alias\) -> Remove-Item'
|
||||
$Result -join '' | Should -Match 'del \[-Path\]'
|
||||
$Result -join '' | Should -Match 'Get-Help \[\[-Name\]'
|
||||
$Result -join '' | Should -Not -Match 'del \(alias\) -> Get-Help'
|
||||
}
|
||||
|
||||
It "Should return the path to an aliased script when -Syntax is specified" {
|
||||
# First, create a script file
|
||||
$TestGcmSyntax = @'
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Position=0, Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
[string[]]
|
||||
$Name
|
||||
)
|
||||
process {
|
||||
"Processing ${Name}"
|
||||
}
|
||||
'@
|
||||
Set-Content -Path TestDrive:\Test-GcmSyntax.ps1 -Value $TestGcmSyntax
|
||||
|
||||
# Now set up an alias for that file
|
||||
New-Alias -Name tgs -Value TestDrive:\Test-GcmSyntax.ps1
|
||||
|
||||
$Result = Get-Command -Name tgs -Syntax
|
||||
|
||||
$Result | Should -Match "tgs \(alias\) -> $([Regex]::Escape((Get-Item TestDrive:\\Test-GcmSyntax.ps1).FullName))"
|
||||
}
|
||||
}
|
||||
|
||||
Context "-Name tests" {
|
||||
It "Should return a AliasInfo object when -Name is an alias" {
|
||||
$Result = Get-Command -Name del
|
||||
|
||||
$Result | Should -BeOfType [System.Management.Automation.AliasInfo]
|
||||
$Result.DisplayName | Should -Be 'del -> Remove-Item'
|
||||
}
|
||||
|
||||
It "Should return a CommandInfo object when -Name is a command" {
|
||||
$Result = Get-Command -Name Remove-Item
|
||||
|
||||
$Result | Should -BeOfType [System.Management.Automation.CommandInfo]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user