Enable -sta and -mta switches for pwsh (#10061)

This commit is contained in:
Steve Lee
2019-07-25 12:38:52 -07:00
committed by Dongbo Wang
parent 87f537f290
commit 2ed9abc99b
24 changed files with 134 additions and 353 deletions
@@ -162,7 +162,7 @@ namespace Microsoft.PowerShell.Commands
}
thread.IsBackground = true;
// thread.SetApartmentState( ApartmentState.STA);
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
}
@@ -395,7 +395,6 @@ namespace Microsoft.PowerShell.Commands
return result;
}
#if !CORECLR
private class ComCreateInfo
{
public object objectCreated;
@@ -435,7 +434,6 @@ namespace Microsoft.PowerShell.Commands
info.success = false;
}
}
#endif
private object CreateComObject()
{
@@ -459,13 +457,6 @@ namespace Microsoft.PowerShell.Commands
// Check Error Code to see if Error is because of Com apartment Mismatch.
if (e.HResult == RPC_E_CHANGED_MODE)
{
#if CORECLR
ThrowTerminatingError(
new ErrorRecord(
new COMException(StringUtil.Format(NewObjectStrings.ApartmentNotSupported, e.Message), e),
"NoCOMClassIdentified",
ErrorCategory.ResourceUnavailable, null));
#else
createInfo = new ComCreateInfo();
Thread thread = new Thread(new ParameterizedThreadStart(STAComCreateThreadProc));
@@ -482,7 +473,6 @@ namespace Microsoft.PowerShell.Commands
ThrowTerminatingError(
new ErrorRecord(createInfo.e, "NoCOMClassIdentified",
ErrorCategory.ResourceUnavailable, null));
#endif
}
else
{
@@ -173,10 +173,8 @@ namespace Microsoft.PowerShell
private const int MaxPipePathLengthMacOS = 104;
internal static string[] validParameters = {
#if STAMODE
"sta",
"mta",
#endif
"command",
"configurationname",
"custompipename",
@@ -644,7 +642,6 @@ namespace Microsoft.PowerShell
}
}
#if STAMODE
internal bool StaMode
{
get
@@ -655,14 +652,10 @@ namespace Microsoft.PowerShell
}
else
{
// Nano doesn't support STA COM apartment, so on Nano powershell has to use MTA as the default.
// return false;
// Win8: 182409 PowerShell 3.0 should run in STA mode by default
return true;
}
}
}
#endif
/// <summary>
/// Processes all the command line parameters to ConsoleHost. Returns the exit code to be used to terminate the process, or
@@ -944,10 +937,15 @@ namespace Microsoft.PowerShell
break;
}
}
#if STAMODE
// explicit setting of the ApartmentState Not supported on NanoServer
else if (MatchSwitch(switchKey, "sta", "s"))
{
if (!Platform.IsWindowsDesktop)
{
WriteCommandLineError(
CommandLineParameterParserStrings.STANotImplemented);
break;
}
if (_staMode.HasValue)
{
// -sta and -mta are mutually exclusive.
@@ -958,10 +956,15 @@ namespace Microsoft.PowerShell
_staMode = true;
}
// Win8: 182409 PowerShell 3.0 should run in STA mode by default..so, consequently adding the switch -mta.
// Not deleting -sta for backward compatability reasons
else if (MatchSwitch(switchKey, "mta", "mta"))
{
if (!Platform.IsWindowsDesktop)
{
WriteCommandLineError(
CommandLineParameterParserStrings.MTANotImplemented);
break;
}
if (_staMode.HasValue)
{
// -sta and -mta are mutually exclusive.
@@ -972,7 +975,6 @@ namespace Microsoft.PowerShell
_staMode = false;
}
#endif
else if (MatchSwitch(switchKey, "workingdirectory", "wo") || MatchSwitch(switchKey, "wd", "wd"))
{
++i;
@@ -1406,15 +1408,7 @@ namespace Microsoft.PowerShell
private bool _abortStartup;
private bool _skipUserInit;
private string _customPipeName;
#if STAMODE
// Win8: 182409 PowerShell 3.0 should run in STA mode by default
// -sta and -mta are mutually exclusive..so tracking them using nullable boolean
// if true, then sta is specified on the command line.
// if false, then mta is specified on the command line.
// if null, then none is specified on the command line..use default in this case
// default is sta.
private bool? _staMode = null;
#endif
private bool _noExit = true;
private bool _explicitReadCommandsFromStdin;
private bool _noPrompt;
@@ -1373,11 +1373,7 @@ namespace Microsoft.PowerShell
// NTRAID#Windows Out Of Band Releases-915506-2005/09/09
// Removed HandleUnexpectedExceptions infrastructure
#if STAMODE
exitCode = DoRunspaceLoop(cpp.InitialCommand, cpp.SkipProfiles, cpp.Args, cpp.StaMode, cpp.ConfigurationName);
#else
exitCode = DoRunspaceLoop(cpp.InitialCommand, cpp.SkipProfiles, cpp.Args, false, cpp.ConfigurationName);
#endif
}
while (false);
@@ -1452,12 +1448,12 @@ namespace Microsoft.PowerShell
_runspaceRef.Runspace.Close();
_runspaceRef = null;
#if STAMODE
if (staMode) // don't recycle the Runspace in STA mode
if (staMode)
{
// don't continue the session in STA mode
ShouldEndSession = true;
}
#endif
}
return ExitCode;
@@ -1496,11 +1492,7 @@ namespace Microsoft.PowerShell
{
args = runspaceCreationArgs as RunspaceCreationEventArgs;
Dbg.Assert(args != null, "Event Arguments to CreateRunspace should not be null");
#if STAMODE
DoCreateRunspace(args.InitialCommand, args.SkipProfiles, args.StaMode, args.ConfigurationName, args.InitialCommandArgs);
#else
DoCreateRunspace(args.InitialCommand, args.SkipProfiles, false, args.ConfigurationName, args.InitialCommandArgs);
#endif
}
catch (ConsoleHostStartupException startupException)
{
@@ -1618,17 +1610,11 @@ namespace Microsoft.PowerShell
private void OpenConsoleRunspace(Runspace runspace, bool staMode)
{
#if STAMODE
// staMode will have following values:
// On FullPS: 'true'/'false' = default('true'=STA) + possibility of overload through cmdline parameter '-mta'
// On NanoPS: always 'false' = default('false'=MTA) + NO possibility of overload through cmdline parameter '-mta'
// ThreadOptions should match on FullPS and NanoPS for corresponding ApartmentStates.
if (staMode)
if (staMode && Platform.IsWindowsDesktop)
{
// we can't change ApartmentStates on CoreCLR
runspace.ApartmentState = ApartmentState.STA;
}
#endif
runspace.ThreadOptions = PSThreadOptions.ReuseThread;
runspace.EngineActivityId = EtwActivity.GetActivityId();
@@ -2896,18 +2882,14 @@ namespace Microsoft.PowerShell
{
InitialCommand = initialCommand;
SkipProfiles = skipProfiles;
#if STAMODE
StaMode = staMode;
#endif
ConfigurationName = configurationName;
InitialCommandArgs = initialCommandArgs;
}
internal string InitialCommand { get; set; }
internal bool SkipProfiles { get; set; }
#if STAMODE
internal bool StaMode { get; set; }
#endif
internal string ConfigurationName { get; set; }
internal Collection<CommandParameter> InitialCommandArgs { get; set; }
}
@@ -210,4 +210,10 @@
<data name="MissingWorkingDirectoryArgument" xml:space="preserve">
<value>Cannot process the command because -WorkingDirectory requires an argument that is a directory path.</value>
</data>
<data name="MTANotImplemented" xml:space="preserve">
<value>Parameter -MTA is not supported on this platform.</value>
</data>
<data name="STANotImplemented" xml:space="preserve">
<value>Parameter -STA is not supported on this platform.</value>
</data>
</root>
@@ -131,8 +131,8 @@ Type 'help' to get help.</value>
[-ConfigurationName &lt;string&gt;] [-CustomPipeName &lt;string&gt;]
[-EncodedCommand &lt;Base64EncodedCommand&gt;]
[-ExecutionPolicy &lt;ExecutionPolicy&gt;] [-InputFormat {Text | XML}]
[-Interactive] [-LoadProfile] [-NoExit] [-NoLogo] [-NonInteractive] [-NoProfile]
[-OutputFormat {Text | XML}] [-SettingsFile &lt;filePath&gt;] [-Version]
[-Interactive] [-LoadProfile] [-MTA] [-NoExit] [-NoLogo] [-NonInteractive] [-NoProfile]
[-OutputFormat {Text | XML}] [-SettingsFile &lt;filePath&gt;] [-STA] [-Version]
[-WindowStyle &lt;style&gt;] [-WorkingDirectory &lt;directoryPath&gt;]
pwsh[.exe] -h | -Help | -? | /?
@@ -298,6 +298,11 @@ All parameters are case-insensitive.</value>
Load the PowerShell profiles. This is the default behavior even if this is
not specified.
-MTA
Start the shell using a multi-threaded apartment.
Only available on Windows.
-NoExit | -noe
Does not exit after running startup commands.
@@ -334,6 +339,11 @@ Hides the copyright banner at startup.
Example: "pwsh -SettingsFile c:\myproject\powershell.config.json"
-STA
Start the shell using a single-threaded apartment. This is the default.
Only available on Windows.
-Version | -v
Displays the version of PowerShell. Additional parameters are ignored.
@@ -1671,9 +1671,7 @@ namespace System.Management.Automation.Runspaces
ss.UseFullLanguageModeInDebugger = this.UseFullLanguageModeInDebugger;
ss.ThreadOptions = this.ThreadOptions;
ss.ThrowOnRunspaceOpenError = this.ThrowOnRunspaceOpenError;
#if !CORECLR // No ApartmentState In CoreCLR
ss.ApartmentState = this.ApartmentState;
#endif
foreach (ModuleSpecification modSpec in this.ModuleSpecificationsToImport)
{
@@ -1812,14 +1810,11 @@ namespace System.Management.Automation.Runspaces
/// </summary>
public bool UseFullLanguageModeInDebugger { get; set; } = false;
#if !CORECLR // No ApartmentState In CoreCLR
/// <summary>
/// ApartmentState of the thread used to execute commands.
/// </summary>
public ApartmentState ApartmentState { get; set; } = Runspace.DefaultApartmentState;
#endif
/// <summary>
/// This property determines whether a new thread is created for each invocation of a command.
/// </summary>
@@ -582,7 +582,6 @@ namespace System.Management.Automation.Runspaces
}
}
#if !CORECLR // No ApartmentState In CoreCLR
internal const ApartmentState DefaultApartmentState = ApartmentState.Unknown;
/// <summary>
@@ -613,7 +612,6 @@ namespace System.Management.Automation.Runspaces
}
private ApartmentState apartmentState = Runspace.DefaultApartmentState;
#endif
/// <summary>
/// This property determines whether a new thread is create for each invocation.
@@ -77,10 +77,7 @@ namespace System.Management.Automation.Runspaces
Host = host;
InitialSessionState = initialSessionState.Clone();
this.ThreadOptions = initialSessionState.ThreadOptions;
#if !CORECLR // No ApartmentState In CoreCLR
this.ApartmentState = initialSessionState.ApartmentState;
#endif
}
/// <summary>
@@ -126,10 +123,7 @@ namespace System.Management.Automation.Runspaces
}
this.ThreadOptions = initialSessionState.ThreadOptions;
#if !CORECLR // No ApartmentState In CoreCLR
this.ApartmentState = initialSessionState.ApartmentState;
#endif
}
/// <summary>
@@ -920,7 +914,6 @@ namespace System.Management.Automation.Runspaces
waitHandles[i] = runningPipelines[i].PipelineFinishedEvent;
}
#if !CORECLR // No ApartmentState.STA In CoreCLR
// WaitAll for multiple handles on a STA (single-thread apartment) thread is not supported as WaitAll will prevent the message pump to run
if (runningPipelines.Length > 1 && Thread.CurrentThread.GetApartmentState() == ApartmentState.STA)
{
@@ -940,7 +933,7 @@ namespace System.Management.Automation.Runspaces
return waitAllIsDone.WaitOne();
}
}
#endif
return WaitHandle.WaitAll(waitHandles);
}
else
@@ -146,32 +146,32 @@ namespace System.Management.Automation.Runspaces
{
lock (this.SyncRoot)
{
if (value != _createThreadOptions)
if (value == _createThreadOptions)
{
if (this.RunspaceStateInfo.State != RunspaceState.BeforeOpen)
{
#if CORECLR // No ApartmentState.STA Support In CoreCLR
bool allowed = value == PSThreadOptions.ReuseThread;
#else
// if the runspace is already opened we only allow changing the options if
// the apartment state is MTA and the new value is ReuseThread
bool allowed = (this.ApartmentState == ApartmentState.MTA || this.ApartmentState == ApartmentState.Unknown) // Unknown is the same as MTA
&&
value == PSThreadOptions.ReuseThread;
#endif
if (!allowed)
{
throw new InvalidOperationException(StringUtil.Format(RunspaceStrings.InvalidThreadOptionsChange));
}
}
_createThreadOptions = value;
return;
}
if (this.RunspaceStateInfo.State != RunspaceState.BeforeOpen)
{
if (!IsValidThreadOptionsConfiguration(value))
{
throw new InvalidOperationException(StringUtil.Format(RunspaceStrings.InvalidThreadOptionsChange));
}
}
_createThreadOptions = value;
}
}
}
private bool IsValidThreadOptionsConfiguration(PSThreadOptions options)
{
// If the runspace is already opened, we only allow changing options when:
// - The new value is ReuseThread, and
// - The apartment state is not STA
return options == PSThreadOptions.ReuseThread && this.ApartmentState != ApartmentState.STA;
}
private PSThreadOptions _createThreadOptions = PSThreadOptions.Default;
/// <summary>
@@ -770,11 +770,7 @@ namespace System.Management.Automation.Runspaces
{
if (_pipelineThread == null)
{
#if CORECLR // No ApartmentState In CoreCLR
_pipelineThread = new PipelineThread();
#else
_pipelineThread = new PipelineThread(this.ApartmentState);
#endif
}
return _pipelineThread;
@@ -179,8 +179,7 @@ namespace System.Management.Automation.Runspaces
// and support impersonation flow as needed (Windows only).
Thread invokeThread = new Thread(new ThreadStart(invokeThreadProcDelegate), DefaultPipelineStackSize);
SetupInvokeThread(invokeThread, true);
#if !CORECLR
// No ApartmentState in CoreCLR
ApartmentState apartmentState;
if (InvocationSettings != null && InvocationSettings.ApartmentState != ApartmentState.Unknown)
@@ -192,11 +191,13 @@ namespace System.Management.Automation.Runspaces
apartmentState = this.LocalRunspace.ApartmentState; // use the Runspace apartment state
}
if (apartmentState != ApartmentState.Unknown)
#if !UNIX
if (apartmentState != ApartmentState.Unknown && !Platform.IsNanoServer && !Platform.IsIoT)
{
invokeThread.SetApartmentState(apartmentState);
}
#endif
invokeThread.Start();
break;
@@ -1188,15 +1189,6 @@ namespace System.Management.Automation.Runspaces
/// <summary>
/// Creates the worker thread and waits for it to be ready.
/// </summary>
#if CORECLR
internal PipelineThread()
{
_worker = new Thread(WorkerProc, LocalPipeline.DefaultPipelineStackSize);
_workItem = null;
_workItemReady = new AutoResetEvent(false);
_closed = false;
}
#else
internal PipelineThread(ApartmentState apartmentState)
{
_worker = new Thread(WorkerProc, LocalPipeline.DefaultPipelineStackSize);
@@ -1204,12 +1196,13 @@ namespace System.Management.Automation.Runspaces
_workItemReady = new AutoResetEvent(false);
_closed = false;
if (apartmentState != ApartmentState.Unknown)
#if !UNIX
if (apartmentState != ApartmentState.Unknown && !Platform.IsNanoServer && !Platform.IsIoT)
{
_worker.SetApartmentState(apartmentState);
}
}
#endif
}
/// <summary>
/// Returns the worker thread.
@@ -328,9 +328,7 @@ namespace System.Management.Automation
/// </summary>
public PSInvocationSettings()
{
#if !CORECLR // No ApartmentState In CoreCLR
this.ApartmentState = ApartmentState.Unknown;
#endif
_host = null;
RemoteStreamOptions = 0;
AddToHistory = false;
@@ -339,13 +337,11 @@ namespace System.Management.Automation
#endregion
#if !CORECLR // No ApartmentState In CoreCLR
/// <summary>
/// ApartmentState of the thread in which the command
/// is executed.
/// </summary>
public ApartmentState ApartmentState { get; set; }
#endif
/// <summary>
/// Host to use with the Runspace when the command is
@@ -4530,9 +4526,8 @@ namespace System.Management.Automation
{
if (pool != null)
{
#if !CORECLR // No ApartmentState In CoreCLR
VerifyThreadSettings(settings, pool.ApartmentState, pool.ThreadOptions, false);
#endif
// getting the runspace asynchronously so that Stop can be supported from a different
// thread.
_worker.GetRunspaceAsyncResult = pool.BeginGetRunspace(null, null);
@@ -4544,9 +4539,8 @@ namespace System.Management.Automation
rsToUse = _rsConnection as Runspace;
if (rsToUse != null)
{
#if !CORECLR // No ApartmentState In CoreCLR
VerifyThreadSettings(settings, rsToUse.ApartmentState, rsToUse.ThreadOptions, false);
#endif
if (rsToUse.RunspaceStateInfo.State != RunspaceState.Opened)
{
string message = StringUtil.Format(PowerShellStrings.InvalidRunspaceState, RunspaceState.Opened, rsToUse.RunspaceStateInfo.State);
@@ -4810,9 +4804,8 @@ namespace System.Management.Automation
{
if (pool != null)
{
#if !CORECLR // No ApartmentState In CoreCLR
VerifyThreadSettings(settings, pool.ApartmentState, pool.ThreadOptions, pool.IsRemote);
#endif
pool.AssertPoolIsOpen();
// for executing in a remote runspace pool case
@@ -4888,9 +4881,8 @@ namespace System.Management.Automation
LocalRunspace rs = _rsConnection as LocalRunspace;
if (rs != null)
{
#if !CORECLR // No ApartmentState In CoreCLR
VerifyThreadSettings(settings, rs.ApartmentState, rs.ThreadOptions, false);
#endif
if (rs.RunspaceStateInfo.State != RunspaceState.Opened)
{
string message = StringUtil.Format(PowerShellStrings.InvalidRunspaceState, RunspaceState.Opened, rs.RunspaceStateInfo.State);
@@ -4939,7 +4931,6 @@ namespace System.Management.Automation
return _invokeAsyncResult;
}
#if !CORECLR // No ApartmentState In CoreCLR
/// <summary>
/// Verifies the settings for ThreadOptions and ApartmentState.
/// </summary>
@@ -4974,7 +4965,6 @@ namespace System.Management.Automation
}
}
}
#endif
/// <summary>
/// </summary>
@@ -1259,7 +1259,6 @@ namespace System.Management.Automation.Runspaces
}
}
#if !CORECLR // No ApartmentState In CoreCLR
/// <summary>
/// ApartmentState of the thread used to execute commands within this RunspacePool.
/// </summary>
@@ -1286,7 +1285,6 @@ namespace System.Management.Automation.Runspaces
_internalPool.ApartmentState = value;
}
}
#endif
/// <summary>
/// Gets Runspace asynchronously from the runspace pool. The caller
@@ -132,10 +132,7 @@ namespace System.Management.Automation.Runspaces.Internal
_initialSessionState = initialSessionState.Clone();
this.host = host;
ThreadOptions = initialSessionState.ThreadOptions;
#if !CORECLR
// No ApartmentState In CoreCLR
this.ApartmentState = initialSessionState.ApartmentState;
#endif
pool = new Stack<Runspace>();
runspaceRequestQueue = new Queue<GetRunspaceAsyncResult>();
ultimateRequestQueue = new Queue<GetRunspaceAsyncResult>();
@@ -851,7 +848,6 @@ namespace System.Management.Automation.Runspaces.Internal
/// </remarks>
internal PSThreadOptions ThreadOptions { get; set; } = PSThreadOptions.Default;
#if !CORECLR // No ApartmentState In CoreCLR
/// <summary>
/// The value of this property is propagated to all the Runspaces in this pool.
/// </summary>
@@ -859,7 +855,6 @@ namespace System.Management.Automation.Runspaces.Internal
/// Any updates to the value of this property must be done before the RunspacePool is opened
/// </remarks>
internal ApartmentState ApartmentState { get; set; } = Runspace.DefaultApartmentState;
#endif
/// <summary>
/// Gets Runspace asynchronously from the runspace pool. The caller
@@ -1257,9 +1252,7 @@ namespace System.Management.Automation.Runspaces.Internal
Runspace result = RunspaceFactory.CreateRunspaceFromSessionStateNoClone(host, _initialSessionState);
result.ThreadOptions = this.ThreadOptions == PSThreadOptions.Default ? PSThreadOptions.ReuseThread : this.ThreadOptions;
#if !CORECLR // No ApartmentState In CoreCLR
result.ApartmentState = this.ApartmentState;
#endif
this.PropagateApplicationPrivateData(result);
@@ -554,9 +554,7 @@ namespace System.Management.Automation
try
{
RunspacePool.ThreadOptions = this.ThreadOptions;
#if !CORECLR // No ApartmentState In CoreCLR
RunspacePool.ApartmentState = this.ApartmentState;
#endif
RunspacePool.Open();
}
catch (InvalidRunspacePoolStateException e)
@@ -8,6 +8,7 @@ using System.Globalization;
using System.IO;
using System.Security.AccessControl;
using System.Text;
using System.Threading;
using System.Management.Automation;
using System.Management.Automation.Internal;
@@ -1050,7 +1051,6 @@ else
maxObjectSizeMB.Value,
Environment.NewLine));
}
#if !CORECLR // No ApartmentState In CoreCLR
if (threadAptState.HasValue)
{
initParameters.Append(string.Format(CultureInfo.InvariantCulture,
@@ -1059,7 +1059,6 @@ else
threadAptState.Value,
Environment.NewLine));
}
#endif
if (threadOptions.HasValue)
{
initParameters.Append(string.Format(CultureInfo.InvariantCulture,
@@ -2041,7 +2040,6 @@ else
internal PSCredential runAsCredential;
internal bool isRunAsCredentialSpecified;
#if !CORECLR // No ApartmentState In CoreCLR
/// <summary>
/// ApartmentState of the Runspace created for the shell.
/// </summary>
@@ -2062,7 +2060,6 @@ else
}
internal ApartmentState? threadAptState;
#endif
/// <summary>
/// ThreadOptions of the Runspace created for the shell.
@@ -3227,9 +3224,7 @@ Set-PSSessionConfiguration $args[0] $args[1] $args[2] $args[3] $args[4] $args[5]
ConfigurationDataFromXML.MAXRCVDOBJSIZETOKEN,
ConfigurationDataFromXML.MAXRCVDCMDSIZETOKEN,
ConfigurationDataFromXML.THREADOPTIONSTOKEN,
#if !CORECLR // No ApartmentState In CoreCLR
ConfigurationDataFromXML.THREADAPTSTATETOKEN,
#endif
ConfigurationDataFromXML.PSVERSIONTOKEN,
ConfigurationDataFromXML.MAXPSVERSIONTOKEN,
ConfigurationDataFromXML.SESSIONCONFIGTOKEN,
@@ -3854,12 +3849,10 @@ Set-PSSessionConfiguration $args[0] $args[1] $args[2] $args[3] $args[4] $args[5]
result.Properties.Add(new PSNoteProperty(ConfigurationDataFromXML.MAXRCVDOBJSIZETOKEN, input));
}
#if !CORECLR // No ApartmentState In CoreCLR
if (threadAptState.HasValue)
{
result.Properties.Add(new PSNoteProperty(ConfigurationDataFromXML.THREADAPTSTATETOKEN, threadAptState.Value));
}
#endif
if (threadOptions.HasValue)
{
@@ -3459,16 +3459,6 @@ namespace System.Management.Automation.Runspaces
/// </summary>
private void RunOnMTAThread(ThreadStart threadProc)
{
//
// By default, non-OneCore PowerShell is launched with ApartmentState being STA.
// In this case, we need to create a separate thread, set its ApartmentState to MTA,
// and do the work.
//
// For OneCore PowerShell, its ApartmentState is always MTA.
//
#if CORECLR
threadProc();
#else
if (Thread.CurrentThread.GetApartmentState() == ApartmentState.MTA)
{
threadProc();
@@ -3481,7 +3471,6 @@ namespace System.Management.Automation.Runspaces
executionThread.Start();
executionThread.Join();
}
#endif
}
/// <summary>
@@ -677,11 +677,7 @@ namespace System.Management.Automation
dataAsPSObject.Properties.Add(new PSNoteProperty(RemoteDataNameStrings.MinRunspaces, minRunspaces));
dataAsPSObject.Properties.Add(new PSNoteProperty(RemoteDataNameStrings.MaxRunspaces, maxRunspaces));
dataAsPSObject.Properties.Add(new PSNoteProperty(RemoteDataNameStrings.ThreadOptions, runspacePool.ThreadOptions));
#if CORECLR // No ApartmentState In CoreCLR, default to MTA for outgoing objects
ApartmentState poolState = ApartmentState.MTA;
#else
ApartmentState poolState = runspacePool.ApartmentState;
#endif
dataAsPSObject.Properties.Add(new PSNoteProperty(RemoteDataNameStrings.ApartmentState, poolState));
dataAsPSObject.Properties.Add(new PSNoteProperty(RemoteDataNameStrings.ApplicationArguments, applicationArguments));
@@ -1113,11 +1109,7 @@ namespace System.Management.Automation
hostInfo = new HostInfo(null);
hostInfo.UseRunspaceHost = true;
#if CORECLR // No ApartmentState In CoreCLR, default to MTA for outgoing objects
ApartmentState passedApartmentState = ApartmentState.MTA;
#else
ApartmentState passedApartmentState = rsPool.ApartmentState;
#endif
dataAsPSObject.Properties.Add(new PSNoteProperty(RemoteDataNameStrings.ApartmentState, passedApartmentState));
dataAsPSObject.Properties.Add(new PSNoteProperty(RemoteDataNameStrings.RemoteStreamOptions, RemoteStreamOptions.AddInvocationInfo));
dataAsPSObject.Properties.Add(new PSNoteProperty(RemoteDataNameStrings.AddToHistory, false));
@@ -1130,11 +1122,7 @@ namespace System.Management.Automation
hostInfo.UseRunspaceHost = true;
}
#if CORECLR // No ApartmentState In CoreCLR, default to MTA for outgoing objects
ApartmentState passedApartmentState = ApartmentState.MTA;
#else
ApartmentState passedApartmentState = settings.ApartmentState;
#endif
dataAsPSObject.Properties.Add(new PSNoteProperty(RemoteDataNameStrings.ApartmentState, passedApartmentState));
dataAsPSObject.Properties.Add(new PSNoteProperty(RemoteDataNameStrings.RemoteStreamOptions, settings.RemoteStreamOptions));
dataAsPSObject.Properties.Add(new PSNoteProperty(RemoteDataNameStrings.AddToHistory, settings.AddToHistory));
@@ -2341,7 +2329,6 @@ namespace System.Management.Automation
return GetPropertyValue<bool>(dataAsPSObject, RemoteDataNameStrings.IsNested);
}
#if !CORECLR // No ApartmentState In CoreCLR
/// <summary>
/// Gets the invocation settings information from the message.
/// </summary>
@@ -2352,7 +2339,7 @@ namespace System.Management.Automation
PSObject dataAsPSObject = PSObject.AsPSObject(data);
return GetPropertyValue<ApartmentState>(dataAsPSObject, RemoteDataNameStrings.ApartmentState);
}
#endif
/// <summary>
/// Gets the stream options from the message.
/// </summary>
@@ -12,6 +12,7 @@ using System.Management.Automation.Internal;
using System.Management.Automation.Runspaces;
using System.Management.Automation.Tracing;
using System.Reflection;
using System.Threading;
using System.Xml;
using Microsoft.PowerShell.Commands;
@@ -44,9 +45,7 @@ namespace System.Management.Automation.Remoting
internal const string MAXRCVDCMDSIZETOKEN = "psmaximumreceiveddatasizepercommandmb";
internal const string MAXRCVDCMDSIZETOKEN_CamelCase = "PSMaximumReceivedDataSizePerCommandMB";
internal const string THREADOPTIONSTOKEN = "pssessionthreadoptions";
#if !CORECLR // No ApartmentState In CoreCLR
internal const string THREADAPTSTATETOKEN = "pssessionthreadapartmentstate";
#endif
internal const string SESSIONCONFIGTOKEN = "sessionconfigurationdata";
internal const string PSVERSIONTOKEN = "PSVersion";
internal const string MAXPSVERSIONTOKEN = "MaxPSVersion";
@@ -68,10 +67,7 @@ namespace System.Management.Automation.Remoting
internal int? MaxReceivedCommandSizeMB;
// Used to set properties on the RunspacePool created for this shell.
internal PSThreadOptions? ShellThreadOptions;
#if !CORECLR // No ApartmentState In CoreCLR
internal Nullable<System.Threading.ApartmentState> ShellThreadApartmentState;
#endif
internal ApartmentState? ShellThreadApartmentState;
internal PSSessionConfigurationData SessionConfigurationData;
internal string ConfigFilePath;
@@ -127,13 +123,11 @@ namespace System.Management.Automation.Remoting
ShellThreadOptions = (PSThreadOptions)LanguagePrimitives.ConvertTo(
optionValue, typeof(PSThreadOptions), CultureInfo.InvariantCulture);
break;
#if !CORECLR // No ApartmentState In CoreCLR
case THREADAPTSTATETOKEN:
AssertValueNotAssigned(THREADAPTSTATETOKEN, ShellThreadApartmentState);
ShellThreadApartmentState = (System.Threading.ApartmentState)LanguagePrimitives.ConvertTo(
optionValue, typeof(System.Threading.ApartmentState), CultureInfo.InvariantCulture);
ShellThreadApartmentState = (ApartmentState)LanguagePrimitives.ConvertTo(
optionValue, typeof(ApartmentState), CultureInfo.InvariantCulture);
break;
#endif
case SESSIONCONFIGTOKEN:
{
AssertValueNotAssigned(SESSIONCONFIGTOKEN, SessionConfigurationData);
@@ -42,11 +42,8 @@ namespace System.Management.Automation
// associated with this powershell
private ServerRemoteHost _remoteHost;
#if !CORECLR
// No ApartmentState In CoreCLR
// apartment state for this powershell
private ApartmentState apartmentState;
#endif
// Handles nested invocation of PS drivers.
private IRSPDriverInvoke _psDriverInvoker;
@@ -55,7 +52,6 @@ namespace System.Management.Automation
#region Constructors
#if !CORECLR
/// <summary>
/// Default constructor for creating ServerPowerShellDrivers.
/// </summary>
@@ -85,66 +81,7 @@ namespace System.Management.Automation
apartmentState, hostInfo, streamOptions, addToHistory, rsToUse, null)
{
}
#else
/// <summary>
/// Default constructor for creating ServerPowerShellDrivers.
/// </summary>
/// <param name="powershell">Decoded powershell object.</param>
/// <param name="extraPowerShell">Extra pipeline to be run after <paramref name="powershell"/> completes.</param>
/// <param name="noInput">Whether there is input for this powershell.</param>
/// <param name="clientPowerShellId">The client powershell id.</param>
/// <param name="clientRunspacePoolId">The client runspacepool id.</param>
/// <param name="runspacePoolDriver">runspace pool driver
/// which is creating this powershell driver</param>
/// <param name="hostInfo">host info using which the host for
/// this powershell will be constructed</param>
/// <param name="streamOptions">Serialization options for the streams in this powershell.</param>
/// <param name="addToHistory">
/// true if the command is to be added to history list of the runspace. false, otherwise.
/// </param>
/// <param name="rsToUse">
/// If not null, this Runspace will be used to invoke Powershell.
/// If null, the RunspacePool pointed by <paramref name="runspacePoolDriver"/> will be used.
/// </param>
internal ServerPowerShellDriver(PowerShell powershell, PowerShell extraPowerShell, bool noInput, Guid clientPowerShellId,
Guid clientRunspacePoolId, ServerRunspacePoolDriver runspacePoolDriver,
HostInfo hostInfo, RemoteStreamOptions streamOptions,
bool addToHistory, Runspace rsToUse)
: this(powershell, extraPowerShell, noInput, clientPowerShellId, clientRunspacePoolId, runspacePoolDriver,
hostInfo, streamOptions, addToHistory, rsToUse, null)
{
}
#endif
#if CORECLR
/// <summary>
/// Default constructor for creating ServerPowerShellDrivers.
/// </summary>
/// <param name="powershell">Decoded powershell object.</param>
/// <param name="extraPowerShell">Extra pipeline to be run after <paramref name="powershell"/> completes.</param>
/// <param name="noInput">Whether there is input for this powershell.</param>
/// <param name="clientPowerShellId">The client powershell id.</param>
/// <param name="clientRunspacePoolId">The client runspacepool id.</param>
/// <param name="runspacePoolDriver">runspace pool driver
/// which is creating this powershell driver</param>
/// <param name="hostInfo">host info using which the host for
/// this powershell will be constructed</param>
/// <param name="streamOptions">Serialization options for the streams in this powershell.</param>
/// <param name="addToHistory">
/// true if the command is to be added to history list of the runspace. false, otherwise.
/// </param>
/// <param name="rsToUse">
/// If not null, this Runspace will be used to invoke Powershell.
/// If null, the RunspacePool pointed by <paramref name="runspacePoolDriver"/> will be used.
/// </param>
/// <param name="output">
/// If not null, this is used as another source of output sent to the client.
/// </param>
internal ServerPowerShellDriver(PowerShell powershell, PowerShell extraPowerShell, bool noInput, Guid clientPowerShellId,
Guid clientRunspacePoolId, ServerRunspacePoolDriver runspacePoolDriver,
HostInfo hostInfo, RemoteStreamOptions streamOptions,
bool addToHistory, Runspace rsToUse, PSDataCollection<PSObject> output)
#else
/// <summary>
/// Default constructor for creating ServerPowerShellDrivers.
/// </summary>
@@ -173,14 +110,11 @@ namespace System.Management.Automation
Guid clientRunspacePoolId, ServerRunspacePoolDriver runspacePoolDriver,
ApartmentState apartmentState, HostInfo hostInfo, RemoteStreamOptions streamOptions,
bool addToHistory, Runspace rsToUse, PSDataCollection<PSObject> output)
#endif
{
InstanceId = clientPowerShellId;
RunspacePoolId = clientRunspacePoolId;
RemoteStreamOptions = streamOptions;
#if !CORECLR // No ApartmentState In CoreCLR
this.apartmentState = apartmentState;
#endif
LocalPowerShell = powershell;
_extraPowerShell = extraPowerShell;
_localPowerShellOutput = new PSDataCollection<PSObject>();
@@ -298,9 +232,7 @@ namespace System.Management.Automation
}
PSInvocationSettings settings = new PSInvocationSettings();
#if !CORECLR // No ApartmentState In CoreCLR
settings.ApartmentState = apartmentState;
#endif
settings.Host = _remoteHost;
// Flow the impersonation policy to pipeline execution thread
@@ -95,46 +95,6 @@ namespace System.Management.Automation
#region Constructors
#if CORECLR // No ApartmentState In CoreCLR
/// <summary>
/// Creates the runspace pool driver.
/// </summary>
/// <param name="clientRunspacePoolId">Client runspace pool id to associate.</param>
/// <param name="transportManager">transport manager associated with this
/// runspace pool driver</param>
/// <param name="maxRunspaces">Maximum runspaces to open.</param>
/// <param name="minRunspaces">Minimum runspaces to open.</param>
/// <param name="threadOptions">Threading options for the runspaces in the pool.</param>
/// <param name="hostInfo">Host information about client side host.</param>
/// <param name="configData">
/// Contains:
/// 1. Script to run after a RunspacePool/Runspace is created in this session.
/// For RunspacePool case, every newly created Runspace (in the pool) will run
/// this script.
/// 2. ThreadOptions for RunspacePool/Runspace
/// 3. ThreadApartment for RunspacePool/Runspace
/// </param>
/// <param name="initialSessionState">Configuration of the runspace.</param>
/// <param name="applicationPrivateData">Application private data.</param>
/// <param name="isAdministrator">True if the driver is being created by an administrator.</param>
/// <param name="serverCapability">Server capability reported to the client during negotiation (not the actual capability).</param>
/// <param name="psClientVersion">Client PowerShell version.</param>
/// <param name="configurationName">Optional endpoint configuration name to create a pushed configured runspace.</param>
internal ServerRunspacePoolDriver(
Guid clientRunspacePoolId,
int minRunspaces,
int maxRunspaces,
PSThreadOptions threadOptions,
HostInfo hostInfo,
InitialSessionState initialSessionState,
PSPrimitiveDictionary applicationPrivateData,
ConfigurationDataFromXML configData,
AbstractServerSessionTransportManager transportManager,
bool isAdministrator,
RemoteSessionCapability serverCapability,
Version psClientVersion,
string configurationName)
#else
/// <summary>
/// Creates the runspace pool driver.
/// </summary>
@@ -175,7 +135,6 @@ namespace System.Management.Automation
RemoteSessionCapability serverCapability,
Version psClientVersion,
string configurationName)
#endif
{
Dbg.Assert(configData != null, "ConfigurationData cannot be null");
@@ -213,7 +172,6 @@ namespace System.Management.Automation
RunspacePool.ThreadOptions = threadOptions;
}
#if !CORECLR // No ApartmentState In CoreCLR
// Set Thread ApartmentState for this RunspacePool
ApartmentState serverApartmentState = configData.ShellThreadApartmentState.HasValue ? configData.ShellThreadApartmentState.Value : Runspace.DefaultApartmentState;
@@ -225,7 +183,6 @@ namespace System.Management.Automation
{
RunspacePool.ApartmentState = apartmentState;
}
#endif
// If we have a runspace pool with a single runspace then we can run nested pipelines on
// on it in a single pipeline invoke thread.
@@ -579,9 +536,7 @@ namespace System.Management.Automation
Guid.Empty,
this.InstanceId,
this,
#if !CORECLR // No ApartmentState In CoreCLR
args.Runspace.ApartmentState,
#endif
hostInfo,
RemoteStreamOptions.AddInvocationInfo,
false,
@@ -760,9 +715,7 @@ namespace System.Management.Automation
// invoked from within the driver
HostInfo hostInfo = RemotingDecoder.GetHostInfo(data.Data);
#if !CORECLR // No ApartmentState In CoreCLR
ApartmentState apartmentState = RemotingDecoder.GetApartmentState(data.Data);
#endif
RemoteStreamOptions streamOptions = RemotingDecoder.GetRemoteStreamOptions(data.Data);
PowerShell powershell = RemotingDecoder.GetPowerShell(data.Data);
@@ -824,9 +777,7 @@ namespace System.Management.Automation
data.PowerShellId,
data.RunspacePoolId,
this,
#if !CORECLR // No ApartmentState In CoreCLR
apartmentState,
#endif
hostInfo,
streamOptions,
addToHistory,
@@ -883,9 +834,7 @@ namespace System.Management.Automation
data.PowerShellId,
data.RunspacePoolId,
this,
#if !CORECLR // No ApartmentState In CoreCLR
apartmentState,
#endif
hostInfo,
streamOptions,
addToHistory,
@@ -904,9 +853,7 @@ namespace System.Management.Automation
data.PowerShellId,
data.RunspacePoolId,
this,
#if !CORECLR // No ApartmentState In CoreCLR
apartmentState,
#endif
_remoteHost,
hostInfo,
streamOptions,
@@ -937,9 +884,7 @@ namespace System.Management.Automation
data.PowerShellId,
data.RunspacePoolId,
this,
#if !CORECLR // No ApartmentState In CoreCLR
apartmentState,
#endif
hostInfo,
streamOptions,
addToHistory,
@@ -971,9 +916,7 @@ namespace System.Management.Automation
data.PowerShellId,
data.RunspacePoolId,
this,
#if !CORECLR // No ApartmentState In CoreCLR
apartmentState,
#endif
hostInfo,
streamOptions,
addToHistory,
@@ -1085,9 +1028,7 @@ namespace System.Management.Automation
data.PowerShellId,
data.RunspacePoolId,
this,
#if !CORECLR // No ApartmentState In CoreCLR
ApartmentState.Unknown,
#endif
useRunspaceHost,
0 /* stream options */,
false /* addToHistory */,
@@ -1224,9 +1165,7 @@ namespace System.Management.Automation
powershellId,
runspacePoolId,
this,
#if !CORECLR // No ApartmentState In CoreCLR
ApartmentState.MTA,
#endif
hostInfo,
streamOptions,
addToHistory,
@@ -2519,9 +2458,7 @@ namespace System.Management.Automation
Guid powershellId,
Guid runspacePoolId,
ServerRunspacePoolDriver runspacePoolDriver,
#if !CORECLR // No ApartmentState In CoreCLR
ApartmentState apartmentState,
#endif
ServerRemoteHost remoteHost,
HostInfo hostInfo,
RemoteStreamOptions streamOptions,
@@ -2557,9 +2494,7 @@ namespace System.Management.Automation
powershellId,
runspacePoolId,
runspacePoolDriver,
#if !CORECLR // No ApartmentState In CoreCLR
apartmentState,
#endif
hostInfo,
streamOptions,
addToHistory,
@@ -74,9 +74,7 @@ namespace System.Management.Automation
// was created
private bool _addToHistory;
// associated with this powershell
#if !CORECLR // No ApartmentState In CoreCLR
private ApartmentState apartmentState; // apartment state for this powershell
#endif
// pipeline that runs the actual command.
private ServerSteppablePipelineSubscriber _eventSubscriber;
@@ -84,36 +82,6 @@ namespace System.Management.Automation
#endregion
#if CORECLR // No ApartmentState In CoreCLR
/// <summary>
/// Default constructor for creating ServerSteppablePipelineDriver...Used by server to concurrently
/// run 2 pipelines.
/// </summary>
/// <param name="powershell">Decoded powershell object.</param>
/// <param name="noInput">Whether there is input for this powershell.</param>
/// <param name="clientPowerShellId">The client powershell id.</param>
/// <param name="clientRunspacePoolId">The client runspacepool id.</param>
/// <param name="runspacePoolDriver">runspace pool driver
/// which is creating this powershell driver</param>
/// <param name="hostInfo">host info using which the host for
/// this powershell will be constructed</param>
/// <param name="streamOptions">Serialization options for the streams in this powershell.</param>
/// <param name="addToHistory">
/// true if the command is to be added to history list of the runspace. false, otherwise.
/// </param>
/// <param name="rsToUse">
/// If not null, this Runspace will be used to invoke Powershell.
/// If null, the RunspacePool pointed by <paramref name="runspacePoolDriver"/> will be used.
/// </param>
/// <param name="eventSubscriber">
/// Steppable pipeline event subscriber
/// </param>
/// <param name="powershellInput">Input collection of the PowerShell pipeline.</param>
internal ServerSteppablePipelineDriver(PowerShell powershell, bool noInput, Guid clientPowerShellId,
Guid clientRunspacePoolId, ServerRunspacePoolDriver runspacePoolDriver,
HostInfo hostInfo, RemoteStreamOptions streamOptions,
bool addToHistory, Runspace rsToUse, ServerSteppablePipelineSubscriber eventSubscriber, PSDataCollection<object> powershellInput)
#else
/// <summary>
/// Default constructor for creating ServerSteppablePipelineDriver...Used by server to concurrently
/// run 2 pipelines.
@@ -143,15 +111,12 @@ namespace System.Management.Automation
Guid clientRunspacePoolId, ServerRunspacePoolDriver runspacePoolDriver,
ApartmentState apartmentState, HostInfo hostInfo, RemoteStreamOptions streamOptions,
bool addToHistory, Runspace rsToUse, ServerSteppablePipelineSubscriber eventSubscriber, PSDataCollection<object> powershellInput)
#endif
{
LocalPowerShell = powershell;
InstanceId = clientPowerShellId;
RunspacePoolId = clientRunspacePoolId;
RemoteStreamOptions = streamOptions;
#if !CORECLR // No ApartmentState In CoreCLR
this.apartmentState = apartmentState;
#endif
NoInput = noInput;
_addToHistory = addToHistory;
_eventSubscriber = eventSubscriber;
@@ -856,9 +856,7 @@ namespace System.Management.Automation.Remoting
int minRunspaces = RemotingDecoder.GetMinRunspaces(rcvdData.Data);
int maxRunspaces = RemotingDecoder.GetMaxRunspaces(rcvdData.Data);
PSThreadOptions threadOptions = RemotingDecoder.GetThreadOptions(rcvdData.Data);
#if !CORECLR // No ApartmentState In CoreCLR
ApartmentState apartmentState = RemotingDecoder.GetApartmentState(rcvdData.Data);
#endif
HostInfo hostInfo = RemotingDecoder.GetHostInfo(rcvdData.Data);
if (_runspacePoolDriver != null)
@@ -878,9 +876,7 @@ namespace System.Management.Automation.Remoting
minRunspaces,
maxRunspaces,
threadOptions,
#if !CORECLR // No ApartmentState In CoreCLR
apartmentState,
#endif
hostInfo,
rsSessionStateToUse,
applicationPrivateData,
+58 -4
View File
@@ -240,7 +240,7 @@ Describe "ConsoleHost unit tests" -tags "Feature" {
'@
$testFilePath = Join-Path $TestDrive "test.ps1"
Set-Content -Path $testFilePath -Value $testScript
$observed = echo hello | pwsh $testFilePath e -
$observed = echo hello | pwsh -noprofile $testFilePath e -
$observed | Should -BeExactly "h-llo"
}
}
@@ -711,8 +711,62 @@ namespace StackTest {
$longPipeName = [string]::new("A", 200)
"`$pid" | & $powershell -CustomPipeName $longPipeName -c -
# 64 is the ExitCode for BadCommandLineParameter
$LASTEXITCODE | Should -Be 64
$LASTEXITCODE | Should -Be $ExitCodeBadCommandLineParameter
}
}
Context "ApartmentState WPF tests" -Tag Slow {
It "WPF requires STA and will work" -Skip:(!$IsWindows -or [System.Management.Automation.Platform]::IsNanoServer) {
add-type -AssemblyName presentationframework
$xaml = [xml]@"
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Name="Window" Title="Initial Window" WindowStartupLocation = "CenterScreen"
Width = "400" Height = "300" ShowInTaskbar = "True">
</Window>
"@
$reader = [System.Xml.XmlNodeReader]::new($xaml)
$Window = [System.Windows.Markup.XamlReader]::Load($reader)
# This will throw an exception if MTA
{ $Window.Show() } | Should -Not -Throw
$Window.Close()
}
}
Context "ApartmentState tests" {
It "Default apartment state for main thread is STA" -Skip:(!$IsWindows -or [System.Management.Automation.Platform]::IsNanoServer) {
[System.Threading.Thread]::CurrentThread.GetApartmentState() | Should -BeExactly "STA"
}
It "Default apartment state for new runspace is MTA" -Skip:(!$IsWindows) {
$ps = [powershell]::Create()
$ps.AddScript({[System.Threading.Thread]::CurrentThread.GetApartmentState()})
$ps.Invoke() | Should -BeExactly "MTA"
}
It "Should be able to set apartment state to: <apartment>" -Skip:(!$IsWindows -or [System.Management.Automation.Platform]::IsNanoServer) -TestCases @(
@{ apartment = "STA"; switch = "-sta" }
@{ apartment = "MTA"; switch = "-mta" }
) {
param ($apartment, $switch)
& $powershell $switch -noprofile -command "[System.Threading.Thread]::CurrentThread.GetApartmentState()" | Should -BeExactly $apartment
}
It "Should fail to set apartment state to: <switch>" -Skip:($IsWindows -and ![System.Management.Automation.Platform]::IsNanoServer) -TestCases @(
@{ switch = "-sta" }
@{ switch = "-mta" }
) {
param ($switch)
& $powershell $switch -noprofile -command exit
$LASTEXITCODE | Should -Be $ExitCodeBadCommandLineParameter
}
}
}
@@ -855,7 +909,7 @@ Describe 'Pwsh startup in directories that contain wild cards' -Tag CI {
param ( $dirname )
try {
Push-Location -LiteralPath "${TESTDRIVE}/${dirname}"
$result = & $powershell -c '(Get-Item .).Name'
$result = & $powershell -noprofile -c '(Get-Item .).Name'
$result | Should -BeExactly $dirname
}
finally {