Command.parameters.add - Running powershell in .Net - c#

I'm trying to find a way to run a powershell script / commands within a web page. After a short search over the internet I found System.management.Automation.I'm trying to run Powershell commands in C#. I wrote the following code and it works fine except I couldn't find how do I add the -recurse parameter of the copy-item command.
protected void ExecuteCode_Click(object sender, EventArgs e)
{
//Clean the result textbox
ResultBox.Text = string.Empty;
//Create the runspace
Runspace runSpace = RunspaceFactory.CreateRunspace();
runSpace.Open();
//Create the pipeline
Pipeline pipeline = runSpace.CreatePipeline();
//Create the commands
Command copyItem = new Command("copy-item");
copyItem.Parameters.Add("Path", "c:\\temp\\");
copyItem.Parameters.Add("Destination", "c:\\temp1\\");
//robocopy.Parameters.Add("Dest", "c:\\temp1");
pipeline.Commands.Add(copyItem);
//Execute the script
var results = pipeline.Invoke();
//display results, with BaseObject converted to string
if (results.Count > 0)
{
//We use a string builder on 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.
builder.Append(psobject.BaseObject.ToString() + "\r\n");
}
//Encode the string in HTML (Prevent security issue with 'dangerous' characters like <>)
ResultBox.Text = Server.HtmlEncode(builder.ToString());
}
/*
//Clean the result textbox
ResultBox.Text = string.Empty;
//Initialize Powershell Engine
var powershellConsole = PowerShell.Create();
//Add the script to the Powershell object
powershellConsole.Commands.AddScript(Input.Text);
//Execute the script
var results = powershellConsole.Invoke();
//display results, with BaseObject converted to string
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.
builder.Append(psobject.BaseObject.ToString() + "\r\n");
}
//Encode the string in HTML (Prevent security issue with 'dangerous' characters like <>)
ResultBox.Text = Server.HtmlEncode(builder.ToString());
}
*/
}

Switch parameters (like -Recurse) are super easy to add - simply specify the parameter name and nothing else:
copyItem.Parameters.Add("Recurse");
That's it, nothing more to it :-)

Related

Capture the console logs of powershell script using c#

I am trying to execute powershell script and capture the formatted output from powershell into C# console window but always return null.
C# Code:
public List<SplunkEvent> events { get; set; } = new List<SplunkEvent>();
public void InvokeCrawl()
{
try
{
List<UrlTracker> urls = new List<UrlTracker>();
urls.Add(new UrlTracker() { AirId = "4812", SiteId = "6976843556", Url = "https://test.com/homepage", RequestorEnterpriseId = "asif.iqbal.khan" });
RunScript("4812", "asif", "iqbal", "pinku", "", urls);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
private void RunScript(string airID, string requestorEnterpriseId, string areaLeadEnterpriseId, string mDEnterpriseId, string serviceLeadEnterpriseId, List<UrlTracker> urls)
{
string _path = AppDomain.CurrentDomain.BaseDirectory + "Script\\Test.ps1";
System.IO.StreamReader sr = new System.IO.StreamReader(_path);
Runspace runspace = RunspaceFactory.CreateRunspace();
runspace.Open();
Pipeline pipeline = runspace.CreatePipeline();
Command myCommand = new Command(_path);
CommandParameter _airId = new CommandParameter("AirId", airID);
myCommand.Parameters.Add(_airId);
CommandParameter _url = new CommandParameter("SiteUrl", urls[0].Url);
myCommand.Parameters.Add(_url);
pipeline.Commands.Add(myCommand);
//pipeline.Commands.AddScript(sr.ReadToEnd());
pipeline.Commands.Add("Out-String");
var results = pipeline.Invoke();
runspace.Close();
StringBuilder stringBuilder = new StringBuilder();
foreach (PSObject obj in results)
{
stringBuilder.AppendLine(obj.ToString());
}
Console.WriteLine(stringBuilder.ToString());
}
Test.ps1 Code:
Output from C#:
Executing the script directly inside windows powershell i could see the result getting printed.
In your Powershell script, use Write-Output instead of Write-Host
You can also remove this line from the C# code.
pipeline.Commands.Add("Out-String");
More info on the difference between the two here: PowerShell difference between Write-Host and Write-Output?

Calling powershell script and capturing output into ASP via C#

I am calling a PowerShell script from c# within an ASP page. The script executes just fine but the output (write-host) of my PowerShell does not get captured. I would like to be able to capture any output back into the ASP page.
The following is is my current code.
protected void ExecuteInputClick(object sender, EventArgs e)
{
Result.Text = string.Empty;
RunspaceConfiguration runspaceConfiguration = RunspaceConfiguration.Create();
Runspace runspace = RunspaceFactory.CreateRunspace(runspaceConfiguration);
runspace.Open();
RunspaceInvoke scriptInvoker = new RunspaceInvoke(runspace);
Pipeline pipeline = runspace.CreatePipeline();
string scriptfile = "C:\\PRJ_Templates\\CreateProject.ps1";
Command myCommand = new Command(scriptfile);
CommandParameter DestDirParam = new CommandParameter("DestinationDirectory", DropDownList1.SelectedValue);
CommandParameter ProjNamParam = new CommandParameter("ProjectName", Input.Text);
myCommand.Parameters.Add(DestDirParam);
myCommand.Parameters.Add(ProjNamParam);
pipeline.Commands.Add(myCommand);
try
{
System.Collections.ObjectModel.Collection<PSObject> results = pipeline.Invoke();
runspace.Close();
StringBuilder stringBuilder = new StringBuilder();
foreach (PSObject obj in results)
{
stringBuilder.AppendLine(obj.ToString());
}
Result.Text = Server.HtmlEncode(stringBuilder.ToString());
}
catch (ActionPreferenceStopException Error) { Result.Text = Error.Message; }
catch (RuntimeException Error) { Result.Text = Error.Message; }
}
Any thought why the write-host is not getting put into Results?

Using C# To Return Data From PowerShell

I am trying to return a PrimarySMTPAddress to a variable, in Powershell the code I run is this:
Get-Mailbox -identity UserName | select PrimarySMTPAddress
And it returns the correct value, I want to get this in my C# Code, I have done the following:
string getPrimarySMTP = "Get-Mailbox -identity " + username + "| select PrimarySMTPAddress";
var runSpace = RunspaceFactory.CreateRunspace(Utility.CreateConnectionInfo());
runSpace.Open();
var pipeline = runSpace.CreatePipeline();
pipeline.Commands.AddScript(getPrimarySMTP);
var primarySmtp = pipeline.Invoke();
runSpace.Dispose();
I would Expect this to return the same data, but it doesn't. I just get an exception:
The term 'select' is not recognized as the name of a cmdlet, function,
script file, or operable program. Check the spelling of the name, or
if a path was included, verify that the path is correct and try again.
Is this the way to return values from a powershell command?
For what version of Exchange ? for 2010 up you need to use Remote Powershell see https://msdn.microsoft.com/en-us/library/office/ff326159%28v=exchg.150%29.aspx . (even in 2007 your code would work because you haven't loaded the snapin).
Cheers
Glen
You may need to add an additional space character before the pipe. It' being concatenated to the username, with the resulting string becoming ... -identity UserName| select ..."
Here's the corrected statement:
string getPrimarySMTP = "Get-Mailbox -identity " + username + " | select PrimarySMTPAddress";
Thanks for asking this question, it helped me to lead to the answer I needed. My code resulted in the following using RemoteRunspace to an Exchange 2013 environment:
try
{
var target = new Uri(Uri);
SecureString PSPassword = new SecureString();
foreach (char c in ConfigurationManager.AppSettings["Password"])
{
PSPassword.AppendChar(c);
}
//var cred = (PSCredential)null;
PSCredential cred = new PSCredential(ConfigurationManager.AppSettings["Username"], PSPassword);
WSManConnectionInfo connectionInfo = new WSManConnectionInfo(target, shell, cred);
connectionInfo.AuthenticationMechanism = AuthenticationMechanism.Default;
connectionInfo.OperationTimeout = 1 * 60 * 1000; // 4 minutes.
connectionInfo.OpenTimeout = 1 * 30 * 1000; // 1 minute.
using (Runspace remoteRunspace = RunspaceFactory.CreateRunspace(connectionInfo))
{
remoteRunspace.Open();
using (PowerShell powershell = PowerShell.Create())
{
powershell.Runspace = remoteRunspace;
powershell.AddScript(PSSnapin);
powershell.Invoke();
powershell.Streams.ClearStreams();
powershell.Commands.Clear();
Pipeline pipeline = remoteRunspace.CreatePipeline();
Command getMailBox = new Command("Get-Mailbox");
getMailBox.Parameters.Add("Identity", Username);
Command cmd = new Command("Select-Object");
string[] Parameter = new string[] { "PrimarySMTPAddress" };
cmd.Parameters.Add("Property", Parameter);
pipeline.Commands.Add(getMailBox);
pipeline.Commands.Add(cmd);
Collection<PSObject> results = pipeline.Invoke();
primarySMTPAddress = results[0].ToString();
primarySMTPAddress = primarySMTPAddress.ToUpper().Replace("#{PRIMARYSMTPADDRESS=", "");
primarySMTPAddress = primarySMTPAddress.ToUpper().Replace("}", "");
}
remoteRunspace.Close();
}
return primarySMTPAddress;
}
catch
{
return "Error";
}
Hope this helps anyone in future.

C#, How to get powershell script file and pass some variable to script?

I am new to using powershell in C# environment. I already created a multiline textbox to type powershell script to execute it and it worked fine. Now I want to get rid of typing in textbox and have 3 selected variables (Container, and NumIP) instead to pass to powerscript script file then execute it. How can I get these file and pass these variables to powershell script file in C#? Or do I have to create a script string in C#?
Here a working powershell script file, since it long codes, I am gonna put 1 line code where I want to pass these 2 variables to these 2 arguments.
[string]$ContainerIn=$args[0]
[int]$ips2get=$args[1]
Here a C# codes,
protected void ExecuteCode_Click(object sender, EventArgs e)
{
// Clean the Result TextBox
ResultBox.Text = string.Empty;
ResultBox.ForeColor = System.Drawing.ColorTranslator.FromHtml("#FFFFFF");
string str = "";
//These 3 input varaibles will pass to powershell script to get specific results
string env = "";
string container = "";
string numIPs = "";
//assign dropdown selected value to variable to pass to script
container = DropDownListContainer.SelectedValue;
numIPs = DropDownListIP.SelectedValue;
if (container == "H02" || container == "H07" || container == "H08")
{
env = "Prod";
}
else
{
env = "NonProd";
}
// Create a Powershell
Runspace runSpace = RunspaceFactory.CreateRunspace();
runSpace.Open();
Pipeline pipeline = runSpace.CreatePipeline();
Command invokeScript = new Command("Invoke-Command");
RunspaceInvoke invoke = new RunspaceInvoke();
//Add powershell command/script functions into scriptblock
ScriptBlock sb = invoke.Invoke(#"{D:\Scripts\Get-FreeAddress.ps1}")[0].BaseObject as ScriptBlock;
invokeScript.Parameters.Add("scriptBlock", sb);
invokeScript.Parameters.Add("computername", TextBoxServer.Text);
pipeline.Commands.Add(invokeScript);
Collection<PSObject> output = pipeline.Invoke();
//splitting results in new lines
foreach (PSObject psObject in output)
{
str = str + psObject + "\r\n";
//str = psObject + "\r\n";
//str += "\n" + psObject;
//str = str + Environment.NewLine + psObject;
}
if (str == "")
{
str = "Error";
ResultBox.ForeColor = System.Drawing.ColorTranslator.FromHtml("#FF0000");
}
//print out powershell output result
ResultBox.Text = str;
}
I know I would probably have to change this code, ScriptBlock sb = invoke.Invoke("{" + PowerShellCodeBox.Text + "}")[0].BaseObject as ScriptBlock;
One way would be to modify your scriptblock creation like so:
string sbstr = String.Format("{D:\Scripts\Get-FreeAddress.ps1 -Env:"{0}" -Container:"{1}" -NumIPs:{2} -GiveInfo:$false}", envTB.Text, contTB.Text, numipTB.Text);
ScriptBlock sb = invoke.Invoke(sbstr)[0].BaseObject as ScriptBlock;
In order to get the local script file propagated to the remote computer to run, you will need to do this instead:
Command invokeScript = new Command("Invoke-Command");
invokeScript.Parameters.Add("computername", TextBoxServer.Text);
invokeScript.Parameters.Add("filepath", "D:\Scripts\Get-FreeAddress.ps1");
invokeScript.Parameters.Add("argumentlist", new[]{envTB.Text, contTB.Text, numipTB.Text, False});
I finally made this work,
I just need to modify to ScriptBlock sb = invoke.Invoke(#"{D:\Scripts\Get-FreeAddress.ps1 '"+container+"' "+numIPs+"}")[0].BaseObject as ScriptBlock;
The powershell script argument will get container and numIPs variables.

C#, How to split strings to new line during foreach loop?

Using Powershell Object and running foreach loop to get the results,
I got 2 correct IP Address results 144.68.205.19 and 144.68.205.22 but it printed in 1 line,
144.68.205.19144.68.205.22
Which it was suppose to be split new line like this,
144.68.205.19
144.68.205.22
Please advise, here a C# codes,
// Powershell
Runspace runSpace = RunspaceFactory.CreateRunspace();
runSpace.Open();
Pipeline pipeline = runSpace.CreatePipeline();
Command invokeScript = new Command("Invoke-Command");
RunspaceInvoke invoke = new RunspaceInvoke();
// invoke-command -computername compName -scriptblock { get-process }
ScriptBlock sb = invoke.Invoke("{"+ PowerShellCodeBox.Text +"}")[0].BaseObject as ScriptBlock;
invokeScript.Parameters.Add("scriptBlock", sb);
invokeScript.Parameters.Add("computername", TextBoxServer.Text);
string str = "";
pipeline.Commands.Add(invokeScript);
Collection<PSObject> output = pipeline.Invoke();
foreach (PSObject psObject in output)
{
str = str + psObject;
}
if (str == ""){
str = "Error";
ResultBox.ForeColor = System.Drawing.ColorTranslator.FromHtml("#FF0000");
}
ResultBox.Text = str;
You could just insert a new line as you're building up str:
foreach (PSObject psObject in output)
{
str += "\n" + psObject;
}
Or use string.Join
string str = String.Join("\n", output);
For starters, if you're planning on building a string in a loop, look at using StringBuilder. Secondly, you're never appending a new line in there, but that's easily solved (using a native method of stringbuilder, too!)
pipeline.Commands.Add(invokeScript);
Collection<PSObject> output = pipeline.Invoke();
StringBuilder sb = new StringBuilder();
foreach (PSObject psObject in output)
{
sb.AppendLine(psObject.ToString());
}

Categories

Resources