diff --git a/PowerShellGitHubDev.psm1 b/PowerShellGitHubDev.psm1 index 1b6605fcd1..02fbfb3e5c 100644 --- a/PowerShellGitHubDev.psm1 +++ b/PowerShellGitHubDev.psm1 @@ -506,6 +506,26 @@ function Send-GitDiffToSd { } } +function Start-ResGen +{ + @("Microsoft.PowerShell.Commands.Management", +"Microsoft.PowerShell.Commands.Utility", +"Microsoft.PowerShell.ConsoleHost", +"Microsoft.PowerShell.CoreCLR.Eventing", +"Microsoft.PowerShell.Security", +"System.Management.Automation") | % { + $module = $_ + ls "$PSScriptRoot/src/$module/resources" | % { + $className = $_.Name.Replace('.resx', '') + $xml = [xml](cat -raw $_.FullName) + $genSource = Get-StronglyTypeCsFileForResx -xml $xml -ModuleName $module -ClassName $className + $outPath = "$PSScriptRoot/src/windows-build/gen/$module/$className.cs" + log "ResGen for $outPath" + Set-Content -Encoding Ascii -Path "$PSScriptRoot/src/windows-build/gen/$module/$className.cs" -Value $genSource + } + } +} + function script:log([string]$message) { Write-Host -Foreground Green $message @@ -570,3 +590,91 @@ function script:Convert-PSObjectToHashtable { } } } + + +function script:Get-StronglyTypeCsFileForResx +{ + param($xml, $ModuleName, $ClassName) +$body = @' +//------------------------------------------------------------------------------ +// +// This code was generated by a Start-ResGen funciton from PowerShellGitHubDev.psm1. +// To add or remove a member, edit your .ResX file then rerun Start-ResGen. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +using System; +using System.Reflection; + +/// +/// A strongly-typed resource class, for looking up localized strings, etc. +/// +[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] +[global::System.Diagnostics.DebuggerNonUserCodeAttribute()] +[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + +internal class {0} {{ + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal {0}() {{ + }} + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager {{ + get {{ + if (object.ReferenceEquals(resourceMan, null)) {{ + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("{1}.resources.{0}", typeof({0}).GetTypeInfo().Assembly); + resourceMan = temp; + }} + return resourceMan; + }} + }} + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture {{ + get {{ + return resourceCulture; + }} + set {{ + resourceCulture = value; + }} + }} + {2} +}} +'@ + + $entry = @' + + /// + /// Looks up a localized string similar to {1} + /// + internal static string {0} {{ + get {{ + return ResourceManager.GetString("{0}", resourceCulture); + }} + }} +'@ + $entries = $xml.root.data | % { + if ($_) { + $val = $_.value.Replace("`n", "`n ///") + $name = $_.name.Replace(' ', '_') + $entry -f $name,$val + } + } | Out-String + $body -f $ClassName,$ModuleName,$entries +} + diff --git a/mapping.json b/mapping.json index 2f4ed00680..b6a47c2c86 100644 --- a/mapping.json +++ b/mapping.json @@ -1137,10 +1137,10 @@ "src/monad/monad/src/engine/resources/Logging.resx": "src/System.Management.Automation/resources/Logging.resx", "src/monad/monad/src/engine/resources/Metadata.resx": "src/System.Management.Automation/resources/Metadata.resx", "src/monad/monad/src/engine/resources/MiniShellErrors.resx": "src/System.Management.Automation/resources/MiniShellErrors.resx", - "src/monad/monad/src/engine/resources/modules.resx": "src/System.Management.Automation/resources/modules.resx", + "src/monad/monad/src/engine/resources/modules.resx": "src/System.Management.Automation/resources/Modules.resx", "src/monad/monad/src/engine/resources/MshHostRawUserInterfaceStrings.resx": "src/System.Management.Automation/resources/MshHostRawUserInterfaceStrings.resx", "src/monad/monad/src/engine/resources/MshSignature.resx": "src/System.Management.Automation/resources/MshSignature.resx", - "src/monad/monad/src/engine/resources/MshSnapinCmdletResources.resx": "src/System.Management.Automation/resources/MshSnapinCmdletResources.resx", + "src/monad/monad/src/engine/resources/MshSnapinCmdletResources.resx": "src/System.Management.Automation/resources/MshSnapInCmdletResources.resx", "src/monad/monad/src/engine/resources/MshSnapinInfo.resx": "src/System.Management.Automation/resources/MshSnapinInfo.resx", "src/monad/monad/src/engine/resources/NativeCP.resx": "src/System.Management.Automation/resources/NativeCP.resx", "src/monad/monad/src/engine/resources/ParameterBinderStrings.resx": "src/System.Management.Automation/resources/ParameterBinderStrings.resx", @@ -1155,7 +1155,7 @@ "src/monad/monad/src/engine/resources/PSDataBufferStrings.resx": "src/System.Management.Automation/resources/PSDataBufferStrings.resx", "src/monad/monad/src/engine/resources/PSListModifierStrings.resx": "src/System.Management.Automation/resources/PSListModifierStrings.resx", "src/monad/monad/src/engine/resources/RegistryProviderStrings.resx": "src/System.Management.Automation/resources/RegistryProviderStrings.resx", - "src/monad/monad/src/engine/resources/remotingerroridstrings.resx": "src/System.Management.Automation/resources/remotingerroridstrings.resx", + "src/monad/monad/src/engine/resources/remotingerroridstrings.resx": "src/System.Management.Automation/resources/RemotingErrorIdStrings.resx", "src/monad/monad/src/engine/resources/RunspaceInit.resx": "src/System.Management.Automation/resources/RunspaceInit.resx", "src/monad/monad/src/engine/resources/RunspacePoolStrings.resx": "src/System.Management.Automation/resources/RunspacePoolStrings.resx", "src/monad/monad/src/engine/resources/RunspaceStrings.resx": "src/System.Management.Automation/resources/RunspaceStrings.resx", diff --git a/src/Microsoft.PowerShell.Commands.Management/project.json b/src/Microsoft.PowerShell.Commands.Management/project.json index 7e20c7dbe2..c2b5201acd 100644 --- a/src/Microsoft.PowerShell.Commands.Management/project.json +++ b/src/Microsoft.PowerShell.Commands.Management/project.json @@ -36,5 +36,5 @@ } }, - "compile": [ "../windows-build/gen/COMMANDS_MANAGEMENT/*.cs" ] + "compile": [ "../windows-build/gen/Microsoft.PowerShell.Commands.Management/*.cs" ] } diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ImplicitRemotingCommands.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ImplicitRemotingCommands.cs index 59107f1a8d..d24ce82ecc 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ImplicitRemotingCommands.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ImplicitRemotingCommands.cs @@ -2507,21 +2507,25 @@ function Get-PSImplicitRemotingSession // index 0 - "-VMId " (VMId is used instead of VMName due to its uniqueness) // index 1 - VM credential + // index 2 - "-ConfigurationName " or empty string private const string NewVMRunspaceTemplate = @" $( & $script:NewPSSession ` {0} ` {1} ` + {2} ` ) "; // index 0 - "-ContainerId " (ContainerId is used instead of ContainerName due to its uniqueness) // index 1 - "-RunAsAdministrator" or empty string + // index 2 - "-ConfigurationName " or empty string private const string NewContainerRunspaceTemplate = @" $( & $script:NewPSSession ` {0} ` {1} ` + {2} ` ) "; @@ -2530,22 +2534,26 @@ function Get-PSImplicitRemotingSession VMConnectionInfo vmConnectionInfo = this.remoteRunspaceInfo.Runspace.ConnectionInfo as VMConnectionInfo; if (vmConnectionInfo != null) { + string vmConfigurationName = vmConnectionInfo.ConfigurationName; return string.Format( CultureInfo.InvariantCulture, NewVMRunspaceTemplate, /* 0 */ this.GenerateConnectionStringForNewRunspace(), - /* 1 */ this.GenerateCredentialParameter()); + /* 1 */ this.GenerateCredentialParameter(), + /* 2 */ String.IsNullOrEmpty(vmConfigurationName) ? String.Empty : String.Concat("-ConfigurationName ", vmConfigurationName)); } else { ContainerConnectionInfo containerConnectionInfo = this.remoteRunspaceInfo.Runspace.ConnectionInfo as ContainerConnectionInfo; if (containerConnectionInfo != null) { + string containerConfigurationName = containerConnectionInfo.ContainerProc.ConfigurationName; return string.Format( CultureInfo.InvariantCulture, NewContainerRunspaceTemplate, /* 0 */ this.GenerateConnectionStringForNewRunspace(), - /* 1 */ containerConnectionInfo.ContainerProc.RunAsAdmin ? "-RunAsAdministrator" : string.Empty); + /* 1 */ containerConnectionInfo.ContainerProc.RunAsAdmin ? "-RunAsAdministrator" : string.Empty, + /* 2 */ String.IsNullOrEmpty(containerConfigurationName) ? String.Empty : String.Concat("-ConfigurationName ", containerConfigurationName)); } else { diff --git a/src/Microsoft.PowerShell.Commands.Utility/project.json b/src/Microsoft.PowerShell.Commands.Utility/project.json index 4de41175b9..77e6525e14 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/project.json +++ b/src/Microsoft.PowerShell.Commands.Utility/project.json @@ -44,5 +44,5 @@ } }, - "compile": [ "../windows-build/gen/COMMANDS_UTILITY/*.cs" ] + "compile": [ "../windows-build/gen/Microsoft.PowerShell.Commands.Utility/*.cs" ] } diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs index a96e11cc33..44e5801972 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs @@ -239,7 +239,7 @@ namespace Microsoft.PowerShell else if (cpp.NamedPipeServerMode) { ClrFacade.StartProfileOptimization("StartupProfileData-NamedPipeServerMode"); - System.Management.Automation.Remoting.RemoteSessionNamedPipeServer.RunServerMode(); + System.Management.Automation.Remoting.RemoteSessionNamedPipeServer.RunServerMode(cpp.ConfigurationName); exitCode = 0; } else if (cpp.SocketServerMode) diff --git a/src/Microsoft.PowerShell.ConsoleHost/project.json b/src/Microsoft.PowerShell.ConsoleHost/project.json index 999371d722..76a1494a5d 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/project.json +++ b/src/Microsoft.PowerShell.ConsoleHost/project.json @@ -26,6 +26,6 @@ }, "compile": [ - "../windows-build/gen/CONSOLE_HOST/*.cs" + "../windows-build/gen/Microsoft.PowerShell.ConsoleHost/*.cs" ] } diff --git a/src/Microsoft.PowerShell.CoreCLR.Eventing/project.json b/src/Microsoft.PowerShell.CoreCLR.Eventing/project.json index 8d2b9d3595..5948cbf144 100644 --- a/src/Microsoft.PowerShell.CoreCLR.Eventing/project.json +++ b/src/Microsoft.PowerShell.CoreCLR.Eventing/project.json @@ -31,5 +31,5 @@ } }, - "compile": [ "../windows-build/gen/CORECLR_EVENTING/*.cs" ] + "compile": [ "../windows-build/gen/Microsoft.PowerShell.CoreCLR.Eventing/*.cs" ] } diff --git a/src/Microsoft.PowerShell.Security/project.json b/src/Microsoft.PowerShell.Security/project.json index eac75ae00d..bf6fd2486b 100644 --- a/src/Microsoft.PowerShell.Security/project.json +++ b/src/Microsoft.PowerShell.Security/project.json @@ -23,5 +23,5 @@ } }, - "compile": [ "../windows-build/gen/SECURITY/*.cs" ] + "compile": [ "../windows-build/gen/Microsoft.PowerShell.Security/*.cs" ] } diff --git a/src/System.Management.Automation/DscSupport/CimDSCParser.cs b/src/System.Management.Automation/DscSupport/CimDSCParser.cs index b781215aed..84700b601d 100644 --- a/src/System.Management.Automation/DscSupport/CimDSCParser.cs +++ b/src/System.Management.Automation/DscSupport/CimDSCParser.cs @@ -999,6 +999,25 @@ namespace Microsoft.PowerShell.DesiredStateConfiguration.Internal return ClassCache.Values.ToList(); } + /// + /// Find cached cim classes defined under specified module + /// + /// + /// List of cached cim classes + public static List GetCachedClassesForModule(PSModuleInfo module) + { + List cachedClasses = new List(); + var moduleQualifiedName = String.Format(CultureInfo.InvariantCulture, "{0}\\{1}", module.Name, module.Version.ToString()); + foreach (var pair in ClassCache) + { + if(pair.Key.StartsWith(moduleQualifiedName, StringComparison.OrdinalIgnoreCase)) + { + cachedClasses.Add(pair.Value.Item2); + } + } + return cachedClasses; + } + /// /// Get the file that defined this class. /// @@ -1189,7 +1208,8 @@ namespace Microsoft.PowerShell.DesiredStateConfiguration.Internal if (!CacheResourcesFromMultipleModuleVersions && DynamicKeyword.ContainsKeyword(keyword.Keyword)) { var oldKeyword = DynamicKeyword.GetKeyword(keyword.Keyword); - if (!oldKeyword.ImplementingModule.Equals(moduleName, StringComparison.OrdinalIgnoreCase) || oldKeyword.ImplementingModuleVersion != moduleVersion) + if (oldKeyword.ImplementingModule == null || + !oldKeyword.ImplementingModule.Equals(moduleName, StringComparison.OrdinalIgnoreCase) || oldKeyword.ImplementingModuleVersion != moduleVersion) { var e = PSTraceSource.NewInvalidOperationException(ParserStrings.DuplicateKeywordDefinition, keyword.Keyword); e.SetErrorId("DuplicateKeywordDefinition"); @@ -2258,6 +2278,96 @@ namespace Microsoft.PowerShell.DesiredStateConfiguration.Internal sb.Append("};"); } + /// + /// Gets the line no for DSC Class Resource Get/Set/Test methods + /// + /// + /// + private static bool GetResourceMethodsLineNumber(TypeDefinitionAst typeDefinitionAst, out Dictionary methodsLinePosition) + { + const string getMethodName = "Get"; + const string setMethodName = "Set"; + const string testMethodName = "Test"; + + methodsLinePosition = new Dictionary(); ; + foreach (var member in typeDefinitionAst.Members) + { + var functionMemberAst = member as FunctionMemberAst; + if (functionMemberAst != null) + { + if (functionMemberAst.Name.Equals(getMethodName, StringComparison.OrdinalIgnoreCase)) + { + methodsLinePosition[getMethodName] = functionMemberAst.NameExtent.StartLineNumber; + } + else if (functionMemberAst.Name.Equals(setMethodName, StringComparison.OrdinalIgnoreCase)) + { + methodsLinePosition[setMethodName] = functionMemberAst.NameExtent.StartLineNumber; + } + else if (functionMemberAst.Name.Equals(testMethodName, StringComparison.OrdinalIgnoreCase)) + { + methodsLinePosition[testMethodName] = functionMemberAst.NameExtent.StartLineNumber; + } + } + } + + // All 3 methods (Get/Set/Test) position should be found. + return (methodsLinePosition.Count == 3); + } + + /// + /// Gets the line no for DSC Class Resource Get/Set/Test methods + /// + /// + /// + /// + /// + public static bool GetResourceMethodsLinePosition(PSModuleInfo moduleInfo, string resourceName, out Dictionary resourceMethodsLinePosition, out string resourceFilePath) + { + resourceMethodsLinePosition = null; + resourceFilePath = string.Empty; + if (moduleInfo == null || string.IsNullOrEmpty(resourceName)) + { + return false; + } + + IEnumerable resourceDefinitions; + List moduleFiles = new List(); + if (moduleInfo.RootModule != null) + { + moduleFiles.Add(moduleInfo.Path); + } + if (moduleInfo.NestedModules != null) + { + foreach (var nestedModule in moduleInfo.NestedModules.Where(m => !string.IsNullOrEmpty(m.Path))) + { + moduleFiles.Add(nestedModule.Path); + } + } + + foreach (string moduleFile in moduleFiles) + { + if (GetResourceDefinitionsFromModule(moduleFile, out resourceDefinitions, null, null)) + { + foreach (var r in resourceDefinitions) + { + var resourceDefnAst = (TypeDefinitionAst)r; + if (!resourceName.Equals(resourceDefnAst.Name, StringComparison.OrdinalIgnoreCase)) + { + continue; + } + + if (GetResourceMethodsLineNumber(resourceDefnAst, out resourceMethodsLinePosition)) + { + resourceFilePath = moduleFile; + return true; + } + } + } + } + + return false; + } + private static void ProcessMembers(StringBuilder sb, List embeddedInstanceTypes, TypeDefinitionAst typeDefinitionAst, string className) { foreach (var member in typeDefinitionAst.Members) @@ -2318,15 +2428,14 @@ namespace Microsoft.PowerShell.DesiredStateConfiguration.Internal /// /// /// - /// - /// - /// - /// + /// /// /// /// - static bool ImportKeywordsFromScriptFile(string fileName, PSModuleInfo module, ICollection resourcesToImport, ICollection resourcesFound, Dictionary functionsToDefine, List errorList, IScriptExtent extent) + private static bool GetResourceDefinitionsFromModule (string fileName, out IEnumerable resourceDefinitions, List errorList, IScriptExtent extent) { + resourceDefinitions = null; + if (string.IsNullOrEmpty(fileName)) { return false; @@ -2356,7 +2465,7 @@ namespace Microsoft.PowerShell.DesiredStateConfiguration.Internal if (errorList != null && extent != null) { List errorMessages = new List(); - foreach(var error in errors) + foreach (var error in errors) { errorMessages.Add(error.ToString()); } @@ -2366,7 +2475,7 @@ namespace Microsoft.PowerShell.DesiredStateConfiguration.Internal return false; } - var resourceDefinitions = ast.FindAll(n => + resourceDefinitions = ast.FindAll(n => { var typeAst = n as TypeDefinitionAst; if (typeAst != null) @@ -2380,6 +2489,28 @@ namespace Microsoft.PowerShell.DesiredStateConfiguration.Internal return false; }, false); + return true; + } + + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + static bool ImportKeywordsFromScriptFile(string fileName, PSModuleInfo module, ICollection resourcesToImport, ICollection resourcesFound, Dictionary functionsToDefine, List errorList, IScriptExtent extent) + { + IEnumerable resourceDefinitions; + if(!GetResourceDefinitionsFromModule(fileName, out resourceDefinitions, errorList, extent)) + { + return false; + } + var result = false; var parser = new CimDSCParser(MyClassCallback); diff --git a/src/System.Management.Automation/engine/CommandDiscovery.cs b/src/System.Management.Automation/engine/CommandDiscovery.cs index 548de11b67..2d57504b8b 100644 --- a/src/System.Management.Automation/engine/CommandDiscovery.cs +++ b/src/System.Management.Automation/engine/CommandDiscovery.cs @@ -586,14 +586,34 @@ namespace System.Management.Automation internal static void VerifyPSEdition(ExternalScriptInfo scriptInfo) { - string requiresPSEdition = scriptInfo.RequiresPSEdition; - if ((requiresPSEdition != null) && !Utils.IsPSEditionSupported(requiresPSEdition)) + if (scriptInfo.RequiresPSEditions != null) { - var message = StringUtil.Format(DiscoveryExceptions.RequiresPSEditionNotCompatible, scriptInfo.Name, requiresPSEdition, PSVersionInfo.PSEdition); - var ex = new RuntimeException(message); - ex.SetErrorId("ScriptRequiresUnmatchedPSEdition"); - ex.SetTargetObject(scriptInfo.Name); - throw ex; + var isCurrentEditionListed = false; + var isRequiresPSEditionSpecified = false; + foreach (var edition in scriptInfo.RequiresPSEditions) + { + isRequiresPSEditionSpecified = true; + isCurrentEditionListed = Utils.IsPSEditionSupported(edition); + if (isCurrentEditionListed) + { + break; + } + } + + // Throw an error if required PowerShell editions are specified and without the current PowerShell Edition. + // + if (isRequiresPSEditionSpecified && !isCurrentEditionListed) + { + var specifiedEditionsString = string.Join(",", scriptInfo.RequiresPSEditions); + var message = StringUtil.Format(DiscoveryExceptions.RequiresPSEditionNotCompatible, + scriptInfo.Name, + specifiedEditionsString, + PSVersionInfo.PSEdition); + var ex = new RuntimeException(message); + ex.SetErrorId("ScriptRequiresUnmatchedPSEdition"); + ex.SetTargetObject(scriptInfo.Name); + throw ex; + } } } diff --git a/src/System.Management.Automation/engine/ExternalScriptInfo.cs b/src/System.Management.Automation/engine/ExternalScriptInfo.cs index d4e1a4abb2..ea84414d8b 100644 --- a/src/System.Management.Automation/engine/ExternalScriptInfo.cs +++ b/src/System.Management.Automation/engine/ExternalScriptInfo.cs @@ -383,12 +383,12 @@ namespace System.Management.Automation } } - internal string RequiresPSEdition + internal IEnumerable RequiresPSEditions { get { var data = GetRequiresData(); - return data == null ? null : data.RequiredPSEdition; + return data == null ? null : data.RequiredPSEditions; } } diff --git a/src/System.Management.Automation/engine/InitialSessionState.cs b/src/System.Management.Automation/engine/InitialSessionState.cs index b7e4829a3b..dc0e68bd32 100644 --- a/src/System.Management.Automation/engine/InitialSessionState.cs +++ b/src/System.Management.Automation/engine/InitialSessionState.cs @@ -3609,7 +3609,18 @@ namespace System.Management.Automation.Runspaces } pse.Runspace = initializedRunspace; - pse.Invoke(); + // Module import should be run in FullLanguage mode since it is running in + // a trusted context. + var savedLanguageMode = pse.Runspace.ExecutionContext.LanguageMode; + pse.Runspace.ExecutionContext.LanguageMode = PSLanguageMode.FullLanguage; + try + { + pse.Invoke(); + } + finally + { + pse.Runspace.ExecutionContext.LanguageMode = savedLanguageMode; + } // Lock down the command visibility to respect default command visibility if (this.DefaultCommandVisibility != SessionStateEntryVisibility.Public) diff --git a/src/System.Management.Automation/engine/Modules/GetModuleCommand.cs b/src/System.Management.Automation/engine/Modules/GetModuleCommand.cs index 1ba0277ef2..5b37cc4874 100644 --- a/src/System.Management.Automation/engine/Modules/GetModuleCommand.cs +++ b/src/System.Management.Automation/engine/Modules/GetModuleCommand.cs @@ -9,9 +9,11 @@ using System.Globalization; using System.IO; using System.Management.Automation; using System.Management.Automation.Internal; +using System.Management.Automation.Language; using System.Management.Automation.Runspaces; using System.Diagnostics.CodeAnalysis; using System.Linq; +using System.Text.RegularExpressions; using System.Threading; using Microsoft.Management.Infrastructure; using Dbg = System.Management.Automation.Diagnostics; @@ -80,7 +82,7 @@ namespace Microsoft.PowerShell.Commands /// [Parameter(ParameterSetName = ParameterSet_AvailableLocally)] [Parameter(ParameterSetName = ParameterSet_AvailableInPsrpSession)] - [ValidateSet("Desktop", "Core")] + [ArgumentCompleter(typeof(PSEditionArgumentCompleter))] public string PSEdition { get; set; } /// @@ -491,5 +493,28 @@ namespace Microsoft.PowerShell.Commands } } } + + /// + /// PSEditionArgumentCompleter for PowerShell Edition names. + /// + public class PSEditionArgumentCompleter : IArgumentCompleter + { + /// + /// CompleteArgument + /// + public IEnumerable CompleteArgument(string commandName, string parameterName, string wordToComplete, CommandAst commandAst, IDictionary fakeBoundParameters) + { + var wordToCompletePattern = WildcardPattern.Get(string.IsNullOrWhiteSpace(wordToComplete) ? "*" : wordToComplete + "*", WildcardOptions.IgnoreCase); + + foreach (var edition in Utils.AllowedEditionValues) + { + if (wordToCompletePattern.IsMatch(edition)) + { + yield return new CompletionResult(edition, edition, CompletionResultType.Text, edition); + } + } + } + } + } // Microsoft.PowerShell.Commands diff --git a/src/System.Management.Automation/engine/Modules/NewModuleManifestCommand.cs b/src/System.Management.Automation/engine/Modules/NewModuleManifestCommand.cs index f14511674c..5f33b34735 100644 --- a/src/System.Management.Automation/engine/Modules/NewModuleManifestCommand.cs +++ b/src/System.Management.Automation/engine/Modules/NewModuleManifestCommand.cs @@ -3,6 +3,7 @@ Copyright (c) Microsoft Corporation. All rights reserved. --********************************************************************/ using System; +using System.Linq; using System.Text; using System.Collections; using System.Collections.Generic; @@ -886,6 +887,14 @@ namespace Microsoft.PowerShell.Commands ValidateUriParamterValue(LicenseUri, "LicenseUri"); ValidateUriParamterValue(IconUri, "IconUri"); + if (CompatiblePSEditions != null && (CompatiblePSEditions.Distinct(StringComparer.OrdinalIgnoreCase).Count() != CompatiblePSEditions.Count())) + { + string message = StringUtil.Format(Modules.DuplicateEntriesInCompatiblePSEditions, String.Join(",", CompatiblePSEditions)); + var ioe = new InvalidOperationException(message); + var er = new ErrorRecord(ioe, "Modules_DuplicateEntriesInCompatiblePSEditions", ErrorCategory.InvalidArgument, CompatiblePSEditions); + ThrowTerminatingError(er); + } + string action = StringUtil.Format(Modules.CreatingModuleManifestFile, filePath); if (ShouldProcess(filePath, action)) diff --git a/src/System.Management.Automation/engine/Modules/TestModuleManifestCommand.cs b/src/System.Management.Automation/engine/Modules/TestModuleManifestCommand.cs index 4fd513d6fa..c452b65611 100644 --- a/src/System.Management.Automation/engine/Modules/TestModuleManifestCommand.cs +++ b/src/System.Management.Automation/engine/Modules/TestModuleManifestCommand.cs @@ -207,26 +207,26 @@ namespace Microsoft.PowerShell.Commands var modules = GetModule(new[] { moduleListModule.Name }, true, true); if (modules.Count == 0) { - string errorMsg = StringUtil.Format(Modules.InvalidFilePathinModuleManifest, moduleListModule.Name, filePath); + string errorMsg = StringUtil.Format(Modules.InvalidModuleListinModuleManifest, moduleListModule.Name, filePath); var errorRecord = new ErrorRecord(new DirectoryNotFoundException(errorMsg), "Modules_InvalidModuleListinModuleManifest", ErrorCategory.ObjectNotFound, _path); WriteError(errorRecord); } } } - } - if (module.CompatiblePSEditions.Any()) - { - // The CompatiblePSEditions module manifest key is supported only on PowerShell version '5.1' or higher. - // Ensure that PowerShellVersion module manifest key value is '5.1' or higher. - // - var minimumRequiredPowerShellVersion = new Version(5,1); - if((module.PowerShellVersion == null) || module.PowerShellVersion < minimumRequiredPowerShellVersion) + if (module.CompatiblePSEditions.Any()) { - string errorMsg = StringUtil.Format(Modules.InvalidPowerShellVersionInModuleManifest, filePath); - var errorRecord = new ErrorRecord(new ArgumentException(errorMsg), "Modules_InvalidPowerShellVersionInModuleManifest", ErrorCategory.InvalidArgument, _path); - WriteError(errorRecord); + // The CompatiblePSEditions module manifest key is supported only on PowerShell version '5.1' or higher. + // Ensure that PowerShellVersion module manifest key value is '5.1' or higher. + // + var minimumRequiredPowerShellVersion = new Version(5,1); + if((module.PowerShellVersion == null) || module.PowerShellVersion < minimumRequiredPowerShellVersion) + { + string errorMsg = StringUtil.Format(Modules.InvalidPowerShellVersionInModuleManifest, filePath); + var errorRecord = new ErrorRecord(new ArgumentException(errorMsg), "Modules_InvalidPowerShellVersionInModuleManifest", ErrorCategory.InvalidArgument, _path); + WriteError(errorRecord); + } } } } diff --git a/src/System.Management.Automation/engine/PSClassSearcher.cs b/src/System.Management.Automation/engine/PSClassSearcher.cs index 65e02a7fc6..9b3b37e27e 100644 --- a/src/System.Management.Automation/engine/PSClassSearcher.cs +++ b/src/System.Management.Automation/engine/PSClassSearcher.cs @@ -231,7 +231,8 @@ namespace System.Management.Automation foreach (var exportedType in exportedTypes) { if (exportedType.Value != null && - classNameMatcher.IsMatch(exportedType.Value.Name)) + classNameMatcher.IsMatch(exportedType.Value.Name) && + exportedType.Value.IsClass) { ast = exportedType.Value.Parent.Parent as ScriptBlockAst; if (ast != null) diff --git a/src/System.Management.Automation/engine/Utils.cs b/src/System.Management.Automation/engine/Utils.cs index 8484e0bbaa..d32c79f4d3 100644 --- a/src/System.Management.Automation/engine/Utils.cs +++ b/src/System.Management.Automation/engine/Utils.cs @@ -77,6 +77,11 @@ namespace System.Management.Automation /// internal static string WinPEIdentificationRegKey = @"System\CurrentControlSet\Control\MiniNT"; + /// + /// Allowed PowerShell Editions + /// + internal static string[] AllowedEditionValues = { "Desktop", "Core" }; + /// /// helper fn to check byte[] arg for null. /// @@ -522,6 +527,16 @@ namespace System.Management.Automation return PSVersionInfo.PSEdition.Equals(checkEdition, StringComparison.OrdinalIgnoreCase); } + /// + /// Checks whether the specified edition values is allowed. + /// + /// Edition value to check + /// true if allowed, false otherwise + internal static bool IsValidPSEditionValue(string editionValue) + { + return AllowedEditionValues.Contains(editionValue, StringComparer.OrdinalIgnoreCase); + } + /// /// Checks whether current monad session supports NetFrameworkVersion specified /// by checkVersion. The specified version is treated as the the minimum required diff --git a/src/System.Management.Automation/engine/parser/Parser.cs b/src/System.Management.Automation/engine/parser/Parser.cs index 0ae7700c65..d936470478 100644 --- a/src/System.Management.Automation/engine/parser/Parser.cs +++ b/src/System.Management.Automation/engine/parser/Parser.cs @@ -2705,7 +2705,7 @@ namespace System.Management.Automation.Language { simpleConfigurationNameValue = outValue as string; if (simpleConfigurationNameValue == null || - !System.Text.RegularExpressions.Regex.IsMatch(simpleConfigurationNameValue, "^[A-Za-z][A-Za-z0-9_]*$")) + !System.Text.RegularExpressions.Regex.IsMatch(simpleConfigurationNameValue, "^[A-Za-z][A-Za-z0-9_./-]*$")) { // This is actually a semantics check, the syntax is fine at this point. // Continue parsing to get as much information as possible diff --git a/src/System.Management.Automation/engine/parser/ast.cs b/src/System.Management.Automation/engine/parser/ast.cs index bdbc1f0f88..d6ce0333eb 100644 --- a/src/System.Management.Automation/engine/parser/ast.cs +++ b/src/System.Management.Automation/engine/parser/ast.cs @@ -708,6 +708,8 @@ namespace System.Management.Automation.Language Utils.EmptyReadOnlyCollection(); internal static readonly ReadOnlyCollection EmptyModuleCollection = Utils.EmptyReadOnlyCollection(); + internal static readonly ReadOnlyCollection EmptyEditionCollection = + Utils.EmptyReadOnlyCollection(); /// /// The application id this script requires, specified like: @@ -726,9 +728,9 @@ namespace System.Management.Automation.Language /// /// The PowerShell Edition this script requires, specified like: /// #requires -PSEdition Desktop - /// If no PSEdition has been specified, this property is null. + /// If no PSEdition has been specified, this property is an empty collection. /// - public string RequiredPSEdition { get; internal set; } + public ReadOnlyCollection RequiredPSEditions { get; internal set; } /// /// The modules this script requires, specified like: diff --git a/src/System.Management.Automation/engine/parser/tokenizer.cs b/src/System.Management.Automation/engine/parser/tokenizer.cs index 8feeb66d37..bb2d39b2c0 100644 --- a/src/System.Management.Automation/engine/parser/tokenizer.cs +++ b/src/System.Management.Automation/engine/parser/tokenizer.cs @@ -1516,7 +1516,7 @@ namespace System.Management.Automation.Language string requiredShellId = null; Version requiredVersion = null; - string requiredEdition = null; + List requiredEditions = null; List requiredModules = null; List requiredSnapins = null; List requiredAssemblies = null; @@ -1565,7 +1565,7 @@ namespace System.Management.Automation.Language { HandleRequiresParameter(parameter, commandAst.CommandElements, snapinSpecified, ref i, ref snapinName, ref snapinVersion, - ref requiredShellId, ref requiredVersion, ref requiredEdition, ref requiredModules, ref requiredAssemblies, ref requiresElevation); + ref requiredShellId, ref requiredVersion, ref requiredEditions, ref requiredModules, ref requiredAssemblies, ref requiresElevation); } else { @@ -1584,7 +1584,9 @@ namespace System.Management.Automation.Language { RequiredApplicationId = requiredShellId, RequiredPSVersion = requiredVersion, - RequiredPSEdition = requiredEdition, + RequiredPSEditions = requiredEditions != null + ? new ReadOnlyCollection(requiredEditions) + : ScriptRequirements.EmptyEditionCollection, RequiresPSSnapIns = requiredSnapins != null ? new ReadOnlyCollection(requiredSnapins) : ScriptRequirements.EmptySnapinCollection, @@ -1614,7 +1616,7 @@ namespace System.Management.Automation.Language ref Version snapinVersion, ref string requiredShellId, ref Version requiredVersion, - ref string requiredEdition, + ref List requiredEditions, ref List requiredModules, ref List requiredAssemblies, ref bool requiresElevation) @@ -1680,19 +1682,23 @@ namespace System.Management.Automation.Language } else if (editionToken.StartsWith(parameter.ParameterName, StringComparison.OrdinalIgnoreCase)) { - if (!(argumentValue is string)) - { - ReportError(argumentAst.Extent, () => ParserStrings.RequiresInvalidStringArgument, editionToken); - return; - } - - if (requiredEdition != null) + if (requiredEditions != null) { ReportError(parameter.Extent, () => ParameterBinderStrings.ParameterAlreadyBound, null, editionToken); return; } - requiredEdition = (string)argumentValue; + if (argumentValue is string || !(argumentValue is IEnumerable)) + { + requiredEditions = HandleRequiresPSEditionArgument(argumentAst, argumentValue, ref requiredEditions); + } + else + { + foreach (var arg in (IEnumerable)argumentValue) + { + requiredEditions = HandleRequiresPSEditionArgument(argumentAst, arg, ref requiredEditions); + } + } } else if (versionToken.StartsWith(parameter.ParameterName, StringComparison.OrdinalIgnoreCase)) { @@ -1787,6 +1793,34 @@ namespace System.Management.Automation.Language return requiredAssemblies; } + private List HandleRequiresPSEditionArgument(Ast argumentAst, object arg, ref List requiredEditions) + { + if (!(arg is string)) + { + ReportError(argumentAst.Extent, () => ParserStrings.RequiresInvalidStringArgument, editionToken); + } + else + { + if (requiredEditions == null) + requiredEditions = new List(); + + var edition = (string) arg; + if (!Utils.IsValidPSEditionValue(edition)) + { + ReportError(argumentAst.Extent, () => ParserStrings.RequiresPSEditionInvalid, editionToken); + } + + if (!requiredEditions.Contains(edition, StringComparer.OrdinalIgnoreCase)) + { + requiredEditions.Add(edition); + } + else + { + ReportError(argumentAst.Extent, () => ParserStrings.RequiresPSEditionValueIsAlreadySpecified, editionToken); + } + } + return requiredEditions; + } #endregion Requires #endregion Comments diff --git a/src/System.Management.Automation/engine/remoting/client/remoterunspaceinfo.cs b/src/System.Management.Automation/engine/remoting/client/remoterunspaceinfo.cs index 222620a038..7ef34003de 100644 --- a/src/System.Management.Automation/engine/remoting/client/remoterunspaceinfo.cs +++ b/src/System.Management.Automation/engine/remoting/client/remoterunspaceinfo.cs @@ -323,28 +323,39 @@ namespace System.Management.Automation.Runspaces remoteRunspace.PSSessionName = name; } - string fullShellName = WSManConnectionInfo.ExtractPropertyAsWsManConnectionInfo( - remoteRunspace.ConnectionInfo, - "ShellUri", string.Empty); - - shell = GetDisplayShellName(fullShellName); - - if (remoteRunspace.ConnectionInfo is VMConnectionInfo) - { - computerType = TargetMachineType.VirtualMachine; - } - else if (remoteRunspace.ConnectionInfo is ContainerConnectionInfo) - { - computerType = TargetMachineType.Container; - } - else if (remoteRunspace.ConnectionInfo is WSManConnectionInfo) + // WSMan session + if (remoteRunspace.ConnectionInfo is WSManConnectionInfo) { computerType = TargetMachineType.RemoteMachine; + + string fullShellName = WSManConnectionInfo.ExtractPropertyAsWsManConnectionInfo( + remoteRunspace.ConnectionInfo, + "ShellUri", string.Empty); + + shell = GetDisplayShellName(fullShellName); + return; } - else + + // VM session + VMConnectionInfo vmConnectionInfo = remoteRunspace.ConnectionInfo as VMConnectionInfo; + if (vmConnectionInfo != null) { - Dbg.Assert(false, "Invalid Runspace"); + computerType = TargetMachineType.VirtualMachine; + shell = vmConnectionInfo.ConfigurationName; + return; } + + // Container session + ContainerConnectionInfo containerConnectionInfo = remoteRunspace.ConnectionInfo as ContainerConnectionInfo; + if (containerConnectionInfo != null) + { + computerType = TargetMachineType.Container; + shell = containerConnectionInfo.ContainerProc.ConfigurationName; + return; + } + + // We only support WSMan/VM/Container sessions now. + Dbg.Assert(false, "Invalid Runspace"); } #endregion Constructor diff --git a/src/System.Management.Automation/engine/remoting/commands/EnterPSHostProcessCommand.cs b/src/System.Management.Automation/engine/remoting/commands/EnterPSHostProcessCommand.cs index e5d484f961..6b8577fb97 100644 --- a/src/System.Management.Automation/engine/remoting/commands/EnterPSHostProcessCommand.cs +++ b/src/System.Management.Automation/engine/remoting/commands/EnterPSHostProcessCommand.cs @@ -204,10 +204,15 @@ namespace Microsoft.PowerShell.Commands { string msgAppDomainName = (!string.IsNullOrEmpty(appDomainName)) ? appDomainName : NamedPipeUtils.DefaultAppDomainName; + // Unwrap inner exception for original error message, if any. + string errorMessage = (e.InnerException != null) ? (e.InnerException.Message ?? string.Empty) : string.Empty; + ThrowTerminatingError( new ErrorRecord( - new RuntimeException(StringUtil.Format(RemotingErrorIdStrings.EnterPSHostProcessCannotConnectToProcess, msgAppDomainName, procId), - e.InnerException), + new RuntimeException( + StringUtil.Format(RemotingErrorIdStrings.EnterPSHostProcessCannotConnectToProcess, + msgAppDomainName, procId, errorMessage), + e.InnerException), "EnterPSHostProcessCannotConnectToProcess", ErrorCategory.OperationTimeout, this)); @@ -627,7 +632,18 @@ namespace Microsoft.PowerShell.Commands private set; } - #endregion +#if !CORECLR + /// + /// Main window title of the process + /// + public string MainWindowTitle + { + get; + private set; + } +#endif + +#endregion #region Constructors @@ -644,6 +660,17 @@ namespace Microsoft.PowerShell.Commands if (string.IsNullOrEmpty(processName)) { throw new PSArgumentNullException("processName"); } if (string.IsNullOrEmpty(appDomainName)) { throw new PSArgumentNullException("appDomainName"); } +#if !CORECLR + MainWindowTitle = String.Empty; + try + { + var proc = System.Diagnostics.Process.GetProcessById(processId); + MainWindowTitle = proc.MainWindowTitle ?? string.Empty; + } + catch (ArgumentException) { } + catch (InvalidOperationException) { } +#endif + this.ProcessName = processName; this.ProcessId = processId; this.AppDomainName = appDomainName; diff --git a/src/System.Management.Automation/engine/remoting/commands/InvokeCommandCommand.cs b/src/System.Management.Automation/engine/remoting/commands/InvokeCommandCommand.cs index 6cf155ad58..207c035b9b 100644 --- a/src/System.Management.Automation/engine/remoting/commands/InvokeCommandCommand.cs +++ b/src/System.Management.Automation/engine/remoting/commands/InvokeCommandCommand.cs @@ -263,18 +263,38 @@ namespace Microsoft.PowerShell.Commands } /// + /// For WSMan session: /// If this parameter is not specified then the value specified in /// the environment variable DEFAULTREMOTESHELLNAME will be used. If /// this is not set as well, then Microsoft.PowerShell is used. + /// + /// For VM/Container sessions: + /// If this parameter is not specified then no configuration is used. /// [Parameter(ValueFromPipelineByPropertyName = true, ParameterSetName = InvokeCommandCommand.ComputerNameParameterSet)] [Parameter(ValueFromPipelineByPropertyName = true, - ParameterSetName = InvokeCommandCommand.UriParameterSet)] + ParameterSetName = InvokeCommandCommand.UriParameterSet)] [Parameter(ValueFromPipelineByPropertyName = true, ParameterSetName = InvokeCommandCommand.FilePathComputerNameParameterSet)] [Parameter(ValueFromPipelineByPropertyName = true, - ParameterSetName = InvokeCommandCommand.FilePathUriParameterSet)] + ParameterSetName = InvokeCommandCommand.FilePathUriParameterSet)] + [Parameter(ValueFromPipelineByPropertyName = true, + ParameterSetName = InvokeCommandCommand.ContainerIdParameterSet)] + [Parameter(ValueFromPipelineByPropertyName = true, + ParameterSetName = InvokeCommandCommand.ContainerNameParameterSet)] + [Parameter(ValueFromPipelineByPropertyName = true, + ParameterSetName = InvokeCommandCommand.VMIdParameterSet)] + [Parameter(ValueFromPipelineByPropertyName = true, + ParameterSetName = InvokeCommandCommand.VMNameParameterSet)] + [Parameter(ValueFromPipelineByPropertyName = true, + ParameterSetName = InvokeCommandCommand.FilePathContainerIdParameterSet)] + [Parameter(ValueFromPipelineByPropertyName = true, + ParameterSetName = InvokeCommandCommand.FilePathContainerNameParameterSet)] + [Parameter(ValueFromPipelineByPropertyName = true, + ParameterSetName = InvokeCommandCommand.FilePathVMIdParameterSet)] + [Parameter(ValueFromPipelineByPropertyName = true, + ParameterSetName = InvokeCommandCommand.FilePathVMNameParameterSet)] public override String ConfigurationName { get @@ -774,6 +794,23 @@ namespace Microsoft.PowerShell.Commands return; } + if (String.IsNullOrEmpty(ConfigurationName)) + { + if ((ParameterSetName == InvokeCommandCommand.ComputerNameParameterSet) || + (ParameterSetName == InvokeCommandCommand.UriParameterSet) || + (ParameterSetName == InvokeCommandCommand.FilePathComputerNameParameterSet) || + (ParameterSetName == InvokeCommandCommand.FilePathUriParameterSet)) + { + // set to default value for WSMan session + ConfigurationName = ResolveShell(null); + } + else + { + // convert null to String.Empty for VM/Container session + ConfigurationName = String.Empty; + } + } + base.BeginProcessing(); // create collection of input writers here @@ -1761,14 +1798,14 @@ namespace Microsoft.PowerShell.Commands ErrorRecord errorRecord = streamObject.Value as ErrorRecord; // - // In case of PSDirectCredentialException, we should output the precise error message + // In case of PSDirectException, we should output the precise error message // in inner exception instead of the generic one in outer exception. // if ((errorRecord != null) && (errorRecord.Exception != null) && (errorRecord.Exception.InnerException != null)) { - PSDirectCredentialException ex = errorRecord.Exception.InnerException as PSDirectCredentialException; + PSDirectException ex = errorRecord.Exception.InnerException as PSDirectException; if (ex != null) { streamObject.Value = new ErrorRecord(errorRecord.Exception.InnerException, diff --git a/src/System.Management.Automation/engine/remoting/commands/PSRemotingCmdlet.cs b/src/System.Management.Automation/engine/remoting/commands/PSRemotingCmdlet.cs index 04f1058b07..b495931920 100644 --- a/src/System.Management.Automation/engine/remoting/commands/PSRemotingCmdlet.cs +++ b/src/System.Management.Automation/engine/remoting/commands/PSRemotingCmdlet.cs @@ -243,7 +243,6 @@ namespace Microsoft.PowerShell.Commands } return resolvedShell; - } /// @@ -551,29 +550,6 @@ namespace Microsoft.PowerShell.Commands } private SwitchParameter useSSL; - /// - /// If this parameter is not specified then the value specified in - /// the environment variable DEFAULTREMOTESHELLNAME will be used. If - /// this is not set as well, then Microsoft.PowerShell is used. - /// - [Parameter(ValueFromPipelineByPropertyName = true, - ParameterSetName = PSRemotingBaseCmdlet.ComputerNameParameterSet)] - [Parameter(ValueFromPipelineByPropertyName = true, - ParameterSetName = PSRemotingBaseCmdlet.UriParameterSet)] - public virtual String ConfigurationName - { - get - { - return shell; - } - set - { - shell = ResolveShell(value); - } - } - - private String shell; - /// /// This parameters specifies the appname which identifies the connection /// end point on the remote machine. If this parameter is not specified @@ -879,11 +855,6 @@ namespace Microsoft.PowerShell.Commands idleTimeout / 1000, BaseTransportManager.MinimumIdleTimeout / 1000)); } - if (String.IsNullOrEmpty(shell)) - { - shell = ResolveShell(null); - } - if (String.IsNullOrEmpty(appName)) { appName = ResolveAppName(null); @@ -1131,6 +1102,54 @@ namespace Microsoft.PowerShell.Commands } private string[] containerName; + /// + /// For WSMan session: + /// If this parameter is not specified then the value specified in + /// the environment variable DEFAULTREMOTESHELLNAME will be used. If + /// this is not set as well, then Microsoft.PowerShell is used. + /// + /// For VM/Container sessions: + /// If this parameter is not specified then no configuration is used. + /// + [Parameter(ValueFromPipelineByPropertyName = true, + ParameterSetName = InvokeCommandCommand.ComputerNameParameterSet)] + [Parameter(ValueFromPipelineByPropertyName = true, + ParameterSetName = InvokeCommandCommand.UriParameterSet)] + [Parameter(ValueFromPipelineByPropertyName = true, + ParameterSetName = InvokeCommandCommand.FilePathComputerNameParameterSet)] + [Parameter(ValueFromPipelineByPropertyName = true, + ParameterSetName = InvokeCommandCommand.FilePathUriParameterSet)] + [Parameter(ValueFromPipelineByPropertyName = true, + ParameterSetName = InvokeCommandCommand.ContainerIdParameterSet)] + [Parameter(ValueFromPipelineByPropertyName = true, + ParameterSetName = InvokeCommandCommand.ContainerNameParameterSet)] + [Parameter(ValueFromPipelineByPropertyName = true, + ParameterSetName = InvokeCommandCommand.VMIdParameterSet)] + [Parameter(ValueFromPipelineByPropertyName = true, + ParameterSetName = InvokeCommandCommand.VMNameParameterSet)] + [Parameter(ValueFromPipelineByPropertyName = true, + ParameterSetName = InvokeCommandCommand.FilePathContainerIdParameterSet)] + [Parameter(ValueFromPipelineByPropertyName = true, + ParameterSetName = InvokeCommandCommand.FilePathContainerNameParameterSet)] + [Parameter(ValueFromPipelineByPropertyName = true, + ParameterSetName = InvokeCommandCommand.FilePathVMIdParameterSet)] + [Parameter(ValueFromPipelineByPropertyName = true, + ParameterSetName = InvokeCommandCommand.FilePathVMNameParameterSet)] + public virtual String ConfigurationName + { + get + { + return shell; + } + set + { + // Only InvokeCommandCommand may enter here, + // which will call ResolveShell() if needed. + shell = value; + } + } + private String shell; + #endregion Parameters #region Private Methods @@ -1432,7 +1451,7 @@ namespace Microsoft.PowerShell.Commands try { - connectionInfo = new VMConnectionInfo(this.Credential, this.VMId[index], this.VMName[index]); + connectionInfo = new VMConnectionInfo(this.Credential, this.VMId[index], this.VMName[index], this.ConfigurationName); remoteRunspace = new RemoteRunspace(Utils.GetTypeTableFromExecutionContextTLS(), connectionInfo, this.Host, null, null, -1); @@ -1509,11 +1528,11 @@ namespace Microsoft.PowerShell.Commands // if (isContainerIdSet) { - connectionInfo = ContainerConnectionInfo.CreateContainerConnectionInfoById(input, RunAsAdministrator.IsPresent); + connectionInfo = ContainerConnectionInfo.CreateContainerConnectionInfoById(input, RunAsAdministrator.IsPresent, this.ConfigurationName); } else { - connectionInfo = ContainerConnectionInfo.CreateContainerConnectionInfoByName(input, RunAsAdministrator.IsPresent); + connectionInfo = ContainerConnectionInfo.CreateContainerConnectionInfoByName(input, RunAsAdministrator.IsPresent, this.ConfigurationName); } resolvedNameList.Add(connectionInfo.ComputerName); @@ -2355,6 +2374,21 @@ private string GetConvertedScript(out List newParameterNames, out List + /// Gets the matching runspaces based on the parameterset + /// + /// write an error record when + /// no matches are found + /// if true write the object down + /// the pipeline + /// list of matching runspaces + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Runspaces")] + protected Dictionary GetMatchingRunspaces(bool writeobject, + bool writeErrorOnNoMatch) + { + return GetMatchingRunspaces(writeobject, writeErrorOnNoMatch, SessionFilterState.All, null); + } + /// /// Gets the matching runspaces based on the parameterset /// @@ -2363,11 +2397,13 @@ private string GetConvertedScript(out List newParameterNames, out Listif true write the object down /// the pipeline /// Runspace state filter value. + /// Runspace configuration name filter value. /// list of matching runspaces [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Runspaces")] protected Dictionary GetMatchingRunspaces(bool writeobject, bool writeErrorOnNoMatch, - SessionFilterState filterState = SessionFilterState.All) + SessionFilterState filterState, + String configurationName) { switch (ParameterSetName) { @@ -2399,49 +2435,49 @@ private string GetConvertedScript(out List newParameterNames, out List newParameterNames, out List /// if true write the object down the pipeline /// Runspace state filter value. + /// Runspace configuration name filter value. /// if true the target is a container instead of virtual machine /// if true the input is container id /// list of matching runspaces private Dictionary GetMatchingRunspacesByContainerVMNameContainerId(bool writeobject, SessionFilterState filterState, + String configurationName, bool isContainer, bool useContainerId) { @@ -2720,6 +2758,8 @@ private string GetConvertedScript(out List newParameterNames, out List matches = new Dictionary(); List remoteRunspaceInfos = this.RunspaceRepository.Runspaces; @@ -2758,13 +2798,15 @@ private string GetConvertedScript(out List newParameterNames, out List(session => (supportWildChar ? inputNamePattern.IsMatch(isContainer ? session.ContainerName : session.VMName) : inputName.Equals(session.ContainerId)) && - sessionNamePattern.IsMatch(session.Name) && + ((sessionNamePattern == null) ? true : sessionNamePattern.IsMatch(session.Name)) && QueryRunspaces.TestRunspaceState(session.Runspace, filterState) && + ((configurationNamePattern == null) ? true : configurationNamePattern.IsMatch(session.ConfigurationName)) && (session.ComputerType == computerType)) .ToList(); @@ -2780,17 +2822,21 @@ private string GetConvertedScript(out List newParameterNames, out List /// if true write the object down the pipeline /// Runspace state filter value. + /// Runspace configuration name filter value. /// if true the target is a container instead of virtual machine /// if true the input is container id /// list of matching runspaces private Dictionary GetMatchingRunspacesByContainerVMNameContainerIdSessionInstanceId(bool writeobject, SessionFilterState filterState, + String configurationName, bool isContainer, bool useContainerId) { String[] inputNames; TargetMachineType computerType; bool supportWildChar = false; + WildcardPattern configurationNamePattern = + String.IsNullOrEmpty(configurationName) ? null : WildcardPattern.Get(configurationName, WildcardOptions.IgnoreCase); Dictionary matches = new Dictionary(); List remoteRunspaceInfos = this.RunspaceRepository.Runspaces; @@ -2828,6 +2874,7 @@ private string GetConvertedScript(out List newParameterNames, out List(); @@ -2843,11 +2890,15 @@ private string GetConvertedScript(out List newParameterNames, out List /// if true write the object down the pipeline /// Runspace state filter value. + /// Runspace configuration name filter value. /// list of matching runspaces private Dictionary GetMatchingRunspacesByVMId(bool writeobject, - SessionFilterState filterState) + SessionFilterState filterState, + String configurationName) { - String[] sessionNames = { "*" }; + String[] sessionNames = { "*" }; + WildcardPattern configurationNamePattern = + String.IsNullOrEmpty(configurationName) ? null : WildcardPattern.Get(configurationName, WildcardOptions.IgnoreCase); Dictionary matches = new Dictionary(); List remoteRunspaceInfos = this.RunspaceRepository.Runspaces; @@ -2861,12 +2912,14 @@ private string GetConvertedScript(out List newParameterNames, out List(session => vmId.Equals(session.VMId) && - sessionNamePattern.IsMatch(session.Name) && + ((sessionNamePattern == null) ? true : sessionNamePattern.IsMatch(session.Name)) && QueryRunspaces.TestRunspaceState(session.Runspace, filterState) && + ((configurationNamePattern == null) ? true : configurationNamePattern.IsMatch(session.ConfigurationName)) && (session.ComputerType == TargetMachineType.VirtualMachine)) .ToList(); @@ -2882,10 +2935,14 @@ private string GetConvertedScript(out List newParameterNames, out List /// if true write the object down the pipeline /// Runspace state filter value. + /// Runspace configuration name filter value. /// list of matching runspaces private Dictionary GetMatchingRunspacesByVMIdSessionInstanceId(bool writeobject, - SessionFilterState filterState) + SessionFilterState filterState, + String configurationName) { + WildcardPattern configurationNamePattern = + String.IsNullOrEmpty(configurationName) ? null : WildcardPattern.Get(configurationName, WildcardOptions.IgnoreCase); Dictionary matches = new Dictionary(); List remoteRunspaceInfos = this.RunspaceRepository.Runspaces; @@ -2897,6 +2954,7 @@ private string GetConvertedScript(out List newParameterNames, out List(session => vmId.Equals(session.VMId) && sessionInstanceId.Equals(session.InstanceId) && QueryRunspaces.TestRunspaceState(session.Runspace, filterState) && + ((configurationNamePattern == null) ? true : configurationNamePattern.IsMatch(session.ConfigurationName)) && (session.ComputerType == TargetMachineType.VirtualMachine)) .ToList(); diff --git a/src/System.Management.Automation/engine/remoting/commands/PushRunspaceCommand.cs b/src/System.Management.Automation/engine/remoting/commands/PushRunspaceCommand.cs index a2050c808f..8354b6fdf8 100644 --- a/src/System.Management.Automation/engine/remoting/commands/PushRunspaceCommand.cs +++ b/src/System.Management.Automation/engine/remoting/commands/PushRunspaceCommand.cs @@ -219,10 +219,67 @@ namespace Microsoft.PowerShell.Commands } private string containerName; + /// + /// For WSMan sessions: + /// If this parameter is not specified then the value specified in + /// the environment variable DEFAULTREMOTESHELLNAME will be used. If + /// this is not set as well, then Microsoft.PowerShell is used. + /// + /// For VM/Container sessions: + /// If this parameter is not specified then no configuration is used. + /// + [Parameter(ValueFromPipelineByPropertyName = true, + ParameterSetName = EnterPSSessionCommand.ComputerNameParameterSet)] + [Parameter(ValueFromPipelineByPropertyName = true, + ParameterSetName = EnterPSSessionCommand.UriParameterSet)] + [Parameter(ValueFromPipelineByPropertyName = true, + ParameterSetName = EnterPSSessionCommand.ContainerIdParameterSet)] + [Parameter(ValueFromPipelineByPropertyName = true, + ParameterSetName = EnterPSSessionCommand.ContainerNameParameterSet)] + [Parameter(ValueFromPipelineByPropertyName = true, + ParameterSetName = EnterPSSessionCommand.VMIdParameterSet)] + [Parameter(ValueFromPipelineByPropertyName = true, + ParameterSetName = EnterPSSessionCommand.VMNameParameterSet)] + public String ConfigurationName + { + get + { + return shell; + } + set + { + shell = value; + } + } + private String shell; + #endregion #region Overrides + /// + /// Resolves shellname and appname + /// + protected override void BeginProcessing() + { + base.BeginProcessing(); + + if (String.IsNullOrEmpty(ConfigurationName)) + { + if ((ParameterSetName == EnterPSSessionCommand.ComputerNameParameterSet) || + (ParameterSetName == EnterPSSessionCommand.UriParameterSet)) + { + // set to default value for WSMan session + ConfigurationName = ResolveShell(null); + } + else + { + // convert null to String.Empty for VM/Container session + ConfigurationName = String.Empty; + } + } + } + /// /// Process record. /// @@ -1013,7 +1070,7 @@ namespace Microsoft.PowerShell.Commands try { VMConnectionInfo connectionInfo; - connectionInfo = new VMConnectionInfo(this.Credential, this.VMId, this.VMName); + connectionInfo = new VMConnectionInfo(this.Credential, this.VMId, this.VMName, this.ConfigurationName); remoteRunspace = CreateTemporaryRemoteRunspaceForPowerShellDirect(this.Host, connectionInfo); } @@ -1036,28 +1093,37 @@ namespace Microsoft.PowerShell.Commands WriteError(errorRecord); } catch (PSRemotingDataStructureException e) + { + ErrorRecord errorRecord; + + // + // In case of PSDirectException, we should output the precise error message + // in inner exception instead of the generic one in outer exception. + // + if ((e.InnerException != null) && (e.InnerException is PSDirectException)) + { + errorRecord = new ErrorRecord(e.InnerException, + "CreateRemoteRunspaceForVMFailed", + ErrorCategory.InvalidArgument, + null); + } + else + { + errorRecord = new ErrorRecord(e, + "CreateRemoteRunspaceForVMFailed", + ErrorCategory.InvalidOperation, + null); + } + + WriteError(errorRecord); + } + catch (Exception e) { ErrorRecord errorRecord = new ErrorRecord(e, "CreateRemoteRunspaceForVMFailed", ErrorCategory.InvalidOperation, null); - - // - // In case of PSDirectCredentialException, we should output the precise error message - // in inner exception instead of the generic one in outer exception. - // - if (e.InnerException != null) - { - PSDirectCredentialException ex = e.InnerException as PSDirectCredentialException; - if (ex != null) - { - errorRecord = new ErrorRecord(e.InnerException, - "CreateRemoteRunspaceForVMFailed", - ErrorCategory.InvalidArgument, - null); - } - } - + WriteError(errorRecord); } @@ -1180,13 +1246,13 @@ namespace Microsoft.PowerShell.Commands // if (!String.IsNullOrEmpty(ContainerId)) { - connectionInfo = ContainerConnectionInfo.CreateContainerConnectionInfoById(ContainerId, RunAsAdministrator.IsPresent); + connectionInfo = ContainerConnectionInfo.CreateContainerConnectionInfoById(ContainerId, RunAsAdministrator.IsPresent, this.ConfigurationName); } else { Dbg.Assert(!String.IsNullOrEmpty(ContainerName), "Either ContainerId or ContainerName has to be set."); - connectionInfo = ContainerConnectionInfo.CreateContainerConnectionInfoByName(ContainerName, RunAsAdministrator.IsPresent); + connectionInfo = ContainerConnectionInfo.CreateContainerConnectionInfoByName(ContainerName, RunAsAdministrator.IsPresent, this.ConfigurationName); } this.ContainerName = connectionInfo.ComputerName; @@ -1211,6 +1277,31 @@ namespace Microsoft.PowerShell.Commands WriteError(errorRecord); } + catch (PSRemotingDataStructureException e) + { + ErrorRecord errorRecord; + + // + // In case of PSDirectException, we should output the precise error message + // in inner exception instead of the generic one in outer exception. + // + if ((e.InnerException != null) && (e.InnerException is PSDirectException)) + { + errorRecord = new ErrorRecord(e.InnerException, + "CreateRemoteRunspaceForContainerFailed", + ErrorCategory.InvalidOperation, + null); + } + else + { + errorRecord = new ErrorRecord(e, + "CreateRemoteRunspaceForContainerFailed", + ErrorCategory.InvalidOperation, + null); + } + + WriteError(errorRecord); + } catch (Exception e) { ErrorRecord errorRecord = new ErrorRecord(e, diff --git a/src/System.Management.Automation/engine/remoting/commands/getrunspacecommand.cs b/src/System.Management.Automation/engine/remoting/commands/getrunspacecommand.cs index 2495fd630b..c8b5a09b9b 100644 --- a/src/System.Management.Automation/engine/remoting/commands/getrunspacecommand.cs +++ b/src/System.Management.Automation/engine/remoting/commands/getrunspacecommand.cs @@ -117,9 +117,13 @@ namespace Microsoft.PowerShell.Commands private Uri[] uris; /// + /// For WSMan sessions: /// If this parameter is not specified then the value specified in /// the environment variable DEFAULTREMOTESHELLNAME will be used. If /// this is not set as well, then Microsoft.PowerShell is used. + /// + /// For VM/Container sessions: + /// If this parameter is not speficied then all sessions that match other filters are returned. /// [Parameter(ValueFromPipelineByPropertyName = true, ParameterSetName = GetPSSessionCommand.ComputerNameParameterSet)] @@ -129,13 +133,26 @@ namespace Microsoft.PowerShell.Commands ParameterSetName = GetPSSessionCommand.ConnectionUriParameterSet)] [Parameter(ValueFromPipelineByPropertyName = true, ParameterSetName = GetPSSessionCommand.ConnectionUriInstanceIdParameterSet)] + [Parameter(ValueFromPipelineByPropertyName = true, + ParameterSetName = GetPSSessionCommand.ContainerIdParameterSet)] + [Parameter(ValueFromPipelineByPropertyName = true, + ParameterSetName = GetPSSessionCommand.ContainerIdInstanceIdParameterSet)] + [Parameter(ValueFromPipelineByPropertyName = true, + ParameterSetName = GetPSSessionCommand.ContainerNameParameterSet)] + [Parameter(ValueFromPipelineByPropertyName = true, + ParameterSetName = GetPSSessionCommand.ContainerNameInstanceIdParameterSet)] + [Parameter(ValueFromPipelineByPropertyName = true, + ParameterSetName = GetPSSessionCommand.VMIdParameterSet)] + [Parameter(ValueFromPipelineByPropertyName = true, + ParameterSetName = GetPSSessionCommand.VMIdInstanceIdParameterSet)] + [Parameter(ValueFromPipelineByPropertyName = true, + ParameterSetName = GetPSSessionCommand.VMNameParameterSet)] + [Parameter(ValueFromPipelineByPropertyName = true, + ParameterSetName = GetPSSessionCommand.VMNameInstanceIdParameterSet)] public String ConfigurationName { get { return shell; } - set - { - shell = ResolveShell(value); - } + set { shell = value; } } private String shell; @@ -367,6 +384,19 @@ namespace Microsoft.PowerShell.Commands #region Overrides + /// + /// Resolves shellname + /// + protected override void BeginProcessing() + { + base.BeginProcessing(); + + if (ConfigurationName == null) + { + ConfigurationName = string.Empty; + } + } + /// /// Get the list of runspaces from the global cache and write them /// down. If no computername or instance id is specified then @@ -389,7 +419,7 @@ namespace Microsoft.PowerShell.Commands } else { - GetMatchingRunspaces(true, true, this.State); + GetMatchingRunspaces(true, true, this.State, this.ConfigurationName); } } // ProcessRecord diff --git a/src/System.Management.Automation/engine/remoting/commands/newrunspacecommand.cs b/src/System.Management.Automation/engine/remoting/commands/newrunspacecommand.cs index 874aa9a8fe..48cae60f6b 100644 --- a/src/System.Management.Automation/engine/remoting/commands/newrunspacecommand.cs +++ b/src/System.Management.Automation/engine/remoting/commands/newrunspacecommand.cs @@ -164,6 +164,40 @@ namespace Microsoft.PowerShell.Commands } private SwitchParameter enableNetworkAccess; + /// + /// For WSMan sessions: + /// If this parameter is not specified then the value specified in + /// the environment variable DEFAULTREMOTESHELLNAME will be used. If + /// this is not set as well, then Microsoft.PowerShell is used. + /// + /// For VM/Container sessions: + /// If this parameter is not specified then no configuration is used. + /// + [Parameter(ValueFromPipelineByPropertyName = true, + ParameterSetName = NewPSSessionCommand.ComputerNameParameterSet)] + [Parameter(ValueFromPipelineByPropertyName = true, + ParameterSetName = NewPSSessionCommand.UriParameterSet)] + [Parameter(ValueFromPipelineByPropertyName = true, + ParameterSetName = NewPSSessionCommand.ContainerIdParameterSet)] + [Parameter(ValueFromPipelineByPropertyName = true, + ParameterSetName = NewPSSessionCommand.ContainerNameParameterSet)] + [Parameter(ValueFromPipelineByPropertyName = true, + ParameterSetName = NewPSSessionCommand.VMIdParameterSet)] + [Parameter(ValueFromPipelineByPropertyName = true, + ParameterSetName = NewPSSessionCommand.VMNameParameterSet)] + public String ConfigurationName + { + get + { + return shell; + } + set + { + shell = value; + } + } + private String shell; + #endregion Parameters #region Cmdlet Overrides @@ -180,6 +214,20 @@ namespace Microsoft.PowerShell.Commands throttleManager.ThrottleComplete += new EventHandler(HandleThrottleComplete); + if (String.IsNullOrEmpty(ConfigurationName)) + { + if ((ParameterSetName == NewPSSessionCommand.ComputerNameParameterSet) || + (ParameterSetName == NewPSSessionCommand.UriParameterSet)) + { + // set to default value for WSMan session + ConfigurationName = ResolveShell(null); + } + else + { + // convert null to String.Empty for VM/Container session + ConfigurationName = String.Empty; + } + } } // BeginProcessing /// @@ -504,13 +552,13 @@ namespace Microsoft.PowerShell.Commands Action errorWriter = delegate(Cmdlet cmdlet) { // - // In case of PSDirectCredentialException, we should output the precise error message + // In case of PSDirectException, we should output the precise error message // in inner exception instead of the generic one in outer exception. // if ((errorRecord.Exception != null) && (errorRecord.Exception.InnerException != null)) { - PSDirectCredentialException ex = errorRecord.Exception.InnerException as PSDirectCredentialException; + PSDirectException ex = errorRecord.Exception.InnerException as PSDirectException; if (ex != null) { errorRecord = new ErrorRecord(errorRecord.Exception.InnerException, @@ -916,7 +964,7 @@ namespace Microsoft.PowerShell.Commands try { - connectionInfo = new VMConnectionInfo(this.Credential, this.VMId[index], this.VMName[index]); + connectionInfo = new VMConnectionInfo(this.Credential, this.VMId[index], this.VMName[index], this.ConfigurationName); runspace = new RemoteRunspace(Utils.GetTypeTableFromExecutionContextTLS(), connectionInfo, this.Host, null, rsName, rsId); @@ -992,11 +1040,11 @@ namespace Microsoft.PowerShell.Commands // if (isContainerIdSet) { - connectionInfo = ContainerConnectionInfo.CreateContainerConnectionInfoById(input, RunAsAdministrator.IsPresent); + connectionInfo = ContainerConnectionInfo.CreateContainerConnectionInfoById(input, RunAsAdministrator.IsPresent, this.ConfigurationName); } else { - connectionInfo = ContainerConnectionInfo.CreateContainerConnectionInfoByName(input, RunAsAdministrator.IsPresent); + connectionInfo = ContainerConnectionInfo.CreateContainerConnectionInfoByName(input, RunAsAdministrator.IsPresent, this.ConfigurationName); } resolvedNameList.Add(connectionInfo.ComputerName); diff --git a/src/System.Management.Automation/engine/remoting/common/RemoteSessionHyperVSocket.cs b/src/System.Management.Automation/engine/remoting/common/RemoteSessionHyperVSocket.cs index e8abe1308c..044d7e5403 100644 --- a/src/System.Management.Automation/engine/remoting/common/RemoteSessionHyperVSocket.cs +++ b/src/System.Management.Automation/engine/remoting/common/RemoteSessionHyperVSocket.cs @@ -30,33 +30,21 @@ namespace System.Management.Automation.Remoting #region Members private System.Net.Sockets.AddressFamily m_AddressFamily; - private HyperVSocketFlag m_Flag; private Guid m_VmId; private Guid m_ServiceId; public const System.Net.Sockets.AddressFamily AF_HYPERV = (System.Net.Sockets.AddressFamily)34; public const int HYPERV_SOCK_ADDR_SIZE = 36; - /// - /// Supported values of m_Flag. - /// - public enum HyperVSocketFlag - { - VM = 0, - HyperVContainer = 1 - } - #endregion #region Constructor public HyperVSocketEndPoint(System.Net.Sockets.AddressFamily AddrFamily, - HyperVSocketFlag Flag, Guid VmId, Guid ServiceId) { m_AddressFamily = AddrFamily; - m_Flag = Flag; m_VmId = VmId; m_ServiceId = ServiceId; } @@ -66,16 +54,6 @@ namespace System.Management.Automation.Remoting get { return m_AddressFamily; } } - /// - /// If Flag is 0, the socket connection is for VM. - /// If Flag is 1, the socket connection is for Hyper-V container. - /// - public HyperVSocketFlag Flag - { - get { return m_Flag; } - set { m_Flag = value; } - } - public Guid VmId { get { return m_VmId; } @@ -101,11 +79,10 @@ namespace System.Management.Automation.Remoting return null; } - HyperVSocketEndPoint endpoint = new HyperVSocketEndPoint(SockAddr.Family, 0, Guid.Empty, Guid.Empty); + HyperVSocketEndPoint endpoint = new HyperVSocketEndPoint(SockAddr.Family, Guid.Empty, Guid.Empty); string sockAddress = SockAddr.ToString(); - endpoint.Flag = (HyperVSocketFlag)short.Parse(sockAddress.Substring(2, 2), CultureInfo.InvariantCulture); endpoint.VmId = new Guid(sockAddress.Substring(4, 16)); endpoint.ServiceId = new Guid(sockAddress.Substring(20, 16)); @@ -122,7 +99,6 @@ namespace System.Management.Automation.Remoting } if ((m_AddressFamily == endpoint.AddressFamily) && - (m_Flag == endpoint.Flag) && (m_VmId == endpoint.VmId) && (m_ServiceId == endpoint.ServiceId)) { @@ -144,7 +120,7 @@ namespace System.Management.Automation.Remoting byte[] vmId = m_VmId.ToByteArray(); byte[] serviceId = m_ServiceId.ToByteArray(); - sockAddress[2] = (byte)m_Flag; + sockAddress[2] = (byte)0; for (int i = 0; i < vmId.Length; i++) { @@ -161,7 +137,7 @@ namespace System.Management.Automation.Remoting public override string ToString() { - return ((ushort)m_Flag).ToString(CultureInfo.InvariantCulture) + m_VmId.ToString() + m_ServiceId.ToString(); + return m_VmId.ToString() + m_ServiceId.ToString(); } #endregion @@ -288,7 +264,7 @@ namespace System.Management.Automation.Remoting // TODO: remove below 6 lines of code when .NET supports Hyper-V socket duplication Guid serviceId = new Guid("a5201c21-2770-4c11-a68e-f182edb29220"); // HV_GUID_VM_SESSION_SERVICE_ID_2 - HyperVSocketEndPoint endpoint = new HyperVSocketEndPoint(HyperVSocketEndPoint.AF_HYPERV, 0, Guid.Empty, serviceId); + HyperVSocketEndPoint endpoint = new HyperVSocketEndPoint(HyperVSocketEndPoint.AF_HYPERV, Guid.Empty, serviceId); Socket listenSocket = new Socket(endpoint.AddressFamily, SocketType.Stream, (System.Net.Sockets.ProtocolType)1); listenSocket.Bind(endpoint); @@ -390,6 +366,13 @@ namespace System.Management.Automation.Remoting #endregion + #region constants in hvsocket.h + + public const int HV_PROTOCOL_RAW = 1; + public const int HVSOCKET_CONTAINER_PASSTHRU = 2; + + #endregion + #region Properties /// @@ -464,11 +447,31 @@ namespace System.Management.Automation.Remoting serviceId = new Guid("a5201c21-2770-4c11-a68e-f182edb29220"); } - _endPoint = new HyperVSocketEndPoint(HyperVSocketEndPoint.AF_HYPERV, - isContainer ? HyperVSocketEndPoint.HyperVSocketFlag.HyperVContainer : HyperVSocketEndPoint.HyperVSocketFlag.VM, - vmId, serviceId); - + _endPoint = new HyperVSocketEndPoint(HyperVSocketEndPoint.AF_HYPERV, vmId, serviceId); + _socket = new Socket(_endPoint.AddressFamily, SocketType.Stream, (System.Net.Sockets.ProtocolType)1); + + // + // We need to call SetSocketOption() in order to set up Hyper-V socket connection between container host and Hyper-V container. + // Here is the scenario: the Hyper-V container is inside a utility vm, which is inside the container host + // + if (isContainer) + { + var value = new byte[sizeof(uint)]; + value[0] = 1; + + try + { + _socket.SetSocketOption((System.Net.Sockets.SocketOptionLevel)HV_PROTOCOL_RAW, + (System.Net.Sockets.SocketOptionName)HVSOCKET_CONTAINER_PASSTHRU, + (byte[])value); + } + catch + { + throw new PSDirectException( + PSRemotingErrorInvariants.FormatResourceString(RemotingErrorIdStrings.RemoteSessionHyperVSocketClientConstructorSetSocketOptionFailure)); + } + } } #endregion @@ -522,9 +525,11 @@ namespace System.Management.Automation.Remoting /// connection occurs or the timeout time has ellapsed. /// /// The credential used for authentication - /// Whether this is the first connection + /// The configuration name of the PS session + /// Whether this is the first connection public bool Connect( NetworkCredential networkCredential, + string configurationName, bool isFirstConnection) { bool result = false; @@ -555,11 +560,8 @@ namespace System.Management.Automation.Remoting null); } - bool emptyPassword = false; - if (String.IsNullOrEmpty(networkCredential.Password)) - { - emptyPassword = true; - } + bool emptyPassword = String.IsNullOrEmpty(networkCredential.Password); + bool emptyConfiguration = String.IsNullOrEmpty(configurationName); Byte[] domain = Encoding.Unicode.GetBytes(networkCredential.Domain); Byte[] userName = Encoding.Unicode.GetBytes(networkCredential.UserName); @@ -585,7 +587,6 @@ namespace System.Management.Automation.Remoting { _socket.Send(Encoding.ASCII.GetBytes("EMPTYPW")); _socket.Receive(response); - _socket.Send(response); responseString = Encoding.ASCII.GetString(response); } else @@ -595,18 +596,49 @@ namespace System.Management.Automation.Remoting _socket.Send(password); _socket.Receive(response); - _socket.Send(response); responseString = Encoding.ASCII.GetString(response); } + // + // There are 3 cases for the responseString received above. + // - "FAIL": credential is invalid + // - "PASS": credentail is valid, but PowerShell Direct in VM does not support configuration (Server 2016 TP4 and before) + // - "CONF": credentail is valid, and PowerShell Direct in VM supports configuration (Server 2016 TP5 and later) + // + // // Credential is invalid. // if (String.Compare(responseString, "FAIL", StringComparison.Ordinal) == 0) { - throw new PSDirectCredentialException( + _socket.Send(response); + + throw new PSDirectException( PSRemotingErrorInvariants.FormatResourceString(RemotingErrorIdStrings.InvalidCredential)); } + + // + // If PowerShell Direct in VM supports configuration, send configuration name. + // + if (String.Compare(responseString, "CONF", StringComparison.Ordinal) == 0) + { + if (emptyConfiguration) + { + _socket.Send(Encoding.ASCII.GetBytes("EMPTYCF")); + } + else + { + _socket.Send(Encoding.ASCII.GetBytes("NONEMPTYCF")); + _socket.Receive(response); + + Byte[] configName = Encoding.Unicode.GetBytes(configurationName); + _socket.Send(configName); + } + } + else + { + _socket.Send(response); + } } _streamReader = new StreamReader(_networkStream); diff --git a/src/System.Management.Automation/engine/remoting/common/RemoteSessionNamedPipe.cs b/src/System.Management.Automation/engine/remoting/common/RemoteSessionNamedPipe.cs index d6b155e470..0c6aaa43e0 100644 --- a/src/System.Management.Automation/engine/remoting/common/RemoteSessionNamedPipe.cs +++ b/src/System.Management.Automation/engine/remoting/common/RemoteSessionNamedPipe.cs @@ -320,6 +320,7 @@ namespace System.Management.Automation.Remoting private readonly object _syncObject; private bool _disposed; private bool _listenerRunning; + private string _configurationName; private StreamReader _streamReader; private StreamWriter _streamWriter; private PowerShellTraceSource _tracer = PowerShellTraceSourceFactory.GetTraceSource(); @@ -366,6 +367,15 @@ namespace System.Management.Automation.Remoting get { return _listenerRunning; } } + /// + /// Name of session configuration. + /// + public string ConfigurationName + { + get { return _configurationName; } + set { _configurationName = value; } + } + /// /// Accessor for the named pipe reader. /// @@ -795,7 +805,8 @@ namespace System.Management.Automation.Remoting /// This method supports PowerShell running in "NamedPipeServerMode", which is used for /// PowerShell Direct Windows Server Container connection and management. /// - internal static void RunServerMode() + /// name of the configuration to use + internal static void RunServerMode(string configurationName) { IPCNamedPipeServerEnabled = true; CreateIPCNamedPipeServerSingleton(); @@ -805,6 +816,8 @@ namespace System.Management.Automation.Remoting throw new RuntimeException(RemotingErrorIdStrings.NamedPipeServerCannotStart); } + IPCNamedPipeServer.ConfigurationName = configurationName; + ManualResetEventSlim clientConnectionEnded = new ManualResetEventSlim(false); IPCNamedPipeServer.ListenerEnded -= OnIPCNamedPipeServerEnded; IPCNamedPipeServer.ListenerEnded += (sender, e) => @@ -1172,8 +1185,7 @@ namespace System.Management.Automation.Remoting int lastError = Marshal.GetLastWin32Error(); if (pipeHandle.IsInvalid) { - throw new PSInvalidOperationException( - StringUtil.Format(RemotingErrorIdStrings.CannotConnectNamedPipe, lastError)); + throw new System.ComponentModel.Win32Exception(lastError); } try diff --git a/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs b/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs index 21841a8d26..d6368c285c 100644 --- a/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs +++ b/src/System.Management.Automation/engine/remoting/common/RunspaceConnectionInfo.cs @@ -1971,6 +1971,7 @@ namespace System.Management.Automation.Runspaces private const int _defaultOpenTimeout = 20000; /* 20 seconds. */ private Guid _vmGuid; private string _vmName; + private string _configurationName; #endregion @@ -1985,6 +1986,15 @@ namespace System.Management.Automation.Runspaces set { _vmGuid = value; } } + /// + /// Configuration name of the VM session. + /// + public string ConfigurationName + { + get { return _configurationName; } + set { _configurationName = value; } + } + #endregion #region Overrides @@ -2047,7 +2057,7 @@ namespace System.Management.Automation.Runspaces internal override RunspaceConnectionInfo InternalCopy() { - VMConnectionInfo result = new VMConnectionInfo(Credential, VMGuid, ComputerName); + VMConnectionInfo result = new VMConnectionInfo(Credential, VMGuid, ComputerName, ConfigurationName); return result; } @@ -2057,7 +2067,8 @@ namespace System.Management.Automation.Runspaces this, instanceId, cryptoHelper, - VMGuid); + VMGuid, + ConfigurationName); } #endregion @@ -2070,12 +2081,14 @@ namespace System.Management.Automation.Runspaces internal VMConnectionInfo( PSCredential credential, Guid vmGuid, - string vmName) + string vmName, + string configurationName) : base() { Credential = credential; VMGuid = vmGuid; ComputerName = vmName; + ConfigurationName = configurationName; AuthenticationMechanism = AuthenticationMechanism.Default; OpenTimeout = _defaultOpenTimeout; @@ -2224,9 +2237,10 @@ namespace System.Management.Automation.Runspaces /// public static ContainerConnectionInfo CreateContainerConnectionInfoById( string containerId, - bool runAsAdmin) + bool runAsAdmin, + string configurationName) { - ContainerProcess containerProc = new ContainerProcess(containerId, null, 0, runAsAdmin); + ContainerProcess containerProc = new ContainerProcess(containerId, null, 0, runAsAdmin, configurationName); return new ContainerConnectionInfo(containerProc); } @@ -2236,9 +2250,10 @@ namespace System.Management.Automation.Runspaces /// public static ContainerConnectionInfo CreateContainerConnectionInfoByName( string containerName, - bool runAsAdmin) + bool runAsAdmin, + string configurationName) { - ContainerProcess containerProc = new ContainerProcess(null, containerName, 0, runAsAdmin); + ContainerProcess containerProc = new ContainerProcess(null, containerName, 0, runAsAdmin, configurationName); return new ContainerConnectionInfo(containerProc); } @@ -2277,6 +2292,7 @@ namespace System.Management.Automation.Runspaces private string containerName; private int processId; private bool runAsAdmin = false; + private string configurationName; private bool processTerminated = false; private uint errorCode = 0; private string errorMessage = string.Empty; @@ -2339,6 +2355,15 @@ namespace System.Management.Automation.Runspaces set { runAsAdmin = value; } } + /// + /// The configuration name of the container session. + /// + internal string ConfigurationName + { + get { return configurationName; } + set { configurationName = value; } + } + /// /// Whether the process in container has terminated. /// @@ -2388,12 +2413,13 @@ namespace System.Management.Automation.Runspaces /// /// Creates an instance used for PowerShell Direct for container. /// - public ContainerProcess(string containerId, string containerName, int processId, bool runAsAdmin) + public ContainerProcess(string containerId, string containerName, int processId, bool runAsAdmin, string configurationName) { this.ContainerId = containerId; this.ContainerName = containerName; this.ProcessId = processId; this.RunAsAdmin = runAsAdmin; + this.ConfigurationName = configurationName; if (!String.IsNullOrEmpty(containerId)) { @@ -2565,8 +2591,9 @@ namespace System.Management.Automation.Runspaces // Windows Server container (i.e., RuntimeId is empty) uses named pipe transport for now. // cmd = string.Format(System.Globalization.CultureInfo.InvariantCulture, - @"{{""CommandLine"": ""powershell.exe {0} -NoLogo"",""RestrictedToken"": {1}}}", + @"{{""CommandLine"": ""powershell.exe {0} -NoLogo {1}"",""RestrictedToken"": {2}}}", (RuntimeId != Guid.Empty) ? "-so -NoProfile" : "-NamedPipeServerMode", + String.IsNullOrEmpty(ConfigurationName) ? String.Empty : String.Concat("-Config ", ConfigurationName), (RunAsAdmin) ? "false" : "true"); // diff --git a/src/System.Management.Automation/engine/remoting/common/remotingexceptions.cs b/src/System.Management.Automation/engine/remoting/common/remotingexceptions.cs index 08243db3e3..fbb37fb8eb 100644 --- a/src/System.Management.Automation/engine/remoting/common/remotingexceptions.cs +++ b/src/System.Management.Automation/engine/remoting/common/remotingexceptions.cs @@ -231,6 +231,7 @@ namespace System.Management.Automation.Remoting InvalidContainerNameMultiple = 971, InvalidContainerNameNotExist = 972, ContainerSessionConnectFailed = 973, + RemoteSessionHyperVSocketClientConstructorSetSocketOptionFailure = 974, // Invoke-Command related error codes. InvalidVMIdNotSingle = 981, @@ -698,10 +699,10 @@ namespace System.Management.Automation.Remoting } /// - /// This exception is used by PowerShell Direct for credential related error. + /// This exception is used by PowerShell Direct errors. /// [Serializable] - public class PSDirectCredentialException : RuntimeException + public class PSDirectException : RuntimeException { #region Constructor @@ -711,7 +712,7 @@ namespace System.Management.Automation.Remoting /// /// A localized string as an error message. /// - public PSDirectCredentialException(string message) + public PSDirectException(string message) : base(message) { } diff --git a/src/System.Management.Automation/engine/remoting/fanin/OutOfProcTransportManager.cs b/src/System.Management.Automation/engine/remoting/fanin/OutOfProcTransportManager.cs index c76caf9f51..cf7e5d7eab 100644 --- a/src/System.Management.Automation/engine/remoting/fanin/OutOfProcTransportManager.cs +++ b/src/System.Management.Automation/engine/remoting/fanin/OutOfProcTransportManager.cs @@ -1264,6 +1264,7 @@ namespace System.Management.Automation.Remoting.Client #region Private Data private Guid _vmGuid; + private string _configurationName; private VMConnectionInfo _connectionInfo; private NetworkCredential _networkCredential; @@ -1275,7 +1276,8 @@ namespace System.Management.Automation.Remoting.Client VMConnectionInfo connectionInfo, Guid runspaceId, PSRemotingCryptoHelper cryptoHelper, - Guid vmGuid) + Guid vmGuid, + string configurationName) : base(runspaceId, cryptoHelper) { if (connectionInfo == null) @@ -1285,6 +1287,7 @@ namespace System.Management.Automation.Remoting.Client _connectionInfo = connectionInfo; _vmGuid = vmGuid; + _configurationName = configurationName; if (connectionInfo.Credential == null) { @@ -1307,7 +1310,7 @@ namespace System.Management.Automation.Remoting.Client internal override void CreateAsync() { _client = new RemoteSessionHyperVSocketClient(_vmGuid, true); - if (!_client.Connect(_networkCredential, true)) + if (!_client.Connect(_networkCredential, _configurationName, true)) { _client.Dispose(); throw new PSInvalidOperationException( @@ -1321,7 +1324,7 @@ namespace System.Management.Automation.Remoting.Client // TODO: remove below 3 lines when Hyper-V socket duplication is supported in .NET framework. _client.Dispose(); _client = new RemoteSessionHyperVSocketClient(_vmGuid, false); - if (!_client.Connect(_networkCredential, false)) + if (!_client.Connect(_networkCredential, _configurationName, false)) { _client.Dispose(); throw new PSInvalidOperationException( @@ -1380,7 +1383,7 @@ namespace System.Management.Automation.Remoting.Client internal override void CreateAsync() { _client = new RemoteSessionHyperVSocketClient(_targetGuid, false, true); - if (!_client.Connect(null, false)) + if (!_client.Connect(null, String.Empty, false)) { _client.Dispose(); throw new PSInvalidOperationException( @@ -1426,9 +1429,7 @@ namespace System.Management.Automation.Remoting.Client } _connectionInfo = connectionInfo; - _threadName = threadName; - Fragmentor.FragmentSize = RemoteSessionNamedPipeServer.NamedPipeBufferSizeForRemoting; } diff --git a/src/System.Management.Automation/engine/remoting/server/OutOfProcServerMediator.cs b/src/System.Management.Automation/engine/remoting/server/OutOfProcServerMediator.cs index b8500955a1..cddb2a7682 100644 --- a/src/System.Management.Automation/engine/remoting/server/OutOfProcServerMediator.cs +++ b/src/System.Management.Automation/engine/remoting/server/OutOfProcServerMediator.cs @@ -552,7 +552,7 @@ namespace System.Management.Automation.Remoting.Server // AppDomain is not available in CoreCLR AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(AppDomainUnhandledException); #endif - SingletonInstance.Start(initialCommand); + SingletonInstance.Start(initialCommand, namedPipeServer.ConfigurationName); } #endregion diff --git a/src/System.Management.Automation/help/CommandHelpProvider.cs b/src/System.Management.Automation/help/CommandHelpProvider.cs index 4f9cc48a72..3fd527cd8c 100644 --- a/src/System.Management.Automation/help/CommandHelpProvider.cs +++ b/src/System.Management.Automation/help/CommandHelpProvider.cs @@ -480,33 +480,8 @@ namespace System.Management.Automation /// private readonly Hashtable _helpFiles = new Hashtable(); - /// - /// Finds a help file associated with the given cmdlet - /// - /// - /// - private string FindHelpFile(CmdletInfo cmdletInfo) + private string GetHelpFile(string helpFile, CmdletInfo cmdletInfo) { - if (cmdletInfo == null) - { - throw PSTraceSource.NewArgumentNullException("cmdletInfo"); - } - - string helpFile = cmdletInfo.HelpFile; - - if (String.IsNullOrEmpty(helpFile)) - { - if (cmdletInfo.Module != null) - { - if (InitialSessionState.IsEngineModule(cmdletInfo.Module.Name)) - { - return System.IO.Path.Combine(cmdletInfo.Module.ModuleBase, CultureInfo.CurrentCulture.Name, engineModuleHelpFileCache[cmdletInfo.Module.Name]); - } - } - - return helpFile; - } - string helpFileToLoad = helpFile; // Get the mshsnapinfo object for this cmdlet. @@ -560,6 +535,80 @@ namespace System.Management.Automation return location; } + /// + /// Finds a help file associated with the given cmdlet + /// + /// + /// + private string FindHelpFile(CmdletInfo cmdletInfo) + { + if (cmdletInfo == null) + { + throw PSTraceSource.NewArgumentNullException("cmdletInfo"); + } + + // Get the help file name from the cmdlet metadata + string helpFile = cmdletInfo.HelpFile; + + if (String.IsNullOrEmpty(helpFile)) + { + if (cmdletInfo.Module != null) + { + if (InitialSessionState.IsEngineModule(cmdletInfo.Module.Name)) + { + return System.IO.Path.Combine(cmdletInfo.Module.ModuleBase, CultureInfo.CurrentCulture.Name, engineModuleHelpFileCache[cmdletInfo.Module.Name]); + } + } + + return helpFile; + } + + // This is the path to the help file. + string location = null; + + if (helpFile.EndsWith(".ni.dll-Help.xml")) + { + // For PowerShell on OneCore, we ship Ngen binaries. As a result, the name of the assembly now contains '.ni' on it, + // e.g., .ni.dll as supposed to .dll. + + // When cmdlet metadata is generated for the 'HelpFile' field, we use the name assembly and we append '-Help.xml' to it. + // Because of this, if the cmdlet is part of an N’gen assembly, then 'HelpFile' field will be pointing to a help file which does not exist. + // If this is the case, we remove '.ni' from the help file name and try again. + // For example: + // Ngen assembly name: Microsoft.PowerShell.Commands.Management.ni.dll + // Cmdlet metadata 'HelpFile': Microsoft.PowerShell.Commands.Management.ni.dll-Help.xml + // Actual help file name: Microsoft.PowerShell.Commands.Management.dll-Help.xml + + // Make sure that the assembly name contains more than '.ni.dll' + string assemblyName = helpFile.Replace(".ni.dll-Help.xml", ""); + + if (!String.IsNullOrEmpty(assemblyName)) + { + // In the first try, we remove '.ni' from the assembly name and we attempt to find the corresponding help file. + string helpFileName = cmdletInfo.HelpFile.Replace(".ni.dll-Help.xml", ".dll-Help.xml"); + location = GetHelpFile(helpFileName, cmdletInfo); + + if (String.IsNullOrEmpty(location)) + { + // If the help file could not be found, then it is possible that the actual assembly name is something like + // .ni.dll, e.g., MyAsembly.ni.dll, so let’s try to find the original help file in the cmdlet metadata. + location = GetHelpFile(helpFile, cmdletInfo); + } + } + else + { + // the assembly name is actually '.ni.dll'. + location = GetHelpFile(helpFile, cmdletInfo); + } + } + else + { + location = GetHelpFile(helpFile, cmdletInfo); + } + + return location; + } + private void LoadHelpFile(string helpFile, string helpFileIdentifier, string commandName, bool reportErrors) { Exception e = null; diff --git a/src/System.Management.Automation/project.json b/src/System.Management.Automation/project.json index b1a8470c43..cb230fb51d 100644 --- a/src/System.Management.Automation/project.json +++ b/src/System.Management.Automation/project.json @@ -81,6 +81,6 @@ }, "compile": [ - "../windows-build/gen/SYS_AUTO/*.cs" + "../windows-build/gen/System.Management.Automation/*.cs" ] } diff --git a/src/System.Management.Automation/resources/DiscoveryExceptions.resx b/src/System.Management.Automation/resources/DiscoveryExceptions.resx index 69bbd10214..f920bd4e71 100644 --- a/src/System.Management.Automation/resources/DiscoveryExceptions.resx +++ b/src/System.Management.Automation/resources/DiscoveryExceptions.resx @@ -185,7 +185,7 @@ The #requires statement must be in one of the following formats: The script '{0}' cannot be run because it contained a "#requires" statement for Windows PowerShell {1}. The version of Windows PowerShell that is required by the script does not match the currently running version of Windows PowerShell {2}. - The script '{0}' cannot be run because it contained a "#requires" statement for PowerShell {1} edition. The edition of PowerShell that is required by the script does not match the currently running PowerShell {2} edition. + The script '{0}' cannot be run because it contained a "#requires" statement for PowerShell editions '{1}'. The edition of PowerShell that is required by the script does not match the currently running PowerShell {2} edition. The script '{0}' cannot be run because the following snap-ins that are specified by the "#requires" statements of the script are missing: {1}. diff --git a/src/System.Management.Automation/resources/modules.resx b/src/System.Management.Automation/resources/Modules.resx similarity index 99% rename from src/System.Management.Automation/resources/modules.resx rename to src/System.Management.Automation/resources/Modules.resx index 0275e9394c..e3d9d77d19 100644 --- a/src/System.Management.Automation/resources/modules.resx +++ b/src/System.Management.Automation/resources/Modules.resx @@ -214,6 +214,9 @@ The module manifest '{0}' is specified with the CompatiblePSEditions key which is supported only on PowerShell version '5.1' or higher. Update the value of the PowerShellVersion key to '5.1' or higher, and try again. + + The specified value '{0}' for CompatiblePSEditions contains duplicate PowerShell Edition names. Try again after removing the duplicate PowerShell Edition names. + Version specified in ModuleVersion key is equal to version folder name. diff --git a/src/System.Management.Automation/resources/MshSnapinCmdletResources.resx b/src/System.Management.Automation/resources/MshSnapInCmdletResources.resx similarity index 100% rename from src/System.Management.Automation/resources/MshSnapinCmdletResources.resx rename to src/System.Management.Automation/resources/MshSnapInCmdletResources.resx diff --git a/src/System.Management.Automation/resources/ParserStrings.resx b/src/System.Management.Automation/resources/ParserStrings.resx index 77d242b029..ba99c3d0da 100644 --- a/src/System.Management.Automation/resources/ParserStrings.resx +++ b/src/System.Management.Automation/resources/ParserStrings.resx @@ -921,6 +921,12 @@ Possible matches are The argument for the Version parameter is not valid. Specify a valid Windows PowerShell version, in the format major.minor version. + + The argument for the {0} parameter is not valid. Specify a valid PowerShell edition. + + + The argument for the {0} parameter contains duplicate values. Do not specify duplicate PowerShell edition values. + Wildcard characters are not supported for module names. @@ -1008,7 +1014,7 @@ Possible matches are A second CIM class definition for '{0}' was found while processing the schema file '{1}'. This class was already defined in the file(s) '{2}'. Remove the redundant definition, and then try again. - Keyword '{0}' already defined in the configuration. + Resource name '{0}' is already being used by another Resource or Configuration. The class name '{0}' does not match '{1}', the name of the file in which it is defined. Rename either the file name to match the class name or vice versa @@ -1060,7 +1066,7 @@ ModuleVersion : Version of module to import. If used, ModuleName must represent Configuration keyword is not allowed in constrainedLanguage mode. - The configuration name '{0}' is not valid. Standard names may only contain letters (a-z, A-Z), numbers (0-9), and underscore (_). The name may not be null or empty, and should start with a letter. + The configuration name '{0}' is not valid. Standard names may only contain letters (a-z, A-Z), numbers (0-9), period (.), hyphen (-) and underscore (_). The name may not be null or empty, and should start with a letter. Configuration only supports the End block in its body. Begin, Process and DynamicParam blocks are not allowed in a configuration. diff --git a/src/System.Management.Automation/resources/remotingerroridstrings.resx b/src/System.Management.Automation/resources/RemotingErrorIdStrings.resx similarity index 99% rename from src/System.Management.Automation/resources/remotingerroridstrings.resx rename to src/System.Management.Automation/resources/RemotingErrorIdStrings.resx index 99e9acb4b4..74aaef4594 100644 --- a/src/System.Management.Automation/resources/remotingerroridstrings.resx +++ b/src/System.Management.Automation/resources/RemotingErrorIdStrings.resx @@ -1240,6 +1240,9 @@ All WinRM sessions connected to Windows PowerShell session configurations, such Network connectivity to {0} has been lost and the reconnection attempt failed. Please repair the network connection and reconnect using Connect-PSSession or Receive-PSSession. + + Failed to create an instance of RemoteSessionHyperVSocketClient due to SetSocketOption failure. + Failed to create an instance of RemoteSessionHyperVSocketServer. @@ -1435,7 +1438,7 @@ All WinRM sessions connected to Windows PowerShell session configurations, such {0}[{1}]: {2} - Unable to connect to application domain name {0} of process {1}. + Unable to connect to application domain name {0} of process {1}. Error: {2}. PowerShell plugin cannot process the Connect operation as required negotiation information is either missing or not complete. @@ -1515,9 +1518,6 @@ All WinRM sessions connected to Windows PowerShell session configurations, such Remote transport error: {0} - - Unable to open pipe connection for PowerShell IPC. Error code: {0}. - Unable to open pipe connection for PowerShell in container. Error code: {0}. diff --git a/src/windows-build b/src/windows-build index 4ea0fb9670..e6bf85694a 160000 --- a/src/windows-build +++ b/src/windows-build @@ -1 +1 @@ -Subproject commit 4ea0fb9670bfb1d659c7916387bc4f8cfb08dab5 +Subproject commit e6bf85694ae8352d77175c4c7d304946e018808c