How to Restrict PowerShell on Windows
PowerShell is powerful - and that power makes it a favorite tool for bypassing restrictions and running attacks. Restricting it is more nuanced than disabling Command Prompt, because the setting most people reach for, execution policy, is not actually a security boundary. This guide explains how to restrict PowerShell properly with Constrained Language Mode and application control, and how to enforce it across a fleet.
Execution policy is not a security control
The most common mistake is trusting Set-ExecutionPolicy. It governs whether scripts run by default, but it is trivially bypassed - a user can paste commands interactively, pipe a script to PowerShell, or pass -ExecutionPolicy Bypass.
Microsoft is explicit that execution policy is a convenience feature, not a security boundary. Treat it as guardrails against accidents, not against a determined user.
The controls that actually restrict PowerShell
Real restriction combines language mode with application control.
- Constrained Language Mode - limits PowerShell to a safe subset, blocking risky APIs (enforced via AppLocker or WDAC)
- AppLocker or WDAC - deny rules that stop powershell.exe and powershell_ise.exe from running
- DisallowRun - a simpler per-user block on the PowerShell executables
- Remove Windows PowerShell 2.0 - the legacy engine can bypass newer protections
Don't forget the second executable
A frequent gap: people block powershell.exe but forget powershell_ise.exe (the ISE) and, on 64-bit systems, the separate 32-bit copy under SysWOW64. Miss one and the block is porous.
A managed agent blocks every PowerShell entry point, applies Constrained Language Mode where appropriate, and re-applies the policy after tampering - so the restriction holds instead of leaking through a forgotten binary.
Restrict PowerShell with app control and language mode
- Understand the goal - Decide whether to block PowerShell entirely or allow it in Constrained Language Mode. Do not rely on Set-ExecutionPolicy - it is not a security boundary.
- Block the executables - Use AppLocker (Enterprise/Education) or DisallowRun to deny powershell.exe and powershell_ise.exe, including the 32-bit copies under SysWOW64.
- Apply Constrained Language Mode - Where you need PowerShell but safely, enforce Constrained Language Mode through AppLocker or WDAC rather than the __PSLockdownPolicy environment variable, which is not tamper-proof.
- Remove PowerShell 2.0 - Disable the legacy Windows PowerShell 2.0 optional feature so it cannot be used to downgrade around your protections.
- Verify - Try to launch PowerShell and the ISE from every path. Confirm they are blocked or running in Constrained Language Mode as intended.
Frequently asked questions
Isn't setting the execution policy enough?
No. Execution policy is not a security boundary - it is easily bypassed with a flag or by pasting commands. Use application control and Constrained Language Mode instead.
What is Constrained Language Mode?
A PowerShell mode that restricts it to a safe subset of the language, blocking the risky APIs attackers rely on. It is enforced properly through AppLocker or WDAC.
Why do I need to block more than powershell.exe?
PowerShell has multiple entry points - the ISE and 32-bit copies under SysWOW64. Blocking only powershell.exe leaves those open as a bypass.
Should I remove PowerShell 2.0?
Yes. The legacy 2.0 engine can be used to sidestep newer protections like Constrained Language Mode, so disable that optional feature.
Restrict PowerShell the right way
CtrlOne blocks every PowerShell entry point and applies language-mode controls fleet-wide - enforced for all users and re-applied after tampering.