Added WindowsPS version check for WinCompat (#11148)

This commit is contained in:
Andrew
2019-12-10 10:40:13 -08:00
committed by Aditya Patwardhan
parent 9649a85ce9
commit 0c46e3e71d
5 changed files with 82 additions and 4 deletions
@@ -1881,13 +1881,22 @@ namespace Microsoft.PowerShell.Commands
internal override IList<PSModuleInfo> ImportModulesUsingWinCompat(IEnumerable<string> moduleNames, IEnumerable<ModuleSpecification> moduleFullyQualifiedNames, ImportModuleOptions importModuleOptions)
{
IList<PSModuleInfo> moduleProxyList = new List<PSModuleInfo>();
#if !UNIX
var winPSVersionString = Utils.GetWindowsPowerShellVersionFromRegistry();
if (!winPSVersionString.StartsWith("5.1", StringComparison.OrdinalIgnoreCase))
{
string errorMessage = string.Format(CultureInfo.InvariantCulture, Modules.WinCompatRequredVersionError, winPSVersionString);
throw new InvalidOperationException(errorMessage);
}
PSSession WindowsPowerShellCompatRemotingSession = CreateWindowsPowerShellCompatResources();
if (WindowsPowerShellCompatRemotingSession == null)
{
return new List<PSModuleInfo>();
}
var moduleProxyList = ImportModule_RemotelyViaPsrpSession(importModuleOptions, moduleNames, moduleFullyQualifiedNames, WindowsPowerShellCompatRemotingSession, usingWinCompat: true);
moduleProxyList = ImportModule_RemotelyViaPsrpSession(importModuleOptions, moduleNames, moduleFullyQualifiedNames, WindowsPowerShellCompatRemotingSession, usingWinCompat: true);
foreach(PSModuleInfo moduleProxy in moduleProxyList)
{
moduleProxy.IsWindowsPowerShellCompatModule = true;
@@ -1896,7 +1905,7 @@ namespace Microsoft.PowerShell.Commands
string message = StringUtil.Format(Modules.WinCompatModuleWarning, moduleProxy.Name, WindowsPowerShellCompatRemotingSession.Name);
WriteWarning(message);
}
#endif
return moduleProxyList;
}
@@ -446,6 +446,41 @@ namespace System.Management.Automation
return null;
}
private static string s_windowsPowerShellVersion = null;
/// <summary>
/// Get the Windows PowerShell version from registry.
/// </summary>
/// <returns>
/// String of Windows PowerShell version from registry.
/// </returns>
internal static string GetWindowsPowerShellVersionFromRegistry()
{
if (!string.IsNullOrEmpty(InternalTestHooks.TestWindowsPowerShellVersionString))
{
return InternalTestHooks.TestWindowsPowerShellVersionString;
}
if (s_windowsPowerShellVersion != null)
{
return s_windowsPowerShellVersion;
}
string engineKeyPath = RegistryStrings.MonadRootKeyPath + "\\" +
PSVersionInfo.RegistryVersionKey + "\\" + RegistryStrings.MonadEngineKey;
using (RegistryKey engineKey = Registry.LocalMachine.OpenSubKey(engineKeyPath))
{
if (engineKey != null)
{
s_windowsPowerShellVersion = engineKey.GetValue(RegistryStrings.MonadEngine_MonadVersion) as string;
return s_windowsPowerShellVersion;
}
}
return string.Empty;
}
#endif
internal static string DefaultPowerShellAppBase => GetApplicationBase(DefaultPowerShellShellID);
@@ -2036,6 +2071,9 @@ namespace System.Management.Automation.Internal
// since we can't manipulate the System32 directory in a test
internal static string TestWindowsPowerShellPSHomeLocation;
// A version of Windows PS that is installed on the system; normally this is retrieved from a reg key that is write-protected.
internal static string TestWindowsPowerShellVersionString;
internal static bool ShowMarkdownOutputBypass;
/// <summary>This member is used for internal test purposes.</summary>
@@ -1160,8 +1160,9 @@ namespace Microsoft.PowerShell.Commands
NewProcessConnectionInfo connectionInfo = new NewProcessConnectionInfo(this.Credential);
connectionInfo.AuthenticationMechanism = this.Authentication;
#if !UNIX
connectionInfo.PSVersion = new Version(5, 1);
#endif
var typeTable = TypeTable.LoadDefaultTypeFiles();
string runspaceName = GetRunspaceName(0, out int runspaceIdUnused);
remoteRunspaces.Add(RunspaceFactory.CreateRunspace(connectionInfo: connectionInfo,
@@ -513,6 +513,9 @@
<data name="WinCompatModuleWarning" xml:space="preserve">
<value>Module {0} is loaded in Windows PowerShell using {1} remoting session; please note that all input and output of commands from this module will be deserialized objects. If you want to load this module into PowerShell Core please use 'Import-Module -SkipEditionCheck' syntax.</value>
</data>
<data name="WinCompatRequredVersionError" xml:space="preserve">
<value>Detected Windows PowerShell version {0}. Windows PowerShell 5.1 is required to load modules using Windows PowerShell compatibility feature. Install Windows Management Framework (WMF) 5.1 from https://aka.ms/WMF5Download to enable this feature.</value>
</data>
<data name="PsModuleOverCimSessionError" xml:space="preserve">
<value>The module {0} cannot be imported over a CimSession. Try using the PSSession parameter of the Import-Module cmdlet.</value>
</data>
@@ -246,7 +246,16 @@ Describe "Import-Module from CompatiblePSEditions-checked paths" -Tag "CI" {
New-TestModules -TestCases $successCases -BaseDir $basePath
New-TestModules -TestCases $failCases -BaseDir $basePath
$allModules = ($successCases + $failCases).ModuleName
$allCases = $successCases + $failCases
$allModules = $allCases.ModuleName
$versionTestCases = @()
foreach($versionString in @('1.0','2.0','3.0','4.0','5.0','5.1','5.1.14393.0'))
{
foreach($case in $allCases)
{
$versionTestCases += $case + @{WinPSVersion = $versionString}
}
}
# make sure there are no ImplicitRemoting leftovers from previous tests
Get-Module | Where-Object {$_.PrivateData.ImplicitRemoting} | Remove-Module -Force
@@ -300,6 +309,24 @@ Describe "Import-Module from CompatiblePSEditions-checked paths" -Tag "CI" {
Import-Module $ModuleName -UseWindowsPowerShell -Force
& "Test-${ModuleName}PSEdition" | Should -Be 'Desktop'
}
It "WinCompat works only with Windows PS 5.1 (when PSEdition <Editions> and WinPSVersion <WinPSVersion>)" -TestCases $versionTestCases -Skip:(-not $IsWindows) {
param($Editions, $ModuleName, $Result, $WinPSVersion)
try {
[System.Management.Automation.Internal.InternalTestHooks]::SetTestHook("TestWindowsPowerShellVersionString", $WinPSVersion)
if ($WinPSVersion.StartsWith('5.1')) {
Import-Module $ModuleName -UseWindowsPowerShell -Force
& "Test-${ModuleName}PSEdition" | Should -Be 'Desktop'
}
else {
{ Import-Module $ModuleName -UseWindowsPowerShell -Force } | Should -Throw -ErrorId "InvalidOperationException"
}
}
finally {
[System.Management.Automation.Internal.InternalTestHooks]::SetTestHook("TestWindowsPowerShellVersionString", $null)
}
}
}
Context "Imports from absolute path" {