1

I have a shortcut file that points to a PowerShell script file that is located in a different directory, and when that PowerShell script is executed via the shortcut file I require to obtain the proper startup directory (the directory where the shortcut file is) to set it in a variable like this:

$gamesDirPath = "{Current Shortcut Directory}\Games"

None from these suggestions seems to return the proper directory.

Note that I'm on PowerShell 5.x

Maybe this question would have an easy solution, but I also tried various times to ask to ChatGPT and each time it does not understand well the question, it demands me to set the location of the .lnk file in a variable inside the script!. Weird. Of course the shortcut file can be located anywhere.

5
  • 1
    Afaik, there is no way for PowerShell to determine it has been opened by a shortcut and therefore will also not have a way to determine the location of that shortcut. If you are the one who creates that shortcut, you could add a parameter to your PS call to provide the path info. Commented Dec 2, 2023 at 13:54
  • Thanks for comment. Any other approach different than calling the script with a path argument?. Maybe using .NET code?. Commented Dec 2, 2023 at 13:58
  • Creating a hard-link instead of a shortcut file solves my problem without requiring code modifications, but I would like to rely in shortcut files for comfort. Commented Dec 2, 2023 at 14:07
  • Use an Environmental variable. Create the variable when games are installed. Commented Dec 2, 2023 at 15:13
  • 1
    This is a longshot. Try blanking out the StartIn directory field inside the shortcut file itselr. You access the shortcut properties by right clicking on the shortcut. Commented Dec 3, 2023 at 1:23

2 Answers 2

3

As stackprotector notes, an executable launched from a shortcut file (.lnk) knows nothing about the latter.

  • It is the Windows (GUI) shell (implemented via explorer.exe processes) that interprets shortcut files and launches the process for the specified executable (command line), so examining the parent process yields nothing useful.

However, you can infer the directory in which the shortcut is located as long as you don't specify an explicit working directory (i.e. as long as you leave Start in: field in the shortcut-file Properties dialog empty).

  • If this condition is met, the automatic $PWD variable will tell your PowerShell script where the launching shortcut file is located, because the Windows shell by default makes a shortcut file's own directory the working directory.

  • Otherwise, read on for an alternative solution, which may be of interest either way.


As an alternative to creating a shortcut file, consider creating a symbolic link to your script file, which then causes the latter to see the link's full path and directory in the automatic $PSCommandPath and $PSScriptRoot variables.

Caveat:

  • Creating symlinks requires elevation (running with admin privileges) by default:

  • While there is a way to disable this requirement, doing so requires elevation too (albeit only once) and it is tied to enabling Developer Mode, which is considered a security risk.[1]

    • To enable Developer Mode, use the Settings app (Start-Process ms-setting:developers)
#requires -RunAsAdministator

New-Item -Force -ItemType SymbolicLink C:\path\to\link.ps1 -Target C:\different-path\to\original.ps1

When invoked via symlink C:\path\to\link.ps1, C:\different-path\to\original.ps1 then sees the following values:

  • $PSScriptRoot is 'C:\path\to'
  • $PSScriptCommandPath is 'C:\path\to\link.ps1'

Note:

  • This is only convenient for invocation from inside PowerShell, given that .ps1 files aren't directly executable from the outside.

  • For direct execution from outside PowerShell, you again need a shortcut file or you can use File Explorer's shortcut menu, assuming a command to execute PowerShell scripts is installed (by default, .ps1 files are opened for editing when double-clicked).

  • The caveat is that execution via File Explorer's shortcut menu usually automatically closes the window when the script has finished executing. To prevent that, you have two options:

    • Modify the definition of the shortcut-menu command in the registry, so as to include -NoExit before -File (or -Command), which then keeps the window open.

    • Put the following code at the end of your script file, which makes it execute pause (wait for a keypress before exiting) if it finds it was invoked from File Explorer:

       if ([Environment]::CommandLine -like "*$PSCommandPath*" -and (Get-Process -Id (Get-CimInstance Win32_Process -Filter "ProcessId = $PID").ParentProcessId).Path -like '*\explorer.exe') {
         pause
       }
      
  • Finally, another option is to make .ps1 files themselves directly executable from File Explorer and the Desktop, but this option should only be chosen for your own user account, given that other uses will not expect this behavior, which can lead to unwanted execution of scripts. See this answer.


[1] You get the following warning: "Turning on developer mode, including installing and running apps from outside the Microsoft Store, could expose your device and personal data to security risks or harm your device."

Sign up to request clarification or add additional context in comments.

2 Comments

$PWD was the key, thanks a lot!. Note that as already said in the answer, the shortcut's "Start in:" value must be EMPTY (an empty value, or two double quotes: ""), because $PWD doesn't point to the shortcut directory if "Start In:" value is the shortcut directory, weird, but it does not work, and if you put ".\" as the "Start In:" value it will point to C:windows\System32. So leave empty the "Start In:" value.
Glad to hear it helped, @ElektroStudios. It seems that the working directory of the Windows shell process that launches a shortcut itself defaults to C:windows\System32, so that's what you get when you specify . or .\. In other words: it only ever makes sense to fill this field with an absolute path.
1

Simplified example - using answer of mklement0

Create GetStartDir.ps1

Code:

"PSScriptRoot   : $PSScriptRoot"
"PWD            : $PWD"
Pause 

Now create a Windows shortcut to your script

C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -noprofile -ExecutionPolicy ByPass -file C:\Temp\test1\GetStartDir.ps1

Edit the shortcut properties, set the "Start in" location to BLANK. Note: Dot does not work. Save.

That shortcut can be copied anywhere. $PWD will be the location of the shortcut.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.