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