Browse Source

test: share the sandbox item and read-deny helpers

- New-TestSandboxItem creates a uniquely named file or folder in a sandbox
  after the path guard, replacing per-file copies.
- Block-TestReadPermission denies OWNER RIGHTS the right to read the
  security descriptor of a sandbox item, so that reading it fails without
  elevation.
- Remove-TestSandbox no longer stops when icacls cannot reset such an
  item: Windows PowerShell turned the icacls message on stderr into a
  terminating error; the item is still deleted through its folder.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: AI Assistant <ai@example.com>
pull/100/head
Raimund Andree 1 week ago
parent
commit
b329998de3
  1. 41
      Tests/Audit.Tests.ps1
  2. 9
      Tests/Inheritance.Tests.ps1
  3. 71
      Tests/TestHelpers.psm1

41
Tests/Audit.Tests.ps1

@ -19,37 +19,6 @@ BeforeAll {
Import-Module -Name $modulePath -Force -ErrorAction Stop Import-Module -Name $modulePath -Force -ErrorAction Stop
$sandbox = New-TestSandbox -Name 'Audit' $sandbox = New-TestSandbox -Name 'Audit'
Push-Location -LiteralPath $sandbox Push-Location -LiteralPath $sandbox
function New-SandboxItem {
param (
[string] $Name,
[switch] $Directory
)
$path = Join-Path -Path $sandbox -ChildPath ('{0}-{1}' -f $Name, [guid]::NewGuid().ToString('N').Substring(0, 8))
Assert-TestSandboxPath -Sandbox $sandbox -Path $path
if ($Directory) {
New-Item -ItemType Directory -Path $path | Out-Null
}
else {
Set-Content -LiteralPath $path -Value 'Audit test'
}
$path
}
# Denies the owner, the current account, to read the security descriptor of the item.
function Deny-ReadPermission {
param ([string] $Path)
Assert-TestSandboxPath -Sandbox $sandbox -Path $Path
$acl = Get-Acl -LiteralPath $Path
$ownerRights = New-Object -TypeName 'System.Security.Principal.SecurityIdentifier' -ArgumentList 'S-1-3-4'
$rule = New-Object -TypeName 'System.Security.AccessControl.FileSystemAccessRule' -ArgumentList (
$ownerRights, [System.Security.AccessControl.FileSystemRights]::ReadPermissions, [System.Security.AccessControl.AccessControlType]::Deny
)
$acl.AddAccessRule($rule)
Set-Acl -LiteralPath $Path -AclObject $acl
}
} }
AfterAll { AfterAll {
@ -61,7 +30,7 @@ AfterAll {
Describe 'Get-NTFSAudit' { Describe 'Get-NTFSAudit' {
Context 'When the audit entries cannot be read' { Context 'When the audit entries cannot be read' {
It 'Should write an error without the Security privilege instead of returning nothing' -Skip:$canReadAudit { It 'Should write an error without the Security privilege instead of returning nothing' -Skip:$canReadAudit {
$file = New-SandboxItem -Name 'NoPrivilege' $file = New-TestSandboxItem -Sandbox $sandbox -Name 'NoPrivilege'
$entries = @(Get-NTFSAudit -Path $file -ErrorVariable auditErrors -ErrorAction SilentlyContinue) $entries = @(Get-NTFSAudit -Path $file -ErrorVariable auditErrors -ErrorAction SilentlyContinue)
@ -71,7 +40,7 @@ Describe 'Get-NTFSAudit' {
} }
It 'Should write an error for a security descriptor that was read without the audit entries' { It 'Should write an error for a security descriptor that was read without the audit entries' {
$file = New-SandboxItem -Name 'AccessOnly' $file = New-TestSandboxItem -Sandbox $sandbox -Name 'AccessOnly'
$sd = New-Object -TypeName 'Security2.FileSystemSecurity2' -ArgumentList ( $sd = New-Object -TypeName 'Security2.FileSystemSecurity2' -ArgumentList (
(Get-Item2 -Path $file), [System.Security.AccessControl.AccessControlSections]::Access (Get-Item2 -Path $file), [System.Security.AccessControl.AccessControlSections]::Access
) )
@ -87,10 +56,10 @@ Describe 'Get-NTFSAudit' {
Context 'When a path fails after a path with audit entries' { Context 'When a path fails after a path with audit entries' {
# Before 5.0.0, the cmdlet wrote the entries of the previous item again for the failing path. # Before 5.0.0, the cmdlet wrote the entries of the previous item again for the failing path.
It 'Should return the entries of the first item once' -Skip:(-not $canReadAudit) { It 'Should return the entries of the first item once' -Skip:(-not $canReadAudit) {
$folder = New-SandboxItem -Name 'Audited' -Directory $folder = New-TestSandboxItem -Sandbox $sandbox -Name 'Audited' -Directory
$denied = New-SandboxItem -Name 'Denied' $denied = New-TestSandboxItem -Sandbox $sandbox -Name 'Denied'
Add-NTFSAudit -Path $folder -Account 'Everyone' -AccessRights Delete -AuditFlags Success Add-NTFSAudit -Path $folder -Account 'Everyone' -AccessRights Delete -AuditFlags Success
Deny-ReadPermission -Path $denied Block-TestReadPermission -Sandbox $sandbox -Path $denied
$entries = @(Get-NTFSAudit -Path $folder, $denied -ExcludeInherited -ErrorAction SilentlyContinue) $entries = @(Get-NTFSAudit -Path $folder, $denied -ExcludeInherited -ErrorAction SilentlyContinue)

9
Tests/Inheritance.Tests.ps1

@ -18,13 +18,6 @@ BeforeAll {
Import-Module -Name $modulePath -Force -ErrorAction Stop Import-Module -Name $modulePath -Force -ErrorAction Stop
$sandbox = New-TestSandbox -Name 'Inheritance' $sandbox = New-TestSandbox -Name 'Inheritance'
Push-Location -LiteralPath $sandbox Push-Location -LiteralPath $sandbox
function New-SandboxFile {
$path = Join-Path -Path $sandbox -ChildPath ('File-{0}.txt' -f [guid]::NewGuid().ToString('N').Substring(0, 8))
Assert-TestSandboxPath -Sandbox $sandbox -Path $path
Set-Content -LiteralPath $path -Value 'Inheritance test'
$path
}
} }
AfterAll { AfterAll {
@ -36,7 +29,7 @@ AfterAll {
Describe 'Set-NTFSInheritance' { Describe 'Set-NTFSInheritance' {
Context 'When -AccessInheritanceEnabled or -AuditInheritanceEnabled is omitted' { Context 'When -AccessInheritanceEnabled or -AuditInheritanceEnabled is omitted' {
BeforeEach { BeforeEach {
$file = New-SandboxFile $file = New-TestSandboxItem -Sandbox $sandbox -Name 'File'
Assert-TestSandboxPath -Sandbox $sandbox -Path $file Assert-TestSandboxPath -Sandbox $sandbox -Path $file
} }

71
Tests/TestHelpers.psm1

@ -86,6 +86,10 @@ function Remove-TestSandbox {
return return
} }
# icacls reports items it cannot reset on stderr, which Windows PowerShell turns into a terminating error when
# the caller uses ErrorAction Stop. Such items can still be deleted through the rights on their folder.
$ErrorActionPreference = 'Continue'
# Windows PowerShell 5.1 follows directory links when it removes a folder recursively, so the links go first. # Windows PowerShell 5.1 follows directory links when it removes a folder recursively, so the links go first.
& icacls.exe $Sandbox /reset /T /C /Q *> $null & icacls.exe $Sandbox /reset /T /C /Q *> $null
$pending = New-Object -TypeName 'System.Collections.Generic.Stack[string]' $pending = New-Object -TypeName 'System.Collections.Generic.Stack[string]'
@ -120,6 +124,70 @@ function Remove-TestSandbox {
} }
} }
function New-TestSandboxItem {
<#
.SYNOPSIS
Creates a file or folder with a unique name in the sandbox and returns its full path.
#>
[Diagnostics.CodeAnalysis.SuppressMessageAttribute(
'PSUseShouldProcessForStateChangingFunctions', '', Justification = 'Test helper that only writes to sandboxes.'
)]
[CmdletBinding()]
[OutputType([string])]
param (
[Parameter(Mandatory)]
[string]
$Sandbox,
[ValidatePattern('^[\w-]+$')]
[string]
$Name = 'Item',
[switch]
$Directory
)
$path = Join-Path -Path $Sandbox -ChildPath ('{0}-{1}' -f $Name, [guid]::NewGuid().ToString('N').Substring(0, 8))
Assert-TestSandboxPath -Sandbox $Sandbox -Path $path
if ($Directory) {
New-Item -ItemType Directory -Path $path | Out-Null
}
else {
Set-Content -LiteralPath $path -Value $Name
}
$path
}
function Block-TestReadPermission {
<#
.SYNOPSIS
Denies the owner of an item in the sandbox to read its security descriptor, so that reading it fails.
.DESCRIPTION
Adds a deny entry for OWNER RIGHTS (S-1-3-4) with ReadPermissions, which replaces the implicit right of the
owner to read the security descriptor. Remove-TestSandbox resets it.
#>
[CmdletBinding()]
param (
[Parameter(Mandatory)]
[string]
$Sandbox,
[Parameter(Mandatory)]
[string]
$Path
)
Assert-TestSandboxPath -Sandbox $Sandbox -Path $Path
$acl = Get-Acl -LiteralPath $Path
$ownerRights = New-Object -TypeName 'System.Security.Principal.SecurityIdentifier' -ArgumentList 'S-1-3-4'
$rule = New-Object -TypeName 'System.Security.AccessControl.FileSystemAccessRule' -ArgumentList (
$ownerRights, [System.Security.AccessControl.FileSystemRights]::ReadPermissions,
[System.Security.AccessControl.AccessControlType]::Deny
)
$acl.AddAccessRule($rule)
Set-Acl -LiteralPath $Path -AclObject $acl
}
function Test-IsElevated { function Test-IsElevated {
<# <#
.SYNOPSIS .SYNOPSIS
@ -160,4 +228,5 @@ function Test-PrivilegeHeld {
Where-Object -Property Name -EQ -Value $Name) Where-Object -Property Name -EQ -Value $Name)
} }
Export-ModuleMember -Function New-TestSandbox, Assert-TestSandboxPath, Remove-TestSandbox, Test-IsElevated, Test-PrivilegeHeld Export-ModuleMember -Function New-TestSandbox, Assert-TestSandboxPath, Remove-TestSandbox, New-TestSandboxItem,
Block-TestReadPermission, Test-IsElevated, Test-PrivilegeHeld

Loading…
Cancel
Save