PowerShell 7 startup was slower than Windows PowerShell 5.1 on native ARM64
In this article
The median for pwsh -NoProfile -c exit was 386.8 ms, while powershell -NoProfile -c exit took 212.2 ms. Looking only at startup, the gap was larger than I expected.
Because PowerShell 7 is newer, I expected at least its startup to be roughly comparable. On 2026-08-02, the result was the opposite on a Surface Pro 11th Edition. The machine had a Snapdragon X Elite X1E80100, Windows 11 Pro 10.0.26200 ARM64, AC power, and the Balanced power plan (381b4222-f694-41f0-9685-ff5bb260df2e), close to my normal working conditions.
My first suspicion was emulation. Reading the PE headers showed Machine 0xAA64 for both pwsh and powershell.exe. Both were native ARM64, so I could not explain the result by saying that one was x64 and therefore slower (if that check had failed, the direction of this article would have changed considerably).
Seven launches, then a comparison
I used Measure-Command seven times and recorded the first run separately from the median of runs two through seven. File caches and runtime state can make the first run unstable; collapsing everything into one median would make the result harder to read. Startup tests often have one unusually heavy first run, so I kept that distinction.
1..7 | ForEach-Object {
(Measure-Command { pwsh -NoProfile -c "exit" }).TotalMilliseconds
}
-NoProfile was mandatory. My pwsh profile contains completion and appearance settings, and loading it would make it impossible to tell whether PowerShell 7 was slow or my own profile was heavy. I waited for OneDrive synchronization to settle, but this was not a clean measurement with every resident process removed.
The numbers moved quite a bit
Here are all seven runs, including the first.
| Command | First run | Median of runs 2–7 | All seven runs |
|---|---|---|---|
| pwsh -NoProfile -c exit | 535.3ms | 386.8ms | 535.3 / 361.2 / 563.7 / 454.2 / 324.5 / 300.4 / 386.8 |
| powershell -NoProfile -c exit | 284.6ms | 212.2ms | 284.6 / 183.6 / 185.4 / 263.8 / 211.9 / 212.2 / 217.3 |
| python -c pass | 64.3ms | 58.0ms | 64.3 / 38.7 / 58.0 / 42.4 / 40.9 / 90.2 / 131.9 |
| node -e 0 | 110.8ms | 95.9ms | 110.8 / 135.8 / 80.3 / 84.4 / 94.4 / 100.5 / 95.9 |
| git --version | 106.9ms | 91.6ms | 106.9 / 80.4 / 97.8 / 58.9 / 91.6 / 104.3 / 71.9 |
pwsh ranged from 300.4 ms to 563.7 ms. The slowest run was 1.9 times the fastest, so deciding which one is faster from a single run would be risky. powershell.exe also moved from 183.6 ms to 284.6 ms, but its median still settled at 212.2 ms (after seeing this variation, seven runs no longer felt excessive).
The incidental Python, Node, and Git measurements were light for startup: Python 58.0 ms, Node 95.9 ms, and Git 91.6 ms. My impression that a PowerShell one-liner felt slightly heavy was not entirely imaginary (even short commands can have very different entry-point costs).
I got the median calculation wrong
The most dangerous part of this test was nearly trusting the first measurement script. I intended to measure three times and take the median, and wrote this:
$sorted = $ms | Sort-Object
$median = $sorted[[int]($n / 2)]
When $n is 3, 3 / 2 is 1.5. PowerShell's [int] uses banker's rounding, so 1.5 rounds to 2. In a three-element array, index 2 is the maximum value. I was silently selecting the worst case instead of the median.
The results looked heavier than they felt, which finally made me notice. I changed it to [math]::Floor() and increased the number of runs to seven; the table above is from that rerun. There was no error or warning, which makes this kind of bug particularly unpleasant (the answer still looks plausible).
Do not blame ARM64 for the slowness
pwsh starts the .NET runtime before it runs. My .NET SDK was 9.0.316, and dotnet --info reported RID win-arm64. The runtime itself was native, so it was difficult to call this an “ARM64 is slow” result.
The more natural explanation was a difference in PowerShell 7's startup structure. It is not unusual for pwsh startup to be heavier than Windows PowerShell 5.1 on x64 machines either, and the 386.8 ms versus 212.2 ms result looked like an extension of that difference. Still, seeing it on Windows on ARM64 matters for short automation.
For a script that runs once a day, this gap is almost irrelevant. But calling it 100 times a day from Task Scheduler or a small helper command adds about 17 seconds of waiting. At that point it is no longer only a feeling. Startup becomes a larger fraction of the total for shorter tasks, so shell choice can matter. For a long-running task the difference disappears into the body, so moving everything to powershell.exe based only on startup would also be wrong. Interactive shells, Task Scheduler jobs, and tools that invoke a shell internally need to be considered separately. The difference remains, but its meaning changes.
Separate interactive use from automation
I still use pwsh for interactive work. Completion, history, and the display behavior differ, and I did not want to move the shell I use every day back to Windows PowerShell 5.1. Paying 386.8 ms when opening it once is barely noticeable when the session stays open, and the wait is not apparent during actual interactive work. I had to separate interactive shells, Task Scheduler invocations, and shells called internally by other tools to avoid a bad decision.
For short scripts called many times, I moved toward powershell.exe. If the operation fits within 5.1, I choose the option whose startup is nearly half as long. When I reorganized automation at the end of July 2026, I used this rule to sort out places where pwsh and powershell.exe had been mixed. The same 386.8 ms means different things depending on whether the caller is Task Scheduler, another CLI helper, or an interactive shell kept open. Separate the use cases. Look only at the entry point. Measure, then decide.
This is only about startup. In my work so far, I have not found that pwsh is slower in the operation itself—loops, walking files, or calling an API. The difference appeared because I measured a command that does nothing but exit; it would be unreasonable to describe all daily work using only 212.2 ms and 386.8 ms.
The final takeaway is that rerunning the measurement was worthwhile. I questioned the first table because the numbers looked a little heavier than my experience. If I had left the median bug in place, I would have reported an exaggerated gap. Plausible-looking numbers deserve suspicion. I initially hesitated over which shell to choose, but I chose to fix the measurement first and then make the decision from the same procedure.