redirecting cmd.exe to httpresponse

2007-10-16 @ 00:52#

i had to solve an interesting problem today and it involved the ability to fire off command line processes from a web UI on IIS. since this was a 'triage' situation, i had a very short time to work out the details. i remembered that .NET exposes the Process and ProcessStartInfo objects that give you quite a bit of control over spawning command shells. with a little poking about, i was able to create a simple ASP.NET page that does the trick.

i made sure to place the ASPX page in a folder that requires a successful Windows auth to make sure only auth'ed users can run the script. it's an internal site, so there's reduced risk of hacking, but it's still a bit dicey to do this.

here's a simple example that will run a small batch file:

<%@ Page Language="C#" %>
<%@ Import Namespace="System.Diagnostics" %>
<%@ Import Namespace="System.IO" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "">
<script runat="server">
    void Submit(object sender, EventArgs args)
        string fmt_html = "<pre>{0}</pre>";
        string batch_cmd = @"cmd.exe";
        string working_dir = @"z:\jobs\";
        string batch_job = @"z:\jobs\dirlist.bat";
        string output = "";

        // set up process to redirect std in/out
        ProcessStartInfo psi = new ProcessStartInfo(batch_cmd);
        psi.WorkingDirectory = working_dir;
        psi.RedirectStandardOutput = true;
        psi.RedirectStandardInput = true;
        psi.RedirectStandardError = true;
        psi.UseShellExecute = false;

            // execute the job
            using (StreamReader batch_rdr = File.OpenText(batch_job))
                using (Process proc = Process.Start(psi))
                    using (StreamReader std_out = proc.StandardOutput)
                        using (StreamWriter std_in = proc.StandardInput)
                            // direct batch file to std_in
                            while (!batch_rdr.EndOfStream)

                            // stream std_out to a string.
                            output = std_out.ReadToEnd().Trim();
        catch (Exception ex)
            output = ex.Message;

        // Write out the results.
        results.Text = String.Format(fmt_html, output);
<html xmlns="" >
<head runat="server">
    <title>simple batch job</title>
    <form runat="server">
    <div><asp:Button Text="Run" OnClick="Submit" runat="server" /></div>
    <div><asp:Label ID="results" runat="server" /></div>

the output looks something like this:

Microsoft Windows [Version 5.2.3790]
(C) Copyright 1985-2003 Microsoft Corp.

Z:\jobs\>dir c:\ /B
Documents and Settings
Program Files