deetle
deetle

Reputation: 387

How to get the script name , the one that was run by PowerShell

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

Answers (2)

codewario
codewario

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

Daniel
Daniel

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

Related Questions