Run with elevated rights a PowerShell script, with spaces in path, from Windows Command Prompt (CMD)
Asked Answered
S

3

2

I tried to launch a long PowerShell script with the name "long name here.ps1" from command prompt. But I am also trying to ensure that it runs as an administrator command in PowerShell. I have all execution policies in PowerShell set accordingly and I used the SS64 Set-ExecutionPolicy command guide for PowerShell to get PowerShell working. But I am trying to use the solution from another Stack Overflow question that talks about running commands as administrator. I am running a batch script that needs to execute a PowerShell script (.ps1) as admin, and I don't mind if the user is prompted by UAC or for the password.

I am currently using the following command:

powershell.exe -command "&{ Start-Process powershell -ArgumentList '-noprofile -file "C:\long name here.ps1"' -verb RunAs}"

I found a similar command in the "Run a Script As Admin" at https://ss64.com/ps/powershell.html. The problem with that code is that my PowerShell script has arguments and a long name with spaces. I have tried many different iterations of this command with no success, and the ones that DON'T work are listed below:

powershell.exe -command "&{ Start-Process powershell -ArgumentList '-noprofile -file C:\long\` name` here.ps1' -verb RunAs}"
powershell.exe -command "&{ Start-Process powershell -ArgumentList '-noprofile -file:"C:\long name here.ps1' -verb RunAs}"

Also, I am completely lost as to how to send arguments to the actual script.

Sprit answered 27/11, 2017 at 16:29 Comment(3)
This link may be relevantFina
I'm not hitting the max-length of my command. The problem is the -file option for powershell. It is not recognizing my filename and therefore does not run it at all.Sprit
I know Task Scheduler has a 256 char limit but I tested that by passing a 291 char argument to a PowerShell script in the same manner as the OP is trying to run his file, and it worked fine. If there is a limit it's going to be unreasonable to hit.Suckow
S
-1

When you use PowerShell.exe -Command you don't need to use quotes. For example, you can run the following:

PowerShell.exe -Command Get-Service 'wuauserv'

Everything after -Command is interpreted as the command. Note also that double quotes in CMD need escaping with a backslash. Therefore:

powershell.exe -Command Start-Process PowerShell -ArgumentList '-NoProfile -File \"C:\long name here.ps1\"' -Verb RunAs

If your file has arguments:

powershell.exe -Command Start-Process PowerShell -ArgumentList '-NoProfile -File \"C:\long name here.ps1\" \"Arg1\" \"Arg2\"' -Verb RunAs
Suckow answered 27/11, 2017 at 17:27 Comment(5)
Worked for me. I managed to pass in 2 arguments using the method described here.Sprit
Bill, if you don't escape them CMD consumes them. That is true anywhere in the argument you're passing to PowerShell,Suckow
This technique doesn't work from PowerShell. From my cursory investigation, it seems that this is because powershell.exe currently uses CommandLineToArgvW. Due to this complexity I don't recommend this solution unless you are sure that the parser won't misinterpret your intent.Muniment
Whether it works from PowerShell or not is irrelevant, OP explicitly states they are running this from Command Prompt therefore that's what we need to format it for, and if you want the quotes to be interpreted as part of the argument sent to PowerShell they need to be escaped.Suckow
Yes, and my point is that this only "works" because PowerShell uses that Win32 API. (If they decide to change to a different API or parse differently, this solution might break.)Muniment
M
1

Use an Open Source Utility

If an open source utility is permissible, you can use a short tool I wrote called elevate.exe to launch powershell.exe as administrator with the -File parameter and the script arguments you want to use:

elevate -- powershell.exe -File "<path>\<long script name>.ps1" -Arg "<long script argument>"

You can get the open source tool here:

https://github.com/Bill-Stewart/elevate

Use a WSH Script

If you can't use an external executable, you can also do this (although it does not handle quoting in as robust a manner as the elevate tool's -- parameter) using a Windows Script Host (WSH) script, elevate.js:

// elevate.js
var args = WScript.Arguments;

if ( (args.Length == 0) || (args.Named.Exists("?")) ) {
  WScript.Echo("Usage: elevate.js command [arg [...]]");
  WScript.Quit();
}

var exec = args.Item(0);
var cmdLine = "";
for ( var i = 1; i < args.Length; i++ ) {
  cmdLine += cmdLine == "" ? '"' + args.Item(i) + '"' : ' "' + args.Item(i) + '"';
}
var shellApp = new ActiveXObject("Shell.Application");
shellApp.ShellExecute(exec,cmdLine,"","runas");

You can call as follows:

wscript.exe "d:\path\elevate.js" powershell.exe -File "C:\long path\script name.ps1" "long script argument"

Self-Elevate your PowerShell Script

Another option is to write a self-elevating PowerShell script. You can check for elevation in the script; if not elevated, it can launch itself elevated and run any command you need. Example:

$isElevated = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)

if ( -not $isElevated ) {
  Start-Process powershell.exe "-File",('"{0}"' -f $MyInvocation.MyCommand.Path) -Verb RunAs
  exit
}

& "d:\long path name\script name.ps1" "Long Argument 1" "Long Argument 2"
Muniment answered 27/11, 2017 at 16:59 Comment(2)
I don't understand the downvotes, but I wasn't looking to do this using a 3rd-party tool, as I want this batch file to be portable.Sprit
You can ignore any downvotes as many people are using the freeware tools quite successfully. But in any case I updated my answer with a WSH script solution and a PowerShell self-elevation solution.Muniment
R
0

If I'm reading your question correctly - powershell wont find the file as it stops reading the path name when it encounters a blank space?

The example given here specifies that; powershell commands to be run from command prompt as an administrator should have the following syntax:

powershell.exe -noprofile -command "&{ start-process powershell -ArgumentList '-noprofile -file MyScript.ps1' -verb RunAs}"

Couple of ways to achieve what you're looking for. But the easiest method would be to escape the quotes using a ` character. So something similar to;

powershell.exe -noprofile -command "&{ start-process powershell -ArgumentList '-noprofile -file `"C:\long file name.ps1`"' -verb RunAs}"

Also might be worth checking out other answers here

Retha answered 27/11, 2017 at 16:57 Comment(3)
Why are you using a call operator with script block?Rahn
Running your example command with the escaped filename still causes command prompt to end theparsing of '-command' line after the -file `". I've tried that method too, and command prompt only sees powershell.exe -noprofile -command "&{ start-process powershell -ArgumentList '-noprofile -file `"Sprit
Probably due to Command Prompt trimming out the double quotes due to it interpreting them as string start and end points. See my answer.Suckow
S
-1

When you use PowerShell.exe -Command you don't need to use quotes. For example, you can run the following:

PowerShell.exe -Command Get-Service 'wuauserv'

Everything after -Command is interpreted as the command. Note also that double quotes in CMD need escaping with a backslash. Therefore:

powershell.exe -Command Start-Process PowerShell -ArgumentList '-NoProfile -File \"C:\long name here.ps1\"' -Verb RunAs

If your file has arguments:

powershell.exe -Command Start-Process PowerShell -ArgumentList '-NoProfile -File \"C:\long name here.ps1\" \"Arg1\" \"Arg2\"' -Verb RunAs
Suckow answered 27/11, 2017 at 17:27 Comment(5)
Worked for me. I managed to pass in 2 arguments using the method described here.Sprit
Bill, if you don't escape them CMD consumes them. That is true anywhere in the argument you're passing to PowerShell,Suckow
This technique doesn't work from PowerShell. From my cursory investigation, it seems that this is because powershell.exe currently uses CommandLineToArgvW. Due to this complexity I don't recommend this solution unless you are sure that the parser won't misinterpret your intent.Muniment
Whether it works from PowerShell or not is irrelevant, OP explicitly states they are running this from Command Prompt therefore that's what we need to format it for, and if you want the quotes to be interpreted as part of the argument sent to PowerShell they need to be escaped.Suckow
Yes, and my point is that this only "works" because PowerShell uses that Win32 API. (If they decide to change to a different API or parse differently, this solution might break.)Muniment

© 2022 - 2024 — McMap. All rights reserved.