Invoke-GutcheckElevated.ps1
|
<#
.SYNOPSIS The launcher the Elevated Part of a Run is started against. Not for a Technician to run. .DESCRIPTION Started by absolute path by the Main Part, behind a UAC prompt, and possibly as a different user than the one who began the Run. It imports the module by path rather than by name. That is the entire reason this file exists: an admin colleague entering their own credentials gets their own logon, and a module installed for the Technician's account is not on that logon's PSModulePath. A launcher that did Import-Module Gutcheck would work on the developer's machine and fail at every Customer Site where the Technician is not a local admin - which is all of them, and the reason the two-Part design exists at all. Check Definitions arrive as JSON in the transfer directory. The elevated process is handed data and never a command, which is ADR-0001 holding at the one boundary where breaking it would mean a Run elevating something it was told to elevate. .PARAMETER ManifestPath Absolute path to Gutcheck.psd1, so the module is imported by path. .PARAMETER TransferPath Directory holding checks.json, and where admin.clixml and the console log are written. #> [CmdletBinding()] param( [Parameter(Mandatory)][string]$ManifestPath, [Parameter(Mandatory)][string]$TransferPath ) $ErrorActionPreference = 'Stop' $ProgressPreference = 'SilentlyContinue' try { New-Item -ItemType Directory -Path $TransferPath -Force | Out-Null # Started before the first Check and stopped however this ends: the Main Part collects # it, and it is what a Technician hands to second level when the admin half misbehaved. try { Start-Transcript -Path (Join-Path $TransferPath 'console-admin.log') -Force | Out-Null } catch { } Import-Module $ManifestPath -Force $identity = [Security.Principal.WindowsIdentity]::GetCurrent().Name Write-Host (Get-Text 'Console.Elevation.Running' $identity) -ForegroundColor Cyan $result = Invoke-Gutcheck -Part Elevated -TransferPath $TransferPath -NoShow $payload = [pscustomobject]@{ Identity = $identity Finding = @($result.Finding) Section = @($result.Section) Event = @($result.Event) Finished = Get-Date } try { Stop-Transcript | Out-Null } catch { } # Written aside and moved into place, so the Main Part never reads a half-written file: # it is polling for this name and a partial read would lose the whole elevated half. $temporary = Join-Path $TransferPath 'admin.tmp' $payload | Export-Clixml -Path $temporary -Depth 6 Move-Item $temporary (Join-Path $TransferPath 'admin.clixml') -Force exit 0 } catch { # The Main Part treats an absent result file as "the admin half did not happen", which # is the truth here too. Writing the message where it can be read still helps. try { Write-Host (Get-Text 'Console.Elevation.Failed' $_.Exception.Message) -ForegroundColor Red } catch { } try { Stop-Transcript | Out-Null } catch { } exit 1 } |