Browse Source

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>
pull/131/head
Raimund Andree 1 week ago
parent
commit
68eab76867
  1. 6
      Tests/ItemCmdlets.Tests.ps1
  2. 8
      Tests/ObjectApis.Tests.ps1
  3. 53
      Tests/ParameterSets.Access.Tests.ps1
  4. 55
      Tests/ParameterSets.Audit.Tests.ps1
  5. 43
      Tests/PipelineControl.Tests.ps1

6
Tests/ItemCmdlets.Tests.ps1

@ -350,9 +350,9 @@ Describe 'Get-ChildItem2' {
# last dot before the dot token and the question mark account for the final segment. The 8.3-compliant # last dot before the dot token and the question mark account for the final segment. The 8.3-compliant
# names of the truth table above have at most one dot, where the first dot and the last dot are the same # names of the truth table above have at most one dot, where the first dot and the last dot are the same
# position, so they cannot tell the two rules apart; this fixture uses names with two or three dots # position, so they cannot tell the two rules apart; this fixture uses names with two or three dots
# instead, including the realistic ones from the WI. Expected values are pinned with the real name of each # instead, including realistic ones such as archive.tar.gz and jquery.min.js. Expected values are pinned
# item, confirmed with `fsutil file setshortname` so that a short name the volume might otherwise assign # with the real name of each item, confirmed with `fsutil file setshortname` so that a short name the volume
# cannot also produce a match. # might otherwise assign cannot also produce a match.
It 'Should match -Filter "<Filter>" on a name with two or more dots the way Windows PowerShell 5.1 does' -ForEach @( It 'Should match -Filter "<Filter>" on a name with two or more dots the way Windows PowerShell 5.1 does' -ForEach @(
@{ Filter = '*.?'; Expected = @('a.b.c', 'v1.2.3', 'x.y.z.w') } @{ Filter = '*.?'; Expected = @('a.b.c', 'v1.2.3', 'x.y.z.w') }
@{ Filter = '*.??'; Expected = @('a.b.c', 'a.b.cd', 'archive.tar.gz', 'index.d.ts', 'jquery.min.js', 'my.file.tx', 'v1.2.3', 'x.y.z.w') } @{ Filter = '*.??'; Expected = @('a.b.c', 'a.b.cd', 'archive.tar.gz', 'index.d.ts', 'jquery.min.js', 'my.file.tx', 'v1.2.3', 'x.y.z.w') }

8
Tests/ObjectApis.Tests.ps1

@ -1026,9 +1026,10 @@ Describe 'The FileSystemSecurity2 conversions from FileSecurity and DirectorySec
} }
} }
# Review finding: PowerShell's binder uses the fixed conversion of 3.1 for every -SecurityDescriptor parameter, so a # PowerShell's binder uses the conversion from FileSecurity and DirectorySecurity for every -SecurityDescriptor
# descriptor that Get-Acl returns, never meant for these cmdlets, now binds where it used to be a binding error. These # parameter, so a descriptor that Get-Acl returns, never meant for these cmdlets, binds where it used to be a binding
# pin the four cmdlets the review named; the one-line probes of the others are in the final report, not here. # error. The descriptor has no item and no audit section unless Get-Acl read one. These pin a reader of the access
# entries, a reader of the audit entries, the inheritance reader, and the writer.
Describe 'Cmdlets with a security descriptor that Get-Acl returns' { Describe 'Cmdlets with a security descriptor that Get-Acl returns' {
BeforeAll { BeforeAll {
$plainFile = New-TestSandboxItem -Sandbox $sandbox -Name 'GetAclPlain' $plainFile = New-TestSandboxItem -Sandbox $sandbox -Name 'GetAclPlain'
@ -1082,6 +1083,7 @@ Describe 'Cmdlets with a security descriptor that Get-Acl returns' {
(Get-Acl -LiteralPath $plainFile).Sddl | Should -BeExactly $before (Get-Acl -LiteralPath $plainFile).Sddl | Should -BeExactly $before
} }
} }
Describe 'RemoveFileSystemAccessRuleAll and RemoveFileSystemAuditRuleAll honor the account list' { Describe 'RemoveFileSystemAccessRuleAll and RemoveFileSystemAuditRuleAll honor the account list' {
BeforeAll { BeforeAll {
$allow = [System.Security.AccessControl.AccessControlType]::Allow $allow = [System.Security.AccessControl.AccessControlType]::Allow

53
Tests/ParameterSets.Access.Tests.ps1

@ -1384,7 +1384,7 @@ Describe 'Invalid and valid values of AccessType, InheritanceFlags, PropagationF
@{ Cmdlet = $cmdlet; Parameter = 'AppliesTo'; Value = 'Typoo' } @{ Cmdlet = $cmdlet; Parameter = 'AppliesTo'; Value = 'Typoo' }
} }
# R1-2: a named $null (a literal $null, a variable, an alias, splatting, or $PSDefaultParameterValues) must # A named $null (a literal $null, a variable, an alias, splatting, or $PSDefaultParameterValues) must
# stay a terminating error, the same as a bad named value; only a $null that a piped object's property # stay a terminating error, the same as a bad named value; only a $null that a piped object's property
# carries keeps the parameter's own default. # carries keeps the parameter's own default.
$accessNamedNullCases = foreach ($cmdlet in 'Add-NTFSAccess', 'Remove-NTFSAccess') { $accessNamedNullCases = foreach ($cmdlet in 'Add-NTFSAccess', 'Remove-NTFSAccess') {
@ -1421,10 +1421,10 @@ Describe 'Invalid and valid values of AccessType, InheritanceFlags, PropagationF
@{ Cmdlet = $cmdlet; Parameter = 'AppliesTo'; EnumTypeName = 'Security2.ApplyTo' } @{ Cmdlet = $cmdlet; Parameter = 'AppliesTo'; EnumTypeName = 'Security2.ApplyTo' }
} }
# R1-4: a quoted or a wildcard word completed in rc8 (a typed parameter of an enumeration); the first # A quoted or a wildcard word completed while these parameters were typed as enumerations, so the completers
# EnumArgumentCompleters.cs returned nothing for either shape. Each ExpectedName has no sibling name that # must offer the names for either shape too. Each ExpectedName has no sibling name that also starts with it
# also starts with it (ThisFolderOnly has no ThisFolderOnlyOneLevel), so the unquoted and quoted forms match # (ThisFolderOnly has no ThisFolderOnlyOneLevel), so the unquoted and quoted forms match it alone; the
# it alone; the wildcard only needs to contain it among the matches. # wildcard only needs to contain it among the matches.
$accessCompletionFormCases = @( $accessCompletionFormCases = @(
@{ Parameter = 'AccessType'; Word = 'D'; ExpectedName = 'Deny' } @{ Parameter = 'AccessType'; Word = 'D'; ExpectedName = 'Deny' }
@{ Parameter = 'InheritanceFlags'; Word = 'Container'; ExpectedName = 'ContainerInherit' } @{ Parameter = 'InheritanceFlags'; Word = 'Container'; ExpectedName = 'ContainerInherit' }
@ -1432,15 +1432,13 @@ Describe 'Invalid and valid values of AccessType, InheritanceFlags, PropagationF
@{ Parameter = 'AppliesTo'; Word = 'ThisFolderO'; ExpectedName = 'ThisFolderOnly' } @{ Parameter = 'AppliesTo'; Word = 'ThisFolderO'; ExpectedName = 'ThisFolderOnly' }
) )
# R1-1: because the five parameters are object, PowerShell counts a $null, an empty string, or DBNull value # Because the five parameters are object, PowerShell counts a $null, an empty string, or DBNull value of a
# of a property as present when it chooses the parameter set, the same as a real value, so AppliesTo (the # property as present when it chooses the parameter set, the same as a real value, so AppliesTo (the Simple
# Simple group) together with a $null/''/DBNull InheritanceFlags or PropagationFlags (the Complex group) # group) together with a $null/''/DBNull InheritanceFlags or PropagationFlags (the Complex group) offers
# offers both groups and is AmbiguousParameterSet -- not InvalidParameterValue, which is what the docs # both groups and is AmbiguousParameterSet, not InvalidParameterValue. The reverse (AppliesTo blank, a
# wrongly claimed for every shape. The reverse (AppliesTo blank, a Complex property valid) is # Complex property valid) is AmbiguousParameterSet too, except that AppliesTo is Mandatory, so a literal
# AmbiguousParameterSet too, except that AppliesTo is Mandatory, so a literal $null of it (unlike '' or # $null of it (unlike '' or DBNull) is rejected earlier by the binder's own Mandatory check. Covers the
# DBNull) is rejected earlier by the binder's own Mandatory check, unrelated to and unchanged by this # Path and SD sets of the access cmdlets; the audit cmdlets are pinned in ParameterSets.Audit.Tests.ps1.
# finding. Covers the four cmdlets' Path and SD sets; the Audit half of the four cmdlets is pinned in
# ParameterSets.Audit.Tests.ps1.
$accessAmbiguousOtherGroupCases = foreach ($cmdlet in 'Add-NTFSAccess', 'Remove-NTFSAccess') { $accessAmbiguousOtherGroupCases = foreach ($cmdlet in 'Add-NTFSAccess', 'Remove-NTFSAccess') {
foreach ($targetKind in 'Path', 'SD') { foreach ($targetKind in 'Path', 'SD') {
foreach ($shape in 'a $null', 'an empty string', 'DBNull') { foreach ($shape in 'a $null', 'an empty string', 'DBNull') {
@ -1459,10 +1457,9 @@ Describe 'Invalid and valid values of AccessType, InheritanceFlags, PropagationF
} }
} }
# R1-3: with the object type, a script block is a plain value (rc8's delay-bind evaluation, once per piped # With the object type, a script block is a plain value (a typed parameter evaluates it once per piped
# object, no longer applies), so it fails the same way any other value of the wrong shape does: a # object), so it fails the same way any other value of the wrong shape does: a terminating
# terminating InvalidParameterValue from ValidateNamedValue in BeginProcessing, before any piped object is # InvalidParameterValue from ValidateNamedValue in BeginProcessing, before any piped object is processed.
# processed.
$accessScriptBlockCases = foreach ($cmdlet in 'Add-NTFSAccess', 'Remove-NTFSAccess') { $accessScriptBlockCases = foreach ($cmdlet in 'Add-NTFSAccess', 'Remove-NTFSAccess') {
@{ Cmdlet = $cmdlet; Parameter = 'AccessType' } @{ Cmdlet = $cmdlet; Parameter = 'AccessType' }
@{ Cmdlet = $cmdlet; Parameter = 'InheritanceFlags' } @{ Cmdlet = $cmdlet; Parameter = 'InheritanceFlags' }
@ -1671,9 +1668,9 @@ Describe 'Invalid and valid values of AccessType, InheritanceFlags, PropagationF
} }
} }
# R1-2: rc8 ended a named $null (for example a variable that misspells a property, such as -AccessType # A typed parameter ends a named $null (for example a variable that misspells a property, such as -AccessType
# $rule.AccessTpye) with a terminating ParameterBindingFailed; the object-typed parameter accepted it and # $rule.AccessTpye) with a terminating ParameterBindingFailed; the object-typed parameter accepts it, so the
# silently kept the default instead. A named $null is now reported the same way as a bad named value. # cmdlet must not keep the default silently. A named $null is reported the same way as a bad named value.
Context 'A named $null is a terminating error' { Context 'A named $null is a terminating error' {
It 'Should throw a terminating error for a named $null of <Cmdlet> -<Parameter>, and change nothing' -ForEach $accessNamedNullCases { It 'Should throw a terminating error for a named $null of <Cmdlet> -<Parameter>, and change nothing' -ForEach $accessNamedNullCases {
$folder = New-TestSandboxItem -Sandbox $sandbox -Name 'NamedNull' -Directory $folder = New-TestSandboxItem -Sandbox $sandbox -Name 'NamedNull' -Directory
@ -1789,10 +1786,10 @@ Describe 'Invalid and valid values of AccessType, InheritanceFlags, PropagationF
} }
} }
# R1-1: rc8 created the entry for every shape below; the object-typed parameters make a $null, an empty # A typed parameter skips a $null, an empty string, or DBNull value of a property, and the entry was created for
# string, or DBNull value of a property of the other group count as present too, so PowerShell cannot resolve # every shape below; the object-typed parameters count such a value of a property of the other group as present
# the parameter set and nothing is changed. # too, so PowerShell cannot resolve the parameter set and nothing is changed.
Context 'A blank value of the other groups property' { Context 'A blank value of a property of the other group' {
It 'Should reject <Cmdlet> (<TargetKind>) for <Direction> (<Shape>) with the error the binder gives, change nothing, and still process the next object' -ForEach $accessAmbiguousOtherGroupCases { It 'Should reject <Cmdlet> (<TargetKind>) for <Direction> (<Shape>) with the error the binder gives, change nothing, and still process the next object' -ForEach $accessAmbiguousOtherGroupCases {
$bad = New-TestSandboxItem -Sandbox $sandbox -Name 'AmbiguousOtherGroupBad' -Directory $bad = New-TestSandboxItem -Sandbox $sandbox -Name 'AmbiguousOtherGroupBad' -Directory
$next = New-TestSandboxItem -Sandbox $sandbox -Name 'AmbiguousOtherGroupNext' -Directory $next = New-TestSandboxItem -Sandbox $sandbox -Name 'AmbiguousOtherGroupNext' -Directory
@ -1826,9 +1823,9 @@ Describe 'Invalid and valid values of AccessType, InheritanceFlags, PropagationF
} }
} }
# R1-3: with the object type, a script block is a plain value (rc8's delay-bind evaluation, once per piped # With the object type, a script block is a plain value (a typed parameter evaluates it once per piped object),
# object, no longer applies), so ValidateNamedValue in BeginProcessing rejects it the same as any other bad # so ValidateNamedValue in BeginProcessing rejects it the same as any other bad value, before any piped object
# value, before any piped object is processed. # is processed.
Context 'A named script block is a terminating error' { Context 'A named script block is a terminating error' {
It 'Should throw a terminating InvalidParameterValue error for a named script block value of <Cmdlet> -<Parameter>, and change nothing' -ForEach $accessScriptBlockCases { It 'Should throw a terminating InvalidParameterValue error for a named script block value of <Cmdlet> -<Parameter>, and change nothing' -ForEach $accessScriptBlockCases {
$folder = New-TestSandboxItem -Sandbox $sandbox -Name 'NamedScriptBlock' -Directory $folder = New-TestSandboxItem -Sandbox $sandbox -Name 'NamedScriptBlock' -Directory

55
Tests/ParameterSets.Audit.Tests.ps1

@ -1054,7 +1054,7 @@ Describe 'Invalid and valid values of AuditFlags, InheritanceFlags, PropagationF
@{ Cmdlet = $cmdlet; Parameter = 'AppliesTo'; Value = 'Typoo' } @{ Cmdlet = $cmdlet; Parameter = 'AppliesTo'; Value = 'Typoo' }
} }
# R1-2: a named $null (a literal $null, a variable, splatting, or $PSDefaultParameterValues) must stay a # A named $null (a literal $null, a variable, splatting, or $PSDefaultParameterValues) must stay a
# terminating error, the same as a bad named value; only a $null that a piped object's property carries # terminating error, the same as a bad named value; only a $null that a piped object's property carries
# keeps the parameter's own default. # keeps the parameter's own default.
$auditNamedNullCases = foreach ($cmdlet in 'Add-NTFSAudit', 'Remove-NTFSAudit') { $auditNamedNullCases = foreach ($cmdlet in 'Add-NTFSAudit', 'Remove-NTFSAudit') {
@ -1093,22 +1093,20 @@ Describe 'Invalid and valid values of AuditFlags, InheritanceFlags, PropagationF
@{ Cmdlet = $cmdlet; Parameter = 'AppliesTo'; EnumTypeName = 'Security2.ApplyTo' } @{ Cmdlet = $cmdlet; Parameter = 'AppliesTo'; EnumTypeName = 'Security2.ApplyTo' }
} }
# R1-4: AuditFlags is the one completer that ParameterSets.Access.Tests.ps1 does not already cover with the # AuditFlags is the one completer that ParameterSets.Access.Tests.ps1 does not already cover with the
# quoted and wildcard forms (it shares the same completer code for InheritanceFlags, PropagationFlags, and # quoted and wildcard forms (it shares the same completer code for InheritanceFlags, PropagationFlags, and
# AppliesTo, so those are pinned there). # AppliesTo, so those are pinned there).
$auditCompletionFormCases = @( $auditCompletionFormCases = @(
@{ Parameter = 'AuditFlags'; Word = 'F'; ExpectedName = 'Failure' } @{ Parameter = 'AuditFlags'; Word = 'F'; ExpectedName = 'Failure' }
) )
# R1-1: because the five parameters are object, PowerShell counts a $null, an empty string, or DBNull value # Because the five parameters are object, PowerShell counts a $null, an empty string, or DBNull value of a
# of a property as present when it chooses the parameter set, the same as a real value, so AppliesTo (the # property as present when it chooses the parameter set, the same as a real value, so AppliesTo (the Simple
# Simple group) together with a $null/''/DBNull InheritanceFlags or PropagationFlags (the Complex group) # group) together with a $null/''/DBNull InheritanceFlags or PropagationFlags (the Complex group) offers
# offers both groups and is AmbiguousParameterSet -- not InvalidParameterValue, which is what the docs # both groups and is AmbiguousParameterSet, not InvalidParameterValue. The reverse (AppliesTo blank, a
# wrongly claimed for every shape. The reverse (AppliesTo blank, a Complex property valid) is # Complex property valid) is AmbiguousParameterSet too, except that AppliesTo is Mandatory, so a literal
# AmbiguousParameterSet too, except that AppliesTo is Mandatory, so a literal $null of it (unlike '' or # $null of it (unlike '' or DBNull) is rejected earlier by the binder's own Mandatory check. Covers the
# DBNull) is rejected earlier by the binder's own Mandatory check, unrelated to and unchanged by this # Path and SD sets of the audit cmdlets; the access cmdlets are pinned in ParameterSets.Access.Tests.ps1.
# finding. Covers the four cmdlets' Path and SD sets; the Access half is pinned in
# ParameterSets.Access.Tests.ps1.
$auditAmbiguousOtherGroupCases = foreach ($cmdlet in 'Add-NTFSAudit', 'Remove-NTFSAudit') { $auditAmbiguousOtherGroupCases = foreach ($cmdlet in 'Add-NTFSAudit', 'Remove-NTFSAudit') {
foreach ($targetKind in 'Path', 'SD') { foreach ($targetKind in 'Path', 'SD') {
foreach ($shape in 'a $null', 'an empty string', 'DBNull') { foreach ($shape in 'a $null', 'an empty string', 'DBNull') {
@ -1127,10 +1125,9 @@ Describe 'Invalid and valid values of AuditFlags, InheritanceFlags, PropagationF
} }
} }
# R1-3: with the object type, a script block is a plain value (rc8's delay-bind evaluation, once per piped # With the object type, a script block is a plain value (a typed parameter evaluates it once per piped
# object, no longer applies), so it fails the same way any other value of the wrong shape does: a # object), so it fails the same way any other value of the wrong shape does: a terminating
# terminating InvalidParameterValue from ValidateNamedValue in BeginProcessing, before any piped object is # InvalidParameterValue from ValidateNamedValue in BeginProcessing, before any piped object is processed.
# processed.
$auditScriptBlockCases = foreach ($cmdlet in 'Add-NTFSAudit', 'Remove-NTFSAudit') { $auditScriptBlockCases = foreach ($cmdlet in 'Add-NTFSAudit', 'Remove-NTFSAudit') {
@{ Cmdlet = $cmdlet; Parameter = 'AuditFlags' } @{ Cmdlet = $cmdlet; Parameter = 'AuditFlags' }
@{ Cmdlet = $cmdlet; Parameter = 'InheritanceFlags' } @{ Cmdlet = $cmdlet; Parameter = 'InheritanceFlags' }
@ -1349,8 +1346,9 @@ Describe 'Invalid and valid values of AuditFlags, InheritanceFlags, PropagationF
} }
} }
# R1-2: rc8 ended a named $null with a terminating ParameterBindingFailed; the object-typed parameter accepted # A typed parameter ends a named $null with a terminating ParameterBindingFailed; the object-typed parameter
# it and silently kept the default instead. A named $null is now reported the same way as a bad named value. # accepts it, so the cmdlet must not keep the default silently. A named $null is reported the same way as a bad
# named value.
Context 'A named $null is a terminating error' { Context 'A named $null is a terminating error' {
It 'Should throw a terminating error for a named $null of <Cmdlet> -<Parameter>, and change nothing' -ForEach $auditNamedNullCases { It 'Should throw a terminating error for a named $null of <Cmdlet> -<Parameter>, and change nothing' -ForEach $auditNamedNullCases {
$folder = New-TestSandboxItem -Sandbox $sandbox -Name 'NamedNull' -Directory $folder = New-TestSandboxItem -Sandbox $sandbox -Name 'NamedNull' -Directory
@ -1445,13 +1443,13 @@ Describe 'Invalid and valid values of AuditFlags, InheritanceFlags, PropagationF
} }
} }
# R1-1: rc8 created the entry for every shape below; the object-typed parameters make a $null, an empty # A typed parameter skips a $null, an empty string, or DBNull value of a property, and the entry was created for
# string, or DBNull value of a property of the other group count as present too, so PowerShell cannot resolve # every shape below; the object-typed parameters count such a value of a property of the other group as present
# the parameter set and nothing is changed. The conversion/parameter-set failure happens before the cmdlet # too, so PowerShell cannot resolve the parameter set and nothing is changed. The conversion/parameter-set
# ever touches the SACL, so the core assertion (the error id, and that the bad object's audit entries are # failure happens before the cmdlet ever touches the SACL, so the core assertion (the error id, and that the bad
# unchanged) runs in every configuration; only the "good next object succeeded" part needs the Security # object's audit entries are unchanged) runs in every configuration; only the "good next object succeeded" part
# privilege, the same way the rest of this file does. # needs the Security privilege, the same way the rest of this file does.
Context 'A blank value of the other groups property' { Context 'A blank value of a property of the other group' {
It 'Should reject <Cmdlet> (<TargetKind>) for <Direction> (<Shape>) with the error the binder gives, change nothing, and still process the next object' -ForEach $auditAmbiguousOtherGroupCases { It 'Should reject <Cmdlet> (<TargetKind>) for <Direction> (<Shape>) with the error the binder gives, change nothing, and still process the next object' -ForEach $auditAmbiguousOtherGroupCases {
$bad = New-TestSandboxItem -Sandbox $sandbox -Name 'AmbiguousOtherGroupBad' -Directory $bad = New-TestSandboxItem -Sandbox $sandbox -Name 'AmbiguousOtherGroupBad' -Directory
$next = New-TestSandboxItem -Sandbox $sandbox -Name 'AmbiguousOtherGroupNext' -Directory $next = New-TestSandboxItem -Sandbox $sandbox -Name 'AmbiguousOtherGroupNext' -Directory
@ -1492,11 +1490,10 @@ Describe 'Invalid and valid values of AuditFlags, InheritanceFlags, PropagationF
} }
} }
# R1-3: with the object type, a script block is a plain value (rc8's delay-bind evaluation, once per piped # With the object type, a script block is a plain value (a typed parameter evaluates it once per piped object),
# object, no longer applies), so ValidateNamedValue in BeginProcessing rejects it the same as any other bad # so ValidateNamedValue in BeginProcessing rejects it the same as any other bad value, before any piped object
# value, before any piped object is processed and before the cmdlet ever touches the SACL. The terminating # is processed and before the cmdlet ever touches the SACL. The terminating error itself needs no Security
# error itself needs no Security privilege; reading the SACL back to confirm nothing changed does, the same # privilege; reading the SACL back to confirm nothing changed does, the same way the rest of this file does.
# way the rest of this file does.
Context 'A named script block is a terminating error' { Context 'A named script block is a terminating error' {
It 'Should throw a terminating InvalidParameterValue error for a named script block value of <Cmdlet> -<Parameter>, and change nothing' -ForEach $auditScriptBlockCases { It 'Should throw a terminating InvalidParameterValue error for a named script block value of <Cmdlet> -<Parameter>, and change nothing' -ForEach $auditScriptBlockCases {
$folder = New-TestSandboxItem -Sandbox $sandbox -Name 'NamedScriptBlock' -Directory $folder = New-TestSandboxItem -Sandbox $sandbox -Name 'NamedScriptBlock' -Directory

43
Tests/PipelineControl.Tests.ps1

@ -637,33 +637,28 @@ namespace NtfsSecurityTests { public class StandInForBreak : System.Management.A
} }
} }
# InvokeAsOwner (and Set-NTFSSecurityDescriptor's WriteChangesAsOwner) take ownership, run the action, and in a # InvokeAsOwner (and WriteChangesAsOwner of Set-NTFSSecurityDescriptor) take ownership, run the action, and in a
# finally restore the previous owner, writing a RestoreOwnerError through WriteError when that restore fails. # finally restore the previous owner, writing a RestoreOwnerError through WriteError when that restore fails.
# WriteError runs the later commands of the pipeline and notes what they raise (IsFromLaterCommand, above); the catch # WriteError runs the later commands of the pipeline and notes what they raise (IsFromLaterCommand, above); the catch
# around the InvokeAsOwner/WriteChangesAsOwner call must pass that on instead of reporting it as the item's own error # around the call must pass that on instead of reporting it as the item's own error and going on, or the caller never
# and going on, or the caller never sees it. Each row denies the current user the right its own action needs (a # sees it. Each row denies the current user the right its own action needs (a change denial for the writers, a read
# change denial for the writers, a read denial on Everyone for Get-FileHash2, which needs file data, not # denial on Everyone for Get-FileHash2, which needs file data, not permissions) and gives the item an owner that only
# permissions) and gives the item an owner that only the Restore privilege can set back, which the tests turn off; # the Restore privilege can set back, which the tests turn off; the cmdlet then takes ownership, runs the action, and
# InvokeAsOwner/WriteChangesAsOwner then takes ownership, runs the action, and fails to restore the owner. Eight of # fails to restore the owner. Eight of the seventeen handlers can be pinned this way. The scenario and the "without a
# the seventeen handlers of item 7 can be pinned this way. The scenario and the "without a later command" assertion # later command" assertion already exist for most of them in the test files of their cmdlets
# already exist for six of them: ParameterSets.Inheritance.Tests.ps1 (Disable/Enable-NTFSAccessInheritance, # (ParameterSets.Inheritance.Tests.ps1, PathErrors.Tests.ps1, SecurityDescriptor.Tests.ps1, FileHash.Tests.ps1), and
# Set-NTFSInheritance), PathErrors.Tests.ps1 (Clear-NTFSAccess -DisableInheritance), SecurityDescriptor.Tests.ps1 # Add-NTFSAccess and Remove-NTFSAccess use the scenario of the inheritance cmdlets, so this table only adds the
# (Set-NTFSSecurityDescriptor), FileHash.Tests.ps1 (Get-FileHash2); Add-NTFSAccess and Remove-NTFSAccess use the same # later-command assertion.
# scenario as the inheritance cmdlets. So this table only adds the later-command assertion, not a duplicate of the
# existing one.
# #
# NOT DONE for the other nine (the reason is the same Windows rule in both groups: taking ownership only bypasses a # The other nine have no row, for one Windows rule: taking ownership only bypasses a denial of
# denial of ReadPermissions/ChangePermissions, never of a different right): Get-NTFSAccess, Get-NTFSOrphanedAccess, # ReadPermissions/ChangePermissions, never of a different right. Get-NTFSAccess, Get-NTFSOrphanedAccess,
# Get-NTFSEffectiveAccess, and Get-NTFSInheritance read the security descriptor; InvokeAsOwner's own first statement, # Get-NTFSEffectiveAccess, and Get-NTFSInheritance read the security descriptor, and so does the first statement of
# FileSystemOwner.GetOwner, reads it too and needs the same ReadPermissions right the cmdlet's read needs, so a # InvokeAsOwner (FileSystemOwner.GetOwner), which needs the same ReadPermissions right: a denial that fails one fails
# denial that fails one fails the other and InvokeAsOwner never reaches the owner-restore step (verified: denying # the other, so the owner-restore step is never reached (denying ReadPermissions reports a ReadSecurityError with the
# ReadPermissions directly to the user reports ReadSecurityError with the plain UnauthorizedAccessException, not # plain UnauthorizedAccessException, and the owner is never taken). Clear-NTFSAudit, Disable-NTFSAuditInheritance,
# RestoreOwnerError, and the owner is never taken; probes-wi2\p-restoreowner-read-vs-write.ps1, # Enable-NTFSAuditInheritance, Add-NTFSAudit, and Remove-NTFSAudit write the SACL, which Windows grants to this
# p-read-cmdlets-2.ps1). Clear-NTFSAudit, Disable-NTFSAuditInheritance, Enable-NTFSAuditInheritance, Add-NTFSAudit, and # elevated session whatever the DACL says and whatever the EnablePrivileges setting is, so the action does not fail
# Remove-NTFSAudit write the SACL, which Windows grants to this elevated session regardless of a DACL deny and # to begin with (the SACL is written and the owner is left unchanged). The handlers of all seventeen carry the check.
# regardless of the module's EnablePrivileges setting, so the action does not fail to begin with (verified with both
# a ChangePermissions deny and EnablePrivileges off: no error, the SACL is written, and the owner is left unchanged;
# probes-wi2\p-audit-restoreowner.ps1, p-audit-restoreowner-2.ps1). The handlers of all seventeen carry the check.
Describe 'A later command that throws at the RestoreOwnerError record' { Describe 'A later command that throws at the RestoreOwnerError record' {
BeforeDiscovery { BeforeDiscovery {
$holdsRestorePrivilege = Test-PrivilegeHeld -Name 'SeRestorePrivilege' $holdsRestorePrivilege = Test-PrivilegeHeld -Name 'SeRestorePrivilege'

Loading…
Cancel
Save