Reputation: 387
I am running a PowerShell script. That script calls a cmdlet which calls a cmdlet and so on. I am 20 cmdlets deep, 9 PowerShell ps1
files deep, how do I get the PowerShell script that stated it it all? As the below only gives the the last calling script, not the one that started it all.
$MyInvocation | Out-Default
Upvotes: 1
Views: 1635
Reputation: 21418
Note: It looks like MS has updated their documentation to also term "advanced functions" which written to function like binary cmdlets as "cmdlets" as well. Previously, MS only technically classified compiled (binary) cmdlets as "cmdlets", though most of the PowerShell community still called PowerShell functions cmdlets and there was little functional difference between them. I'm leaving this here as a tidbit of history on the subject.
First, unless you defined your script with [CmdletBinding()]
, it most likely isn't a cmdlet, just a script. Cmdlets are technically compiled from C# but PowerShell-defined "cmdlets" are just functions or scripts either decorated with [CmdletBinding()]
or use advanced attributes on at least one parameter to the script.
Edit: I originally claimed you can't do this with a built-in construct, but @Daniel's helpful answer proved me wrong.
Get-PSCallStack
can be used for this and I recommend it. Still, there is some good info about dot-sourcing below and this is another way you could solve this.
You would have to keep track of this yourself by either passing in the original script as a parameter to each child script (not recommended) or create a global variable with the original value of $MyInvocation.MyCommand
either in the first script you execute or in your initial command which runs the script:
$global:OriginalCommand = $MyInvocation.MyCommand
$global:OriginalCommand
should now return your original executed command if you reference it in your child scripts.
A third, but more complex option, would be to dot-source your scripts when you execute them:
. ./script.ps1
Dot-sourcing your script executes them in the current scope, and $MyInvocation
should match the original values of your entrypoint script. The downside to this approach is that all of your scripts will execute under the same scope (you will still get additional child scopes where appropriate, just not for each script), and you will need to take care not to stomp on variables that might still be in use by one of the parent scripts.
Dot-sourcing is typically used to, for instance, define functions and import them into a script when modules aren't desired for some reason. However, it's not invalid to use dot-sourcing in the way I described above, you just need to take care of the caveats of each script invoked with dot-sourcing sharing the same script scope.
Here is some more information in about_Scopes about Using Dot Source Notation with Scope.
Upvotes: 1
Reputation: 5114
Built-in Get-PSCallStack
should give you what you are looking for
Example Output
PS C:\temp\powershell> .\test_stack3.ps1 | ft *
Command Location Arguments ScriptName ScriptLineNumber InvocationInfo Position FunctionName
------- -------- --------- ---------- ---------------- -------------- -------- ------------
test3 test_stack.ps1: line 2 {} C:\temp\powershell\test_stack.ps1 2 System.Management.Automation.InvocationInfo Get-PSCallStack test3
test2 test_stack.ps1: line 5 {} C:\temp\powershell\test_stack.ps1 5 System.Management.Automation.InvocationInfo test3 test2
test1 test_stack.ps1: line 8 {} C:\temp\powershell\test_stack.ps1 8 System.Management.Automation.InvocationInfo test2 test1
test_stack.ps1 test_stack.ps1: line 11 {} C:\temp\powershell\test_stack.ps1 11 System.Management.Automation.InvocationInfo test1 <ScriptBlock>
test_stack2.ps1 test_stack2.ps1: line 1 {} C:\temp\powershell\test_stack2.ps1 1 System.Management.Automation.InvocationInfo .\test_stack.ps1 <ScriptBlock>
first test_stack3.ps1: line 5 {} C:\temp\powershell\test_stack3.ps1 5 System.Management.Automation.InvocationInfo .\test_stack2.ps1 first
test_stack3.ps1 test_stack3.ps1: line 8 {} C:\temp\powershell\test_stack3.ps1 8 System.Management.Automation.InvocationInfo first <ScriptBlock>
<ScriptBlock> <No file> {} 1 System.Management.Automation.InvocationInfo .\test_stack3.ps1 | ft * <ScriptBlock>
Upvotes: 1