-
Notifications
You must be signed in to change notification settings - Fork 171
Expand file tree
/
Copy pathsudo.ps1
More file actions
94 lines (81 loc) · 3.46 KB
/
sudo.ps1
File metadata and controls
94 lines (81 loc) · 3.46 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
<#
.SYNOPSIS
Runs a scriptblock, command or application as an elevated process using sudo.exe
.DESCRIPTION
Wraps sudo.exe to add functionality for running PowerShell scripts or commands in an elevated process.
When running a scriptblock or PowerShell command, a new copy of PowerShell is run with sudo and an EncodedCommand.
When running a native application, the command itself is run with sudo.
This script DOES NOT (currently) support piping input to the elevated command.
#>
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
[CmdletBinding(DefaultParameterSetName = "Script")]
param(
# A scriptblock to run in an elevated process
[Parameter(Mandatory, Position = 0, ParameterSetName = "Script")]
[scriptblock]$ScriptBlock,
# Run PowerShell with the -NoProfile switch
[switch]$NoProfile,
# A command or application to run in an elevated process
[Parameter(Mandatory, Position = 0, ParameterSetName = "Command")]
[string]$Command,
# Arguments to pass to the command or application
[Parameter(Position = 1, ParameterSetName = "Command", ValueFromRemainingArguments)]
[Alias("Args")]
[PSObject[]]$ArgumentList
)
begin {
if ($IsLinux -or $IsMacOS) {
throw "This script works only on Microsoft Windows"
}
if ($__SUDO_TEST -ne $true) {
$Env:SUDOEXE = "sudo.exe"
} elseif (!$Env:SUDOEXE) {
throw "Environment variable SUDOEXE has not been set for testing"
}
if (!(Get-Command -Type Application -Name $Env:SUDOEXE -ErrorAction Ignore)) {
throw "Env:SUDOEXE is set to '$Env:SUDOEXE' but it cannot be found."
}
$thisPowerShell = (Get-Process -Id $PID).MainModule.FileName
if (!$thisPowerShell) {
throw "Cannot determine PowerShell executable path."
}
function ConvertToBase64EncodedString([string]$InputObject) {
$bytes = [System.Text.Encoding]::Unicode.GetBytes($InputObject)
[Convert]::ToBase64String($bytes)
}
}
end {
# If the first parameter is the name of an executable, just run that without PowerShell
if ($PSCmdlet.ParameterSetName -eq "Command") {
if (@(Get-Command $Command -ErrorAction Ignore)[0].CommandType -eq "Application") {
# NOTE: this assumes that all the parameters can be just strings
if ($PSBoundParameters.Contains("Debug")) {
Trace-Command -PSHost -Name param* -Expression { & $Env:SUDOEXE $Command @ArgumentList }
} else {
& $Env:SUDOEXE $Command $ArgumentList
}
return
} else {
# In this case, we're going to need to _make_ a scriptblock out of $MyInvocation.Statement
# NOT $MyInvocation.Line because there might be more than one line in the statement
# IISReset and Jaykul apologize for the reflection, but we need to support old versions of PowerShell
$Statement = [System.Management.Automation.InvocationInfo].GetMember(
'_scriptPosition',
[System.Reflection.BindingFlags]'NonPublic,Instance'
)[0].GetValue($MyInvocation).Text.
# Strip the 'sudo' or 'sudo.ps1` or whatever off the front of the statement
$Statement = $Statement.SubString($MyInvocation.InvocationName.Length).Trim()
$EncodedCommand = ConvertToBase64EncodedString $Statement
}
} else {
$EncodedCommand = ConvertToBase64EncodedString $scriptBlock
}
$switches = @("-NoLogo", "-NonInteractive")
if ($NoProfile) { $switches += "-NoProfile" }
if ($PSBoundParameters.Contains("Debug")) {
Trace-Command -PSHost -Name param* -Expression { & $Env:SUDOEXE $ThisPowerShell @switches -EncodedCommand $encodedCommand }
} else {
& $Env:SUDOEXE $ThisPowerShell @switches -EncodedCommand $encodedCommand
}
}