Functions/GenXdev.Windows/Invoke-CommandElevated.ps1
|
<# .SYNOPSIS Runs code in an elevated PowerShell session, streaming output back to the original terminal. .DESCRIPTION Ensures a scriptblock is executed in an elevated (admin) session using a proper user-experience. After the scriptblock has completed, the environment variables are updated to reflect any changes made in the elevated session. In contrast to other Environment variables, the directories in $ENV:PATH is merged. .LICENSE Copyright (C) 2026 René Vaessen / GenXdev This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>. .PARAMETER ScriptBlock Scriptblock to execute in elevated session .PARAMETER JobDescription Description of the job to be displayed in the window title .PARAMETER PauseAfterCompletion Optionally pauses after the scriptblock has completed .PARAMETER DontUpdateEnvironment Optionally skips updating the environment after the elevated session has completed. .EXAMPLE Invoke-CommandElevated { sfc /scannow } -PauseAfterCompletion #> function Invoke-CommandElevated { [CmdletBinding()] param ( [Parameter(Mandatory = $true, Position = 0, HelpMessage = "Scriptblock to execute in elevated session")] [ScriptBlock] $ScriptBlock, [Parameter(Mandatory = $false, Position = 1, HelpMessage = "Description of the job to be displayed in the window title")] [String] $JobDescription = "Launching elevated session", [Parameter(Mandatory = $false, HelpMessage = "Optionally pauses after the scriptblock has completed")] [Switch] $PauseAfterCompletion, [Parameter(Mandatory = $false, HelpMessage = "Optionally skips updating the environment after the elevated session has completed.")] [Switch] $DontUpdateEnvironment ) if (GenXdev\CurrentUserHasElevatedRights) { Microsoft.PowerShell.Core\Invoke-Command -ScriptBlock $ScriptBlock return } 1..25 | Microsoft.PowerShell.Core\ForEach-Object { Microsoft.PowerShell.Utility\Write-Progress -Id 11232 -Activity "$JobDescription" -Status "Prepare for upcoming UAC prompt.." -PercentComplete $_ Microsoft.PowerShell.Utility\Start-Sleep -Milliseconds 80 } [System.Diagnostics.Process] $process; try { $CurrentWindow = GenXdev\Get-PowershellMainWindow $command = @" `$ErrorOccurred = `$false; `$Host.UI.RawUI.WindowTitle = "$JobDescription" Import-Module -Name GenXdev -Version '3.30.2026'; GenXdev\Set-WindowPosition -X $($CurrentWindow.Left) -Y $($CurrentWindow.Top) -Width $($CurrentWindow.Width) -Height $($CurrentWindow.Height) -SetRestored -SetForeground; GenXdev\Set-WindowPosition -Process (Get-Process -Pid `$PID) -X $($CurrentWindow.Left) -Y $($CurrentWindow.Top) -Width $($CurrentWindow.Width) -Height $($CurrentWindow.Height) -SetRestored -SetForeground; try { 1..10 | % { Write-Progress -Id 11233 -Activity "$JobDescription" -Status "Executing elevated command.." -PercentComplete (`$_ * 10) Start-Sleep -Milliseconds 200 } Write-Progress -Id 11233 -PercentComplete 100 -Completed Write-Host "--------------------" -foregroundcolor Cyan; Write-Host "$JobDescription" -foregroundcolor Yellow; Write-Host "--------------------" -foregroundcolor Cyan; $ScriptBlock Write-Host "--------------------" -foregroundcolor Cyan; $($PauseAfterCompletion ? 'Pause' : '') } catch { `$ErrorOccurred = `$true; Write-Progress -Id 11233 -Activity "$JobDescription" -Status "Error occured!" -PercentComplete 100 -Completed Write-Host "--------------------" -foregroundcolor Cyan; GenXdev\Show-ExceptionPanel `$PSItem.Exception Write-Host "--------------------" -foregroundcolor Cyan; Pause } finally { 1..10 | % { Write-Progress -Id 11233 -Activity "$JobDescription" -Status "Returning to previous session" -PercentComplete (`$_ * 10) Start-Sleep -Milliseconds 200 } Write-Progress -Id 11233 -Activity "$JobDescription" -Status "Returning to previous session" -PercentComplete 100 -Completed Exit (`$ErrorOccurred ? 1 : 0) } "@; Microsoft.PowerShell.Utility\Write-Verbose "Elevating command: $command" $encodedCommand = [Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes($command)); $arguments = @( "-NoProfile", "-NoLogo", "-MTA", "-EncodedCommand", $encodedCommand ); $process = Microsoft.PowerShell.Management\Start-Process ` -FilePath (Microsoft.PowerShell.Management\Get-Process -Pid $PID).Path ` -ArgumentList $arguments ` -WorkingDirectory $PWD.Path ` -WindowStyle Minimized ` -Verb "RunAs" ` -PassThru; if (-not $process) { throw "User cancelled" } Microsoft.PowerShell.Utility\Write-Progress -Id 11232 -Activity "$JobDescription" -Status "Loading PowerShell modules.." -PercentComplete 25 } catch { Microsoft.PowerShell.Utility\Write-Progress -Id 11232 -PercentComplete 100 -Completed throw "User cancelled" } $i = 25; while (-not $process.HasExited) { Microsoft.PowerShell.Utility\Write-Progress -Id 11232 -Activity "$JobDescription" -Status "Loading PowerShell modules.." -PercentComplete ([Math]::Min(75, $i++)) Microsoft.PowerShell.Utility\Start-Sleep -Milliseconds 250 } $errorOccurred = $process.ExitCode -ne 0 if ($errorOccurred) { 75..100 | Microsoft.PowerShell.Core\ForEach-Object { Microsoft.PowerShell.Utility\Write-Progress -Id 11232 -Activity "$JobDescription" -Status ($errorOccurred ? "Completed with error!" : "Completed") -PercentComplete $_ Microsoft.PowerShell.Utility\Start-Sleep -Milliseconds 80 } } Microsoft.PowerShell.Utility\Write-Progress -Id 11232 -PercentComplete 100 -Completed if (-not $DontUpdateEnvironment) { GenXdev\Update-Environment } GenXdev\Set-WindowPosition -SetForeground -RestoreFocus } |