Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PowerShell: Run script from shortcut using relative path

Tags:

powershell

EDIT: To future readers, in short, PowerShell scripts weren't intended to be used this way which is why there is no elegant solution.

I have the following line which runs a script as an administrator from a shortcut:

C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -noprofile -noexit Start-Process Powershell -verb RunAs -ArgumentList "C:\Documents\WindowsPowerShell\Scripts\test.ps1"

I want to change:

"C:\Documents\WindowsPowerShell\Scripts\test.ps1"

to a relative path like:

".\test.ps1"

but I haven't figured out how I can do that. How can I run the script relative to the location of the shortcut? (The shortcut and script are in the same folder)

like image 256
Jesse Good Avatar asked Mar 18 '14 20:03

Jesse Good


2 Answers

Here is an ugly workaround.

Shortcut.lnk file with Target: %COMSPEC% /C .\launcher.cmd (source) and Start In: %CD% (or blank).

Launcher.cmd file with contents:

Powershell -noprofile -noexit -File %CD%\PSlauncher.ps1

PSlauncher.ps1 file with contents:

Start-Process Powershell -verb RunAs -ArgumentList ($pwd.path + "\test.ps1")

Surely there is a better solution. Maybe with the -WorkingDirectory parameter of Start-Process? Or storing credentials with the Convert*-SecureString cmdlets? Count me curious.

Why do you want a shortcut?

like image 134
noam Avatar answered Oct 07 '22 14:10

noam


After much trial and error, I've come up with a solution:

Create a shortcut with this (edited for your .ps1) to have scrips run as admin relative to any directory:

CMD /C PowerShell "SL -PSPath '%CD%'; $Path = (GL).Path; SL ~; Start PowerShell -Verb RunAs -Args \""SL -PSPath '"$Path"'; & '".\YourScriptHere.ps1"'"\""

You'll have to empty the shortcut's "Start in" field to have its relative path be set as the working directory.

Or, here's a script that will generate one of these shortcuts for each .ps1 in a directory (with "Start in" already cleared):

(GCI | Where-Object {$_.Extension -eq ".ps1"}).Name | ForEach-Object {
    $WshShell = New-Object -ComObject WScript.Shell
    $Shortcut = $WshShell.CreateShortcut((GL).Path+"\$_ Run.lnk")
    $Shortcut.TargetPath = 'CMD'
    $Shortcut.Arguments = "/C PowerShell `"SL -PSPath `'%CD%`'; `$Path = (GL).Path; SL ~; Start PowerShell -Verb RunAs -Args \`"`"SL -PSPath `'`"`$Path`"`'; & `'`".\$_`"`'`"\`"`""    
    $Shortcut.IconLocation = 'PowerShell.exe'
    $Shortcut.Save()
}

If needed, add -NoExit, -ExecutionPolicy Unrestricted, etc. just after the first \".

Notes:

The reason for a second, admin instance of PowerShell launching from the first, is that launching as admin directly (by ticking a shortcut's "Run as administrator" box), for some reason ignores "Start in" and always launches in System32.

CMD is being used to launch the first instance because PowerShell currently fails to resolve paths containing square brackets, interpreting them as regex characters. This would normally be avoided using the LiteralPath parameter (aka PSPath), but here, the path is being passed behind the scenes at launch, and it's up to the developers to fix (I just filed a bug report here).

like image 40
Mica Avatar answered Oct 07 '22 15:10

Mica