Home » Development » expand your scope – you can dot-source more than just files

expand your scope – you can dot-source more than just files

I’m working on a small project that will require me to dot-source some PowerShell files in order to load their functions, aliases, and variables and make them available in a session. Actually, I have to do a little more than dot-source each file, but I’ll keep the example simple to illustrate the wrinkle I ran into.

Suppose I have this file, file-to-load.ps1:

Function Get-MyName
{
    Write-Output "Blair Conrad"
}

I dot-source it from the console, and everything’s great:

PS> . .\file-to-load.ps1
PS> Get-MyName
Blair Conrad

Because I’ll be doing this over and over, and I want to manipulate the .ps1 files a little more, I decide to wrap the dot-sourcing in a function, and call it.

Function Load-File([string] $filename)
{
    . $filename
}
PS> Load-File(‘.\file-to-load.ps1’)
PS>
PS> Get-MyName
The term ‘Get-MyName’ is not recognized as the name of a cmdlet, function,
script file, or operable program. Check the spelling of the name, or if
a path was included, verify that the path is correct and try again.
At line:1 char:11
+ Get-MyName <<<<
+ CategoryInfo : ObjectNotFound: (Get-MyName:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException

Not good. The Get-MyName function is loaded inside the scope of the Load-File function. It’s only available as long as I’m inside Load-File.

I thought about modifying all the script files that were to be loaded, scoping each contained function, alias, and variable as global, but that would be a pain, and I’m not going to be the only one writing these files. Eventually, I came upon it: dot-source the Load-File function:

PS> . Load-File(‘.\file-to-load.ps1’)
PS>
PS> Get-MyName
Blair Conrad

I’ll admit I don’t quite understand why it works, but for now, I’m content to know that it does.

Advertisements

5 Comments

  1. Iain Wyatt says:

    Your other option is to declare the function as global in the script and then you don’t need to dot source the sctript and the function will still be available –

    function global:Get-MyName
    {
    Write-Output “Blair Conrad”
    }

    see http://www.microsoft.com/technet/scriptcenter/resources/pstips/jun08/pstip0627.mspx towards the end.

    Iain

    • Blair Conrad says:

      Absolutely true, thanks for mentioning it. I’d done that before stumbling on the dot-source thing. I opted to go with the dot-source so I wouldn’t force my coworkers who were writing their “Includes” (see Using Subversion to Evangelize PowerShell for context) to have to do that. Many of them (like me) are PowerShell beginners, and I didn’t want to add an additional hurdle.

  2. […] To import PS1 files with functions, they have to be dot-sourced and that provided me with some challenge: if PS1 is dot-sourced inside the function, it will be available only in that function’s scope. To overcome this one could scope each contained function, alias, and variable as global (nasty!) or call Import-Component function itself using dot-sourcing (yes, you can dot-source more than just files). […]

  3. zaphodikus says:

    Really old – but the reason you got the curious side-effect that
    . Load-File(‘.\file-to-load.ps1’)
    works, is because of the way that the parser works more than the scope being unexpectedly wrong in the normal cases.
    try using invoke-expression (I know, it’s evil) to dot-source, a bit like this:
    & “. $filename”

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: