diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6c153da..c7e42d2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -74,5 +74,8 @@ The format is based on
- Fix the `InheritanceEnabled` property of audit entries, which reported the
inheritance of the access entries; it now reports whether the audit
entries are inherited
+- Fix `Get-NTFSInheritance -SecurityDescriptor`, which reported
+ `AuditInheritanceEnabled` as `$true` for a security descriptor that was
+ read without its audit section; it now reports `$null`, like `-Path`
[Unreleased]: https://github.com/raandree/NTFSSecurity/compare/4.2.6...HEAD
diff --git a/Docs/Cmdlets/Get-NTFSInheritance.md b/Docs/Cmdlets/Get-NTFSInheritance.md
index dcd0577..a9b0656 100644
--- a/Docs/Cmdlets/Get-NTFSInheritance.md
+++ b/Docs/Cmdlets/Get-NTFSInheritance.md
@@ -29,7 +29,7 @@ The `Get-NTFSInheritance` cmdlet reports whether a file or folder inherits acces
`AccessInheritanceEnabled` is `$false` when the discretionary access control list (DACL) of the item is protected, which is the state that `Disable-NTFSAccessInheritance` produces. `AuditInheritanceEnabled` reports the same for the system access control list (SACL), which holds the audit rules. When the audit section cannot be read because the session does not hold the Security privilege, `AuditInheritanceEnabled` is `$null` and its column stays empty; the access value is still reported and no error is written.
-In the `Path` parameter set the cmdlet reads the security descriptor of each item from disk. In the `SecurityDescriptor` parameter set it reads the state from the `Security2.FileSystemSecurity2` objects that `Get-NTFSSecurityDescriptor` returns, without touching the file system. Note that a descriptor that was retrieved without its audit section reports `AuditInheritanceEnabled` as `$true`, because the protection flag of a section that was never read is not set.
+In the `Path` parameter set the cmdlet reads the security descriptor of each item from disk. In the `SecurityDescriptor` parameter set it reads the state from the `Security2.FileSystemSecurity2` objects that `Get-NTFSSecurityDescriptor` returns, without touching the file system. A descriptor that was read without its audit section, because the session doesn't hold the Security privilege, reports `AuditInheritanceEnabled` as `$null`, like the `Path` parameter set.
`-Path` accepts pipeline input by value and by property name through its `FullName` alias, so the output of `Get-ChildItem`, `Get-ChildItem2`, and `Get-Item2` binds to it. Relative paths are resolved against the current location, and when no path is supplied at all, the cmdlet reports the current location.
@@ -130,6 +130,8 @@ When the module setting `EnablePrivileges` is `$true` (the default in the `Priva
Reading the audit section (SACL) of an item requires the Security privilege (`SeSecurityPrivilege`), which an account can only use in an elevated session. Without it, the cmdlet still reports the access state and sets `AuditInheritanceEnabled` to `$null` instead of writing an error.
+Before 5.0.0, a security descriptor that was read without its audit section reported `AuditInheritanceEnabled` as `$true`.
+
If the security descriptor of an item cannot be opened because the account has no permission to it, the cmdlet takes ownership of the item, reads the state, and sets the previous owner back. That fallback only succeeds when the account can take ownership of the item and restore the original owner; otherwise the cmdlet writes an error and continues with the next item.
A path that does not exist produces a non-terminating error and the cmdlet continues with the remaining paths.
diff --git a/NTFSSecurity/en-US/NTFSSecurity.dll-Help.xml b/NTFSSecurity/en-US/NTFSSecurity.dll-Help.xml
index 993a3d0..57ec507 100644
--- a/NTFSSecurity/en-US/NTFSSecurity.dll-Help.xml
+++ b/NTFSSecurity/en-US/NTFSSecurity.dll-Help.xml
@@ -5329,7 +5329,7 @@ PS C:\> Get-NTFSAudit -SecurityDescriptor $sd
The `Get-NTFSInheritance` cmdlet reports whether a file or folder inherits access rules from its parent folder and whether it inherits audit rules. For each item it writes one `Security2.FileSystemInheritanceInfo` object with the `Name`, `FullName`, `AccessInheritanceEnabled`, and `AuditInheritanceEnabled` properties, plus the underlying file system object in the `Item` property. The default table view shows `Name`, `AccessInheritanceEnabled`, and `AuditInheritanceEnabled`.
`AccessInheritanceEnabled` is `$false` when the discretionary access control list (DACL) of the item is protected, which is the state that `Disable-NTFSAccessInheritance` produces. `AuditInheritanceEnabled` reports the same for the system access control list (SACL), which holds the audit rules. When the audit section cannot be read because the session does not hold the Security privilege, `AuditInheritanceEnabled` is `$null` and its column stays empty; the access value is still reported and no error is written.
- In the `Path` parameter set the cmdlet reads the security descriptor of each item from disk. In the `SecurityDescriptor` parameter set it reads the state from the `Security2.FileSystemSecurity2` objects that `Get-NTFSSecurityDescriptor` returns, without touching the file system. Note that a descriptor that was retrieved without its audit section reports `AuditInheritanceEnabled` as `$true`, because the protection flag of a section that was never read is not set.
+ In the `Path` parameter set the cmdlet reads the security descriptor of each item from disk. In the `SecurityDescriptor` parameter set it reads the state from the `Security2.FileSystemSecurity2` objects that `Get-NTFSSecurityDescriptor` returns, without touching the file system. A descriptor that was read without its audit section, because the session doesn't hold the Security privilege, reports `AuditInheritanceEnabled` as `$null`, like the `Path` parameter set.
`-Path` accepts pipeline input by value and by property name through its `FullName` alias, so the output of `Get-ChildItem`, `Get-ChildItem2`, and `Get-Item2` binds to it. Relative paths are resolved against the current location, and when no path is supplied at all, the cmdlet reports the current location.
@@ -5426,6 +5426,7 @@ PS C:\> Get-NTFSAudit -SecurityDescriptor $sd
When the module setting `EnablePrivileges` is `$true` (the default in the `PrivateData` section of NTFSSecurity.psd1), this cmdlet tries to enable the Backup, Restore, Take Ownership, and Security privileges while it runs and disables the privileges it enabled when it finishes. These privileges are only available in an elevated session of an account that holds them, such as a member of the local Administrators group. If a privilege cannot be enabled, the cmdlet continues without it and writes a debug message.
Reading the audit section (SACL) of an item requires the Security privilege (`SeSecurityPrivilege`), which an account can only use in an elevated session. Without it, the cmdlet still reports the access state and sets `AuditInheritanceEnabled` to `$null` instead of writing an error.
+ Before 5.0.0, a security descriptor that was read without its audit section reported `AuditInheritanceEnabled` as `$true`.
If the security descriptor of an item cannot be opened because the account has no permission to it, the cmdlet takes ownership of the item, reads the state, and sets the previous owner back. That fallback only succeeds when the account can take ownership of the item and restore the original owner; otherwise the cmdlet writes an error and continues with the next item.
A path that does not exist produces a non-terminating error and the cmdlet continues with the remaining paths.
diff --git a/Security2/FileSystem/FileSystemInheritanceInfo.cs b/Security2/FileSystem/FileSystemInheritanceInfo.cs
index 1b822c9..81163db 100644
--- a/Security2/FileSystem/FileSystemInheritanceInfo.cs
+++ b/Security2/FileSystem/FileSystemInheritanceInfo.cs
@@ -94,7 +94,14 @@ namespace Security2
public static FileSystemInheritanceInfo GetFileSystemInheritanceInfo(FileSystemSecurity2 sd)
{
- return new FileSystemInheritanceInfo(sd.Item, !sd.SecurityDescriptor.AreAccessRulesProtected, !sd.SecurityDescriptor.AreAuditRulesProtected);
+ // Like for an item, the audit state is unknown when the SACL was not read.
+ bool? auditInheritanceEnabled = null;
+ if (sd.HasAuditSection)
+ {
+ auditInheritanceEnabled = !sd.SecurityDescriptor.AreAuditRulesProtected;
+ }
+
+ return new FileSystemInheritanceInfo(sd.Item, !sd.SecurityDescriptor.AreAccessRulesProtected, auditInheritanceEnabled);
}
#endregion GetFileSystemInheritanceInfo
diff --git a/Tests/Inheritance.Tests.ps1 b/Tests/Inheritance.Tests.ps1
index 8503a53..ddcde8e 100644
--- a/Tests/Inheritance.Tests.ps1
+++ b/Tests/Inheritance.Tests.ps1
@@ -26,6 +26,33 @@ AfterAll {
Remove-Module -Name NTFSSecurity -Force -ErrorAction SilentlyContinue
}
+Describe 'Get-NTFSInheritance' {
+ Context 'With a security descriptor' {
+ BeforeEach {
+ $file = New-TestSandboxItem -Sandbox $sandbox -Name 'Descriptor'
+ }
+
+ It 'Should report the same state as for the path of the item' {
+ $byPath = Get-NTFSInheritance -Path $file
+ $bySecurityDescriptor = Get-NTFSInheritance -SecurityDescriptor (Get-NTFSSecurityDescriptor -Path $file)
+
+ $bySecurityDescriptor.AccessInheritanceEnabled | Should -Be $byPath.AccessInheritanceEnabled
+ $bySecurityDescriptor.AuditInheritanceEnabled | Should -Be $byPath.AuditInheritanceEnabled
+ }
+
+ It 'Should report the audit inheritance as $null for a security descriptor without the audit entries' {
+ $sd = New-Object -TypeName 'Security2.FileSystemSecurity2' -ArgumentList (
+ (Get-Item2 -Path $file), [System.Security.AccessControl.AccessControlSections]::Access
+ )
+
+ $result = Get-NTFSInheritance -SecurityDescriptor $sd
+
+ $result.AccessInheritanceEnabled | Should -BeTrue
+ $result.AuditInheritanceEnabled | Should -BeNullOrEmpty
+ }
+ }
+}
+
Describe 'Set-NTFSInheritance' {
Context 'When -AccessInheritanceEnabled or -AuditInheritanceEnabled is omitted' {
BeforeEach {