Reputation: 91
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
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
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
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
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
Reputation: 15470
You are missing the argument NoExit here.
Start-Process -Filepath "Powershell.exe" -ArgumentList "-NoExit -File "C:\myscript.ps1" -Credential $MyCredential
Upvotes: 0