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: