Merge pull request #762 from PowerShell/vors/master

Add changes from source-depot branch and Start-ResGen
This commit is contained in:
Sergei Vorobev
2016-04-04 17:12:04 -07:00
42 changed files with 1055 additions and 258 deletions
+108
View File
@@ -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 = @'
//------------------------------------------------------------------------------
// <auto-generated>
// 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.
// </auto-generated>
//------------------------------------------------------------------------------
using System;
using System.Reflection;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
[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}() {{
}}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[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;
}}
}}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {{
get {{
return resourceCulture;
}}
set {{
resourceCulture = value;
}}
}}
{2}
}}
'@
$entry = @'
/// <summary>
/// Looks up a localized string similar to {1}
/// </summary>
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
}
+3 -3
View File
@@ -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",
@@ -36,5 +36,5 @@
}
},
"compile": [ "../windows-build/gen/COMMANDS_MANAGEMENT/*.cs" ]
"compile": [ "../windows-build/gen/Microsoft.PowerShell.Commands.Management/*.cs" ]
}
@@ -2507,21 +2507,25 @@ function Get-PSImplicitRemotingSession
// index 0 - "-VMId <vm id>" (VMId is used instead of VMName due to its uniqueness)
// index 1 - VM credential
// index 2 - "-ConfigurationName <configuration name>" or empty string
private const string NewVMRunspaceTemplate = @"
$(
& $script:NewPSSession `
{0} `
{1} `
{2} `
)
";
// index 0 - "-ContainerId <container id>" (ContainerId is used instead of ContainerName due to its uniqueness)
// index 1 - "-RunAsAdministrator" or empty string
// index 2 - "-ConfigurationName <configuration name>" 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
{
@@ -44,5 +44,5 @@
}
},
"compile": [ "../windows-build/gen/COMMANDS_UTILITY/*.cs" ]
"compile": [ "../windows-build/gen/Microsoft.PowerShell.Commands.Utility/*.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)
@@ -26,6 +26,6 @@
},
"compile": [
"../windows-build/gen/CONSOLE_HOST/*.cs"
"../windows-build/gen/Microsoft.PowerShell.ConsoleHost/*.cs"
]
}
@@ -31,5 +31,5 @@
}
},
"compile": [ "../windows-build/gen/CORECLR_EVENTING/*.cs" ]
"compile": [ "../windows-build/gen/Microsoft.PowerShell.CoreCLR.Eventing/*.cs" ]
}
@@ -23,5 +23,5 @@
}
},
"compile": [ "../windows-build/gen/SECURITY/*.cs" ]
"compile": [ "../windows-build/gen/Microsoft.PowerShell.Security/*.cs" ]
}
@@ -999,6 +999,25 @@ namespace Microsoft.PowerShell.DesiredStateConfiguration.Internal
return ClassCache.Values.ToList();
}
/// <summary>
/// Find cached cim classes defined under specified module
/// </summary>
/// <param name="module"></param>
/// <returns>List of cached cim classes</returns>
public static List<Microsoft.Management.Infrastructure.CimClass> GetCachedClassesForModule(PSModuleInfo module)
{
List<Microsoft.Management.Infrastructure.CimClass> cachedClasses = new List<Microsoft.Management.Infrastructure.CimClass>();
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;
}
/// <summary>
/// Get the file that defined this class.
/// </summary>
@@ -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("};");
}
/// <summary>
/// Gets the line no for DSC Class Resource Get/Set/Test methods
/// </summary>
/// <param name="typeDefinitionAst"></param>
/// <param name="methodsLinePosition"></param>
private static bool GetResourceMethodsLineNumber(TypeDefinitionAst typeDefinitionAst, out Dictionary<string, int> methodsLinePosition)
{
const string getMethodName = "Get";
const string setMethodName = "Set";
const string testMethodName = "Test";
methodsLinePosition = new Dictionary<string, int>(); ;
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);
}
/// <summary>
/// Gets the line no for DSC Class Resource Get/Set/Test methods
/// </summary>
/// <param name="moduleInfo"></param>
/// <param name="resourceName"></param>
/// <param name="resourceMethodsLinePosition"></param>
/// <param name="resourceFilePath"></param>
public static bool GetResourceMethodsLinePosition(PSModuleInfo moduleInfo, string resourceName, out Dictionary<string, int> resourceMethodsLinePosition, out string resourceFilePath)
{
resourceMethodsLinePosition = null;
resourceFilePath = string.Empty;
if (moduleInfo == null || string.IsNullOrEmpty(resourceName))
{
return false;
}
IEnumerable<Ast> resourceDefinitions;
List<string> moduleFiles = new List<string>();
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<object> embeddedInstanceTypes, TypeDefinitionAst typeDefinitionAst, string className)
{
foreach (var member in typeDefinitionAst.Members)
@@ -2318,15 +2428,14 @@ namespace Microsoft.PowerShell.DesiredStateConfiguration.Internal
///
/// </summary>
/// <param name="fileName"></param>
/// <param name="module"></param>
/// <param name="resourcesToImport"></param>
/// <param name="resourcesFound"></param>
/// <param name="functionsToDefine"></param>
/// <param name="resourceDefinitions"></param>
/// <param name="errorList"></param>
/// <param name="extent"></param>
/// <returns></returns>
static bool ImportKeywordsFromScriptFile(string fileName, PSModuleInfo module, ICollection<string> resourcesToImport, ICollection<string> resourcesFound, Dictionary<string, ScriptBlock> functionsToDefine, List<ParseError> errorList, IScriptExtent extent)
private static bool GetResourceDefinitionsFromModule (string fileName, out IEnumerable<Ast> resourceDefinitions, List<ParseError> 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<String> errorMessages = new List<string>();
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;
}
/// <summary>
///
/// </summary>
/// <param name="fileName"></param>
/// <param name="module"></param>
/// <param name="resourcesToImport"></param>
/// <param name="resourcesFound"></param>
/// <param name="functionsToDefine"></param>
/// <param name="errorList"></param>
/// <param name="extent"></param>
/// <returns></returns>
static bool ImportKeywordsFromScriptFile(string fileName, PSModuleInfo module, ICollection<string> resourcesToImport, ICollection<string> resourcesFound, Dictionary<string, ScriptBlock> functionsToDefine, List<ParseError> errorList, IScriptExtent extent)
{
IEnumerable<Ast> resourceDefinitions;
if(!GetResourceDefinitionsFromModule(fileName, out resourceDefinitions, errorList, extent))
{
return false;
}
var result = false;
var parser = new CimDSCParser(MyClassCallback);
@@ -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;
}
}
}
@@ -383,12 +383,12 @@ namespace System.Management.Automation
}
}
internal string RequiresPSEdition
internal IEnumerable<string> RequiresPSEditions
{
get
{
var data = GetRequiresData();
return data == null ? null : data.RequiredPSEdition;
return data == null ? null : data.RequiredPSEditions;
}
}
@@ -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)
@@ -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
/// </summary>
[Parameter(ParameterSetName = ParameterSet_AvailableLocally)]
[Parameter(ParameterSetName = ParameterSet_AvailableInPsrpSession)]
[ValidateSet("Desktop", "Core")]
[ArgumentCompleter(typeof(PSEditionArgumentCompleter))]
public string PSEdition { get; set; }
/// <summary>
@@ -491,5 +493,28 @@ namespace Microsoft.PowerShell.Commands
}
}
}
/// <summary>
/// PSEditionArgumentCompleter for PowerShell Edition names.
/// </summary>
public class PSEditionArgumentCompleter : IArgumentCompleter
{
/// <summary>
/// CompleteArgument
/// </summary>
public IEnumerable<CompletionResult> 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
@@ -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))
@@ -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);
}
}
}
}
@@ -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)
@@ -77,6 +77,11 @@ namespace System.Management.Automation
/// </summary>
internal static string WinPEIdentificationRegKey = @"System\CurrentControlSet\Control\MiniNT";
/// <summary>
/// Allowed PowerShell Editions
/// </summary>
internal static string[] AllowedEditionValues = { "Desktop", "Core" };
/// <summary>
/// helper fn to check byte[] arg for null.
/// </summary>
@@ -522,6 +527,16 @@ namespace System.Management.Automation
return PSVersionInfo.PSEdition.Equals(checkEdition, StringComparison.OrdinalIgnoreCase);
}
/// <summary>
/// Checks whether the specified edition values is allowed.
/// </summary>
/// <param name="editionValue">Edition value to check</param>
/// <returns>true if allowed, false otherwise</returns>
internal static bool IsValidPSEditionValue(string editionValue)
{
return AllowedEditionValues.Contains(editionValue, StringComparer.OrdinalIgnoreCase);
}
/// <summary>
/// Checks whether current monad session supports NetFrameworkVersion specified
/// by checkVersion. The specified version is treated as the the minimum required
@@ -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
@@ -708,6 +708,8 @@ namespace System.Management.Automation.Language
Utils.EmptyReadOnlyCollection<string>();
internal static readonly ReadOnlyCollection<ModuleSpecification> EmptyModuleCollection =
Utils.EmptyReadOnlyCollection<ModuleSpecification>();
internal static readonly ReadOnlyCollection<string> EmptyEditionCollection =
Utils.EmptyReadOnlyCollection<string>();
/// <summary>
/// The application id this script requires, specified like:
@@ -726,9 +728,9 @@ namespace System.Management.Automation.Language
/// <summary>
/// The PowerShell Edition this script requires, specified like:
/// <code>#requires -PSEdition Desktop</code>
/// If no PSEdition has been specified, this property is null.
/// If no PSEdition has been specified, this property is an empty collection.
/// </summary>
public string RequiredPSEdition { get; internal set; }
public ReadOnlyCollection<string> RequiredPSEditions { get; internal set; }
/// <summary>
/// The modules this script requires, specified like:
@@ -1516,7 +1516,7 @@ namespace System.Management.Automation.Language
string requiredShellId = null;
Version requiredVersion = null;
string requiredEdition = null;
List<string> requiredEditions = null;
List<ModuleSpecification> requiredModules = null;
List<PSSnapInSpecification> requiredSnapins = null;
List<string> 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<string>(requiredEditions)
: ScriptRequirements.EmptyEditionCollection,
RequiresPSSnapIns = requiredSnapins != null
? new ReadOnlyCollection<PSSnapInSpecification>(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<string> requiredEditions,
ref List<ModuleSpecification> requiredModules,
ref List<string> 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<string> HandleRequiresPSEditionArgument(Ast argumentAst, object arg, ref List<string> requiredEditions)
{
if (!(arg is string))
{
ReportError(argumentAst.Extent, () => ParserStrings.RequiresInvalidStringArgument, editionToken);
}
else
{
if (requiredEditions == null)
requiredEditions = new List<string>();
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
@@ -323,28 +323,39 @@ namespace System.Management.Automation.Runspaces
remoteRunspace.PSSessionName = name;
}
string fullShellName = WSManConnectionInfo.ExtractPropertyAsWsManConnectionInfo<string>(
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<string>(
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
@@ -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
/// <summary>
/// Main window title of the process
/// </summary>
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;
@@ -263,18 +263,38 @@ namespace Microsoft.PowerShell.Commands
}
/// <summary>
/// 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.
/// </summary>
[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,
@@ -243,7 +243,6 @@ namespace Microsoft.PowerShell.Commands
}
return resolvedShell;
}
/// <summary>
@@ -551,29 +550,6 @@ namespace Microsoft.PowerShell.Commands
}
private SwitchParameter useSSL;
/// <summary>
/// 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.
/// </summary>
[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;
/// <summary>
/// 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;
/// <summary>
/// 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.
/// </summary>
[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<string> newParameterNames, out List<o
#region Private / Protected Methods
/// <summary>
/// Gets the matching runspaces based on the parameterset
/// </summary>
/// <param name="writeErrorOnNoMatch">write an error record when
/// no matches are found</param>
/// <param name="writeobject">if true write the object down
/// the pipeline</param>
/// <returns>list of matching runspaces</returns>
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Runspaces")]
protected Dictionary<Guid, PSSession> GetMatchingRunspaces(bool writeobject,
bool writeErrorOnNoMatch)
{
return GetMatchingRunspaces(writeobject, writeErrorOnNoMatch, SessionFilterState.All, null);
}
/// <summary>
/// Gets the matching runspaces based on the parameterset
/// </summary>
@@ -2363,11 +2397,13 @@ private string GetConvertedScript(out List<string> newParameterNames, out List<o
/// <param name="writeobject">if true write the object down
/// the pipeline</param>
/// <param name="filterState">Runspace state filter value.</param>
/// <param name="configurationName">Runspace configuration name filter value.</param>
/// <returns>list of matching runspaces</returns>
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Runspaces")]
protected Dictionary<Guid, PSSession> GetMatchingRunspaces(bool writeobject,
bool writeErrorOnNoMatch,
SessionFilterState filterState = SessionFilterState.All)
SessionFilterState filterState,
String configurationName)
{
switch (ParameterSetName)
{
@@ -2399,49 +2435,49 @@ private string GetConvertedScript(out List<string> newParameterNames, out List<o
// container id + optional session name
case PSRunspaceCmdlet.ContainerIdParameterSet:
{
return GetMatchingRunspacesByContainerVMNameContainerId(writeobject, filterState, true, true);
return GetMatchingRunspacesByContainerVMNameContainerId(writeobject, filterState, configurationName, true, true);
}
// container id + session instanceid
case PSRunspaceCmdlet.ContainerIdInstanceIdParameterSet:
{
return GetMatchingRunspacesByContainerVMNameContainerIdSessionInstanceId(writeobject, filterState, true, true);
return GetMatchingRunspacesByContainerVMNameContainerIdSessionInstanceId(writeobject, filterState, configurationName, true, true);
}
// container name + optional session name
case PSRunspaceCmdlet.ContainerNameParameterSet:
{
return GetMatchingRunspacesByContainerVMNameContainerId(writeobject, filterState, true, false);
return GetMatchingRunspacesByContainerVMNameContainerId(writeobject, filterState, configurationName, true, false);
}
// container name + session instanceid
case PSRunspaceCmdlet.ContainerNameInstanceIdParameterSet:
{
return GetMatchingRunspacesByContainerVMNameContainerIdSessionInstanceId(writeobject, filterState, true, false);
return GetMatchingRunspacesByContainerVMNameContainerIdSessionInstanceId(writeobject, filterState, configurationName, true, false);
}
// vm Guid + optional session name
case PSRunspaceCmdlet.VMIdParameterSet:
{
return GetMatchingRunspacesByVMId(writeobject, filterState);
return GetMatchingRunspacesByVMId(writeobject, filterState, configurationName);
}
// vm Guid + session instanceid
case PSRunspaceCmdlet.VMIdInstanceIdParameterSet:
{
return GetMatchingRunspacesByVMIdSessionInstanceId(writeobject, filterState);
return GetMatchingRunspacesByVMIdSessionInstanceId(writeobject, filterState, configurationName);
}
// vm name + optional session name
case PSRunspaceCmdlet.VMNameParameterSet:
{
return GetMatchingRunspacesByContainerVMNameContainerId(writeobject, filterState, false, false);
return GetMatchingRunspacesByContainerVMNameContainerId(writeobject, filterState, configurationName, false, false);
}
// vm name + session instanceid
case PSRunspaceCmdlet.VMNameInstanceIdParameterSet:
{
return GetMatchingRunspacesByContainerVMNameContainerIdSessionInstanceId(writeobject, filterState, false, false);
return GetMatchingRunspacesByContainerVMNameContainerIdSessionInstanceId(writeobject, filterState, configurationName, false, false);
}
}
@@ -2708,11 +2744,13 @@ private string GetConvertedScript(out List<string> newParameterNames, out List<o
/// </summary>
/// <param name="writeobject">if true write the object down the pipeline</param>
/// <param name="filterState">Runspace state filter value.</param>
/// <param name="configurationName">Runspace configuration name filter value.</param>
/// <param name="isContainer">if true the target is a container instead of virtual machine</param>
/// <param name="useContainerId">if true the input is container id</param>
/// <returns>list of matching runspaces</returns>
private Dictionary<Guid, PSSession> GetMatchingRunspacesByContainerVMNameContainerId(bool writeobject,
SessionFilterState filterState,
String configurationName,
bool isContainer,
bool useContainerId)
{
@@ -2720,6 +2758,8 @@ private string GetConvertedScript(out List<string> newParameterNames, out List<o
TargetMachineType computerType;
bool supportWildChar = false;
String[] sessionNames = { "*" };
WildcardPattern configurationNamePattern =
String.IsNullOrEmpty(configurationName) ? null : WildcardPattern.Get(configurationName, WildcardOptions.IgnoreCase);
Dictionary<Guid, PSSession> matches = new Dictionary<Guid, PSSession>();
List<PSSession> remoteRunspaceInfos = this.RunspaceRepository.Runspaces;
@@ -2758,13 +2798,15 @@ private string GetConvertedScript(out List<string> newParameterNames, out List<o
foreach (string sessionName in sessionNames)
{
WildcardPattern sessionNamePattern = WildcardPattern.Get(sessionName, WildcardOptions.IgnoreCase);
WildcardPattern sessionNamePattern =
String.IsNullOrEmpty(sessionName) ? null : WildcardPattern.Get(sessionName, WildcardOptions.IgnoreCase);
var matchingRunspaceInfos = remoteRunspaceInfos
.Where<PSSession>(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<PSSession>();
@@ -2780,17 +2822,21 @@ private string GetConvertedScript(out List<string> newParameterNames, out List<o
/// </summary>
/// <param name="writeobject">if true write the object down the pipeline</param>
/// <param name="filterState">Runspace state filter value.</param>
/// <param name="configurationName">Runspace configuration name filter value.</param>
/// <param name="isContainer">if true the target is a container instead of virtual machine</param>
/// <param name="useContainerId">if true the input is container id</param>
/// <returns>list of matching runspaces</returns>
private Dictionary<Guid, PSSession> 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<Guid, PSSession> matches = new Dictionary<Guid, PSSession>();
List<PSSession> remoteRunspaceInfos = this.RunspaceRepository.Runspaces;
@@ -2828,6 +2874,7 @@ private string GetConvertedScript(out List<string> newParameterNames, out List<o
: inputName.Equals(session.ContainerId)) &&
sessionInstanceId.Equals(session.InstanceId) &&
QueryRunspaces.TestRunspaceState(session.Runspace, filterState) &&
((configurationNamePattern == null) ? true : configurationNamePattern.IsMatch(session.ConfigurationName)) &&
(session.ComputerType == computerType))
.ToList<PSSession>();
@@ -2843,11 +2890,15 @@ private string GetConvertedScript(out List<string> newParameterNames, out List<o
/// </summary>
/// <param name="writeobject">if true write the object down the pipeline</param>
/// <param name="filterState">Runspace state filter value.</param>
/// <param name="configurationName">Runspace configuration name filter value.</param>
/// <returns>list of matching runspaces</returns>
private Dictionary<Guid, PSSession> 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<Guid, PSSession> matches = new Dictionary<Guid, PSSession>();
List<PSSession> remoteRunspaceInfos = this.RunspaceRepository.Runspaces;
@@ -2861,12 +2912,14 @@ private string GetConvertedScript(out List<string> newParameterNames, out List<o
{
foreach (string sessionName in sessionNames)
{
WildcardPattern sessionNamePattern = WildcardPattern.Get(sessionName, WildcardOptions.IgnoreCase);
WildcardPattern sessionNamePattern =
String.IsNullOrEmpty(sessionName) ? null : WildcardPattern.Get(sessionName, WildcardOptions.IgnoreCase);
var matchingRunspaceInfos = remoteRunspaceInfos
.Where<PSSession>(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<PSSession>();
@@ -2882,10 +2935,14 @@ private string GetConvertedScript(out List<string> newParameterNames, out List<o
/// </summary>
/// <param name="writeobject">if true write the object down the pipeline</param>
/// <param name="filterState">Runspace state filter value.</param>
/// <param name="configurationName">Runspace configuration name filter value.</param>
/// <returns>list of matching runspaces</returns>
private Dictionary<Guid, PSSession> GetMatchingRunspacesByVMIdSessionInstanceId(bool writeobject,
SessionFilterState filterState)
SessionFilterState filterState,
String configurationName)
{
WildcardPattern configurationNamePattern =
String.IsNullOrEmpty(configurationName) ? null : WildcardPattern.Get(configurationName, WildcardOptions.IgnoreCase);
Dictionary<Guid, PSSession> matches = new Dictionary<Guid, PSSession>();
List<PSSession> remoteRunspaceInfos = this.RunspaceRepository.Runspaces;
@@ -2897,6 +2954,7 @@ private string GetConvertedScript(out List<string> newParameterNames, out List<o
.Where<PSSession>(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<PSSession>();
@@ -219,10 +219,67 @@ namespace Microsoft.PowerShell.Commands
}
private string containerName;
/// <summary>
/// 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.
/// </summary>
[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
/// <summary>
/// Resolves shellname and appname
/// </summary>
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;
}
}
}
/// <summary>
/// Process record.
/// </summary>
@@ -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,
@@ -117,9 +117,13 @@ namespace Microsoft.PowerShell.Commands
private Uri[] uris;
/// <summary>
/// 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.
/// </summary>
[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
/// <summary>
/// Resolves shellname
/// </summary>
protected override void BeginProcessing()
{
base.BeginProcessing();
if (ConfigurationName == null)
{
ConfigurationName = string.Empty;
}
}
/// <summary>
/// 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
@@ -164,6 +164,40 @@ namespace Microsoft.PowerShell.Commands
}
private SwitchParameter enableNetworkAccess;
/// <summary>
/// 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.
/// </summary>
[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<EventArgs>(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
/// <summary>
@@ -504,13 +552,13 @@ namespace Microsoft.PowerShell.Commands
Action<Cmdlet> 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);
@@ -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;
/// <summary>
/// Supported values of m_Flag.
/// </summary>
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; }
}
/// <summary>
/// If Flag is 0, the socket connection is for VM.
/// If Flag is 1, the socket connection is for Hyper-V container.
/// </summary>
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
/// <summary>
@@ -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.
/// </summary>
/// <param name="networkCredential">The credential used for authentication</param>
/// <param name="isFirstConnection">Whether this is the first connection</param>
/// <param name="configurationName">The configuration name of the PS session</param>
/// <param name="isFirstConnection">Whether this is the first connection</param>
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);
@@ -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; }
}
/// <summary>
/// Name of session configuration.
/// </summary>
public string ConfigurationName
{
get { return _configurationName; }
set { _configurationName = value; }
}
/// <summary>
/// Accessor for the named pipe reader.
/// </summary>
@@ -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.
/// </summary>
internal static void RunServerMode()
/// <param name="configurationName">name of the configuration to use</param>
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
@@ -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; }
}
/// <summary>
/// Configuration name of the VM session.
/// </summary>
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
/// </summary>
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
/// </summary>
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; }
}
/// <summary>
/// The configuration name of the container session.
/// </summary>
internal string ConfigurationName
{
get { return configurationName; }
set { configurationName = value; }
}
/// <summary>
/// Whether the process in container has terminated.
/// </summary>
@@ -2388,12 +2413,13 @@ namespace System.Management.Automation.Runspaces
/// <summary>
/// Creates an instance used for PowerShell Direct for container.
/// </summary>
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");
//
@@ -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
}
/// <summary>
/// This exception is used by PowerShell Direct for credential related error.
/// This exception is used by PowerShell Direct errors.
/// </summary>
[Serializable]
public class PSDirectCredentialException : RuntimeException
public class PSDirectException : RuntimeException
{
#region Constructor
@@ -711,7 +712,7 @@ namespace System.Management.Automation.Remoting
/// <param name="message">
/// A localized string as an error message.
/// </param>
public PSDirectCredentialException(string message)
public PSDirectException(string message)
: base(message)
{
}
@@ -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;
}
@@ -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
@@ -480,33 +480,8 @@ namespace System.Management.Automation
/// </summary>
private readonly Hashtable _helpFiles = new Hashtable();
/// <summary>
/// Finds a help file associated with the given cmdlet
/// </summary>
/// <param name="cmdletInfo"></param>
/// <returns></returns>
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;
}
/// <summary>
/// Finds a help file associated with the given cmdlet
/// </summary>
/// <param name="cmdletInfo"></param>
/// <returns></returns>
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., <AssemblyName>.ni.dll as supposed to <AssemblyName>.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
// <Name>.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;
@@ -81,6 +81,6 @@
},
"compile": [
"../windows-build/gen/SYS_AUTO/*.cs"
"../windows-build/gen/System.Management.Automation/*.cs"
]
}
@@ -185,7 +185,7 @@ The #requires statement must be in one of the following formats:
<value>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}.</value>
</data>
<data name="RequiresPSEditionNotCompatible" xml:space="preserve">
<value>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.</value>
<value>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.</value>
</data>
<data name="RequiresMissingPSSnapIns" xml:space="preserve">
<value>The script '{0}' cannot be run because the following snap-ins that are specified by the "#requires" statements of the script are missing: {1}.</value>
@@ -214,6 +214,9 @@
<data name="InvalidPowerShellVersionInModuleManifest" xml:space="preserve">
<value>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.</value>
</data>
<data name="DuplicateEntriesInCompatiblePSEditions" xml:space="preserve">
<value>The specified value '{0}' for CompatiblePSEditions contains duplicate PowerShell Edition names. Try again after removing the duplicate PowerShell Edition names.</value>
</data>
<data name="ModuleVersionEqualsToVersionFolder" xml:space="preserve">
<value>Version specified in ModuleVersion key is equal to version folder name.</value>
</data>
@@ -921,6 +921,12 @@ Possible matches are</value>
<data name="RequiresVersionInvalid" xml:space="preserve">
<value>The argument for the Version parameter is not valid. Specify a valid Windows PowerShell version, in the format major.minor version.</value>
</data>
<data name="RequiresPSEditionInvalid" xml:space="preserve">
<value>The argument for the {0} parameter is not valid. Specify a valid PowerShell edition.</value>
</data>
<data name="RequiresPSEditionValueIsAlreadySpecified" xml:space="preserve">
<value>The argument for the {0} parameter contains duplicate values. Do not specify duplicate PowerShell edition values.</value>
</data>
<data name="WildCardModuleNameError" xml:space="preserve">
<value>Wildcard characters are not supported for module names.</value>
</data>
@@ -1008,7 +1014,7 @@ Possible matches are</value>
<value>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.</value>
</data>
<data name="DuplicateKeywordDefinition" xml:space="preserve">
<value>Keyword '{0}' already defined in the configuration.</value>
<value>Resource name '{0}' is already being used by another Resource or Configuration.</value>
</data>
<data name="ClassNameNotSameAsDefiningFile" xml:space="preserve">
<value>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</value>
@@ -1060,7 +1066,7 @@ ModuleVersion : Version of module to import. If used, ModuleName must represent
<value>Configuration keyword is not allowed in constrainedLanguage mode.</value>
</data>
<data name="InvalidConfigurationName" xml:space="preserve">
<value>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.</value>
<value>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.</value>
</data>
<data name="UnsupportedNamedBlockInConfiguration" xml:space="preserve">
<value>Configuration only supports the End block in its body. Begin, Process and DynamicParam blocks are not allowed in a configuration.</value>
@@ -1240,6 +1240,9 @@ All WinRM sessions connected to Windows PowerShell session configurations, such
<data name="RCAutoDisconnectingError" xml:space="preserve">
<value>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.</value>
</data>
<data name="RemoteSessionHyperVSocketClientConstructorSetSocketOptionFailure" xml:space="preserve">
<value>Failed to create an instance of RemoteSessionHyperVSocketClient due to SetSocketOption failure.</value>
</data>
<data name="RemoteSessionHyperVSocketServerConstructorFailure" xml:space="preserve">
<value>Failed to create an instance of RemoteSessionHyperVSocketServer.</value>
</data>
@@ -1435,7 +1438,7 @@ All WinRM sessions connected to Windows PowerShell session configurations, such
<value>{0}[{1}]: {2}</value>
</data>
<data name="EnterPSHostProcessCannotConnectToProcess" xml:space="preserve">
<value>Unable to connect to application domain name {0} of process {1}.</value>
<value>Unable to connect to application domain name {0} of process {1}. Error: {2}.</value>
</data>
<data name="WSManPluginConnectNoNegotiationData" xml:space="preserve">
<value>PowerShell plugin cannot process the Connect operation as required negotiation information is either missing or not complete.</value>
@@ -1515,9 +1518,6 @@ All WinRM sessions connected to Windows PowerShell session configurations, such
<data name="RemoteTransportError" xml:space="preserve">
<value>Remote transport error: {0}</value>
</data>
<data name="CannotConnectNamedPipe" xml:space="preserve">
<value>Unable to open pipe connection for PowerShell IPC. Error code: {0}.</value>
</data>
<data name="CannotConnectContainerNamedPipe" xml:space="preserve">
<value>Unable to open pipe connection for PowerShell in container. Error code: {0}.</value>
</data>