Table of Contents
1. Introduction to the Problem Statement
PowerShell, a powerful scripting language and command-line shell, is widely used for automation in Windows environments. A common requirement in PowerShell scripting is to call one script from another, enabling modular programming and reusability of code.
Suppose we have two scripts:
ChildScript.ps1
: This script performs a task and returns a value. For instance, it could check disk space and return true if there’s enough space or false otherwise.MainScript.ps1
: This script callsChildScript.ps1
and takes action based on the returned value fromChildScript.ps1
.
2. ChildScript.ps1
1 2 3 4 5 6 7 8 9 10 11 12 13 |
# ChildScript.ps1 # Function to check disk space function Check-DiskSpace { # Example condition: If free space is more than 10GB $freeSpace = Get-PSDrive C | Select-Object -ExpandProperty Free return $freeSpace -gt 10GB } # Calling the function and returning its output Check-DiskSpace |
ChildScript.ps1
defines a function Check-DiskSpace
that checks if the free space on the C drive is more than 10GB and returns $true
or $false
accordingly.
Let’s write different main script based on the different methods which we are going to use.
3. Using the &
Operator (Call Operator)
The most straightforward method is to use the &
operator, also known as the call operator, in PowerShell.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
# MainScript.ps1 # Path to the child script $childScriptPath = ".\ChildScript.ps1" # Calling the child script and capturing the output $isEnoughSpace = & $childScriptPath # Making a decision based on the output if ($isEnoughSpace) { Write-Host "Sufficient disk space available." } else { Write-Host "Warning: Low disk space." } |
Explanation:
- Setting Path to the Child Script: The script sets
$childScriptPath
with the relative path toChildScript.ps1
. - Calling the Child Script: It uses the call operator (
&
) to executeChildScript.ps1
and captures its output (expected to be a boolean value) in the variable$isEnoughSpace
. - Decision Based on Output: An
if-else
statement checks the value of$isEnoughSpace
. If it’s$true
, the script prints “Sufficient disk space available.” Otherwise, it prints “Warning: Low disk space.”
This script demonstrates how to call a separate PowerShell script and use its output for conditional logic within the calling script.
Performance:
This method is efficient and has minimal performance overhead. It is a direct call and executes the script in the current PowerShell session.
4. Using Dot Sourcing
Dot sourcing is a technique in PowerShell to run a script in the current scope, allowing the main script to access variables and functions defined in the child script.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
# MainScript.ps1 # Path to the child script $childScriptPath = ".\ChildScript.ps1" # Dot sourcing the child script . $childScriptPath # Since the function is now available in the main script's scope, it can be called directly $isEnoughSpace = Check-DiskSpace # Decision based on the output if ($isEnoughSpace) { Write-Host "Sufficient disk space available." } else { Write-Host "Warning: Low disk space." } |
This script, MainScript.ps1
, demonstrates how to use dot sourcing in PowerShell to call a function from another script (ChildScript.ps1
) and use its output for decision-making:
- Setting the Path to the Child Script: The variable
$childScriptPath
is assigned the relative path toChildScript.ps1
. - Dot Sourcing the Child Script: The dot sourcing operator (
.
) is used to executeChildScript.ps1
. This makes all functions and variables fromChildScript.ps1
available in the scope ofMainScript.ps1
. - Calling the Function Directly: The function
Check-DiskSpace
fromChildScript.ps1
is called directly, and its output (expected to be a boolean indicating disk space status) is stored in$isEnoughSpace
. - Making a Decision Based on the Output: The script uses an
if-else
statement to check$isEnoughSpace
. If it’s$true
, it indicates sufficient disk space and prints “Sufficient disk space available.” Otherwise, it prints “Warning: Low disk space.”
This approach is useful when we want to access functions or variables from another script directly within the current script’s scope.
Performance:
Dot sourcing is efficient and particularly useful when the main script needs to access resources defined in the child script. It has similar performance characteristics to the call operator.
5. Using Invoke-Expression
Another method is to use the Invoke-Expression
cmdlet, which evaluates a string as PowerShell code and executes it.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
# MainScript.ps1 # Path to the child script $childScriptPath = ".\ChildScript.ps1" # Calling the child script and capturing the output using Invoke-Expression $isEnoughSpace = Invoke-Expression $childScriptPath # Making a decision based on the output if ($isEnoughSpace) { Write-Host "Sufficient disk space available." } else { Write-Host "Warning: Low disk space." } |
Explanation: Invoke-Expression
evaluates the script at the specified path as a PowerShell command. The output of the child script is captured into $isEnoughSpace
, which is then used to make a decision.
Performance:
Invoke-Expression
has a slight overhead of parsing the string expression, but this is generally negligible. It’s as efficient as the call operator for most practical purposes.
6. Using Start Process
For running scripts completely independently, Start-Process
can be used. For Start-Process
, it’s important to note that it starts a separate process, which makes capturing output directly more complex. To capture output, we would typically redirect the output to a file and then read from that file.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
# MainScript.ps1 # Path to the child script $childScriptPath = ".\ChildScript.ps1" $outputFile = ".\output.txt" # Starting the child script as a separate process and redirecting output to a file Start-Process PowerShell -ArgumentList "-File `"$childScriptPath`" > `"$outputFile`"" -Wait -NoNewWindow # Reading output from the file $isEnoughSpace = Get-Content $outputFile -Raw # Making a decision based on the output if ($isEnoughSpace -eq $true) { Write-Host "Sufficient disk space available." } else { Write-Host "Warning: Low disk space." } # Optionally, delete the output file if it's no longer needed Remove-Item $outputFile |
Explanation: Start-Process
is used to run ChildScript.ps1
in a separate PowerShell process. The output is redirected to a temporary file (output.txt
). The main script then reads the content of this file to capture the output of the child script. After processing the output, the temporary file is deleted for cleanup.
This method is useful for complete isolation of the child script, running it in a separate process. This can be beneficial for resource-intensive scripts or scripts that need to run in a different context.
Performance:
Running a script as a separate process introduces additional overhead compared to other methods. It is slower due to the creation of a new process but provides isolation and is useful when such separation is necessary.
7. Calling PowerShell Script with Parameters from Another Script
In advanced PowerShell scripting, it’s common to not only call one script from another but also to pass parameters to the called script. This approach enhances script flexibility and allows for dynamic execution based on varying inputs.
Scenario: Continuing with our previous example, let’s say ChildScript.ps1
now accepts a parameter to specify the drive for which to check disk space. MainScript.ps1
needs to call ChildScript.ps1
with a specific drive letter as a parameter and then act based on the returned value.
Goal: We will explore methods to call ChildScript.ps1
with a parameter from MainScript.ps1
, capture the output, and use it in MainScript.ps1
for further actions.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
# ChildScript.ps1 param ( [string]$DriveLetter ) function Check-DiskSpace { param ( [string]$Drive ) $freeSpace = Get-PSDrive $Drive | Select-Object -ExpandProperty Free return $freeSpace -gt 10GB } Check-DiskSpace -Drive $DriveLetter |
Explanation: ChildScript.ps1
now accepts a parameter $DriveLetter
. The Check-DiskSpace
function uses this parameter to check the disk space of the specified drive.
Let’s use different methods to call powerShell script with parameters from another Script:
7.1 Using the Call Operator (&
) with Parameters:
1 2 3 4 5 6 7 8 9 10 11 12 |
# Using the Call Operator with Parameters $childScriptPath = ".\ChildScript.ps1" $drive = "C" $isEnoughSpace = & $childScriptPath -DriveLetter $drive if ($isEnoughSpace) { Write-Host "Sufficient disk space available on drive $drive." } else { Write-Host "Warning: Low disk space on drive $drive." } |
7.2 Using Dot Sourcing with Parameters:
1 2 3 4 5 6 7 8 9 10 11 |
# Using Dot Sourcing with Parameters . $childScriptPath -DriveLetter $drive $isEnoughSpace = Check-DiskSpace -Drive $drive if ($isEnoughSpace) { Write-Host "Sufficient disk space available on drive $drive." } else { Write-Host "Warning: Low disk space on drive $drive." } |
7.3 Using Invoke-Expression with Parameters:
1 2 3 4 5 6 7 8 9 10 11 |
# Using Invoke-Expression with Parameters $scriptWithParams = "$childScriptPath -DriveLetter $drive" $isEnoughSpace = Invoke-Expression $scriptWithParams if ($isEnoughSpace) { Write-Host "Sufficient disk space available on drive $drive." } else { Write-Host "Warning: Low disk space on drive $drive." } |
7.4 Using Start-Process with Parameters:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
# Using Start-Process with Parameters $outputFile = ".\output.txt" $argumentList = "-File `"$childScriptPath`" -DriveLetter $drive > `"$outputFile`"" Start-Process PowerShell -ArgumentList $argumentList -Wait -NoNewWindow $isEnoughSpace = Get-Content $outputFile -Raw if ($isEnoughSpace) { Write-Host "Sufficient disk space available on drive $drive." } else { Write-Host "Warning: Low disk space on drive $drive." } Remove-Item $outputFile |
8. Passing Complex Objects as Parameter
Passing complex objects as parameters directly between PowerShell scripts is inherently challenging due to the nature of how scripts and processes handle data. However, there are a few methods and workarounds to consider:
8.1. Dot Sourcing
Dot sourcing is a method that can be used when scripts are run in the same context. It doesn’t start a new process, but rather runs the script in the current PowerShell session.
- Usage: If we dot-source a child script, it runs in the context of the calling script. This allows shared access to complex objects defined in one script to another.
- Limitation: This only works when scripts are executed in the same PowerShell session. It’s not suitable for scenarios requiring scripts to run in isolated environments.
8.2. Session-Based Variables
In PowerShell, we can create session-based variables that can store complex objects. These variables are accessible in scripts that run in the same session.
- Usage: Define a session variable in one script and access it in another script.
- Limitation: Similar to dot sourcing, this method works only within the same PowerShell session.
8.3. Serialization and Deserialization
For passing data between scripts running in different contexts (e.g., different processes), serialization is the most viable method. We serialize an object to a string format like JSON or XML, pass the string to the other script, and then deserialize it back to an object.
- Usage: Use
ConvertTo-Json
andConvertFrom-Json
orExport-Clixml
andImport-Clixml
for converting objects to and from strings. - Limitation: Serialization may not perfectly preserve some types of objects, and there is an overhead in serializing and deserializing objects.
8.4. Temporary File Storage
Storing objects in temporary files is another way to share complex data between scripts. This is a more manual approach but can be effective for certain types of objects.
- Usage: Store the object in a temporary file in one script and read it from the other script.
- Limitation: Requires managing temporary files and ensuring they are securely created and properly deleted after use.
8.5. Inter-Process Communication (IPC)
For advanced scenarios, IPC mechanisms like named pipes or memory-mapped files can be used to pass complex objects between scripts.
- Usage: Establish an IPC channel to transmit data between processes.
- Limitation: This approach is complex and may be overkill for simpler scripting needs.
9. Conclusion
There are multiple ways to call a PowerShell script from another script, each with different use cases and performance implications:
- Using the Call Operator (
&
): Best for general-purpose script calling. It’s simple, efficient, and executes the script in the current session. - Using
Invoke-Expression
: Offers flexibility but should be used with caution to avoid security risks. - Dot Sourcing (
.
): Ideal for scenarios where the main script needs to access resources from the child script. - Using
Start-Process
: Suitable for isolating the child script execution from the main script, albeit with some performance overhead.
In choosing the right method, consider the specific requirements of our script, such as whether we need to share variables and functions between scripts, or if we require script execution isolation. For most cases, the call operator or dot sourcing will suffice, offering a balance between efficiency and functionality.