mirror of https://github.com/raandree/NTFSSecurity
Tree:
62cf026e6e
master
4.2.6
4.2.4
4.2.3
5.0.0-rc9
5.0.0-rc8
5.0.0-rc7
5.0.0-rc6
5.0.0-rc5
5.0.0-rc4
5.0.0-rc3
5.0.0-rc2
5.0.0-rc1
${ noResults }
201 Commits (62cf026e6e206f6db1f564985ca7c987998e11f2)
| Author | SHA1 | Message | Date |
|---|---|---|---|
|
|
62cf026e6e |
fix(owner): pass on what a later command raises at the RestoreOwnerError record
InvokeAsOwner (and Set-NTFSSecurityDescriptor's WriteChangesAsOwner) take
ownership of an item, run the action, and in a finally restore the
previous owner, writing a non-terminating RestoreOwnerError through
WriteError when that restore fails. WriteError runs the later commands
of the pipeline while it writes, so in the rare case that a later
command throws exactly when it sees that RestoreOwnerError record (for
example `... 2>&1 | ForEach-Object { if ($_.FullyQualifiedErrorId -like
'RestoreOwnerError,*') { throw } else { $_ } }`), that exception used to
leave InvokeAsOwner through the finally and reach the handler around the
call, which reported it as the item's own error (AddAceError,
ReadSecurityError, ModifySdError, and so on) and moved on to the next
path. The caller never saw the exception.
Thirteen handlers now check IsFromLaterCommand as the first statement of
their catch, the same pattern SetSecurityDescriptor.cs already used in
its second handler and GetSecurityDescriptor.cs already used: Add/Clear
and Get-NTFSAccess, Get-NTFSOrphanedAccess, Get-NTFSEffectiveAccess,
Clear-NTFSAudit, Get-FileHash2, the six inheritance cmdlets, and the
owner-retry of Set-NTFSSecurityDescriptor. The four add/remove access and
audit cmdlets have the same flaw and belong to another work item.
Tests\PipelineControl.Tests.ps1 adds one table-driven It, elevated only,
that denies the current user the right a cmdlet's action needs, gives
the item an owner only the Restore privilege can set back (which the
test turns off), and asserts that a later command's exception reaches
the caller, no item-error record was written for it, and the next path
is untouched. Six of the thirteen handlers are pinned this way (the
other seven need the current user to both fail and succeed the same
access check at once, which Windows does not allow; see the comment
above the Describe block and the probes under ..\probes-wi2\ for the
empirical evidence). The four add and remove cmdlets, which have the same
flaw, follow in the next commit of this item.
Get-NTFSInheritance, the one of the thirteen that writes its result in a
finally, writes it after the try instead, so that the object does not go to
the later command that has just thrown.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
|
2 weeks ago |
|
|
dbd671763b |
docs(items): split -Filter paragraphs for platyPS, sharpen the PowerShell 7 claim, fix -Path wording
An independent review found that platyPS 0.14.2, which generates the shipped help file from these pages, pairs up every two literal asterisks within one paragraph as markdown emphasis and drops them, even inside backticks: the -Filter parameter description and the matching paragraph of NOTES each had three or four literal asterisks in one paragraph, so `Get-Help Get-ChildItem2 -Parameter Filter` and the NOTES section showed `Report. ` instead of `` Report.* `` and ` . ` instead of a plain asterisk pattern, silently losing the character that the sentence was about. Both paragraphs are now several short paragraphs, each with at most one literal asterisk; a pattern that itself needs more than one asterisk, such as a plain asterisk, a dot, and an asterisk, is spelled out in words instead, the way the page already did before this feature. Verified by running `New-ExternalHelp` from platyPS 0.14.2 into a temporary folder (not the repository's help file) and confirming every pattern renders intact in the generated XML, then removing the folder. The same two paragraphs also said PowerShell 7's own `Get-ChildItem -Filter` returns nothing for any pattern that ends in a dot and returns every item only for a pattern of an asterisk, a dot, and one question mark. Measured directly on PowerShell 7.6.7, both overstated the difference: a trailing dot returns nothing there only when the character right before the dot is not an asterisk (a star right before the dot behaves the same as Windows PowerShell 5.1 and as Get-ChildItem2 there too), and a pattern of an asterisk, a dot, and two question marks also returns every item, not only one question mark. Both paragraphs now say exactly that. Also removed "(Decision 27, item 4)" from both paragraphs and from two test comments (the maintainer's agent already removed it from the integration branch; this avoids a conflicting edit), and changed one sentence of the DESCRIPTION section that said every -Path value must name a folder: a value that names a file returns that file, as the PARAMETERS section and NOTES already said and the cmdlet already did. No test changes: these are documentation wording changes only, and the page keeps its existing structure (headings, parameter block, NOTES list). Re-ran Tests\ItemCmdlets.Tests.ps1 (no code changed in this commit) to confirm the suite is still green: elevated-Desktop 193/0/0, elevated-Core 192/0/1, basic-Desktop 187/0/6, basic-Core 186/0/7 (passed/failed/skipped), three times, identical. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com> |
2 weeks ago |
|
|
2deec1761b |
fix(items): reject a -Filter of more than 32,767 characters
An independent review found that a very long -Filter pattern (for
example, a run of 120,000 question marks, or 45,000 asterisks) crashes
the whole host process with an uncatchable StackOverflowException: the
matcher recurses roughly once per character of the pattern, and a long
enough pattern exhausts the stack. A pattern this long serves no
purpose that a shorter one could not also serve, and the review
confirmed that patterns of 32,767 characters or fewer, of any shape
(literal, "?" repeated, "*" repeated, "*?" repeated, "*." repeated),
do not come close to exhausting the stack.
Added `[ValidateLength(0, 32767)]` next to the existing
`[ValidateNotNull]` on -Filter, so that a pattern longer than 32,767
characters is rejected at parameter binding, before it ever reaches
the matcher, with the same `ParameterArgumentValidationError` and
`'Filter'` in the message as the existing null rejection; shorter
values, including an empty one, are unaffected.
Tests (Tests\ItemCmdlets.Tests.ps1, "Get-ChildItem2" > "Recursion, type
filters, and depth"): a -Filter of 32,768 characters now gives
ParameterArgumentValidationError, and one of exactly 32,767 characters
("?" repeated, in a folder with one file) returns the right result
without crashing. The crash itself was confirmed in a disposable child
process (not through the shared Pester harness, to avoid taking that
process down too) with the reviewer's probe
(C:\Temp\ntfs-rc9\review-probes-r3\p9-longpattern.ps1 -N 120000 -Kind
qm): the process terminated with a StackOverflowException before this
fix, and after it, the same probe at the exact boundaries (32,767 and
32,768 characters, every pattern kind the probe offers) neither
crashes nor is accepted past the limit.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
|
2 weeks ago |
|
|
ab2fb87f1f |
fix(items): let an asterisk before a dot in -Filter cross every dot but the last
An independent review found that the matcher of Get-ChildItem2 -Filter
(commit 69cd8ed) bounded a star in front of a dot token at the FIRST
dot of the name instead of the LAST one (Win32 DOS_STAR). The
differential oracle of 69cd8ed used only 8.3-compliant names, which
have at most one dot, so the first dot and the last dot are always the
same position there and the bug could not show up. With a name that
has two or more dots, such as "archive.tar.gz" or "jquery.min.js", the
star stopped too early and the rest of the pattern could not reach the
final segment of the name, so a pattern such as "*.?", "*.??", or
"*.?.?" wrongly returned nothing for these names, although Windows
PowerShell 5.1 returns them.
What a user sees changing: -Filter patterns of the shape "a star
followed by a dot" (including "*.?", "*.??", "*.???", a star in a
multi-part pattern such as "a*.?" or "x.*.?") now also match names
with two or more dots, the same as Windows PowerShell 5.1, in both
editions. A name with at most one dot is unaffected (that case was
already correct).
Fixed by bounding the star at `name.LastIndexOf('.')` instead of the
first dot at or after the current position, and corrected the two
comments that described the old, narrower rule.
Also added a discriminating row to the existing short-name test
(`-Filter 'LONGFI~1*'` against a plain file named `LongFileName`,
expected to return nothing): the three rows already in that test
happen to give the same result whether the matcher reads the real
name or the short name, so they could not have caught a regression to
short-name matching; this row can.
Tests (Tests\ItemCmdlets.Tests.ps1, "Get-ChildItem2" > "Recursion, type
filters, and depth"): added a 9-row test with 10 names that have two or
three dots (including the realistic ones from the review: archive.tar.gz,
jquery.min.js, my.file.name.txt, v1.2.3, index.d.ts), expected values
pinned from Windows PowerShell 5.1 with `fsutil file setshortname` (and,
for one row, `fsutil 8dot3name strip`) so that a short name the volume
assigns cannot also produce a match; and the LONGFI~1* row above. Both
fail on the build of 69cd8ed and pass after this fix.
The fix was checked with the reviewer's differential harness
(C:\Temp\ntfs-rc9\review-probes-r3\diff5.ps1) against this build: 0
mismatches over two independent fixtures (732,630 real-name/pattern
pairs with names of two or more dots, short names overridden with
`fsutil file setshortname` so that a hit can only come from the real
name), in addition to the 109,308 pairs of 8.3-compliant names checked
for 69cd8ed.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
|
2 weeks ago |
|
|
522fd7fa06 |
fix(items): match -Filter of Get-ChildItem2 with the dot rules of Windows PowerShell 5.1
Get-ChildItem2 -Filter now applies a single matcher, in the cmdlet, that
follows the Win32 "DOS" wildcard rules Windows PowerShell 5.1 applies to
Get-ChildItem -Filter, on the real name of the item, in both editions
(Decision 27, item 4, option B). Before this change the pattern was
matched twice: once by the AlphaFS enumeration and once by the cmdlet
with a WildcardPattern that read a dot as an ordinary character, so the
two editions, and Get-ChildItem itself, disagreed on patterns with a
dot. AlphaFS now always enumerates with "*", and the new matcher decides
alone.
What a user sees changing:
- "Report.*" also returns "Report", which has no dot (previously only
names with a dot matched a pattern ending in ".*").
- A pattern that ends in a dot, such as "Report." or "Rep*.", now
returns the names without a dot, instead of nothing.
- "*.*.*" now returns every item, the same as "*.*" and a plain "*",
instead of only names with two literal dots.
- Breaking: an empty -Filter ('') now returns every item, like no
filter at all, instead of nothing. This matches the policy of
Windows PowerShell 5.1 for every other dot pattern; a script that
relied on an empty -Filter returning nothing should pass -Filter '*'
explicitly to keep that behavior from before.
- A single dot ('.') as -Filter also returns every item, matching
Get-ChildItem.
- Get-ChildItem2 deliberately no longer follows PowerShell 7's own
Get-ChildItem -Filter for a pattern that ends in a dot (which there
returns nothing) or for "*.?" (which there returns every item): it
follows the Windows PowerShell 5.1 rules in both editions instead, so
the two editions of Get-ChildItem2 agree with each other.
- Unaffected: -Filter matching by the real name and not the 8.3 short
name, brackets and backticks as ordinary characters, case-insensitive
matching with the invariant culture, the null-Filter error, and every
other parameter and its interaction with -Filter.
The matcher was derived and checked against a differential oracle of
real Windows PowerShell 5.1 Get-ChildItem -Filter runs: two independent
sets of 8.3-compliant names (22 and 19 names) against 54,654 generated
patterns each (alphabet a, b, c, ., *, ? up to length 6; the remaining
1,333 of the 55,987 generated patterns per set are refused by the .NET
enumeration API itself for ending in ".." and are not part of either
product's -Filter semantics), with zero differences in both sets.
Tests (Tests\ItemCmdlets.Tests.ps1, "Get-ChildItem2" > "Recursion, type
filters, and depth"):
- Changed the dot-rules table (pins the new values for "Report.*",
"Report.", "Rep*.", "*.", and an empty -Filter) and the dedicated
"*.*.*" test (now expects every item), both of which pinned the old,
changed-on-purpose behavior.
- Added three rows to the existing short-name-sensitive test, to pin
that the new matcher still reads the real name, not the short name,
for the trailing-dot and "X.*" rule families.
- Added a 36-row truth table (22 fixed 8.3-compliant names, patterns
from every family the WI calls out) with the literal result of
Windows PowerShell 5.1 as static, hand-verified data; the test runs
no Get-ChildItem of its own.
- Added -Recurse with a selective -Filter across three folder levels,
a dot -Filter with -File and -Directory, an empty -Filter, and a
-Filter on a -Path that names a file.
Docs\Cmdlets\Get-ChildItem2.md: restated the -Filter parameter
description and the matching note in NOTES with the Windows PowerShell
5.1 policy and the deliberate PowerShell 7 difference, and removed the
sentences that described the dot rules as a limitation or a mismatch
with Get-ChildItem in Windows PowerShell 5.1.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
|
2 weeks ago |
|
|
e060c24f4d |
fix(security2): keep a descriptor without an item usable by the cmdlets that take a security descriptor
PowerShell's parameter binder uses the conversion that 3.1 fixed for every -SecurityDescriptor parameter, so a descriptor that Get-Acl returns, never meant for these cmdlets, now binds where it used to be a binding error. Two more consequences of that surfaced: With the default module setting GetInheritedFrom ($true), Get-NTFSAccess, Get-NTFSAudit, Get-NTFSOrphanedAccess, and Get-NTFSOrphanedAudit stopped with the InvalidOperationException that a previous fix added for a descriptor without an item; a cmdlet user has no parameter to avoid it. GetFileSystemAccessRules and GetFileSystemAuditRules now treat getInheritedFrom as false for such a descriptor instead of throwing: the entries come back with no source, the same as an entry whose source Windows cannot name. The private constructor that wraps a descriptor directly marked every section, including Audit, as read; Get-Acl never reads Audit unless -Audit is given. This made HasAuditSection wrongly report true, so the existing #109 check let Get-NTFSAudit go on with no audit data instead of reporting that the descriptor has none, and let Get-NTFSInheritance report AuditInheritanceEnabled as a real value instead of null (unknown). The constructor now includes Audit in the sections only when the descriptor's binary form actually carries a SACL, the same test HasSystemAcl already uses. Get-NTFSOwner, Get-NTFSSimpleAccess, Get-NTFSOrphanedAccess, Get-NTFSEffectiveAccess, and Add-/Remove-NTFSAccess with such a descriptor already worked; Set-NTFSSecurityDescriptor already reported a clear, non-terminating error. A review finding on the earlier fix is also addressed: two assertions read a property through reflection instead of a plain PowerShell property access, which silently turns a throwing getter into $null without a trace and so could not tell a getter that throws from one that legitimately returns null. Every existing behavior for an item that is not null is unchanged. Public signatures are unchanged. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com> |
2 weeks ago |
|
|
3f146b8e52 |
fix(security2): let the readers handle a descriptor that has no item
3.1 made a FileSystemSecurity2 without an item reachable from a .NET caller (the conversions from FileSecurity and DirectorySecurity), but six sibling call sites still dereferenced the item without checking it first, so a caller who converted a FileSecurity or DirectorySecurity and then read its entries, owner, inheritance, or effective access met a NullReferenceException instead of a usable result. GetFileSystemAccessRules and GetFileSystemAuditRules (the FileSystemSecurity2 overload) now give each returned entry the same null FullName that the descriptor itself reports; asking for the source of an inherited entry (getInheritedFrom) needs the path of the item, so it now throws one clear InvalidOperationException instead, naming the reason, when the descriptor has none. FileSystemOwner and FileSystemInheritanceInfo give a null FullName (and Name) the same way; FileSystemOwner.ToString, which must never return null, gives an empty string instead, since there is no other representation to fall back to. The FileSystemAccessRule2(rule, item) constructor, which EffectiveAccess.GetEffectiveAccess uses to build its result, now accepts a null item the same way, so effective access can be calculated for such a descriptor and the result names no path. Every existing behavior for an item that is not null is unchanged; only a .NET caller that reads such a descriptor can notice the difference, and only for the better: a usable result or a clear error instead of an unrelated NullReferenceException. Public signatures are unchanged. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com> |
2 weeks ago |
|
|
b69b21e14b |
fix(privileges): report a malformed EnablePrivileges setting with one clear error
BaseCmdletWithPrivControl.BeginProcessing and EndProcessing read (bool)privateData["EnablePrivileges"] without checking it first; a setting that is not a Boolean, such as the string '$true' from a typo in the module manifest, or a missing key, made every cmdlet derived from the class fail with an InvalidCastException or a NullReferenceException before anything useful was said. Enable-Privileges had its own try/catch for the same cast that raised a different message (a ParseException), but it was unreachable, because BeginProcessing always failed first. A new helper, GetEnablePrivilegesSetting, centralizes the check in the base class: a setting that is missing or not a Boolean now stops the cmdlet with one terminating error, id EnablePrivilegesSettingInvalid, category InvalidData, that names the setting, says it must be $true or $false, and names the module manifest. BeginProcessing, EndProcessing, and Enable-Privileges all use it now; the dead try/catch of Enable-Privileges is removed, so a mistaken setting no longer produces two different messages depending on which cmdlet hit it first. The valid settings $true and $false keep today's behavior. GetInheritedFrom (used by Get-NTFSAccess and Get-NTFSAudit), GetFileSystemModeProperty, and IdentifyHardLinks (both used by Get-ChildItem2) read their own setting the same unchecked way and share this weakness; they are not changed here; see the final report. Breaking: a script that caught the old InvalidCastException, NullReferenceException, or ParseException for a malformed EnablePrivileges setting now needs to catch the terminating error with id EnablePrivilegesSettingInvalid instead. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com> |
2 weeks ago |
|
|
a0362c359c |
fix(security2): make the path overloads of AddFileSystemAccessRule and AddFileSystemAuditRule write at once
AddFileSystemAccessRule(string, List<IdentityReference2>, ...) and AddFileSystemAuditRule(string, List<IdentityReference2>, ...) were iterator methods (yield return), so nothing happened until the caller enumerated the result: called as a statement, or assigned to a variable that the caller never reads, they changed nothing. Their siblings, the overloads for FileSystemInfo and FileSystemSecurity2 with a list, and the single-account overloads, already built a list and wrote at once. Both overloads now build the list and add the entries before returning, like their siblings; a call that is never enumerated now adds the entries just the same. An exception that adding an entry raises changes only in timing: it is now thrown by the call itself, not by the later enumeration of its result. The returned collection still holds one rule per account, in the order of the account list, for both a file path and a folder path. Public signatures are unchanged. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com> |
2 weeks ago |
|
|
a0a97d971e |
fix(security2): honor the account list of RemoveFileSystemAccessRuleAll and RemoveFileSystemAuditRuleAll
Both methods built a LINQ query that filtered the explicit entries down to the ones whose account was in the given list, but never used the result: the loop right below removed every explicit entry of the descriptor regardless of the list, including an empty one. The cmdlets never pass a list, so only a .NET caller of Security2.dll that does is affected. A non-null list now removes only the explicit entries whose account is one of the listed accounts (compared like the rest of the class does, by IdentityReference2 equality of the entry's SID); null still removes every explicit entry, and an empty list now removes none. Inherited entries are still never touched, as before. Both the FileSystemSecurity2 overload (in-memory only, until a caller writes the descriptor) and the FileSystemInfo overload (which also writes) are fixed, for access and audit entries alike. Public signatures are unchanged. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com> |
2 weeks ago |
|
|
987334e415 |
fix(security2): keep the descriptor in the conversions from FileSecurity and DirectorySecurity
Converting a FileSecurity or DirectorySecurity object to FileSystemSecurity2 (for example `[Security2.FileSystemSecurity2] $fileSecurity`) always threw, because the conversion ignored the descriptor it was given and built the result from an empty path, which AlphaFS rejects. The conversion now wraps the descriptor that was passed: SecurityDescriptor is that same instance, IsFile reflects whether it came from a FileSecurity or a DirectorySecurity, the round trip back to FileSecurity/DirectorySecurity returns the same instance, and Equals/GetHashCode keep comparing descriptors by reference. The resulting object has no item, since it was never read from a file or folder: FullName and Name are now null instead of throwing a NullReferenceException, and Write() throws a clear InvalidOperationException instead of a NullReferenceException deep in SetSecurity. A caller can still write such an object by setting its Item property first, or by calling Write(FileSystemInfo) or Write(string) directly, neither of which depends on an item being set. No cmdlet reaches this conversion; only a .NET caller of Security2.dll that converts a FileSecurity/DirectorySecurity it built itself is affected. Public signatures are unchanged. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com> |
2 weeks ago |
|
|
899fdf49b9 |
docs(coverage): record the CI run of the tests-only round
The CI of #129 ran the new tests on the GitHub runner (windows-2025, run 39551726767): the four configurations gave the counts of the local run with no failure, and each of the 29 test files has the same number of executed and skipped cases as in the local run. The report said that the runner had not run the tests yet; it now gives the result and states the one thing that is still open, that the new cases ran on Windows Server 2025 only. The Evidence CSV lists the log and the four NUnit files of the run, whose retention on GitHub ends. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com> |
2 weeks ago |
|
|
d28c7a06c7 |
test(coverage): report the tests-only round and what is left
Adds the report of the tests-only round of the quality gate: 89 new It blocks that run as 121 cases per configuration, so that the suite goes from 1,494 to 1,615 cases per configuration with no failure in Windows PowerShell 5.1 and PowerShell 7, elevated and as a basic user. The ParameterSets CSV has the 64 rows with the status before and after: 38 are closed (7 before), 26 have something left (16 Limit, 7 MaintainerDecision, 3 would-pin), and the report names every leftover. The Evidence CSV lists the files outside git with size and SHA-256. No product code, cmdlet page, or CI file changes. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com> |
2 weeks ago |
|
|
404cecad33 |
test(inheritance): close budget gaps for no-op, OpenError category, and unchanged-section pins
Adds 15 It blocks (25 instances, Tests\ParameterSets.Inheritance.Tests.ps1) closing the budget items of worklist-inheritance.md rows 1-16: - The documented no-op / current-location behavior without -Path, pinned with Push-Location into a dedicated sandbox folder, for Disable/Enable-NTFSAccessInheritance, Disable/Enable- NTFSAuditInheritance, Set-NTFSInheritance, Get-NTFSOwner, Set-NTFSOwner, and Get-NTFSSecurityDescriptor. - The OpenError category for a path that does not exist, for Disable/Enable-NTFSAccessInheritance and Set-NTFSInheritance. - Owner unchanged after Disable-NTFSAccessInheritance -SecurityDescriptor protects the DACL; an independent Get-Acl -Audit oracle for Set-NTFSInheritance; the -RemoveInheritedAuditRules / -RemoveExplicitAuditRules switches on a -SecurityDescriptor with the owner and DACL confirmed unchanged after the write. - The Name property and a DACL protected without the module for Get-NTFSInheritance (-Path and -SecurityDescriptor); Get-NTFSOwner on a descriptor read without its Owner section; the SACL unchanged after Set-NTFSOwner changes the owner; the DACL unchanged and the -PassThru type for Set-NTFSOwner -SecurityDescriptor. - The by-property-name pipeline and the category/target of the -PassThru ReadSecurityError for Set-NTFSSecurityDescriptor. Every assertion reads state with an independent .NET oracle (Get-Acl, Get-Acl -Audit) or asserts an ErrorId/category/target triple; none repeats an existing test. Items marked Limit, would-pin, or lab in the worklist are out of scope and untouched. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com> |
2 weeks ago |
|
|
9a2a8096e4 |
test(items): cite the doc for the Move-Item2 -Force folder-replace comment
Points the comment at Move-Item2.md's -Force and Notes sections, which document the overwrite as a replace, instead of only describing the probe that showed it. No test logic changed. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com> |
2 weeks ago |
|
|
e32e36a9ba |
test(items): close budget gaps for item, link, disk-space, and privilege cmdlets
Adds pipeline/positional binding, long-path, bracket/wildcard literal-path, drive-root, omitted-path-default, and error category/target coverage for Copy-Item2, Get-ChildItem2, Get-Item2, Move-Item2, Remove-Item2, Test-Path2, Get-FileHash2, and Get-DiskSpace; positional binding, FileInfo pipeline input, and share-error category coverage for New-NTFSHardLink and Get-NTFSHardLink; positional binding and folder LinkType/target coverage for New-NTFSSymbolicLink; and -PassThru privilege-state coverage for Enable-Privileges and Disable-Privileges. No product code changed. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com> |
2 weeks ago |
|
|
472003e49e |
test(access): close budget parameter-set gaps for the access cmdlets
Add 20 new It blocks (32 executed cases once the 13-scope -ForEach of Add-NTFSAccess/SDSimple expands) to ParameterSets.Access.Tests.ps1, closing every REMAINING item that worklist-access.md marks budget for rows 1-13: - Add-NTFSAccess: several accounts and positional binding (PathComplex); a Deny entry's exact rights with no auto-added Synchronize (PathComplex and PathSimple); a denied write and a Deny entry without rights through PathSimple; all 13 -AppliesTo scopes of a security descriptor read back with .NET, piped and several (SDSimple); piped and several descriptors asserted for Add itself, not only as a fixture (SDComplex). - Remove-NTFSAccess: the -PassThru output's count against the complete survivor list for several piped paths; several accounts and positional binding (PathComplex); a Deny entry's rights-reduction without -RemoveSpecific; a missing and a denied path, piped, several (PathSimple); rights-reduction without -RemoveSpecific and disk independence until Set-NTFSSecurityDescriptor, piped and several descriptors (SDSimple); the on-disk write-through only after Set-NTFSSecurityDescriptor, piped and several descriptors (SDComplex). - Get-NTFSAccess: what the cmdlet returns without -Path, asserted on an actual emitted object's type (Path). - Get-NTFSOrphanedAccess: the category of ReadSecurityError after a failed ownership retry (Path); -ExcludeInherited and an entry added to a descriptor only in memory (SD). - Get-NTFSSimpleAccess: the category and target of a missing path's ReadError (Path). - Get-NTFSEffectiveAccess: one call combining a failing and a succeeding path (Path). Items the REASON marks MaintainerDecision, Limit, or would-pin are left untouched, per the group notes of the brief. No product code changed. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com> |
2 weeks ago |
|
|
7c3de81f2f |
test(audit): close budget gaps for Add/Remove/Clear/Get-NTFSAudit and Get-NTFSOrphanedAudit
Closes the eight remaining 'budget' parameter-set gaps that Quality-Gate-Unknowns-2026-10-10-ParameterSets.csv lists for the audit cmdlets, in Tests\ParameterSets.Audit.Tests.ps1 only: - Add-NTFSAudit PathComplex: binds -Account (several accounts) and -AuditFlags from a single piped object's property names in one call. - Remove-NTFSAudit PathComplex: removes for several accounts named in one call, and leaves the empty Audit SDDL and the DACL unchanged for an item that has no SACL. - Remove-NTFSAudit SDSimple and SDComplex: proves the item on disk keeps its audit section until Set-NTFSSecurityDescriptor writes the change, and that -PassThru returns FileSystemAuditRule2 objects for both sets. - Clear-NTFSAudit Path: asserts the cleared state of the succeeding path that follows a missing one in the same pipeline. - Get-NTFSAudit SD: asserts the output's type, account, rights, flags, and inherited state directly, independent of the Path set's output. - Get-NTFSOrphanedAudit Path: adds the OpenError category of the ReadSecurityError without the Security privilege (PermissionDenied needs a remote/lab target and is not in scope), and -ExcludeExplicit. - Get-NTFSOrphanedAudit SD: adds -Account and -ExcludeInherited/ -ExcludeExplicit filters against a piped security descriptor. Every new test reads state back with an independent oracle (Get-Acl -Audit or the .NET SACL-only accessor), and the Set-NTFSSecurityDescriptor cases confirm the SD cmdlets change the item only in memory. The owner retry after access denied (Limit) and the open maintainer item on exceptions from the SD change itself (MaintainerDecision) are left out, as the worklist directs. 9 new It blocks (10 executed cases; one is split SDSimple/SDComplex by -ForEach) were verified test-first: a mutated copy with one flipped expectation per new It failed only those 10 cases in the configurations where they run, and nothing else; three repeated runs of the real file in all four configurations (Windows PowerShell 5.1 and PowerShell 7, elevated and basic user) gave identical, all-green results; and Invoke-ScriptAnalyzer reports nothing, matching the base commit's file. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com> |
2 weeks ago |
|
|
b39eeac0e7 |
test(lab): record the acceptance of the published 5.0.0-rc8
The published rc8 passed the identity check (tag, CI run, Gallery hash, GitHub zip), the three cells of the operating-system matrix (1,374 passed, 0 failed, 12 skipped, every end state CLEAN), the module's own suite on six machine classes (24 runs, 0 failed, the same skipped tests as the host), and the first lab with case 9 (245 passed, 0 failed, 1 skipped per edition, CLEAN). The counts of the live controller equal those of the published rc7, and the live tests and the controller are the same Git blobs, so the cells measure the changed module. The record also shows that the boundary of the new GetEffectiveAccessError, a computer name of 32,718 characters, holds on Windows Server 2019, 2022, and 2025 and on Windows 11 26H1, which backs the wording of the CHANGELOG and the cmdlet page. The four tables follow the record of the published rc7. The README names the record and says that saved machines are restored first, the domain controllers before the others. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com> |
2 weeks ago |
|
|
e2e9324eb9 |
chore(release): prepare 5.0.0-rc8
Set the prerelease label to rc8 and add 5.0.0-rc7, which the PowerShell Gallery has had since 2026-10-10, to the versions that the Gallery has (Docs/Contributing/05-Releasing.md). A separate commit, so that it can be dropped if the changes of this branch go into another prerelease instead. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com> |
2 weeks ago |
|
|
25fe77500e |
fix(access): report what the initialization of the authorization manager throws
Get-NTFSEffectiveAccess returned no access and no error when Windows refused
to start the authorization manager for the computer of -ServerName.
Win32.GetEffectiveAccess ignored what the initialization threw (an outer
catch { }), so the result looked like an account without any rights. It
reproduces on Windows Server 2025 in both editions with a name of 32,718
characters or more, which fails with error 14, where a shorter name gets RPC
server unavailable and falls back to this computer.
One try/catch now records every exception, and the cmdlet writes a
GetEffectiveAccessError. The warning that the result is based on this computer
comes only with a result now: it also preceded an error, such as for an
account that Windows can't resolve when the computer can't be reached, which
the cmdlet page and the lab tests contradict.
Two tests failed first in Windows PowerShell 5.1 and PowerShell 7, as an
administrator and as a basic user, and pass in all four configurations. The
cmdlet page, the help file, and the CHANGELOG say what changed.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
|
2 weeks ago |
|
|
52022a99fd |
docs(coverage): report the fix of the piped AppliesTo, its reviews, and the acceptance of the final package
The report of Handoff 5 now tells what came after the final measurement of 61e936e: - why a piped AppliesTo was dropped for a path (the default parameter set), the fix (93ed2c7), the defect of that fix that the third independent review found (the scope of a piped object reached the next one, 9783d2a), and the corrections of what the documents said about empty and unconvertible values (7bc7925, 2112ee3); - three independent reviews and two checks of the third reviewer, with every finding and its resolution, including the seven Minor findings of the second check of 7bc7925 and of this report; - the red and green runs of the tests, among them the runs of the tests of the CSV route on the build before the fix and on 93ed2c7; - the measurements of 9783d2a, 7bc7925, and 2112ee3 (1,492 cases per configuration, 3,266 of 3,668 sequence points, the same 183 unvisited methods) on the bytes of one build; - the acceptance of the final package in the labs: the first lab (245, 0, 1 per edition), the unit suite on the three file servers and the client (16 configurations, 1,189 cases each), and the three cells of the matrix lab (229, 0, 2 per edition), every end state clean; and the first start of the cells, which did nothing because the command that I had given the maintainer did not set the module path. The Runs, Evidence, and ParameterSets tables are regenerated. The lines that the ParameterSets table cites are mapped to the tests of 6143545. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com> |
3 weeks ago |
|
|
a14e5b5040 |
docs(lab): warn that powershell.exe started from PowerShell 7 inherits its module path
A cell of the matrix did nothing when the maintainer started Run-MatrixSequence.ps1 with Start-Process powershell.exe from a PowerShell 7 session: Windows PowerShell 5.1 inherits the PSModulePath of PowerShell 7, cannot load Microsoft.PowerShell.Utility from it, the script stops at its first call of Get-FileHash, and a hidden window leaves no log. The README of the lab kit now says to start the scripts in a Windows PowerShell window, or from PowerShell 7 to set the module path to the three WindowsPowerShell folders first. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com> |
3 weeks ago |
|
|
6143545ff3 |
test(audit): claim only what the AmbiguousParameterSet rows assert
The follow-up review of 7bc7925 found that the two rows added with the fix of the piped AppliesTo (an object with AppliesTo and InheritanceFlags, piped to Add-NTFSAudit and to Remove-NTFSAudit) said that they change nothing but compared the DACL, which these cmdlets never write. The older row of the named call to Add-NTFSAudit had the same title and the same comparison. A rejected call fails while the parameters bind, before ProcessRecord, so the error is the behavior under test. The three rows now say and assert the error only. The rows of the access cmdlets compare the DACL, which is what those cmdlets write, and stay as they are. The focused run of the two ParameterSets files on the package of 9783d2a passes in the four configurations (89 cases; 88, 88, 53, 53 passed). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com> |
3 weeks ago |
|
|
7bc7925d33 |
docs(access,audit): say what an empty or null AppliesTo does, and test the Import-Csv route
The follow-up review of 9783d2a found that "an empty AppliesTo fails to bind", in the changelog entry and in the four cmdlet pages, holds only for $null. A blank cell that Import-Csv reads is an empty string, which the binder cannot convert: PathSimple does not bind, and the row gets the default scope, as an object without the property does. An AppliesTo that is not the name of a scope is ignored the same way (probe p-empty-appliesto.ps1, both editions, on the package of 9783d2a and on the baseline). Only $null fails to bind, with ParameterArgumentValidationErrorNullNotAllowed, for that object. The pages, the help file, and the changelog entry now say so. The tests of the CSV route read a CSV file with Import-Csv, the route that the documentation shows, instead of ConvertFrom-Csv of strings, which makes a trailing blank cell $null. They pin the blank cell as the default scope and the $null object as a binding error for that object only, with the other objects processed. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com> |
3 weeks ago |
|
|
9783d2af4d |
fix(access,audit): keep the scope of a piped object from reaching the next one
Independent review of 93ed2c7: ProcessRecord of Add-NTFSAccess, Remove-NTFSAccess, Add-NTFSAudit, and Remove-NTFSAudit wrote the scope that it converts from AppliesTo into the fields behind InheritanceFlags and PropagationFlags. PowerShell resets only the parameters that the previous piped object bound, so the next object that had no scope, or only one flag, took the scope of the one before it: AppliesTo ThisFolderOnly, then none gave None/None twice, and Remove left the InheritOnly part of every entry. Without the default set (93ed2c7) a piped path object with AppliesTo reaches that code; for a piped -SecurityDescriptor object it was a defect of rc7 already. The flags of a record are locals now. The loop of the two Remove cmdlets converted the scope a second time into the same fields; the locals make that redundant, so it is gone. The tests pipe objects with and without a scope, a CSV file, and descriptor objects into the four cmdlets: red on the build of 93ed2c7 (8 of 87 cases of the two files, in every elevated configuration; 4 in the basic-user ones, where the audit rows skip), green on this build. An empty AppliesTo cell fails to bind for that row only; a test pins it. The Remove-NTFSAudit PathSimple row cannot tell the sets apart (its entry is on a file), and its comment says so. Docs/Examples.md no longer says that a scope is needed so that PowerShell can choose the parameter set (true before 5.0.0 only); the changelog entry names the new errors. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com> |
3 weeks ago |
|
|
93ed2c7da4 |
fix(access,audit): bind the AppliesTo property of a piped object for paths
Add-NTFSAccess, Remove-NTFSAccess, Add-NTFSAudit, and Remove-NTFSAudit declared PathComplex as the default parameter set. An object that had Path, Account, and AccessRights satisfied the mandatory parameters of the default set, so PowerShell never tried PathSimple and the cmdlet dropped the AppliesTo property of the object. Since 4b1abc9 made -AppliesTo mandatory in the Simple sets, the default set is redundant for every call that names its parameters, and it masked PathSimple for the pipeline. Without a default set, an object that has AppliesTo binds PathSimple, one that has InheritanceFlags or PropagationFlags binds PathComplex, and one that has neither binds PathComplex with the default scope. An object that has AppliesTo and InheritanceFlags now fails with AmbiguousParameterSet, like the same two named parameters. Named calls, -SecurityDescriptor calls without AppliesTo, and the round trip Get-NTFSAccess | Add-NTFSAccess keep their behavior. The tests pipe objects of each shape and fail without the change. The cmdlet pages and the help file follow the build. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com> |
3 weeks ago |
|
|
88ed362455 |
test(items): assert that Get-ChildItem2 restores the culture of the caller
The tr-TR test reset the culture in its own finally block, so a cmdlet that did not restore it, or that wrote an item inside the scope of the invariant culture, would still pass. The test now reads the culture in the next pipeline stage for each item and once more after the call. Both mutations fail it: writing the item inside the scope, and leaving the scope without restoring the culture. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com> |
3 weeks ago |
|
|
21188b1c3e |
docs(coverage): drop four environments from scope and record the AppliesTo cause
The maintainer decided on 2026-10-11 that Server Core, ARM64, a localized operating system, and non-Windows file servers are not needed by the audience of the tool. They leave the open items, the completion matrix, and the limits of the report, and Decision 25 records the choice (Decision 23 and #34 are not changed). Open item 3 of the report now gives the cause of the dropped AppliesTo for a path: the default parameter set PathComplex wins when a piped object satisfies its mandatory parameters. A stand-alone model with the four sets and no default binds PathSimple for an object with AppliesTo and keeps every named call; the real cmdlets were not changed. debugging-insights.md keeps the lesson. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com> |
3 weeks ago |
|
|
b25a12770d |
docs(coverage): report the final measurement and review of Handoff 5
The final commit 61e936e was built once, at 8a625c8, and measured on those bytes: 1,459 cases per configuration, 3,258 of 3,664 sequence points, 1,090 of 1,168 explicit branch points, and the same 187 unvisited methods, all classified. The first lab accepts the final build (245 passed, 1 skipped per edition), the 22 files of the matrix suite pass on Windows Server 2019, 2022, and 2025 and on Windows 11 in 16 configurations, and both labs are clean. The report adds the second culture defect that the independent review found (Get-ChildItem2 -Filter in tr-TR), the review and how each finding was resolved, the probe that tells which parameter set binds for a piped AppliesTo, and the corrected description of the branch summary of the tool, which adds one point per method and is not read. The Runs table lists every run, the Evidence table hashes the evidence outside git, and the ParameterSets table cites the lines of the final tests. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com> |
3 weeks ago |
|
|
61e936e80f |
test(items,audit): resolve the findings of the independent review of the tests
Items: the comparison of Get-Privileges with whoami compares the State only
where whoami prints the English words, because the column is localized. The
rows 'as an array with an empty element' of Copy-Item2 and Move-Item2 now pass
an array: a switch unrolls @(''), so they had passed the plain empty string. The
empty-path rows of both cmdlets run in a folder of their own, so that a guard
that regressed would copy or move an empty folder and not the sandbox into
itself.
Audit: a piped AppliesTo property does not select PathSimple, the default set
PathComplex binds and the property is dropped (a descriptor object does select
SDSimple), so the rows named PathSimple bound PathComplex. The PathSimple rows
of Add-NTFSAudit and Remove-NTFSAudit now name -AppliesTo and pipe the rest,
and the Add rows use a folder and assert the scope of the new entry (None, not
the default ContainerInherit and ObjectInherit). The descriptor rows assert the
entry in the descriptor and, after Set-NTFSSecurityDescriptor, on disk.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
|
3 weeks ago |
|
|
fbe02896ef |
fix(items): run the enumeration of Get-ChildItem2 with the invariant culture
The change of the previous commit was necessary but not enough. AlphaFS 2.2 also matches the filter: it builds a case-insensitive regular expression from it that takes the culture of the thread when it is created. With tr-TR the enumeration itself returned nothing for index* in a folder with Index.txt, in both editions (Directory.EnumerateFileSystemEntries of AlphaFS returned an empty list, .NET returned Index.txt), so the new test still failed on a build that had the previous change alone. The enumeration, that is the creation of the enumerator and every MoveNext, now runs with the invariant culture, which is restored before an item reaches the pipeline, so that no later command sees it. No other cmdlet passes a pattern of the user to AlphaFS. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com> |
3 weeks ago |
|
|
0028ccd232 |
fix(items): match the filter of Get-ChildItem2 without the culture of the thread
With the culture of the thread tr-TR, the case-insensitive WildcardPattern that compares each name with the filter treats I and i as different letters. The enumeration had already matched the name without regard to the culture, so the cmdlet dropped the items whose names differ from the filter in the case of an I: -Filter 'index*' returned nothing for Index.txt, and -Filter '*.ini' did not return SETTINGS.INI. Both editions. The independent review of the coverage report found it; the scan of culture-sensitive calls had not listed WildcardPattern. The test sets the culture of the thread to tr-TR. On the previous build it fails in the four configurations (3 of 134 cases of ItemCmdlets.Tests.ps1: index*, *.ini, and *.INI; INDEX* is the control). The pattern is now WildcardOptions.CultureInvariant. The changelog entry of the identity comparison named the operator -eq, which tr-TR never affected (probes on the previous build: -eq, -contains, and -in return True for every case); it now names the method Equals. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com> |
3 weeks ago |
|
|
bea855e498 |
docs(coverage): record the lab acceptance of the fixed build and the state of Handoff 5
The report gets the section on the acceptance of the fixed build in the first lab (both editions 245 passed, 0 failed, 1 skipped), the matching row of the completion matrix, and the bullet of the summary. The Memory Bank carries the Handoff 5 evidence, the coverage baselines and the live-coverage method. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com> |
3 weeks ago |
|
|
f1f3d8f078 |
test(inheritance): read the SACL alone where a test asserts the audit protection flag
Get-Acl -Audit reads the SACL together with the other sections. On a domain member (Windows Server 2019, 2022, and 2025 of the operating-system matrix) that read reports the SACL of an item without audit entries as protected from inheritance, where the read of the SACL alone and Get-NTFSInheritance report it as not protected (FileSystemSecurity2 documents the same difference). The test 'Disable-NTFSAuditInheritance -SecurityDescriptor should take two piped descriptors ...' asserted the on-disk flag of a fresh file with Get-Acl -Audit, and failed in all six elevated configurations of the three file servers. Diagnostic runs on 2019 and 2025 show both reads side by side. Four more assertions read the flag of an item that ends without audit entries and expect "protected"; there they could not tell a written flag from none. The five assertions now read the SACL alone through .NET, as the module does. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com> |
3 weeks ago |
|
|
5788b72e19 |
docs(coverage): report of the coverage unknowns of the quality gate and its tables
Handoff 5: the coverage of rc7 (fa0701b), the live tests and a domain member, the judged matrix of the 64 parameter sets and the tests that it led to, the cultures, and the final commit. The tables are the unvisited methods, the cmdlets, the reconciliation, the parameter sets, the mutations, the roles of the live suite, the cultures, and the runs. The evidence table follows with the lab acceptance of the fixed build. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com> |
3 weeks ago |
|
|
b2cb47b5a0 |
test(lab): run the parameter-set test files in the suite of the operating-system matrix
Run-MatrixLocalSuite.ps1 stages the behavior test files of the repository. Add the four ParameterSets files of the quality gate (access, audit, inheritance, items), so that the next acceptance proves them on every machine, in both editions, elevated and as a basic user. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com> |
3 weeks ago |
|
|
994506d864 |
test(items): pass the hash algorithm of a comparison in a variable
The analyzer flags -Algorithm MD5 as a broken hash algorithm. The test compares the output of Get-FileHash2 with Get-FileHash and uses no hash for security, so the algorithm comes from a variable, like the data of FileHash.Tests.ps1. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com> |
3 weeks ago |
|
|
35a929ac66 |
test(inheritance): assert the parameter sets that the judged matrix found untested
Close the TestNeeded gaps of judged-inheritance.csv for the inheritance, owner, and security-descriptor cmdlets (Disable/Enable-NTFSAccessInheritance, Disable/Enable-NTFSAuditInheritance, Get/Set-NTFSInheritance, Get/Set-NTFSOwner, Get-NTFSSecurityDescriptor) in one new file, Tests\ParameterSets.Inheritance.Tests.ps1. 20 new It blocks (48 data rows) assert, in the matrix's priority order: - State: independent Get-Acl/Get-Acl -Audit oracles for access and audit inheritance transitions, the -RemoveInherited/-RemoveExplicit switches with a -SecurityDescriptor, Set-NTFSInheritance setting both flags in one call, and Set-NTFSOwner leaving the Access entries and group unchanged. - Error: ErrorId/category/target triples for a denied write, a missing path, a denied read, and a refused owner, each continuing to the next item; RestoreOwnerError for the three Path cmdlets that protect or set access inheritance, which had none before. - Pipeline: every -Path and -SecurityDescriptor set that no existing test piped, including the direct, named Get-NTFSOwner -SecurityDescriptor call the scan could not classify, and the documented Set-NTFSInheritance round trip. No existing test file, helper, or production source changed. Validated test-first (each new assertion checked for a real, failable precondition) and proven with 10 one-statement C# mutations in a separate, discarded worktree: 9 detected, 1 honestly undetected (ValueFromPipelineByPropertyName alone still binds Get-ChildItem2 output through its native FullName property, so removing ValueFromPipeline from -Path is invisible to an object-only pipeline test). All four configurations (elevated/basic user x Windows PowerShell 5.1/PowerShell 7) pass with zero failures; audit- and Restore-privilege-dependent rows skip in basic user and run elevated. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com> |
3 weeks ago |
|
|
ef45b388c7 |
test(access): assert the parameter sets that the judged matrix found untested
Adds Tests/ParameterSets.Access.Tests.ps1, closing the TestNeeded rows of paramsets/judged-access.csv for Add-NTFSAccess, Remove-NTFSAccess, Clear-NTFSAccess, Get-NTFSAccess, Get-NTFSOrphanedAccess, Get-NTFSSimpleAccess, and Get-NTFSEffectiveAccess: 20 new It blocks (26 executed cases) covering pipeline binding (ValueFromPipeline and ValueFromPipelineByPropertyName, including positional file/folder objects), -PassThru combined with one denied and one succeeding path, error ErrorId/category/target for read and write failures, continuation after a per-item error, state read back with .NET (not -PassThru/Get-NTFSAccess), SecurityDescriptor-set pipelines and memory-vs-disk behavior, and the declared output types and PathSimple/SDSimple vs PathComplex/SDComplex parameter-set boundaries. No row with GapKind=MaintainerDecision is pinned: the -SecurityDescriptor sets of Add/Remove keep their open per-item error behavior untested either way. Finding: a plain piped object with an AppliesTo property does not steer Add-NTFSAccess/Remove-NTFSAccess to the PathSimple/SDSimple parameter set by itself; PowerShell resolves the ambiguity to the default set (PathComplex/ SDComplex) and silently drops the unmatched property. The proposed test for that exact shape (notes section (b), item 2c) could not be written as specified; the pipeline test for PathSimple instead binds -Path through the pipeline while -AppliesTo is named explicitly, which does select the set. Validated in all four configurations (elevated/basic user, Windows PowerShell 5.1/PowerShell 7): 26 passed, 0 failed, 0 skipped in each. Eight one-statement production mutations across all seven cmdlets were applied in an isolated worktree, built, and run against this file; each was detected by at least one new test, then the source was restored exactly and rebuilt. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com> |
3 weeks ago |
|
|
3fa5adeb0c |
test(audit): assert the parameter sets that the judged matrix found untested
Add Tests\ParameterSets.Audit.Tests.ps1, closing the TestNeeded gaps that judged-audit.csv/judged-audit-notes.md recorded for Add-NTFSAudit, Remove-NTFSAudit, Clear-NTFSAudit, Get-NTFSAudit, and Get-NTFSOrphanedAudit: - Pipeline binding by value and by property name for every parameter set of all five cmdlets, including the four sets the matrix flagged as bound only by splat or pipe calls (Add-NTFSAudit SDSimple, Remove-NTFSAudit PathSimple and SDSimple, Get-NTFSOrphanedAudit SD), each of which also gets a direct, named call. - Continuation past a failing path or a descriptor without an audit section, asserting the ErrorId, category, and target of the error and the state or output of the item that follows. - State assertions beyond -PassThru: SACL/DACL SDDL before and after, the in-memory descriptor versus the item on disk until Set-NTFSSecurityDescriptor writes it, and the protected/unprotected SACL after Clear-NTFSAudit -DisableInheritance. - Narrowing of an audit entry's rights when Remove-NTFSAudit runs without -RemoveSpecific, and the AmbiguousParameterSet error when -AppliesTo and -InheritanceFlags are combined. No production code, existing test file, or helper module changed. Fixture DACLs use .NET SetAccessControl through the existing TestHelpers.psm1 helpers; no test pins the open item of the -SecurityDescriptor sets of Add and Remove having no per-item handler around the change itself. Verified in all four configurations (elevated/basic user x Windows PowerShell 5.1/PowerShell 7): 0 failures. Mutation-tested with 9 one-statement changes to the production C# in a separate, detached worktree; 8 were caught by the new tests and one (the -AppliesTo-to-flags conversion for the Simple sets, masked on a file target) was not, which the pre-existing PermissionScopes.Tests.ps1 already catches on a folder target. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com> |
3 weeks ago |
|
|
112db810e0 |
test(items): assert the cmdlets that the judged matrix found untested
Add Tests\ParameterSets.Items.Tests.ps1, closing TestNeeded gaps the judged parameter-set matrix found for Copy-Item2, Get-ChildItem2, Get-Item2, Move-Item2, Remove-Item2, Test-Path2, Get-FileHash2, Get-DiskSpace, New-NTFSHardLink, Get-NTFSHardLink, New-NTFSSymbolicLink, Enable-Privileges, Disable-Privileges, and Get-Privileges: - Pipeline input by value for Copy-Item2, Move-Item2, Get-ChildItem2, Get-Item2, and Remove-Item2 (never exercised before), including continuation past a missing item and AlphaFS objects piped from Get-ChildItem2. - An empty string, $null, a piped empty string, or an empty array element for -Path/-Target is rejected by ValidateNotNullOrEmpty and never falls back to the current location, for Copy-Item2, Move-Item2, Remove-Item2, New-NTFSHardLink, and New-NTFSSymbolicLink. Verified by running against the built module in both PowerShell editions before being pinned. - Get-NTFSHardLink error categories, output type, and positional binding. - Pipeline continuation (Select-Object -First 1) for New-NTFSHardLink and New-NTFSSymbolicLink, and a successful link after an earlier failure in the same New-NTFSSymbolicLink call. - Enable-Privileges and Disable-Privileges error paths (SecurityError, Security2.AdjustPriviledgeException), runnable on any token. - Get-DiskSpace with a valid and an invalid drive letter together in either order, and positional/lower-case binding. - Get-Privileges compared against whoami /priv for the five privileges that both name the same way. - Get-FileHash2 pipeline objects with -Algorithm, and a locked path before a valid one with its error category and a relative-path hash. Every It asserts persisted state, an ErrorId/category/target, continuation, or an output type; none asserts only an English message. All four runtime configurations (elevated/basic user x Windows PowerShell 5.1/PowerShell 7) pass with 0 failures; two symbolic-link-privilege-gated tests skip on the basic-user configurations and run on both elevated ones. Mutation testing against 8 one-statement changes in a separate, discarded worktree confirmed each targeted test fails for the right reason; production sources were restored exactly after every mutation and no production code changed here. Does not pin the Get-ChildItem2 -Filter dot rules, the Decision 22 link and move/copy behaviors, the PrivilegeEnabler class, or the owner-restore handlers. A probe of Get-NTFSHardLink and New-NTFSHardLink -PassThru through a subst-mapped drive found a pre-existing defect (reported separately, not fixed or pinned here): both combine the apparent drive root with the volume-relative hard-link names from Windows, which throws FileNotFoundException once the drive's root differs from the real NTFS volume root. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com> |
3 weeks ago |
|
|
419cfb3f6c |
fix(identity): compare an identity with a name without the culture of the thread
IdentityReference2.Equals(string) lowercased both names with ToLower(), which uses the culture of the thread. In tr-TR, I becomes U+0131, so an account whose name holds an uppercase I (NT AUTHORITY\SYSTEM, BUILTIN\Administrators) no longer matched the same name in another case, for example $entry.Account -eq 'nt authority\system'. Compare with StringComparison.OrdinalIgnoreCase. The test sets the culture of the thread to tr-TR and compares the system account with its name in three cases. Before the fix it fails in all four configurations (elevated and basic user, Windows PowerShell 5.1 and PowerShell 7); after it, all rows pass. The unit suite under tr-TR did not find it, because no test compares a name that holds an uppercase I. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com> |
3 weeks ago |
|
|
22ee60abcc |
docs(lab): state the manifest of the evidence without a file count
The manifest was refreshed after the final log line and the exit file were added, so a fixed count in the record would be wrong. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com> |
3 weeks ago |
|
|
425e903796 |
test(lab): record the acceptance of the published 5.0.0-rc7
The published prerelease passed every stage of the lab acceptance on 2026-10-10, with the counts of the final local candidate: the three cells of the operating-system matrix (1,374 passed, 0 failed, 12 skipped), the module's own suite in 24 runs on six machine classes without a failure, and the first lab with case 9 (245 passed, 0 failed, 1 skipped per edition). Every end state was verified clean. Each controller run used the package that the identity check had verified byte for byte. Add the record with four tables, link it from the lab README and describe the order of the stages, which follows the one-hour life of the evaluation client. Update Decision 24, the progress, the active context, and the deployment notes for the state after the acceptance. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com> |
3 weeks ago |
|
|
49734efb35 |
docs(lab): record the findings of the security review
The built-in security-review agent (the custom security-reviewer still can't start: its model isn't offered, and it wasn't overridden) read the branch and found no exploitable vulnerability in the module changes. It reported two LOW items that are not changed and are left for the maintainer: the swallowed initialization exceptions of GetEffectiveAccess (older than the fixes and not reproducible on any machine of the matrix) and the ACL of the stage folders under C:\ in the lab kit. The record, the Memory Bank, and the next steps say so, and the record says how the decision of "this computer" was tested. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com> |
3 weeks ago |
|
|
7019247655 |
test(lab): justify the plain-text conversions of the kit and say how far Repair reaches
The four ConvertTo-SecureString -AsPlainText calls of Probe-EffectiveAccess.ps1 and Run-MatrixLocalSuite.ps1 get a SuppressMessageAttribute with a justification, as the controller already has for the same case: the lab installation password comes from the AutomatedLab lab definition and the passwords of the probe users are random and exist only in memory. The header of Test-MatrixCleanup.ps1 says that Repair matches the prefixes of the kit in the whole domain and on the whole machine, which the security review pointed out, and that an unresolved S-1-5-21-* member of Performance Log Users can be a real principal of a trust that is down. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com> |
3 weeks ago |
|
|
246cf5f27d |
docs(lab): record the dry run of the -Version path of the sequence runner
Run-MatrixSequence.ps1 -Version 5.0.0-rc6 ran once on OSFile19 in Windows PowerShell as a dry run. The controller used the published module, the validation reported LIVE_RESULT_NOT_ACCEPTED as it must (151 passed, 78 failed, 2 skipped: the live tests that rc6 predates), and the cleanup verdict was CLEAN. It tests the mechanics and accepts nothing. The deployment notes say how to pass the file servers and when to start the evaluation client. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com> |
3 weeks ago |
|
|
b78784d07f |
docs(lab): state the scope of the cleanup sweep and what the replay shows
The second follow-up review found no Blocker and no Major, and four Minors that are corrected. Test-MatrixCleanup.ps1 and the README say that every unresolved S-1-5-21-* member of Performance Log Users counts as an entry of the probe; a Verify with the new script found none on the two machines of the first lab. The record says that the replay shows that the module doesn't decide the outcome and that six runs can't rule out a small effect, which the result bullet and the summary of the evidence had left out; it lists the first-lab counts among its tables, names the controller blob of rc7d, says that the first-lab check ran before the profile and log-group fields existed, counts nine restarts inside the series, and mentions the first attempt of the cleanup test that died. The controller comment says "for the baseline and for the final candidate alike" instead of "whichever version"; no code changed. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com> |
3 weeks ago |
|
|
70f494a651 |
docs(lab): correct the record after the follow-up review and add the first-lab run
The follow-up review found no Blocker and no Major, and five Minors, all verified against the raw logs and all corrected: rc7e's first cell was 4.6 minutes after the removal of rc7d, which created and removed accounts without a test (the timeline now includes rc7d); one lifetime that fits both tests is 9.95 to 10.25 minutes, not 9.35 to 10.20; the client restarted at 05:34, which matters for the counterfactual of ab7 only; and five statements that the record's own data contradicted (the age of the entries in failing and passing cells, the blob of the live tests of the replay, the exporter's scope, the folders that the check counts, and the blob of the controller of ab7 to ab10). The record says that six replay runs cannot rule out a small effect of the module, that the window of the client test is 0.3 minute wide, and that the cleanup check ran with real residue of every kind. The final candidate also passed the live controller in the first lab, where case 9 runs: 245 passed, 0 failed, 1 skipped per edition, with the fixture removed and verified clean. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com> |
3 weeks ago |