0

If I am in the console/terminal at the C:\temp location, and I invoke the script C:\scripts\test.ps1, how can I get the path of the current folder (C:\temp) from inside the script I just invoked?

None of the following has the required information:

  • Get-Location
  • $myinvocation
  • $pwd
  • $PSScriptRoot
mklement0
  • 382,024
  • 64
  • 607
  • 775
ZEE
  • 2,931
  • 5
  • 35
  • 47
  • no @jeff... all that solutions except $ExecutionContext I had already try... $ExecutionContext is interesting but unfortunately didn't work too for the presented case! – ZEE Aug 28 '23 at 19:55
  • I'm not an expert in PowerShell, but I wouldn't expect you would be able to. If you are calling a script it is executed without regard to the location from which it was executed. It only knows the permission context of what it is running under. The script doesn't even know it was called from PowerShell console vs terminal vs as a command in some other application or the ISE, etc. ad infinitum. – TylerH Aug 28 '23 at 20:03
  • This begs the question, _why_ do you want to know this from inside the script you just executed? – TylerH Aug 28 '23 at 20:04
  • well @Tyler... to simplify... just imagine you have some .ps1 scripts in the %PATH%... and when you invoke one from the whatever location you are... you want to know this location inside the script.... I hope that from some $context*/$session or even from [.net] we can get that info... that is rather !important ;-) – ZEE Aug 28 '23 at 20:45
  • That doesn't really explain _why_ you want to know it; it only repeats _that_ you want to know it. What are you expecting to _do_ with the information of where the script was called "from", once you have that information? – TylerH Aug 28 '23 at 20:55
  • 1
    Note to potential close voters: This question is _not_ a duplicate of https://stackoverflow.com/q/5466329/45375 - the latter is about finding the directory in which the _executing script_ is located, whereas this one is about the _current_ (working) directory. – mklement0 Aug 29 '23 at 13:54
  • @ZEE, your mentioning of `$myinvocation` and `$PSScriptRoot` added to the confusion (they relate to the script being invoked, not to the current directory). `$pwd` and an argument-less `Get-Location` call _do_ report PowerShell's current _location_ (and would indeed work if `C:\temp` is the current location), which generally may or may not be a _directory_, however. Separately, there is the _process_' working directory, as seen by .NET API calls. The answer now (hopefully) covers all angles. Let us know if you think something is unclear or missing. – mklement0 Aug 29 '23 at 17:50

1 Answers1

2

Note:

  • The next section discusses PowerShell's notion of what the current (working) directory is, which is specific to PowerShell.

    • $pwd and Get-Location typically work - but not always: see below.
  • By contrast, if you want to know what the current process sees as its current directory, which notably applies to calls to .NET APIs, use [Environment]::CurrentDirectory - this is typically not what PowerShell sees as its current location.

    • The reason for this discrepancy, which is rooted in PowerShell's ability to host multiple runspaces (threads) in a single process, is explained in GitHub issue #3428

      • Therefore, robustly calling .NET APIs (in-process) currently requires passing full, native file-system paths - see this answer

      • However, calls to external programs are not affected, because PowerShell does set its notion of the current file-system directory as the working directory of the child process that is invariably created for external programs.

    • Follow-up GitHub issue #17149 ponders synchronizing PowerShell's current (file-system) location with that of the process for the foreground runspace, specifically in the future, starting with an experimental feature; the latter has not yet been implemented as of PowerShell (Core) 7.3.6


PowerShell's current location vs. its current directory, PowerShell-specific vs. native file-system paths:

tl;dr

  • $PWD (equivalent to calling Get-Location without arguments) will typically - but not necessarily - reflect PowerShell's current file-system location (working directory).

    • The fully robust solution for returning a string that expresses the working directory as file-system-native path is:

      (Get-Location -PSProvider FileSystem).ProviderPath
      
  • With use of $PWD / argument-less Get-Location, additional considerations apply with respect to (a) whether the resulting object even represents a file-system location, and (b) even if so, whether its form is understood by external programs.

Read on for background information.


Get-Location reports PowerShell's current location, which, however, isn't guaranteed to be a file-system location, given that a PowerShell provider other than the FileSystem provider could be the one underlying the current location - even though that is rare in practice.

Therefore, to robustly determine the full path of the current file-system location, use the following:

(Get-Location -PSProvider FileSystem).Path

Note that the above expresses the file-system location potentially in terms of PowerShell-only drives, namely if the path passed to Set-Location was expressed in terms of a drive created with New-PSDrive.

Therefore, to robustly determine the full path of the current file-system location as a native file-system path, use .ProviderPath instead of .Path:

# .ProviderPath only differs from .Path if the current
# file-system location is on a PowerShell-only drive
# (a non-persistent drive established with New-PSDrive)
(Get-Location -PSProvider FileSystem).ProviderPath

In the simplest case - if you're willing to assume that the current location is a file-system location - you can use the automatic $PWD variable, which is in effect a more efficient alternative to calling Get-Location without arguments.

# Same as: (Get-Location).Path
$PWD.Path  # same as: "$PWD" (stringified)

Note:

  • Stringifying a System.Management.Automation.PathInfo instance - as reported by $PWD / Get-Location - results in the value of its .Path property, so situationally you may not need to access the .Path property explicitly; e.g., "The current location is: $PWD"

  • As noted, the .ProviderPath (e.g. $PWD.ProviderPath) returns the native file-system path (for instances representing the paths to items of the FileSystem provider; more generally, it returns the form of the path that is native to the underlying provider).

mklement0
  • 382,024
  • 64
  • 607
  • 775
  • What would the outcome of each call be in the context of OP's situation? Would it be `C:\temp` for all three commands? – TylerH Aug 29 '23 at 13:49
  • 1
    @TylerH, yes, given that `C:\temp` is a file-system-native path, `$PWD.Path`/ `(Get-Location).Path` and `$PWD.ProviderPath` / `(Get-Location).ProviderPath` all return `C:\temp`. I've updated the answer to make that clearer, along with a tr;dl section. – mklement0 Aug 29 '23 at 14:19
  • thanks mklement0; [Environment]::CurrentDirectory is the answer... but your complete and exhaustive answer for sure contributed to clarify the subject... – ZEE Aug 31 '23 at 13:41
  • Glad to hear it, @ZEE. It's tricky business, for sure. – mklement0 Aug 31 '23 at 13:42