Browse Source

Merge pull request #103 from raandree/ai/defects-d

fix: output types, messages, and dead code (defect group D)
pull/112/head
Raimund Andrée 6 days ago
committed by GitHub
parent
commit
b741f316b3
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 22
      .memory-bank/activeContext.md
  2. 4
      .memory-bank/progress.md
  3. 15
      CHANGELOG.md
  4. 10
      Docs/Cmdlets/Copy-Item2.md
  5. 2
      Docs/Cmdlets/Disable-NTFSAccessInheritance.md
  6. 2
      Docs/Cmdlets/Disable-NTFSAuditInheritance.md
  7. 2
      Docs/Cmdlets/Disable-Privileges.md
  8. 2
      Docs/Cmdlets/Enable-NTFSAccessInheritance.md
  9. 2
      Docs/Cmdlets/Enable-NTFSAuditInheritance.md
  10. 2
      Docs/Cmdlets/Enable-Privileges.md
  11. 4
      Docs/Cmdlets/Get-FileHash2.md
  12. 10
      Docs/Cmdlets/Move-Item2.md
  13. 4
      Docs/Cmdlets/New-NTFSSymbolicLink.md
  14. 10
      Docs/Cmdlets/Remove-Item2.md
  15. 2
      Docs/Cmdlets/Set-NTFSInheritance.md
  16. 8
      Docs/Cmdlets/Test-Path2.md
  17. 2
      NTFSSecurity/AccessCmdlets/GetEffectiveAccess.cs
  18. 2
      NTFSSecurity/AuditCmdlets/AddAudit.cs
  19. 2
      NTFSSecurity/AuditCmdlets/RemoveAudit.cs
  20. 1
      NTFSSecurity/InheritanceCmdlets/DisableAccessInheritance.cs
  21. 1
      NTFSSecurity/InheritanceCmdlets/DisableAuditInheritance.cs
  22. 1
      NTFSSecurity/InheritanceCmdlets/EnableAccessInheritance.cs
  23. 1
      NTFSSecurity/InheritanceCmdlets/EnableAuditInheritance.cs
  24. 1
      NTFSSecurity/InheritanceCmdlets/SetInheritance.cs
  25. 11
      NTFSSecurity/ItemCmdlets/CopyItem2.cs
  26. 11
      NTFSSecurity/ItemCmdlets/MoveItem2.cs
  27. 8
      NTFSSecurity/ItemCmdlets/RemoveItem2.cs
  28. 5
      NTFSSecurity/LinkCmdlets/NewSymbolicLink.cs
  29. 2
      NTFSSecurity/MiscCmdlets/GetFileHash2.cs
  30. 9
      NTFSSecurity/OtherCmdlets.cs
  31. 2
      NTFSSecurity/PathCmdlets/TestPath2.cs
  32. 73
      NTFSSecurity/en-US/NTFSSecurity.dll-Help.xml
  33. 9
      Tests/Access.Tests.ps1
  34. 25
      Tests/ItemCmdlets.Tests.ps1
  35. 102
      Tests/OutputTypes.Tests.ps1
  36. 9
      Tests/Privileges.Tests.ps1

22
.memory-bank/activeContext.md

@ -42,16 +42,22 @@ the PRs, and tags `5.0.0-rc2` after the merges.
Review: Dependabot PRs ran unreviewed actions in a job with
`contents: write`; the wiki preview is now read-only (`publish-wiki`).
- `ai/defects-a` fixes defects 1 to 13 and the same repeat bug in
`Get-NTFSAccess` (found with 4): Windows PowerShell 310 passed, 17
skipped; PowerShell 7 280 passed, 47 skipped (327 tests). 10 tests need
privileges and run only in CI.
`Get-NTFSAccess` (found with 4); its review fixes are in the last
commit: Windows PowerShell 312 passed, 17 skipped; PowerShell 7 282
passed, 47 skipped (329 tests).
- `ai/defects-b` fixes defects 14 to 17 (`-AppliesTo` is mandatory in the
`Simple` sets; `-RemoveSpecific` is back): Windows PowerShell 331 passed,
19 skipped; PowerShell 7 301 passed, 49 skipped (350 tests).
`Simple` sets; `-RemoveSpecific` is back): Windows PowerShell 333 passed,
19 skipped; PowerShell 7 303 passed, 49 skipped (352 tests).
- `ai/defects-c` fixes defects 18 to 21, the same missing `continue` in
`Remove-NTFSAudit`, and a stale hash in `Get-FileHash2`.
`Remove-NTFSAudit`, and a stale hash in `Get-FileHash2`. Its review
found that a failed retry after taking ownership left the owner changed;
`BaseCmdlet.InvokeAsOwner` now restores it: Windows PowerShell 356
passed, 20 skipped; PowerShell 7 325 passed, 51 skipped (376 tests).
- `ai/defects-d` fixes defects 22 to 24 and `-PassThru` under `-WhatIf` in
the `*-Item2` cmdlets: Windows PowerShell 379 passed, 23 skipped;
PowerShell 7 348 passed, 54 skipped (402 tests).
## Next step
Group D (22 to 24) on `ai/defects-d`, then the E decisions and the bugs
from the issue triage (`ai/issue-fixes`).
The E decisions on `ai/decisions-e` (Decision 13 for `Set-NTFSInheritance`),
then the bugs from the issue triage (`ai/issue-fixes`) and 5.0.0-rc2.

4
.memory-bank/progress.md

@ -154,7 +154,7 @@ Numbered as agreed with the maintainer; each is documented on its page.
after a failed change, and a failed retry after taking ownership left the
owner changed; `BaseCmdlet.InvokeAsOwner` now restores it on every path.
#### D: Metadata and cosmetics
#### D: Metadata and cosmetics (fixed on `ai/defects-d`, not merged)
- (22) Wrong or missing `[OutputType]` (`Test-Path2`, `Get-FileHash2`,
`Add-NTFSAudit`, `*-Item2`, inheritance cmdlets);
@ -163,6 +163,8 @@ Numbered as agreed with the maintainer; each is documented on its page.
- (23) Typos: "Privliege" in the `Get-NTFSEffectiveAccess` warning; "are
now enabled" in the `Disable-Privileges` verbose message.
- (24) Dead code in `RemoveItem2.cs` and `OtherCmdlets.cs`.
- Found with group D: `-PassThru` of the `*-Item2` cmdlets wrote the item
also when `-WhatIf` skipped the operation.
#### E: Maintainer decisions before changing behavior

15
CHANGELOG.md

@ -134,5 +134,20 @@ The format is based on
- Fix the cmdlets that take ownership of an item to repeat an operation that
was denied: when the second attempt failed as well, the account that ran
the cmdlet stayed the owner of the item; now the previous owner is restored
- Fix `-PassThru` of `Enable-Privileges` and `Disable-Privileges`, which
wrote the privileges as one collection instead of one object per
privilege, and of `New-NTFSSymbolicLink`, which returned a file object for
a link to a folder
- Declare the output types of `Test-Path2`, `Get-FileHash2`,
`Add-NTFSAudit`, `Remove-NTFSAudit`, `Copy-Item2`, `Move-Item2`,
`Remove-Item2`, and the inheritance cmdlets correctly, so that
`Get-Command` and tab completion report the objects they write
- Fix the verbose messages of `Copy-Item2` and `Move-Item2`, which named the
source path as the destination, and of `Disable-Privileges`, which said
that the privileges were enabled, and the spelling of the privilege in
the warning of `Get-NTFSEffectiveAccess`
- Fix `-PassThru` of `Copy-Item2`, `Move-Item2`, and `Remove-Item2`, which
wrote the item also when `-WhatIf` or a declined confirmation skipped the
operation
[Unreleased]: https://github.com/raandree/NTFSSecurity/compare/4.2.6...HEAD

10
Docs/Cmdlets/Copy-Item2.md

@ -176,14 +176,20 @@ You can pipe an object that has a `Destination` property to supply the target of
## OUTPUTS
### System.Object
### Alphaleonis.Win32.Filesystem.FileInfo
By default this cmdlet returns nothing. With `-PassThru $true` it returns an `Alphaleonis.Win32.Filesystem.FileInfo` or `Alphaleonis.Win32.Filesystem.DirectoryInfo` object for each item that it copied.
By default this cmdlet returns nothing. With `-PassThru $true` it returns a file object for each file that it copied.
### Alphaleonis.Win32.Filesystem.DirectoryInfo
With `-PassThru $true` the cmdlet returns a folder object for each folder that it copied.
## NOTES
`Copy-Item2` copies through the AlphaFS library (`Alphaleonis.Win32.Filesystem`), which is why it handles source and destination paths that exceed the 260-character `MAX_PATH` limit of the built-in `Copy-Item` cmdlet.
Before 5.0.0, `-PassThru` also wrote the item when `-WhatIf` or a declined confirmation skipped the operation.
Before 5.0.0, copying a folder that contained files failed with a `CopyError` that reported a `DirectoryNotFoundException` for the first file in the folder.
If a path in `-Path` does not exist or the destination file exists and `-Force` is missing, the cmdlet writes a non-terminating error and continues with the next path. Before 5.0.0, it skipped the remaining paths that were passed in the same call.

2
Docs/Cmdlets/Disable-NTFSAccessInheritance.md

@ -156,7 +156,7 @@ You can pipe the security descriptors that `Get-NTFSSecurityDescriptor` returns
## OUTPUTS
### System.Object
### Security2.FileSystemInheritanceInfo
By default this cmdlet returns no output. With `-PassThru` it writes one `Security2.FileSystemInheritanceInfo` object per item, which reports the `AccessInheritanceEnabled` and `AuditInheritanceEnabled` state after the change.

2
Docs/Cmdlets/Disable-NTFSAuditInheritance.md

@ -156,7 +156,7 @@ You can pipe the security descriptors that `Get-NTFSSecurityDescriptor` returns
## OUTPUTS
### System.Object
### Security2.FileSystemInheritanceInfo
By default this cmdlet returns no output. With `-PassThru` it writes one `Security2.FileSystemInheritanceInfo` object per item, which reports the `AccessInheritanceEnabled` and `AuditInheritanceEnabled` state after the change.

2
Docs/Cmdlets/Disable-Privileges.md

@ -93,7 +93,7 @@ This cmdlet does not accept pipeline input.
### ProcessPrivileges.PrivilegeAndAttributes
With `-PassThru`, the cmdlet writes the privilege collection of the current process. The pipeline enumerates it into one `ProcessPrivileges.PrivilegeAndAttributes` object per privilege, each with a `Privilege`, a `PrivilegeAttributes`, and a `PrivilegeState` property. Without `-PassThru`, the cmdlet writes nothing.
With `-PassThru`, the cmdlet writes one `ProcessPrivileges.PrivilegeAndAttributes` object per privilege of the current process, each with a `Privilege`, a `PrivilegeAttributes`, and a `PrivilegeState` property. Without `-PassThru`, the cmdlet writes nothing. Before 5.0.0, it wrote the privileges as one collection.
## NOTES

2
Docs/Cmdlets/Enable-NTFSAccessInheritance.md

@ -155,7 +155,7 @@ You can pipe the security descriptors that `Get-NTFSSecurityDescriptor` returns
## OUTPUTS
### System.Object
### Security2.FileSystemInheritanceInfo
By default this cmdlet returns no output. With `-PassThru` it writes one `Security2.FileSystemInheritanceInfo` object per item, which reports the `AccessInheritanceEnabled` and `AuditInheritanceEnabled` state after the change.

2
Docs/Cmdlets/Enable-NTFSAuditInheritance.md

@ -155,7 +155,7 @@ You can pipe the security descriptors that `Get-NTFSSecurityDescriptor` returns
## OUTPUTS
### System.Object
### Security2.FileSystemInheritanceInfo
By default this cmdlet returns no output. With `-PassThru` it writes one `Security2.FileSystemInheritanceInfo` object per item, which reports the `AccessInheritanceEnabled` and `AuditInheritanceEnabled` state after the change.

2
Docs/Cmdlets/Enable-Privileges.md

@ -95,7 +95,7 @@ This cmdlet does not accept pipeline input.
### ProcessPrivileges.PrivilegeAndAttributes
With `-PassThru`, the cmdlet writes the privilege collection of the current process. The pipeline enumerates it into one `ProcessPrivileges.PrivilegeAndAttributes` object per privilege, each with a `Privilege`, a `PrivilegeAttributes`, and a `PrivilegeState` property. Without `-PassThru`, the cmdlet writes nothing.
With `-PassThru`, the cmdlet writes one `ProcessPrivileges.PrivilegeAndAttributes` object per privilege of the current process, each with a `Privilege`, a `PrivilegeAttributes`, and a `PrivilegeState` property. Without `-PassThru`, the cmdlet writes nothing. Before 5.0.0, it wrote the privileges as one collection.
## NOTES

4
Docs/Cmdlets/Get-FileHash2.md

@ -111,9 +111,9 @@ You can supply the `-Algorithm` value through a pipeline object that has an `Alg
## OUTPUTS
### Security2.FileSystemAccessRule2
### Alphaleonis.Win32.Filesystem.FileInfo
The cmdlet does not return access rules. For every hashed file it writes the file object of that file, decorated with the type name `Alphaleonis.Win32.Filesystem.FileInfo+Hash` and extended with the `Hash` and `Algorithm` note properties, so all regular file properties such as `FullName`, `Name`, and `Length` remain available.
For every hashed file, the cmdlet writes the file object of that file, decorated with the type name `Alphaleonis.Win32.Filesystem.FileInfo+Hash` and extended with the `Hash` and `Algorithm` note properties, so all regular file properties such as `FullName`, `Name`, and `Length` remain available.
## NOTES

10
Docs/Cmdlets/Move-Item2.md

@ -176,14 +176,20 @@ You can pipe an object that has a `Destination` property to supply the target of
## OUTPUTS
### System.Object
### Alphaleonis.Win32.Filesystem.FileInfo
By default this cmdlet returns nothing. With `-PassThru $true` it returns an `Alphaleonis.Win32.Filesystem.FileInfo` or `Alphaleonis.Win32.Filesystem.DirectoryInfo` object for each item that it moved, pointing at the new location.
By default this cmdlet returns nothing. With `-PassThru $true` it returns a file object for each file that it moved, pointing at the new location.
### Alphaleonis.Win32.Filesystem.DirectoryInfo
With `-PassThru $true` the cmdlet returns a folder object for each folder that it moved, pointing at the new location.
## NOTES
`Move-Item2` moves through the AlphaFS library (`Alphaleonis.Win32.Filesystem`), which is why it handles source and destination paths that exceed the 260-character `MAX_PATH` limit of the built-in `Move-Item` cmdlet.
Before 5.0.0, `-PassThru` also wrote the item when `-WhatIf` or a declined confirmation skipped the operation.
The cmdlet chooses between two mutually exclusive move options. Without `-Force` it moves with `CopyAllowed`, which permits a file to cross volume boundaries because Windows then copies and deletes it. With `-Force` it moves with `ReplaceExisting`, which overwrites the destination but does not request `CopyAllowed`, so a move across volumes can fail when `-Force` is specified.
If a path in `-Path` does not exist or the destination file exists and `-Force` is missing, the cmdlet writes a non-terminating error and continues with the next path. Before 5.0.0, it skipped the remaining paths that were passed in the same call.

4
Docs/Cmdlets/New-NTFSSymbolicLink.md

@ -124,11 +124,11 @@ You can pass the path of the new link and the path of the target as strings.
### Alphaleonis.Win32.Filesystem.FileInfo
With `-PassThru`, the cmdlet writes a file object for the new link. The cmdlet writes that object type for a link to a folder as well. Without `-PassThru`, the cmdlet writes nothing.
With `-PassThru`, the cmdlet writes a file object for a new link to a file. Without `-PassThru`, the cmdlet writes nothing.
### Alphaleonis.Win32.Filesystem.DirectoryInfo
The cmdlet does not write folder objects. A directory symbolic link is also returned as a file object.
With `-PassThru`, the cmdlet writes a folder object for a new link to a folder. Before 5.0.0, it wrote a file object for those links as well.
## NOTES

10
Docs/Cmdlets/Remove-Item2.md

@ -169,14 +169,20 @@ You can pipe one or more paths to this cmdlet, either as strings or as objects t
## OUTPUTS
### System.Object
### Alphaleonis.Win32.Filesystem.FileInfo
By default this cmdlet returns nothing. With `-PassThru` it returns an `Alphaleonis.Win32.Filesystem.FileInfo` or `Alphaleonis.Win32.Filesystem.DirectoryInfo` object for each item that it deleted.
By default this cmdlet returns nothing. With `-PassThru` it returns a file object for each file that it deleted.
### Alphaleonis.Win32.Filesystem.DirectoryInfo
With `-PassThru` the cmdlet returns a folder object for each folder that it deleted.
## NOTES
`Remove-Item2` deletes through the AlphaFS library (`Alphaleonis.Win32.Filesystem`), which is why it reaches items whose path exceeds the 260-character `MAX_PATH` limit of the built-in `Remove-Item` cmdlet. Deletion is permanent; the cmdlet does not use the Recycle Bin.
Before 5.0.0, `-PassThru` also wrote the item when `-WhatIf` or a declined confirmation skipped the operation.
The module defines the aliases `rm2` and `del2` for this cmdlet.
A path that does not exist causes the error `FileNotFound`, and a deletion that the file system rejects causes a `DeleteError`. In both cases the cmdlet continues with the next path. Before 5.0.0, a path that did not exist made the cmdlet skip the remaining paths that were passed in the same call.

2
Docs/Cmdlets/Set-NTFSInheritance.md

@ -178,7 +178,7 @@ You can supply `-AccessInheritanceEnabled` and `-AuditInheritanceEnabled` throug
## OUTPUTS
### System.Object
### Security2.FileSystemInheritanceInfo
By default this cmdlet returns no output. With `-PassThru` it writes one `Security2.FileSystemInheritanceInfo` object per item, which reports the `AccessInheritanceEnabled` and `AuditInheritanceEnabled` state after the change.

8
Docs/Cmdlets/Test-Path2.md

@ -109,13 +109,9 @@ You can supply the `-PathType` value through a pipeline object that has a `PathT
## OUTPUTS
### Alphaleonis.Win32.Filesystem.FileInfo
### System.Boolean
`Test-Path2` does not write file objects. For each path it writes a single `System.Boolean` value that is `$true` when the item exists and matches `-PathType`, and `$false` otherwise.
### Alphaleonis.Win32.Filesystem.DirectoryInfo
`Test-Path2` does not write folder objects either. A folder is reported through the same `System.Boolean` result as a file.
For each path, the cmdlet writes `$true` when the item exists and matches `-PathType`, and `$false` otherwise.
## NOTES

2
NTFSSecurity/AccessCmdlets/GetEffectiveAccess.cs

@ -72,7 +72,7 @@ namespace NTFSSecurity
securityPrivilege = privControl.GetPrivileges().Where(priv => priv.Privilege == ProcessPrivileges.Privilege.Security).ToList();
if (securityPrivilege.Count() == 0)
{
this.WriteWarning("The user does not hold the Security Privliege and might not be able to read the effective permissions");
this.WriteWarning("The user does not hold the Security privilege and might not be able to read the effective permissions.");
}
else
{

2
NTFSSecurity/AuditCmdlets/AddAudit.cs

@ -8,7 +8,7 @@ using System.Security.AccessControl;
namespace NTFSSecurity
{
[Cmdlet(VerbsCommon.Add, "NTFSAudit", DefaultParameterSetName = "PathComplex")]
[OutputType(typeof(FileSystemAccessRule2))]
[OutputType(typeof(FileSystemAuditRule2))]
public class AddAudit : BaseCmdletWithPrivControl
{
private IdentityReference2[] account;

2
NTFSSecurity/AuditCmdlets/RemoveAudit.cs

@ -8,7 +8,7 @@ using System.Security.AccessControl;
namespace NTFSSecurity
{
[Cmdlet(VerbsCommon.Remove, "NTFSAudit", DefaultParameterSetName = "PathComplex")]
[OutputType(typeof(FileSystemAccessRule2))]
[OutputType(typeof(FileSystemAuditRule2))]
public class RemoveAudit : BaseCmdletWithPrivControl
{
private IdentityReference2[] account;

1
NTFSSecurity/InheritanceCmdlets/DisableAccessInheritance.cs

@ -6,6 +6,7 @@ using System.Management.Automation;
namespace NTFSSecurity
{
[Cmdlet(VerbsLifecycle.Disable, "NTFSAccessInheritance", DefaultParameterSetName = "Path")]
[OutputType(typeof(FileSystemInheritanceInfo))]
public class DisableAccessInheritance : BaseCmdletWithPrivControl
{
private bool removeInheritedAccessRules;

1
NTFSSecurity/InheritanceCmdlets/DisableAuditInheritance.cs

@ -7,6 +7,7 @@ namespace NTFSSecurity
{
[Cmdlet(VerbsLifecycle.Disable, "NTFSAuditInheritance", DefaultParameterSetName = "Path")]
[OutputType(typeof(FileSystemInheritanceInfo))]
public class DisableAuditInheritance : BaseCmdletWithPrivControl
{
private bool removeInheritedAccessRules;

1
NTFSSecurity/InheritanceCmdlets/EnableAccessInheritance.cs

@ -6,6 +6,7 @@ using System.Management.Automation;
namespace NTFSSecurity
{
[Cmdlet(VerbsLifecycle.Enable, "NTFSAccessInheritance", DefaultParameterSetName = "Path")]
[OutputType(typeof(FileSystemInheritanceInfo))]
public class EnableAccessInheritance : BaseCmdletWithPrivControl
{
private bool removeExplicitAccessRules;

1
NTFSSecurity/InheritanceCmdlets/EnableAuditInheritance.cs

@ -6,6 +6,7 @@ using System.Management.Automation;
namespace NTFSSecurity
{
[Cmdlet(VerbsLifecycle.Enable, "NTFSAuditInheritance", DefaultParameterSetName = "Path")]
[OutputType(typeof(FileSystemInheritanceInfo))]
public class EnableAuditInheritance : BaseCmdletWithPrivControl
{
private bool removeExplicitAccessRules;

1
NTFSSecurity/InheritanceCmdlets/SetInheritance.cs

@ -6,6 +6,7 @@ using System.Management.Automation;
namespace NTFSSecurity
{
[Cmdlet(VerbsCommon.Set, "NTFSInheritance", DefaultParameterSetName = "Path")]
[OutputType(typeof(FileSystemInheritanceInfo))]
public class SetInheritance : BaseCmdletWithPrivControl
{
private bool? accessInheritanceEnabled;

11
NTFSSecurity/ItemCmdlets/CopyItem2.cs

@ -5,6 +5,7 @@ using System.Management.Automation;
namespace NTFSSecurity
{
[Cmdlet(VerbsCommon.Copy, "Item2", SupportsShouldProcess = true)]
[OutputType(typeof(FileInfo), typeof(DirectoryInfo))]
public class CopyItem2 : BaseCmdlet
{
private string destination;
@ -93,12 +94,15 @@ namespace NTFSSecurity
try
{
var processed = false;
if (item is FileInfo)
{
if (ShouldProcess(resolvedPath, "Copy File"))
{
((FileInfo)item).CopyTo(actualDestination, force ? CopyOptions.None : CopyOptions.FailIfExists, PathFormat.RelativePath);
WriteVerbose(string.Format("File '{0}' copied to '{0}'", resolvedPath, destination));
WriteVerbose(string.Format("File '{0}' copied to '{1}'", resolvedPath, actualDestination));
processed = true;
}
}
else
@ -109,11 +113,12 @@ namespace NTFSSecurity
// DirectoryNotFoundException for the first file.
Directory.CreateDirectory(actualDestination);
((DirectoryInfo)item).CopyTo(actualDestination, force ? CopyOptions.None : CopyOptions.FailIfExists, PathFormat.RelativePath);
WriteVerbose(string.Format("Directory '{0}' copied to '{0}'", resolvedPath, destination));
WriteVerbose(string.Format("Directory '{0}' copied to '{1}'", resolvedPath, actualDestination));
processed = true;
}
}
if (passThru)
if (passThru && processed)
WriteObject(item);
}
catch (System.IO.IOException ex)

11
NTFSSecurity/ItemCmdlets/MoveItem2.cs

@ -5,6 +5,7 @@ using System.Management.Automation;
namespace NTFSSecurity
{
[Cmdlet(VerbsCommon.Move, "Item2", SupportsShouldProcess = true)]
[OutputType(typeof(FileInfo), typeof(DirectoryInfo))]
public class MoveItem2 : BaseCmdlet
{
private string destination;
@ -93,12 +94,15 @@ namespace NTFSSecurity
try
{
var processed = false;
if (item is FileInfo)
{
if (ShouldProcess(resolvedPath, "Move File"))
{
((FileInfo)item).MoveTo(actualDestination, force ? MoveOptions.ReplaceExisting : MoveOptions.CopyAllowed, PathFormat.RelativePath);
WriteVerbose(string.Format("File '{0}' moved to '{0}'", resolvedPath, destination));
WriteVerbose(string.Format("File '{0}' moved to '{1}'", resolvedPath, actualDestination));
processed = true;
}
}
else
@ -106,11 +110,12 @@ namespace NTFSSecurity
if (ShouldProcess(resolvedPath, "Move Directory"))
{
((DirectoryInfo)item).MoveTo(actualDestination, force ? MoveOptions.ReplaceExisting : MoveOptions.CopyAllowed, PathFormat.RelativePath);
WriteVerbose(string.Format("Directory '{0}' moved to '{0}'", resolvedPath, destination));
WriteVerbose(string.Format("Directory '{0}' moved to '{1}'", resolvedPath, actualDestination));
processed = true;
}
}
if (passThru)
if (passThru && processed)
WriteObject(item);
}
catch (System.IO.IOException ex)

8
NTFSSecurity/ItemCmdlets/RemoveItem2.cs

@ -5,11 +5,11 @@ using System.Management.Automation;
namespace NTFSSecurity
{
[Cmdlet(VerbsCommon.Remove, "Item2", SupportsShouldProcess = true)]
[OutputType(typeof(FileInfo), typeof(DirectoryInfo))]
public class RemoveItem2 : BaseCmdlet
{
private SwitchParameter force;
private SwitchParameter recurse;
private string filter;
private bool passThru;
[Parameter(Position = 1, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)]
@ -71,12 +71,15 @@ namespace NTFSSecurity
try
{
var processed = false;
if (item is FileInfo)
{
if (ShouldProcess(item.ToString(), "Remove File"))
{
((FileInfo)item).Delete(force);
WriteVerbose(string.Format("File '{0}' was removed", item.ToString()));
processed = true;
}
}
else
@ -85,10 +88,11 @@ namespace NTFSSecurity
{
((DirectoryInfo)item).Delete(recurse, force);
WriteVerbose(string.Format("Directory '{0}' was removed", item.ToString()));
processed = true;
}
}
if (passThru)
if (passThru && processed)
WriteObject(item);
}
catch (System.IO.IOException ex)

5
NTFSSecurity/LinkCmdlets/NewSymbolicLink.cs

@ -70,7 +70,10 @@ namespace NTFSSecurity
if (passThru)
{
WriteObject(new FileInfo(path));
if (targetItem is FileInfo)
WriteObject(new FileInfo(path));
else
WriteObject(new DirectoryInfo(path));
}
}
catch (System.IO.FileNotFoundException ex)

2
NTFSSecurity/MiscCmdlets/GetFileHash2.cs

@ -7,7 +7,7 @@ using Security2.FileSystem.FileInfo;
namespace NTFSSecurity
{
[Cmdlet(VerbsCommon.Get, "FileHash2")]
[OutputType(typeof(FileSystemAccessRule2))]
[OutputType(typeof(FileInfo))]
public class GetFileHash2 : BaseCmdlet
{
private HashAlgorithms algorithm = HashAlgorithms.SHA256;

9
NTFSSecurity/OtherCmdlets.cs

@ -14,7 +14,6 @@ namespace NTFSSecurity
{
private bool enablePrivileges = false;
private SwitchParameter passThru;
public string[] Path { get; set; }
[Parameter]
public SwitchParameter PassThru
@ -54,7 +53,7 @@ namespace NTFSSecurity
if (passThru)
{
this.WriteObject(this.privControl.GetPrivileges());
this.WriteObject(this.privControl.GetPrivileges(), true);
}
}
@ -71,7 +70,6 @@ namespace NTFSSecurity
public class DisablePrivileges : BaseCmdletWithPrivControl
{
private SwitchParameter passThru;
public string[] Path { get; set; }
[Parameter]
public SwitchParameter PassThru
@ -100,11 +98,11 @@ namespace NTFSSecurity
}
this.DisableFileSystemPrivileges();
this.WriteVerbose("The privileges 'TakeOwnership', 'Restore' and 'Backup' are now enabled.");
this.WriteVerbose("The privileges 'TakeOwnership', 'Restore' and 'Backup' are now disabled.");
if (passThru)
{
this.WriteObject(this.privControl.GetPrivileges());
this.WriteObject(this.privControl.GetPrivileges(), true);
}
}
@ -120,7 +118,6 @@ namespace NTFSSecurity
[OutputType(typeof(ProcessPrivileges.PrivilegeAndAttributes))]
public class GetPrivileges : BaseCmdlet
{
public string[] Path { get; set; }
protected override void BeginProcessing()
{

2
NTFSSecurity/PathCmdlets/TestPath2.cs

@ -5,7 +5,7 @@ using System.Management.Automation;
namespace NTFSSecurity
{
[Cmdlet(VerbsDiagnostic.Test, "Path2")]
[OutputType(typeof(FileInfo), typeof(DirectoryInfo))]
[OutputType(typeof(bool))]
public class TestPath2 : BaseCmdlet
{
private TestPathType pathType = TestPathType.Any;

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

@ -2163,16 +2163,25 @@ PS C:\&gt; Set-NTFSSecurityDescriptor -SecurityDescriptor $sd</dev:code>
<command:returnValues>
<command:returnValue>
<dev:type>
<maml:name>System.Object</maml:name>
<maml:name>Alphaleonis.Win32.Filesystem.FileInfo</maml:name>
</dev:type>
<maml:description>
<maml:para>By default this cmdlet returns nothing. With `-PassThru $true` it returns a file object for each file that it copied.</maml:para>
</maml:description>
</command:returnValue>
<command:returnValue>
<dev:type>
<maml:name>Alphaleonis.Win32.Filesystem.DirectoryInfo</maml:name>
</dev:type>
<maml:description>
<maml:para>By default this cmdlet returns nothing. With `-PassThru $true` it returns an `Alphaleonis.Win32.Filesystem.FileInfo` or `Alphaleonis.Win32.Filesystem.DirectoryInfo` object for each item that it copied.</maml:para>
<maml:para>With `-PassThru $true` the cmdlet returns a folder object for each folder that it copied.</maml:para>
</maml:description>
</command:returnValue>
</command:returnValues>
<maml:alertSet>
<maml:alert>
<maml:para>`Copy-Item2` copies through the AlphaFS library (`Alphaleonis.Win32.Filesystem`), which is why it handles source and destination paths that exceed the 260-character `MAX_PATH` limit of the built-in `Copy-Item` cmdlet.</maml:para>
<maml:para>Before 5.0.0, `-PassThru` also wrote the item when `-WhatIf` or a declined confirmation skipped the operation.</maml:para>
<maml:para>Before 5.0.0, copying a folder that contained files failed with a `CopyError` that reported a `DirectoryNotFoundException` for the first file in the folder.</maml:para>
<maml:para>If a path in `-Path` does not exist or the destination file exists and `-Force` is missing, the cmdlet writes a non-terminating error and continues with the next path. Before 5.0.0, it skipped the remaining paths that were passed in the same call.</maml:para>
</maml:alert>
@ -2400,7 +2409,7 @@ PS C:\&gt; Set-NTFSSecurityDescriptor -SecurityDescriptor $sd</dev:code>
<command:returnValues>
<command:returnValue>
<dev:type>
<maml:name>System.Object</maml:name>
<maml:name>Security2.FileSystemInheritanceInfo</maml:name>
</dev:type>
<maml:description>
<maml:para>By default this cmdlet returns no output. With `-PassThru` it writes one `Security2.FileSystemInheritanceInfo` object per item, which reports the `AccessInheritanceEnabled` and `AuditInheritanceEnabled` state after the change.</maml:para>
@ -2645,7 +2654,7 @@ PS C:\&gt; Set-NTFSSecurityDescriptor -SecurityDescriptor $sd</dev:code>
<command:returnValues>
<command:returnValue>
<dev:type>
<maml:name>System.Object</maml:name>
<maml:name>Security2.FileSystemInheritanceInfo</maml:name>
</dev:type>
<maml:description>
<maml:para>By default this cmdlet returns no output. With `-PassThru` it writes one `Security2.FileSystemInheritanceInfo` object per item, which reports the `AccessInheritanceEnabled` and `AuditInheritanceEnabled` state after the change.</maml:para>
@ -2785,7 +2794,7 @@ PS C:\&gt; Set-NTFSSecurityDescriptor -SecurityDescriptor $sd</dev:code>
<maml:name>ProcessPrivileges.PrivilegeAndAttributes</maml:name>
</dev:type>
<maml:description>
<maml:para>With `-PassThru`, the cmdlet writes the privilege collection of the current process. The pipeline enumerates it into one `ProcessPrivileges.PrivilegeAndAttributes` object per privilege, each with a `Privilege`, a `PrivilegeAttributes`, and a `PrivilegeState` property. Without `-PassThru`, the cmdlet writes nothing.</maml:para>
<maml:para>With `-PassThru`, the cmdlet writes one `ProcessPrivileges.PrivilegeAndAttributes` object per privilege of the current process, each with a `Privilege`, a `PrivilegeAttributes`, and a `PrivilegeState` property. Without `-PassThru`, the cmdlet writes nothing. Before 5.0.0, it wrote the privileges as one collection.</maml:para>
</maml:description>
</command:returnValue>
</command:returnValues>
@ -3017,7 +3026,7 @@ PS C:\&gt; Get-Privileges | Where-Object { $_.Privilege -in 'Backup', 'Restore',
<command:returnValues>
<command:returnValue>
<dev:type>
<maml:name>System.Object</maml:name>
<maml:name>Security2.FileSystemInheritanceInfo</maml:name>
</dev:type>
<maml:description>
<maml:para>By default this cmdlet returns no output. With `-PassThru` it writes one `Security2.FileSystemInheritanceInfo` object per item, which reports the `AccessInheritanceEnabled` and `AuditInheritanceEnabled` state after the change.</maml:para>
@ -3262,7 +3271,7 @@ PS C:\&gt; Set-NTFSSecurityDescriptor -SecurityDescriptor $sd</dev:code>
<command:returnValues>
<command:returnValue>
<dev:type>
<maml:name>System.Object</maml:name>
<maml:name>Security2.FileSystemInheritanceInfo</maml:name>
</dev:type>
<maml:description>
<maml:para>By default this cmdlet returns no output. With `-PassThru` it writes one `Security2.FileSystemInheritanceInfo` object per item, which reports the `AccessInheritanceEnabled` and `AuditInheritanceEnabled` state after the change.</maml:para>
@ -3403,7 +3412,7 @@ PS C:\&gt; Set-NTFSSecurityDescriptor -SecurityDescriptor $sd</dev:code>
<maml:name>ProcessPrivileges.PrivilegeAndAttributes</maml:name>
</dev:type>
<maml:description>
<maml:para>With `-PassThru`, the cmdlet writes the privilege collection of the current process. The pipeline enumerates it into one `ProcessPrivileges.PrivilegeAndAttributes` object per privilege, each with a `Privilege`, a `PrivilegeAttributes`, and a `PrivilegeState` property. Without `-PassThru`, the cmdlet writes nothing.</maml:para>
<maml:para>With `-PassThru`, the cmdlet writes one `ProcessPrivileges.PrivilegeAndAttributes` object per privilege of the current process, each with a `Privilege`, a `PrivilegeAttributes`, and a `PrivilegeState` property. Without `-PassThru`, the cmdlet writes nothing. Before 5.0.0, it wrote the privileges as one collection.</maml:para>
</maml:description>
</command:returnValue>
</command:returnValues>
@ -4140,10 +4149,10 @@ PS C:\&gt; Disable-Privileges</dev:code>
<command:returnValues>
<command:returnValue>
<dev:type>
<maml:name>Security2.FileSystemAccessRule2</maml:name>
<maml:name>Alphaleonis.Win32.Filesystem.FileInfo</maml:name>
</dev:type>
<maml:description>
<maml:para>The cmdlet does not return access rules. For every hashed file it writes the file object of that file, decorated with the type name `Alphaleonis.Win32.Filesystem.FileInfo+Hash` and extended with the `Hash` and `Algorithm` note properties, so all regular file properties such as `FullName`, `Name`, and `Length` remain available.</maml:para>
<maml:para>For every hashed file, the cmdlet writes the file object of that file, decorated with the type name `Alphaleonis.Win32.Filesystem.FileInfo+Hash` and extended with the `Hash` and `Algorithm` note properties, so all regular file properties such as `FullName`, `Name`, and `Length` remain available.</maml:para>
</maml:description>
</command:returnValue>
</command:returnValues>
@ -6938,16 +6947,25 @@ PS C:\Data&gt; Get-NTFSSecurityDescriptor</dev:code>
<command:returnValues>
<command:returnValue>
<dev:type>
<maml:name>System.Object</maml:name>
<maml:name>Alphaleonis.Win32.Filesystem.FileInfo</maml:name>
</dev:type>
<maml:description>
<maml:para>By default this cmdlet returns nothing. With `-PassThru $true` it returns an `Alphaleonis.Win32.Filesystem.FileInfo` or `Alphaleonis.Win32.Filesystem.DirectoryInfo` object for each item that it moved, pointing at the new location.</maml:para>
<maml:para>By default this cmdlet returns nothing. With `-PassThru $true` it returns a file object for each file that it moved, pointing at the new location.</maml:para>
</maml:description>
</command:returnValue>
<command:returnValue>
<dev:type>
<maml:name>Alphaleonis.Win32.Filesystem.DirectoryInfo</maml:name>
</dev:type>
<maml:description>
<maml:para>With `-PassThru $true` the cmdlet returns a folder object for each folder that it moved, pointing at the new location.</maml:para>
</maml:description>
</command:returnValue>
</command:returnValues>
<maml:alertSet>
<maml:alert>
<maml:para>`Move-Item2` moves through the AlphaFS library (`Alphaleonis.Win32.Filesystem`), which is why it handles source and destination paths that exceed the 260-character `MAX_PATH` limit of the built-in `Move-Item` cmdlet.</maml:para>
<maml:para>Before 5.0.0, `-PassThru` also wrote the item when `-WhatIf` or a declined confirmation skipped the operation.</maml:para>
<maml:para>The cmdlet chooses between two mutually exclusive move options. Without `-Force` it moves with `CopyAllowed`, which permits a file to cross volume boundaries because Windows then copies and deletes it. With `-Force` it moves with `ReplaceExisting`, which overwrites the destination but does not request `CopyAllowed`, so a move across volumes can fail when `-Force` is specified.</maml:para>
<maml:para>If a path in `-Path` does not exist or the destination file exists and `-Force` is missing, the cmdlet writes a non-terminating error and continues with the next path. Before 5.0.0, it skipped the remaining paths that were passed in the same call.</maml:para>
</maml:alert>
@ -7300,7 +7318,7 @@ PS C:\Data&gt; Get-NTFSSecurityDescriptor</dev:code>
<maml:name>Alphaleonis.Win32.Filesystem.FileInfo</maml:name>
</dev:type>
<maml:description>
<maml:para>With `-PassThru`, the cmdlet writes a file object for the new link. The cmdlet writes that object type for a link to a folder as well. Without `-PassThru`, the cmdlet writes nothing.</maml:para>
<maml:para>With `-PassThru`, the cmdlet writes a file object for a new link to a file. Without `-PassThru`, the cmdlet writes nothing.</maml:para>
</maml:description>
</command:returnValue>
<command:returnValue>
@ -7308,7 +7326,7 @@ PS C:\Data&gt; Get-NTFSSecurityDescriptor</dev:code>
<maml:name>Alphaleonis.Win32.Filesystem.DirectoryInfo</maml:name>
</dev:type>
<maml:description>
<maml:para>The cmdlet does not write folder objects. A directory symbolic link is also returned as a file object.</maml:para>
<maml:para>With `-PassThru`, the cmdlet writes a folder object for a new link to a folder. Before 5.0.0, it wrote a file object for those links as well.</maml:para>
</maml:description>
</command:returnValue>
</command:returnValues>
@ -7545,16 +7563,25 @@ PS C:\Data&gt; Get-NTFSSecurityDescriptor</dev:code>
<command:returnValues>
<command:returnValue>
<dev:type>
<maml:name>System.Object</maml:name>
<maml:name>Alphaleonis.Win32.Filesystem.FileInfo</maml:name>
</dev:type>
<maml:description>
<maml:para>By default this cmdlet returns nothing. With `-PassThru` it returns an `Alphaleonis.Win32.Filesystem.FileInfo` or `Alphaleonis.Win32.Filesystem.DirectoryInfo` object for each item that it deleted.</maml:para>
<maml:para>By default this cmdlet returns nothing. With `-PassThru` it returns a file object for each file that it deleted.</maml:para>
</maml:description>
</command:returnValue>
<command:returnValue>
<dev:type>
<maml:name>Alphaleonis.Win32.Filesystem.DirectoryInfo</maml:name>
</dev:type>
<maml:description>
<maml:para>With `-PassThru` the cmdlet returns a folder object for each folder that it deleted.</maml:para>
</maml:description>
</command:returnValue>
</command:returnValues>
<maml:alertSet>
<maml:alert>
<maml:para>`Remove-Item2` deletes through the AlphaFS library (`Alphaleonis.Win32.Filesystem`), which is why it reaches items whose path exceeds the 260-character `MAX_PATH` limit of the built-in `Remove-Item` cmdlet. Deletion is permanent; the cmdlet does not use the Recycle Bin.</maml:para>
<maml:para>Before 5.0.0, `-PassThru` also wrote the item when `-WhatIf` or a declined confirmation skipped the operation.</maml:para>
<maml:para>The module defines the aliases `rm2` and `del2` for this cmdlet.</maml:para>
<maml:para>A path that does not exist causes the error `FileNotFound`, and a deletion that the file system rejects causes a `DeleteError`. In both cases the cmdlet continues with the next path. Before 5.0.0, a path that did not exist made the cmdlet skip the remaining paths that were passed in the same call.</maml:para>
</maml:alert>
@ -9508,7 +9535,7 @@ PS C:\&gt; Set-NTFSSecurityDescriptor -SecurityDescriptor $sd</dev:code>
<command:returnValues>
<command:returnValue>
<dev:type>
<maml:name>System.Object</maml:name>
<maml:name>Security2.FileSystemInheritanceInfo</maml:name>
</dev:type>
<maml:description>
<maml:para>By default this cmdlet returns no output. With `-PassThru` it writes one `Security2.FileSystemInheritanceInfo` object per item, which reports the `AccessInheritanceEnabled` and `AuditInheritanceEnabled` state after the change.</maml:para>
@ -10085,18 +10112,10 @@ PS C:\&gt; Set-NTFSSecurityDescriptor -SecurityDescriptor $sd</dev:code>
<command:returnValues>
<command:returnValue>
<dev:type>
<maml:name>Alphaleonis.Win32.Filesystem.FileInfo</maml:name>
</dev:type>
<maml:description>
<maml:para>`Test-Path2` does not write file objects. For each path it writes a single `System.Boolean` value that is `$true` when the item exists and matches `-PathType`, and `$false` otherwise.</maml:para>
</maml:description>
</command:returnValue>
<command:returnValue>
<dev:type>
<maml:name>Alphaleonis.Win32.Filesystem.DirectoryInfo</maml:name>
<maml:name>System.Boolean</maml:name>
</dev:type>
<maml:description>
<maml:para>`Test-Path2` does not write folder objects either. A folder is reported through the same `System.Boolean` result as a file.</maml:para>
<maml:para>For each path, the cmdlet writes `$true` when the item exists and matches `-PathType`, and `$false` otherwise.</maml:para>
</maml:description>
</command:returnValue>
</command:returnValues>

9
Tests/Access.Tests.ps1

@ -10,6 +10,7 @@ BeforeDiscovery {
Import-Module -Name (Join-Path -Path $PSScriptRoot -ChildPath 'TestHelpers.psm1') -Force
# With the Restore privilege, Windows may grant writing the DACL despite a deny entry.
$canBypassWriteDeny = Test-PrivilegeHeld -Name 'SeRestorePrivilege'
$holdsSecurityPrivilege = Test-PrivilegeHeld -Name 'SeSecurityPrivilege'
}
BeforeAll {
@ -55,6 +56,14 @@ Describe 'Get-NTFSEffectiveAccess' {
Set-Acl -LiteralPath $effectiveFile -AclObject $acl
}
# Before 5.0.0, the warning misspelled the privilege as "Privliege".
It 'Should warn once that the Security privilege is missing' -Skip:$holdsSecurityPrivilege {
Get-NTFSEffectiveAccess -Path $effectiveFile -WarningVariable accessWarnings -WarningAction SilentlyContinue | Out-Null
$accessWarnings | Should -HaveCount 1
$accessWarnings[0].Message | Should -BeExactly 'The user does not hold the Security privilege and might not be able to read the effective permissions.'
}
It 'Should leave out an account without access when -ExcludeNoneAccessEntries is used' {
$result = @(Get-NTFSEffectiveAccess -Path $effectiveFile -Account 'S-1-5-32-546' -ExcludeNoneAccessEntries -WarningAction SilentlyContinue -ErrorAction Stop)

25
Tests/ItemCmdlets.Tests.ps1

@ -116,6 +116,31 @@ Describe 'Copy-Item2, Move-Item2, and Remove-Item2 with several paths' {
$itemErrors | Should -HaveCount 1
Join-Path -Path $destination -ChildPath 'Second.txt' | Should -Exist
}
# Before 5.0.0, the verbose message named the source path as the destination.
It '<Command> should name the destination in the verbose message' -ForEach @(
@{ Command = 'Copy-Item2'; Verb = 'copied' }
@{ Command = 'Move-Item2'; Verb = 'moved' }
) {
$target = Join-Path -Path $destination -ChildPath 'First.txt'
$messages = & $Command -Path $first -Destination $destination -Verbose 4>&1
$messages.Message | Should -Contain ("File '{0}' {1} to '{2}'" -f $first, $Verb, $target)
}
# Before 5.0.0, -PassThru wrote the item also when -WhatIf skipped the operation.
It '<_> should write nothing with -PassThru and -WhatIf' -ForEach @('Copy-Item2', 'Move-Item2', 'Remove-Item2') {
$parameters = @{ Path = $first; PassThru = $true; WhatIf = $true }
if ($_ -ne 'Remove-Item2') {
$parameters.Destination = $destination
}
$result = @(& $_ @parameters)
$result | Should -BeNullOrEmpty
$first | Should -Exist
}
}
Describe 'Copy-Item2' {

102
Tests/OutputTypes.Tests.ps1

@ -0,0 +1,102 @@
<#
Tests the output types of the cmdlets of the module built in NTFSSecurity\bin\Release: the [OutputType] that
Get-Command reports, and the objects that -PassThru writes. Tests that need a privilege skip without it and run
in CI, whose runners are elevated.
#>
[Diagnostics.CodeAnalysis.SuppressMessageAttribute(
'PSUseDeclaredVarsMoreThanAssignments', '', Justification = 'Pester shares variables between blocks.'
)]
param ()
BeforeDiscovery {
Import-Module -Name (Join-Path -Path $PSScriptRoot -ChildPath 'TestHelpers.psm1') -Force
$holdsBackupPrivilege = Test-PrivilegeHeld -Name 'SeBackupPrivilege'
$canCreateSymbolicLinks = Test-PrivilegeHeld -Name 'SeCreateSymbolicLinkPrivilege'
$itemTypes = @('Alphaleonis.Win32.Filesystem.FileInfo', 'Alphaleonis.Win32.Filesystem.DirectoryInfo')
$declaredTypes = @(
@{ Name = 'Test-Path2'; Types = @('System.Boolean') }
@{ Name = 'Get-FileHash2'; Types = @('Alphaleonis.Win32.Filesystem.FileInfo') }
@{ Name = 'Add-NTFSAudit'; Types = @('Security2.FileSystemAuditRule2') }
@{ Name = 'Remove-NTFSAudit'; Types = @('Security2.FileSystemAuditRule2') }
@{ Name = 'Copy-Item2'; Types = $itemTypes }
@{ Name = 'Move-Item2'; Types = $itemTypes }
@{ Name = 'Remove-Item2'; Types = $itemTypes }
@{ Name = 'Enable-NTFSAccessInheritance'; Types = @('Security2.FileSystemInheritanceInfo') }
@{ Name = 'Disable-NTFSAccessInheritance'; Types = @('Security2.FileSystemInheritanceInfo') }
@{ Name = 'Enable-NTFSAuditInheritance'; Types = @('Security2.FileSystemInheritanceInfo') }
@{ Name = 'Disable-NTFSAuditInheritance'; Types = @('Security2.FileSystemInheritanceInfo') }
@{ Name = 'Set-NTFSInheritance'; Types = @('Security2.FileSystemInheritanceInfo') }
)
}
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 'OutputTypes'
Push-Location -LiteralPath $sandbox
}
AfterAll {
Pop-Location
Remove-TestSandbox -Sandbox $sandbox
Remove-Module -Name NTFSSecurity -Force -ErrorAction SilentlyContinue
}
Describe 'Declared output types' {
It '<Name> should declare the type of the objects it writes' -ForEach $declaredTypes {
@((Get-Command -Name $Name).OutputType.Name) | Should -Be $Types
}
}
Describe 'Privilege cmdlets with -PassThru' {
AfterEach {
Disable-Privileges -ErrorAction SilentlyContinue -WarningAction SilentlyContinue
}
# Before 5.0.0, -PassThru wrote the privileges as one collection.
It 'Enable-Privileges should write one object per privilege' {
$result = @(Enable-Privileges -PassThru -ErrorAction SilentlyContinue)
$result.Count | Should -BeGreaterThan 1
$result | ForEach-Object -Process { $_ | Should -BeOfType [ProcessPrivileges.PrivilegeAndAttributes] }
}
It 'Disable-Privileges should write one object per privilege' -Skip:(-not $holdsBackupPrivilege) {
Enable-Privileges -ErrorAction SilentlyContinue
$result = @(Disable-Privileges -PassThru -WarningAction SilentlyContinue)
$result.Count | Should -BeGreaterThan 1
$result | ForEach-Object -Process { $_ | Should -BeOfType [ProcessPrivileges.PrivilegeAndAttributes] }
}
}
Describe 'New-NTFSSymbolicLink with -PassThru' {
# Before 5.0.0, the cmdlet returned a file object for a link to a folder as well.
It 'Should return a folder object for a link to a folder' -Skip:(-not $canCreateSymbolicLinks) {
$folder = New-TestSandboxItem -Sandbox $sandbox -Name 'Target' -Directory
$link = Join-Path -Path $sandbox -ChildPath 'FolderLink'
Assert-TestSandboxPath -Sandbox $sandbox -Path $link
$result = New-NTFSSymbolicLink -Path $link -Target $folder -PassThru
$result | Should -BeOfType [Alphaleonis.Win32.Filesystem.DirectoryInfo]
}
}
Describe 'Cmdlet classes' {
# Before 5.0.0, these classes declared members that nothing used.
It '<_> should declare no Path property, which was never a parameter' -ForEach @(
'Enable-Privileges', 'Disable-Privileges', 'Get-Privileges'
) {
(Get-Command -Name $_).ImplementingType.GetProperty('Path') | Should -BeNullOrEmpty
}
It 'Remove-Item2 should declare no filter field' {
$flags = [System.Reflection.BindingFlags]'NonPublic, Instance'
(Get-Command -Name 'Remove-Item2').ImplementingType.GetField('filter', $flags) | Should -BeNullOrEmpty
}
}

9
Tests/Privileges.Tests.ps1

@ -59,6 +59,15 @@ Describe 'Disable-Privileges' {
$privilegeWarnings | Should -BeNullOrEmpty
Get-BackupPrivilegeState | Should -Be 'Disabled'
}
# Before 5.0.0, the verbose message said that the privileges were now enabled.
It 'Should say in the verbose message that the privileges are disabled' -Skip:(-not $holdsPrivileges) {
Enable-Privileges
$messages = Disable-Privileges -Verbose -WarningAction SilentlyContinue 4>&1
$messages.Message | Should -Contain "The privileges 'TakeOwnership', 'Restore' and 'Backup' are now disabled."
}
}
}

Loading…
Cancel
Save