c# – 在IIS Express中使用PowerShell作为CGI二进制文件

我正在尝试使用Power
Shell作为IIS Express的CGI二进制文件.我得到了它的工作,但有一个愚蠢的解决方案,我不是特别喜欢.我想了解为什么需要解决这个问题.

这是一个简单的cgi.ps1文件,我用来试试这个:

"HTTP/1.1 200 OK`r`nContent-Type: text/plain`r`n`r`n"

Get-ChildItem env:

与此web.config文件一起:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <handlers>
            <add name="PowerShell CGI" path="*.cgi" verb="GET,HEAD,POST" modules="CgiModule" scriptProcessor="&quot;%SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe&quot; -NoLogo -NoProfile -NonInteractive -ExecutionPolicy Unrestricted -File C:\Users\Nikhil\Documents\GitHub\PowerShellCGI\App\cgi.ps1"/>
        </handlers>
    </system.webServer>
</configuration>

然后,在此目录中启动IIS Express并导航到http:// localhost:8080 / hello.cgi后,出现错误:

HTTP Error 502.2 – Bad Gateway
The specified CGI application
misbehaved by not returning a complete set of HTTP headers. The
headers it did return are “”.

我看了Process Monitor,而powershell.exe实际上是用正确的参数启动的. IIS Express跟踪日志文件显示退出代码为0,但输出流中没有任何内容.奇怪的是,从IIS Express启动时,powershell.exe甚至从不读取我的ps1文件;如果我在使用Process Monitor捕获事件时手动使用相同的命令行,我可以看到正在读取的文件.

接下来,我试图查看一个普通的cmd.exe批处理脚本是否可以用作CGI脚本.这很好用;这是我使用的简单cgi.cmd:

@echo off
echo HTTP/1.1 200 OK
echo Content-Type: text/plain
echo.
echo Hello, World!

嗯……如果我从cgi.cmd脚本中启动powershell.exe怎么办?这也不起作用 – cmd脚本的所有输出都返回到IIS Express; PowerShell输出仍在某处丢失.

然而,有趣的是,当我这样做时(从cmd脚本调用PowerShell),每个页面刷新时都会有一个PowerShell窗口闪烁.所以看起来PowerShell只在新窗口中执行我的脚本,因此stdin / stdout没有连接到IIS中的CGI.

如果我在cmd脚本中使用start / b powershell.exe …该怎么办?这并没有什么不同.

如果我在IIS Express配置中设置system.webServer / cgi / createCGIWithNewConsole = true怎么办?这也没有用,但确实有一个PowerShell控制台弹出每个请求的效果.

解决方法

我认为问题是powershell.exe想要一个自己的控制台,当它启动一个新的控制台时,输入和输出重定向不再连接到新的控制台.

这就是我最终让它工作的原因:我编写了一个瘦启动器来启动powershell.exe,并重定向stdio,stdout和stderr.这是完整的Program.cs:

using System;
using System.Diagnostics;

namespace PowerShell_CGI
{
    class Program
    {
        static void Main(string[] args)
        {
            var process = new Process();
            process.StartInfo = new ProcessStartInfo
            {
                FileName = "powershell.exe",
                Arguments = String.Join(" ", args),
                UseShellExecute = false,
                RedirectStandardInput = true,
                RedirectStandardOutput = true,
                RedirectStandardError = true,
                CreateNoWindow = true
            };

            process.OutputDataReceived += (sender, e) =>
            {
                Console.WriteLine(e.Data);
            };

            process.ErrorDataReceived += (sender, e) =>
            {
                Console.Error.WriteLine(e.Data);
            };

            process.Start();
            process.BeginOutputReadLine();
            process.BeginErrorReadLine();

            process.StandardInput.Write(Console.In.ReadToEnd());

            process.WaitForExit();
        }
    }
}

现在,在我的web.config中使用这一行,一切正常:

<add name="PowerShell-CGI" path="*" verb="GET,HEAD,POST" modules="CgiModule" scriptProcessor="C:\Users\Nikhil\Documents\GitHub\PowerShellCGI\App\PowerShell-CGI.exe -NoLogo -NoProfile -NonInteractive -ExecutionPolicy Unrestricted -File C:\Users\Nikhil\Documents\GitHub\PowerShellCGI\App\cgi.ps1" />

我的问题是:为什么需要这种愚蠢的解决方法?我的程序只是执行powershell.exe,它具有相同的参数,相同的stdio,相同的stdout,以及它获得的相同stderr.我怀疑它可能与CreateNoWindow标志有关;但是不是开始/做同样的事情吗?为什么我的小包装程序可以重定向powershell.exe的输入和输出就好了,但IIS Express中的CGI模块不能?

推论问题:我如何使用powershell.exe作为CGI二进制文件,没有任何黑客可以使它工作?我希望它看起来像cmd.exe一样简单.

最佳答案 如果有人感兴趣,我遇到了同样的问题,并且能够使用IIS 8.5上的以下配置解决它.

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <handlers>
            <add name="PowerShell CGI" path="*.ps1" verb="GET,POST,HEAD" modules="CgiModule" scriptProcessor="C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -NoLogo -NoProfile -NonInteractive -File &quot;%s&quot; %s" resourceType="File" requireAccess="Script" />
        </handlers>
    </system.webServer>
</configuration>
点赞