mirror of https://github.com/raandree/NTFSSecurity
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
9.0 KiB
9.0 KiB
| status | last-verified | owner | source |
|---|---|---|---|
| current | 2026-10-09 | active-agent | repository and regression evidence |
System patterns
Architecture
| Component | Responsibility |
|---|---|
NTFSSecurity.psd1 |
Root script, nested binary, initialization, types, help |
NTFSSecurity.Init.ps1 |
Loads Security2/privilege assemblies and prepends formatting |
NTFSSecurity.dll |
36 PowerShell cmdlets; BaseCmdlet path/privilege behavior |
Security2.dll |
DACL/SACL objects, owners, inheritance, effective access, Win32 |
| AlphaFS | Long-path files/directories/links |
| PrivilegeControl / ProcessPrivileges | Token privilege operations |
en-US/NTFSSecurity.dll-Help.xml |
Committed help generated from cmdlet Markdown |
Decisions
Read only task-relevant records; the index controls routing.
Patterns
Cmdlets and security sections
- BaseCmdlet resolves relative paths against the current filesystem location; file-object input binds FullName through path transformation.
- Write only changed/read sections (Decision 19); a descriptor parameter
changes memory until
Set-NTFSSecurityDescriptorpersists it. - Access denial can retry through InvokeAsOwner; restore the previous owner on every exit, except a successful descriptor write that intentionally sets the owner. Restoration failures must report RestoreOwnerError.
- Privilege cleanup runs in EndProcessing and Dispose, reads current states, attempts all cleanup, and preserves explicit enables. Dispose has no stream.
- Pipeline getters never throw; per-item errors name input and allow continuation.
- Folder moves never use CopyAllowed; preserve cross-volume source folders.
- Apply implied Hidden/Force before deciding to emit, including the first item.
- A catch-all for the failures of one item must pass on what a later command
raises through a Write call. A downstream throw is an ordinary exception,
so a type check finds only the end of the pipeline, break, and continue.
BaseCmdlet notes the exception that its WriteObject, WriteError,
WriteVerbose, and WriteDebug raised (WriteWarning is not noted: no catch-all
encloses it);
IsFromLaterCommandrecognizes it, and the type checkPipelineControl.IsEndbacks it up for other calls into PowerShell. A write inside a helper, such as the owner restore ofInvokeAsOwner, is an accepted gap: its handler reports the item's own error, which raises too. Prefer writing outside the try.Tests/PipelineControl.Tests.ps1has rows for every cmdlet: add a row for a new one, and keep the typed-throw rows (they fail if PowerShell stops wrapping a thrown exception). - Record an enabled privilege before the next write, which a later command can answer with an exception: Dispose disables only what is recorded.
Get-ChildItem2 -Filterhas two matchers: the AlphaFS enumeration, whose dot rules also differ from those ofGet-ChildItem(probe:Report.*andRep*.in both editions), and a PowerShell wildcard on the name, where only*and?are special.*.*is treated as*; the other dot patterns are pinned byItemCmdlets.Testsand are an open maintainer decision.
Tests and documentation
- Tests import Release in isolated processes, both editions and privilege modes. File/ACL/link fixtures use shared sandbox guards and cleanup. Privilege-dependent skips must have eligible counterparts in the matrix.
- Assert persisted state, errors/targets, continuation, and no failed PassThru output. Prove new characterization guards with bounded mutations; restore source exactly and rebuild before green validation or packaging. Apply the mutations of one round together only when no guard can fail because of another mutation; otherwise split the rounds.
- A test that arranges a retry asserts its precondition (the plain write is denied), or it can pass without reaching the retry.
- A test variable must not take the name of an automatic variable such as
$foreach: Pester runs the block inside a foreach, and the value is lost. - The CI scripts set
$ErrorActionPreference = 'Stop'; focused runs do the same, and a test that needs a non-terminating error (for example to take it through2>&1) names-ErrorAction Continue. - Fixture DACLs use .NET SetAccessControl, not Set-Acl's unintended SACL writes.
- Scope/descendant expectations are independent of the production converter.
- Drive-root tests map a sandbox folder with
substthroughNew-TestDriveMapping(elevated only; the basic token cannot). Tests that need a letter without a volume take the lowest free one. - Desktop platyPS: generate help, rebuild, round-trip unchanged, check links. platyPS 0.14.2 turns a pair of asterisks in a paragraph into emphasis, also inside backticks, and the help drops them: write the words, put patterns in example code blocks, and check the generated XML.
- Live tests use only approved lab targets, SMB then independent server state; Get/SetFileSecurity preserves stored DACLs; rights oracles use S4U tokens.
- A suite that is green on the development host and on CI says little about a feature that the environment lacks. The matrix found three defects that every earlier run had missed because the host is outside a domain and the CI runner's token differs: run the suite on a domain member, on other builds, and as a basic user before a release, and classify a failure by a probe under the real tokens (elevated, filtered, local standard, domain standard) before calling it a defect or a design.
- A fixture that deletes an account and creates it again with the same name
gets the old SID and groups from Kerberos S4U logons (the oracle of the live
tests, and the Authz functions behind
Get-NTFSEffectiveAccess) on the domain controller and on member servers for more than seven minutes, and no cache flush helped (a ticket purge renews only the session's own token). A failure that follows the order of the cells and not the version of the module points to such state: run a loop probe with the baseline and the candidate side by side before blaming the code. The controller names the account of case 3 anew for each new fixture.
CI results and publication
- Use Path.Combine then GetFullPath for a rooted-or-repository-relative result path; Join-Path appends even a rooted child and corrupts it.
- Discovery handles only expected PackageNotFound as absence; repository, authentication, and network errors remain failures.
- Rerun/uncertain-upload success requires Gallery SHA-512 equality with the exact build artifact. Base64 is case-sensitive: use ordinal comparison. Missing/different/unverifiable metadata preserves the upload error.
- Secrets stay by environment reference, never in process arguments/logs. Test all external publication commands with mocks; no test may upload.
- AltCover aggregates all four sequential runs without --save. Report sequence points, not unique source lines; keep unmatched paths visible.