diff --git a/test/powershell/Modules/Microsoft.PowerShell.Security/ConstrainedLanguageRestriction.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Security/ConstrainedLanguageRestriction.Tests.ps1
new file mode 100644
index 000000000..bf13c8f2a
--- /dev/null
+++ b/test/powershell/Modules/Microsoft.PowerShell.Security/ConstrainedLanguageRestriction.Tests.ps1
@@ -0,0 +1,916 @@
+##
+## Tests for PowerShell system lock down and constrained language mode restrictions
+## These are Windows platform only tests
+##
+
+##
+## ----------
+## Test Note:
+## ----------
+## Since these tests change session and system state (constrained language and system lockdown)
+## they will all use try/finally blocks instead of Pester AfterEach/AfterAll to ensure session
+## and system state is restored.
+## Pester AfterEach, AfterAll is not reliable when the session is constrained language or locked down.
+##
+
+if ($IsWindows)
+{
+ $code = @'
+
+ #region Using directives
+
+ using System;
+ using System.Globalization;
+ using System.Reflection;
+ using System.Collections;
+ using System.Collections.Generic;
+ using System.IO;
+ using System.Security;
+ using System.Runtime.InteropServices;
+ using System.Threading;
+ using System.Management.Automation;
+
+ #endregion
+
+ /// Adds a new type to the Application Domain
+ [Cmdlet("Invoke", "LanguageModeTestingSupportCmdlet")]
+ public sealed class InvokeLanguageModeTestingSupportCmdlet : PSCmdlet
+ {
+ [Parameter()]
+ public SwitchParameter EnableFullLanguageMode
+ {
+ get { return enableFullLanguageMode; }
+ set { enableFullLanguageMode = value; }
+ }
+ private SwitchParameter enableFullLanguageMode;
+
+ [Parameter()]
+ public SwitchParameter EnableConstrainedLanguageMode
+ {
+ get { return enableConstrainedLanguageMode; }
+ set { enableConstrainedLanguageMode = value; }
+ }
+ private SwitchParameter enableConstrainedLanguageMode;
+
+ [Parameter()]
+ public SwitchParameter SetLockdownMode
+ {
+ get { return setLockdownMode; }
+ set { setLockdownMode = value; }
+ }
+ private SwitchParameter setLockdownMode;
+
+ [Parameter()]
+ public SwitchParameter RevertLockdownMode
+ {
+ get { return revertLockdownMode; }
+ set { revertLockdownMode = value; }
+ }
+ private SwitchParameter revertLockdownMode;
+
+ protected override void BeginProcessing()
+ {
+ if (enableFullLanguageMode)
+ {
+ SessionState.LanguageMode = PSLanguageMode.FullLanguage;
+ }
+
+ if (enableConstrainedLanguageMode)
+ {
+ SessionState.LanguageMode = PSLanguageMode.ConstrainedLanguage;
+ }
+
+ if (setLockdownMode)
+ {
+ Environment.SetEnvironmentVariable("__PSLockdownPolicy", "0x80000007", EnvironmentVariableTarget.Machine);
+ }
+
+ if (revertLockdownMode)
+ {
+ Environment.SetEnvironmentVariable("__PSLockdownPolicy", null, EnvironmentVariableTarget.Machine);
+ }
+ }
+ }
+'@
+
+ if (-not (Get-Command Invoke-LanguageModeTestingSupportCmdlet -ea Ignore))
+ {
+ $moduleName = Get-RandomFileName
+ $moduleDirectory = join-path $TestDrive\Modules $moduleName
+ if (-not (Test-Path $moduleDirectory))
+ {
+ $null = New-Item -ItemType Directory $moduleDirectory -Force
+ }
+
+ try
+ {
+ Add-Type -TypeDefinition $code -OutputAssembly $moduleDirectory\TestCmdletForConstrainedLanguage.dll -ErrorAction Ignore
+ } catch {}
+
+ Import-Module -Name $moduleDirectory\TestCmdletForConstrainedLanguage.dll
+ }
+} # end if ($IsWindows)
+
+try
+{
+ $defaultParamValues = $PSDefaultParameterValues
+ $PSDefaultParameterValues["it:Skip"] = !$IsWindows
+
+ Describe "Built-ins work within constrained language" -Tags 'Feature','RequireAdminOnWindows' {
+
+ BeforeAll {
+ $TestCasesBuiltIn = @(
+ @{testName = "Verify built-in function"; scriptblock = { Get-Verb } }
+ @{testName = "Verify built-in error variable"; scriptblock = { Write-Error SomeError -ErrorVariable ErrorOutput -ErrorAction SilentlyContinue; $ErrorOutput} }
+ )
+ }
+
+ It "" -TestCases $TestCasesBuiltIn {
+
+ param ($scriptblock)
+
+ try
+ {
+ Invoke-LanguageModeTestingSupportCmdlet -EnableConstrainedLanguageMode
+
+ $result = (& $scriptblock)
+ }
+ finally
+ {
+ Invoke-LanguageModeTestingSupportCmdlet -EnableFullLanguageMode
+ }
+
+ $result.Count | Should BeGreaterThan 0
+ }
+ }
+
+ Describe "Background jobs" -Tags 'Feature','RequireAdminOnWindows' {
+
+ Context "Background jobs in system lock down mode" {
+
+ # TODO
+ # Test is pending because PowerShell Core currently stubs out Windows system lockdown APIs
+ It "Verifies that background jobs in system lockdown mode run in constrained language" -Pending {
+
+ try
+ {
+ Invoke-LanguageModeTestingSupportCmdlet -SetLockdownMode
+
+ $job = Start-Job -ScriptBlock { [object]::Equals("A", "B") } | Wait-Job
+ $expectedError = $job.ChildJobs[0].Error
+ $job | Remove-Job
+ }
+ finally
+ {
+ Invoke-LanguageModeTestingSupportCmdlet -RevertLockdownMode
+ }
+
+ $expectedError.FullyQualifiedErrorId | Should Match "MethodInvocationNotSupportedInConstrainedLanguage"
+ }
+ }
+
+ Context "Background jobs within inconsistent mode" {
+
+ It "Verifies that background job is denied when mode is inconsistent" {
+
+ try
+ {
+ Invoke-LanguageModeTestingSupportCmdlet -EnableConstrainedLanguageMode
+
+ Start-Job { [object]::Equals("A", "B") }
+ throw "No Exception!"
+ }
+ catch
+ {
+ $exception = $_
+ }
+ finally
+ {
+ Invoke-LanguageModeTestingSupportCmdlet -EnableFullLanguageMode
+ }
+
+ $exception.FullyQualifiedErrorId | Should Match "CannotStartJobInconsistentLanguageMode"
+ }
+ }
+ }
+
+ Describe "Add-Type in constrained language" -Tags 'Feature','RequireAdminOnWindows' {
+
+ It "Verifies Add-Type fails in constrained language mode" {
+
+ try
+ {
+ Invoke-LanguageModeTestingSupportCmdlet -EnableConstrainedLanguageMode
+
+ Add-Type -TypeDefinition 'public class ConstrainedLanguageTest { public static string Hello = "HelloConstrained"; }'
+ throw "No Exception!"
+ }
+ catch
+ {
+ $exception = $_
+ }
+ finally
+ {
+ Invoke-LanguageModeTestingSupportCmdlet -EnableFullLanguageMode
+ }
+
+ $exception.FullyQualifiedErrorId | Should Match "CannotDefineNewType"
+ }
+
+ It "Verifies Add-Type works back in full language mode again" {
+ Add-Type -TypeDefinition 'public class AfterFullLanguageTest { public static string Hello = "HelloAfter"; }'
+ [AfterFullLanguageTest]::Hello | Should Be "HelloAfter"
+ }
+ }
+
+ Describe "New-Object in constrained language" -Tags 'Feature','RequireAdminOnWindows' {
+
+ Context "New-Object with dotNet types" {
+
+ It "Verifies New-Object works in constrained language of allowed string type" {
+
+ try
+ {
+ Invoke-LanguageModeTestingSupportCmdlet -EnableConstrainedLanguageMode
+
+ $resultString = New-Object System.String "Hello"
+ }
+ finally
+ {
+ Invoke-LanguageModeTestingSupportCmdlet -EnableFullLanguageMode
+ }
+
+ $resultString | Should Be "Hello"
+ }
+
+ It "Verifies New-Object throws error in constrained language for disallowed IntPtr type" {
+
+ try
+ {
+ Invoke-LanguageModeTestingSupportCmdlet -EnableConstrainedLanguageMode
+
+ New-Object System.IntPtr 1234
+ throw "No Exception!"
+ }
+ catch
+ {
+ $exception = $_
+ }
+ finally
+ {
+ Invoke-LanguageModeTestingSupportCmdlet -EnableFullLanguageMode
+ }
+
+ $exception.FullyQualifiedErrorId | Should Match "CannotCreateTypeConstrainedLanguage"
+ }
+
+ It "Verifies New-Object works for IntPtr type back in full language mode again" {
+
+ New-Object System.IntPtr 1234 | Should Be 1234
+ }
+ }
+
+ Context "New-Object with COM types" {
+
+ # TODO
+ # Test is pending because PowerShell Core currently stubs out Windows system lockdown APIs
+ It "Verifies New-Object with COM types is disallowed in system lock down" -Pending {
+
+ try
+ {
+ Invoke-LanguageModeTestingSupportCmdlet -SetLockdownMode -EnableConstrainedLanguageMode
+
+ New-Object -Com ADODB.Parameter
+ throw "No Exception!"
+ }
+ catch
+ {
+ $exception = $_
+ }
+ finally
+ {
+ Invoke-LanguageModeTestingSupportCmdlet -RevertLockdownMode -EnableFullLanguageMode
+ }
+
+ $exception.FullyQualifiedErrorId | Should Match "CannotCreateComTypeConstrainedLanguage"
+ }
+
+ It "Verifies New-Object with COM types works back in full language mode again" {
+
+ $result = New-Object -ComObject ADODB.Parameter
+ $result.Direction | Should Be 1
+ }
+ }
+ }
+
+ Describe "New-Item command on function drive in constrained language" -Tags 'Feature','RequireAdminOnWindows' {
+
+ It "Verifies New-Item directory on function drive is not allowed in constrained language mode" {
+
+ try
+ {
+ Invoke-LanguageModeTestingSupportCmdlet -EnableConstrainedLanguageMode
+
+ $null = New-Item -Path function:\SomeEvilFunction -ItemType Directory -Value SomeBadScriptBlock -ErrorAction Stop
+ throw "No Exception!"
+ }
+ catch
+ {
+ $exception = $_
+ }
+ finally
+ {
+ Invoke-LanguageModeTestingSupportCmdlet -EnableFullLanguageMode
+ }
+
+ $exception.FullyQualifiedErrorId | Should Match "NotSupported"
+ }
+ }
+
+ Describe "Script debugging in constrained language" -Tags 'Feature','RequireAdminOnWindows' {
+
+ It "Verifies that a debugging breakpoint cannot be set in constrained language and no system lockdown" {
+
+ try
+ {
+ Invoke-LanguageModeTestingSupportCmdlet -EnableConstrainedLanguageMode
+
+ function MyDebuggerFunction {}
+ Set-PSBreakpoint -Command MyDebuggerFunction
+ throw "No Exception!"
+ }
+ catch
+ {
+ $exception = $_
+ }
+ finally
+ {
+ Invoke-LanguageModeTestingSupportCmdlet -EnableFullLanguageMode
+ }
+
+ $exception.FullyQualifiedErrorId | Should Match "CannotSetBreakpointInconsistentLanguageMode"
+ }
+
+ # TODO
+ # Test is pending because PowerShell Core currently stubs out Windows system lockdown APIs
+ It "Verifies that a debugging breakpoint can be set in constrained language with system lockdown" -Pending {
+
+ try
+ {
+ Invoke-LanguageModeTestingSupportCmdlet -SetLockdownMode -EnableConstrainedLanguageMode
+
+ function MyDebuggerFunction2 {}
+ $Global:DebuggingOk = $null
+ $null = Set-PSBreakpoint -Command MyDebuggerFunction2 -Action { $Global:DebuggingOk = "DebuggingOk" }
+ MyDebuggerFunction2
+ }
+ finally
+ {
+ Invoke-LanguageModeTestingSupportCmdlet -RevertLockdownMode -EnableFullLanguageMode
+ }
+
+ $Global:DebuggingOk | Should Be "DebuggingOk"
+ }
+
+ # TODO
+ # Test is pending because PowerShell Core currently stubs out Windows system lockdown APIs
+ It "Verifies that debugger commands do not run in full language mode when system is locked down" -Pending {
+
+ try
+ {
+ Invoke-LanguageModeTestingSupportCmdlet -SetLockdownMode -EnableConstrainedLanguageMode
+
+ function MyDebuggerFunction3 {}
+ $null = Set-PSBreakpoint -Command MyDebuggerFunction3 -Action { $Global:dbgResult = [object]::Equals("A", "B") }
+
+ $restoreEAPreference = $ErrorActionPreference
+ $ErrorActionPreference = "Stop"
+ MyDebuggerFunction3
+ throw "No Exception!"
+ }
+ catch
+ {
+ $exception = $_
+ }
+ finally
+ {
+ if ($restoreEAPreference -ne $null) { $ErrorActionPreference = $restoreEAPreference }
+ Invoke-LanguageModeTestingSupportCmdlet -RevertLockdownMode -EnableFullLanguageMode
+ }
+
+ $exception.FullyQualifiedErrorId | Should Match "MethodInvocationNotSupportedInConstrainedLanguage"
+ }
+
+ # TODO
+ # Test is pending because PowerShell Core currently stubs out Windows system lockdown APIs
+ It "Verifies that debugger command injection is blocked in system lock down" -Pending {
+
+ $trustedScriptContent = @'
+ function Trusted
+ {
+ param ($UserInput)
+
+ Add-Type -TypeDefinition $UserInput
+ try { $null = New-Object safe_738057 -ErrorAction Ignore } catch {}
+ try { $null = New-Object pwnd_738057 -ErrorAction Ignore } catch {}
+ }
+
+ Trusted -UserInput 'public class safe_738057 { public safe_738057() { System.Environment.SetEnvironmentVariable("pwnd_738057", "False"); } }'
+
+ "Hello World"
+'@
+ $trustedFile = Join-Path $TestDrive CommandInjectionDebuggingBlocked_System32.ps1
+
+ try
+ {
+ Invoke-LanguageModeTestingSupportCmdlet -SetLockdownMode -EnableConstrainedLanguageMode
+
+ Set-Content $trustedScriptContent -Path $trustedFile
+ $env:pwnd_738057 = "False"
+ Set-PSBreakpoint -Script $trustedFile -Line 12 -Action { Trusted -UserInput 'public class pwnd_738057 { public pwnd_738057() { System.Environment.SetEnvironmentVariable("pwnd_738057", "Pwnd"); } }' }
+ & trustedFile
+ }
+ finally
+ {
+ Invoke-LanguageModeTestingSupportCmdlet -RevertLockdownMode -EnableFullLanguageMode
+ }
+
+ $env:pwnd_738057 | Should Not Be "Pwnd"
+ }
+ }
+
+ Describe "Engine events in constrained language mode" -Tags 'Feature','RequireAdminOnWindows' {
+
+ It "Verifies engine event in constrained language mode, its action runs as constrained" {
+
+ try
+ {
+ Invoke-LanguageModeTestingSupportCmdlet -EnableConstrainedLanguageMode
+
+ $job = Register-EngineEvent LockdownEvent -Action { [object]::Equals("A", "B") }
+ $null = New-Event LockdownEvent
+ Wait-Job $job
+ Unregister-Event LockdownEvent
+ }
+ finally
+ {
+ Invoke-LanguageModeTestingSupportCmdlet -EnableFullLanguageMode
+ }
+
+ $job.Error.FullyQualifiedErrorId | Should Match "MethodInvocationNotSupportedInConstrainedLanguage"
+ }
+ }
+
+ Describe "Module scope scripts in constrained language mode" -Tags 'Feature','RequireAdminOnWindows' {
+
+ It "Verifies that while in constrained language mode script run in a module scope also runs constrained" {
+ Import-Module PSDiagnostics
+ $module = Get-Module PSDiagnostics
+
+ try
+ {
+ Invoke-LanguageModeTestingSupportCmdlet -EnableConstrainedLanguageMode
+
+ & $module { [object]::Equals("A", "B") }
+ throw "No Exception!"
+ }
+ catch
+ {
+ $exception = $_
+ }
+ finally
+ {
+ Invoke-LanguageModeTestingSupportCmdlet -EnableFullLanguageMode
+ }
+
+ $exception.FullyQualifiedErrorId | Should Match "MethodInvocationNotSupportedInConstrainedLanguage"
+ }
+ }
+
+ Describe "Switch -file in constrained language mode" -Tags 'Feature','RequireAdminOnWindows' {
+
+ It "Verifies that switch -file will not work in constrained language without provider" {
+
+ [initialsessionstate] $iss = [initialsessionstate]::Create()
+ $iss.LanguageMode = "ConstrainedLanguage"
+ [runspace] $rs = [runspacefactory]::CreateRunspace($iss)
+ $rs.Open()
+ $pl = $rs.CreatePipeline("switch -file $testDrive/foo.txt { 'A' { 'B' } }")
+
+ try
+ {
+ $pl.Invoke()
+ throw "No Exception!"
+ }
+ catch
+ {
+ $exception = $_
+ }
+ finally
+ {
+ $rs.Dispose()
+ }
+
+ $exception.FullyQualifiedErrorId | Should Match "DriveNotFoundException"
+ }
+ }
+
+ Describe "Get content syntax in constrained language mode" -Tags 'Feature','RequireAdminOnWindows' {
+
+ It "Verifies that the get content syntax returns null value in constrained language without provider" {
+
+ $iss = [initialsessionstate]::Create()
+ $iss.LanguageMode = "ConstrainedLanguage"
+ $rs = [runspacefactory]::CreateRunspace($iss)
+ $rs.Open()
+ $pl = $rs.CreatePipeline('${' + "$testDrive/foo.txt}")
+
+ $result = $pl.Invoke()
+ $rs.Dispose()
+
+ $result[0] | Should BeNullOrEmpty
+ }
+ }
+
+ Describe "Stream redirection in constrained language mode" -Tags 'Feature','RequireAdminOnWindows' {
+
+ It "Verifies that stream redirection doesn't work in constrained language mode without provider" {
+
+ $iss = [initialsessionstate]::CreateDefault2()
+ $iss.Providers.Clear()
+ $iss.LanguageMode = "ConstrainedLanguage"
+ $rs = [runspacefactory]::CreateRunspace($iss)
+ $rs.Open()
+ $pl = $rs.CreatePipeline('"Hello" > c:\temp\foo.txt')
+
+ try
+ {
+ $pl.Invoke()
+ throw "No Exception!"
+ }
+ catch
+ {
+ $exception = $_
+ }
+ finally
+ {
+ $rs.Dispose()
+ }
+
+ $exception.FullyQualifiedErrorId | Should Match "CmdletInvocationException"
+ }
+ }
+
+ Describe "Invoke-Expression in constrained language mode" -Tags 'Feature','RequireAdminOnWindows' {
+
+ BeforeAll {
+
+ function VulnerableFunctionFromFullLanguage { Invoke-Expression $Args[0] }
+
+ $TestCasesIEX = @(
+ @{testName = "Verifies direct Invoke-Expression does not bypass constrained language mode";
+ scriptblock = { Invoke-Expression '[object]::Equals("A", "B")' } }
+ @{testName = "Verifies indirect Invoke-Expression does not bypass constrained language mode";
+ scriptblock = { VulnerableFunctionFromFullLanguage '[object]::Equals("A", "B")' } }
+ )
+ }
+
+ It "" -TestCases $TestCasesIEX {
+
+ param ($scriptblock)
+
+ try
+ {
+ Invoke-LanguageModeTestingSupportCmdlet -EnableConstrainedLanguageMode
+
+ & $scriptblock
+ throw 'No Exception!'
+ }
+ catch
+ {
+ $exception = $_
+ }
+ finally
+ {
+ Invoke-LanguageModeTestingSupportCmdlet -EnableFullLanguageMode
+ }
+
+ $exception.FullyQualifiedErrorId | Should Match "MethodInvocationNotSupportedInConstrainedLanguage"
+ }
+ }
+
+ Describe "Dynamic method invocation in constrained language mode" -Tags 'Feature','RequireAdminOnWindows' {
+
+ It "Verifies dynamic method invocation does not bypass constrained language mode" {
+
+ try
+ {
+ Invoke-LanguageModeTestingSupportCmdlet -EnableConstrainedLanguageMode
+
+ $type = [IO.Path]
+ $method = "GetRandomFileName"
+ $type::$method()
+ throw 'No Exception!'
+ }
+ catch
+ {
+ $exception = $_
+ }
+ finally
+ {
+ Invoke-LanguageModeTestingSupportCmdlet -EnableFullLanguageMode
+ }
+
+ $exception.FullyQualifiedErrorId | Should Match "MethodInvocationNotSupportedInConstrainedLanguage"
+ }
+
+ It "Verifies dynamic methods invocation does not bypass constrained language mode" {
+
+ try
+ {
+ Invoke-LanguageModeTestingSupportCmdlet -EnableConstrainedLanguageMode
+
+ $type = [IO.Path]
+ $methods = "GetRandomFileName","GetTempPath"
+ $type::($methods[0])()
+ throw 'No Exception!'
+ }
+ catch
+ {
+ $exception = $_
+ }
+ finally
+ {
+ Invoke-LanguageModeTestingSupportCmdlet -EnableFullLanguageMode
+ }
+
+ $exception.FullyQualifiedErrorId | Should Match "MethodInvocationNotSupportedInConstrainedLanguage"
+ }
+ }
+
+ Describe "Tab expansion in constrained language mode" -Tags 'Feature','RequireAdminOnWindows' {
+
+ It "Verifies that tab expansion cannot convert disallowed IntPtr type" {
+
+ try
+ {
+ Invoke-LanguageModeTestingSupportCmdlet -EnableConstrainedLanguageMode
+
+ $result = @(TabExpansion2 '(1234 -as [IntPtr]).' 20 | % CompletionMatches | ? CompletionText -Match Pointer)
+ }
+ finally
+ {
+ Invoke-LanguageModeTestingSupportCmdlet -EnableFullLanguageMode
+ }
+
+ $result.Count | Should Be 0
+ }
+ }
+
+ Describe "Variable AllScope in constrained language mode" -Tags 'Feature','RequireAdminOnWindows' {
+
+ It "Verifies Set-Variable cannot create AllScope in constrained language" {
+
+ try
+ {
+ Invoke-LanguageModeTestingSupportCmdlet -EnableConstrainedLanguageMode
+
+ Set-Variable -Name SetVariableAllScopeNotSupported -Value bar -Option AllScope
+ throw "No Exception!"
+ }
+ catch
+ {
+ $exception = $_
+ }
+ finally
+ {
+ Invoke-LanguageModeTestingSupportCmdlet -EnableFullLanguageMode
+ }
+
+ $exception.FullyQualifiedErrorId | Should Match "NotSupported"
+ }
+
+ It "Verifies New-Variable cannot create AllScope in constrained language" {
+
+ try
+ {
+ Invoke-LanguageModeTestingSupportCmdlet -EnableConstrainedLanguageMode
+
+ New-Variable -Name NewVarialbeAllScopeNotSupported -Value bar -Option AllScope
+ throw "No Exception!"
+ }
+ catch
+ {
+ $exception = $_
+ }
+ finally
+ {
+ Invoke-LanguageModeTestingSupportCmdlet -EnableFullLanguageMode
+ }
+
+ $exception.FullyQualifiedErrorId | Should Match "NotSupported"
+ }
+ }
+
+ Describe "Data section additional commands in constrained language" -Tags 'Feature','RequireAdminOnWindows' {
+
+ function InvokeDataSectionConstrained
+ {
+ try
+ {
+ Invoke-Expression 'data foo -SupportedCommand Add-Type { Add-Type }'
+ throw "No Exception!"
+ }
+ catch
+ {
+ $exception = $_
+ }
+
+ return $exception
+ }
+
+ It "Verifies data section Add-Type additional command is disallowed in constrained language" {
+
+ try
+ {
+ Invoke-LanguageModeTestingSupportCmdlet -EnableConstrainedLanguageMode
+
+ $exception1 = InvokeDataSectionConstrained
+ # Repeat to make sure the first time properly restored the language mode to constrained.
+ $exception2 = InvokeDataSectionConstrained
+ }
+ finally
+ {
+ Invoke-LanguageModeTestingSupportCmdlet -EnableFullLanguageMode
+ }
+
+ $exception1.FullyQualifiedErrorId | Should Match "DataSectionAllowedCommandDisallowed"
+ $exception2.FullyQualifiedErrorId | Should Match "DataSectionAllowedCommandDisallowed"
+ }
+
+ It "Verifies data section with no-constant expression Add-Type additional command is disallowed in constrained language" {
+
+ try
+ {
+ Invoke-LanguageModeTestingSupportCmdlet -EnableConstrainedLanguageMode
+
+ $addedCommand = "Add-Type"
+ Invoke-Expression 'data foo -SupportedCommand $addedCommand { Add-Type }'
+ throw "No Exception!"
+ }
+ catch
+ {
+ $exception = $_
+ }
+ finally
+ {
+ Invoke-LanguageModeTestingSupportCmdlet -EnableFullLanguageMode
+ }
+
+ $exception.FullyQualifiedErrorId | Should Match "DataSectionAllowedCommandDisallowed"
+ }
+ }
+
+ Describe "Import-LocalizedData additional commands in constrained language" -Tags 'Feature','RequireAdminOnWindows' {
+
+ It "Verifies Import-LocalizedData disallows Add-Type in constrained language" {
+
+ try
+ {
+ Invoke-LanguageModeTestingSupportCmdlet -EnableConstrainedLanguageMode
+
+ $localizedDataFileName = Join-Path $TestDrive ImportLocalizedDataAdditionalCommandsNotSupported.psd1
+ $null = New-Item -ItemType File -Path $localizedDataFileName -Force
+ Import-LocalizedData -SupportedCommand Add-Type -BaseDirectory $TestDrive -FileName ImportLocalizedDataAdditionalCommandsNotSupported
+ throw "No Exception!"
+ }
+ catch
+ {
+ $exception = $_
+ }
+ finally
+ {
+ Invoke-LanguageModeTestingSupportCmdlet -EnableFullLanguageMode
+ }
+
+ $exception.FullyQualifiedErrorId | Should Match "CannotDefineSupportedCommand"
+ }
+ }
+
+ Describe "Where and Foreach operators should not allow unapproved types in constrained language" -Tags 'Feature','RequireAdminOnWindows' {
+
+ BeforeAll {
+
+ $script1 = @'
+ $data = @(
+ @{
+ Node = "first"
+ Value1 = 1
+ Value2 = 2
+ first = $true
+ }
+ @{
+ Node = "second"
+ Value1 = 3
+ Value2 = 4
+ Second = $true
+ }
+ @{
+ Node = "third"
+ Value1 = 5
+ Value2 = 6
+ third = $true
+ }
+ )
+
+ $result = $data.where{$_.Node -eq "second"}
+ Write-Output $result
+
+ # Execute method in scriptblock of where operator, should throw in ConstrainedLanguage mode.
+ $data.where{[system.io.path]::GetRandomFileName() -eq "Hello"}
+'@
+
+ $script2 = @'
+ $data = @(
+ @{
+ Node = "first"
+ Value1 = 1
+ Value2 = 2
+ first = $true
+ }
+ @{
+ Node = "second"
+ Value1 = 3
+ Value2 = 4
+ Second = $true
+ }
+ @{
+ Node = "third"
+ Value1 = 5
+ Value2 = 6
+ third = $true
+ }
+ )
+
+ $result = $data.foreach('value1')
+ Write-Output $result
+
+ # Execute method in scriptblock of foreach operator, should throw in ConstrainedLanguage mode.
+ $data.foreach{[system.io.path]::GetRandomFileName().Length}
+'@
+
+ $script3 = @'
+ # Method call should throw error.
+ (Get-Process powershell*).Foreach('GetHashCode')
+'@
+
+ $script4 = @'
+ # Where method call should throw error.
+ (get-process powershell).where{$_.GetType().FullName -match "process"}
+'@
+
+ $TestCasesForeach = @(
+ @{testName = "Verify where statement with invalid method call in constrained language is disallowed"; script = $script1 }
+ @{testName = "Verify foreach statement with invalid method call in constrained language is disallowed"; script = $script2 }
+ @{testName = "Verify foreach statement with embedded method call in constrained language is disallowed"; script = $script3 }
+ @{testName = "Verify where statement with embedded method call in constrained language is disallowed"; script = $script4 }
+ )
+ }
+
+ It "" -TestCases $TestCasesForeach {
+
+ param (
+ [string] $script
+ )
+
+ try
+ {
+ Invoke-LanguageModeTestingSupportCmdlet -EnableConstrainedLanguageMode
+
+ # Scriptblock must be created inside constrained language.
+ $sb = [scriptblock]::Create($script)
+ & sb
+ throw "No Exception!"
+ }
+ catch
+ {
+ $exception = $_
+ }
+ finally
+ {
+ Invoke-LanguageModeTestingSupportCmdlet -EnableFullLanguageMode
+ }
+
+ $exception.FullyQualifiedErrorId | Should Match "MethodInvocationNotSupportedInConstrainedLanguage"
+ }
+ }
+
+ # End Describe blocks
+}
+finally
+{
+ if ($defaultParamValues -ne $null)
+ {
+ $Global:PSDefaultParameterValues = $defaultParamValues
+ }
+}
diff --git a/test/tools/Modules/HelpersCommon/HelpersCommon.psd1 b/test/tools/Modules/HelpersCommon/HelpersCommon.psd1
index fbc067114..b5c57ce46 100644
--- a/test/tools/Modules/HelpersCommon/HelpersCommon.psd1
+++ b/test/tools/Modules/HelpersCommon/HelpersCommon.psd1
@@ -16,6 +16,5 @@ Copyright = 'Copyright (C) Microsoft Corporation, All rights reserved.'
Description = 'Temporary module contains functions for using in tests'
-FunctionsToExport = 'Wait-UntilTrue', 'Test-IsElevated', 'ShouldBeErrorId', 'Wait-FileToBePresent'
-
+FunctionsToExport = 'Wait-UntilTrue', 'Test-IsElevated', 'ShouldBeErrorId', 'Wait-FileToBePresent', 'Get-RandomFileName'
}
diff --git a/test/tools/Modules/HelpersCommon/HelpersCommon.psm1 b/test/tools/Modules/HelpersCommon/HelpersCommon.psm1
index 74e441b00..7adb1e0d3 100644
--- a/test/tools/Modules/HelpersCommon/HelpersCommon.psm1
+++ b/test/tools/Modules/HelpersCommon/HelpersCommon.psm1
@@ -78,3 +78,7 @@ function ShouldBeErrorId
}
}
+function Get-RandomFileName
+{
+ [System.IO.Path]::GetFileNameWithoutExtension([IO.Path]::GetRandomFileName())
+}