Browse Source

fix: read the current location from the session, not from $PWD

A variable named PWD in the scope of the caller, such as a loop variable,
hid the automatic variable, and every cmdlet failed with a
NullReferenceException, also for an absolute path. The cmdlets now read
the current file system location from the session state, and only for a
relative path (#86).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
pull/105/head
Raimund Andree 1 week ago
parent
commit
b45ac11b02
  1. 5
      CHANGELOG.md
  2. 52
      NTFSSecurity/BaseCmdlets.cs
  3. 33
      Tests/Owner.Tests.ps1

5
CHANGELOG.md

@ -172,5 +172,10 @@ The format is based on
- Fix a `FormatException` in the cmdlets for a path with braces, such as - Fix a `FormatException` in the cmdlets for a path with braces, such as
`C:\Data\{Archive}`: their messages formatted the path a second time `C:\Data\{Archive}`: their messages formatted the path a second time
([#3](https://github.com/raandree/NTFSSecurity/issues/3)) ([#3](https://github.com/raandree/NTFSSecurity/issues/3))
- Fix a `NullReferenceException` in every cmdlet when a variable named
`PWD` in the scope of the caller, such as a loop variable, hid the
automatic variable; the cmdlets now read the current location from the
session, and only for a relative path
([#86](https://github.com/raandree/NTFSSecurity/issues/86))
[Unreleased]: https://github.com/raandree/NTFSSecurity/compare/4.2.6...HEAD [Unreleased]: https://github.com/raandree/NTFSSecurity/compare/4.2.6...HEAD

52
NTFSSecurity/BaseCmdlets.cs

@ -26,32 +26,7 @@ namespace NTFSSecurity
#region GetFileSystemInfo #region GetFileSystemInfo
protected System.IO.FileSystemInfo GetFileSystemInfo(string path) protected System.IO.FileSystemInfo GetFileSystemInfo(string path)
{ {
string currentLocation = GetVariableValue("PWD").ToString(); path = GetRelativePath(path);
if (path == ".")
{
path = currentLocation;
}
if (path.StartsWith(".."))
{
path = System.IO.Path.Combine(
string.Join("\\", currentLocation.Split('\\').Take(currentLocation.Split('\\').Count() - path.Split('\\').Count(s => s == "..")).ToArray()),
string.Join("\\", path.Split('\\').Where(e => e != "..").ToArray()));
}
else if (path.StartsWith("."))
{
//combine . and .\path\subpath
path = System.IO.Path.Combine(currentLocation, path.Substring(2));
}
else if (path.StartsWith("\\"))
{
//do nothing
}
else
{
////combine . and \path\subpath or path\subpath
path = System.IO.Path.Combine(currentLocation, path.Substring(0));
}
if (System.IO.File.Exists(path)) if (System.IO.File.Exists(path))
{ {
@ -114,18 +89,17 @@ namespace NTFSSecurity
#region GetRelativePath #region GetRelativePath
protected string GetRelativePath(string path) protected string GetRelativePath(string path)
{ {
string currentLocation = GetVariableValue("PWD").ToString();
if (string.IsNullOrEmpty(path)) if (string.IsNullOrEmpty(path))
{ {
path = currentLocation; path = GetCurrentLocation();
} }
else if (path == ".") else if (path == ".")
{ {
path = currentLocation; path = GetCurrentLocation();
} }
else if (path.StartsWith("..")) else if (path.StartsWith(".."))
{ {
var currentLocation = GetCurrentLocation();
path = System.IO.Path.Combine( path = System.IO.Path.Combine(
string.Join("\\", currentLocation.Split('\\').Take(currentLocation.Split('\\').Count() - path.Split('\\').Count(s => s == "..")).ToArray()), string.Join("\\", currentLocation.Split('\\').Take(currentLocation.Split('\\').Count() - path.Split('\\').Count(s => s == "..")).ToArray()),
string.Join("\\", path.Split('\\').Where(e => e != "..").ToArray())); string.Join("\\", path.Split('\\').Where(e => e != "..").ToArray()));
@ -133,20 +107,28 @@ namespace NTFSSecurity
else if (path.StartsWith(".")) else if (path.StartsWith("."))
{ {
//combine . and .\path\subpath //combine . and .\path\subpath
path = System.IO.Path.Combine(currentLocation, path.Substring(2)); path = System.IO.Path.Combine(GetCurrentLocation(), path.Substring(2));
} }
else if (path.StartsWith("\\")) else if (path.StartsWith("\\") || System.IO.Path.IsPathRooted(path))
{ {
//do nothing //an absolute path needs no location
} }
else else
{ {
////combine . and \path\subpath or path\subpath ////combine . and path\subpath
path = System.IO.Path.Combine(currentLocation, path); path = System.IO.Path.Combine(GetCurrentLocation(), path);
} }
return path; 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()
{
return SessionState.Path.CurrentFileSystemLocation.ProviderPath;
}
#endregion #endregion
#region InvokeAsOwner #region InvokeAsOwner

33
Tests/Owner.Tests.ps1

@ -4,6 +4,9 @@
[Diagnostics.CodeAnalysis.SuppressMessageAttribute( [Diagnostics.CodeAnalysis.SuppressMessageAttribute(
'PSUseDeclaredVarsMoreThanAssignments', '', Justification = 'Pester shares variables between blocks.' 'PSUseDeclaredVarsMoreThanAssignments', '', Justification = 'Pester shares variables between blocks.'
)] )]
[Diagnostics.CodeAnalysis.SuppressMessageAttribute(
'PSAvoidAssignmentToAutomaticVariable', '', Justification = 'A test shadows $PWD on purpose (#86).'
)]
param () param ()
BeforeDiscovery { BeforeDiscovery {
@ -52,3 +55,33 @@ Describe 'Get-NTFSOwner' {
} }
} }
} }
Describe 'Current location' {
BeforeAll {
function Invoke-WithShadowedPwd {
param ([scriptblock] $Command)
$PWD = $null
& $Command
}
}
# Before 5.0.0, a variable named PWD in the scope of the caller, such as a loop variable, made every cmdlet
# fail with a NullReferenceException, also for an absolute path (#86).
It 'Should ignore a variable named PWD for an absolute path' {
$file = New-TestSandboxItem -Sandbox $sandbox -Name 'Pwd'
$result = Invoke-WithShadowedPwd -Command { Get-NTFSOwner -Path $file -ErrorAction Stop }
$result.FullName | Should -Be $file
}
It 'Should resolve a relative path against the current location despite a variable named PWD' {
$file = New-TestSandboxItem -Sandbox $sandbox -Name 'PwdRelative'
$name = Split-Path -Path $file -Leaf
$result = Invoke-WithShadowedPwd -Command { Get-NTFSOwner -Path $name -ErrorAction Stop }
$result.FullName | Should -Be $file
}
}

Loading…
Cancel
Save