简体   繁体   中英

Executing powershell .ps1 file on server and viewing results C# asp.net

I'm trying to execute a .ps1 PowerShell file on my server using a C# asp.net webpage. The script takes one parameter, and I've verified that it works by using the command prompt on the server. After it runs, I need to display the results on the webpage.

Currently, I'm using:

protected void btnClickCmdLine(object sender, EventArgs e)
{
    lblResults.Text = "Please wait...";
    try
    {
        string tempGETCMD = null;
        Process CMDprocess = new Process();
        System.Diagnostics.ProcessStartInfo StartInfo = new System.Diagnostics.ProcessStartInfo();
        StartInfo.FileName = "cmd"; //starts cmd window
        StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
        StartInfo.CreateNoWindow = true;
        StartInfo.RedirectStandardInput = true;
        StartInfo.RedirectStandardOutput = true;
        StartInfo.UseShellExecute = false; //required to redirect
        CMDprocess.StartInfo = StartInfo;
        CMDprocess.Start();
        lblResults.Text = "Starting....";
        System.IO.StreamReader SR = CMDprocess.StandardOutput;
        System.IO.StreamWriter SW = CMDprocess.StandardInput;
        SW.WriteLine("@echo on");

        SW.WriteLine("cd C:\\Tools\\PowerShell\\");

       SW.WriteLine("powershell .\\poweron.ps1 **parameter**");

        SW.WriteLine("exit"); //exits command prompt window
        tempGETCMD = SR.ReadToEnd(); //returns results of the command window
        lblResults.Text = tempGETCMD;
        SW.Close();
        SR.Close();
    }
    catch (Exception ex)
    {
        lblErrorMEssage.Text = ex.ToString();
        showError();
    }
}

However, it won't even display the initial "Please wait.." if I include the line where it calls powershell. It will just eventually timeout, even though I have increased the AsyncPostBackTimeout on the ScriptManager. Can anyone please tell me what I'm doing wrong? Thanks

A little dated; however, to those in search of a similar solution, I would not create a cmd and pass powershell to it but leverage the System.Management.Automation namespace and create a PowerShell console object server-side without the middle man of cmd. You can pass commands or .ps1 files to the AddScript() function - both with arguments - to it for execution. Much cleaner than a separate shell that will have to then call the powershell.exe.

Ensure appropriate identity of the application pool and that principal has the appropriate level of rights required to perform the PowerShell commands and/or scripts. Also, make sure you have the execution policy configured via Set-ExecutionPolicy to the appropriate level (unrestricted/ or remote signed, unless you're signing), in the event you're still going to go the way of executing a .ps1 file server side.

Here's some starter code that is executing commands submitted by a TextBox web form as if it were aa PowerShell console using these objects - should illustrate the approach:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Management.Automation;
using System.Text;

namespace PowerShellExecution
{
    public partial class Default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {

        }

        protected void ExecuteCode_Click(object sender, EventArgs e)
        {
            // Clean the Result TextBox
            ResultBox.Text = string.Empty;

            // Initialize PowerShell engine
            var shell = PowerShell.Create();

            // Add the script to the PowerShell object
            shell.Commands.AddScript(Input.Text);

            // Execute the script
            var results = shell.Invoke();

            // display results, with BaseObject converted to string
            // Note : use |out-string for console-like output
            if (results.Count > 0)
            {
                // We use a string builder ton create our result text
                var builder = new StringBuilder();

                foreach (var psObject in results)
                {
                    // Convert the Base Object to a string and append it to the string builder.
                    // Add \r\n for line breaks
                    builder.Append(psObject.BaseObject.ToString() + "\r\n");
                }

                // Encode the string in HTML (prevent security issue with 'dangerous' caracters like < >
                ResultBox.Text = Server.HtmlEncode(builder.ToString());
            }
        }
    }
}

Here's is a write up for you that covers how to create a page from start to finish with Visual Studio and get this done, http://grokgarble.com/blog/?p=142 .

I would think you can not run powershell script from aspx page directly like this, since it may related with security reason. in order to run and capture the output:

  1. create a remote runspace: http://social.msdn.microsoft.com/Forums/hu/sharepointgeneralprevious/thread/88b11fe3-c218-49a3-ac4b-d1a04939980c http://msdn.microsoft.com/en-us/library/windows/desktop/ee706560%28v=vs.85%29.aspx

  2. PSHost: Capturing Powershell output in C# after Pipeline.Invoke throws

1 works very well for me.

BTW, the label is not updated because the event is not finished. you may need use ajax to show the label while waiting for powershell.

When I tried this I found the standard input needs to be flushed or closed before SR.ReadToEnd() can complete. Try this:

    lblResults.Text = "Please wait...";
    try
    {
        string tempGETCMD = null;
        Process CMDprocess = new Process();
        System.Diagnostics.ProcessStartInfo StartInfo = new System.Diagnostics.ProcessStartInfo();
        StartInfo.FileName = "cmd"; //starts cmd window
        StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
        StartInfo.CreateNoWindow = true;
        StartInfo.RedirectStandardInput = true;
        StartInfo.RedirectStandardOutput = true;
        StartInfo.UseShellExecute = false; //required to redirect
        CMDprocess.StartInfo = StartInfo;
        CMDprocess.Start();
        lblResults.Text = "Starting....";
        using (System.IO.StreamReader SR = CMDprocess.StandardOutput)
        {
            using (System.IO.StreamWriter SW = CMDprocess.StandardInput)
            {
                SW.WriteLine("@echo on");
                SW.WriteLine("cd C:\\Tools\\PowerShell\\");
                SW.WriteLine("powershell .\\poweron.ps1 **parameter**");
                SW.WriteLine("exit"); //exits command prompt window
            }
            tempGETCMD = SR.ReadToEnd(); //returns results of the command window
        }
        lblResults.Text = tempGETCMD;
    }
    catch (Exception ex)
    {
        lblErrorMessage.Text = ex.ToString();
        showError();
    }
}

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