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>
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>
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>
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>
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>
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>
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>
Test-MatrixCleanup.ps1 now also counts and removes the profiles and the
profile folders C:\Users\NtfsProbe* (retried, because a profile that the
last task used stays loaded for a few seconds) and the entries of the
account probe in Performance Log Users. net.exe lists a local user by its
bare name and a deleted domain account by its SID or its cached name, so
the check matches NtfsProbe anywhere in the line or a SID.
Export-CellTimeline.ps1 takes the account of a cell that stopped before its
tests from the snapshot of its fixture, so that the series can include
such a cell, and reports SameNameAsPreviousCell and SameAccountAsPreviousCell
instead of one column that compared names only.
Test-StaleAuthzModel.ps1 computes its grid of lifetimes by index (the
accumulated step lost the grid point 10.25), prints a range as segments,
and prints the range of one lifetime for both tests.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
The effective-access failures of the Admin role in the Windows Server
2022 cell don't depend on the module. A replay of seven cells with the
baseline and the final candidate alternating failed the baseline in two
of three cells and the final candidate in one of three, not counting the
warm-up. In a failing cell the remote authorization managers answer as
if the account had no groups while the name resolution, the Kerberos
logon, and the local manager are right in the same second.
One model with one lifetime (9.35 to 10.20 minutes) fits all 43 Admin
role runs of 27 cells, and none of 5,000 random assignments of the
outcomes does. Four more cells with unique account names pass, two of
them where the model predicts a failure for a reused name.
The record, the README, and a timeline CSV now say what the evidence
supports and what it doesn't establish, that the cleanup check ran with
real residue, and that fdd7a8b reverts cleanly while 962887a conflicts
with it.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
Test-MatrixCleanup.ps1 now counts and repairs the probe folders
(C:\NtfsProbeRecreation and C:\NtfsProbeModules), the local NtfsProbe*
users with their profiles, and the NtfsProbe* objects of the directory.
The scripts of the matrix default to the client OSWin11E.
Export-CellTimeline.ps1 writes one row for every cell, edition, and
Admin role: the module, the account and its relative ID, the times, and
the three effective-access tests. Test-StaleAuthzModel.ps1 replays such a
timeline against a model of the failures: the fit, a listing of the runs,
the cells of a controller that reuses the account name, and a permutation
test.
The comment in the controller says what the replay showed. The code of
the controller is unchanged.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
The record, its tables (the suite per candidate, the failing tests, and the
controller cells), and the README of the lab. The final local candidate passes the
module's suite on Windows Server 2019, 2022, and 2025, Windows 11 22H2 and 26H1,
and the host in both editions, elevated and as a basic user, and the live
controller in three cells. The record states what a local build does not prove.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
The suite runner removes its stage on a machine after it has copied the results
back; after an early stop, the stage stays for the diagnosis. The end-state check
counts the items in the stage folders and the scheduled tasks and standard users
of the kit, and -Mode Repair removes what is left of the stage and the tasks.
Probe-AccountRecreation.ps1 deletes an account and creates it again with the same
name in a loop, logs the user on with Kerberos S4U on the domain controller, the
client, and the file server, and asks Get-NTFSEffectiveAccess of each module under
test. It shows that Windows returns the old SID and groups, whichever version of
the module asks.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
When an account is deleted and created again with the same name, a Kerberos S4U
logon for it keeps returning the SID and the groups of the deleted account for
a while, on the domain controller, the client, and the file server. The matrix
deletes the fixture after each cell and creates it for the next, so the
effective-access tests of the Admin role found no access for the new account in
cells that followed within minutes (Windows Server 2022 cell, candidate and
baseline alike, shown by a probe that creates the accounts in a loop). A new
fixture now gets NtfsLiveSubject and four digits; a fixture that exists keeps
its account.
The end-state check of the matrix also reports leftover scheduled tasks, stage
folders, standard users, and probe accounts, which the review asked for.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
The review of the matrix kit found no Blocker or Major issue and these
Minor ones, all fixed here:
- Add-OsMatrixMachine.ps1 assigned the path of the AutomatedLab disk
deployment lock before it checked that the lock exists, so a refusal because
another deployment held the lock made the finally block delete that foreign
lock. The path is kept until this script has created the lock.
- Repair-OsMatrixBoot.ps1 tested the switches of the machine with an array
-ne, which is false for a machine without an adapter, so the guard that is
meant to refuse a machine outside the lab let it through and the script
turned it off. The guard counts the switches now.
- Deploy-OsMatrixLab.ps1 took the installation and domain administrator
password of the lab from Get-Random, which isn't a cryptographic generator.
It uses RandomNumberGenerator without a remainder bias, as the controller
does.
- Run-MatrixLocalSuite.ps1 removed its scheduled tasks, which store the
password of the account that runs them, only after a successful poll. The
finally block of the machine removes the tasks of the run now.
- Probe-EffectiveAccess.ps1 cleaned up the domain controller before the machine
without a try block, so a failure there skipped the cleanup of the machine.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
Probe-EffectiveAccess.ps1 runs Invoke-EffectiveAccessProbe.ps1 on one machine
of the operating-system matrix under up to four tokens and copies the output
back: the lab account in a scheduled task at the highest run level, the same
account with the token of a basic user (SAFER level Normal User), a local
standard user, and a standard user of the domain. The standard users are
created for the run with a random password that exists only in memory, get
the batch logon right through Performance Log Users, and are removed again
with their profiles and group memberships; the names carry a time stamp,
because Windows keeps the SID of a deleted account for its name for a while.
For the account of the token and for well-known SIDs and the accounts of the
domain, the probe asks the cmdlet for the default server name, localhost, an
empty name, the names of this computer, and other computers, and writes the
result, the warnings, and the native error with the failing method. It showed
that the remote interface of the authorization manager of a computer in a
domain refuses every user who isn't an administrator, which is the defect
that the previous commit fixes.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
On a computer in a domain, Get-NTFSEffectiveAccess wrote "Access is denied"
and no result for every user who wasn't an administrator of the computer,
also for the default -ServerName localhost and for every other name of this
computer. The remote interface of the authorization manager of a computer
answers only its administrators and the members of Access Control Assistance
Operators, and a computer in a domain offers that interface to every caller.
On a computer outside a domain the interface is not reachable, so the cmdlet
already used the local authorization manager there, which is why the tests
passed on the development host and on the CI runners.
For a name of this computer, the cmdlet now uses the local authorization
manager when the remote one refuses the user. That manager is the one the name
asks for, and it answered correctly in every probe on Windows Server 2019,
2022, and 2025 and on Windows 11: for a standard domain user, a local standard
user, and an administrator with a filtered token, for the user's own account,
Everyone, the Administrator of the computer, and the Administrator and Domain
Users of the domain. For the name of another computer, the denial stays an
error, as the cmdlet page and the live test of the delegated account describe.
Twenty tests of the suite failed in the basic-user mode on every domain-joined
machine of the operating-system matrix, with the published 5.0.0-rc7 code and
with the code before this change, and pass with it (Windows Server 2019: basic
user 782 and 780 passed, 0 failed, in Windows PowerShell and PowerShell 7). A
new live test runs the case as the administrator of the file server, who isn't
an administrator of the client.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
Tests\Lab\Acceptance gets the scripts of Decision 24, which extends the
acceptance of the live tests from one lab to several operating-system builds:
- Deploy-OsMatrixLab.ps1, Add-OsMatrixMachine.ps1, Complete-OsMatrixLab.ps1
and Repair-OsMatrixBoot.ps1 build NtfsSecurityOsMatrixLab with AutomatedLab
(Server 2019, 2022 and 2025 file servers, Windows 11 clients) and repair a
base image whose host-side bcdboot left an empty EFI system partition.
- Test-MatrixReadiness.ps1 and Test-MatrixCleanup.ps1 gate each run and prove
that it left nothing behind (fixture accounts, shares, folders, group
members, orphaned SIDs, profiles); -Mode Repair removes what is left.
- Run-MatrixSequence.ps1 runs the live controller for every cell of the matrix
and stops after an infrastructure failure.
- Run-MatrixLocalSuite.ps1 and Invoke-LocalSuite.ps1 run the module's own
Pester suite on each machine in both editions, elevated and as a basic user,
as scheduled tasks: a process started from a remoting session gets every
privilege enabled, which eight of the tests do not expect.
- Export-MatrixResults.ps1 collates the cells, the skipped tests and the
package hashes into the results table.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
The operating-system matrix runs on Windows Server 2019, 2022 and 2025 found
three defects in the fixture setup and removal of Invoke-NTFSSecurityLabTest.ps1:
- A native command's stderr that is redirected with 2>&1 is a terminating
error in Windows PowerShell 5.1 under $ErrorActionPreference = 'Stop'. The
first "The directory is not empty" line from PowerShell 7 ended the removal
on Server 2019 before any retry. The removal is now a bounded loop whose
PowerShell 7 command writes its errors to its output.
- Get-LocalGroupMember fails with "Failed to compare two elements in the
array" when a group holds an orphaned SID, for example that of an account an
earlier run deleted. The setup adds the members with Add-LocalGroupMember and
ignores MemberExistsException instead of checking the members first.
- A user profile that is gone in the meantime no longer fails the client
cleanup, and the retries are reported to the host.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
The independent review of the acceptance record found no Blocker or Major
issue. This commit corrects what it found: the commit that fixed the break
row, what the State test shows, the baseline failures that carry no message,
the count of results, the wording about the folders before the first run, the
truncated messages in the results file, the README row of case 10, and the
review section of the record.
The 42 messageless baseline failures are now explained by a diagnostic that
runs the bodies of those tests in a TEMP sandbox: on the base, the second item
is removed, copied, moved, re-owned, or rewritten after Select-Object -First 1
or a throw; on the candidate it stays. The diagnostic, the check of the result
files, and a read-only check of a published version are in Tests/Lab/Acceptance.
Decision 22 no longer says that Copy-Item2 is like Copy-Item for a folder: the
built-in Copy-Item creates the missing parent folders of a folder copy,
Copy-Item2 of rc6 and of the candidate doesn't. The choice stays, the reference
point is corrected, and the question is left to the maintainer. The migration
hint of item 8 is stated as it is.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
Decision 23 separates what the reporters of #34 said from what was tested
(Windows only), names the gaps, and lays out the maintainer's options: wait
for a report on the published candidate, or accept the untested risk with a
release-note caveat. It accepts nothing and keeps the gate open. It also holds
a draft comment for the issue, which the maintainer posts.
The checklist in Tests/Lab tells a storage administrator and a delegated user
how to run the commands of case 1 against a disposable folder on a NetApp, EMC,
or IBM file server, what to report, and what to keep out of the report.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
Case 10 of the lab tests checks, over SMB and on the file server, what the
fixes of ai/quality-gate-paths changed: the owner restore, InheritedFrom, a
later command that ends the pipeline or throws (also at the verbose, debug,
and error streams), Get-ChildItem2 -Filter, and the privileges that a
stopped cmdlet left enabled. The fixture adds the folders that the tests
need. 78 tests per edition are new.
The record compares the candidate 83149ee with its base f11ff41 in the lab:
the candidate passed 486 tests and failed none, the base failed 148 of the
same tests, and each of them passes on the candidate. The fixture was removed
and the end state verified independently.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
Handoff 1 of the pre-5.0.0 quality gate. The report classifies every
C# method that no test visited at 5a5d58b (231 methods, 442 sequence
points: 223 explained, 8 open for the maintainer) and records the
measurement (3,192/3,634 sequence points, 87.84%), 26 bounded
mutations, a red/green matrix of the fix commits over ten states of
the branch, the open items, the handoff to gate 3, and nine static
review passes. The CSV files hold the method, cmdlet, and parameter
set tables, the guard rows of the matrix with their test files, and
the SHA-256 of each of its 40 logs.
The Memory Bank notes (active context, progress, tech context, system
patterns) and the lab README point to it. No code, test, or help
changes.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
The tag 5.0.0-rc6 published the package to the PowerShell Gallery; the
Release job failed after the upload, because Publish-PSResource gave up
waiting while the Gallery accepted the package and its retry got 409. The
live tests downloaded the package, checked the hash of the Gallery, and
passed in both editions, except the one test whose expected warning text
5.0.0-rc7 changed. The rc6 record gets a section on the release; the run
is the baseline of the rc7 record.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
The live tests of dc6e9f5, the last commit of the branch that changes the
module, passed in both editions after the checkpoint of step 3: 326 tests,
none failed, 2 skipped as in rc6. The record names the package hashes,
the suite, the readiness of the lab, the earlier runs, and the removal of
the fixture.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
When the computer of -ServerName can't be reached, the cmdlet calculates
the result with the group memberships known on this computer and warns.
The warning now names that computer, which a command with many items
couldn't tell otherwise. The live test expects the new text as well.
Decision 22, item 5: an assumption in autopilot, flagged for the
maintainer's review.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
The acceptance ran three times, for acfe3af, 1b9edbb, and 7b0781f, the
last commit that changes the module; each run passed 326 tests in both
editions with no failure. The record now describes the run of 7b0781f,
with its hashes, readiness, checkpoint, and the checked removal of the
fixture after each run, and names the earlier runs.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
The candidate acfe3af passed the live tests in both editions with all
roles: 326 tests, none failed. The record lists the hashes of the
packages, the readiness of the lab, the checkpoint, the results, the
baseline, and the checked removal of the fixture. The published 5.0.0-rc5
fails only the two hard-link tests of case 8 on the share, the defect that
rc6 fixes.
The README of the live tests describes the acceptance of a release
candidate, and the release guide runs it before a release.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
Add the cases 4b (orphaned audit entry), 5 (owner), 6 (audit inheritance,
Clear-NTFSAudit, Get-NTFSInheritance), 7 (item cmdlets on the share),
8 (link cmdlets on the share), and 9 (Get-NTFSSimpleAccess), and the
accounts of three other domains and forests (-ForeignDomainController).
The fixture writes the folders with SetAccessControl instead of Set-Acl,
which also wrote an empty SACL and dropped the inherited audit entries.
The delegated account expects the denial of Get-NTFSEffectiveAccess
-ServerName, which the file server answers only for its administrators
and the members of Access Control Assistance Operators.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
Add Tests\Lab, which runs the module against a Windows file server with
domain accounts in an AutomatedLab lab: #34 over SMB, the audit cmdlets
over SMB, Get-NTFSEffectiveAccess with domain and file server groups,
Get-NTFSOrphanedAccess with a deleted domain account, long paths on a
share, and #108. Invoke-NTFSSecurityLabTest.ps1 prepares the lab and
runs the tests per module version and PowerShell edition; without a
lab, every live test skips. CI excludes the folder.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>