Making a powershell script run from aspx – it worked in 1/2 hour!

So, there is this process, that if the user could click a button themselves would save a lot of stress on everyone – the person who has to run the powershell script AND the people who have to ask (who wants to pester someone all the time?)

So in prep – I did a test – I didn’t know anything about powershell scripting so I hit google. I found a simple copy/paste of a file script and modified it to copy a file from one directory to another (and it echos something to the command line). Since it is the www – I made a share location so that it could be run from the network instead of my “C:\temp” directory because C: means MY c:\ and MY will change depending on who hits the button.

Next, I went and copied and pasted an example from someone else, found out which “using” statements are required, hooked up a following DLL manually required to get this working and presto – it worked in about 1/2 hour. Here are the steps:

Steps

  • make a share and a destination directory (might need a share for that too).
  • Make a new web project or aspx page
  • Manually connect the following powershell DLL into the project C:\Windows\assembly\GAC_MSIL\System.Management.Automation\1.0.0.0__31bf3856ad364e35\System.Management.Automation.dll
  • make your powershell script and test it (it is included in the code below – kinda – in the variable: “st”)
  • fudge your script into the code below – I already did and in the future, if this goes through I would read it from a text file not encode it like I did – this was just a test
  • compile, test it and publish it (ok – I can write that easier than I did it but … it works 🙂 )

[csharp]

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

namespace RunPowerShellToCopyDb
{
public partial class _Default : Page
{
protected void Page_Load(object sender, EventArgs e)
{

}

protected void ButtonDoIt_Click(object sender, EventArgs e)
{
string st = "";

//ideally we want to read this from a file in the App_Data directory or something but this is good test.
st += "$targetdirectory = \"\\\\cdc-ebley2-7\\temp\\dest\"\n";

st += "$sourcedirectory = \"\\\\cdc-ebley2-7\\temp\"\n";

st += "if (!(Test-Path -path $targetdirectory)) {New-Item $targetdirectory -Type Directory}\n";
st += "Copy-Item -Path $sourcedirectory\\a.csv -Destination $targetdirectory\n";
st += "echo this_is_an_echo_statement_after_the_copy_is_done Look at \\\\cdc-ebley2-7\\temp\\dest for a.csv";
outputItem.InnerHtml = "output: "+RunScript(st);
}

private string RunScript(string scriptText)
{
// create Powershell runspace

Runspace runspace = RunspaceFactory.CreateRunspace();

// open it
runspace.Open();
//runspace.SessionStateProxy.SetVariable("DemoForm", this);
// create a pipeline and feed it the script text

Pipeline pipeline = runspace.CreatePipeline();
pipeline.Commands.AddScript(scriptText);

// add an extra command to transform the script
// output objects into nicely formatted strings

// remove this line to get the actual objects
// that the script returns. For example, the script

// "Get-Process" returns a collection
// of System.Diagnostics.Process instances.

pipeline.Commands.Add("Out-String");

// execute the script
PSObject bob;
Collection<PSObject> results = pipeline.Invoke();

// close the runspace

runspace.Close();

// convert the script result into a single string

StringBuilder stringBuilder = new StringBuilder();
foreach (PSObject obj in results)
{
stringBuilder.AppendLine(obj.ToString());
}

return stringBuilder.ToString();
}
}
}

[/csharp]
[csharp]

<%@ Page Title="Home Page" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="RunPowerShellToCopyDb._Default" %>

<asp:Content runat="server" ID="FeaturedContent" ContentPlaceHolderID="FeaturedContent">
<section class="featured">
<div class="content-wrapper">
<hgroup class="title">
<h1><%: Title %>.</h1>
<h2>Modify this template to jump-start your ASP.NET application.</h2>
</hgroup>
<p>
<asp:Button ID="ButtonDoIt" runat="server" Text="Jamie … Press this button" OnClick="ButtonDoIt_Click" />

</p>
</div>
</section>
</asp:Content>
<asp:Content runat="server" ID="BodyContent" ContentPlaceHolderID="MainContent">
<h3>Output:</h3>
<ol class="round">
<li id="outputItem" runat="server">

</li>

</ol>
</asp:Content>

[/csharp]