I have .ps1 script which should return me SID of current user (or administrator). But i have no idea how can i get this value from that script into my C# code. Can somebody help me, please?
Currently i am calling one script in this way:
ProcessStartInfo newProcessInfo = new ProcessStartInfo();
newProcessInfo.FileName = #"C:\Windows\SysWOW64\WindowsPowerShell\v1.0\powershell.exe";
newProcessInfo.Verb = "runas";
newProcessInfo.Arguments = #"sfc /scannow";
Process.Start(newProcessInfo);
newProcessInfo.Arguments = #"-Command ""sfc /scannow""";
newProcessInfo.Arguments = #"–ExecutionPolicy Bypass -File ""c:\\Users\\HP\\Desktop\\HotelMode-PB\\HotelMode.ps1""";
And i need to get SID of user from another .ps1 script and then use it in this cmd command:
HotelMode.ps1 -UserSid "" [-debug]
Use the System.Management.Automation API directly instead of launching powershell.exe:
using System;
using System.Collections.ObjectModel;
using System.Management.Automation;
// ...
using(PowerShell ps = PowerShell.Create())
{
ps.AddCommand("Set-ExecutionPolicy")
.AddParameter("ExecutionPolicy","Bypass")
.AddParameter("Scope","Process")
.AddParameter("Force");
ps.AddScript(#"C:\Users\HP\Desktop\HotelMode-PB\HotelMode.ps1");
Collection<PSObject> result = ps.Invoke();
foreach(var outputObject in result)
{
// outputObject contains the result of the powershell script
}
}
Related
I have been looking around here but unable to get specifics on implementing this PowerShell cmdlet in C#. I attempted the following but failed to get it to compile and run.
The cmdlet I would like to run in PowerShell from C#:
Restart-Computer -Computername (Get-Content C:\machineslist.txt) -Credential Administrator -Force
Here is my humble attempt:
PowerShell ps = PowerShell.Create();
ps.AddCommand("Restart-Computer");
ps.AddParameter("-ComputerName");
ScriptBlock filter2 = ScriptBlock.Create("(Get-Content C:\\machineslist.txt)");
ps.AddParameter("FilterScript2", filter2);
ps.AddParameter("-Credential");
ps.AddArgument("Administrator");
//not sure how to add password
ps.AddParameter("-Force");
foreach (PSObject result in ps.Invoke())
{
Console.WriteLine(
"{0,-24}{1}",
result.Members["Length"].Value,
result.Members["Name"].Value);
} // End foreach
To make this code snippet to compile and run, you will first need to reference the System.Management.Automation assembly (located under C:\Program Files (x86)\Reference Assemblies\Microsoft\WindowsPowerShell\3.0).
You do not need a ScriptBlock as it increases complexity, it's easier to just add the script with AddScript.
You do not need to prefix parameters with -
To pass credentials you can use PSCredential. Normally you would provide a secure string, you can translate a string into a secure string using NetworkCredential as an helper.
You will need to handle errors as well, but this is out of scope for this question!
Enjoy :-)
using System;
using System.Management.Automation;
using System.Net;
using System.Security;
namespace Sample
{
class Program
{
static void Main(string[] args)
{
PowerShell ps = PowerShell.Create();
ps.AddScript("Get-Content C:\\machineslist.txt");
ps.AddCommand("Restart-Computer");
SecureString secureString = new NetworkCredential("", "Password").SecurePassword;
PSCredential psc = new PSCredential("Administrator", secureString);
ps.AddParameter("Credential", psc);
ps.AddParameter("Force");
// Simulation only
ps.AddParameter("WhatIf");
var results = ps.Invoke();
foreach (var error in ps.Streams.Error)
{
Console.WriteLine(error);
}
foreach (PSObject result in results)
{
Console.WriteLine(result);
//Console.WriteLine("{0,-24}{1}", result.Members["Length"].Value, result.Members["Name"].Value);
}
}
}
}
I have the following c# code:
var powerShell = PowerShell.Create();
powerShell.Runspace = runspace;
powerShell.AddArgument(connectionString);
powerShell.AddArgument(storedProc);
powerShell.AddArgument(dataSource);
powerShell.AddArgument(filterList);
powerShell.AddArgument(destinationFile);
var script = "path\to\the\powershell.ps1";
powerShell.AddScript(script);
powerShell.Invoke();
And I want it to work with this powershell script:
$connString = $args[0]
$spName = $args[1]
$dataSource = $args[2]
$filterList = $args[3]
$destinationFile = $args[4]
bcp "$spName $filterList" queryout "$destinationFile" -c -t"\0" $connString
I have NO experience with powershell. Does this look right to you guys and gals? What about the .NET code. Would that run the script like I'm assuming?
Your C# needs some tweaking. First, you can't add arguments until you have added a command. Second, the AddScript() method wants the script contents of Powershell.ps1 - not the path. Try this:
var ps = PowerShell.Create();
ps.Runspace = runspace;
var script = System.IO.File.ReadAllText(#"path\to\the\powershell.ps1");
ps.AddScript(script)
ps.AddArgument(connectionString);
ps.AddArgument(storedProc);
ps.AddArgument(dataSource);
ps.AddArgument(filterList);
ps.AddArgument(destinationFile);
var results = ps.Invoke();
I want to execute some PowerShell script through C# but it requires admin privilege. This is my code (I got it here):
using (new Impersonator("user", "domain", "password"))
{
// create Powershell runspace
Runspace runspace = RunspaceFactory.CreateRunspace();
// open it
runspace.Open();
// create a pipeline and feed it the script text
Pipeline pipeline = runspace.CreatePipeline();
pipeline.Commands.AddScript(scriptText);
// add parameters if any
foreach (var parameter in parameters)
{
pipeline.Commands[0].Parameters.Add(parameter.Key, parameter.Value);
}
// 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
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();
}
Anyway, this doesn't work on my machine. For example, if the script text is "Set-ExecutionPolicy Unrestricted" then I get "Access to the registry key 'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\PowerShell\1\ShellIds\Microsoft.PowerShell' is denied."
And in my case, it cannot get list of virtual machines through Get-VM command. (I found that Get-VM only return results if it runs under Admin privilege.)
Do I do something wrong? Is there another solution for this problem?
This will launch PowerShell as an Administrator:
var newProcessInfo = new System.Diagnostics.ProcessStartInfo();
newProcessInfo.FileName = #"C:\Windows\SysWOW64\WindowsPowerShell\v1.0\powershell.exe";
newProcessInfo.Verb = "runas";
System.Diagnostics.Process.Start(newProcessInfo);
If you need to pass in a script to run, then use:
newProcessInfo.Arguments = #"C:\path\to\script.ps1";
i'm trying to wrap an already made powershell script with C# GUI client.
the script acts according to inputs from the user, and it has also outputs according to them.
i would like to get the powershell outputs, display them to my C# client and
and then to enter the input according to his choice.
this is my script, and the code below is what i came up to but it doesn't work.
(i can only get the output at the end, and only if i don't have Read-Host in my powershell script). hope that it helps some how.
Write-Host
Write-Host 'Hello World!'
Write-Host "Good-bye World! `n"
$option = Read-Host "Please enter your number"
switch ($option){
"1"
{
Write-Host "jack"
}
"2"
{
Write-Host "john"
}
"3"
{
Write-Host "joe"
}
}
public void WrapPowerShell()
{
string directory = Directory.GetCurrentDirectory();
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.FileName = #"powershell.exe";
startInfo.Arguments = string.Format(#"& '{0}'", directory + #"\hello.ps1");
startInfo.RedirectStandardOutput = true;
startInfo.RedirectStandardError = true;
startInfo.UseShellExecute = false;
startInfo.CreateNoWindow = false;
Process process = new Process();
process.StartInfo = startInfo;
process.Start();
string output = process.StandardOutput.ReadToEnd();
// Assert.IsTrue(output.Contains("StringToBeVerifiedInAUnitTest"));
string errors = process.StandardError.ReadToEnd();
}
Big Thanks in advance For your answers!!
This is a helper class that I wrote to help me create an ASP.NET web app that allowed people to run powershell scripts.
PSHelper.cs
using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using System.Text;
namespace admin_scripts {
public class PSHelper {
// See the _ps_user_lookup method for demonstration of using this method
public static Runspace new_runspace() {
InitialSessionState init_state = InitialSessionState.CreateDefault();
init_state.ThreadOptions = PSThreadOptions.UseCurrentThread;
init_state.ImportPSModule(new[] { "ActiveDirectory", "C:\\ps_modules\\disable_user.psm1" });
// Custom PS module containing functions related
// to disabling AD accounts at work.
// You would use your own module here, obviously.
return RunspaceFactory.CreateRunspace(init_state);
}
// This method is for dead-simple scripts that you only want text output from
// Not as flexible as the previous method, but it's good for the really simple cases
public static string run_simple_script( string body ) {
Runspace runspace = new_runspace();
runspace.Open();
Pipeline pipeline = runspace.CreatePipeline();
pipeline.Commands.AddScript(body);
pipeline.Commands.Add("Out-String");
Collection<PSObject> output = pipeline.Invoke();
runspace.Close();
StringBuilder sb = new StringBuilder();
foreach( PSObject line in output ) {
sb.AppendLine(line.ToString());
}
return sb.ToString();
}
}
}
I would invoke a script from an ASP.NET handler like so:
private PSObject _ps_user_lookup( string id_param ) {
Runspace runspace = PSHelper.new_runspace();
runspace.Open();
using( Pipeline pipe = runspace.CreatePipeline() ) {
Command cmd = new Command("Get-ADUser");
cmd.Parameters.Add(new CommandParameter("Identity", id_param));
cmd.Parameters.Add(new CommandParameter("Properties", "*"));
cmd.Parameters.Add(new CommandParameter("Server", "REDACTED"));
pipe.Commands.Add(cmd);
return pipe.Invoke().FirstOrDefault();
}
}
The real beauty of this arrangement is that the web application would run the script using the credentials of the web user's domain account. I hope you find it useful.
I want to run Powershell command on remote machine. This is method that I am using (localhost:131 is because I use tunnel to remote machine's port 5985):
public string RunRemotePowerShellCommand(string command)
{
System.Security.SecureString password = new System.Security.SecureString();
foreach (char c in _password.ToCharArray())
{
password.AppendChar(c);
}
string schema = "http://schemas.microsoft.com/powershell/Microsoft.Powershell";
WSManConnectionInfo connectionInfo = new WSManConnectionInfo(false,
"localhost", 131, "/wsman", schema, new PSCredential(_domain + #"\" + _userName, password));
using (Runspace remoteRunspace = RunspaceFactory.CreateRunspace(connectionInfo))
{
remoteRunspace.Open();
using (PowerShell powershell = PowerShell.Create())
{
powershell.Runspace = remoteRunspace;
powershell.AddCommand(command);
powershell.Invoke();
Collection<PSObject> results = powershell.Invoke();
// convert the script result into a single string
StringBuilder stringBuilder = new StringBuilder();
foreach (PSObject obj in results)
{
stringBuilder.AppendLine(obj.ToString());
}
return stringBuilder.ToString();
}
}
}
I'm trying to run following command:
D:\FolderName\scriptName.ps1 -action editbinding -component "comp1","comp2","comp3","comp4"
Like this:
RunRemotePowerShellCommand(#"D:\FolderName\scriptName.ps1 -action editbinding -component ""comp1"",""comp2"",""comp3"",""comp4""");
but I get:
Error: System.Management.Automation.RemoteException: The term 'D:\FolderName\scriptName.ps1 -action editbinding -component "comp1","comp2","comp3","comp4"' is not recognized as a name of cmdlet, function, script file, or operable program. Check the spelling of the name, or if the path is included, verify that the path is correct and try again.
The method works fine with simple commands, and the command that I want to run is ok when I run it on remote machine.
Thanks in advance.
Regards,
Dusan
You need to use the powershell.AddParameter() method to add the parameters for your command. The AddCommand() call should name just the command: cmdlet name, function name, path to script, etc. From the docs:
PowerShell ps = PowerShell.Create();
ps.AddCommand("Get-Process");
ps.AddArgument("wmi*");
ps.AddCommand("Sort-Object");
ps.AddParameter("descending");
ps.AddArgument("id");
I has a similar requirement.
My solution was to create a powershell function in C# code and use it over the powershell remote session like.
using System;
using System.Management.Automation;
namespace PowerShellTest
{
class Program
{
static void Main(string[] args)
{
string func = #"function Test { Write-Host 'hello' };";
PowerShell ps = PowerShell.Create();
ps.AddScript(func);
ps.Invoke();
ps.AddCommand("Test");
ps.Invoke();
Console.WriteLine("Successfully executed function");
Console.ReadLine();
}
}
}