Why is performance of executing a script from PowerShell directly much quicker than when executing the script from the System.Management.Automation.PowerShell class? When I execute my script directly in PS, it takes less than a second, though when I execute it through the code below, the Invoke takes several minutes.
public bool Execute(string filename, out string result)
{
StringBuilder sb = new StringBuilder();
using (PowerShell ps = PowerShell.Create())
{
ps.Runspace.SessionStateProxy.SetVariable("filename", filename);
ps.AddScript(this.script);
Collection<PSObject> psOutput = ps.Invoke();
foreach (PSObject item in psOutput)
{
Console.WriteLine(item);
}
PSDataCollection<ErrorRecord> errors = ps.Streams.Error;
foreach (ErrorRecord err in errors)
{
Console.WriteLine(err);
}
result = sb.ToString();
return errors.Count == 0;
}
}
Script text:
[regex]$r = "\$\%\$@@(.+)\$\%\$@@";
(Get-Content $filename) |
Foreach-Object {
$line = $_;
$find = $r.matches($line);
if ($find[0].Success) {
foreach ($match in $find) {
$found = $match.value
$replace = $found -replace "[^A-Za-z0-9\s]", "";
$line.Replace($found, $replace);
}
}
else
{
$line;
}
} |
Set-Content $filename
I tested the execution of the script against this method in c#, and this method takes less than 2 seconds to execute the script.
public bool Execute(string filename, out string result)
{
StringBuilder standardOutput = new StringBuilder();
string currentPath = Path.GetDirectoryName(filename);
string psFile = Path.Combine(currentPath, Path.GetFileNameWithoutExtension(Path.GetRandomFileName()) + ".ps1");
this.script = this.script.Replace("$filename", "\"" + filename + "\"");
File.WriteAllText(psFile, this.script);
using (Process process = new Process())
{
process.StartInfo = new ProcessStartInfo("powershell.exe", String.Format("-executionpolicy unrestricted \"{0}\"", psFile))
{
WindowStyle = ProcessWindowStyle.Hidden,
UseShellExecute = false,
RedirectStandardOutput = true
};
process.Start();
var output = process.StandardOutput.ReadToEnd();
while (!process.HasExited)
{
standardOutput.Append(process.StandardOutput.ReadToEnd());
}
process.WaitForExit();
standardOutput.Append(process.StandardOutput.ReadToEnd());
result = standardOutput.ToString();
return process.ExitCode == 0;
}
}