diff --git a/src/System.Management.Automation/engine/hostifaces/RunspacePoolInternal.cs b/src/System.Management.Automation/engine/hostifaces/RunspacePoolInternal.cs
index 35608783ae8..4b1096c40de 100644
--- a/src/System.Management.Automation/engine/hostifaces/RunspacePoolInternal.cs
+++ b/src/System.Management.Automation/engine/hostifaces/RunspacePoolInternal.cs
@@ -63,7 +63,6 @@ internal class RunspacePoolInternal
/// The explicit PSHost implementation.
///
///
- /// RunspaceConfiguration is null.
/// Host is null.
///
///
diff --git a/src/System.Management.Automation/security/SecurityManager.cs b/src/System.Management.Automation/security/SecurityManager.cs
index e4c79e2e72e..19dcfdbe13b 100644
--- a/src/System.Management.Automation/security/SecurityManager.cs
+++ b/src/System.Management.Automation/security/SecurityManager.cs
@@ -48,7 +48,7 @@ namespace Microsoft.PowerShell
/// Unrestricted - No files must be signed. If a file originates from the
/// internet, Monad provides a warning prompt to alert the user. To
/// suppress this warning message, right-click on the file in File Explorer,
- /// select "Properties," and then "Unblock."
+ /// select "Properties," and then "Unblock." Requires Shell.
/// Bypass - No files must be signed, and internet origin is not verified
///
///
@@ -136,10 +136,6 @@ private bool CheckPolicy(ExternalScriptInfo script, PSHost host, out Exception r
if (!IsSupportedExtension(fi.Extension))
return true;
- // Product binaries are always trusted
- if (SecuritySupport.IsProductBinary(path))
- return true;
-
// Get the execution policy
_executionPolicy = SecuritySupport.GetExecutionPolicy(_shellId);
@@ -189,6 +185,11 @@ private bool CheckPolicy(ExternalScriptInfo script, PSHost host, out Exception r
#endif
if (_executionPolicy == ExecutionPolicy.Unrestricted)
{
+ // Product binaries are always trusted
+ // This avoids signature and security zone checks
+ if (SecuritySupport.IsProductBinary(path))
+ return true;
+
// We need to give the "Remote File" warning
// if the file originated from the internet
if (!IsLocalFile(fi.FullName))
diff --git a/test/csharp/test_FileSystemProvider.cs b/test/csharp/test_FileSystemProvider.cs
index 5ad95a6daf5..78631251692 100644
--- a/test/csharp/test_FileSystemProvider.cs
+++ b/test/csharp/test_FileSystemProvider.cs
@@ -37,9 +37,8 @@ private ExecutionContext GetExecutionContext()
{
CultureInfo currentCulture = CultureInfo.CurrentCulture;
PSHost hostInterface = new DefaultHost(currentCulture,currentCulture);
- RunspaceConfiguration runspaceConfiguration = RunspaceConfiguration.Create();
InitialSessionState iss = InitialSessionState.CreateDefault2();
- AutomationEngine engine = new AutomationEngine(hostInterface, runspaceConfiguration, iss);
+ AutomationEngine engine = new AutomationEngine(hostInterface, iss);
ExecutionContext executionContext = new ExecutionContext(engine, hostInterface, iss);
return executionContext;
}
diff --git a/test/csharp/test_SessionState.cs b/test/csharp/test_SessionState.cs
index 7558c1b6789..eec20153772 100644
--- a/test/csharp/test_SessionState.cs
+++ b/test/csharp/test_SessionState.cs
@@ -20,9 +20,8 @@ public void TestDrives()
{
CultureInfo currentCulture = CultureInfo.CurrentCulture;
PSHost hostInterface = new DefaultHost(currentCulture,currentCulture);
- RunspaceConfiguration runspaceConfiguration = RunspaceConfiguration.Create();
InitialSessionState iss = InitialSessionState.CreateDefault2();
- AutomationEngine engine = new AutomationEngine(hostInterface, runspaceConfiguration, iss);
+ AutomationEngine engine = new AutomationEngine(hostInterface, iss);
ExecutionContext executionContext = new ExecutionContext(engine, hostInterface, iss);
SessionStateInternal sessionState = new SessionStateInternal(executionContext);
Collection drives = sessionState.Drives(null);
diff --git a/test/powershell/Installer/WindowsInstaller.Tests.ps1 b/test/powershell/Installer/WindowsInstaller.Tests.ps1
index 0084671ab66..759869784a5 100644
--- a/test/powershell/Installer/WindowsInstaller.Tests.ps1
+++ b/test/powershell/Installer/WindowsInstaller.Tests.ps1
@@ -9,13 +9,13 @@ Describe "Windows Installer" -Tags "Scenario" {
@{ Name = "WMF 5.1"; Url = "https://www.microsoft.com/download/details.aspx?id=54616" }
)
}
-
+
It "WiX (Windows Installer XML) file contains pre-requisites link $preRequisitesLink" {
$wixProductFile = Join-Path -Path $PSScriptRoot -ChildPath "..\..\..\assets\Product.wxs"
(Get-Content $wixProductFile -Raw).Contains($preRequisitesLink) | Should Be $true
}
- It "Pre-Requisistes link for '' is reachable" -TestCases $linkCheckTestCases -Test {
+ It "Pre-Requisistes link for '' is reachable: " -TestCases $linkCheckTestCases -Test {
param ($Url)
# Because an outdated link 'https://www.microsoft.com/download/details.aspx?id=504100000' would still return a 200 reponse (due to a redirection to an error page), it only checks that it returns something
diff --git a/test/powershell/Modules/Microsoft.PowerShell.Security/ExecutionPolicy.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Security/ExecutionPolicy.Tests.ps1
index 406f0fd2d0c..debe15d28aa 100644
--- a/test/powershell/Modules/Microsoft.PowerShell.Security/ExecutionPolicy.Tests.ps1
+++ b/test/powershell/Modules/Microsoft.PowerShell.Security/ExecutionPolicy.Tests.ps1
@@ -1,3 +1,4 @@
+Import-Module HelpersCommon
#
# These are general tests that verify non-Windows behavior
#
@@ -95,6 +96,8 @@ try {
$LocalSignatureCorruptedScript = Join-Path -Path $remoteTestDirectory -ChildPath LocalSignatureCorruptedScript.ps1
$LocalSignedScript = Join-Path -Path $remoteTestDirectory -ChildPath LocalSignedScript.ps1
$LocalUnsignedScript = Join-Path -Path $remoteTestDirectory -ChildPath LocalUnsignedScript.ps1
+ $PSHomeUnsignedModule = Join-Path -Path $PSHome -ChildPath 'Modules' -AdditionalChildPath 'LocalUnsignedModule', 'LocalUnsignedModule.psm1'
+ $PSHomeUntrustedModule = Join-Path -Path $PSHome -ChildPath 'Modules' -AdditionalChildPath 'LocalUntrustedModule', 'LocalUntrustedModule.psm1'
$TrustedSignatureCorruptedScript = Join-Path -Path $remoteTestDirectory -ChildPath TrustedSignatureCorruptedScript.ps1
$TrustedSignedScript = Join-Path -Path $remoteTestDirectory -ChildPath TrustedSignedScript.ps1
$TrustedUnsignedScript = Join-Path -Path $remoteTestDirectory -ChildPath TrustedUnsignedScript.ps1
@@ -169,6 +172,18 @@ try {
AddSignature = $false
Corrupted = $false
}
+ @{
+ FilePath = $PSHomeUnsignedModule
+ FileType = $fileType.Local
+ AddSignature = $false
+ Corrupted = $false
+ }
+ @{
+ FilePath = $PSHomeUntrustedModule
+ FileType = $fileType.Untrusted
+ AddSignature = $false
+ Corrupted = $false
+ }
@{
FilePath = $TrustedSignatureCorruptedScript
FileType = $fileType.Trusted
@@ -230,9 +245,11 @@ try {
function createTestFile
{
param (
+ [Parameter(Mandatory)]
[string]
$FilePath,
+ [Parameter(Mandatory)]
[int]
$FileType,
@@ -243,7 +260,14 @@ try {
$Corrupted
)
- $null = New-Item -Path $filePath -ItemType File
+ $folder = Split-Path -Path $FilePath
+ # create folder if it doesn't already exist
+ if(!(Test-Path $folder))
+ {
+ $null = New-Item -Path $folder -ItemType Directory
+ }
+
+ $null = New-Item -Path $filePath -ItemType File -Force
$content = "`"Hello`"" + "`r`n"
if($AddSignature)
@@ -460,6 +484,34 @@ ZoneId=$FileType
#Get Execution Policy
$originalExecPolicy = Get-ExecutionPolicy
$originalExecutionPolicy = $originalExecPolicy
+
+ $archiveSigned = $false
+ $archivePath = Get-Module -ListAvailable Microsoft.PowerShell.Archive -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Path
+ if($archivePath)
+ {
+ $archiveFolder = Split-Path -Path $archivePath
+
+ # get all the certs used to sign the module
+ $script:archiveAllCert = Get-ChildItem -File -Path (Join-Path -Path $archiveFolder -ChildPath '*') -Recurse |
+ Get-AuthenticodeSignature
+
+ # filter only to valid signatures
+ $script:archiveCert = $script:archiveAllCert |
+ Where-Object { $_.status -eq 'Valid'} |
+ Select-Object -Unique -ExpandProperty SignerCertificate
+
+ # if we have valid signatures, add them to trusted publishers so powershell will trust them.
+ if($script:archiveCert)
+ {
+ $store = [System.Security.Cryptography.X509Certificates.X509Store]::new([System.Security.Cryptography.X509Certificates.StoreName]::TrustedPublisher,[System.Security.Cryptography.X509Certificates.StoreLocation]::CurrentUser)
+ $store.Open([System.Security.Cryptography.X509Certificates.OpenFlags]::ReadWrite)
+ $archiveCert | ForEach-Object {
+ $store.Add($_)
+ }
+ $store.Close()
+ $archiveSigned = $true
+ }
+ }
}
}
AfterAll {
@@ -472,6 +524,15 @@ ZoneId=$FileType
}
}
+ Context "Prereq: Validate that 'Microsoft.PowerShell.Archive' is signed" {
+ It "'Microsoft.PowerShell.Archive' should have a signature" {
+ $script:archiveAllCert | should not be null
+ }
+ It "'Microsoft.PowerShell.Archive' should have a valid signature" {
+ $script:archiveCert | should not be null
+ }
+ }
+
Context "Validate that 'Restricted' execution policy works on OneCore powershell" {
BeforeAll {
@@ -598,6 +659,36 @@ ZoneId=$FileType
foreach($testScript in $testScripts) {
Test-UnrestrictedExecutionPolicy $testScript $expected
}
+
+ $error = "UnauthorizedAccess,Microsoft.PowerShell.Commands.ImportModuleCommand"
+ $testData = @(
+ @{
+ module = $PSHomeUntrustedModule
+ error = $null
+ }
+ @{
+ module = $PSHomeUnsignedModule
+ error = $null
+ }
+ @{
+ module = "Microsoft.PowerShell.Archive"
+ error = $null
+ }
+ )
+
+ $TestTypePrefix = "Test 'Unrestricted' execution policy."
+ It "$TestTypePrefix Importing Module should throw ''" -TestCases $testData {
+ param([string]$module, [string]$error)
+ $testScript = {Import-Module -Name $module -Force}
+ if($error)
+ {
+ $testScript | ShouldBeErrorId $error
+ }
+ else
+ {
+ $testScript | Should Not throw
+ }
+ }
}
Context "Validate that 'ByPass' execution policy works on OneCore powershell" {
@@ -813,102 +904,134 @@ ZoneId=$FileType
}
}
- function Test-AllSignedExecutionPolicy {
-
- param($testScript, $error)
-
- $TestTypePrefix = "Test 'AllSigned' execution policy."
-
- It "$TestTypePrefix Running $testScript script should return $error" {
+ $TestTypePrefix = "Test 'AllSigned' execution policy."
- $scriptName = $testScript
-
- $exception = $null
- try
- {
- & $scriptName
- }
- catch
- {
- $exception = $_
- }
- $errorType = $null
-
- if($null -ne $exception)
- {
- $errorType = $exception.exception.getType()
- }
-
- $result = $errorType
+ $error = "UnauthorizedAccess,Microsoft.PowerShell.Commands.ImportModuleCommand"
+ $testData = @(
+ @{
+ module = $PSHomeUntrustedModule
+ error = $error
+ }
+ @{
+ module = $PSHomeUnsignedModule
+ error = $error
+ }
+ @{
+ module = "Microsoft.PowerShell.Archive"
+ error = $null
+ }
+ )
- $result | Should be $error
+ It "$TestTypePrefix Importing Module should throw ''" -TestCases $testData {
+ param([string]$module, [string]$error)
+ $testScript = {Import-Module -Name $module -Force}
+ if($error)
+ {
+ $testScript | ShouldBeErrorId $error
+ }
+ else
+ {
+ $testScript | Should Not throw
}
}
- $error = "System.Management.Automation.PSSecurityException"
+
+ $error = "UnauthorizedAccess"
+ $pendingTestData = @(
+ # The following files are not signed correctly when generated, so we will skip for now
+ # filed https://github.com/PowerShell/PowerShell/issues/5559
+ @{
+ testScript = $MyComputerSignedScript
+ error = $null
+ }
+ @{
+ testScript = $UntrustedSignedScript
+ error = $null
+ }
+ @{
+ testScript = $TrustedSignedScript
+ error = $null
+ }
+ @{
+ testScript = $LocalSignedScript
+ error = $null
+ }
+ @{
+ testScript = $IntranetSignedScript
+ error = $null
+ }
+ @{
+ testScript = $InternetSignedScript
+ error = $null
+ }
+ )
+ It "$TestTypePrefix Running Script should throw ''" -TestCases $pendingTestData -Pending {}
+
$testData = @(
@{
- testScript = $LocalUnsignedScript
- expected = $null
+ testScript = $InternetSignatureCorruptedScript
error = $error
}
@{
- testScript = $LocalSignatureCorruptedScript
- expected = $null
+ testScript = $InternetUnsignedScript
error = $error
}
@{
- testScript = $MyComputerUnsignedScript
- expected = $null
+ testScript = $IntranetSignatureCorruptedScript
error = $error
}
@{
- testScript = $MyComputerSignatureCorruptedScript
- expected = $null
+ testScript = $IntranetSignatureCorruptedScript
error = $error
}
@{
- testScript = $TrustedUnsignedScript
- expected = $null
+ testScript = $IntranetUnsignedScript
error = $error
}
@{
- testScript = $TrustedSignatureCorruptedScript
- expected = $null
+ testScript = $LocalSignatureCorruptedScript
error = $error
}
@{
- testScript = $IntranetUnsignedScript
- expected = $null
+ testScript = $LocalUnsignedScript
error = $error
}
@{
- testScript = $IntranetSignatureCorruptedScript
- expected = $null
+ testScript = $TrustedSignatureCorruptedScript
error = $error
}
@{
- testScript = $InternetUnsignedScript
- expected = $null
+ testScript = $TrustedUnsignedScript
error = $error
}
@{
- testScript = $InternetSignatureCorruptedScript
- expected = $null
+ testScript = $UntrustedSignatureCorruptedScript
error = $error
}
@{
testScript = $UntrustedUnsignedScript
- expected = $null
error = $error
}
@{
- testScript = $UntrustedSignatureCorruptedScript
- expected = $null
+ testScript = $MyComputerSignatureCorruptedScript
+ error = $error
+ }
+ @{
+ testScript = $MyComputerUnsignedScript
error = $error
}
+
)
- foreach($testScript in $testScripts) {
- Test-AllSignedExecutionPolicy $testScript $error
+ It "$TestTypePrefix Running Script should throw ''" -TestCases $testData {
+ param([string]$testScript, [string]$error)
+ $testScript | should exist
+ if($error)
+ {
+ {& $testScript} | ShouldBeErrorId $error
+ }
+ else
+ {
+ {& $testScript} | Should Not throw
+ }
}
}
}