|
|
|
|
using Alphaleonis.Win32.Filesystem;
|
|
|
|
|
using Security2;
|
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Management.Automation;
|
|
|
|
|
|
|
|
|
|
namespace NTFSSecurity.AuditCmdlets
|
|
|
|
|
{
|
|
|
|
|
[Cmdlet(VerbsCommon.Get, "NTFSOrphanedAudit")]
|
|
|
|
|
[OutputType(typeof(FileSystemAuditRule2))]
|
|
|
|
|
public class GetOrphanedAudit : GetAudit
|
|
|
|
|
{
|
|
|
|
|
int orphanedSidCount = 0;
|
|
|
|
|
|
|
|
|
|
protected override void ProcessRecord()
|
|
|
|
|
{
|
|
|
|
|
if (ParameterSetName == "SD")
|
|
|
|
|
{
|
|
|
|
|
foreach (var sd in securityDescriptors)
|
|
|
|
|
{
|
fix: drive roots, audit descriptors, -WhatIf conflicts, and small items
- #41: for the root of a drive, the cmdlets read and changed the security
descriptor of the drive, a device object. FileSystemSecurity2 now routes
drive roots through the path-based AlphaFS methods, which keep the
trailing backslash; the removal and inheritance helpers use it too.
- #109: Add-, Remove-, and Clear-NTFSAudit report a security descriptor
without the audit entries like Get-NTFSAudit, through one helper, and
Get-NTFSEffectiveAccess names the cause that Windows reported instead
of a missing Security privilege.
- #108: Copy-Item2 and Move-Item2 check the destination only for an
operation that runs; with -WhatIf, a verbose message names the conflict.
- #111: Disable-Privileges skips the privileges that the token doesn't
hold, the privilege messages are spelled right, and Get-FileHash2
declares the type name of its objects; 05-Releasing.md documents the
release metadata tests.
- rc3 review leftovers: Remove-NTFSAudit writes nothing for an item
without a SACL, the owner retry of Set-NTFSSecurityDescriptor restores
the previous owner in a finally block and keeps an owner that the
descriptor sets, and FileSystemSecurity2.Write with another item writes
only the sections that were read.
Each fix has a test that failed first, in Windows PowerShell 5.1 and
PowerShell 7; writing a drive root was checked once on a temporary VHD.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
4 weeks ago
|
|
|
if (!TestAuditSection(sd))
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
WriteOrphanedAces(FileSystemAuditRule2.GetFileSystemAuditRules(sd, !ExcludeExplicit, !ExcludeInherited, getInheritedFrom), sd.FullName);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach (var p in paths)
|
|
|
|
|
{
|
|
|
|
|
FileSystemInfo item = null;
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
item = this.GetFileSystemInfo2(p);
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
this.WriteError(new ErrorRecord(ex, "ReadError", ErrorCategory.OpenError, p));
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
IEnumerable<FileSystemAuditRule2> acl = null;
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
acl = FileSystemAuditRule2.GetFileSystemAuditRules(item, !ExcludeExplicit, !ExcludeInherited, getInheritedFrom);
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
this.WriteWarning(string.Format("Could not read item {0}. The error was: {1}", p, ex.Message));
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Outside the try block, so that a stopped pipeline isn't reported as a read error.
|
|
|
|
|
WriteOrphanedAces(acl, p);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void WriteOrphanedAces(IEnumerable<FileSystemAuditRule2> acl, string path)
|
|
|
|
|
{
|
|
|
|
|
var orphanedAces = acl.Where(ace => string.IsNullOrEmpty(ace.Account.AccountName));
|
|
|
|
|
if (Account != null)
|
|
|
|
|
{
|
|
|
|
|
orphanedAces = orphanedAces.Where(ace => ace.Account == Account);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var orphanedAceList = orphanedAces.ToList();
|
|
|
|
|
orphanedSidCount += orphanedAceList.Count;
|
|
|
|
|
|
|
|
|
|
this.WriteVerbose(string.Format("Item {0} knows about {1} orphaned SIDs in its ACL", path, orphanedAceList.Count));
|
|
|
|
|
|
|
|
|
|
// One object per entry, not one collection per item
|
|
|
|
|
orphanedAceList.ForEach(ace => WriteObject(ace));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected override void EndProcessing()
|
|
|
|
|
{
|
|
|
|
|
WriteVerbose(string.Format("Total orphaned Access Control Enties: {0}", orphanedSidCount));
|
|
|
|
|
base.EndProcessing();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|