3

System.Management.Automation.PowerShell クラスからスクリプトを実行する場合よりも、PowerShell からスクリプトを直接実行するパフォーマンスの方がはるかに速いのはなぜですか? PS で直接スクリプトを実行すると、1 秒もかかりませんが、以下のコードを使用して実行すると、Invoke に数分かかります。

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;
    }
}

スクリプト テキスト:

[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

C# でこのメソッドに対するスクリプトの実行をテストしたところ、このメソッドはスクリプトの実行に 2 秒もかかりませんでした。

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;
    }
}
4

0 に答える 0