Sunday, July 6, 2008

The DotSource Operator

A while back I asked Stephen Ng if he had seen any documentation on importing scripts as modules or libraries, and he hadn't. I sort of filed it away for future reference, knowing that if we went down this path we'd probably want to find some way to keep a repository of PowerShell scripts for common use.

Fast forward to a few days ago, when the latest entry from The PowerShell Guy showed up in my Google Reader. In his Get-IpConfig function (which I'll discuss in a later post) he has a line with an open parenthesis followed by a dot.wasn't the most readable line of code in the world anyway, but as I was mentally parsing it I hit a snag. I had no idea what that dot was doing just after the open parenthesis.

As it turns out, this is what's known as the dotsource operator. The dotsource operator (I wish people would stop and think a bit when choosing these terrible names) is like the ampersand (&) operator, in that it executes the script or code block that comes after it, but it also declares all variables in the global scope. Why would you want to do this?

Let's use a terrible example and say I have a script that will get a list of users and groups on a computer. I have a script, Get-UsersAndGroups.ps1. It creates two variables, $users and $groups, and exits. I want to be able to use those variables, so I run the following:

PS C:\> .\Get-UsersAndGroups.ps1
PS C:\> $users

I get nothing back, even though I know I created the variable. $users was created in the script's scope, though, and once the script finishes running it takes its variables with it.

I have three options here:
  1. Change my script to send the variables to the output pipeline. Maybe this script is being used by other people, though, so I don't necessarily want to change the pipeline.
  2. Explicitly declare the variables as $global:users and $global:groups in the script. The problem with this is that I don't necessarily always want to declare these variables in the global namespace.
  3. Use the dotsource operator.
The way to use the dotsource operator is like this:

PS C:\> . .\Get-UsersAndGroups.ps1
PS C:\> $users
Tim
Administrator
Alfred E. Neuman

(Note that there is a space between the dots there, otherwise I'd just be telling PowerShell to look in the parent directory.)

To wrap this up, we can take all of this newfound knowledge and see how you can create libraries in PowerShell. By dotsourcing (yes, people even use it as a verb, ugh) a script with functions and constants in it, we can import the functions in a way that makes them usable by our scripts, that way we can reuse the code.

The one big problem is that PowerShell has no concept of a /lib directory that it looks for modules in by default, so you must know the path to the script you will be importing. I'll leave that as a future exercise, but I have a spark of an idea in my head of how we can create a function that looks up a script by its name to import and distribute it using a common company Profile so that all company PowerShell Scripters have a common location for libraries, like sitecustomize.py in Python.

1 comment:

Anonymous said...

You might like CTP2's Module support ;-)

Greetings /\/\o\/\/