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 module's own tests ran on Windows Server 2019, 2022, and 2025 and on
Windows 11 in the operating-system matrix. Two tests failed on every
domain-joined machine and passed on the development host:
- Get-NTFSInheritance -SecurityDescriptor reported AuditInheritanceEnabled
as $false for an item without audit entries, where -Path reported $true.
On these computers Windows reports the SACL as protected from
inheritance when it reads all sections together, and as not protected
when it reads the SACL alone. The descriptor now takes the audit section
from a separate read, like it already did for the access section. Write()
stores the sections that were read, so a descriptor with the wrong flag
would also have written the SACL back as protected.
- Get-NTFSEffectiveAccess -ServerName '' wrote an "Access is denied"
error on computers where Windows takes an empty name for this computer.
An empty name no longer asks the remote interface of the authorization
manager; the cmdlet warns and returns the result of this computer, like
for any name that can't be reached.
The existing tests that found them stay as the regression guards: they were
red on three virtual machines (Windows Server 2022 and 2025, Windows 11)
and are green after the change. Three tests are new: the audit state of a
file and a folder without audit entries, and of a file and a folder with
disabled audit inheritance, by path and by descriptor.
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>
The maintainer delegated open decisions to the agent on 2026-10-09 ("do it and
report about it later"). The agent checked the ten choices of Decision 22
against the source, the tests, the cmdlet pages, and the changelog, and
confirmed all of them. The record lists the impact for a caller and the
documentation of each choice, and says how to revert one. Its status stays
proposed until the maintainer confirms it.
The Memory Bank notes the repeated lab acceptance of the paths fixes and the
lesson about proving a fix with a baseline run.
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 comment above the recording Write methods of BaseCmdlet named three
cmdlets that call ShouldProcess in a try block; only Remove-Item2 does.
The Get-ChildItem2 page now says that the dot rules of the matching can
differ, not that they differ, and the generated help follows. No test and
no executable code changes.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
The cmdlet page said that the AlphaFS enumeration alone decides which names match, while the code compares each returned name with the pattern again; both apply, and the page now says so. The comment of PipelineControl said that every Write method is noted, but WriteWarning is not, and it names ShouldProcess as an example of an unnoted call. The changelog entries about the privileges name the cmdlets that enable them for the duration of their command, because Enable-Privileges keeps them enabled by design.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
The independent review of the delta found the tests below weak. The verbose and debug rows of PipelineControl ran their command without an error action; the CI runner sets Stop, under which the handler that reports a later command's exception as an item error ended the pipeline with it, so the mutations that stop recording the verbose or the debug exception escaped (M19 in two configurations, M20 in all four). The rows now say -ErrorAction SilentlyContinue. The Enable-Privileges tests for a script named NTFSSecurity.Init.ps1 could not fail for the branch they name when the module setting was true, because the module enables the privileges itself before the cmdlet runs; they now also assert the verbose message that only the cmdlet writes, and they disable the privileges before each test so that the child process inherits none.
The first-nested-folder test asserts the first folder, not either. Set-TestNullDacl refuses an item that is a link, which the native call would follow out of the sandbox. A table pins the three outcomes that the filter documentation lists for a dot (Report.*, a trailing dot, an empty value), so a change of those rules is a decision.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
The CI runner sets $ErrorActionPreference to Stop, so three new PipelineControl tests that take the error of a nested folder through 2>&1 ended at the first error before the later command saw it (elevated Windows PowerShell 5.1 of the frozen run: three failures). They now pass -ErrorAction Continue. The focused runner of this work did not set the preference and missed it; it does now.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
Add-NTFSAccess, Remove-NTFSAccess, and Add-NTFSAudit report an AddAceError or RemoveAceError for each item when .NET refuses an entry without rights, change nothing, and return nothing with -PassThru. Get-NTFSAccess returns the one entry that .NET reports for a NULL DACL without a source; the new helper Set-TestNullDacl writes it through SetNamedSecurityInfo inside the sandbox guard. Get-NTFSHardLink lists the names of a file whose read rights are denied, which is why its UnauthorizedAccessException handler has no trigger. The public Extensions.ForEach and GetParent helpers, which a static scan listed as unused although cmdlets call them, are tested directly.
All of these characterize behavior that was already correct, so none was red before; the mutations that prove their detection run against the frozen measurement commit.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
Get-ChildItem2 swallowed what a later command threw for the error of a nested folder, for example `Get-ChildItem2 -Recurse 2>&1 | ForEach-Object { throw 'x' }`: the recursion took it for a failure of the folder above, wrote a verbose message, and left the loop over the folders, so the listing ended early and the caller never saw the exception. BaseCmdlet now notes the exception that WriteError raises, as it does for WriteObject, WriteVerbose, and WriteDebug. The report that -ErrorAction Stop is swallowed there too was not reproducible (the error reaches the caller), and a break or Select-Object -First was already passed on by type; the tests keep both.
A cmdlet that enables the privileges wrote the debug message "..enabled" before it noted the privilege, so a later command that ended the pipeline or threw at that message left the privilege enabled: Dispose disables only what is noted. TryEnablePrivilege also took the exception of a later command for a failure to enable the privilege and went on with the next one, so `Get-NTFSOwner 5>&1 | ForEach-Object { if ($_.Message -eq '..enabled') { throw 'x' } }` enabled all four privileges and hid the exception. The privilege is noted before the message, and TryEnablePrivilege passes the exception on.
Red before the fix in the Release build of 7aa8315: three tests (the throw on the error stream, in four configurations the first, in the two elevated ones the two privilege tests). Also covers the typed-throw rows that fail if PowerShell stops wrapping a thrown exception, and Enable-Privileges in a script named NTFSSecurity.Init.ps1.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
The catch for an UnauthorizedAccessException of Get-ChildItem2 had an exception filter that passes on what a later command raises. A bounded mutation that removed the filter was not detected: PowerShell wraps the exception of a throw, so a cmdlet never sees the type that was thrown, and no later command can raise a raw UnauthorizedAccessException through a Write call. The filter and the test style that was meant to reach it are removed instead of leaving a branch that nothing can enter.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
The Write wrappers of BaseCmdlet note what a later command raises, so PipelineControl.IsEnd is reached only for an exception that did not pass through one, and its branches had no test. The tests call it through reflection: for a PipelineStoppedException, for a stand-in type that derives from a class named FlowControlException, as PowerShell keeps the exceptions of break and continue internal, and for failures of an item, also one that has an inner exception that ends the pipeline.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
A throw in a later command, or an error with -ErrorAction Stop, reaches a cmdlet through its Write call as an ordinary exception. The catch for the failures of an item reported it as the error of that item and went on, so that Remove-Item2 -PassThru removed the next item after a throw, and the caller never saw the exception. The earlier check found only the end of the pipeline and a break or continue. BaseCmdlet now notes the exception that its WriteObject, WriteVerbose, and WriteDebug raised, and every catch that can enclose a write passes it on; Get-DiskSpace writes outside its try. Set-NTFSSecurityDescriptor and Get-FileHash2 also caught it at a verbose message.
Get-ChildItem2 -Filter *.* returns every item, as Get-ChildItem does. The cmdlet compared each name with the pattern again and dropped the items without a dot, most folders among them; the dot stays an ordinary character in other patterns.
The failed lookup of InheritedFrom frees its native buffer. The help paragraph of -Filter has no pair of asterisks, which platyPS turns into emphasis, and the page has an example for *.*.
Review of the independent pass: the restored-owner test asserts that a plain write is denied, the drive-mapping helper has guard tests and takes letters that the no-volume tests do not, and the pipeline tests cover a throw, an error with -ErrorAction Stop, and the verbose and debug streams for every cmdlet that can reach the code.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
The escape of brackets in the pattern read the filter before the pattern could reject it, so a null filter ended in a NullReferenceException. The parameter now rejects null with a validation error that names it; an empty filter still matches no item.
The cmdlet compares each name that the enumeration returns with the pattern again. The two disagree for *.*: the enumeration returns every item, as Get-ChildItem does, and the comparison drops the names without a dot, files and folders alike. A test pins this and reaches the branch that drops an item; the help says that a dot is an ordinary character.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
The restore test of Set-NTFSSecurityDescriptor used a deny entry for the user, which a member of the owner group Administrators does not feel, so the first write succeeded and the ownership retry never ran. A deny entry for OWNER RIGHTS stops that write also for the owner; taking ownership drops the entry, the cmdlet writes the descriptor, and the user sets the group back without the Restore privilege. A probe shows the plain write is denied in that setup in both editions.
Remove-NTFSAccess with -SecurityDescriptor and -AccessType Deny had no test, although the overload for a descriptor adds Synchronize to allow entries only.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
The cases for the retry of Set-NTFSSecurityDescriptor covered a descriptor that sets the owner, an owner that did not change, and an owner that the user cannot assign without the Restore privilege. The success path was not tested: the user can set a group of its access token back as the owner, such as Administrators in an elevated session, so the cmdlet restores the owner and reports nothing. The test runs elevated only, because the filtered token of the basic user cannot assign that group.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
The cmdlet compares the name of every item that the enumeration returns with the pattern again, and it built that comparison with the wildcard syntax of PowerShell. A bracket then began a character class, so Report[1].txt was returned by the enumeration, which treats a bracket as itself, and dropped by the comparison, and a file with brackets in its name could not be found for its name with -Filter, which Get-ChildItem does. The documentation names only * and ? as wildcards, so a bracket and a backtick now stand for themselves in the comparison.
The regression test fails without the fix in all four configurations. The probe also showed that AlphaFS compares only the long name, so the test for *.htm guards the documented contract and no 8.3 behavior. The page of the cmdlet names the rule and the help file is generated again.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
New guards cover the default AllAccess token handle, token handles that lack the right to query or to adjust privileges, and the finalizer of an abandoned PrivilegeEnabler, which closes the handle that it owns; writes to the root of a drive that subst maps to a sandbox folder, which skip for the restricted token of the basic-user runner that cannot define a drive letter; Get-ChildItem2 -Filter against a match by short name; retargeting a descriptor with Item; the path overloads of the inheritance helpers for a missing path and of the audit rule reader for folders; removing a generic right while another account holds an exact entry; and an empty -ServerName.
Follow-ups of the independent review: dispose the enabler in the finally block before its handle, don't pin that the iterator overloads write only when enumerated, arrange the previous owner of the RestoreOwnerError test, and describe what ObjectApis.Tests.ps1 does.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
A catch for the failures of an item wrapped the write of its object. When a later command ended the pipeline, a break or continue in a script block or Select-Object -First, the exception passed through that catch, which reported it as an error of the item and went on with the next one. Remove-Item2, Copy-Item2, and Move-Item2 with -PassThru then removed, copied, or moved every item although the caller had ended the pipeline, and Set-NTFSOwner and Set-NTFSSecurityDescriptor changed every item. Get-NTFSSecurityDescriptor, Get-NTFSSimpleAccess, and Get-DiskSpace ignored the break, and Get-ChildItem2 ignored it for items below the first folder.
A helper recognizes the end of the pipeline and the control-flow exceptions of PowerShell by their base type, and these catches pass them on. The new table-driven tests run every cmdlet that writes objects: 26 cases for the nine cmdlets fail without the fix in all four configurations and the 64 cases of the others pass.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
When Windows cannot name the folder of an inherited entry, such as for an item that was deleted after its descriptor was read or for a folder above it that the user cannot read, the module fills InheritedFrom with a fallback text. The callers removed the last character of every source, which belongs to the trailing backslash of a real folder, so the fallback read 'unknown paren'. The fallback also named an unknown parent for explicit entries, which have no source. Remove only a trailing backslash, and name an unknown parent for inherited entries only.
The regression tests fail without the fix in all four configurations for access entries and in both elevated configurations for audit entries. The cmdlet pages name the text, and the help file is generated again.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
The removal helpers for a path ran only against a file. Run both removal tests for a file and a folder, and add the deny variant of the iterator overload that adds the entries of several accounts.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
Resolve relative paths with Get-Item2, report copies and moves to a drive that does not exist, warn once about MACTripleDES across pipeline objects, and check the exceptions of PrivilegeControl for held, repeated and missing privileges.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
PSScriptAnalyzer flagged the plural nouns and the state-changing verb of three helpers; the repository suppresses that rule for test helpers with a justification.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
Cover the access and audit rule helpers that take a path, including the lazy iterator overloads and exact versus partial removal, the inheritance helpers for paths, owner and descriptor objects, generic rights mapping, identity construction errors and the PrivilegeEnabler class. These public APIs have no cmdlet caller.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
Cover locked and denied copy and move, recursive enumeration that stops or meets a broken junction, hard link counts on a network share, denied link creation, the default root folder of a drive root, ownerless -PassThru and an undefined hash algorithm.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
Clear-NTFSAccess -DisableInheritance and Set-NTFSSecurityDescriptor took ownership of an item that the user owned already, left a DACL without the right to set an owner, and then reported a RestoreOwnerError for setting the same owner back. Skip the restore when the previous owner is the current user. The guards fail without the fix in all four configurations and also cover the owner that cannot be set back without the Restore privilege, the missing path of Get-ChildItem2, and the descriptor write that retries as owner.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
Reproduce and fix public rule paths, simplified audit comparisons and ReadData conversion, and boxed privilege equality. Add behavior guards for descriptor inheritance, unresolved identities, audit capability and recursive denial. Freeze this source for Release matrix measurement; final gate evidence and independent review follow.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
A Gallery upload can succeed while PSResourceGet reports a timeout or a
409 from its retry. Recover that uncertain outcome only after the
published SHA512 matches the exact build artifact. Verify the same hash
before skipping an existing version, and preserve the original upload
error when the version is absent, different, or unverifiable.
Keep API keys in the existing environment secret. Unexpected discovery
errors fail instead of silently proceeding. Offline tests reproduce
legacy false failures and blind skips; all 14 tests pass in each edition
and privilege configuration. No real package was published by tests.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
Join-Path appended an absolute ResultPath to the repository path,
producing an invalid path and preventing the restricted-token test run.
Use Path.Combine to keep rooted paths intact while retaining repository-
relative paths. Clarify the script parameter help.
The offline process-boundary tests fail with the original expression in
both editions and pass in all four configurations with the fix. They do
not launch a process or modify privileges.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
Exercise all 13 scopes using named scopes and explicit Windows flags,
through disk paths and in-memory descriptors, for access and audit
entries. Verify removal keeps another account, and check actual
inheritance through children and grandchildren, including OneLevel.
Cover keep/remove switches and successful PassThru for both files and
folders, including Set-NTFSInheritance enabling protection states.
Controlled mutations lose OneLevel and keep folders protected: 12 tests
fail as expected. Restored implementations pass the 170-test focused
suite in all four configurations where privileges permit. No cmdlet
contract changes.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
Cover recursive, read-only, locked, long-path, and junction deletion in
sandbox folders. Exercise denied ownership retries and both successful
and failed restoration after an operation fails, without inconclusive
results or a success-shaped hash.
The tests fail when folder deletion and owner restoration are omitted:
16 expected failures in the controlled mutation run. Restored code passes
all 66 focused tests where applicable in both editions and privilege
configurations. No production behavior changes.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
5.0.0-rc6 is on the PowerShell Gallery, and its GitHub release waits for a
rerun of the failed Release job. The publish step's false failure is open
work for the maintainer's decision; #116 waits for his review of
Decision 22.
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>
Decision 22 lists the ten choices for the behavior changes of Phase 2,
proposed for the maintainer's review, and the outcome of the review.
progress.md and activeContext.md record the branch, the suite, the lab
acceptance, and the next steps; systemPatterns.md adds patterns for
writing cmdlets.
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>