Browse Source

fix: write why Test-Path2 returns false for a path that is not valid

Since this branch, Test-Path2 writes $false for a path that Windows
PowerShell rejects, such as one with a |, but it didn't say why. It now
writes the reason as a debug message. Only the lookup of the item is in
the try block, so that an error elsewhere in the cmdlet can't turn into
$false.

Found by the security review of fcb370e..00c3646 (finding 4).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
ai/release-5.0.0-rc6
Raimund Andree 4 days ago
parent
commit
b241441c68
  1. 3
      CHANGELOG.md
  2. 2
      Docs/Cmdlets/Test-Path2.md
  3. 45
      NTFSSecurity/PathCmdlets/TestPath2.cs
  4. 2
      NTFSSecurity/en-US/NTFSSecurity.dll-Help.xml
  5. 16
      Tests/ItemCmdlets.Tests.ps1

3
CHANGELOG.md

@ -272,7 +272,8 @@ The format is based on
- Fix `Test-Path2`, which stopped with the terminating error "Illegal
characters in path" in Windows PowerShell for a path with a character
that Windows doesn't allow in names, such as `|`; it now returns `$false`
for such a path, as in PowerShell 7
for such a path, as in PowerShell 7, and writes the reason as a debug
message
- Fix the cmdlets that enable the Backup, Restore, Take Ownership, and
Security privileges, which left them enabled in the session when a later
command, such as `Select-Object -First`, or a terminating error stopped

2
Docs/Cmdlets/Test-Path2.md

@ -117,7 +117,7 @@ For each path, the cmdlet writes `$true` when the item exists and matches `-Path
The cmdlet resolves paths through the AlphaFS library, which is not bound by the 260-character `MAX_PATH` limit of the Windows PowerShell file system provider. Use `Test-Path2` instead of `Test-Path` when a path can be longer than that limit.
A path that does not exist is not an error condition. The cmdlet writes `$false` and continues with the next path. This also applies to a path with a character that Windows doesn't allow in names, such as `|` or `<`; before 5.0.0, such a path stopped the cmdlet with the terminating error "Illegal characters in path" in Windows PowerShell.
A path that does not exist is not an error condition. The cmdlet writes `$false` and continues with the next path. This also applies to a path with a character that Windows doesn't allow in names, such as `|` or `<`; Windows PowerShell rejects such a path, and the cmdlet writes the reason as a debug message. Before 5.0.0, such a path stopped the cmdlet with the terminating error "Illegal characters in path" in Windows PowerShell.
## RELATED LINKS

45
NTFSSecurity/PathCmdlets/TestPath2.cs

@ -45,42 +45,51 @@ namespace NTFSSecurity
{
foreach (var path in paths)
{
FileSystemInfo item = null;
try
{
FileSystemInfo item;
TryGetFileSystemInfo2(path, out item);
if (item == null)
WriteObject(false);
else
{
if (PathType == TestPathType.Any)
WriteObject(true);
else if (PathType == TestPathType.Container & item is DirectoryInfo)
WriteObject(true);
else if (PathType == TestPathType.Leaf & item is FileInfo)
WriteObject(true);
else
WriteObject(false);
}
}
catch (System.IO.FileNotFoundException ex)
{
WriteError(new ErrorRecord(ex, "PathNotFound", ErrorCategory.ObjectNotFound, path));
continue;
}
// In Windows PowerShell, .NET rejects a path with a character that Windows doesn't allow in names.
// Such an item can't exist, so the cmdlet writes $false, as in PowerShell 7 and like Test-Path.
catch (System.ArgumentException)
catch (System.ArgumentException ex)
{
WriteObject(false);
WriteInvalidPath(path, ex);
continue;
}
catch (System.NotSupportedException)
catch (System.NotSupportedException ex)
{
WriteInvalidPath(path, ex);
continue;
}
if (item == null)
WriteObject(false);
else
{
if (PathType == TestPathType.Any)
WriteObject(true);
else if (PathType == TestPathType.Container & item is DirectoryInfo)
WriteObject(true);
else if (PathType == TestPathType.Leaf & item is FileInfo)
WriteObject(true);
else
WriteObject(false);
}
}
}
private void WriteInvalidPath(string path, System.Exception exception)
{
WriteDebug(string.Format("'{0}' is not a valid path: {1}", path, exception.Message));
WriteObject(false);
}
protected override void EndProcessing()
{
base.EndProcessing();

2
NTFSSecurity/en-US/NTFSSecurity.dll-Help.xml

@ -10136,7 +10136,7 @@ PS C:\&gt; Set-NTFSSecurityDescriptor -SecurityDescriptor $sd</dev:code>
<maml:alertSet>
<maml:alert>
<maml:para>The cmdlet resolves paths through the AlphaFS library, which is not bound by the 260-character `MAX_PATH` limit of the Windows PowerShell file system provider. Use `Test-Path2` instead of `Test-Path` when a path can be longer than that limit.</maml:para>
<maml:para>A path that does not exist is not an error condition. The cmdlet writes `$false` and continues with the next path. This also applies to a path with a character that Windows doesn't allow in names, such as `|` or `&lt;`; before 5.0.0, such a path stopped the cmdlet with the terminating error "Illegal characters in path" in Windows PowerShell.</maml:para>
<maml:para>A path that does not exist is not an error condition. The cmdlet writes `$false` and continues with the next path. This also applies to a path with a character that Windows doesn't allow in names, such as `|` or `&lt;`; Windows PowerShell rejects such a path, and the cmdlet writes the reason as a debug message. Before 5.0.0, such a path stopped the cmdlet with the terminating error "Illegal characters in path" in Windows PowerShell.</maml:para>
</maml:alert>
</maml:alertSet>
<command:examples>

16
Tests/ItemCmdlets.Tests.ps1

@ -319,6 +319,22 @@ Describe 'Test-Path2' {
$testErrors | Should -BeNullOrEmpty
$result -join ',' | Should -Be 'False,True'
}
# PowerShell 7 accepts these characters and finds no item, so only Windows PowerShell rejects the path. Before
# 5.0.0-rc6, the cmdlet wrote $false for a rejected path without saying why. -Debug would prompt in Windows
# PowerShell, so the test sets the preference.
It 'Should say in a debug message why it writes $false for a path that Windows PowerShell rejects' -Skip:($PSVersionTable.PSEdition -ne 'Desktop') {
$invalid = Join-Path -Path $folder -ChildPath 'a|b'
$DebugPreference = 'Continue'
$output = @(Test-Path2 -Path $invalid -ErrorAction Stop 5>&1)
$messages = @($output | Where-Object -FilterScript { $_ -is [Management.Automation.DebugRecord] } |
Where-Object -Property Message -Like -Value '*is not a valid path*')
$messages | Should -HaveCount 1
$messages[0].Message.Contains("'$invalid'") | Should -BeTrue
$output | Where-Object -FilterScript { $_ -is [bool] } | Should -BeFalse
}
}
Describe 'Get-DiskSpace' {

Loading…
Cancel
Save