mirror of https://github.com/raandree/NTFSSecurity
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
131 lines
8.3 KiB
131 lines
8.3 KiB
[CmdletBinding()]
|
|
param (
|
|
[Parameter(Mandatory)] [string] $MatrixRoot,
|
|
[Parameter(Mandatory)] [string[]] $Label,
|
|
[Parameter(Mandatory)] [string] $OutputPath
|
|
)
|
|
|
|
# The timeline of the cells of the operating-system matrix (Decision 24): for each cell and edition in which the Admin role ran, in the order in which the
|
|
# cells ran, the module under test, the account of case 3 (its name and its relative ID, which tells two accounts of one name apart within a domain),
|
|
# whether the previous cell had the same name and the same account, when the previous fixture was removed, when the accounts were created, when the
|
|
# Admin role started, the minutes between them, and the three effective-access tests of case 3 in the Admin role (result, milliseconds, and the rights
|
|
# that a failing test received). A failing effective-access test of the Admin role is easy to blame on the module or on the environment; this table
|
|
# puts it beside the module, the position of the cell in the sequence, and the age of the accounts. Pass every label of a series, also a run that
|
|
# stopped before its tests (it writes no row, but it created and removed the accounts, which the next cell reports as the previous removal). The
|
|
# times come from the logs of Run-MatrixSequence.ps1 and of the controller (UTC). It reads files only; Windows PowerShell 5.1 or PowerShell 7.
|
|
$ErrorActionPreference = 'Stop'
|
|
# -File passes an array as one string, so a list may arrive as 'A,B'.
|
|
$Label = @($Label | ForEach-Object -Process { $_ -split ',' } | Where-Object -FilterScript { $_ })
|
|
function Get-LogTime {
|
|
param ([string[]] $Lines, [string] $Pattern)
|
|
$line = $Lines | Where-Object -FilterScript { $_ -match $Pattern } | Select-Object -First 1
|
|
if ($line -and $line -match '^\[(\d{4}-\d\d-\d\d \d\d:\d\d:\d\d)Z?\]') {
|
|
[DateTime]::ParseExact($Matches[1], 'yyyy-MM-dd HH:mm:ss', [Globalization.CultureInfo]::InvariantCulture)
|
|
}
|
|
}
|
|
|
|
$cells = New-Object -TypeName 'System.Collections.Generic.List[object]'
|
|
foreach ($name in $Label) {
|
|
$sequenceLog = Join-Path -Path $MatrixRoot -ChildPath ('{0}-sequence.log' -f $name)
|
|
if (-not (Test-Path -LiteralPath $sequenceLog)) { continue }
|
|
$candidate = if ((Get-Content -LiteralPath $sequenceLog -TotalCount 1) -match 'candidate-(\w+)') { $Matches[1] } else { '' }
|
|
foreach ($folder in (Get-ChildItem -LiteralPath $MatrixRoot -Directory -Filter ('{0}-*' -f $name))) {
|
|
$runLog = Join-Path -Path $folder.FullName -ChildPath 'run.log'
|
|
if (-not (Test-Path -LiteralPath $runLog)) { continue }
|
|
$run = @(Get-Content -LiteralPath $runLog)
|
|
$removeLog = Join-Path -Path $folder.FullName -ChildPath 'cleanup-2-remove.log'
|
|
$removed = if (Test-Path -LiteralPath $removeLog) { Get-LogTime -Lines @(Get-Content -LiteralPath $removeLog) -Pattern 'Removed the live tests' }
|
|
$configuration = Get-ChildItem -LiteralPath (Join-Path -Path $folder.FullName -ChildPath 'Results') -Recurse -Filter 'local-*.json' -ErrorAction SilentlyContinue |
|
|
Where-Object -FilterScript { $_.Name -match '-\d{14}\.json$' } | Select-Object -First 1
|
|
$subjectName = ''
|
|
$subjectRid = ''
|
|
if ($configuration) {
|
|
$subject = (Get-Content -LiteralPath $configuration.FullName -Raw | ConvertFrom-Json).Accounts.Subject
|
|
$subjectName = $subject.Name
|
|
$subjectRid = ($subject.Sid -split '-')[-1]
|
|
}
|
|
else {
|
|
# A cell that stopped before its tests has no result file, but it created and removed the accounts, so the snapshot of its fixture names them.
|
|
$snapshotLog = Join-Path -Path $folder.FullName -ChildPath 'cleanup-1-snapshot.log'
|
|
$snapshot = if (Test-Path -LiteralPath $snapshotLog) { Get-Content -LiteralPath $snapshotLog -Raw }
|
|
if ($snapshot -match '(?m)^(\w+)\.\S+\s+OU NTFSSecurityLive.*\b(NtfsLiveSubject\w*)=S-[\d-]+-(\d+)') {
|
|
$subjectName = '{0}\{1}' -f $Matches[1], $Matches[2]
|
|
$subjectRid = $Matches[3]
|
|
}
|
|
}
|
|
|
|
$cells.Add([pscustomobject]@{
|
|
Run = $name
|
|
Candidate = $candidate
|
|
FileServer = $folder.Name.Substring($name.Length + 1)
|
|
Folder = $folder.FullName
|
|
Lines = $run
|
|
Subject = $subjectName
|
|
SubjectRid = $subjectRid
|
|
Started = Get-LogTime -Lines $run -Pattern 'START live tests'
|
|
Created = Get-LogTime -Lines $run -Pattern 'Preparing the accounts'
|
|
Removed = $removed
|
|
})
|
|
}
|
|
}
|
|
|
|
$rows = New-Object -TypeName 'System.Collections.Generic.List[object]'
|
|
$previous = $null
|
|
foreach ($cell in ($cells | Sort-Object -Property Started)) {
|
|
foreach ($edition in 'Desktop', 'Core') {
|
|
$adminStart = Get-LogTime -Lines $cell.Lines -Pattern "local-$edition-\d+: role Admin$"
|
|
if (-not $adminStart) { continue }
|
|
$tests = @{ T1 = ''; T2 = ''; T3 = '' }
|
|
$failures = 0
|
|
$adminLog = Get-ChildItem -LiteralPath (Join-Path -Path $cell.Folder -ChildPath 'Results') -Recurse -Filter "local-$edition-*-Admin.log" | Select-Object -First 1
|
|
if ($adminLog) {
|
|
$text = @(Get-Content -LiteralPath $adminLog.FullName)
|
|
$start = ($text | Select-String -Pattern 'Describing Get-NTFSEffectiveAccess for a domain account on a share folder' | Select-Object -First 1).LineNumber
|
|
$seen = 0
|
|
for ($index = $start; $start -and $index -lt $text.Count -and $seen -lt 3; $index++) {
|
|
if ($text[$index] -notmatch '^\s+\[([+-])\] (.+?) (\d+(?:\.\d+)?m?s) \(') { continue }
|
|
$outcome = $Matches[1]; $title = $Matches[2]; $duration = $Matches[3]
|
|
$received = ''
|
|
if ($outcome -eq '-') {
|
|
$failures++
|
|
for ($next = $index + 1; $next -lt [Math]::Min($index + 12, $text.Count); $next++) {
|
|
if ($text[$next] -match "But was:\s+'(0x\w+)'") { $received = ' ' + $Matches[1]; break }
|
|
if ($text[$next] -match 'Expected \$null or empty') { $received = ' errors'; break }
|
|
}
|
|
}
|
|
|
|
$key = if ($title -match 'with -ServerName, without') { 'T1' } elseif ($title -match 'without -ServerName') { 'T2' } else { 'T3' }
|
|
$tests[$key] = '{0} {1}{2}' -f $(if ($outcome -eq '+') { 'pass' } else { 'FAIL' }), $duration, $received
|
|
$seen++
|
|
}
|
|
}
|
|
|
|
$hasPrevious = $null -ne $previous -and $null -ne $previous.Removed
|
|
$sameName = $null -ne $previous -and $cell.Subject -and $previous.Subject -eq $cell.Subject
|
|
$rows.Add([pscustomobject][ordered]@{
|
|
Run = $cell.Run
|
|
Candidate = $cell.Candidate
|
|
FileServer = $cell.FileServer
|
|
Edition = $edition
|
|
Subject = $cell.Subject
|
|
SubjectRid = $cell.SubjectRid
|
|
SameNameAsPreviousCell = [bool] $sameName
|
|
SameAccountAsPreviousCell = [bool] ($sameName -and $previous.SubjectRid -eq $cell.SubjectRid)
|
|
PreviousRemoval = $(if ($hasPrevious) { '{0:yyyy-MM-dd HH:mm:ss}' -f $previous.Removed })
|
|
AccountsCreated = '{0:yyyy-MM-dd HH:mm:ss}' -f $cell.Created
|
|
AdminRoleStarted = '{0:yyyy-MM-dd HH:mm:ss}' -f $adminStart
|
|
MinutesRemovalToCreation = $(if ($hasPrevious) { '{0:N1}' -f ($cell.Created - $previous.Removed).TotalMinutes })
|
|
MinutesCreationToAdmin = '{0:N1}' -f ($adminStart - $cell.Created).TotalMinutes
|
|
MinutesRemovalToAdmin = $(if ($hasPrevious) { '{0:N1}' -f ($adminStart - $previous.Removed).TotalMinutes })
|
|
T1ServerNameFileServer = $tests.T1
|
|
T2DefaultServerName = $tests.T2
|
|
T3UnreachableServerName = $tests.T3
|
|
EffectiveAccessFailures = $failures
|
|
})
|
|
}
|
|
|
|
$previous = [pscustomobject]@{ Removed = $cell.Removed; Subject = $cell.Subject; SubjectRid = $cell.SubjectRid }
|
|
}
|
|
|
|
$rows | Export-Csv -LiteralPath $OutputPath -NoTypeInformation -Encoding ASCII
|
|
'{0} rows for {1} cells written to {2}' -f $rows.Count, $cells.Count, $OutputPath
|
|
|