I've got a PowerShell script that needs to be able to call another PS script from within the same directory with elevated credentials. Because the scripts need to be portable, the file path of the scripts isn't known ahead of time and needs to be able to handle spaces and special characters in the file path without failing.
Since elevating a PS session will cause the current working directory to change to "C:\Windows\System32", I need to be able to pass the current directory to the script as a parameter. Now, my current script (below) is handling this fine as long as there aren't special characters in the directory path.
Here's my current script (updated per @mklement0's suggestion):
$scriptpath = $MyInvocation.MyCommand.Path
$dir = Split-Path $scriptpath
Start-Process Powershell -Verb runas -ArgumentList "-ExecutionPolicy","Bypass","-File","`"$dir\elevated.ps1`"","`"$dir`""
I've tried escaping some of the special characters, like so:
$dir = $dir.Replace('&','`"&`"')
but that's not working consistently for all the different characters that Windows allows in a folder/filename. Not all special characters need to be escaped either, but I need to make sure this works for the ones that do; at least those that are likely to show up in a filepath.
Special characters I'm mainly concerned with (though foreign characters might also need to be addressed at some point): !@#$%^_+-=.,{}`~&()[]
Example directory path I'm testing with:
C:\Users\Administrator\Desktop\Test Folder\badname-!@#$%^_+-=.,{}`~&()[]
Trying to run my script from the above location returns the following error:
The specified wildcard character pattern is not valid: badname-!@#$%^_+-=.,{}\~&()[] + CategoryInfo : NotSpecified: (:) [], ParentContainsErrorRecordException + FullyQualifiedErrorId : RuntimeException
So, what's the best way to have the script dynamically handle special characters in the directory path?
As an aside: In PSv3+ you can use $PSScriptRoot
to refer to the directory in which the script is located.
If you can modify the target script, you can place Set-Location -LiteralPath $PSScriptRoot
at the top to change to that folder.
To avoid quoting/escaping problems, pass arguments individually, as distinct elements of an array to -ArgumentList
(-Args
):
# Update: While this works, it is ultimately simpler to pass a *single string*
# with *embedded double-quoting*.
Start-Process powershell -Verb runas -ArgumentList '-ExecutionPolicy', 'Bypass',
'-File', "`"$dir\elevated.ps1`"", "`"$dir`""
Update:
-ArgumentList
, as shown above - see this answer.Unfortunately, that alone is not enough:
When you use -File
, even though the arguments are passed individually, the script file path and the directory path still require embedded "..."
quoting in order to pass values with embedded spaces correctly: "`"..."`"
passes a value with embedded double-quoting (`
is PowerShell's escape character, so `"
escapes a double quote).Tip of the hat to Ansgar Wiechers.
This bug has been reported as GitHub issue #5576; unfortunately, it won't be fixed, for the sake of backward compatibility.
In case you ever need to pass an argument with embedded "
characters (which filesystem paths by definition never contain), use something like:
('"{0}"' -f ($value -replace '"', '\"'))
Sadly, even that is not enough if your path contains [
characters that aren't each part of a syntactically valid wildcard-pattern range (e.g., [ab]
, [0-9]
), because PowerShell - in Windows PowerShell and in PowerShell (Core) up to at least v7.3.6 - mistakenly interprets the path as a wildcard pattern and fails if it finds it malformed - see GitHub issue #4726.
[
and possibly ]
are used in your path; e.g. foo[1]
works, but foo[]
doesn't.Alternative with -Command
:
-Commmand
allows you to pass a piece of PowerShell code - a mini-script, if you will - which you can use to pass a single, quoted string that is parsed by PowerShell rules by the new instance:
Start-Process powershell -Verb runas -ArgumentList '-ExecutionPolicy', 'Bypass',
'-Command', "& `"$dir\elevated.ps1`" `"$dir`""
Note the need to use &
to invoke the script, because it is given as a quoted string, and that the expansion of $dir
is performed by the current session.
Unfortunately, the problem with filenames that happen to look like malformed wildcard patterns (discussed above) applies to this invocation scenario too.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With