How to Write Interdependent Scripts

PowerShell Team

A lot of the time, I want to build scripts that depend on other scripts that I’ve already written.  Sometimes I will just want to be able to use a custom Cmdlet or function I’ve written.  Sometimes, I’ll simply want to always call the underlying script without changing anything and sometimes I’ll want to change to make the default arguments to a command customizable (like giving a custom Copy-Item script a default destination).

 

There are two ways you can approach this.  You can reference the script, by .\ or by absolute path, and pass it’s arguments normally, or you can determine the location of the current script and create aliases or functions that call the script.  Of the two ways to go, the second, while a little trickier, is the recommended approach.

 

The first approach has a couple of drawbacks.  If you use .\ to run the scripts, then they have to really be in the current directory.  If you use this approach, you would have to switch the location where the scripts are (with Push-Location) just before you run the script, and then revert it when you’re done.  This approach works for making one command that depends on another, but if you tried to have another command that used that command, it wouldn’t work (because the new scripts would change the location, and then your script would change the location, and then the new scripts would be looking for scripts in the wrong place).  It is not a sustainable approach.

 

If you ever write production scripts that call other scripts with .\, you should try the approach below instead, because your scripts can conflict with others that take the same approach, or can have trouble working if scripts are called from another directory.

 

The second approach is pretty simple, and can be done in 3 steps:

 

1.       Find the root location of the script

2.       Set an Alias or create a function to call the script that the script depends on

3.       In each of the script files, check for all of the required commands before running

 

I’ll demonstrate the technique below.  In this case, I’m writing a script that depends on two other scripts, Get-MyData –Id <int> -DataSet<Object> and Set-MyData –Id <int> -DataSet<Object>, which depend on a third and fourth command, Test-MyData (used by both) and Add-MyData (used by just Set-MyData)

 

Part 1 can be done in this simple line, which should be at the top of the script (not within a function or script block)

      $scriptRoot = Split-Path (Resolve-Path $myInvocation.MyCommand.Path)

 

To do part 2:

 

If you don’t want to change the arguments you’re passing, you can just alias the script:

 

Set-Alias “Set-MyData” $scriptRoot\Set-MyData.ps1

 

Now let’s suppose I’ll almost always want to get the same set of data.  I can omit that parameter by writing a function that uses a different default and calls Get-MyData

 

function Get-MyData($id, $dataSet = “MyDataSet”) {

   $scriptRoot\Get-MyData –id $id `

     -dataSet $dataSet

}

 

To do part 3, you would put this little snippet of code after the parameter block in Set-MyData.ps1.  In Get-MyData.ps1, $requiredCommands would just be “Test-MyData”.

 

$requiredCommands = “Test-MyData”, “Add-MyData”

$null = get-command $requiredcommands -ea SilentlyContinue -ev missingRequiredcommands

foreach ($cmd in $missingRequiredCommands) {

    Write-Warning “Missing $($cmd.Exception.CommandName)”

}

if ($missingRequiredCommands.Count) { throw “Missing Required Commands, Exiting.” }

 

By following the approach outlined above (finding the root, aliasing the dependent scripts, and checking for dependencies in each script), you can reuse your PowerShell code quickly and easily.

 

Hope this helps,

 

James Brundage [MSFT]

0 comments

Discussion is closed.

Feedback usabilla icon