Search code examples
powershell

Get proper startup directory in PowerShell when executed via a shortcut file


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.


Solution

  • 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."