Fix share completion with provider and spaces (#19440)

This commit is contained in:
MartinGC94
2025-02-25 12:02:56 +05:00
committed by GitHub
parent a23e30bed3
commit d6b5e5e13c
2 changed files with 37 additions and 9 deletions
@@ -4478,14 +4478,15 @@ namespace System.Management.Automation
var wordToComplete = context.WordToComplete;
var quote = HandleDoubleAndSingleQuote(ref wordToComplete);
// First, try to match \\server\share
// support both / and \ when entering UNC paths for typing convenience (#17111)
var shareMatch = Regex.Match(wordToComplete, @"^(?:\\\\|//)([^\\/]+)(?:\\|/)([^\\/]*)$");
// Matches file shares with and without the provider name and with either slash direction.
// Avoids matching Windows device paths like \\.\CDROM0 and \\?\Volume{b8f3fc1c-5cd6-4553-91e2-d6814c4cd375}\
var shareMatch = s_shareMatch.Match(wordToComplete);
if (shareMatch.Success)
{
// Only match share names, no filenames.
var server = shareMatch.Groups[1].Value;
var sharePattern = WildcardPattern.Get(shareMatch.Groups[2].Value + "*", WildcardOptions.IgnoreCase);
var provider = shareMatch.Groups[1].Value;
var server = shareMatch.Groups[2].Value;
var sharePattern = WildcardPattern.Get(shareMatch.Groups[3].Value + "*", WildcardOptions.IgnoreCase);
var ignoreHidden = context.GetOption("IgnoreHiddenShares", @default: false);
var shares = GetFileShares(server, ignoreHidden);
if (shares.Count == 0)
@@ -4498,13 +4499,20 @@ namespace System.Management.Automation
{
if (sharePattern.IsMatch(share))
{
string shareFullPath = "\\\\" + server + "\\" + share;
if (quote != string.Empty)
string sharePath = $"\\\\{server}\\{share}";
string completionText;
if (quote == string.Empty)
{
shareFullPath = quote + shareFullPath + quote;
completionText = share.Contains(' ')
? $"'{provider}{sharePath}'"
: $"{provider}{sharePath}";
}
else
{
completionText = $"{quote}{provider}{sharePath}{quote}";
}
shareResults.Add(new CompletionResult(shareFullPath, shareFullPath, CompletionResultType.ProviderContainer, shareFullPath));
shareResults.Add(new CompletionResult(completionText, share, CompletionResultType.ProviderContainer, sharePath));
}
}
@@ -5155,6 +5163,10 @@ namespace System.Management.Automation
return result;
}
private static readonly Regex s_shareMatch = new(
@"(^Microsoft\.PowerShell\.Core\\FileSystem::|^FileSystem::|^)(?:\\\\|//)(?![.|?])([^\\/]+)(?:\\|/)([^\\/]*)$",
RegexOptions.IgnoreCase | RegexOptions.Compiled);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private struct SHARE_INFO_1
{
@@ -1931,6 +1931,10 @@ class InheritedClassTest : System.Attribute
$res.CompletionMatches[0].CompletionText | Should -BeExactly $afterTab
}
It "Tab completion UNC path with filesystem provider" -Skip:(!$IsWindows) {
$res = TabExpansion2 -inputScript 'Filesystem::\\localhost\admin'
$res.CompletionMatches[0].CompletionText | Should -BeExactly 'Filesystem::\\localhost\ADMIN$'
}
It "Tab completion for registry" -Skip:(!$IsWindows) {
$beforeTab = 'registry::HKEY_l'
@@ -3115,6 +3119,18 @@ function MyFunction ($param1, $param2)
}
}
Describe "TabCompletion elevated tests" -Tags CI, RequireAdminOnWindows {
It "Tab completion UNC path with spaces" -Skip:(!$IsWindows) {
$Share = New-SmbShare -Temporary -ReadAccess (whoami.exe) -Path C:\ -Name "Test Share"
$res = TabExpansion2 -inputScript '\\localhost\test'
$res.CompletionMatches[0].CompletionText | Should -BeExactly "& '\\localhost\Test Share'"
if ($null -ne $Share)
{
Remove-SmbShare -InputObject $Share -Force -Confirm:$false
}
}
}
Describe "Tab completion tests with remote Runspace" -Tags Feature,RequireAdminOnWindows {
BeforeAll {
$skipTest = -not $IsWindows