Browse Source

fix: return the file when Get-ChildItem2 gets a file path

Defect 2. Get-ChildItem2 cast every -Path item to DirectoryInfo, so a file
path stopped the cmdlet with an InvalidCastException, a terminating error
that also skipped the remaining paths. Like Get-ChildItem, a file path now
returns the file itself, filtered like the other items; with -Directory it
returns nothing.

Tests/ItemCmdlets.Tests.ps1 (new): 3 tests.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
pull/100/head
Raimund Andree 1 week ago
parent
commit
d2c3d04b07
  1. 2
      CHANGELOG.md
  2. 4
      Docs/Cmdlets/Get-ChildItem2.md
  3. 16
      NTFSSecurity/ItemCmdlets/GetChildItem2.cs
  4. 5
      NTFSSecurity/en-US/NTFSSecurity.dll-Help.xml
  5. 57
      Tests/ItemCmdlets.Tests.ps1

2
CHANGELOG.md

@ -55,5 +55,7 @@ The format is based on
- Fix `Set-NTFSInheritance`, which failed with "Nullable object must have a
value" when `-AccessInheritanceEnabled` or `-AuditInheritanceEnabled` was
omitted; an omitted parameter now leaves its section unchanged
- Fix `Get-ChildItem2`, which stopped with an `InvalidCastException` when
`-Path` pointed to a file; it now returns the file, like `Get-ChildItem`
[Unreleased]: https://github.com/raandree/NTFSSecurity/compare/4.2.6...HEAD

4
Docs/Cmdlets/Get-ChildItem2.md

@ -182,7 +182,7 @@ Accept wildcard characters: False
### -Path
Specifies the folders whose content you want to list. Relative paths are resolved against the current location, and wildcard characters are not supported. If you omit this parameter, the cmdlet lists the current location. A value that points to a file instead of a folder produces an error.
Specifies the folders whose content you want to list. Relative paths are resolved against the current location, and wildcard characters are not supported. If you omit this parameter, the cmdlet lists the current location. A value that points to a file returns that file, like `Get-ChildItem`, unless you use `-Directory`.
```yaml
Type: String[]
@ -305,6 +305,8 @@ The `PrivateData` section of the module manifest `NTFSSecurity.psd1` contains tw
A folder that cannot be read produces a non-terminating error with the ID `DirUnauthorizedAccessError` for an access denial or `DirUnspecifiedError` for any other failure, and a path that does not exist produces the error `FileNotFound`. In each case the cmdlet continues with the next path. Failures that occur while `-Recurse` collects the subfolders of a folder are reported as verbose messages only, not as errors.
Before 5.0.0, a `-Path` value that points to a file stopped the cmdlet with an `InvalidCastException`.
## RELATED LINKS
[Get-Item2](Get-Item2.md)

16
NTFSSecurity/ItemCmdlets/GetChildItem2.cs

@ -148,12 +148,11 @@ namespace NTFSSecurity
{
foreach (var path in paths)
{
DirectoryInfo di = null;
FileSystemInfo item = null;
try
{
di = (DirectoryInfo)GetFileSystemInfo2(path);
item = GetFileSystemInfo2(path);
}
catch (System.IO.FileNotFoundException ex)
{
@ -161,6 +160,17 @@ namespace NTFSSecurity
continue;
}
var di = item as DirectoryInfo;
if (di == null)
{
// Like Get-ChildItem, a file path returns the file itself.
if (!directory)
{
WriteFileSystemInfoCollection(new FileSystemInfo[] { item }.GetEnumerator());
}
continue;
}
try
{
WriteFileSystem(di, 0);

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

@ -3482,7 +3482,7 @@ PS C:\&gt; Disable-Privileges</dev:code>
<command:parameter required="false" variableLength="true" globbing="false" pipelineInput="True (ByPropertyName, ByValue)" position="1" aliases="FullName">
<maml:name>Path</maml:name>
<maml:description>
<maml:para>Specifies the folders whose content you want to list. Relative paths are resolved against the current location, and wildcard characters are not supported. If you omit this parameter, the cmdlet lists the current location. A value that points to a file instead of a folder produces an error.</maml:para>
<maml:para>Specifies the folders whose content you want to list. Relative paths are resolved against the current location, and wildcard characters are not supported. If you omit this parameter, the cmdlet lists the current location. A value that points to a file returns that file, like `Get-ChildItem`, unless you use `-Directory`.</maml:para>
</maml:description>
<command:parameterValue required="true" variableLength="false">String[]</command:parameterValue>
<dev:type>
@ -3734,7 +3734,7 @@ PS C:\&gt; Disable-Privileges</dev:code>
<command:parameter required="false" variableLength="true" globbing="false" pipelineInput="True (ByPropertyName, ByValue)" position="1" aliases="FullName">
<maml:name>Path</maml:name>
<maml:description>
<maml:para>Specifies the folders whose content you want to list. Relative paths are resolved against the current location, and wildcard characters are not supported. If you omit this parameter, the cmdlet lists the current location. A value that points to a file instead of a folder produces an error.</maml:para>
<maml:para>Specifies the folders whose content you want to list. Relative paths are resolved against the current location, and wildcard characters are not supported. If you omit this parameter, the cmdlet lists the current location. A value that points to a file returns that file, like `Get-ChildItem`, unless you use `-Directory`.</maml:para>
</maml:description>
<command:parameterValue required="true" variableLength="false">String[]</command:parameterValue>
<dev:type>
@ -3838,6 +3838,7 @@ PS C:\&gt; Disable-Privileges</dev:code>
<maml:para>The module defines the alias `dir2` for this cmdlet.</maml:para>
<maml:para>The `PrivateData` section of the module manifest `NTFSSecurity.psd1` contains two settings that this cmdlet reads when it starts. `GetFileSystemModeProperty` adds the calculated `Mode` property to every item. `IdentifyHardLinks` adds the `HardLinkCount` property to every file, which requires an extra call into the file system for each file and therefore slows down large listings noticeably. Set either value to `$false` in the manifest and import the module again if you prefer the faster enumeration over the additional properties.</maml:para>
<maml:para>A folder that cannot be read produces a non-terminating error with the ID `DirUnauthorizedAccessError` for an access denial or `DirUnspecifiedError` for any other failure, and a path that does not exist produces the error `FileNotFound`. In each case the cmdlet continues with the next path. Failures that occur while `-Recurse` collects the subfolders of a folder are reported as verbose messages only, not as errors.</maml:para>
<maml:para>Before 5.0.0, a `-Path` value that points to a file stopped the cmdlet with an `InvalidCastException`.</maml:para>
</maml:alert>
</maml:alertSet>
<command:examples>

57
Tests/ItemCmdlets.Tests.ps1

@ -0,0 +1,57 @@
<#
Tests the long-path item cmdlets of the module built in NTFSSecurity\bin\Release on files in a sandbox folder.
#>
[Diagnostics.CodeAnalysis.SuppressMessageAttribute(
'PSUseDeclaredVarsMoreThanAssignments', '', Justification = 'Pester shares variables between blocks.'
)]
param ()
BeforeAll {
Import-Module -Name (Join-Path -Path $PSScriptRoot -ChildPath 'TestHelpers.psm1') -Force
$modulePath = Join-Path -Path $PSScriptRoot -ChildPath '..\NTFSSecurity\bin\Release\NTFSSecurity.psd1'
Import-Module -Name $modulePath -Force -ErrorAction Stop
$sandbox = New-TestSandbox -Name 'ItemCmdlets'
Push-Location -LiteralPath $sandbox
}
AfterAll {
Pop-Location
Remove-TestSandbox -Sandbox $sandbox
Remove-Module -Name NTFSSecurity -Force -ErrorAction SilentlyContinue
}
Describe 'Get-ChildItem2' {
Context 'When -Path is a file' {
BeforeAll {
$folder = Join-Path -Path $sandbox -ChildPath 'ChildItem'
$file = Join-Path -Path $folder -ChildPath 'File.txt'
$other = Join-Path -Path $folder -ChildPath 'Folder\Other.txt'
Assert-TestSandboxPath -Sandbox $sandbox -Path $folder, $file, $other
New-Item -ItemType Directory -Path (Split-Path -Path $other -Parent) -Force | Out-Null
Set-Content -LiteralPath $file -Value 'File'
Set-Content -LiteralPath $other -Value 'Other'
}
It 'Should return the file itself, like Get-ChildItem' {
$items = @(Get-ChildItem2 -Path $file -ErrorVariable childItemErrors -ErrorAction SilentlyContinue)
$childItemErrors | Should -BeNullOrEmpty
$items | Should -HaveCount 1
$items[0] | Should -BeOfType [Alphaleonis.Win32.Filesystem.FileInfo]
$items[0].Name | Should -BeExactly 'File.txt'
}
It 'Should continue with the next path after a file' {
$items = @(Get-ChildItem2 -Path $file, (Join-Path -Path $folder -ChildPath 'Folder') -ErrorAction SilentlyContinue)
$items.Name | Should -Be @('File.txt', 'Other.txt')
}
It 'Should return nothing for a file with -Directory' {
$items = @(Get-ChildItem2 -Path $file -Directory -ErrorVariable childItemErrors -ErrorAction SilentlyContinue)
$childItemErrors | Should -BeNullOrEmpty
$items | Should -BeNullOrEmpty
}
}
}
Loading…
Cancel
Save