简体   繁体   中英

How can I execute scripts in a code created powershell shell that has Write-Host commands in it?

I have a script that I am writing which relies on functions in an imported module. This script takes a while due to IO (web requests) and I would like to parallize it for hundreds of thousands of iterations of a script block.

After attempting several different methods (with little success due to restrictions with Start-Job and other things) the current implementation relies on pre-creating a pool of powershell "shells" created via $shell = [Powershell]::Create() .

One of the module methods I have to call to bootstrap the shell (so it's in a correct state) has a call to Write-Host in it. When I call $shell.Invoke() the following error occurs:

Write-Host: A command that prompts the user failed because the host program or the command type does not support user interaction. Try a host program that supports user interaction, such as the Windows PowerShell Console or Windows PowerShell ISE, and remove prompt-related commands from command types that do not support user interaction, such as Windows PowerShell workflows.

Now, since the module is custom I can remove the Write-Host calls, but that reduces user friendliness when it is run directly by end users. I can create a switch parameter that does not execute Write-Host if the parameter is true, but to do that down the line is a good bit of work (feasible, but I'd rather not).

Is there any way I can get Write-Host to not error out in this scenario? I don't actually care about the input in this scenario, I just don't want the errors.

The fastest way to get this to work is to define a dummy write-host function in your script, or to simply define it in the runspace independently before running your script.

$ps.addscript("function write-host {}").invoke()
$ps.commands.clear()
# now you can invoke scripts that use write-host
# feel free to implement a write-host that writes to a log file

Simple as that. The reason you're getting that error is because programmatic invocation like that does not expect user interaction. There are ways to make this work but it employs different APIs.

If you need the output, you can use:

$ps.addscript("function write-host($out) {write-output $out}").invoke()
$ps.commands.clear()

尝试将您的 WMF 版本更改为 5.1 - https://www.microsoft.com/en-us/download/details.aspx?id=54616

If you want to keep using the Pipeline class, you can use the Command.MergeMyResults [method][1]. For example, to redirect all type of streams to pipeline output:

private string RunScript(string scriptText) {

    Runspace runspace = RunspaceFactory.CreateRunspace();

    runspace.Open();

    Pipeline pipeline = runspace.CreatePipeline();
    pipeline.Commands.AddScript("Write-Host Test");
    pipeline.Commands[pipeline.Commands.Count-1]
       .MergeMyResults(PipelineResultTypes.All, PipelineResultTypes.Output)
    
    Collection < PSObject > results = pipeline.Invoke();

    runspace.Close();

    foreach(PSObject obj in results) {
        Console.WriteLine(obj.ToString());
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM