Ikrananka
Ikrananka

Reputation: 35

Self Elevating Script + Execution Policy

I'm trying to use the following code from th question "PowerShell: Running a command as Administrator" to not only self elevate my script to run automatically in an Administrator-level PowerShell, but also for the Administrator-level PowerShell session to be run with an ExecutionPolicy level of RemoteSigned. I'm assuming that I need to use something like -ExecutionPolicy RemoteSigned in $newProcess.Arguments but am completely lost as to if this is the case, and if it is then what the syntax do I use to create the the multiple arguments?

# Get the ID and security principal of the current user account
$myWindowsID = [System.Security.Principal.WindowsIdentity]::GetCurrent();
$myWindowsPrincipal = New-Object System.Security.Principal.WindowsPrincipal($myWindowsID);

# Get the security principal for the administrator role
$adminRole = [System.Security.Principal.WindowsBuiltInRole]::Administrator;

# Check to see if we are currently running as an administrator
if ($myWindowsPrincipal.IsInRole($adminRole)) {
    # We are running as an administrator, so change the title and background colour to indicate this
    $Host.UI.RawUI.WindowTitle = $myInvocation.MyCommand.Definition + "(Elevated)";
    $Host.UI.RawUI.BackgroundColor = "DarkBlue";
    Clear-Host;
} else {
    # We are not running as an administrator, so relaunch as administrator

    # Create a new process object that starts PowerShell
    $newProcess = New-Object System.Diagnostics.ProcessStartInfo "PowerShell";

    # Specify the current script path and name as a parameter with added scope and support for scripts with spaces in it's path
    $newProcess.Arguments = "& '" + $script:MyInvocation.MyCommand.Path + "'"

    # Indicate that the process should be elevated
    $newProcess.Verb = "runas";

    # Start the new process
    [System.Diagnostics.Process]::Start($newProcess);

    # Exit from the current, unelevated, process
    Exit;
}

# Run your code that needs to be elevated here...

Write-Host -NoNewLine "Press any key to continue...";
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown");

Upvotes: 3

Views: 8191

Answers (2)

jkix
jkix

Reputation: 306

Alternate approach - "entrypointing"

Use an entrypoint script for flexibility and ease of maintenance

Given my own experience in maintaining and developing PowerShell scripts, I propose an alternate solution which may prove more maintainer-friendly.

Basic idea

Instead of checking for admin rights, elevating if not, worrying about $MyInvocation variables and whatnot, worrying that code below your elevation block won't run right, I've often found it really helpful to offload my PowerShell checks into an 'Entrypoint' script that I put in front of any workhorse script, and by doing so, make sure the script you launch is always going to launch from the top with exactly the runtime arguments you'd expect.  

Example code

./Entrypoint.ps1

Start-Process pwsh.exe `
     -Verb RunAs -ArgumentList (
     '-NoExit', # Will make sure the script doesn't exit
     '-ExecutionPolicy RemoteSigned', # RemoteSigned
     '-File "./ActualScript.ps1"' # You could do command instead, etc
)

./ActualScript.ps1

Write-Host "Hello world, as admin!"

Pros:

  • The -ArgumentList parameter is really flexible and allows for credential passthrough, env variables, etc.
  • Instead of relying on a block of code within your workhorse script to make a check you want to apply to the entirety of the script, and having to relaunch, just make your script run the way you want to begin with; you can do a lot more than just elevation.

Caveats:

  • This doesn't auto-elevate an existing script. Which is not exactly what you asked. The answer provided is great and I have not seen one that's better.
  • There may be reasons you'd want to explicitly check the privileges of a shell, such that you do one thing if unelevated and another if not, rather than always just making sure to elevate. If, however, you only just want to make sure your processes run in an elevated shell, this is a far simpler solution.

(I've also played with shortcuts, modifying the target, etc, if you're not entirely opposed to the GUI, which are doubly nice because you can have them launch as an admin with a checkbox.)

Upvotes: 0

Ansgar Wiechers
Ansgar Wiechers

Reputation: 200483

$newProcess.Arguments is indeed where you add the relevant parameters. However, you may want to run the script via the parameter -File instead of using the call operator (&) in an implicit -Command parameter.

$newProcess = New-Object Diagnostics.ProcessStartInfo 'powershell.exe'
$newProcess.Arguments = '-ExecutionPolicy RemoteSigned -File "' +
                        $script:MyInvocation.MyCommand.Path + '"'
$newProcess.Verb = 'runas'
[Diagnostics.Process]::Start($newProcess)

Upvotes: 4

Related Questions