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

Advertisements

About mnaoumov

Senior .NET Developer in Readify
This entry was posted in Uncategorized and tagged . Bookmark the permalink.

4 Responses to PowerShell $PSScriptRoot vs dot-sourcing

  1. I am surprised it works in PSv3. The PSv2 behaviour is exactly as I would expect, though maybe not have anticipated. About the only thing I’ve ever dot-sourced is $PROFILE, everything else I just use a psm1 script module and import it.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s