private/Confirm-MsecEvidenceOverwrite.ps1
|
function Confirm-MsecEvidenceOverwrite { <# .SYNOPSIS Asks before an evidence report replaces a worksheet that already holds data. Returns $true to go ahead. .DESCRIPTION Snapshot reports REPLACE rather than append - that is the point of them, and it is also how last month's evidence gets destroyed by a mistyped path. This asks first, and only when something would actually be lost: a new file, or a new owner in an existing file, is not a question worth interrupting for. The prompt names the sheet, how many rows it holds and when they were collected, so the answer can be given on the facts rather than on a generic "are you sure". ASKED BEFORE THE COLLECTION, NOT AFTER. Callers put this immediately after the owner is known and before any data is gathered, so declining costs nothing - no Graph enumeration, and on the VM reports no Run Command invocations against live machines. Unattended runs need -Force: a scheduled task has no one to answer, and ShouldContinue in a non-interactive host is an error rather than a default. .PARAMETER Cmdlet The calling cmdlet's $PSCmdlet, which is what owns the prompt and honours -Confirm. .PARAMETER Force Skip the prompt and replace. For scheduled and unattended runs. #> [CmdletBinding(DefaultParameterSetName = 'Single')] [OutputType([bool])] param( [Parameter(Mandatory)] [string] $Path, [Parameter(Mandatory, ParameterSetName = 'Single')] [string] $OwnerName, [Parameter(Mandatory, ParameterSetName = 'Single')] [AllowEmptyString()] [string] $OwnerId, # Several subjects in one run - a report that writes a sheet per group rather than one # per tenant. Each needs a Name and an Id. Asked as ONE question: a wildcard can match # forty groups, and forty prompts is a prompt nobody reads. [Parameter(Mandatory, ParameterSetName = 'Many')] [AllowEmptyCollection()] [object[]] $Owner, [Parameter(Mandatory)] [string] $OwnerColumn, [Parameter(Mandatory)] $Cmdlet, [switch] $Force ) if ($Force) { return $true } $subjects = if ($PSCmdlet.ParameterSetName -eq 'Many') { @($Owner) } else { @([pscustomobject]@{ Name = $OwnerName; Id = $OwnerId }) } $replacing = @( foreach ($subject in $subjects) { $sheet = Resolve-MsecEvidenceSheet -Path $Path -OwnerName ([string] $subject.Name) ` -OwnerId ([string] $subject.Id) -OwnerColumn $OwnerColumn if ($sheet.IsReplace) { $held = if ($sheet.RowCount) { "$($sheet.RowCount) row(s)" + $(if ($sheet.CollectedUtc) { " collected $($sheet.CollectedUtc) UTC" } else { '' }) } else { 'data that could not be read back' } [pscustomobject]@{ Name = $subject.Name; SheetName = $sheet.SheetName; Held = $held } } } ) if (-not $replacing.Count) { return $true } $query = if ($replacing.Count -eq 1) { "Worksheet '$($replacing[0].SheetName)' in '$Path' already holds $($replacing[0].Held) for '$($replacing[0].Name)'. Writing replaces them - a snapshot report does not append. Continue?" } else { "$($replacing.Count) worksheet(s) in '$Path' already hold evidence and will be replaced - a snapshot report does not append: " + (($replacing | ForEach-Object { "'$($_.SheetName)' ($($_.Held))" }) -join ', ') + '. Continue?' } if ($Cmdlet.ShouldContinue($query, 'Replace existing evidence?')) { return $true } Write-Warning "Skipped - '$Path' was left unchanged. Use -Force to replace without being asked, or write to a different path." return $false } |