Execution.psm1
function Invoke-SelfElevation() { # Self-elevate the script if required if (-not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] 'administrator')) { if ([int] (Get-CimInstance -Class Win32_OperatingSystem | Select-Object -ExpandProperty BuildNumber) -ge 6000) { # $elevateVersion = '1.0.0' # $elevateDir = Join-Path $RootDir "_tools" # $elevateExe = Join-Path $elevateDir 'elevate.exe' # if (!(Test-Path $elevateExe)) { # if (-not (Test-Path $elevateDir)) { # New-Item $elevateDir -ItemType Directory > $null # } # Log info 'Downloading elevate' # Invoke-WebRequest "https://github.com/DoCode/elevation/releases/download/$elevateVersion/elevate.exe" -UseBasicParsing -OutFile $elevateExe # } # Always append '-newWindow' to leave elevated window open $Global:ScriptArgs += ' -newWindow' $Global:ScriptArgs = $Global:ScriptArgs.Trim() $argumentList = "-NoProfile -ExecutionPolicy Unrestricted -Command `"& `"$($MyInvocation.PSCommandPath)`" $Global:ScriptArgs`"" Start-Process -FilePath powershell -ArgumentList $argumentList -WorkingDirectory $PSScriptRoot -Verb runas # $argumentList = "powershell -NoProfile -ExecutionPolicy Unrestricted -Command `"& `"$PSCommandPath`" $ScriptArgs`"" # Start-Process -FilePath $elevateExe -ArgumentList $argumentList -WorkingDirectory $elevateDir exit 0 } } } function Exit-WithAndWaitOnExplorer([int] $exitCode) { $parentProcessId = Get-CimInstance Win32_Process -Filter "ProcessId = $PID" | Select-Object -ExpandProperty ParentProcessId if ($parentProcessId) { $parentParentProcessId = Get-CimInstance Win32_Process -Filter "ProcessId = $parentProcessId" | Select-Object -ExpandProperty ParentProcessId if ($parentParentProcessId) { $parentParentProcessName = Get-CimInstance Win32_Process -Filter "ProcessId = $parentParentProcessId" | Select-Object -ExpandProperty Name } } $newWindow = $Global:ScriptArgs.ToLowerInvariant().Contains('-newWindow'.ToLowerInvariant()) if (($parentParentProcessId -and $parentParentProcessName -eq 'explorer.exe') -or $newWindow) { Log info 'Press any key to continue . . . ' $HOST.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown') > $null $HOST.UI.RawUI.FlushInputBuffer() } exit $exitCode } function Start-NativeExecution() { $backupEap = $Script:ErrorActionPreference $Script:ErrorActionPreference = 'Continue' try { if ($args.Length -lt 1) { Log warning 'No arguments specified' return } Log trace "Execute: '$args'" $command = $args[0] | Get-QuotedPath $arguments = $args | Select-Object -Skip 1 | Get-QuotedPath Log trace "Command: '$command'" if ($arguments -and $arguments.Length -gt 0) { Log trace "Arguments: '$arguments'" } $wrapperScriptBlock = [ScriptBlock]::Create("& $command $arguments") $calledFromPrompt = Test-CalledFromPrompt if ($calledFromPrompt) { $wrapperScriptBlock = [ScriptBlock]::Create("& $command $arguments") } else { $wrapperScriptBlock = [ScriptBlock]::Create("& $command $arguments 2>&1") } Log trace "WrapperScriptBlock: '$wrapperScriptBlock'" $messages = & $wrapperScriptBlock # NOTE: If $wrapperScriptBlock's command doesn't have a native invocation, # $LASTEXITCODE will point to the obsolete value Log trace "LASTEXITCODE: $LASTEXITCODE" if (-not $?) { Log error "Execution of '$args' failed with exit code $LASTEXITCODE." $logLevel = 'error' } else { if ($LASTEXITCODE -ne 0) { $logLevel = 'warning' } else { $logLevel = 'info' } } if ($calledFromPrompt -and (Test-Path Variable:\messages)) { if ($messages -is [System.Object[]]) { foreach ($message in $messages) { if ($message.GetType() -eq [System.Management.Automation.ErrorRecord]) { $lines = $message.Exception.Message.Split("`r`n", [System.StringSplitOptions]::RemoveEmptyEntries) } elseif ($message.GetType() -eq [string]) { $lines = $message.Split("`r`n", [System.StringSplitOptions]::RemoveEmptyEntries) } if (Test-Path Variable:\lines) { $lines | Log $logLevel } } } if ($messages -is [string]) { $messages.Split("`r`n", [System.StringSplitOptions]::RemoveEmptyEntries) | Log $logLevel } } } catch { if ($_.Exception -and $_.Exception.Message) { $_.Exception.Message.Split("`r`n", [System.StringSplitOptions]::RemoveEmptyEntries) | Log error } } finally { if (-not (Test-Path Variable:\messages)) { $messages = $null } $Script:ErrorActionPreference = $backupEap } return $messages } function Get-QuotedPath { [CmdletBinding()] param( [Parameter(Mandatory, ValueFromPipeline)] [string] $Path ) process { Log trace "Path: $Path" if ($Path -match '\s') { return "`"$Path`"" } else { return $Path } } } function Test-CalledFromPrompt() { $command = (Get-PSCallStack)[-2].Command Log trace "PromptCommand: $command" return ($command -eq 'prompt') } |