James O'Neill's blog

Windows Platform, Virtualization and PowerShell with a little Photography for good measure.

Dude, where’s my script ?

Dude, where’s my script ?

  • Comments 1
  • Likes

I’ve been working on a PowerShell script over the last few days which uses an XML file. (That’s another post in the stack). I had a nagging question about how to figure out where the script file is in order to because that’s where the XML file needs to be loaded from. Fortunately someone else threw a near identical question to our discussion list internally and Lee Holmes came up with answer - it’s in the sample from his PowerShell Cookbook

To determine the location of the currently executing script, use this function:

function Get-ScriptPath
{     Split-Path $myInvocation.ScriptName 

}

I’ve used $myInvocation before. People pick up one of the script libraries I put together, when they are new to PowerShell, and rarely know that they need “Dot Source” a library – i.e. invoke it as . script name

So now I have this at the end of my library scripts.

if ($myinvocation.line -match "^\.\s") {"Functions loaded" } 
Else {write-host -ForegroundColor red "No Functions were loaded - you need to invoke with . scriptname "}

A little bit of regular expression checks the line starts with . followed by a space. (The first try checked just for a space and anyone who run the script .\scriptName), and then the script either reports the functions have been loaded or tell the user the right way to load them. 

But I had a bit of trouble with Lee’s one liner. It turns out that in a script which uses $myInvocation.ScriptName outside a function Scriptname is empty: $myinvocation contains the command line used to run the script in the Line property and the name name of the script itself (without the path) in the MyCommand  property. If PowerShell found the script on the path it won’t work.  But inside a function the command-line property is the line of script that called the function the scriptname property contains the name of the script that holds the command line.

So I tried this.

PS C:\Users\jamesone\Documents\windowsPowershell> set-content Invoke.ps1 "where_am_I -fake parameter"
PS C:\Users\jamesone\Documents\windowsPowershell> function where_am_i {$myInvocation}
PS C:\Users\jamesone\Documents\windowsPowershell> .\invoke

MyCommand        : where_am_i
ScriptLineNumber : 1
OffsetInLine     : -2147483648
ScriptName       : C:\Users\jamesone\Documents\windowsPowershell\Invoke.ps1
Line             : where_am_I -fake parameter

Ah ha !  That’s clever. The function doesn’t need to be in the script, but it can know which line from which script called it.  And Split-Path divides the folder from the from file name. Though I will probably name the function get-ScriptFolder

Comments
  • Yes, as mentioned in the recipe -- putting the code in a function is the crucial point to prevent an ugly conditional statement. An alternative is "& { $myInvocation.ScriptName }", but that looks too idiomatic for my liking.

    Lee

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment