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 }
435 Commits (master)
| Author | SHA1 | Message | Date |
|---|---|---|---|
|
|
72176542f0 |
docs(memory-bank): record that rc9 is merged, tagged, and published, and that its lab acceptance runs
#131 (rc9) and #132 (the Memory Bank) are merged, the tag 5.0.0-rc9 is at the merge commit of #131 (823c814, whose tree equals the validated head 696ac38), the CI run of the tag passed, and the Gallery and GitHub have the package. The identity check verified the published bytes (hashes in progress.md), and the pathological-input, ToString, and valid-shape probes give the results of the validated build on them. The lab acceptance of the published bytes runs in one detached chain since 11:00:36Z; activeContext.md says how to finish it and what the stable pull request needs. The oldest milestones of progress.md are condensed to stay within the line budget. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com> |
1 week ago |
|
|
f2bcd9d38d
|
Merge pull request #132 from raandree/ai/memory-bank-merged
docs(memory-bank): rc9 decision, status, and lessons |
1 week ago |
|
|
823c814908
|
Merge pull request #131 from raandree/ai/rc9
fix: reject bad piped parameter values and prepare 5.0.0-rc9 |
1 week ago |
|
|
fcdc2cd573 |
docs(memory-bank): record the last checks of round 2 and the final head of rc9
Record that the branch ai/rc9 ends at 696ac38 (36 commits over d0cb57c, 2,162 cases per configuration, 0 failed), that the last two checks of round 2 found four Nits in the message formatter and in the reading of a sequence (all fixed test-first, the last one at its root), that both reviewers closed with no finding, and that a collection that holds itself still ends the host through the three flags parameters, as in rc8, which stays a known limit. The lesson for the next agent: a failing Dispose must never change what was read. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com> |
1 week ago |
|
|
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 |
|
|
90e04c6081 |
docs(memory-bank): close out the rc9 work with the head, the final suite, and the open work
Record that the branch ai/rc9 is complete at de67883 (32 commits over d0cb57c, 2,116 cases per configuration, 0 failed), what the two review rounds found, that the maintainer chose to reject a list for -AccessType and -AppliesTo, and what is left before the stable pull request (push, pull request, merge, and tag of rc9 by the maintainer, then the lab acceptance of the published bytes). Lessons for the next agent: PowerShell combines the numbers of a list for an enumeration that is not a flags enumeration bit by bit, and code that opens a one-element collection needs a depth limit. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com> |
1 week ago |
|
|
de67883cd9 |
docs: say that PowerShell combines the numbers of a list bit by bit
The pages of -AccessType and -AppliesTo of Add-NTFSAccess, Remove-NTFSAccess, Add-NTFSAudit, and Remove-NTFSAudit, and the changelog, said that PowerShell adds up the numbers of a list for an enumeration that is not a flags enumeration. It combines them bit by bit (a logical or), which is why one of the values wins silently or a scope that nobody named is selected. The help file is regenerated from the pages, and the pages and the file are a fixpoint after a rebuild. 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 |
|
|
e3eed8c773 |
docs: state the reason for the list rule and the edge cases of the filter exactly
Say that a list for -AccessType or -AppliesTo lets one of the values win silently or, for -AppliesTo, selects a scope that nobody named (the sum of two Allow and Deny numbers is always one of the two), and that every kind of collection counts. State the third edge case of Get-ChildItem2 -Filter (blanks at the end of the pattern, also before a final dot), limit the error of Windows PowerShell 5.1 to an even number of dots at the end, and name the pattern of a single dot, for which the built-in filter of PowerShell 7 returns every item. The help file is regenerated, and the pages and the file are a fixpoint after a rebuild. 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 |
|
|
42f07a55f0 |
docs: correct the statements that the second review found and regenerate the help file
Say in the pages and in the CHANGELOG what a script block, a named $null of -AppliesTo, a list for -AccessType or -AppliesTo, and a piped value that PowerShell cannot convert did before 5.0.0 and do now; name the carry-over of the scope between piped descriptors for the objects that it affected; mark the descriptor sets that go on after a failing descriptor and the checks of the object with both parameter groups as breaking, with the hint that a script that relied on the stop needs -ErrorAction Stop. Describe where Get-ChildItem2 -Filter differs from the built-in filter of PowerShell 7 with the shapes that really differ (a pattern that ends in a dot, an asterisk followed by a dot and question marks) and state the two cases that are not like Windows PowerShell 5.1: a blank at the end of the pattern is part of it, and a pattern that ends in two dots is accepted. The pages and the help file are a fixpoint again after a rebuild. 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 |
|
|
6d98b68d95 |
docs(help): regenerate the help file for the changed cmdlet pages
Regenerate NTFSSecurity.dll-Help.xml from the pages with New-ExternalHelp and let platyPS wrap the syntax of the four add and remove pages for the parameters that are Object now. The pages and the file are a fixpoint: after a rebuild, Update-MarkdownHelp changes no page and New-ExternalHelp changes no file. State two sentences more plainly: what a blank value of the other parameter group does to the four add and remove cmdlets, and where Get-ChildItem2 -Filter differs from the built-in Get-ChildItem in PowerShell 7. 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 |
|
|
32a411856a |
docs(changelog): describe the changes of 5.0.0-rc9
Add the entries for the filter of Get-ChildItem2, the error of Get-NTFSOrphanedAccess, the position of -SecurityDescriptor of Set-NTFSSecurityDescriptor, the conversions from FileSecurity and DirectorySecurity (and what they mean for the cmdlets: Get-Acl objects now bind), the account list of the RemoveAll methods, the path overloads of the Add methods, the EnablePrivileges setting, the 17 owner-restore handlers, the piped values that the add and remove cmdlets could not convert, and the descriptors of those cmdlets that fail one by one. Say what the object type of the five parameters costs (a script block is no longer evaluated per object; an empty value of the other group makes an object ambiguous) and replace the sentence that said such a value is ignored. Each statement was checked by a probe against the published rc8 and the build of this branch, in both editions. 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 |
|
|
1c26ea7f4e |
docs(memory-bank): record the rc9 review, the known limits, and the lessons
Decision 27 gets the review findings of rc9 and what became of each, with the known limits that the maintainer is told about. debugging-insights gets the lessons of the piped optional parameters (the binder skips a value that it cannot convert, and the price of an object parameter), of a differential oracle that covers only part of the input, of agents in parallel worktrees (one shared stash), and of the help generation. 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 |
|
|
46a0cb0c7a |
docs(access): say that a local standard user still gets "Access is denied" for a domain user account
Get-NTFSEffectiveAccess already falls back to the local authorization manager for a name of this computer when the remote one refuses the caller, which covers every account except a user account of the domain: Windows still answers "Access is denied" for that one case, because the local manager has no domain credentials to resolve it. The cmdlet already writes this as a non-terminating GetEffectiveAccessError and returns no result for the item; nothing in the behavior changes. Docs\Cmdlets\Get-NTFSEffectiveAccess.md gets one more NOTES paragraph, in the style of the neighboring "Before 5.0.0..." paragraphs, saying so and naming the accounts that still get a result (accounts of this computer, and domain groups such as Everyone or Domain Users). Evidence: Tests\Lab\Acceptance-2026-10-10-os-matrix.md, "The probe", row "Local standard user". No code change; Tests\Help.Tests.ps1 (unchanged) already covers the page's synopsis, parameters, examples, and links. 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 |
|
|
9fde8d19a4 |
fix(access): write an error when Get-NTFSOrphanedAccess cannot read an item
Get-NTFSOrphanedAccess wrote a warning ("Could not read item {0}. The
error was: {1}") for a read failure that is not an access denial, while
every sibling (Get-NTFSAccess, Get-NTFSAudit, Get-NTFSEffectiveAccess,
Get-NTFSInheritance, Get-NTFSSecurityDescriptor) writes a non-terminating
error and goes on with the next item. The cmdlet now writes
ReadSecurityError, categorized as OpenError and targeting the path,
through WriteError, then continues, the same pattern
Get-NTFSAccess (GetAccess.cs) already uses for the same kind of failure.
A script that collected this warning with -WarningVariable now has to
read $Error or -ErrorVariable instead.
No existing test pinned the warning (searched for "Could not read item"
and Get-NTFSOrphanedAccess with -WarningVariable across Tests\; none
found), so none needed changing.
NOT DONE: a new test that triggers this exact catch (a read failure that
is not UnauthorizedAccessException) through the public surface. Five
probes (..\probes-wi2\p-orphaned-read-failure*.ps1) tried a sharing
lock, an over-long path, a dangling and a looped junction, and an
alternate data stream; none reached this catch without also failing
GetFileSystemInfo2 first (a different error, ReadFileError) or succeeding
outright, because an elevated session that can read the item at all can
read its ACL as well. The change is still correct and matches the
module's convention; it is defensive code for a condition this harness
cannot construct deterministically.
Docs\Cmdlets\Get-NTFSOrphanedAccess.md documents the new error next to
the existing ReadSecurityError paragraph for the access-denied case.
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> |
1 week ago |
|
|
fbb20ea4d9 |
docs(memory-bank): record that the rc9 work items are running
The designs of Decision 27 are chosen, and four work items run in worktrees under C:\Temp\ntfs-rc9 on the branch ai/rc9-before-stable. The inventory of open decisions in progress.md now points to Decision 27. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com> |
1 week ago |
|
|
9bc38d01d5 |
docs(memory-bank): record the design choices of Decision 27 for rc9
The maintainer chose the designs of the open items on 2026-10-21: fix 3.1, 3.2, 3.3, and 3.10 of the library items, the dot rules of Get-ChildItem2 -Filter (option B), keep WriteError for Get-NTFSAccess and pin it, an error for Get-NTFSOrphanedAccess, and position 1 for Set-NTFSSecurityDescriptor. Fix B of the piped optional parameters is revised before the build: a bad value on the command line stays a terminating error, a bad piped value is an error per path. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com> |
1 week ago |
|
|
f31c1c2465 |
docs(memory-bank): record Decision 27, the scope of rc9 before 5.0.0
A probe on the published rc8 found that a piped optional enum parameter silently ignores a value that PowerShell cannot convert: a typo for Deny in AccessType creates an Allow entry, AuditFlags, the flags, and AppliesTo fall back to their defaults, and Get-FileHash2 runs SHA256. Named calls fail loudly. The maintainer decided on 2026-10-21 that rc9 fixes the family in the four access and audit cmdlets, changes the items 3 to 7 of the sheet, and gets an independent review. Decision 27 holds the probes, the options, the designs that five read-only research threads proposed, and the recommended defaults. The lab suite run of the new tests (24 runs on six machine classes, 0 failed) is recorded as the agent's flagged assumption. activeContext and progress follow. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com> |
1 week ago |
|
|
7535c0865e |
docs(memory-bank): record that #129 and #130 are merged
The maintainer merged the tests-only round (#129, 2026-10-21 08:24Z) and the Memory Bank (#130, 08:47Z); master is d0cb57c. The new tests gave the same counts on the runner in three CI runs (the first PR head, the second PR head, and master after #129). The notes no longer list the merge as open. What is open before the stable pull request is the decision on #34 (2026-11-02), the check of the PSGALLERY_API_KEY, and the decision on the open items, among them the 10 rows (7 MaintainerDecision, 3 would-pin) that wait for the maintainer. last-verified moves to 2026-10-21 in the three files. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com> |
2 weeks ago |
|
|
d0cb57c503
|
Merge pull request #130 from raandree/ai/memory-bank-rc8
docs(memory-bank): record the published rc8, the tests-only round, and the path to stable |
2 weeks ago |
|
|
792279d90d
|
Merge pull request #129 from raandree/ai/tests-round-1
test: close the plain gaps of the quality gate (tests only) |
2 weeks ago |
|
|
5d7dd3804a |
docs(memory-bank): record the merge of #128 and the CI of #129 and #130
#128 (the rc8 record) merged on 2026-10-21 at 05:48Z, and the tests-only round and this Memory Bank are #129 and #130 with a green CI. On the runner the four configurations give the counts of the local run in each of the 29 test files, so the notes no longer say that the branch is not pushed or that the runner has not run the tests. Records that no plain test gap is left and that the 10 rows that need a decision (7 MaintainerDecision, 3 would-pin) wait for the maintainer. The status paragraph of progress.md drops the list of the merged pull requests of 2026-10-10 that the milestones already carry, which keeps the file within its line budget. 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 |