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 }
18 Commits (master)
| Author | SHA1 | Message | Date |
|---|---|---|---|
|
|
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> |
2 weeks 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> |
2 weeks 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>
|
2 weeks 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> |
2 weeks 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> |
2 weeks 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> |
2 weeks 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> |
2 weeks 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> |
2 weeks 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> |
2 weeks 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> |
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 |
|
|
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 |
|
|
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 |
|
|
f1f3d8f078 |
test(inheritance): read the SACL alone where a test asserts the audit protection flag
Get-Acl -Audit reads the SACL together with the other sections. On a domain member (Windows Server 2019, 2022, and 2025 of the operating-system matrix) that read reports the SACL of an item without audit entries as protected from inheritance, where the read of the SACL alone and Get-NTFSInheritance report it as not protected (FileSystemSecurity2 documents the same difference). The test 'Disable-NTFSAuditInheritance -SecurityDescriptor should take two piped descriptors ...' asserted the on-disk flag of a fresh file with Get-Acl -Audit, and failed in all six elevated configurations of the three file servers. Diagnostic runs on 2019 and 2025 show both reads side by side. Four more assertions read the flag of an item that ends without audit entries and expect "protected"; there they could not tell a written flag from none. The five assertions now read the SACL alone through .NET, as the module does. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com> |
3 weeks ago |
|
|
3fa5adeb0c |
test(audit): assert the parameter sets that the judged matrix found untested
Add Tests\ParameterSets.Audit.Tests.ps1, closing the TestNeeded gaps that judged-audit.csv/judged-audit-notes.md recorded for Add-NTFSAudit, Remove-NTFSAudit, Clear-NTFSAudit, Get-NTFSAudit, and Get-NTFSOrphanedAudit: - Pipeline binding by value and by property name for every parameter set of all five cmdlets, including the four sets the matrix flagged as bound only by splat or pipe calls (Add-NTFSAudit SDSimple, Remove-NTFSAudit PathSimple and SDSimple, Get-NTFSOrphanedAudit SD), each of which also gets a direct, named call. - Continuation past a failing path or a descriptor without an audit section, asserting the ErrorId, category, and target of the error and the state or output of the item that follows. - State assertions beyond -PassThru: SACL/DACL SDDL before and after, the in-memory descriptor versus the item on disk until Set-NTFSSecurityDescriptor writes it, and the protected/unprotected SACL after Clear-NTFSAudit -DisableInheritance. - Narrowing of an audit entry's rights when Remove-NTFSAudit runs without -RemoveSpecific, and the AmbiguousParameterSet error when -AppliesTo and -InheritanceFlags are combined. No production code, existing test file, or helper module changed. Fixture DACLs use .NET SetAccessControl through the existing TestHelpers.psm1 helpers; no test pins the open item of the -SecurityDescriptor sets of Add and Remove having no per-item handler around the change itself. Verified in all four configurations (elevated/basic user x Windows PowerShell 5.1/PowerShell 7): 0 failures. Mutation-tested with 9 one-statement changes to the production C# in a separate, detached worktree; 8 were caught by the new tests and one (the -AppliesTo-to-flags conversion for the Simple sets, masked on a file target) was not, which the pre-existing PermissionScopes.Tests.ps1 already catches on a folder target. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant <ai@example.com> |
3 weeks ago |