Improve security with PowerShell’s constrained language mode

History has conclusively demonstrated that cyberattackers will take advantage of any perceived weakness in a system in order to gain access to a system. Although some have downplayed the idea that PowerShell can be used as a tool for attacking a system, there have been quite a few documented instances of attackers doing just that. Since PowerShell can sometimes be of interest to those who have bad intent, it is a good idea to harden PowerShell whenever possible in an effort to prevent it from being exploited. One option for doing so is to enable constrained language mode within your PowerShell sessions.

What is constrained language mode?

So what is the constrained language mode? Simply put, the mode is a tool that can be used to limit the types of commands that can be executed within a PowerShell session. Let me give you a really simple example.

If you look at the figure below, you can see that I have opened two separate PowerShell windows. The top window is completely normal. As you can see, I entered a mathematical expression into this window. This expression asks for the square root of 64. PowerShell returned a value of 8, which is the correct answer. The figure’s lower PowerShell window has the constrained language mode enabled. I entered exactly the same mathematical expression into this window, but received an error message telling me that PowerShell was unable to invoke the method.

OK, so what’s really going on here? How come the command failed in one window, but succeeded in another? The simple explanation is that constrained language mode allows you to continue using basic PowerShell cmdlets but blocks commands that can be used to interact with various APIs. The reason why the mathematical expression shown in the previous figure produced an error is because I was attempting to use .NET. Had I entered a simpler expression such as 2+2, the operation would have been allowed.

There is a long list of items that PowerShell either limits or blocks when constrained language mode is enabled. I won’t bore you with the full list, but some of the more noteworthy items include:

• COM objects
• Unapproved .NET types
• XAML based workflows
• PowerShell classes

Setting PowerShell’s constrained language mode

If you want to determine which language mode PowerShell is currently using, enter this command:


As you can see in the screenshot below, PowerShell is set to use full language mode, which means that constrained language mode is not enabled.

If you decide that you want to enable constrained delegation, you can do so by using a variation of the command shown above. Simply enter the command as before, but append =”ConstrainedLanguage”. The full command looks like this:

$ExecutionContext.SessionState.LanguageMode = "ConstrainedLanguage"

You can see what a switch from full language to constrained language looks like in the screenshot below.

PowerShell’s Achilles’ heel

The problem with using constrained delegation as a security feature is that depending on how it is implemented, it can be relatively easy for an attacker to get around it. The reason for this is that PowerShell’s language mode is session specific. Let me show you what I mean.

If you look at the screenshot below, you can see that I have two PowerShell windows open. I set the language mode of the window on the left to Constrained Language. I then verified the language mode to make sure that PowerShell really had been properly set to use constrained language. Next, I opened up the window on the right and checked PowerShell’s language mode. The PowerShell session running in that window is using full language, even though the session within the window on the left remains limited to using constrained language. In other words, if an attacker wants to gain access to the full language, then they need only to open another PowerShell session.

Two problems

Although constrained language mode can improve security, its use presents two big problems. First, as previously noted, constrained language mode is easy to circumvent because it is session specific. If an attacker wants to avoid constrained language mode, they can simply launch a new PowerShell session.

The second problem with using constrained language mode is that it can break your existing PowerShell scripts. I showed you an example earlier of a mathematical expression that could not be evaluated because doing so required the use of .NET. Just imagine if that expression had been a part of a script.

The trick to making the use of constrained language practical is to accept the idea that constrained language mode is not designed to be used by itself. Instead, constrained language mode is designed to be used in conjunction with Device Guard User Mode Code Integrity (UMCI).

For those who might not be familiar with UMCI, it is a tool that allows administrators to set policies describing the code that is allowed to run on the system. Because Device Guard runs on a system wide basis, it is ideal for enforcing the use of constrained language mode. An attacker will not be able to circumvent constrained language mode by opening a new PowerShell session, because Device Guard policies apply to the system as a whole, not solely to the current PowerShell session.

A powerful tool

Constrained language mode can be a very powerful tool for locking down PowerShell in an effort to prevent it from being used for nefarious purposes. Even so, it is completely ineffective by itself, because an attacker could bypass it by launching another PowerShell session, or simply disable it by entering a single command. In spite of its weaknesses however, constrained language mode can greatly enhance PowerShell’s security when it is used in conjunction with Device Guard User Mode Code Integrity.

Featured image: Shutterstock

Brien Posey

Brien Posey is a freelance technology author and speaker with over two decades of IT experience. Prior to going freelance, Brien was a CIO for a national chain of hospitals and healthcare facilities. He has also served as a network engineer for the United States Department of Defense at Fort Knox. In addition, Brien has worked as a network administrator for some of the largest insurance companies in America. To date, Brien has received Microsoft’s MVP award numerous times in categories including Windows Server, IIS, Exchange Server, and File Systems / Storage. You can visit Brien’s Website at:

Published by
Brien Posey
Tags Powershell

Recent Posts

Will IPv6 ever kill IPv4? If so, when?

IPv6 and its vast pool of Internet address spaces has long been expected to kill off IPv4. But the old…

16 hours ago

Another tool for your toolbox: Using Capacity Planner for Hyper-V Replica

For those who use the Hyper-V replica feature, a tool from Microsoft can help you analyze the infrastructure required to…

20 hours ago

Create a Log Analytics query without using your keyboard (No experience necessary!)

Never created a query in Log Analytics? It’s easy. In the case shown here, it’s so easy you don’t need…

23 hours ago

Can I have your attention: Add PowerShell on-screen alerts to your scripts

While there is no native command for pop-up messages in PowerShell, you can generate PowerShell on-screen alerts and pop-up boxes…

2 days ago

How spammers harvest email addresses — and what you can do about it

Spammers are pretty smart and have thought up many ingenious ways of getting hold of your email address. Is there…

2 days ago

How to create an Azure disaster recovery site using Azure Site Recovery

Here’s how to replicate an application running in one of the Azure regions to another region with just a few…

2 days ago