Prid
Prid

Reputation: 1624

How does PSScriptRoot inside Dot-Sourced file work?

Suppose I have 2 files, A.ps1 and B.ps1, in this directory structure:

-- 📁 root
 |
 |-- A.ps1
 |
 |-- 📁 subfolder
   |
   |-- B.ps1

A.ps1:

Write-Host $PSScriptRoot

B.ps1:

. "\root\A.ps1"

Now, taking this fact into account:

Dot sourcing takes the script you've specified and immediately executes it as though it had been at that spot in your original script

THE PROBLEM: If I were to run B.ps1, I would expect the result to be \root\subfolder, but it's \root, why??

If A.ps1 is dot-sourced into B.ps1, shouldn't the contents of script A.ps1 run as if they were written directly inside of B.ps1? Meaning, shouldn't $PSScriptRoot run as if it was called from B.ps1, and thus evaluate to \root\subfolder? I've even tested this by wrapping A.ps1 in a function and calling that function in B.ps1 after dot-sourcing. Still yields the same result..

How does dot-sourcing really work?

Upvotes: 4

Views: 1140

Answers (1)

zett42
zett42

Reputation: 27776

As commenters noted, $PSScriptRoot is independent of scope. From the docs (emphasis mine):

$PSScriptRoot
Contains the full path of the executing script's parent directory.

Dot-Sourcing doesn't literally "include" the script at the spot (contrary to the #include directive of C++, for instance), PowerShell still knows it is running a different script. The only thing that is different compared to calling the script (explicitly using the call operator & or running the script by entering its path), is the scoping.

There is a way to get the $PSScriptRoot of the calling script though. Turn the script to be dot-sourced into an advanced function cmdlet by using the CmdletBinding() and/or the Parameter() attribute. This makes the automatic variable $PSCmdlet available, which gives you (amongst other things), the $PSScriptRoot of the invoking script.

A.ps1

# CmdletBinding is an attribute of param(), so that is required as well
[CmdletBinding()] param()

$PSScriptRoot                         # Outputs directory that contains A.ps1
$PSCmdlet.MyInvocation.PSScriptRoot   # Outputs directory of the invoking script

Upvotes: 7

Related Questions