JinHH
JinHH

Reputation: 91

How to elevate a Powershell script from within a script

I'm new to Powershell, but in a lot of ways liking it a lot. For reasons, I have created a script that loads a set of local admin credentials from a file on the hard drive and creates a PSCredential-object, $MyCred.

I want to use $MyCred to elevate a separate script (which makes a few registry changes to open RDP connections). I've tried passing the $MyCred to the Start-Process cmdlet:

Start-Process Powershell.exe -Credential $MyCredential

Then I receive the following error:

Start-Process : This command cannot be run due to the error: The directory name is invalid.

If I run the Start-Process with -credential and an empty variable, I'm prompted for username and password. When I type them in, I get an elevated powershell prompt with no issues and am able to make the changes in registry to my test system.

I've verified the contents of $myCred and it has both U/N and P/W stored correctly (as in, identical to what I input manually). Using New-PSSEssion like

New-PSSession -Credential $MyCredential

returns access denied, which I've read is also disabled by default on a lot of systems.

In an ideal world, the code would look something like:

Start-Process Powershell.exe -Credential $MyCredential -File C:\MyScript.ps1

This should start an elevated powershell that runs a few commands in the second script and then terminates. What am I missing here?

Grateful for all help I can get, thanks! I might be something completely obvious.


Background is, we have some computers that we cannot ourselves get our hands on, and are also not able to reach through RDP. We do have users at the sites that can run the script for us. But it's important that they do not get the local admin-password. So we want to create a script that reads an encrypted password file, generates the local admin PSCredential object, and passes that to a script that makes the necessary registry changes to allow for RDP access.

Upvotes: 10

Views: 39249

Answers (5)

Chris
Chris

Reputation: 1

This works for me

$KeyFile = "$PSScriptRoot\AESkey.txt" # location of the AESKey
$PasswordFile = "$PSScriptRoot\password.txt"

$key = Get-Content $KeyFile           
$MyPassword = Get-Content $PasswordFile | ConvertTo-SecureString -Key $key
$userUPN = "UserName" # User account login 

$adminCreds = New-Object System.Management.Automation.PSCredential($userUPN, $MyPassword)

Start-Process Powershell.exe -ArgumentList "-Verb RunAs -NoExit -File 'C:\Path-To-File'" -Credential $adminCreds 

Upvotes: -1

mbomb007
mbomb007

Reputation: 4231

This code is from a helpful guide: How to Self-Elevate a PowerShell Script

It checks the current script's security, and if it needs elevation, the script will be re-launched as admin. If UAC is enabled, it will prompt for your confirmation. After relaunching, it will have the necessary access and run the code after the check.

# 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) {
  $CommandLine = "-File `"" + $MyInvocation.MyCommand.Path + "`" " + $MyInvocation.UnboundArguments
  Start-Process -FilePath PowerShell.exe -Verb Runas -ArgumentList $CommandLine
  Exit
 }
}

# Remainder of script here

Update: I've found that this won't maintain the current working directory after elevation. If anyone knows how to fix that, comment with a solution.

Upvotes: 6

Suncat2000
Suncat2000

Reputation: 1086

This is merely an enhancement to @mbomb007's answer, cobbled together from other examples around the web and my own efforts to pass all original arguments, with both named and positional parameters. Note that the added function does not encode special characters that may be used in the parameter values. Passing arguments is strangely absent from most posts.

function Pass-Parameters {
    Param ([hashtable]$NamedParameters)
    return ($NamedParameters.GetEnumerator()|%{"-$($_.Key) `"$($_.Value)`""}) -join " "
}

# 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) {
  $CommandLine = "-File `"" + $MyInvocation.MyCommand.Path + "`" " + (Pass-Parameters $MyInvocation.BoundParameters) + " " + $MyInvocation.UnboundArguments
  Start-Process -FilePath PowerShell.exe -Verb Runas -ArgumentList $CommandLine
  Exit
 }
}

# Remainder of script here

Upvotes: 6

postanote
postanote

Reputation: 16076

There are many use case articles on this topic. A quick web search, using 'PowerShell self-elevating script' will show them. Even from MS directly

A self-elevating PowerShell script

# 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 Administrator"
 if ($myWindowsPrincipal.IsInRole($adminRole))
    {
    # We are running "as Administrator" - so change the title and background color to indicate this
    $Host.UI.RawUI.WindowTitle = $myInvocation.MyCommand.Definition + "(Elevated)"
    $Host.UI.RawUI.BackgroundColor = "DarkBlue"
    clear-host
    }
 else
    {
    # We are not running "as 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
    $newProcess.Arguments = $myInvocation.MyCommand.Definition;

    # 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: 13

wasif
wasif

Reputation: 15470

You are missing the argument NoExit here.

Start-Process -Filepath "Powershell.exe" -ArgumentList "-NoExit -File "C:\myscript.ps1" -Credential $MyCredential 

Upvotes: 0

Related Questions