I am working with Jenkins to deploy PowerShell scripts remotely. As such, I am trying to figure out if there will be problems utilizing $PSScriptRoot
over $MyInvocation.MyCommand.Path
for getting the current scripts root directory.
A colleague in passing told me that utilizing $PSScriptRoot
would be a bad idea for remote functionality as I might occasionally find that it does not return the expected value at runtime for one reason or another, even if it worked previously. However, could not explain why that would be.
In my research, I have not found anything on this that could explain this further or what the best practice way for avoiding such a problem would be. I primarily found that these two are basically interchangeable; however, $PSScriptRoot
can only be used in PowerShell v3 or later. And through the help of several of you already, I have also come to learn that $MyInvocation
has situational differences that allows it to change based on scope and module. But I still haven't found out if or why this would be a problem with PowerShell Remoting.
Example 001
So I have a PowerShell script in Jenkins, that uses $PSScriptRoot
to act as the means of finding a script I wish to call via a relative path. Would I be able to rely on this to always provide the same/expected path to said script?
Example 002
Using a PowerShell script that was called by a PowerShell script that Jenkins initiated, would I be able to expect $PSScriptRoot
to be able to provide me with the path of where that script actually sits, or would it give me a path based on Jenkins?
Personally, I am expecting both to be that $PSScriptRoot
will provide me with the actual physical location of the script that is running rather than a relative path that changes based on the initial script that called it.
Since having this understanding would help save me a lot of time and headache, I am hoping that fellow programmers such as yourself could help enlighten me to IF this is true, and why such a problem would happen.
I am trying to find out if using $PSScriptRoot
would cause me problems in PowerShell Remoting that would make using $MyInvocation
a more viable option?
PSScriptRoot - Contains the full path to the script that invoked the current command. The value of this property is populated only when the caller is a script.
According to PowerShell documentation: $MyInvocation Contains an information about the current command, such as the name, parameters, parameter values, and information about how the command was started, called, or "invoked," such as the name of the script that called the current command.
$PSScriptRoot.GetType().FullName
> System.String
$PSScriptRoot
> C:\Temp
$PSScriptRoot
is an automatic variable which only holds a string object of the current script's directory.
$MyInvocation.GetType().FullName
> System.Management.Automation.InvocationInfo
$MyInvocation
> MyCommand : test.ps1
> BoundParameters : {}
> UnboundArguments : {}
> ScriptLineNumber : 0
> OffsetInLine : 0
> HistoryId : 4
> ScriptName :
> Line :
> PositionMessage :
> PSScriptRoot :
> PSCommandPath :
> InvocationName : C:\Temp\test.ps1
> PipelineLength : 2
> PipelinePosition : 1
> ExpectingInput : False
> CommandOrigin : Internal
> DisplayScriptPosition :
$MyInvocation | Get-Member -Force
TypeName: System.Management.Automation.InvocationInfo
Name MemberType Definition
---- ---------- ----------
pstypenames CodeProperty System.Collections.ObjectModel.Collection`1[[System.String, mscorlib...
psadapted MemberSet psadapted {MyCommand, BoundParameters, UnboundArguments, ScriptLineN...
psbase MemberSet psbase {MyCommand, BoundParameters, UnboundArguments, ScriptLineNumb...
psextended MemberSet psextended {}
psobject MemberSet psobject {BaseObject, Members, Properties, Methods, ImmediateBaseObj...
Equals Method bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetType Method type GetType()
get_BoundParameters Method System.Collections.Generic.Dictionary[string,System.Object] get_Boun...
get_CommandOrigin Method System.Management.Automation.CommandOrigin get_CommandOrigin()
get_DisplayScriptPosition Method System.Management.Automation.Language.IScriptExtent get_DisplayScrip...
get_ExpectingInput Method bool get_ExpectingInput()
get_HistoryId Method long get_HistoryId()
get_InvocationName Method string get_InvocationName()
get_Line Method string get_Line()
get_MyCommand Method System.Management.Automation.CommandInfo get_MyCommand()
get_OffsetInLine Method int get_OffsetInLine()
get_PipelineLength Method int get_PipelineLength()
get_PipelinePosition Method int get_PipelinePosition()
get_PositionMessage Method string get_PositionMessage()
get_PSCommandPath Method string get_PSCommandPath()
get_PSScriptRoot Method string get_PSScriptRoot()
get_ScriptLineNumber Method int get_ScriptLineNumber()
get_ScriptName Method string get_ScriptName()
get_UnboundArguments Method System.Collections.Generic.List[System.Object] get_UnboundArguments()
set_DisplayScriptPosition Method void set_DisplayScriptPosition(System.Management.Automation.Language...
ToString Method string ToString()
BoundParameters Property System.Collections.Generic.Dictionary[string,System.Object] BoundPar...
CommandOrigin Property System.Management.Automation.CommandOrigin CommandOrigin {get;}
DisplayScriptPosition Property System.Management.Automation.Language.IScriptExtent DisplayScriptPos...
ExpectingInput Property bool ExpectingInput {get;}
HistoryId Property long HistoryId {get;}
InvocationName Property string InvocationName {get;}
Line Property string Line {get;}
MyCommand Property System.Management.Automation.CommandInfo MyCommand {get;}
OffsetInLine Property int OffsetInLine {get;}
PipelineLength Property int PipelineLength {get;}
PipelinePosition Property int PipelinePosition {get;}
PositionMessage Property string PositionMessage {get;}
PSCommandPath Property string PSCommandPath {get;}
PSScriptRoot Property string PSScriptRoot {get;}
ScriptLineNumber Property int ScriptLineNumber {get;}
ScriptName Property string ScriptName {get;}
UnboundArguments Property System.Collections.Generic.List[System.Object] UnboundArguments {get;}
Function Example { $MyInvocation } Example
MyCommand : Example
BoundParameters : {}
UnboundArguments : {}
ScriptLineNumber : 8
OffsetInLine : 1
HistoryId : 6
ScriptName : C:\Temp\test.ps1
Line : Example
PositionMessage : At C:\Temp\test.ps1:8 char:1
+ Example
+ ~~~~~~~
PSScriptRoot : C:\Temp
PSCommandPath : C:\Temp\test.ps1
InvocationName : Example
PipelineLength : 1
PipelinePosition : 1
ExpectingInput : False
CommandOrigin : Internal
DisplayScriptPosition :
$MyInvocation
is an automatic variable with a very different type, generated for each scope. Its members and utility varies based on scope.
Tests completed on PSv5.1, Windows 7 SP1
Remember that both of these variables refer to the file that is being executed. If there is no file, they are empty.
In remoting, like when you use Invoke-Command -ScriptBlock { }
there is no file.
It might work if you are calling a function that's in a module in the remoting session, and that function uses $PSScriptRoot
or $MyInvocaton...
in which case it would likely return whatever file it's in.
In the case of something like Jenkins, that's not remoting. Jenkins creates a temporary file and runs your code out of it, so that's the file that will be returned.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With