How to Call a PowerShell Script from Another Script

If you have a main script that needs to run a helper script, put the call operator and the helper’s full path on one line: & "$PSScriptRoot\Jobs\Get-OpenInvoices.ps1". That’s how you call a PowerShell script from another script.

The line itself is easy. The trouble starts around it: relative paths that break when you launch from a different folder, variables that disappear after the call, and errors that quietly stop the whole job.

In this tutorial, I’ll show you how to call a PowerShell script from another script with the call operator, dot-sourcing, a separate pwsh process and a module. You’ll also pass parameters, read return values and exit codes, and catch errors.

The sample scripts we’ll use

Every method below works on the same small project for Summit Peak Supply, a made-up outdoor gear wholesaler in Denver. The main script, Start-MonthEnd.ps1, runs the month-end jobs by calling the other scripts.

Here’s the folder layout. I kept everything under C:\psfaqs, but any folder works:

C:\psfaqs\
    Start-MonthEnd.ps1                     the main (calling) script
    Jobs\Get-OpenInvoices.ps1              returns open invoices as objects
    Jobs\Measure-Invoices.ps1              calls Get-OpenInvoices.ps1 and counts them
    Jobs\Send-Reminders.ps1                ends with an exit code
    Jobs\Import-Payments.ps1               throws an error when a file is missing
    Jobs\Sync-Customers.ps1                writes a non-terminating error
    Helpers\InvoiceTools.ps1               shared variables and a Format-Usd function
    Modules\SummitTools\SummitTools.psm1   the same tools as a module

To build it, create the three folders in File Explorer, then open VS Code or Notepad and save each file with a .ps1 extension. This is the child script most examples call:

param(
    [string]$City = 'Austin',
    [decimal]$MinAmount = 0
)
$invoices = @(
    [pscustomobject]@{ Invoice = 'INV-1041'; Customer = 'Maria Lopez'; City = 'Austin'; Amount = [decimal]'1250.50' }
    [pscustomobject]@{ Invoice = 'INV-1042'; Customer = 'Tom Baker'; City = 'Denver'; Amount = [decimal]'860.00' }
    [pscustomobject]@{ Invoice = 'INV-1043'; Customer = 'Dana Reyes'; City = 'Austin'; Amount = [decimal]'3420.75' }
    [pscustomobject]@{ Invoice = 'INV-1044'; Customer = 'Kevin Walsh'; City = 'Seattle'; Amount = [decimal]'415.20' }
)
$invoices | Where-Object { $_.City -eq $City -and $_.Amount -ge $MinAmount }

It takes a city and a minimum amount, then sends matching invoices down the pipeline. Austin has two open invoices, Denver and Seattle have one each. For more small jobs like this, browse these practical PowerShell script examples.

If Windows blocks the first run, the cause is the execution policy, not your code. Here’s how to fix running scripts is disabled on this system without weakening the whole PC.

Method 1: Call a script with the & call operator (Recommended)

The call operator & runs a command, script or script block. Microsoft’s about_Operators page says it runs in a child scope, so the called script can’t overwrite the caller’s variables.

Same sample project here: Start-MonthEnd.ps1 calls Get-OpenInvoices.ps1 twice, once with a path built from $PSScriptRoot and once with a relative path. Here’s the main script: