diff --git a/src/System.Management.Automation/engine/hostifaces/PowerShellProcessInstance.cs b/src/System.Management.Automation/engine/hostifaces/PowerShellProcessInstance.cs
index e7ace3aad5..efa8271193 100644
--- a/src/System.Management.Automation/engine/hostifaces/PowerShellProcessInstance.cs
+++ b/src/System.Management.Automation/engine/hostifaces/PowerShellProcessInstance.cs
@@ -14,17 +14,18 @@ namespace System.Management.Automation.Runspaces
///
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
///
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,
diff --git a/src/System.Management.Automation/engine/remoting/commands/PSRemotingCmdlet.cs b/src/System.Management.Automation/engine/remoting/commands/PSRemotingCmdlet.cs
index 5f2ba937dc..f5faf6123e 100644
--- a/src/System.Management.Automation/engine/remoting/commands/PSRemotingCmdlet.cs
+++ b/src/System.Management.Automation/engine/remoting/commands/PSRemotingCmdlet.cs
@@ -781,7 +781,7 @@ namespace Microsoft.PowerShell.Commands
///
[Parameter(ValueFromPipelineByPropertyName = true,
ParameterSetName = InvokeCommandCommand.SSHHostParameterSet)]
- public string Subsystem { get; set; }
+ public virtual string Subsystem { get; set; }
#endregion
diff --git a/src/System.Management.Automation/engine/remoting/commands/StartJob.cs b/src/System.Management.Automation/engine/remoting/commands/StartJob.cs
index 7e8c160f9d..b6156efb05 100644
--- a/src/System.Management.Automation/engine/remoting/commands/StartJob.cs
+++ b/src/System.Management.Automation/engine/remoting/commands/StartJob.cs
@@ -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; }
}
+ ///
+ /// Suppress HostName.
+ ///
+ public override string[] HostName
+ {
+ get { return null; }
+ }
+
+ ///
+ /// Suppress Subsystem.
+ ///
+ public override string Subsystem
+ {
+ get { return null; }
+ }
+
#endregion
///
@@ -548,6 +565,25 @@ namespace Microsoft.PowerShell.Commands
///
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)
diff --git a/src/System.Management.Automation/resources/RemotingErrorIdStrings.resx b/src/System.Management.Automation/resources/RemotingErrorIdStrings.resx
index e100c8babc..daad2f6ad3 100644
--- a/src/System.Management.Automation/resources/RemotingErrorIdStrings.resx
+++ b/src/System.Management.Automation/resources/RemotingErrorIdStrings.resx
@@ -787,6 +787,10 @@ Do you want to continue?
The specified authentication mechanism "{0}" is not supported. Only "{1}" is supported for this operation.
+
+ 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.
+
The "{0}" executable file was not found. Verify that the WOW64 feature is installed.
diff --git a/test/xUnit/csharp/test_PowerShellAPI.cs b/test/xUnit/csharp/test_PowerShellAPI.cs
new file mode 100644
index 0000000000..7a54f9008e
--- /dev/null
+++ b/test/xUnit/csharp/test_PowerShellAPI.cs
@@ -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(() => ps.Invoke());
+ Assert.IsType(ex.InnerException);
+ Assert.Equal("IPCPwshExecutableNotFound,Microsoft.PowerShell.Commands.StartJobCommand", ex.ErrorRecord.FullyQualifiedErrorId);
+ }
+ }
+ }
+}