diff --git a/dotnet-cli/ExecutingPowerShellScript/ExecutingPowerShellScript/ExecutingPowerShellScript.csproj b/dotnet-cli/ExecutingPowerShellScript/ExecutingPowerShellScript/ExecutingPowerShellScript.csproj
index 05f8c26c9d..e45a0046e6 100644
--- a/dotnet-cli/ExecutingPowerShellScript/ExecutingPowerShellScript/ExecutingPowerShellScript.csproj
+++ b/dotnet-cli/ExecutingPowerShellScript/ExecutingPowerShellScript/ExecutingPowerShellScript.csproj
@@ -2,13 +2,19 @@
Exe
- net7.0
+ net10.0
enable
enable
-
+
+
+
+
+
+ PreserveNewest
+
diff --git a/dotnet-cli/ExecutingPowerShellScript/ExecutingPowerShellScript/PSCustomRunspace.cs b/dotnet-cli/ExecutingPowerShellScript/ExecutingPowerShellScript/PSCustomRunspace.cs
index ed96f71ba5..f7b7ce1f80 100644
--- a/dotnet-cli/ExecutingPowerShellScript/ExecutingPowerShellScript/PSCustomRunspace.cs
+++ b/dotnet-cli/ExecutingPowerShellScript/ExecutingPowerShellScript/PSCustomRunspace.cs
@@ -1,56 +1,62 @@
-using Microsoft.PowerShell.Commands;
+using Microsoft.PowerShell.Commands;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
-namespace ExecutingPowerShellScript
+namespace ExecutingPowerShellScript;
+
+public class PSCustomRunspace : IDisposable
{
- public class PSCustomRunspace
+ private readonly Runspace _rs;
+
+ public PSCustomRunspace()
+ {
+ InitialSessionState iss = InitialSessionState.Create();
+ var entry = new SessionStateVariableEntry(
+ "AllowedCommands", new[] { "Get-Date" }, "List of allowed commands");
+ iss.Variables.Add(entry);
+
+ var getDateCmdlet = new SessionStateCmdletEntry("Get-Date",
+ typeof(GetDateCommand), "");
+ iss.Commands.Add(getDateCmdlet);
+
+ _rs = RunspaceFactory.CreateRunspace(iss);
+ _rs.Open();
+ }
+
+ public string ExecuteCommand(string command)
{
- private readonly Runspace? _rs;
+ using var ps = PowerShell.Create();
+ ps.Runspace = _rs;
+ ps.AddCommand(command);
+ var results = ps.Invoke();
- public PSCustomRunspace()
+ if (ps.HadErrors)
{
- InitialSessionState iss = InitialSessionState.Create();
- var entry = new SessionStateVariableEntry(
- "AllowedCommands", new[] { "Get-Date" }, "List of allowed commands");
- iss.Variables.Add(entry);
-
- var ms = new ModuleSpecification("Microsoft.PowerShell.Utility");
- iss.ImportPSModule(new[] { ms });
- var getDateCmdlet = new SessionStateCmdletEntry("Get-Date",
- typeof(GetDateCommand), "");
- iss.Commands.Add(getDateCmdlet);
- _rs = RunspaceFactory.CreateRunspace(iss);
- _rs.Open();
+ throw new InvalidOperationException(ps.Streams.Error[0].ToString());
}
- public string ExecuteCommand(string command)
+ return results.FirstOrDefault()?.ToString() ?? string.Empty;
+ }
+
+ public bool StartProcess(string processName)
+ {
+ try
{
using var ps = PowerShell.Create();
ps.Runspace = _rs;
- ps.AddCommand(command);
- var processes = ps.Invoke();
+ ps.AddCommand("Start-Process").AddArgument(processName);
+ ps.Invoke();
- return processes.First().ToString();
+ return true;
}
-
- public bool StartProcess(string processName)
+ catch (Exception)
{
- try
- {
- using (var ps = PowerShell.Create())
- {
- ps.Runspace = _rs;
- ps.AddCommand("Start-Process").AddArgument(processName);
- ps.Invoke();
-
- return true;
- }
- }
- catch (Exception)
- {
- return false;
- }
+ return false;
}
}
+
+ public void Dispose()
+ {
+ _rs.Dispose();
+ }
}
diff --git a/dotnet-cli/ExecutingPowerShellScript/ExecutingPowerShellScript/PowerShellClass.cs b/dotnet-cli/ExecutingPowerShellScript/ExecutingPowerShellScript/PowerShellClass.cs
index 2fe026c547..93b035b053 100644
--- a/dotnet-cli/ExecutingPowerShellScript/ExecutingPowerShellScript/PowerShellClass.cs
+++ b/dotnet-cli/ExecutingPowerShellScript/ExecutingPowerShellScript/PowerShellClass.cs
@@ -1,45 +1,42 @@
-using System.Management.Automation;
+using Microsoft.PowerShell;
+using System.Management.Automation;
+using System.Management.Automation.Runspaces;
-namespace ExecutingPowerShellScript
+namespace ExecutingPowerShellScript;
+
+public class PowerShellClass
{
- public class PowerShellClass
+ public bool ExecuteScript(string pathToScript)
{
- public bool ExecuteScript(string pathToScript)
- {
- using var ps = PowerShell.Create();
- ps.AddScript(pathToScript).Invoke();
- if (ps.HadErrors)
- {
- return false;
- }
- else
- {
- return true;
- }
- }
+ var iss = InitialSessionState.CreateDefault();
+ iss.ExecutionPolicy = ExecutionPolicy.Bypass;
- public string ExecuteCommand(string command)
- {
- using var ps = PowerShell.Create();
- ps.AddCommand(command);
- var processes = ps.Invoke();
+ using var ps = PowerShell.Create(iss);
+ ps.AddCommand(pathToScript).Invoke();
- return processes.First().ToString();
- }
+ return !ps.HadErrors;
+ }
- public bool StartProcess(string processName)
+ public string ExecuteCommand(string command)
+ {
+ using var ps = PowerShell.Create();
+ ps.AddCommand(command);
+ var results = ps.Invoke();
+
+ if (ps.HadErrors)
{
- using var ps = PowerShell.Create();
- ps.AddCommand("Start-Process").AddArgument(processName);
- ps.Invoke();
- if (ps.HadErrors)
- {
- return false;
- }
- else
- {
- return true;
- }
+ throw new InvalidOperationException(ps.Streams.Error[0].ToString());
}
+
+ return results.FirstOrDefault()?.ToString() ?? string.Empty;
+ }
+
+ public bool StartProcess(string processName)
+ {
+ using var ps = PowerShell.Create();
+ ps.AddCommand("Start-Process").AddArgument(processName);
+ ps.Invoke();
+
+ return !ps.HadErrors;
}
}
diff --git a/dotnet-cli/ExecutingPowerShellScript/ExecutingPowerShellScript/PowerShellResult.cs b/dotnet-cli/ExecutingPowerShellScript/ExecutingPowerShellScript/PowerShellResult.cs
new file mode 100644
index 0000000000..63cb50c5b4
--- /dev/null
+++ b/dotnet-cli/ExecutingPowerShellScript/ExecutingPowerShellScript/PowerShellResult.cs
@@ -0,0 +1,3 @@
+namespace ExecutingPowerShellScript;
+
+public record PowerShellResult(int ExitCode, string Output, string Error);
diff --git a/dotnet-cli/ExecutingPowerShellScript/ExecutingPowerShellScript/ProcessStart.cs b/dotnet-cli/ExecutingPowerShellScript/ExecutingPowerShellScript/ProcessStart.cs
index f6ee1c7d21..59999b5198 100644
--- a/dotnet-cli/ExecutingPowerShellScript/ExecutingPowerShellScript/ProcessStart.cs
+++ b/dotnet-cli/ExecutingPowerShellScript/ExecutingPowerShellScript/ProcessStart.cs
@@ -1,40 +1,52 @@
-using System.Diagnostics;
+using System.Diagnostics;
-namespace ExecutingPowerShellScript
+namespace ExecutingPowerShellScript;
+
+public class ProcessStart
{
- public class ProcessStart
+ public async Task ExecuteScriptAsync(string pathToScript)
{
- public string ExecuteScript(string pathToScript)
+ var processStartInfo = new ProcessStartInfo("pwsh")
{
- var scriptArguments = "-ExecutionPolicy Bypass -File \"" + pathToScript + "\"";
- var processStartInfo = new ProcessStartInfo("powershell.exe", scriptArguments);
- processStartInfo.RedirectStandardOutput = true;
- processStartInfo.RedirectStandardError = true;
+ UseShellExecute = false,
+ RedirectStandardOutput = true,
+ RedirectStandardError = true
+ };
+ processStartInfo.ArgumentList.Add("-ExecutionPolicy");
+ processStartInfo.ArgumentList.Add("Bypass");
+ processStartInfo.ArgumentList.Add("-File");
+ processStartInfo.ArgumentList.Add(pathToScript);
+
+ using var process = new Process { StartInfo = processStartInfo };
+ process.Start();
- using var process = new Process();
- process.StartInfo = processStartInfo;
- process.Start();
- string output = process.StandardOutput.ReadToEnd();
- string error = process.StandardError.ReadToEnd();
+ var outputTask = process.StandardOutput.ReadToEndAsync();
+ var errorTask = process.StandardError.ReadToEndAsync();
+ await Task.WhenAll(outputTask, errorTask);
+ await process.WaitForExitAsync();
- return output;
- }
+ return new PowerShellResult(process.ExitCode, outputTask.Result, errorTask.Result);
+ }
- public string ExecuteCommand(string command)
+ public async Task ExecuteCommandAsync(string command)
+ {
+ var processStartInfo = new ProcessStartInfo("pwsh")
{
- ProcessStartInfo processStartInfo = new ProcessStartInfo();
- processStartInfo.FileName = "powershell.exe";
- processStartInfo.Arguments = $"-Command \"{command}\"";
- processStartInfo.UseShellExecute = false;
- processStartInfo.RedirectStandardOutput = true;
- using (var process = new Process())
- {
- process.StartInfo = processStartInfo;
- process.Start();
- string output = process.StandardOutput.ReadToEnd();
-
- return output;
- }
- }
+ UseShellExecute = false,
+ RedirectStandardOutput = true,
+ RedirectStandardError = true
+ };
+ processStartInfo.ArgumentList.Add("-Command");
+ processStartInfo.ArgumentList.Add(command);
+
+ using var process = new Process { StartInfo = processStartInfo };
+ process.Start();
+
+ var outputTask = process.StandardOutput.ReadToEndAsync();
+ var errorTask = process.StandardError.ReadToEndAsync();
+ await Task.WhenAll(outputTask, errorTask);
+ await process.WaitForExitAsync();
+
+ return new PowerShellResult(process.ExitCode, outputTask.Result, errorTask.Result);
}
-}
\ No newline at end of file
+}
diff --git a/dotnet-cli/ExecutingPowerShellScript/ExecutingPowerShellScript/Program.cs b/dotnet-cli/ExecutingPowerShellScript/ExecutingPowerShellScript/Program.cs
index 4216264fba..f55501cc2b 100644
--- a/dotnet-cli/ExecutingPowerShellScript/ExecutingPowerShellScript/Program.cs
+++ b/dotnet-cli/ExecutingPowerShellScript/ExecutingPowerShellScript/Program.cs
@@ -1,35 +1,21 @@
-namespace ExecutingPowerShellScript
-{
- internal class Program
- {
- static void Main(string[] args)
- {
- var processStart = new ProcessStart();
- var output1 = processStart.ExecuteScript(@"C:\Users\scule\Desktop\echo.ps1");
- Console.WriteLine(output1.ToString());
+using ExecutingPowerShellScript;
- var output2 = processStart.ExecuteCommand("echo 'I am invoked using echo command!'");
- Console.WriteLine(output2.ToString());
+var scriptPath = Path.Combine(AppContext.BaseDirectory, "echo.ps1");
- var powerShellClass = new PowerShellClass();
- var output3 = powerShellClass.ExecuteScript(@"C:\Users\scule\Desktop\echo.ps1");
- Console.WriteLine(output3.ToString());
+var processStart = new ProcessStart();
+var scriptResult = await processStart.ExecuteScriptAsync(scriptPath);
+Console.WriteLine(scriptResult.Output);
- var output4 = powerShellClass.ExecuteCommand("Get-Date");
- Console.WriteLine(output4);
+var commandResult = await processStart.ExecuteCommandAsync("echo 'I am invoked using echo command!'");
+Console.WriteLine(commandResult.Output);
- var output5 = powerShellClass.StartProcess("notepad");
- Console.WriteLine(output5.ToString());
+var powerShellClass = new PowerShellClass();
+Console.WriteLine(powerShellClass.ExecuteScript(scriptPath));
+Console.WriteLine(powerShellClass.ExecuteCommand("Get-Date"));
- var customRunspace = new PSCustomRunspace();
- var output6 = customRunspace.ExecuteCommand("Get-Date");
- Console.WriteLine(output6.ToString());
- customRunspace.StartProcess("notepad");
+// notepad is a Windows example; on Linux, start a GUI program such as gedit
+Console.WriteLine(powerShellClass.StartProcess("notepad"));
- var output7 = customRunspace.StartProcess("notepad");
- Console.WriteLine(output7.ToString());
-
- Console.ReadLine();
- }
- }
-}
\ No newline at end of file
+using var customRunspace = new PSCustomRunspace();
+Console.WriteLine(customRunspace.ExecuteCommand("Get-Date"));
+Console.WriteLine(customRunspace.StartProcess("notepad"));
diff --git a/dotnet-cli/ExecutingPowerShellScript/ExecutingPowerShellScript/echo.ps1 b/dotnet-cli/ExecutingPowerShellScript/ExecutingPowerShellScript/echo.ps1
new file mode 100644
index 0000000000..c7f1d33c81
--- /dev/null
+++ b/dotnet-cli/ExecutingPowerShellScript/ExecutingPowerShellScript/echo.ps1
@@ -0,0 +1 @@
+'I am invoked using ProcessStartInfoClass!'
diff --git a/dotnet-cli/ExecutingPowerShellScript/Tests/PSCustomRunspaceLiveTest.cs b/dotnet-cli/ExecutingPowerShellScript/Tests/PSCustomRunspaceLiveTest.cs
index 414f6d38ba..df93b9b1b2 100644
--- a/dotnet-cli/ExecutingPowerShellScript/Tests/PSCustomRunspaceLiveTest.cs
+++ b/dotnet-cli/ExecutingPowerShellScript/Tests/PSCustomRunspaceLiveTest.cs
@@ -1,27 +1,26 @@
-using ExecutingPowerShellScript;
+using ExecutingPowerShellScript;
-namespace Tests
+namespace Tests;
+
+public class PSCustomRunspaceLiveTest
{
- public class PSCustomRunspaceLiveTest
+ [Fact]
+ public void GivenCommand_WhenInvoked_ThenExecutesCommandGiven()
{
- [Fact]
- public void GivenCommand_WhenInvoked_ThenExecutesCommandGiven()
- {
- var customRunspace = new PSCustomRunspace();
- var result = customRunspace.ExecuteCommand("Get-Date");
- var expectedResult = DateTime.Now.ToShortDateString();
+ using var customRunspace = new PSCustomRunspace();
+
+ var result = customRunspace.ExecuteCommand("Get-Date");
- Assert.Equal(expectedResult, DateTime.Parse(result).ToShortDateString());
- }
+ Assert.Equal(DateTime.Now.ToShortDateString(), DateTime.Parse(result).ToShortDateString());
+ }
+
+ [Fact]
+ public void GivenName_WhenInvoked_ThenDoesntStartAProcess()
+ {
+ using var customRunspace = new PSCustomRunspace();
- [Fact]
- public void GivenName_WhenInvoked_ThenDoesntStartAProcess()
- {
- var customRunspace = new PSCustomRunspace();
- var result = customRunspace.StartProcess("notepad");
- var expectedResult = false;
+ var result = customRunspace.StartProcess("notepad");
- Assert.Equal(expectedResult, result);
- }
+ Assert.False(result);
}
}
diff --git a/dotnet-cli/ExecutingPowerShellScript/Tests/PowerShellClassLiveTest.cs b/dotnet-cli/ExecutingPowerShellScript/Tests/PowerShellClassLiveTest.cs
index 2571496cb4..dae366cd29 100644
--- a/dotnet-cli/ExecutingPowerShellScript/Tests/PowerShellClassLiveTest.cs
+++ b/dotnet-cli/ExecutingPowerShellScript/Tests/PowerShellClassLiveTest.cs
@@ -1,27 +1,37 @@
-using ExecutingPowerShellScript;
+using ExecutingPowerShellScript;
-namespace Tests
+namespace Tests;
+
+public class PowerShellClassLiveTest
{
- public class PowerShellClassLiveTest
+ [Fact]
+ public void GivenPath_WhenInvoked_ThenExecutesScript()
{
- [Fact]
- public void GivenCommand_WhenInvoked_ThenExecutesCommand()
- {
- var powerShellClass = new PowerShellClass();
- var result = powerShellClass.ExecuteCommand("Get-Date");
- var expected = true;
-
- Assert.Equal(expected, result!="");
- }
-
- [Fact]
- public void GivenName_WhenInvoked_ThenStartsAProcess()
- {
- var powerShellClass = new PowerShellClass();
- var result = powerShellClass.StartProcess("notepad");
- var expectedResult = "True";
-
- Assert.Equal(expectedResult, result.ToString());
- }
+ var powerShellClass = new PowerShellClass();
+ var scriptPath = Path.Combine(AppContext.BaseDirectory, "echo.ps1");
+
+ var result = powerShellClass.ExecuteScript(scriptPath);
+
+ Assert.True(result);
+ }
+
+ [Fact]
+ public void GivenCommand_WhenInvoked_ThenExecutesCommand()
+ {
+ var powerShellClass = new PowerShellClass();
+
+ var result = powerShellClass.ExecuteCommand("Get-Date");
+
+ Assert.NotEqual(string.Empty, result);
+ }
+
+ [Fact]
+ public void GivenName_WhenInvoked_ThenStartsAProcess()
+ {
+ var powerShellClass = new PowerShellClass();
+
+ var result = powerShellClass.StartProcess("notepad");
+
+ Assert.True(result);
}
}
diff --git a/dotnet-cli/ExecutingPowerShellScript/Tests/ProcessStartLiveTest.cs b/dotnet-cli/ExecutingPowerShellScript/Tests/ProcessStartLiveTest.cs
index d9bedf76f0..fee4e8192d 100644
--- a/dotnet-cli/ExecutingPowerShellScript/Tests/ProcessStartLiveTest.cs
+++ b/dotnet-cli/ExecutingPowerShellScript/Tests/ProcessStartLiveTest.cs
@@ -1,27 +1,41 @@
-using ExecutingPowerShellScript;
+using ExecutingPowerShellScript;
-namespace Tests
+namespace Tests;
+
+public class ProcessStartLiveTest
{
- public class ProcessStartLiveTest
+ [Fact]
+ public async Task GivenPath_WhenInvoked_ThenExecutesGivenScript()
{
- [Fact]
- public void GivenPath_WhenInvoked_ThenExecutesGivenScript()
- {
- var processStart = new ProcessStart();
- var result = processStart.ExecuteScript(@"C:\Users\scule\Desktop\echo.ps1");
- var expected= "I am invoked using ProcessStartInfoClass!\r\n";
-
- Assert.Equal(expected, result.ToString());
- }
-
- [Fact]
- public void GivenCommand_WhenInvoked_ThenExecutesGivenCommand()
- {
- var processStart = new ProcessStart();
- var result= processStart.ExecuteCommand("echo 'I am invoked using echo command!'");
- var expected = "I am invoked using echo command!\r\n";
-
- Assert.Equal(expected, result.ToString());
- }
+ var processStart = new ProcessStart();
+ var scriptPath = Path.Combine(AppContext.BaseDirectory, "echo.ps1");
+
+ var result = await processStart.ExecuteScriptAsync(scriptPath);
+
+ Assert.Equal(0, result.ExitCode);
+ Assert.Equal("I am invoked using ProcessStartInfoClass!" + Environment.NewLine, result.Output);
+ Assert.Equal(string.Empty, result.Error);
+ }
+
+ [Fact]
+ public async Task GivenCommand_WhenInvoked_ThenExecutesGivenCommand()
+ {
+ var processStart = new ProcessStart();
+
+ var result = await processStart.ExecuteCommandAsync("echo 'I am invoked using echo command!'");
+
+ Assert.Equal(0, result.ExitCode);
+ Assert.Equal("I am invoked using echo command!" + Environment.NewLine, result.Output);
+ }
+
+ [Fact]
+ public async Task GivenFailingCommand_WhenInvoked_ThenReturnsNonZeroExitCodeAndError()
+ {
+ var processStart = new ProcessStart();
+
+ var result = await processStart.ExecuteCommandAsync("Get-Item 'does-not-exist.txt'");
+
+ Assert.Equal(1, result.ExitCode);
+ Assert.NotEqual(string.Empty, result.Error);
}
}
diff --git a/dotnet-cli/ExecutingPowerShellScript/Tests/Tests.csproj b/dotnet-cli/ExecutingPowerShellScript/Tests/Tests.csproj
index 137567461d..a7c8f19621 100644
--- a/dotnet-cli/ExecutingPowerShellScript/Tests/Tests.csproj
+++ b/dotnet-cli/ExecutingPowerShellScript/Tests/Tests.csproj
@@ -1,7 +1,7 @@
- net7.0
+ net10.0
enable
enable
@@ -9,13 +9,13 @@
-
-
-
+
+
+
runtime; build; native; contentfiles; analyzers; buildtransitive
all
-
+
runtime; build; native; contentfiles; analyzers; buildtransitive
all