I have the next piece of code that works calling a remote powershell script ( the script is into the remote system ) but I would like to send parameters to script:
c# method:
public void RemoteConnection()
{
connectionInfo = new WSManConnectionInfo(false, remoteMachineName, 5985, "/wsman", shellUri, credentials);
runspace = RunspaceFactory.CreateRunspace(connectionInfo);
runspace.Open();
Pipeline pipeline = runspace.CreatePipeline(path);
var results = pipeline.Invoke();
foreach (PSObject obj in results)
Console.WriteLine(obj.ToString());
}
I tried to send parameters with CommandParameter but I obtained an error message:
Pipeline pipeline = runspace.CreatePipeline();
Command myCommand = new Command(path);
CommandParameter testParam0 = new CommandParameter("suma");
myCommand.Parameters.Add(testParam0);
CommandParameter testParam = new CommandParameter("x", "89");
myCommand.Parameters.Add(testParam);
CommandParameter testParam2 = new CommandParameter("y", "11");
myCommand.Parameters.Add(testParam2);
pipeline.Commands.Add(myCommand);
Error Message:
{"Cannot perform operation because operation \"NewNotImplementedException at offset 76 in file:line:column <filename unknown>:0:0\r\n\" is not implemented."}
I can call my powershell script(which is into my remote system ) in this way:
PS C:\grace\powershell> .\script1.ps1 -suma -x 9 -y 19
28
PS C:\grace\powershell> .\script1.ps1 -suma "9" "19"
28
How can I send through c# program parameters for my powershell script?
How it worked for me:
public void RemoteConnection()
{
connectionInfo = new WSManConnectionInfo(false, remoteMachineName, 5985, "/wsman", shellUri, credentials);
runspace = RunspaceFactory.CreateRunspace(connectionInfo);
runspace.Open();
Pipeline pipeline = runspace.CreatePipeline(path);
Command myCommand = new Command(path);
CommandParameter testParam0 = new CommandParameter("-suma");
myCommand.Parameters.Add(testParam0);
CommandParameter testParam = new CommandParameter("x", "34");
myCommand.Parameters.Add(testParam);
CommandParameter testParam2 = new CommandParameter("y", "11");
myCommand.Parameters.Add(testParam2);
pipeline.Commands.Add(myCommand);
var results = pipeline.Invoke();
foreach (PSObject obj in results)
Console.WriteLine(obj.ToString());
}
Note I'm sending the path to CreatePipeline and also to create a new Command (Maybe is necessary a further review)
Maybe this could help you:
http://com2kid.wordpress.com/2011/09/22/remotely-executing-commands-in-powershell-using-c/
Setting all the command together.
Related
I want to execute a PowerShell script through C#. My script will create a .csv file at a location specified. The below code creates a file at the location specified, but I want the code to return an object which has all the content/data the file has. Is that possible?
RunspaceConfiguration runspaceConfiguration = RunspaceConfiguration.Create();
using (Runspace runspace = RunspaceFactory.CreateRunspace(runspaceConfiguration))
{
runspace.Open();
RunspaceInvoke scriptInvoker = new RunspaceInvoke(runspace);
Pipeline pipeline = runspace.CreatePipeline();
Command scriptCommand = new Command(#"C:\powershell.ps1");
Collection<CommandParameter> commandParameters = new Collection<CommandParameter>();
pipeline.Commands.Add(scriptCommand);
Collection<PSObject> psObjects;
psObjects = pipeline.Invoke();
}
Can you rather make use of Powershell APIs?
For example:
PowerShell psinstance = PowerShell.Create();
psinstance.AddScript(scriptPath);
var results = psinstance.Invoke();
More details can be found here:
https://blogs.msdn.microsoft.com/kebab/2014/04/28/executing-powershell-scripts-from-c/
You can return file content from powershell with this command and then write powershell output to the PSDataCollection.
private async Task<IEnumerable<string>> Process(string command)
{
var output = new List<string>();
using (var powerShell = System.Management.Automation.PowerShell.Create())
{
powerShell.AddScript(command);
var outputCollection = new PSDataCollection<PSObject>();
await Task.Factory.FromAsync(
powerShell.BeginInvoke<PSObject, PSObject>(null, outputCollection),
result =>
{
OnDeployEnd?.Invoke(this, EventArgs.Empty);
foreach (var data in outputCollection)
{
output.Add(data.ToString());
}
}
);
if (powerShell.HadErrors)
{
var errorsReport = powerShell.Streams.Error.GetErrorsReport();
throw new Exception(errorsReport);
}
}
return output;
}
I'm adapting this solution to a Windows Forms solution. So far I've been able to execute the Get-WUList command with no problems. But it doesn't seem to go well with the Hide-WUUpdate. This is what I've tried so far:
public class PowerShellController : IPowerShell
{
//Created at a global scope so anyone can fetch it.
InitialSessionState initial;
RunspaceInvoke scriptInvoker;
Runspace runspace;
PowerShell ps;
//The View to Control
IView view;
//The Helper GridViewProcessor class
IGridViewProcessor gp;
//Initializing the Controller - Loads the Module.
public PowerShellController()
{
initial = InitialSessionState.CreateDefault();
initial.ImportPSModule(new string[] { #"C:\Users\Jose\Documents\WindowsPowerShell\Modules\PSWindowsUpdate\PSWindowsUpdate.psd1" });
scriptInvoker = new RunspaceInvoke();
scriptInvoker.Invoke("Set-ExecutionPolicy Unrestricted -Scope Process");
runspace = RunspaceFactory.CreateRunspace(initial);
runspace.Open();
using (ps = PowerShell.Create())
{
ps.Runspace = runspace;
}
//Console.WriteLine("Please Wait. This will take a while to load.");
}
public void SetView(IView view, IGridViewProcessor gp)
{
this.view = view;
this.gp = gp;
}
public void GetAvailableUpdates()
{
MessageBox.Show("Ok. The program will kind of hang. This is normal." +
"This Means that it will start looking for updates "
);
IEnumerable<PSObject> WUList; //Placeholder for the PS Executed Command
using (ps = PowerShell.Create())
{
//Adds the PowerShell Command
ps.Commands.AddCommand("Get-WUList");
//Executes the PowerShell command
WUList = ps.Invoke();
}
//Loads the Model - Can be later on rewritten for Ninject Support.
List<WindowsUpdate> model = new List<WindowsUpdate>();
int id = 1;
foreach (PSObject result in WUList)
{
WindowsUpdate item = new WindowsUpdate
{
Id = id,
Name = result.Members["Title"].Value.ToString(),
Size = result.Members["Size"].Value.ToString(),
Type = UpdateType.Undefined,
};
model.Add(item);
id++; //Icnrease ID count
//Console.WriteLine("Update Name {0} --- Size: {1}", result.Members["Title"].Value.ToString(), result.Members["Size"].Value.ToString());
}
//Adds it to the view:
view.AddUpdateToGrid(model);
}
public void HideSelectedUpdates(DataGridView grid)
{
//Gets SelectedUpdates to the WindowsUpdate model
var SelectedUpdates = gp.GetSelectedUpdates(grid);
using (ps = PowerShell.Create())
{
foreach (var update in SelectedUpdates)
{
ps.Commands.Clear();
ps.Commands.AddCommand("Hide-WUUpdate").AddParameter("Title",update.Name).AddParameter("Confirm", false);
//ps.Commands.AddCommand("Hide-WUUpdate -Title \""+update.Name+"\"");
var result = ps.Invoke();
}
}
MessageBox.Show("Updates Have been hidden");
}
}
The method I can't seem to work is the HideSelectedUpdates(DataGridView grid).
Script gets executed and no exceptions are thrown, but it doesn't seem to reflect any changes at all.
Any suggestions?
I'm trying to get smallest Exchange database in my Exchange 2010 server using remote session.
I successfully connect to my exchange server and get database with properties. Some of them with value, but Properties DatabaseSize with Null value.
Did some body be able to get database size value?
Part of my code below:
static void Main(string[] args)
{
string exchangePowershellRPSURI = "http://my.domain/powershell?serializationLevel=Full";
PSCredential credentials = (PSCredential)null;
//Provides the connection information that is needed to connect to a remote runspace
// Prepare the connection
WSManConnectionInfo connInfo = new WSManConnectionInfo((new Uri(exchangePowershellRPSURI)),
"http://schemas.microsoft.com/powershell/Microsoft.Exchange", credentials);
connInfo.AuthenticationMechanism = AuthenticationMechanism.Kerberos;
connInfo.SkipCACheck = true;
connInfo.SkipCNCheck = true;
connInfo.SkipRevocationCheck = true;
// Create the runspace where the command will be executed
Runspace runspace = RunspaceFactory.CreateRunspace(connInfo);
// Add the command to the runspace's pipeline
runspace.Open();
//Represents the base functionality of a pipeline that can be used to invoke commands
Pipeline pipeline = runspace.CreatePipeline();
Command getMDB = new Command("Get-MailboxDatabase");
getMDB.Parameters.Add("Identity", "*");
getMDB.Parameters.Add("Status", null);
pipeline.Commands.Add(getMDB);
Collection<PSObject> select = pipeline.Invoke();
if (select.Count > 0)
{
foreach(PSObject obj in select)
{
var db = obj.Properties["DatabaseSize"].Value;
string name = obj.Properties["Name"].Value.ToString();
Console.WriteLine("Database Name: {0} Size: {1}", name, db);
}
}
else
{
Console.WriteLine("Failed to create email account");
}
runspace.Dispose();
Console.ReadLine();
}
I have found an solution
In the getMDB.Parameters.Add need for Status parameter to change value from "null" to "true"
getMDB.Parameters.Add("Status", null);
I'm using WSManAutomation to remotely manage servers.
I need to install and uninstall applications on remote servers that have WinRM over HTTPS enabled. The connection is not a problem
So far the code below executes msiexec.exe in the remote host as I can see it in the list of processes but it does not execute the uninstall command.
public void UninstallProduct(string path, string target, string username = null, string password = null)
{
IWSMan wsman = new WSManClass();
IWSManConnectionOptions options = (IWSManConnectionOptions)wsman.CreateConnectionOptions();
if (options != null)
{
try
{
options.UserName = username;
options.Password = password;
int iFlags = (int)_WSManSessionFlags.WSManFlagCredUsernamePassword;
IWSManSession session = (IWSManSession)wsman.CreateSession(string.Format("https://{0}:5986/wsman", target), iFlags, options);
// IWSManSession session = (IWSManSession)wsman.CreateSession(string.Format("http://{0}/wsman", target), 0, options);
if (session != null)
{
try
{
string strResource = "http://schemas.microsoft.com/wbem/wsman/1/wmi/root/cimv2/Win32_Process";
string strInputParameters =string.Format("<p:Create_INPUT xmlns:p=\"{0}\"><p:CommandLine>\"{1}\"</p:CommandLine></p:Create_INPUT>", "http://schemas.microsoft.com/wbem/wsman/1/wmi/root/cimv2/Win32_Process",path);
var reply = session.Invoke("Create", strResource, strInputParameters);
Console.WriteLine(reply);
Console.WriteLine();
}
finally
{
Marshal.ReleaseComObject(session);
}
}
}
finally
{
Marshal.ReleaseComObject(options);
}
}
}
The call to the method above would be:
obj.UninstallProduct(#"C:\Windows\System32\msiexec.exe /x {E499AB77-9B27-416CB9B6F-4A171D02BB31} /passive", "hostname", #"hostname\Administrator", "password");
Do you know why the command does not get executed?
Should I use another way to uninstall a product?
Thanks in advance.
Finally I came across a way to do this using remote PowerShell
string command = string.Format("(Get-WmiObject -Class Win32_Product | Where-Object {$_.Name -match {0}}).Uninstall()", productName);
PSCredential credential = new PSCredential(username, securePassword);
string shellUri = "http://schemas.microsoft.com/powershell/Microsoft.PowerShell";
WSManConnectionInfo connectionInfo = new WSManConnectionInfo(true, target, 5986, "/wsman", shellUri, credential);
using (Runspace runspace = RunspaceFactory.CreateRunspace(connectionInfo))
{
runspace.Open();
Pipeline pipeline = runspace.CreatePipeline(command);
try
{
Collection<PSObject> results = pipeline.Invoke("Set-ExecutionPolicy Unrestricted -Scope Process");
}
finally
{
runspace.Close();
}
}
I am using the following C# code to connect to a Linux box and execute a script that is placed there
public static void linux_connect()
{
KeyboardInteractiveAuthenticationMethod kauth = new KeyboardInteractiveAuthenticationMethod(<username>);
PasswordAuthenticationMethod pauth = new PasswordAuthenticationMethod(<username>,<password>);
ConnectionInfo connectionInfo = new ConnectionInfo(<host ip>, 22, <username>, kauth, pauth);
using (var ssh = new SshClient(connectionInfo))
{
ssh.Connect();
string command = "tmp/Ftp.sh";
var cmd = ssh.CreateCommand(command);
Console.WriteLine(cmd.Result);
var asynch = cmd.BeginExecute(delegate(IAsyncResult ar)
{
}, null);
var reader = new StreamReader(cmd.OutputStream);
while (!asynch.IsCompleted)
{
var result = reader.ReadToEnd();
if (string.IsNullOrEmpty(result))
continue;
Console.Write(result);
}
cmd.EndExecute(asynch);
}
}
My Ftp.sh script is a s follows:
#!/bin/bash
cd /apps/sample_folder
sudo -u (authorized_username) ftp (some_server)
The cd command executes successfully but when control reaches the sudo command, I should be prompted for a password on my console but unfortunately I am not. Could someone please tell me how to make this interactive so that I am prompted for a password on my application console and I am able to enter it and then copy file from to the desired location