mirror of https://github.com/raandree/NTFSSecurity
Branch:
master
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 }
219 Commits (master)
| Author | SHA1 | Message | Date |
|---|---|---|---|
|
|
696ac38912 |
fix(access): ignore a failure to release the enumerator when a value is read
The previous commit made a sequence whose enumerator throws in Dispose after the second element count as a list, and left every other count to the catch, which hands the collection to the conversion of PowerShell. A sequence of one element whose enumerator fails in Dispose therefore got through when that element was a comma list or an array of two values: PowerShell combined the numbers bit by bit and the entry was created with a value that nobody named. The reading is done with an explicit enumerator that is released in its own guard now, so a failing release changes nothing of what was read, whatever the number of elements. The catch is back to what it was: a reading that fails leaves the collection to the conversion, which rejects it with its own error. Tests, written first: 8 rows failed on the previous commit in all four configurations and none fails now (a compiled stand-in whose enumerator throws in Dispose; a sequence of one comma list and of one array of two values, for AccessType and AppliesTo, named and piped). Two rows pin that a sequence of one valid value stays valid. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com> |
1 week ago |
|
|
b436423ab8 |
fix(access): count a sequence as a list when its enumerator fails after the second element
The check of a list for -AccessType and -AppliesTo stops reading a collection after the second element. The loop then releases the enumerator, and when that failed the catch handed the collection to the conversion of PowerShell with isList still false. PowerShell combines the numbers of a list bit by bit, so a sequence of Allow and Deny whose enumerator throws in Dispose created a Deny entry, and one of SubfoldersOnly and FilesOnly a scope that nobody named. The catch keeps what the loop knows: two elements read make a list, which is rejected like every other list. Only a custom enumerator can do this; the last review of round 2 found it. Tests, written first: 4 rows failed on the previous commit in all four configurations and none fails now (a compiled stand-in whose enumerator throws in Dispose, for AccessType and AppliesTo, named and piped). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com> |
1 week ago |
|
|
ce34395a8b |
fix(access): name a value that cannot be formatted by the short form of its type
The fallback of the message of a bad parameter value used the full name of the type. For a generic type that spells out the assembly of every type argument, so a LINQ iterator whose selector throws gave a message of 330 characters, where the code before the last commit printed the short form. The fallback uses Type.ToString now: System.Collections.Generic.List`1[System.Object]. Two rows pin the short form (a generic list of one object whose ToString throws, for AccessType and InheritanceFlags of Add-NTFSAccess, piped). They failed on the previous commit in all four configurations and pass now. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com> |
1 week ago |
|
|
ec58a18c28 |
fix(access): build the message of a bad parameter value even when the text of the value throws
The message of the error is built inside the catch block of the conversion, and Describe formatted the one element of a collection of one element outside of any guard. An element whose ToString throws (a script method, for example) ended the command with a terminating ExtendedTypeSystemException instead of the InvalidParameterValue error for that item, and a piped command stopped at that object, where the pages say that the error is reported for just that item. Describe now falls back to the type name whatever the text or the enumeration of the value does, for the five parameters of the four cmdlets alike. Tests, written first: 24 rows failed on the previous build in all four configurations and none fails now (an array of one object whose ToString throws, piped for every parameter and named for one parameter of each kind). New rows also pin what the previous commit claimed but did not test: the message names the first ten elements of a list and ends with an ellipsis from the eleventh, and a sequence of 100,000 elements is read only up to its first elements (a counting sequence, named and piped). A build without the two limits fails 4 of them and a build with a limit of nine fails 6, in all four configurations. The comment of the nesting limit now says exactly what it counts. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com> |
1 week ago |
|
|
da41a8e3ee |
fix(access): end a collection that holds itself and name the typo in the message of a list
The check that rejects a list for -AccessType and -AppliesTo opened every level of a collection of one element, so that a collection that holds itself never returned. It opens at most 32 levels now and counts a deeper nesting as a list, and it stops reading a collection after the second element, so that a long or endless sequence is not read to its end. The message names what the caller wrote: the one element of a collection of one element (also when that element is a collection itself), the first ten elements of a longer collection followed by "...", and otherwise the text of the value. Before, a collection of one misspelled name was named by its type. Tests, written first: 28 rows failed on the previous build in all four configurations and none fails now. They cover an array of one misspelled name, a collection nested 40 levels deep for both parameters of both cmdlets, and an array that holds an array of one name, which stays valid. The assertion of the value text expects "The value '<text>'", because the old pattern could also match the name of a type. The comments say that PowerShell combines the numbers of a list bit by bit, which is what it does, and not that it adds them. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com> |
1 week ago |
|
|
e39aeed1b2 |
fix(access): reject a list of any kind of collection for -AccessType and -AppliesTo
The rejection of a list for the enumerations that are not flags
enumerations looked only at a string with a comma and at an IList of more
than one element. A collection that is not an IList (a HashSet, a Queue, the
keys of a hashtable, a LINQ sequence), a collection of one element that
holds a comma list (@('Allow,Deny'), such as a JSON array of one string), and
a collection that holds a collection of several elements still reached
LanguagePrimitives.ConvertTo, which added up the numbers: -AppliesTo
$scopes.Keys created a ThisFolderAndFiles entry that nobody named.
ParameterConversion takes the one value out of the argument now: a wrapped
PSObject counts as what it wraps, a collection of one element converts as
its element (also when that element is a collection of one element), and a
collection of several elements or an element with a comma is the list that is
rejected. A dictionary, an empty collection, and a collection that cannot be
enumerated keep going to the conversion, which reports them as before. A
blank value inside a collection of one element is reported as blank.
The tests add the shapes to the bad-value tables of the four cmdlets (32
rows, red before the change and green after it in four configurations) and
pin that a list of one name and a hash set of one name stay valid. The
valid-value matrices of rc8 and this build still differ in the nine list rows
only, and a probe of 50 shapes shows every collection of several values
rejected and every single value accepted, in both editions.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
|
1 week ago |
|
|
1b8a3763a1 |
fix(access): reject a list for -AccessType and -AppliesTo, and complete in capitals in Turkish
-AccessType and -AppliesTo of Add-NTFSAccess, Remove-NTFSAccess, Add-NTFSAudit (-AppliesTo), and Remove-NTFSAudit (-AppliesTo) take one value, but PowerShell adds up the numbers of a comma list or an array for an enumeration, so that -AppliesTo 'ThisFolderOnly,FilesOnly' created a FilesOnly entry and -AccessType 'Allow,Deny' created a Deny entry, without a message. The conversion in ParameterConversion now rejects a string with a comma and a collection of more than one element for an enumeration that is not a flags enumeration, with the same InvalidParameterValue error as for a misspelled name (terminating for a named value, one error per object for a piped one). A single name and a collection of one element convert as before, and the flags parameters still take a list. The valid-value matrices of both published rc8 and this build give the same entries in both editions, named, piped by property name, and splatted, apart from the nine list rows. The completers of the five parameters compared with WildcardOptions.IgnoreCase only, so that a word typed in capitals did not complete while the culture of the thread was Turkish (an I and an i are different letters there, and THISFOLDERO did not match ThisFolderOnly). They compare culture invariant now, like the filter of Get-ChildItem2. The tests pin both, red before the change and green after it in four configurations, and the headers of the two test files no longer say that the -SecurityDescriptor sets have no handler per descriptor. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com> |
1 week ago |
|
|
accf6b8edd |
chore(release): prepare 5.0.0-rc9
Set the prerelease label to rc9 and add 5.0.0-rc8, which the PowerShell Gallery has had since 2026-10-20, 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> |
1 week ago |
|
|
68eab76867 |
test: describe the new tests by behavior, not by review finding
Remove the labels of review findings and the references to probe scripts and reports that are not in the repository from the comments of the tests that rc9 adds, and say what each test pins in words that stand alone. Only comments and the name of one Context in each of two files change; no assertion does. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com> |
1 week ago |
|
|
140c790c11 |
docs(access): say what a blank, null, or script block value of a property does, and pin it
R1-1 (major): the four pages claimed that a blank cell of AppliesTo, AccessType or AuditFlags, InheritanceFlags, or PropagationFlags is an InvalidParameterValue error for every shape. That is wrong when the blank, $null, or DBNull value belongs to the group that -AppliesTo did not select: PowerShell counts a property that is present, even blank, as offered for choosing the parameter set, the same as a real value, so AppliesTo together with a blank InheritanceFlags or PropagationFlags (for example a short CSV row, whose missing trailing columns Import-Csv fills with $null) is AmbiguousParameterSet, and rc8 created the entry. The pages now say that a CSV file should have the columns of only one group, that mixing both groups fails with AmbiguousParameterSet, that a literal $null named or piped for -AppliesTo itself fails with its own, unrelated, pre-existing error because -AppliesTo is mandatory, and keep the sentence that a bad value within the chosen group is InvalidParameterValue. R1-3 (minor): the pages now also say that a script block is a plain value for these parameters and is not evaluated once for each piped object the way rc8 evaluated it, so a named script block is a terminating InvalidParameterValue error. Neither finding needed a code change; both already read this way. Pinned with new table-driven tests, over the four cmdlets and their Path and SD parameter sets, for AppliesTo valid combined with a $null, an empty string, or DBNull InheritanceFlags or PropagationFlags and the reverse, and for a named script block of each of the five parameters: the error id the binder already gives, nothing changed, and, where applicable, the next piped object still processed. Confirmed unchanged against the pre-R1-2/R1-4 build. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com> |
1 week ago |
|
|
7732fe57ac |
fix(owner): pass on what a later command raises at the RestoreOwnerError record for the add and remove cmdlets
Add-NTFSAccess, Remove-NTFSAccess, Add-NTFSAudit, and Remove-NTFSAudit had the same flaw as the 13 handlers fixed before: when a later command of the pipeline throws exactly at the RestoreOwnerError record that InvokeAsOwner writes after a failed restore of the owner, the catch around the call reported the exception as the item's own AddAceError or RemoveAceError and went on with the next path, so the caller never saw it. The four handlers now check IsFromLaterCommand first, like the others, so all 17 handlers of item 7 of Decision 27 pass the exception on. The table of Tests\PipelineControl.Tests.ps1 gets two rows, for Add-NTFSAccess and Remove-NTFSAccess, which use the scenario of the inheritance cmdlets (a ChangePermissions deny for the user and an owner that only the Restore privilege can set back). The two audit cmdlets can't be pinned this way: Windows lets this elevated session write the SACL whatever the DACL says, so their action never fails to begin with. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com> |
1 week ago |
|
|
e75bc15953 |
fix(access): complete quoted and wildcard words of the five parameters
The completers for AccessType, AuditFlags, InheritanceFlags, PropagationFlags, and AppliesTo returned nothing for a quoted word (-AccessType "D) or a wildcard word (-AppliesTo *Only, -AccessType D*), which rc8's built-in enum-parameter completion still offered. PowerShell auto-closes an unterminated quote before it reaches the completer, so the word a completer receives for -AccessType "D is "D", not D. EnumArgumentCompletion.Complete now strips a leading quote and its matching trailing quote from the word before matching, matches the enumeration's names with WildcardPattern(word + "*", WildcardOptions.IgnoreCase) the way PowerShell's own enum completion does, and, when the word was quoted, returns each match in the same quote character (CompletionText 'FilesOnly' for a leading single quote). An unquoted, non-wildcard word is unaffected: appending "*" to it only turns an exact prefix match into a prefix-wildcard match. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com> |
1 week ago |
|
|
d3ba5a9a31 |
fix(access): stop for a named $null of the five parameters
A named $null of AccessType, AuditFlags, InheritanceFlags, PropagationFlags, or AppliesTo (a literal $null, a variable that holds $null such as a misspelled property, the alias -AccessControlType, splatting, or a null entry of $PSDefaultParameterValues) silently kept the parameter's default instead of stopping: Add-NTFSAccess -AccessType $null created an Allow entry, Add-NTFSAudit -AuditFlags $null audited Success and Failure, and Remove-NTFSAccess -AccessType $null removed nothing. Before the five parameters became object (Decision 27, fix B), the same named $null ended with a terminating ParameterBindingFailed. Each cmdlet's BeginProcessing now checks, for a value that is null, whether MyInvocation.BoundParameters has the parameter's name; a piped property that is null is not bound yet at that point and still keeps the default, but a value that is already bound and null is reported the same way as a bad named value: a terminating InvalidParameterValue error naming the parameter and its valid values. AppliesTo is Mandatory and a named $null of it was already a terminating ParameterArgumentValidationErrorNullNotAllowed from the binder itself, unchanged by this fix. ParameterConversion gains the message for this case next to the existing blank-value message, so that the wording is built in one place. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com> |
1 week ago |
|
|
62699eeb7b |
fix(access): report a failing change of a descriptor as an error per descriptor
In the four -SecurityDescriptor parameter sets of Add-NTFSAccess, Remove-NTFSAccess, Add-NTFSAudit, and Remove-NTFSAudit, a change that throws, such as a Deny entry without rights, ended the cmdlet with a terminating error, while the -Path parameter sets already wrote an AddAceError or RemoveAceError for the failing item and went on to the next one. The two kinds of parameter sets now behave the same way. Each descriptor's change is wrapped in its own try/catch: a failure writes a non-terminating AddAceError or RemoveAceError, category WriteError, that targets the descriptor, and the cmdlet continues with the next descriptor in the pipeline instead of stopping. -PassThru stays outside the try, so what a later command raises when the cmdlet writes its output is never caught there. The existing TestAuditSection check of the audit cmdlets, and everything else about a successful change, is unchanged. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com> |
1 week ago |
|
|
abdf212fe4 |
fix(access): report a piped AccessType, AuditFlags, flags, or scope that isn't valid
Add-NTFSAccess, Remove-NTFSAccess, Add-NTFSAudit, and Remove-NTFSAudit silently kept the default value of AccessType, AuditFlags, InheritanceFlags, PropagationFlags, and AppliesTo when a piped object's property could not be converted to the parameter's type: a misspelled AccessType such as "Denyy", or a blank CSV cell, created an Allow entry with no message. For a permissions tool, a typo for Deny that silently grants access is a security-relevant defect (Decision 27). The five parameters are now declared as object and converted inside the cmdlet, the way the PowerShell binder converts a typed parameter (names in any case, comma-separated flag lists, numbers, enum instances). A value that cannot be converted, including a blank one, is now an error named InvalidParameterValue: terminating and catchable when it is named on the command line, exactly as the binder reported it before; a non-terminating error targeting that path or descriptor when it comes from a piped object, which leaves that item unchanged and lets the pipeline continue with the next one. A $null value is still not an error and keeps the parameter's default. Tab completion of the five parameters keeps working through explicit argument completers. Choosing between the Simple and Complex parameter sets is unaffected and still rejects AppliesTo together with InheritanceFlags or PropagationFlags as AmbiguousParameterSet, for every mix of string and enum values. The four cmdlet pages document the parameters as Type: Object, list the valid values, and describe the new error; a sentence that said a piped AppliesTo typo or blank cell was silently ignored is corrected. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com> |
1 week ago |
|
|
21629d3415 |
test(items,owner,access): bind four parameters by property name
The coverage record of Handoff 5 listed getters of parameters that take pipeline input by property name and that no test bound that way: -Destination of Copy-Item2 and Move-Item2, -Account of Set-NTFSOwner, and -Account of Get-NTFSEffectiveAccess (the getters of AccessType, AuditFlags, and the scope and flag parameters of the access and audit cmdlets, and -Algorithm of Get-FileHash2, are bound by tests now). PowerShell calls the getter of such a parameter once per command when a piped object binds it, so a test has to pipe an object that has the property. Each test pipes two objects that name different values and checks that each item gets its own: two destinations for the copied and the moved file (Copy-Item2 and Move-Item2, read back with Get-Content and Test-Path), two owners that only the Restore privilege can assign (Set-NTFSOwner, read back with Get-Acl; elevated only), and the effective access of Everyone, which an allow entry grants, and of Guests, which a deny entry takes away (Get-NTFSEffectiveAccess). Tests only; no product change. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com> |
1 week ago |
|
|
37bd42d2dd |
fix(securitydescriptor): make -SecurityDescriptor of Set-NTFSSecurityDescriptor the first positional parameter
Set-NTFSSecurityDescriptor declared -SecurityDescriptor at Position = 2, its only positional parameter; every sibling that takes a security descriptor or a path takes its first positional parameter at 1. Moved to Position = 1 for consistency. A positional call with one argument already bound to it, because it was the only positional parameter in its only parameter set, so no script that calls the cmdlet positionally can notice a difference; this is cosmetic, as Decision 27 describes it. Tests\SecurityDescriptor.Tests.ps1 adds a characterization-turned-pin test: the declared Position is 1, and Set-NTFSSecurityDescriptor $sd still works positionally. RED before the change (Position was 2), GREEN after, in all four configurations. Docs\Cmdlets\Set-NTFSSecurityDescriptor.md: Position: 1 in the yaml block of -SecurityDescriptor. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com> |
1 week ago |
|
|
cd788c7693 |
test(access): pin the ReadSecurityError category of Get-NTFSAccess after a failed ownership retry
Get-NTFSAccess writes ReadSecurityError with category WriteError when a read succeeds only after the cmdlet takes ownership and the restored owner is irrelevant to that path; Get-NTFSAudit, Get-NTFSEffectiveAccess, Get-NTFSInheritance, and Get-NTFSSecurityDescriptor already report the same failure the same way, so this is the module's convention, unlike Get-NTFSOrphanedAccess, whose own category for the same failure is ReadError. No script could notice: the behavior does not change. A characterization test in Tests\ParameterSets.Access.Tests.ps1, next to the orphaned-access test that already pins the ReadError side of the same convention, is green at once and runs in all four configurations. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com> |
1 week ago |
|
|
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>
|
1 week 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> |
1 week 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>
|
1 week 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>
|
1 week 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>
|
1 week 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> |
1 week 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> |
1 week 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> |
1 week 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> |
1 week 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> |
1 week 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 |