Я пытаюсь использовать PowerShell в качестве бинарного CGI из IIS Express. Я получил его на работу, но с глупой работой, которая мне не особенно нравится. Я хотел бы понять, почему это необходимо.
Вот простой файл 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=""%SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe" -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://localhost:8080/hello.cgi
, я получаю сообщение об ошибке:
Ошибка HTTP 502.2 - Bad Gateway
Указанное приложение CGI плохо себя ведет, не возвращая полный набор заголовков HTTP. Заголовки, которые он вернул, - это "".
Я посмотрел с 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!
Хм... Что делать, если я запускаю powershell.exe из скрипта cgi.cmd? Это тоже не сработало - весь вывод из сценария cmd возвращается в IIS Express; выход PowerShell все еще где-то потерян.
Однако интересно то, что когда я это делал (вызывается PowerShell из сценария cmd), появляется окно PowerShell, которое мигает при каждом обновлении страницы. Таким образом, похоже, что PowerShell выполняет мой скрипт только в новом окне, поэтому stdin/stdout не подключен к CGI в IIS.
Что делать, если я использую start/b powershell.exe...
в сценарии cmd? Это не изменило ситуацию.
Что делать, если я устанавливаю system.webServer/cgi/createCGIWithNewConsole = true
в конфигурации IIS Express? Это тоже не сработало, но с каждым запросом это вызвало появление консоли 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
; но не start/b
делать то же самое? Почему моя маленькая программа-обертка может перенаправлять ввод и вывод из файла powershell.exe просто отлично, но модуль CGI в IIS Express не может?
Сводный вопрос: как я могу использовать 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 "%s" %s" resourceType="File" requireAccess="Script" />
</handlers>
</system.webServer>
</configuration>