{
	"id": "f5cb5b6d-aa1a-4d75-b548-5fe1d18a55dd",
	"created_at": "2026-04-06T03:36:52.115522Z",
	"updated_at": "2026-04-10T03:35:21.416893Z",
	"deleted_at": null,
	"sha1_hash": "481854c410738f5cce0504f4a015575d752b3cd7",
	"title": "PowerShell Constrained Language Mode",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 97696,
	"plain_text": "PowerShell Constrained Language Mode\r\nBy PowerShell Team\r\nPublished: 2017-11-02 · Archived: 2026-04-06 03:25:14 UTC\r\nPowerShell Constrained Language Mode\r\nUpdate (May 17, 2018)\r\nIn addition to the constraints listed in this article, system wide Constrained Language mode now also disables the\r\nScheduledJob module. The ScheduledJob feature uses Dot Net serialization that is vulnerable to deserialization\r\nattacks. So now whenever an application whitelisting solution is applied such as DeviceGuard or AppLocker,\r\nPowerShell will run in Constrained Language mode and also disable the ScheduledJob module. Use the Windows\r\nTask Scheduler or PowerShell ScheduledTasks module as an alternative. For more information see CVE-2018-\r\n0958.\r\nWhat is PowerShell Constrained Language?\r\nPowerShell Constrained Language is a language mode of PowerShell designed to support day-to-day\r\nadministrative tasks, yet restrict access to sensitive language elements that can be used to invoke arbitrary\r\nWindows APIs.\r\nYou can place a PowerShell session into Constrained Language mode simply by setting a property:\r\nPS C:\\\u003e $ExecutionContext.SessionState.LanguageMode\r\nFullLanguage\r\nPS C:\\\u003e $ExecutionContext.SessionState.LanguageMode = \"ConstrainedLanguage\"\r\nPS C:\\\u003e $ExecutionContext.SessionState.LanguageMode\r\nConstrainedLanguage\r\nPS C:\\\u003e [System.Console]::WriteLine(\"Hello\")\r\nCannot invoke method. Method invocation is supported only on core types in this language mode.\r\nAt line:1 char:1\r\n+ [System.Console]::WriteLine(\"Hello\")\r\n+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r\n + CategoryInfo : InvalidOperation: (:) [], RuntimeException\r\n + FullyQualifiedErrorId : MethodInvocationNotSupportedInConstrainedLanguage\r\nOf course, this is not secure. A user can simply start another PowerShell session which will run in Full Language\r\nmode and have full access to PowerShell features. As part of the implementation of Constrained Language,\r\nPowerShell included an environment variable for debugging and unit testing called __PSLockdownPolicy . While\r\nwe have never documented this, some have discovered it and described this as an enforcement mechanism. This is\r\nhttps://devblogs.microsoft.com/powershell/powershell-constrained-language-mode/\r\nPage 1 of 5\n\nunwise because an attacker can easily change the environment variable to remove this enforcement. In addition,\r\nthere are also file naming conventions that enable FullLanguage mode on a script, effectively bypassing\r\nConstrained Language. Again, this is for unit testing. These test hooks cannot override a Device Guard UMCI\r\npolicy and can only be used when no policy enforcement is applied.\r\nThen what is it for?\r\nPowerShell Constrained Language mode was designed to work with system-wide application control solutions\r\nsuch as Device Guard User Mode Code Integrity (UMCI). Application control solutions are an incredibly effective\r\nway to drastically reduce the risk of viruses, ransomware, and unapproved software. For DeviceGuard UMCI the\r\napproved applications are determined via a UMCI policy. PowerShell automatically detects when a UMCI policy\r\nis being enforced on a system and will run only in Constrained Language mode. So PowerShell Constrained\r\nLanguage mode becomes more interesting when working in conjunction with system-wide lockdown policies.\r\nPowerShell’s detection of system policy enforcement through DeviceGuard is supported only for Windows\r\nplatform running Windows PowerShell version 5.1 or PowerShell 7. It does not work on non-Windows platforms.\r\nSo this is currently very much a Windows security feature. However, we will continue to enhance this for non-Windows platforms where feasible.\r\nThese lockdown policies are important for high-value systems that need to be protected against malicious\r\nadministrators or compromised administrator credentials. With a policy enforced even administrators are limited\r\nto what they can do on the system.\r\nSince Constrained Language is so limited, you will find that many of the approved scripts that you use for\r\nadvanced systems management no longer work. The solution to this is simple: add these scripts (or more\r\neffectively: your code signing authority that signed them) to your Device Guard policy. This will allow your\r\napproved scripts to run in Full Language mode.\r\nFor example, all PowerShell module files shipped with Windows (e.g., Install-WindowsFeature) are trusted and\r\nsigned. The UMCI policy allowing signed Windows files lets PowerShell run these modules in Full Language\r\nmode. But if you create a custom PowerShell module that is not allowed by the policy then it will be considered\r\nuntrusted and run with Constrained Language restrictions.\r\nConsequently, any PowerShell module marked as trusted in the policy needs to be carefully reviewed for security\r\nvulnerabilities. A vulnerability could allow code injection, or leak private functions not intended for public use. In\r\neither case it could allow a user to run arbitrary code in Full Language mode, thus bypassing the system policy\r\nprotections.\r\nWe have described these dangers in much more detail in our post, “Writing Secure PowerShell Scripts” (coming\r\nsoon).\r\nWhat does Constrained Language constrain?\r\nConstrained Language consists of a number of restrictions that limit unconstrained code execution on a locked-down system. These restrictions are:\r\nhttps://devblogs.microsoft.com/powershell/powershell-constrained-language-mode/\r\nPage 2 of 5\n\nPowerShell module script files must explicitly export functions by name without the use of wildcard\r\ncharacters. This is to prevent inadvertently exposing powerful helper function not meant to be used\r\npublicly.\r\nPowerShell module manifest files must explicitly export functions by name without the use of wildcards.\r\nAgain, to prevent inadvertent exposure of functions.\r\nCOM objects are blocked. They can expose Win32 APIs that have likely never been rigorously hardened as\r\npart of an attack surface.\r\nOnly approved .NET types are allowed. Many .NET types can be used to invoke arbitrary Win32 APIs. As\r\na result only specific whitelisted types are allowed.\r\nAdd-Type is blocked. It allows the creation of arbitrary types defined in different languages.\r\nThe use of PowerShell classes are disallowed. PowerShell classes are just arbitrary C# type definitions.\r\nPowerShell type conversion is not allowed. Type conversion implicitly creates types and runs type\r\nconstructors.\r\nDot sourcing across language modes is disallowed. Dot sourcing a script file brings all functions, variables,\r\naliases from that script into the current scope. So this blocks a trusted script from being dot sourced into an\r\nuntrusted script and exposing all of its internal functions. Similarly, an untrusted script is prevented from\r\nbeing dot sourced into a trusted script so that it cannot pollute the trusted scope.\r\nCommand resolution automatically hides commands you cannot run. For example, a function created in\r\nConstrained Language mode is not visible to script running in Full Language mode.\r\nXAML based workflows are blocked since they cannot be constrained by PowerShell. But script based\r\nworkflows and trusted XAML based workflows shipped in-box are allowed.\r\nThe SupportedCommand parameter for Import-LocalizedData is disabled. It allows additional commands\r\nprevented by Constrained Language.\r\nInvoke-Expression cmdlet always runs in Constrained Language. Invoke-Expression cannot validate input\r\nas trusted.\r\nSet-PSBreakpoint command is blocked unless there is a system-wide lockdown through UMCI.\r\nCommand completers are always run in Constrained Language. Command completers are not validated as\r\ntrustworthy.\r\nCommands and script run within the script debugger will always be run in Constrained Language if there is\r\na system-wide lockdown.\r\nThe DSC Configuration keyword is disabled.\r\nSupported commands and Statements are not allowed in script DATA sections.\r\nStart-Job is unavailable if the system is not locked-down. Start-Job starts PowerShell in a new process and\r\nif the system is not locked-down the new process runs in Full Language mode.\r\nAs we can see, Constrained Language mode imposes some significant restrictions on PowerShell. Nevertheless, it\r\nremains a formidable and capable shell and scripting language. You can run native commands and PowerShell\r\ncmdlets and you have access to the full scripting features: variables, statements, loops, functions, arrays,\r\nhashtables, error handling, etc.\r\nHow is this different from JEA?\r\nhttps://devblogs.microsoft.com/powershell/powershell-constrained-language-mode/\r\nPage 3 of 5\n\nPowerShell Constrained Language restricts only some elements of the PowerShell language along with access to\r\nWin32 APIs. It provides full shell access to all native commands and many cmdlets. It is not designed to operate\r\nindependently and needs to work with application control solutions such as UMCI to fully lockdown a system and\r\nprevent access to unauthorized applications. Its purpose is to provide PowerShell on a locked-down system\r\nwithout compromising the system.\r\nJEA (Just Enough Administration) is a sandboxed PowerShell remote session that is designed to strictly limit what\r\nthe logged on user can do. It is configured in ‘no language mode’, has no access to file or other drive providers,\r\nand makes only a small set of cmdlets available. These cmdlets are often custom and designed to perform specific\r\nmanagement functions without giving unfettered access to the system. The set of cmdlets provided in the session\r\nis role based (RBAC) and the session can be run in virtual or Group Managed Service accounts.\r\nThe JEA scenario is where an administrator needs to perform a management task on a high-value machine (such\r\nas collect logs or restart a specific service). The administrator creates a remote PowerShell session to the\r\nmachine’s JEA endpoint. Within that session the user has access to only those commands needed to perform the\r\ntask and cannot directly access the file system or the registry or run arbitrary code.\r\nSummary\r\nPowerShell Constrained Language is designed to work with application whitelisting solutions in order to restrict\r\nwhat can be accessed in an interactive PowerShell session with policy enforcement. You configure which scripts\r\nare allowed full system access through the whitelisting solution policy. In contrast, JEA is a sandboxed\r\nPowerShell remote session that restricts an interactive session to specific commands based on user role.\r\nPaul Higinbotham [MSFT] PowerShell Team\r\nCategory\r\nAuthor\r\nPowerShell Team\r\nPowerShell is a task-based command-line shell and scripting language built on .NET. PowerShell helps system\r\nadministrators and power-users rapidly automate tasks that manage operating systems (Linux, macOS, and\r\nWindows) and processes.\r\nhttps://devblogs.microsoft.com/powershell/powershell-constrained-language-mode/\r\nPage 4 of 5\n\nSource: https://devblogs.microsoft.com/powershell/powershell-constrained-language-mode/\r\nhttps://devblogs.microsoft.com/powershell/powershell-constrained-language-mode/\r\nPage 5 of 5",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"MITRE"
	],
	"references": [
		"https://devblogs.microsoft.com/powershell/powershell-constrained-language-mode/"
	],
	"report_names": [
		"powershell-constrained-language-mode"
	],
	"threat_actors": [
		{
			"id": "2864e40a-f233-4618-ac61-b03760a41cbb",
			"created_at": "2023-12-01T02:02:34.272108Z",
			"updated_at": "2026-04-10T02:00:04.97558Z",
			"deleted_at": null,
			"main_name": "WildCard",
			"aliases": [],
			"source_name": "ETDA:WildCard",
			"tools": [
				"RustDown",
				"SysJoker"
			],
			"source_id": "ETDA",
			"reports": null
		},
		{
			"id": "256a6a2d-e8a2-4497-b399-628a7fad4b3e",
			"created_at": "2023-11-30T02:00:07.299845Z",
			"updated_at": "2026-04-10T02:00:03.484788Z",
			"deleted_at": null,
			"main_name": "WildCard",
			"aliases": [],
			"source_name": "MISPGALAXY:WildCard",
			"tools": [],
			"source_id": "MISPGALAXY",
			"reports": null
		}
	],
	"ts_created_at": 1775446612,
	"ts_updated_at": 1775792121,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/481854c410738f5cce0504f4a015575d752b3cd7.pdf",
		"text": "https://archive.orkl.eu/481854c410738f5cce0504f4a015575d752b3cd7.txt",
		"img": "https://archive.orkl.eu/481854c410738f5cce0504f4a015575d752b3cd7.jpg"
	}
}