mirror of
https://github.com/PowerShell/PowerShell
synced 2026-06-08 12:12:50 +00:00
Make 'Start-Job' throw terminating error when PowerShell is being hosted (#9128)
This commit is contained in:
@@ -14,17 +14,18 @@ namespace System.Management.Automation.Runspaces
|
||||
/// </summary>
|
||||
public sealed class PowerShellProcessInstance : IDisposable
|
||||
{
|
||||
#region Private Members
|
||||
#region Fields
|
||||
|
||||
private readonly ProcessStartInfo _startInfo;
|
||||
private static readonly string s_PSExePath;
|
||||
private RunspacePool _runspacePool;
|
||||
private readonly object _syncObject = new object();
|
||||
private bool _started;
|
||||
private bool _isDisposed;
|
||||
private bool _processExited;
|
||||
|
||||
#endregion Private Members
|
||||
internal static readonly string PwshExePath;
|
||||
|
||||
#endregion Fields
|
||||
|
||||
#region Constructors
|
||||
|
||||
@@ -33,11 +34,9 @@ namespace System.Management.Automation.Runspaces
|
||||
static PowerShellProcessInstance()
|
||||
{
|
||||
#if UNIX
|
||||
s_PSExePath = Path.Combine(Utils.DefaultPowerShellAppBase,
|
||||
"pwsh");
|
||||
PwshExePath = Path.Combine(Utils.DefaultPowerShellAppBase, "pwsh");
|
||||
#else
|
||||
s_PSExePath = Path.Combine(Utils.DefaultPowerShellAppBase,
|
||||
"pwsh.exe");
|
||||
PwshExePath = Path.Combine(Utils.DefaultPowerShellAppBase, "pwsh.exe");
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -49,16 +48,16 @@ namespace System.Management.Automation.Runspaces
|
||||
/// <param name="useWow64"></param>
|
||||
public PowerShellProcessInstance(Version powerShellVersion, PSCredential credential, ScriptBlock initializationScript, bool useWow64)
|
||||
{
|
||||
string psWow64Path = s_PSExePath;
|
||||
string psWow64Path = PwshExePath;
|
||||
|
||||
if (useWow64)
|
||||
{
|
||||
string procArch = Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE");
|
||||
|
||||
if ((!string.IsNullOrEmpty(procArch)) && (procArch.Equals("amd64", StringComparison.OrdinalIgnoreCase) ||
|
||||
procArch.Equals("ia64", StringComparison.OrdinalIgnoreCase)))
|
||||
if (!string.IsNullOrEmpty(procArch) && (procArch.Equals("amd64", StringComparison.OrdinalIgnoreCase) ||
|
||||
procArch.Equals("ia64", StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
psWow64Path = s_PSExePath.ToLowerInvariant().Replace("\\system32\\", "\\syswow64\\");
|
||||
psWow64Path = PwshExePath.ToLowerInvariant().Replace("\\system32\\", "\\syswow64\\");
|
||||
|
||||
if (!File.Exists(psWow64Path))
|
||||
{
|
||||
@@ -71,21 +70,7 @@ namespace System.Management.Automation.Runspaces
|
||||
}
|
||||
}
|
||||
|
||||
#if CORECLR
|
||||
string processArguments = " -s -NoLogo -NoProfile";
|
||||
#else
|
||||
// Adding Version parameter to powershell
|
||||
// Version parameter needs to go before all other parameters because the native layer looks for Version or
|
||||
// PSConsoleFile parameters before parsing other parameters.
|
||||
// The other parameters get parsed in the managed layer.
|
||||
Version tempVersion = powerShellVersion ?? PSVersionInfo.PSVersion;
|
||||
string processArguments = string.Format(CultureInfo.InvariantCulture,
|
||||
"-Version {0}", new Version(tempVersion.Major, tempVersion.Minor));
|
||||
|
||||
processArguments = string.Format(CultureInfo.InvariantCulture,
|
||||
"{0} -s -NoLogo -NoProfile", processArguments);
|
||||
|
||||
#endif
|
||||
|
||||
if (initializationScript != null)
|
||||
{
|
||||
@@ -103,7 +88,7 @@ namespace System.Management.Automation.Runspaces
|
||||
// to 'false' in our use, we can ignore the 'WindowStyle' setting in the initialization below.
|
||||
_startInfo = new ProcessStartInfo
|
||||
{
|
||||
FileName = useWow64 ? psWow64Path : s_PSExePath,
|
||||
FileName = useWow64 ? psWow64Path : PwshExePath,
|
||||
Arguments = processArguments,
|
||||
UseShellExecute = false,
|
||||
RedirectStandardInput = true,
|
||||
|
||||
@@ -781,7 +781,7 @@ namespace Microsoft.PowerShell.Commands
|
||||
/// </summary>
|
||||
[Parameter(ValueFromPipelineByPropertyName = true,
|
||||
ParameterSetName = InvokeCommandCommand.SSHHostParameterSet)]
|
||||
public string Subsystem { get; set; }
|
||||
public virtual string Subsystem { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Management.Automation;
|
||||
using System.Management.Automation.Internal;
|
||||
using System.Management.Automation.Remoting;
|
||||
@@ -197,6 +198,22 @@ namespace Microsoft.PowerShell.Commands
|
||||
get { return null; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Suppress HostName.
|
||||
/// </summary>
|
||||
public override string[] HostName
|
||||
{
|
||||
get { return null; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Suppress Subsystem.
|
||||
/// </summary>
|
||||
public override string Subsystem
|
||||
{
|
||||
get { return null; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
@@ -548,6 +565,25 @@ namespace Microsoft.PowerShell.Commands
|
||||
/// </summary>
|
||||
protected override void BeginProcessing()
|
||||
{
|
||||
if (!File.Exists(PowerShellProcessInstance.PwshExePath))
|
||||
{
|
||||
// The pwsh executable file is not found under $PSHOME.
|
||||
// This means that PowerShell is currently being hosted in another application,
|
||||
// and 'Start-Job' is not supported by design in that scenario.
|
||||
string message = StringUtil.Format(
|
||||
RemotingErrorIdStrings.IPCPwshExecutableNotFound,
|
||||
PowerShellProcessInstance.PwshExePath);
|
||||
|
||||
var exception = new PSNotSupportedException(message);
|
||||
var errorRecord = new ErrorRecord(
|
||||
exception,
|
||||
"IPCPwshExecutableNotFound",
|
||||
ErrorCategory.NotInstalled,
|
||||
PowerShellProcessInstance.PwshExePath);
|
||||
|
||||
ThrowTerminatingError(errorRecord);
|
||||
}
|
||||
|
||||
CommandDiscovery.AutoloadModulesWithJobSourceAdapters(this.Context, this.CommandOrigin);
|
||||
|
||||
if (ParameterSetName == DefinitionNameParameterSet)
|
||||
|
||||
@@ -787,6 +787,10 @@ Do you want to continue?</value>
|
||||
<data name="IPCSupportsOnlyDefaultAuth" xml:space="preserve">
|
||||
<value>The specified authentication mechanism "{0}" is not supported. Only "{1}" is supported for this operation.</value>
|
||||
</data>
|
||||
<data name="IPCPwshExecutableNotFound" xml:space="preserve">
|
||||
<value>The pwsh executable cannot be found at "{0}".
|
||||
Note that 'Start-Job' is not supported by design in scenarios where PowerShell is being hosted in other applications. Instead, usage of the 'ThreadJob' module is recommended in such scenarios.</value>
|
||||
</data>
|
||||
<data name="IPCWowComponentNotPresent" xml:space="preserve">
|
||||
<value>The "{0}" executable file was not found. Verify that the WOW64 feature is installed.</value>
|
||||
</data>
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using System;
|
||||
using System.Management.Automation;
|
||||
using Xunit;
|
||||
|
||||
namespace PSTests.Sequential
|
||||
{
|
||||
// Not static because a test requires non-const variables
|
||||
public static class PowerShellHostingScenario
|
||||
{
|
||||
// Test that it does not throw an exception
|
||||
[Fact]
|
||||
public static void TestStartJobThrowTerminatingException()
|
||||
{
|
||||
using (var ps = PowerShell.Create())
|
||||
{
|
||||
ps.AddCommand("Start-Job").AddParameter("ScriptBlock", ScriptBlock.Create("1+1"));
|
||||
var ex = Assert.Throws<CmdletInvocationException>(() => ps.Invoke());
|
||||
Assert.IsType<PSNotSupportedException>(ex.InnerException);
|
||||
Assert.Equal("IPCPwshExecutableNotFound,Microsoft.PowerShell.Commands.StartJobCommand", ex.ErrorRecord.FullyQualifiedErrorId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user