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?
Related
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?
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 :-)
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.
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());
}
I'm trying to run powershell commands on a remote sharepoint server from a c# console app. This is the code I have so far. It runs without errors but does nothing. What am I doing wrong?
Thanks
server name, username password, and url were taken out
public static string RunScript()
{
Runspace remoteRunspace = null;
openRunspace("http://server/wsman",
"http://schemas.microsoft.com/powershell/Microsoft.PowerShell",
#"domain\user",
"password",
ref remoteRunspace);
try
{
StringBuilder stringBuilder = new StringBuilder();
using (PowerShell powershell = PowerShell.Create())
{
powershell.Runspace = remoteRunspace;
powershell.AddScript("Add-PsSnapin Microsoft.SharePoint.PowerShell");
powershell.AddScript("enable-SPFeature -identity \"2dfc204b-e9da-4c6c-8b4f-c2f7c593ad4e\" -url sharepointsite -Confirm:$False");
powershell.Invoke();
Collection<PSObject> results = powershell.Invoke();
remoteRunspace.Close();
foreach (PSObject obj in results)
{
stringBuilder.AppendLine(obj.ToString());
}
}
return stringBuilder.ToString();
}
catch (Exception e)
{
return "";
}
}
public static void openRunspace(string uri, string schema, string username, string livePass, ref Runspace remoteRunspace)
{
System.Security.SecureString password = new System.Security.SecureString();
foreach (char c in livePass.ToCharArray())
{
password.AppendChar(c);
}
PSCredential psc = new PSCredential(username, password);
WSManConnectionInfo rri = new WSManConnectionInfo(new Uri(uri), schema, psc);
rri.AuthenticationMechanism = AuthenticationMechanism.Kerberos;
rri.ProxyAuthentication = AuthenticationMechanism.Negotiate;
remoteRunspace = RunspaceFactory.CreateRunspace(rri);
remoteRunspace.Open();
}
You can try to check if you have access to the SharePoint databases, to add snap-in correctly you need ShellAccess permission on Configuration database as I remember and farm admin rights. Possibly your script can't add snap-in, so cant do anything with SharePoint object model.