diff --git a/.memory-bank/progress.md b/.memory-bank/progress.md index 39e21ef..51331ec 100644 --- a/.memory-bank/progress.md +++ b/.memory-bank/progress.md @@ -182,8 +182,9 @@ Numbered as agreed with the maintainer; each is documented on its page. #### Issue triage (fixes on `ai/issue-fixes`, not merged) -- Fixed: #3 (braces in a path), #86 (`$PWD` shadowed), #88 (an object - passed by position); `Docs/FAQ.md` answers the recurring questions. +- Fixed: #3 (braces in a path), #86 (`$PWD` shadowed, also for the default + location of nine cmdlets, found by the review), #88 (an object passed by + position); `Docs/FAQ.md` answers the recurring questions. - Open bugs: #5 (`-Attributes` matches all, `Get-ChildItem` any; needs a decision), #17 (`GenericAll`), #34 and #67 (writes owner and group), #41 (drive root), #82 (`Size` type data), #90 (trailing space). diff --git a/NTFSSecurity/AccessCmdlets/GetAccess.cs b/NTFSSecurity/AccessCmdlets/GetAccess.cs index 1239306..95af170 100644 --- a/NTFSSecurity/AccessCmdlets/GetAccess.cs +++ b/NTFSSecurity/AccessCmdlets/GetAccess.cs @@ -74,7 +74,7 @@ namespace NTFSSecurity if (paths.Count == 0) { - paths = new List() { GetVariableValue("PWD").ToString() }; + paths = new List() { GetCurrentLocation() }; } } diff --git a/NTFSSecurity/AccessCmdlets/GetEffectiveAccess.cs b/NTFSSecurity/AccessCmdlets/GetEffectiveAccess.cs index 96eb1db..1e63063 100644 --- a/NTFSSecurity/AccessCmdlets/GetEffectiveAccess.cs +++ b/NTFSSecurity/AccessCmdlets/GetEffectiveAccess.cs @@ -109,7 +109,7 @@ namespace NTFSSecurity } // Like the other cmdlets, use the current location when -Path is omitted. - var targets = paths.Count > 0 ? paths : new List() { GetVariableValue("PWD").ToString() }; + var targets = paths.Count > 0 ? paths : new List() { GetCurrentLocation() }; foreach (var path in targets) { diff --git a/NTFSSecurity/AuditCmdlets/GetAudit.cs b/NTFSSecurity/AuditCmdlets/GetAudit.cs index 3c6c58c..fabe976 100644 --- a/NTFSSecurity/AuditCmdlets/GetAudit.cs +++ b/NTFSSecurity/AuditCmdlets/GetAudit.cs @@ -74,7 +74,7 @@ namespace NTFSSecurity if (paths.Count == 0) { - paths = new List() { GetVariableValue("PWD").ToString() }; + paths = new List() { GetCurrentLocation() }; } } diff --git a/NTFSSecurity/BaseCmdlets.cs b/NTFSSecurity/BaseCmdlets.cs index 3ccf04f..0571c96 100644 --- a/NTFSSecurity/BaseCmdlets.cs +++ b/NTFSSecurity/BaseCmdlets.cs @@ -122,10 +122,13 @@ namespace NTFSSecurity return path; } - // Read from the session state, not from $PWD: a variable named PWD in the caller's scope shadows the - // automatic variable and can be $null (#86). In a location of another provider, such as the registry, this - // is the last file system location. - private string GetCurrentLocation() + /// + /// Returns the current file system location of the session. It is read from the session state, not from + /// $PWD, which a variable named PWD in the scope of the caller can hide (#86). In a location of another + /// provider, such as the registry, this is the last file system location. + /// + /// The provider path of the current file system location. + protected string GetCurrentLocation() { return SessionState.Path.CurrentFileSystemLocation.ProviderPath; } diff --git a/NTFSSecurity/InheritanceCmdlets/GetInheritance.cs b/NTFSSecurity/InheritanceCmdlets/GetInheritance.cs index fe44035..9b02228 100644 --- a/NTFSSecurity/InheritanceCmdlets/GetInheritance.cs +++ b/NTFSSecurity/InheritanceCmdlets/GetInheritance.cs @@ -42,7 +42,7 @@ namespace NTFSSecurity if (paths.Count == 0) { - paths = new List() { GetVariableValue("PWD").ToString() }; + paths = new List() { GetCurrentLocation() }; } } diff --git a/NTFSSecurity/ItemCmdlets/CopyItem2.cs b/NTFSSecurity/ItemCmdlets/CopyItem2.cs index 8481cc1..0775bc7 100644 --- a/NTFSSecurity/ItemCmdlets/CopyItem2.cs +++ b/NTFSSecurity/ItemCmdlets/CopyItem2.cs @@ -97,12 +97,13 @@ namespace NTFSSecurity try { var processed = false; + FileSystemInfo copy = null; if (item is FileInfo) { if (ShouldProcess(resolvedPath, "Copy File")) { - ((FileInfo)item).CopyTo(actualDestination, force ? CopyOptions.None : CopyOptions.FailIfExists, PathFormat.RelativePath); + copy = ((FileInfo)item).CopyTo(actualDestination, force ? CopyOptions.None : CopyOptions.FailIfExists, PathFormat.RelativePath); WriteVerbose(string.Format("File '{0}' copied to '{1}'", resolvedPath, actualDestination)); processed = true; } @@ -114,14 +115,15 @@ namespace NTFSSecurity // AlphaFS 2.2 copies into an existing folder only and otherwise fails with a // DirectoryNotFoundException for the first file. Directory.CreateDirectory(actualDestination); - ((DirectoryInfo)item).CopyTo(actualDestination, force ? CopyOptions.None : CopyOptions.FailIfExists, PathFormat.RelativePath); + copy = ((DirectoryInfo)item).CopyTo(actualDestination, force ? CopyOptions.None : CopyOptions.FailIfExists, PathFormat.RelativePath); WriteVerbose(string.Format("Directory '{0}' copied to '{1}'", resolvedPath, actualDestination)); processed = true; } } + // Write the object for the copy that CopyTo returns, not the source item. if (passThru && processed) - WriteObject(item); + WriteObject(copy); } catch (System.IO.IOException ex) { diff --git a/NTFSSecurity/ItemCmdlets/GetChildItem2.cs b/NTFSSecurity/ItemCmdlets/GetChildItem2.cs index 9394b15..70aaa2b 100644 --- a/NTFSSecurity/ItemCmdlets/GetChildItem2.cs +++ b/NTFSSecurity/ItemCmdlets/GetChildItem2.cs @@ -134,7 +134,7 @@ namespace NTFSSecurity if (paths.Count == 0) { - paths = new List() { GetVariableValue("PWD").ToString() }; + paths = new List() { GetCurrentLocation() }; } wildcard = new WildcardPattern(filter, WildcardOptions.Compiled | WildcardOptions.IgnoreCase); diff --git a/NTFSSecurity/ItemCmdlets/GetItem2.cs b/NTFSSecurity/ItemCmdlets/GetItem2.cs index 4b3c662..c2fe9e8 100644 --- a/NTFSSecurity/ItemCmdlets/GetItem2.cs +++ b/NTFSSecurity/ItemCmdlets/GetItem2.cs @@ -30,7 +30,7 @@ namespace NTFSSecurity if (paths.Count == 0) { - paths = new List() { GetVariableValue("PWD").ToString() }; + paths = new List() { GetCurrentLocation() }; } modeMethodInfo = typeof(FileSystemCodeMembers).GetMethod("Mode"); diff --git a/NTFSSecurity/LinkCmdlets/GetHardLink.cs b/NTFSSecurity/LinkCmdlets/GetHardLink.cs index 37f0d33..7f96b1a 100644 --- a/NTFSSecurity/LinkCmdlets/GetHardLink.cs +++ b/NTFSSecurity/LinkCmdlets/GetHardLink.cs @@ -31,7 +31,7 @@ namespace NTFSSecurity if (paths.Count == 0) { - paths = new List() { GetVariableValue("PWD").ToString() }; + paths = new List() { GetCurrentLocation() }; } modeMethodInfo = typeof(FileSystemCodeMembers).GetMethod("Mode"); diff --git a/NTFSSecurity/PathCmdlets/TestPath2.cs b/NTFSSecurity/PathCmdlets/TestPath2.cs index e25409f..b443d73 100644 --- a/NTFSSecurity/PathCmdlets/TestPath2.cs +++ b/NTFSSecurity/PathCmdlets/TestPath2.cs @@ -37,7 +37,7 @@ namespace NTFSSecurity if (paths.Count == 0) { - paths = new List() { GetVariableValue("PWD").ToString() }; + paths = new List() { GetCurrentLocation() }; } } diff --git a/NTFSSecurity/SecurityDescriptorCmdlets/GetSecurityDescriptor.cs b/NTFSSecurity/SecurityDescriptorCmdlets/GetSecurityDescriptor.cs index 16a0f9d..4d2f634 100644 --- a/NTFSSecurity/SecurityDescriptorCmdlets/GetSecurityDescriptor.cs +++ b/NTFSSecurity/SecurityDescriptorCmdlets/GetSecurityDescriptor.cs @@ -29,7 +29,7 @@ namespace NTFSSecurity if (paths.Count == 0) { - paths.Add(GetVariableValue("PWD").ToString()); + paths.Add(GetCurrentLocation()); } } diff --git a/Tests/ItemCmdlets.Tests.ps1 b/Tests/ItemCmdlets.Tests.ps1 index 4586755..336091a 100644 --- a/Tests/ItemCmdlets.Tests.ps1 +++ b/Tests/ItemCmdlets.Tests.ps1 @@ -137,6 +137,18 @@ Describe 'Copy-Item2, Move-Item2, and Remove-Item2 with several paths' { $first | Should -Exist } + It 'Copy-Item2 -PassThru should return the copy of a folder' { + $sourceFolder = Join-Path -Path $folder -ChildPath 'SourceFolder' + Assert-TestSandboxPath -Sandbox $sandbox -Path $sourceFolder + New-Item -ItemType Directory -Path $sourceFolder | Out-Null + Set-Content -LiteralPath (Join-Path -Path $sourceFolder -ChildPath 'Inner.txt') -Value 'Inner' + + $result = Copy-Item2 -Path $sourceFolder -Destination (Join-Path -Path $destination -ChildPath 'Copied') -PassThru $true + + $result.FullName | Should -Be (Join-Path -Path $destination -ChildPath 'Copied') + $sourceFolder | Should -Exist + } + It 'Move-Item2 -PassThru should return the item at its new location' { $result = Move-Item2 -Path $first -Destination $destination -PassThru $true diff --git a/Tests/Owner.Tests.ps1 b/Tests/Owner.Tests.ps1 index 026dec3..6e169ac 100644 --- a/Tests/Owner.Tests.ps1 +++ b/Tests/Owner.Tests.ps1 @@ -58,6 +58,8 @@ Describe 'Get-NTFSOwner' { Describe 'Current location' { BeforeAll { + # The command runs in a child scope of this function, so the cmdlets see its $PWD = $null through the scope + # chain, as in the report. function Invoke-WithShadowedPwd { param ([scriptblock] $Command) @@ -84,6 +86,21 @@ Describe 'Current location' { $result.FullName | Should -Be $file } + + It '<_> should use the current location without -Path despite a variable named PWD' -ForEach @( + 'Get-NTFSAccess', 'Get-NTFSAudit', 'Get-NTFSEffectiveAccess', 'Get-NTFSInheritance', 'Get-ChildItem2', + 'Get-Item2', 'Get-NTFSSecurityDescriptor' + ) { + $cmdlet = $_ + + { Invoke-WithShadowedPwd -Command { & $cmdlet -ErrorAction SilentlyContinue -WarningAction SilentlyContinue } } | + Should -Not -Throw + } + + It 'Get-NTFSHardLink should report the folder of the current location, not a NullReferenceException' { + { Invoke-WithShadowedPwd -Command { Get-NTFSHardLink -ErrorAction SilentlyContinue } } | + Should -Throw -ExpectedMessage '*must be a file*' + } } Describe 'File and folder objects as arguments' { @@ -108,4 +125,4 @@ Describe 'File and folder objects as arguments' { $result.FullName | Should -Be $file } -} \ No newline at end of file +}