mirror of
https://github.com/PowerShell/PowerShell
synced 2026-06-08 12:12:50 +00:00
Add -PropertyType argument completer for New-ItemProperty (#21117)
This commit is contained in:
+121
@@ -1,7 +1,11 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Management.Automation;
|
||||
using System.Management.Automation.Language;
|
||||
|
||||
namespace Microsoft.PowerShell.Commands
|
||||
{
|
||||
@@ -63,6 +67,9 @@ namespace Microsoft.PowerShell.Commands
|
||||
/// </summary>
|
||||
[Parameter(ValueFromPipelineByPropertyName = true)]
|
||||
[Alias("Type")]
|
||||
#if !UNIX
|
||||
[ArgumentCompleter(typeof(PropertyTypeArgumentCompleter))]
|
||||
#endif
|
||||
public string PropertyType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
@@ -175,4 +182,118 @@ namespace Microsoft.PowerShell.Commands
|
||||
#endregion Command code
|
||||
|
||||
}
|
||||
|
||||
#if !UNIX
|
||||
/// <summary>
|
||||
/// Provides argument completion for PropertyType parameter.
|
||||
/// </summary>
|
||||
public class PropertyTypeArgumentCompleter : IArgumentCompleter
|
||||
{
|
||||
private static readonly string[] s_RegistryPropertyTypes = new string[]
|
||||
{
|
||||
"String",
|
||||
"ExpandString",
|
||||
"Binary",
|
||||
"DWord",
|
||||
"MultiString",
|
||||
"QWord",
|
||||
"Unknown"
|
||||
};
|
||||
|
||||
private static string GetRegistryPropertyTypeToolTip(string propertyTypeName) => propertyTypeName switch
|
||||
{
|
||||
"String" => TabCompletionStrings.RegistryStringToolTip,
|
||||
"ExpandString" => TabCompletionStrings.RegistryExpandStringToolTip,
|
||||
"Binary" => TabCompletionStrings.RegistryBinaryToolTip,
|
||||
"DWord" => TabCompletionStrings.RegistryDWordToolTip,
|
||||
"MultiString" => TabCompletionStrings.RegistryMultiStringToolTip,
|
||||
"QWord" => TabCompletionStrings.RegistryQWordToolTip,
|
||||
_ => TabCompletionStrings.RegistryUnknownToolTip
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Returns completion results for PropertyType parameter.
|
||||
/// </summary>
|
||||
/// <param name="commandName">The command name.</param>
|
||||
/// <param name="parameterName">The parameter name.</param>
|
||||
/// <param name="wordToComplete">The word to complete.</param>
|
||||
/// <param name="commandAst">The command AST.</param>
|
||||
/// <param name="fakeBoundParameters">The fake bound parameters.</param>
|
||||
/// <returns>List of Completion Results.</returns>
|
||||
public IEnumerable<CompletionResult> CompleteArgument(
|
||||
string commandName,
|
||||
string parameterName,
|
||||
string wordToComplete,
|
||||
CommandAst commandAst,
|
||||
IDictionary fakeBoundParameters)
|
||||
{
|
||||
if (!IsRegistryProvider(fakeBoundParameters))
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
string quote = CompletionCompleters.HandleDoubleAndSingleQuote(ref wordToComplete);
|
||||
var propertyTypePattern = WildcardPattern.Get(wordToComplete + "*", WildcardOptions.IgnoreCase);
|
||||
|
||||
foreach (string propertyType in s_RegistryPropertyTypes)
|
||||
{
|
||||
if (propertyTypePattern.IsMatch(propertyType))
|
||||
{
|
||||
string completionText = quote == string.Empty
|
||||
? propertyType
|
||||
: quote + propertyType + quote;
|
||||
|
||||
yield return new CompletionResult(
|
||||
completionText,
|
||||
propertyType,
|
||||
CompletionResultType.ParameterValue,
|
||||
GetRegistryPropertyTypeToolTip(propertyType));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if parameter paths are from Registry provider.
|
||||
/// </summary>
|
||||
/// <param name="fakeBoundParameters">The fake bound parameters.</param>
|
||||
/// <returns>Boolean indicating if paths are from Registry Provider.</returns>
|
||||
private static bool IsRegistryProvider(IDictionary fakeBoundParameters)
|
||||
{
|
||||
Collection<PathInfo> paths;
|
||||
|
||||
if (fakeBoundParameters.Contains("Path"))
|
||||
{
|
||||
paths = ResolvePath(fakeBoundParameters["Path"], isLiteralPath: false);
|
||||
}
|
||||
else if (fakeBoundParameters.Contains("LiteralPath"))
|
||||
{
|
||||
paths = ResolvePath(fakeBoundParameters["LiteralPath"], isLiteralPath: true);
|
||||
}
|
||||
else
|
||||
{
|
||||
paths = ResolvePath(@".\", isLiteralPath: false);
|
||||
}
|
||||
|
||||
return paths.Count > 0 && paths[0].Provider.NameEquals("Registry");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resolve path or literal path using Resolve-Path.
|
||||
/// </summary>
|
||||
/// <param name="path">The path to resolve.</param>
|
||||
/// <param name="isLiteralPath">Specifies if path is literal path.</param>
|
||||
/// <returns>Collection of Pathinfo objects.</returns>
|
||||
private static Collection<PathInfo> ResolvePath(object path, bool isLiteralPath)
|
||||
{
|
||||
using var ps = System.Management.Automation.PowerShell.Create(RunspaceMode.CurrentRunspace);
|
||||
|
||||
ps.AddCommand("Microsoft.PowerShell.Management\\Resolve-Path");
|
||||
ps.AddParameter(isLiteralPath ? "LiteralPath" : "Path", path);
|
||||
|
||||
Collection<PathInfo> output = ps.Invoke<PathInfo>();
|
||||
|
||||
return output;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -353,4 +353,25 @@ using namespace <AliasName> = <.NET-namespace></value>
|
||||
|
||||
using type <AliasName> = <.NET-type></value>
|
||||
</data>
|
||||
<data name="RegistryStringToolTip" xml:space="preserve">
|
||||
<value>A normal string.</value>
|
||||
</data>
|
||||
<data name="RegistryExpandStringToolTip" xml:space="preserve">
|
||||
<value>A string that contains unexpanded references to environment variables that are expanded when the value is retrieved.</value>
|
||||
</data>
|
||||
<data name="RegistryBinaryToolTip" xml:space="preserve">
|
||||
<value>Binary data in any form.</value>
|
||||
</data>
|
||||
<data name="RegistryDWordToolTip" xml:space="preserve">
|
||||
<value>A 32-bit binary number.</value>
|
||||
</data>
|
||||
<data name="RegistryMultiStringToolTip" xml:space="preserve">
|
||||
<value>An array of strings.</value>
|
||||
</data>
|
||||
<data name="RegistryQWordToolTip" xml:space="preserve">
|
||||
<value>A 64-bit binary number.</value>
|
||||
</data>
|
||||
<data name="RegistryUnknownToolTip" xml:space="preserve">
|
||||
<value>An unsupported registry data type.</value>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -931,6 +931,87 @@ ConstructorTestClass(int i, bool b)
|
||||
}
|
||||
}
|
||||
|
||||
Context 'New-ItemProperty -PropertyType parameter completion' {
|
||||
BeforeAll {
|
||||
if ($IsWindows) {
|
||||
$allRegistryValueKinds = 'String ExpandString Binary DWord MultiString QWord Unknown'
|
||||
$allRegistryValueKindsWithQuotes = "'String' 'ExpandString' 'Binary' 'DWord' 'MultiString' 'QWord' 'Unknown'"
|
||||
$dwordValueKind = 'DWord'
|
||||
$qwordValueKind = 'QWord'
|
||||
$binaryValueKind = 'Binary'
|
||||
$multiStringValueKind = 'MultiString'
|
||||
$registryPath = "HKCU:\test1\sub"
|
||||
New-Item -Path $registryPath -Force
|
||||
$registryLiteralPath = "HKCU:\test2\*\sub"
|
||||
New-Item -Path $registryLiteralPath -Force
|
||||
$fileSystemPath = "TestDrive:\test1.txt"
|
||||
New-Item -Path $fileSystemPath -Force
|
||||
$fileSystemLiteralPathDir = "TestDrive:\[]"
|
||||
$fileSystemLiteralPath = "$fileSystemLiteralPathDir\test2.txt"
|
||||
New-Item -Path $fileSystemLiteralPath -Force
|
||||
}
|
||||
}
|
||||
|
||||
It "Should complete Property Type for '<TextInput>'" -Skip:(!$IsWindows) -TestCases @(
|
||||
# -Path completions
|
||||
@{ TextInput = "New-ItemProperty -Path $registryPath -PropertyType "; ExpectedPropertyTypes = $allRegistryValueKinds }
|
||||
@{ TextInput = "New-ItemProperty -Path $registryPath -PropertyType d"; ExpectedPropertyTypes = $dwordValueKind }
|
||||
@{ TextInput = "New-ItemProperty -Path $registryPath -PropertyType q"; ExpectedPropertyTypes = $qwordValueKind }
|
||||
@{ TextInput = "New-ItemProperty -Path $registryPath -PropertyType bin"; ExpectedPropertyTypes = $binaryValueKind }
|
||||
@{ TextInput = "New-ItemProperty -Path $registryPath -PropertyType multi"; ExpectedPropertyTypes = $multiStringValueKind }
|
||||
@{ TextInput = "New-ItemProperty -Path $registryPath -PropertyType invalidproptype"; ExpectedPropertyTypes = '' }
|
||||
@{ TextInput = "New-ItemProperty -Path $fileSystemPath -PropertyType "; ExpectedPropertyTypes = '' }
|
||||
|
||||
# -LiteralPath completions
|
||||
@{ TextInput = "New-ItemProperty -LiteralPath $registryLiteralPath -PropertyType "; ExpectedPropertyTypes = $allRegistryValueKinds }
|
||||
@{ TextInput = "New-ItemProperty -LiteralPath $registryLiteralPath -PropertyType d"; ExpectedPropertyTypes = $dwordValueKind }
|
||||
@{ TextInput = "New-ItemProperty -LiteralPath $registryLiteralPath -PropertyType q"; ExpectedPropertyTypes = $qwordValueKind }
|
||||
@{ TextInput = "New-ItemProperty -LiteralPath $registryLiteralPath -PropertyType bin"; ExpectedPropertyTypes = $binaryValueKind }
|
||||
@{ TextInput = "New-ItemProperty -LiteralPath $registryLiteralPath -PropertyType multi"; ExpectedPropertyTypes = $multiStringValueKind }
|
||||
@{ TextInput = "New-ItemProperty -LiteralPath $registryLiteralPath -PropertyType invalidproptype"; ExpectedPropertyTypes = '' }
|
||||
@{ TextInput = "New-ItemProperty -LiteralPath $fileSystemLiteralPath -PropertyType "; ExpectedPropertyTypes = '' }
|
||||
|
||||
# All of these should return no completion since they don't specify -Path/-LiteralPath
|
||||
@{ TextInput = "New-ItemProperty -PropertyType "; ExpectedPropertyTypes = '' }
|
||||
@{ TextInput = "New-ItemProperty -PropertyType d"; ExpectedPropertyTypes = '' }
|
||||
@{ TextInput = "New-ItemProperty -PropertyType q"; ExpectedPropertyTypes = '' }
|
||||
@{ TextInput = "New-ItemProperty -PropertyType bin"; ExpectedPropertyTypes = '' }
|
||||
@{ TextInput = "New-ItemProperty -PropertyType multi"; ExpectedPropertyTypes = '' }
|
||||
@{ TextInput = "New-ItemProperty -PropertyType invalidproptype"; ExpectedPropertyTypes = '' }
|
||||
|
||||
# All of these should return completion even with quotes included
|
||||
@{ TextInput = "New-ItemProperty -Path $registryPath -PropertyType '"; ExpectedPropertyTypes = $allRegistryValueKindsWithQuotes }
|
||||
@{ TextInput = "New-ItemProperty -Path $registryPath -PropertyType 'bin"; ExpectedPropertyTypes = "'$binaryValueKind'" }
|
||||
) {
|
||||
param($TextInput, $ExpectedPropertyTypes)
|
||||
$res = TabExpansion2 -inputScript $TextInput -cursorColumn $TextInput.Length
|
||||
$completionText = $res.CompletionMatches.CompletionText
|
||||
$completionText -join ' ' | Should -BeExactly $ExpectedPropertyTypes
|
||||
}
|
||||
|
||||
It "Test fallback to provider of current location if no path specified" -Skip:(!$IsWindows) {
|
||||
try {
|
||||
Push-Location HKCU:\
|
||||
$textInput = "New-ItemProperty -PropertyType "
|
||||
$res = TabExpansion2 -inputScript $textInput -cursorColumn $textInput.Length
|
||||
$completionText = $res.CompletionMatches.CompletionText
|
||||
$completionText -join ' ' | Should -BeExactly $allRegistryValueKinds
|
||||
}
|
||||
finally {
|
||||
Pop-Location
|
||||
}
|
||||
}
|
||||
|
||||
AfterAll {
|
||||
if ($IsWindows) {
|
||||
Remove-Item -Path $registryPath -Force
|
||||
Remove-Item -LiteralPath $registryLiteralPath -Force
|
||||
Remove-Item -Path $fileSystemPath -Force
|
||||
Remove-Item -LiteralPath $fileSystemLiteralPathDir -Recurse -Force
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Context "Format cmdlet's View paramter completion" {
|
||||
BeforeAll {
|
||||
$viewDefinition = @'
|
||||
|
||||
Reference in New Issue
Block a user