Version 1 (modified by Vijay Varadan, 8 years ago) (diff)


PowerShell: Dot Sourcing Scripts Quirks

Jan 05 2016


I spent the last couple of days of 2015 porting my build environment scripts (recommend that you read that article first) over to PowerShell. I ran into some rather quirky and inconsistent behavior when dot-sourcing scripts.

I wanted to stick to the same organization and file layout that I had for the MSYS and Linux platforms. Essentially, something like this:

    |-$PROFILE ![1]
              |-devenv.ps1 ![3]
              | |-devenv.ps1 ![4]
                |-project1.ps1 ![5]
              | |-devenv.ps1
                |-devenv.ps1 ![2]
  1. $PROFILE [1] contains the Start-Dev() function
  2. devenv.ps1 [2] user specific overrides go here
  3. devenv.ps1 [3] common to all projects, users and roles, like build / install directories
  4. devenv.ps1 [4] role specific settings go here
  5. project1.ps1 [5] project and sub-project (if any) specific settings go here

So, I started off with the 1:1 port attempt with necessary adjustments to naming conventions (camel case for variables, title case for functions, etc). So, the user profile script [1] has a Start-Dev() function which is the equivalent of startdev() in .bashrc. Just like it works for the MSYS platform, this function in turn dot-sources the user specific devenv.ps1 [2]. devenv.ps1 [2] dot-sources the common devenv.ps1 [3] and the role specific (in this case, developer) devenv.ps1 [4], which dot-sources the project specific [5] for that role.

I expected things would work fine, but they didn't. It was a tad difficult to debug initially, since the environment variables were getting set and I could see them when I invoked the Start-Dev() function, but functions and aliases that were setup in the dot-sourced PS1 files were missing from the PowerShell environment. The inconsistency flummoxed me for a bit. So, I threw in some Write-Host statements immediately following the lines where the functions and aliases were defined and they were fine. Similarly, they existed in the caller, cascading upwards all the way to the initial dot-sourcing that happens in the Start-Dev() function.

First I tried replacing the dot-sourcing with Invoke-Expression, but as I expected based on the documentation, that didn't work either. The behavior was inconsistent - environment variables were set / updated correctly, but function and alias definitions just disappeared, poof! I tried PowerShell modules instead of scripts to see if that fixed the problem, but no dice. The solution I ended up with was to create a Start-Dev.ps1 script with the contents of the function dumped into the script's global space. I dot-sourced the script like this:

PS C:\Users\vijay> . Start-Dev 1 project1

That did the trick. All functions and aliases defined in the dot-sourced files became defined and available in the PowerShell environment. I wrapped up the porting work by adding an alias to simplify invocation of the Start-Dev.ps1 script.