Skip to content
mnaoumov.dev
Go back

PowerShell $PSScriptRoot vs dot-sourcing

In my previous blogpost I talked about $PSScriptRoot variable

Unfortunately there is a problem with that approach and dot-sourcing in PowerShell 2

Imagine we have

C:\Scripts\Script1.ps1

#requires -version 2.0

[CmdletBinding()]
param
(
)

$script:ErrorActionPreference = "Stop"
Set-StrictMode -Version Latest
$PSScriptRoot = $MyInvocation.MyCommand.Path | Split-Path

. "$PSScriptRoot\SubFolder\Script2.ps1"
. "$PSScriptRoot\SubFolder\Script3.ps1"

Invoke-Script4

C:\Scripts\SubFolder\Script2.ps1

#requires -version 2.0

[CmdletBinding()]
param
(
)

$script:ErrorActionPreference = "Stop"
Set-StrictMode -Version Latest
$PSScriptRoot = $MyInvocation.MyCommand.Path | Split-Path

function Invoke-Script4
{
    & "$PSScriptRoot\Script4.ps1"
}

C:\Scripts\SubFolder\Script3.ps1

#requires -version 2.0

[CmdletBinding()]
param
(
)

$script:ErrorActionPreference = "Stop"
Set-StrictMode -Version Latest

C:\Scripts\SubFolder\Script4.ps1

#requires -version 2.0

[CmdletBinding()]
param
(
)

$script:ErrorActionPreference = "Stop"
Set-StrictMode -Version Latest
$PSScriptRoot = $MyInvocation.MyCommand.Path | Split-Path

"Script4.ps1 invoked"

Then if you invoke C:\Scripts\Script1.ps1 in PowerShell 3 it is all good and works as expected

C:\> C:\scripts\Script1.ps1 Script4.ps1 invoked

However if you run the same in PowerShell 2

C:\> C:\Scripts\Script1.ps1
. : The term 'C:\Scripts\SubFolder\SubFolder\Script3.ps1' is not recognized as the name of a cmdlet, function, script f
ile, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct an
d try again.
At C:\Scripts\Script1.ps1:13 char:2
+ . <<<<  "$PSScriptRoot\SubFolder\Script3.ps1"
    + CategoryInfo          : ObjectNotFound: (C:\Scripts\SubF...der\Script3.ps1:String) [], ParentContainsErrorRecord
   Exception
    + FullyQualifiedErrorId : CommandNotFoundException

As you can see we have strange double SubFolder C:\Scripts\SubFolder\SubFolder\Script3.ps1

When we execute Script1.ps1 it uses dot-sourcing for Script2.ps1 which changes $PSScriptRoot variable and then when Script1.ps1 executes its line #13 that variable is already changed and pointing to the wrong folder

I found another blogpost about the same issue http://rkeithhill.wordpress.com/2010/09/19/determining-scriptdir-safely/

And finally I have got a reliable solution

Instead of defining $PSScriptRoot variable define the following function

function PSScriptRoot { $MyInvocation.ScriptName | Split-Path }

And replace usage $PSScriptRoot with $(PSScriptRoot)

This approach works as expected in PowerShell 2 and 3


Share this post on:

Previous Post
PowerShell 3 bug with stack trace
Next Post
Useful git hooks - Part 3