134

Note: PowerShell 1.0
I'd like to get the current executing PowerShell file name. That is, if I start my session like this:

powershell.exe .\myfile.ps1 

I'd like to get the string ".\myfile.ps1" (or something like that). EDIT: "myfile.ps1" is preferable.
Any ideas?

2
  • Thanks, current answers are almost the same, but I only need the file name (and not the whole path), so the accepted answer is @Keith's. +1 to both answers, though. Now I know about the $MyInvocation thingy :-) Commented May 3, 2009 at 21:54
  • How about getting the parent script from an included script? Commented Apr 25, 2013 at 17:06

12 Answers 12

136

I've tried to summarize the various answers here, updated for PowerShell 5:

  • If you're only using PowerShell 3 or higher, use $PSCommandPath

  • If want compatibility with older versions, insert the shim:

    if ($PSCommandPath -eq $null) { function GetPSCommandPath() { return $MyInvocation.PSCommandPath; } $PSCommandPath = GetPSCommandPath }

    This adds $PSCommandPath if it doesn't already exist.

    The shim code can be executed anywhere (top-level or inside a function), though $PSCommandPath variable is subject to normal scoping rules (eg, if you put the shim in a function, the variable is scoped to that function only).

Details

There's 4 different methods used in various answers, so I wrote this script to demonstrate each (plus $PSCommandPath):

function PSCommandPath() { return $PSCommandPath } function ScriptName() { return $MyInvocation.ScriptName } function MyCommandName() { return $MyInvocation.MyCommand.Name } function MyCommandDefinition() { # Begin of MyCommandDefinition() # Note: ouput of this script shows the contents of this function, not the execution result return $MyInvocation.MyCommand.Definition # End of MyCommandDefinition() } function MyInvocationPSCommandPath() { return $MyInvocation.PSCommandPath } Write-Host "" Write-Host "PSVersion: $($PSVersionTable.PSVersion)" Write-Host "" Write-Host "`$PSCommandPath:" Write-Host " * Direct: $PSCommandPath" Write-Host " * Function: $(PSCommandPath)" Write-Host "" Write-Host "`$MyInvocation.ScriptName:" Write-Host " * Direct: $($MyInvocation.ScriptName)" Write-Host " * Function: $(ScriptName)" Write-Host "" Write-Host "`$MyInvocation.MyCommand.Name:" Write-Host " * Direct: $($MyInvocation.MyCommand.Name)" Write-Host " * Function: $(MyCommandName)" Write-Host "" Write-Host "`$MyInvocation.MyCommand.Definition:" Write-Host " * Direct: $($MyInvocation.MyCommand.Definition)" Write-Host " * Function: $(MyCommandDefinition)" Write-Host "" Write-Host "`$MyInvocation.PSCommandPath:" Write-Host " * Direct: $($MyInvocation.PSCommandPath)" Write-Host " * Function: $(MyInvocationPSCommandPath)" Write-Host "" 

Output:

PS C:\> .\Test\test.ps1 PSVersion: 5.1.19035.1 $PSCommandPath: * Direct: C:\Test\test.ps1 * Function: C:\Test\test.ps1 $MyInvocation.ScriptName: * Direct: * Function: C:\Test\test.ps1 $MyInvocation.MyCommand.Name: * Direct: test.ps1 * Function: MyCommandName $MyInvocation.MyCommand.Definition: * Direct: C:\Test\test.ps1 * Function: # Begin of MyCommandDefinition() # Note this is the contents of the MyCommandDefinition() function, not the execution results return $MyInvocation.MyCommand.Definition; # End of MyCommandDefinition() $MyInvocation.PSCommandPath: * Direct: * Function: C:\Test\test.ps1 

Notes:

  • Executed from C:\, but actual script is C:\Test\test.ps1.
  • No method tells you the passed invocation path (.\Test\test.ps1)
  • $PSCommandPath is the only reliable way, but was introduced in PowerShell 3
  • For versions prior to 3, no single method works both inside and outside of a function
Sign up to request clarification or add additional context in comments.

7 Comments

For anyone reading today (2017), they should be reading THIS post as the correct answer! +1
@CollinChaffin: agreed and now (2017) the least currently supported is Windows 7 so there is no reason not to use $PSCommandPath if legacy (WindowsXP) is not required.
The first code example is flawed as it contains two definitions of the same function (function PSCommandPath ) and a reference to the wrong function ( Write-Host " * Direct: $PSCommandPath"; Write-Host " * Function: $(ScriptName)"; - or am I overlooking something obvious ?
@MikeL'Angelo You're right! Went unnoticed for 3 years. Fixed, thank you. The output and conclusion is the same though.
A long answer where $PSCommandPath suffices in 99% of cases. Thanks though.
|
90

While the current Answer is right in most cases, there are certain situations that it will not give you the correct answer. If you use inside your script functions then:

$MyInvocation.MyCommand.Name 

Returns the name of the function instead name of the name of the script.

function test { $MyInvocation.MyCommand.Name } 

Will give you "test" no matter how your script is named. The right command for getting the script name is always

$MyInvocation.ScriptName 

this returns the full path of the script you are executing. If you need just the script filename than this code should help you:

split-path $MyInvocation.PSCommandPath -Leaf 

3 Comments

Note that at the top level, Scriptname is undefined with posh v4. I like to use at the top level, $MyInvocation.MyCommand.Definition for full path or Name as per the other answers.
$MyInvocation.ScriptName return empty string for me, PS v3.0.
@JohnC $MyInvocation.ScriptName only works from inside a function. See my answer below.
78

If you only want the filename (not the full path) use this:

$ScriptName = $MyInvocation.MyCommand.Name 

1 Comment

That's false for any use outside the global scope. If you create a function and you invoke this code in a function, you will get the name of the function rather then the name of the file.
35

Try the following

$path = $MyInvocation.MyCommand.Definition 

This may not give you the actual path typed in but it will give you a valid path to the file.

4 Comments

@Hamish the question specifically says if invoked from a file.
FYI: This give you the full path and the file name (Powershell 2.0)
I was searching for exactly this command. Thank you, JaredPar! :)
Use Split-Path to get the directory? $path = Split-Path $MyInvocation.MyCommand.Definition -Parent
11

beware: Unlike the $PSScriptRoot and $PSCommandPath automatic variables, the PSScriptRoot and PSCommandPath properties of the $MyInvocation automatic variable contain information about the invoker or calling script, not the current script.

e.g.

PS C:\Users\S_ms\OneDrive\Documents> C:\Users\SP_ms\OneDrive\Documents\DPM ... =!C:\Users\S_ms\OneDrive\Documents\DPM.ps1 

...where DPM.ps1 contains

Write-Host ("="+($MyInvocation.PSCommandPath)+"!"+$PSCommandPath) 

Comments

9

If you are looking for the current directory in which the script is being executed, you can try this one:

$fullPathIncFileName = $MyInvocation.MyCommand.Definition $currentScriptName = $MyInvocation.MyCommand.Name $currentExecutingPath = $fullPathIncFileName.Replace($currentScriptName, "") Write-Host $currentExecutingPath 

6 Comments

That wouldn't work correctly on C:\ilike.ps123\ke.ps1, would it?
@fridojet - Not sure, not near a PS terminal to test it. Why dont you try it and see?
No, just a rhetorical question ;-) - It would be just logical because the Replace() method replaces every occurrence of the needle (not just the last occurrence) and I also tested it. However, it's a nice idea to do something like subtraction on strings.
... What about String.TrimEnd() ($currentExecutingPath = $fullPathIncFileName.TrimEnd($currentScriptName))? - It's working correctly: "Ich bin Hamster".TrimEnd("ster") returns Ich bin Ham and "Ich bin Hamsterchen".TrimEnd("ster") returns Ich bin Hamsterchen (instead of Ich bin Hamchen) - Fine!
$currentScriptPath = $MyInvocation.MyCommand.Definition; $currentScriptName = $MyInvocation.MyCommand.Name; $currentScriptDir = $currentScriptPath.Substring(0,$currentScriptPath.IndexOf($currentScriptName));
|
9

As noted in previous responses, using "$MyInvocation" is subject to scoping issues and doesn't necessarily provide consistent data (return value vs. direct access value). I've found that the "cleanest" (most consistent) method for getting script info like script path, name, parms, command line, etc. regardless of scope (in main or subsequent/nested function calls) is to use "Get-Variable" on "MyInvocation"...

# Get the MyInvocation variable at script level # Can be done anywhere within a script $ScriptInvocation = (Get-Variable MyInvocation -Scope Script).Value # Get the full path to the script $ScriptPath = $ScriptInvocation.MyCommand.Path # Get the directory of the script $ScriptDirectory = Split-Path $ScriptPath # Get the script name # Yes, could get via Split-Path, but this is "simpler" since this is the default return value $ScriptName = $ScriptInvocation.MyCommand.Name # Get the invocation path (relative to $PWD) # @GregMac, this addresses your second point $InvocationPath = ScriptInvocation.InvocationName 

So, you can get the same info as $PSCommandPath, but a whole lot more in the deal. Not sure, but it looks like "Get-Variable" was not available until PS3 so not a lot of help for really old (not updated) systems.

There are also some interesting aspects when using "-Scope" as you can backtrack to get the names, etc. of the calling function(s). 0=current, 1=parent, etc.

Hope this is somewhat helpful.

Ref, https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/get-variable

Comments

6

I would argue that there is a better method, by setting the scope of the variable $MyInvocation.MyCommand.Path:

ex> $script:MyInvocation.MyCommand.Name

This method works in all circumstances of invocation:

EX: Somescript.ps1

function printme () { "In function:" ( "MyInvocation.ScriptName: " + [string]($MyInvocation.ScriptName) ) ( "script:MyInvocation.MyCommand.Name: " + [string]($script:MyInvocation.MyCommand.Name) ) ( "MyInvocation.MyCommand.Name: " + [string]($MyInvocation.MyCommand.Name) ) } "Main:" ( "MyInvocation.ScriptName: " + [string]($MyInvocation.ScriptName) ) ( "script:MyInvocation.MyCommand.Name: " + [string]($script:MyInvocation.MyCommand.Name) ) ( "MyInvocation.MyCommand.Name: " + [string]($MyInvocation.MyCommand.Name) ) " " printme exit 

OUTPUT:

PS> powershell C:\temp\test.ps1 Main: MyInvocation.ScriptName: script:MyInvocation.MyCommand.Name: test.ps1 MyInvocation.MyCommand.Name: test.ps1 In function: MyInvocation.ScriptName: C:\temp\test.ps1 script:MyInvocation.MyCommand.Name: test.ps1 MyInvocation.MyCommand.Name: printme 

Notice how the above accepted answer does NOT return a value when called from Main. Also, note that the above accepted answer returns the full path when the question requested the script name only. The scoped variable works in all places.

Also, if you did want the full path, then you would just call:

$script:MyInvocation.MyCommand.Path 

Comments

6

A short demonstration of @gregmac's (excellent and detailed) answer, which essentially recommends $PSCommandPath as the only reliable command to return the currently running script where Powershell 3.0 and above is used.

Here I show returning either the full path or just the file name.

Test.ps1:

'Direct:' $PSCommandPath # Full Path Split-Path -Path $PSCommandPath -Leaf # File Name only function main () { '' 'Within a function:' $PSCommandPath Split-Path -Path $PSCommandPath -Leaf } main 

Output:

PS> .\Test.ps1 Direct: C:\Users\John\Documents\Sda\Code\Windows\PowerShell\Apps\xBankStatementRename\Test.ps1 Test.ps1 Within a function: C:\Users\John\Documents\Sda\Code\Windows\PowerShell\Apps\xBankStatementRename\Test.ps1 Test.ps1 

Comments

2

Did some testing with the following script, on both PS 2 and PS 4 and had the same result. I hope this helps people.

$PSVersionTable.PSVersion function PSscript { $PSscript = Get-Item $MyInvocation.ScriptName Return $PSscript } "" $PSscript = PSscript $PSscript.FullName $PSscript.Name $PSscript.BaseName $PSscript.Extension $PSscript.DirectoryName "" $PSscript = Get-Item $MyInvocation.InvocationName $PSscript.FullName $PSscript.Name $PSscript.BaseName $PSscript.Extension $PSscript.DirectoryName 

Results -

Major Minor Build Revision ----- ----- ----- -------- 4 0 -1 -1 C:\PSscripts\Untitled1.ps1 Untitled1.ps1 Untitled1 .ps1 C:\PSscripts C:\PSscripts\Untitled1.ps1 Untitled1.ps1 Untitled1 .ps1 C:\PSscripts 

Comments

2

This can works on most powershell versions:

(& { $MyInvocation.ScriptName; }) 

This can work for Scheduled Job

Get-ScheduledJob |? Name -Match 'JOBNAMETAG' |% Command 

Comments

1

+1 for @AntGut's solution. I use included common scripts and MyInvocation and PSCommandPath are scoped to the included script.

I have a common logging function and to get the name of the top-level script, this works:

$ScriptInvocation = (Get-Variable MyInvocation -Scope Script).Value $ScriptName = $ScriptInvocation.MyCommand.Name 

1 Comment

One liner version : $ScriptName = ((Get-Variable MyInvocation -Scope Script).Value).MyCommand.Name

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.