mirror of
https://github.com/ChrisTitusTech/winutil.git
synced 2025-04-01 17:12:09 +00:00
Fix WinUtil admin elevation for stable and pre-release builds
This commit is contained in:
parent
e4565f1f6f
commit
09b54a6eee
@ -1,11 +1,12 @@
|
||||
<#
|
||||
.NOTES
|
||||
Author : Chris Titus @christitustech
|
||||
Runspace Author: @DeveloperDurp
|
||||
GitHub : https://github.com/ChrisTitusTech
|
||||
Version : #{replaceme}
|
||||
Author : Chris Titus @christitustech
|
||||
Runspace Author : @DeveloperDurp
|
||||
GitHub : https://github.com/ChrisTitusTech
|
||||
Version : #{replaceme}
|
||||
#>
|
||||
|
||||
# Define the arguments for the WinUtil script
|
||||
param (
|
||||
[switch]$Debug,
|
||||
[string]$Config,
|
||||
@ -17,12 +18,13 @@ if ($Debug) {
|
||||
$DebugPreference = "Continue"
|
||||
}
|
||||
|
||||
# Handle the -Config parameter
|
||||
if ($Config) {
|
||||
$PARAM_CONFIG = $Config
|
||||
}
|
||||
|
||||
$PARAM_RUN = $false
|
||||
# Handle the -Run switch
|
||||
$PARAM_RUN = $false
|
||||
if ($Run) {
|
||||
Write-Host "Running config file tasks..."
|
||||
$PARAM_RUN = $true
|
||||
@ -39,38 +41,66 @@ $sync.version = "#{replaceme}"
|
||||
$sync.configs = @{}
|
||||
$sync.ProcessRunning = $false
|
||||
|
||||
if (!([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
|
||||
Write-Output "Winutil needs to be run as Administrator. Attempting to relaunch."
|
||||
$argList = @()
|
||||
# Store elevation status of the process
|
||||
$isElevated = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
|
||||
|
||||
$PSBoundParameters.GetEnumerator() | ForEach-Object {
|
||||
$argList += if ($_.Value -is [switch] -and $_.Value) {
|
||||
"-$($_.Key)"
|
||||
} elseif ($_.Value) {
|
||||
"-$($_.Key) `"$($_.Value)`""
|
||||
}
|
||||
# Initialize the arguments list array
|
||||
$argsList = @()
|
||||
|
||||
# Add the passed parameters to $argsList
|
||||
$PSBoundParameters.GetEnumerator() | ForEach-Object {
|
||||
$argsList += if ($_.Value -is [switch] -and $_.Value) {
|
||||
"-$($_.Key)"
|
||||
} elseif ($_.Value) {
|
||||
"-$($_.Key) `"$($_.Value)`""
|
||||
}
|
||||
}
|
||||
|
||||
$script = if ($MyInvocation.MyCommand.Path) {
|
||||
"& { & '$($MyInvocation.MyCommand.Path)' $argList }"
|
||||
} else {
|
||||
"iex '& { $(irm https://github.com/ChrisTitusTech/winutil/releases/latest/download/winutil.ps1) } $argList'"
|
||||
}
|
||||
|
||||
$powershellcmd = if (Get-Command pwsh -ErrorAction SilentlyContinue) { "pwsh" } else { "powershell" }
|
||||
$processCmd = if (Get-Command wt.exe -ErrorAction SilentlyContinue) { "wt.exe" } else { $powershellcmd }
|
||||
|
||||
Start-Process $processCmd -ArgumentList "$powershellcmd -ExecutionPolicy Bypass -NoProfile -Command $script" -Verb RunAs
|
||||
# Set the download URL for the latest release
|
||||
$downloadURL = "https://github.com/ChrisTitusTech/winutil/releases/latest/download/winutil.ps1"
|
||||
|
||||
# Download the WinUtil script to '$env:TEMP'
|
||||
try {
|
||||
Write-Host "Downloading the latest stable WinUtil version..." -ForegroundColor Green
|
||||
Invoke-RestMethod $downloadURL -OutFile "$env:TEMP\winutil.ps1"
|
||||
} catch {
|
||||
Write-Host "Error downloading WinUtil: $_" -ForegroundColor Red
|
||||
break
|
||||
}
|
||||
|
||||
$dateTime = Get-Date -Format "yyyy-MM-dd_HH-mm-ss"
|
||||
# Setup the commands used to launch the script
|
||||
$powershellCmd = if (Get-Command pwsh.exe -ErrorAction SilentlyContinue) { "pwsh.exe" } else { "powershell.exe" }
|
||||
$processCmd = if (Get-Command wt.exe -ErrorAction SilentlyContinue) { "wt.exe" } else { $powershellCmd }
|
||||
|
||||
# Setup the script's launch arguments
|
||||
$launchArguments = "-ExecutionPolicy Bypass -NoProfile -File `"$env:TEMP\winutil.ps1`" $argsList"
|
||||
if ($processCmd -ne $powershellCmd) {
|
||||
$launchArguments = "$powershellCmd $launchArguments"
|
||||
}
|
||||
|
||||
# Set the title of the running PowerShell instance
|
||||
$BaseWindowTitle = $MyInvocation.MyCommand.Path ?? $MyInvocation.MyCommand.Definition
|
||||
$Host.UI.RawUI.WindowTitle = if ($isElevated) {
|
||||
$BaseWindowTitle + " (Admin)"
|
||||
} else {
|
||||
$BaseWindowTitle + " (User)"
|
||||
}
|
||||
|
||||
# Relaunch the script as administrator if necessary
|
||||
try {
|
||||
if (!$isElevated) {
|
||||
Write-Host "WinUtil is not running as administrator. Relaunching..." -ForegroundColor DarkCyan
|
||||
Start-Process $processCmd -ArgumentList $launchArguments -Verb RunAs
|
||||
break
|
||||
} else {
|
||||
Write-Host "Running the latest stable version of WinUtil as admin." -ForegroundColor DarkCyan
|
||||
}
|
||||
} catch {
|
||||
Write-Host "Error launching WinUtil: $_" -ForegroundColor Red
|
||||
break
|
||||
}
|
||||
|
||||
# Start WinUtil transcript logging-mm-ss"
|
||||
$logdir = "$env:localappdata\winutil\logs"
|
||||
[System.IO.Directory]::CreateDirectory("$logdir") | Out-Null
|
||||
Start-Transcript -Path "$logdir\winutil_$dateTime.log" -Append -NoClobber | Out-Null
|
||||
|
||||
# Set PowerShell window title
|
||||
$Host.UI.RawUI.WindowTitle = $myInvocation.MyCommand.Definition + "(Admin)"
|
||||
clear-host
|
||||
Start-Transcript -Path "$logdir\winutil_$dateTime.log" -Append -NoClobber | Out-Null
|
182
windev.ps1
182
windev.ps1
@ -1,55 +1,169 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
This Script is used as a target for the https://christitus.com/windev alias.
|
||||
It queries the latest winget release (no matter if Pre-Release, Draft or Full Release) and invokes It
|
||||
This script is used as a target for the https://christitus.com/windev alias.
|
||||
It queries the latest WinUtil release (no matter if it's a Pre-Release, Draft, or Full Release) and runs it.
|
||||
.DESCRIPTION
|
||||
This Script provides a simple way to always start the bleeding edge release even if it's not yet a full release.
|
||||
This function should be run with administrative privileges.
|
||||
Because this way of recursively invoking scripts via Invoke-Expression it might very well happen that AV Programs flag this because it's a common way of mulitstage exploits to run
|
||||
This script provides a simple way to start the bleeding edge release even if it's not yet a full release.
|
||||
This function can be run both with administrator and non-administrator permissions.
|
||||
If it is not running as administrator, it will attempt to relaunch itself with administrator permissions.
|
||||
The script no longer uses Invoke-Expression for its execution and now relies on Start-Process.
|
||||
.EXAMPLE
|
||||
irm https://christitus.com/windev | iex
|
||||
Run in PowerShell > irm https://christitus.com/windev | iex
|
||||
OR
|
||||
Run in Admin Powershell > ./windev.ps1
|
||||
Run in PowerShell > .\windev.ps1
|
||||
OR
|
||||
Run in PowerShell > iex "& { $(irm https://christitus.com/windev) } <arguments>"
|
||||
OR
|
||||
Run in PowerShell > .\windev.ps1 <arguments>
|
||||
#>
|
||||
|
||||
# Function to fetch the latest release tag from the GitHub API
|
||||
function Get-LatestRelease {
|
||||
# Define the arguments for the WinUtil script; enables argument auto-completion.
|
||||
param (
|
||||
[switch]$Debug,
|
||||
[string]$Config,
|
||||
[switch]$Run
|
||||
)
|
||||
|
||||
# Speed up download-related tasks by suppressing the output of Write-Progress.
|
||||
$ProgressPreference = "SilentlyContinue"
|
||||
|
||||
# Determine whether or not the active process is currently running as administrator.
|
||||
$ProcessIsElevated = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
|
||||
|
||||
# Function to get the latest stable or pre-release tag from the repository's releases page.
|
||||
function Get-WinUtilReleaseTag {
|
||||
# Retrieve the list of released versions from the repository's releases page.
|
||||
try {
|
||||
$releases = Invoke-RestMethod -Uri 'https://api.github.com/repos/ChrisTitusTech/winutil/releases'
|
||||
$latestRelease = $releases | Where-Object {$_.prerelease -eq $true} | Select-Object -First 1
|
||||
return $latestRelease.tag_name
|
||||
$ReleasesList = Invoke-RestMethod 'https://api.github.com/repos/ChrisTitusTech/winutil/releases'
|
||||
} catch {
|
||||
Write-Host "Error fetching release data: $_" -ForegroundColor Red
|
||||
return $latestRelease.tag_name
|
||||
Write-Host "Error downloading WinUtil's releases list: $_" -ForegroundColor Red
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
# Function to redirect to the latest pre-release version
|
||||
function RedirectToLatestPreRelease {
|
||||
$latestRelease = Get-LatestRelease
|
||||
if ($latestRelease) {
|
||||
$url = "https://github.com/ChrisTitusTech/winutil/releases/download/$latestRelease/winutil.ps1"
|
||||
# Filter through the released versions and select the first matching stable or pre-release version.
|
||||
$StableRelease = $ReleasesList | Where-Object { -not $_.prerelease } | Select-Object -First 1
|
||||
$PreRelease = $ReleasesList | Where-Object { $_.prerelease } | Select-Object -First 1
|
||||
|
||||
# Set the release tag based on the available releases; if no release tag is found use the 'latest' tag.
|
||||
$ReleaseTag = if ($PreRelease) {
|
||||
$PreRelease.tag_name
|
||||
} elseif ($StableRelease) {
|
||||
$StableRelease.tag_name
|
||||
} else {
|
||||
Write-Host 'Unable to determine latest pre-release version.' -ForegroundColor Red
|
||||
Write-Host "Using latest Full Release"
|
||||
$url = "https://github.com/ChrisTitusTech/winutil/releases/latest/download/winutil.ps1"
|
||||
"latest"
|
||||
}
|
||||
|
||||
$script = Invoke-RestMethod $url
|
||||
# Elevate Shell if necessary
|
||||
if (!([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
|
||||
Write-Output "Winutil needs to be run as Administrator. Attempting to relaunch."
|
||||
# Return the release tag to facilitate the usage of the version number within other parts of the script.
|
||||
return $ReleaseTag
|
||||
}
|
||||
|
||||
$powershellcmd = if (Get-Command pwsh -ErrorAction SilentlyContinue) { "pwsh" } else { "powershell" }
|
||||
$processCmd = if (Get-Command wt.exe -ErrorAction SilentlyContinue) { "wt.exe" } else { $powershellcmd }
|
||||
# Get the latest stable or pre-release tag; falling back to the 'latest' release tag if no releases are found.
|
||||
$WinUtilReleaseTag = Get-WinUtilReleaseTag
|
||||
|
||||
Start-Process $processCmd -ArgumentList "$powershellcmd -ExecutionPolicy Bypass -NoProfile -Command $(Invoke-Expression $script)" -Verb RunAs
|
||||
# Function to generate the URL used to download the latest release of WinUtil from the releases page.
|
||||
function Get-WinUtilReleaseURL {
|
||||
$WinUtilDownloadURL = if ($WinUtilReleaseTag -eq "latest") {
|
||||
"https://github.com/ChrisTitusTech/winutil/releases/$($WinUtilReleaseTag)/download/winutil.ps1"
|
||||
} else {
|
||||
"https://github.com/ChrisTitusTech/winutil/releases/download/$($WinUtilReleaseTag)/winutil.ps1"
|
||||
}
|
||||
else{
|
||||
Invoke-Expression $script
|
||||
|
||||
return $WinUtilDownloadURL
|
||||
}
|
||||
|
||||
# Get the URL used to download the latest release of WinUtil from the releases page.
|
||||
$WinUtilReleaseURL = Get-WinUtilReleaseURL
|
||||
|
||||
# Create the file path that the latest WinUtil release will be downloaded to on the local disk.
|
||||
$WinUtilScriptPath = Join-Path "$env:TEMP" "winutil.ps1"
|
||||
|
||||
# Function to download the latest release of WinUtil from the releases page to the local disk.
|
||||
function Get-LatestWinUtil {
|
||||
if (!(Test-Path $WinUtilScriptPath)) {
|
||||
Write-Host "WinUtil is not found. Downloading WinUtil '$($WinUtilReleaseTag)'..." -ForegroundColor DarkYellow
|
||||
Invoke-RestMethod $WinUtilReleaseURL -OutFile $WinUtilScriptPath
|
||||
}
|
||||
}
|
||||
|
||||
# Call the redirect function
|
||||
# Function to check for any version changes to WinUtil, re-downloading the script if it has been upgraded/downgraded.
|
||||
function Get-WinUtilUpdates {
|
||||
# Make a web request to the latest WinUtil release URL and store the script's raw code for processing.
|
||||
$RawWinUtilScript = (Invoke-WebRequest $WinUtilReleaseURL -UseBasicParsing).RawContent
|
||||
|
||||
RedirectToLatestPreRelease
|
||||
# Create the regular expression pattern used to extract the script's version number from the script's raw content.
|
||||
$VersionExtractionRegEx = "(\bVersion\s*:\s)([\d.]+)"
|
||||
|
||||
# Match the entire 'Version:' header and extract the script's version number directly using RegEx capture groups.
|
||||
$RemoteWinUtilVersion = (([regex]($VersionExtractionRegEx)).Match($RawWinUtilScript).Groups[2].Value)
|
||||
$LocalWinUtilVersion = (([regex]($VersionExtractionRegEx)).Match((Get-Content $WinUtilScriptPath)).Groups[2].Value)
|
||||
|
||||
# Check if WinUtil needs an update and either download a fresh copy or notify the user its already up-to-date.
|
||||
if ([version]$RemoteWinUtilVersion -ne [version]$LocalWinUtilVersion) {
|
||||
Write-Host "WinUtil is out-of-date. Downloading WinUtil '$($RemoteWinUtilVersion)'..." -ForegroundColor DarkYellow
|
||||
Invoke-RestMethod $WinUtilReleaseURL -OutFile $WinUtilScriptPath
|
||||
} else {
|
||||
Write-Host "WinUtil is already up-to-date. Skipped update checking." -ForegroundColor Yellow
|
||||
}
|
||||
}
|
||||
|
||||
# Function to start the latest release of WinUtil that was previously downloaded and saved to '$env:TEMP\winutil.ps1'.
|
||||
function Start-LatestWinUtil {
|
||||
param (
|
||||
[Parameter(Mandatory = $false)]
|
||||
[array]$WinUtilArgumentsList
|
||||
)
|
||||
|
||||
# Setup the commands used to launch WinUtil using Windows Terminal or Windows PowerShell/PowerShell Core.
|
||||
$PowerShellCommand = if (Get-Command pwsh.exe -ErrorAction SilentlyContinue) { "pwsh.exe" } else { "powershell.exe" }
|
||||
$ProcessCommand = if (Get-Command wt.exe -ErrorAction SilentlyContinue) { "wt.exe" } else { $PowerShellCommand }
|
||||
|
||||
# Setup the script's launch arguments based on the presence of Windows Terminal or Windows PowerShell/PowerShell Core:
|
||||
# 1. Windows Terminal needs the name of the process to start ($PowerShellCommand) in addition to the launch arguments.
|
||||
# 2. Windows PowerShell and PowerShell Core can receive and use the launch arguments as is without extra modification.
|
||||
$WinUtilLaunchArguments = "-ExecutionPolicy Bypass -NoProfile -File `"$WinUtilScriptPath`""
|
||||
if ($ProcessCommand -ne $PowerShellCommand) {
|
||||
$WinUtilLaunchArguments = "$PowerShellCommand $WinUtilLaunchArguments"
|
||||
}
|
||||
|
||||
# If WinUtil's launch arguments are provided, append them to the end of the list of current launch arguments.
|
||||
if ($WinUtilArgumentsList) {
|
||||
$WinUtilLaunchArguments += " " + $($WinUtilArgumentsList -join " ")
|
||||
}
|
||||
|
||||
# If the WinUtil script is not running as administrator, relaunch the script with administrator permissions.
|
||||
if (!$ProcessIsElevated) {
|
||||
Write-Host "WinUtil is not running as administrator. Relaunching..." -ForegroundColor DarkCyan
|
||||
Write-Host "Running the selected WinUtil release: Version '$($WinUtilReleaseTag)'." -ForegroundColor Green
|
||||
Start-Process $ProcessCommand -ArgumentList $WinUtilLaunchArguments -Verb RunAs
|
||||
} else {
|
||||
Write-Host "Running the selected WinUtil release: Version '$($WinUtilReleaseTag)'." -ForegroundColor Green
|
||||
Start-Process $ProcessCommand -ArgumentList $WinUtilLaunchArguments
|
||||
}
|
||||
}
|
||||
|
||||
# If WinUtil has not already been downloaded, attempt to download it and save it to '$env:TEMP\winutil.ps1'.
|
||||
try {
|
||||
Get-LatestWinUtil
|
||||
} catch {
|
||||
Write-Host "Error downloading WinUtil '$($WinUtilReleaseTag)': $_" -ForegroundColor Red
|
||||
break
|
||||
}
|
||||
|
||||
# Attempt to check for WinUtil updates, if a version is released or removed this will re-download WinUtil.
|
||||
try {
|
||||
Get-WinUtilUpdates
|
||||
} catch {
|
||||
Write-Host "Error updating WinUtil '$($WinUtilReleaseTag)': $_" -ForegroundColor Red
|
||||
break
|
||||
}
|
||||
|
||||
# Attempt to start the latest release of WinUtil saved to the local disk; also supports WinUtil's arguments.
|
||||
try {
|
||||
if ($args) {
|
||||
Start-LatestWinUtil $args
|
||||
} else {
|
||||
Start-LatestWinUtil
|
||||
}
|
||||
} catch {
|
||||
Write-Host "Error launching WinUtil '$($WinUtilReleaseTag)': $_" -ForegroundColor Red
|
||||
}
|
Loading…
Reference in New Issue
Block a user