Error when running powershell command remotely - c#

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();
}
}
}

Related

C# Powershell not returning any Get-ChildItem results

When I run powershell from my MVC application, i get no results from the Get-ChildItem –Path IIS:\AppPools command.
If i run it directly in powershell it works fine. I have set the site to run on administrator account, thinking that maybe it cant "see" the pools, but no luck.
This is just a test too, accessing the pools, as what i was origionally struggling with was turning off an application pool, as it "could not be found". with Get-WebAppPoolState -name $service
public static string test()
{
using (var powershell = PowerShell.Create())
{
using (Runspace runspace = RunspaceFactory.CreateRunspace())
{
using (RunspaceInvoke invoker = new RunspaceInvoke())
{
invoker.Invoke("Set-ExecutionPolicy Unrestricted");
invoker.Invoke("Import-Module WebAdministration");
runspace.Open();
powershell.Runspace = runspace;
powershell.AddScript(#"Import-Module WebAdministration
Get-ChildItem –Path IIS:\AppPools");
var results = powershell.Invoke();
var result = "";
result += ResultsToString(results); // results is a blank list
result += String.Join(",", powershell.Streams.Error.ToList().Select(x => x.Exception.Message));
return result;
}
}
}
}
Any ideas where the issue lies? code, permissions?

Powershell script working on Console app but not working on ASP.NET

I Have a powershell script to connect on Skype for Business Online and it is working on powershell also on Console application but when I call from ASP.NET not working
The exception when I run through ASP.NET:
"The term 'Get-CsPowerShellEndpoint' 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"
string command = #"$PlainPassword ='****';
$UserName = '****';
$SecurePassword = $PlainPassword | ConvertTo-SecureString-AsPlainText -Force;
$SkypeOnlineCred = New - Object - TypeName System.Management.Automation.PSCredential -ArgumentList $UserName, $SecurePassword;
Remove-Variable -Name PlainPassword;
Remove-Variable -Name SecurePassword;
Remove-Variable -Name UserName;
$SkypeOnlineSession = New-CsOnlineSession Credential $SkypeOnlineCred;
Import-PSSession -Session $SkypeOnlineSession | Out-Null;";
var initial = InitialSessionState.CreateDefault();
initial.ImportPSModule(new string[] {
"C:\\Program Files\\Common Files\\Skype for Business Online\\Modules\\SkypeOnlineConnector\\SkypeOnlineConnectorStartup.psm1"
});
using (Runspace runspace = RunspaceFactory.CreateRunspace(initial))
{
// Open runspace
runspace.Open();
// Initialize PowerShell engine
using (PowerShell shell = PowerShell.Create())
{
shell.Runspace = runspace;
// Add the script to the PowerShell object
shell.Commands.AddScript(command);
try
{
// Execute the script
var results = shell.Invoke();
if (shell.Streams.Error.Count > 0)
{
throw new Exception(shell.Streams.Error[0].Exception.Message);
}
// display results, with BaseObject converted to string
// Note : use |out-string for console-like output
return results;
}
catch (Exception e)
{
throw new Exception("On Invoke" + e.Message);
}
}
}

How to get value from powershell script into C# variable?

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
}
}

How to get a list of AppV virtual processes using C#

I am trying to get a list of all Virtual Processes started by Microsoft AppV using C#.
I tried using Powershell in C# but I get this error:
System.Management.Automation.CommandNotFoundException: 'The 'Get-AppvVirtualProcess' command was found in the module 'AppvClient', but the module could not be loaded. For more information, run 'Import-Module AppvClient'.'
The weird thing is that if I use the Powershell command line, it works just fine and lists the virtual processes.
So in C# I did a:
ps.Commands.AddCommand("Get-Command");
and it shows Get-AppvVirtualProcess listed as a command:
The result:
Function Get-AppvVirtualProcess 1.0.0.0 A
I tried loading the module in C# manually using:
InitialSessionState initial = InitialSessionState.CreateDefault();
initial.ImportPSModule(new string[] {#"C:\Program Files\Microsoft Application Virtualization\Client\AppvClient\AppvClient.psd1" });
and
ps.Commands.AddCommand("Import-Module").AddArgument("AppvClient");
But it still gives me the same error mentioned above.
The code in C# looks like this:
public static void powershellCommand()
{
Collection<PSObject> result;
using (Runspace myRunSpace = RunspaceFactory.CreateRunspace())
{
InitialSessionState initial = InitialSessionState.CreateDefault();
initial.ImportPSModule(new string[] {#"C:\Program Files\Microsoft Application Virtualization\Client\AppvClient\AppvClient.psd1" });
Runspace runspace = RunspaceFactory.CreateRunspace(initial);
runspace.Open();
PowerShell ps = PowerShell.Create();
ps.Runspace = runspace;
ps.Commands.AddCommand("Import-Module").AddArgument("AppvClient");
ps.Commands.AddCommand("Get-AppvVirtualProcess");
result = ps.Invoke();
var builder = new StringBuilder();
foreach (PSObject psObject in result)
{
builder.Append(psObject.ToString() + "\n");
builder.ToString();
}
Console.WriteLine("Virtual Process: {0}", builder.ToString());
}
}
Instead of Runspace, I tried this as well but I get the same error:
public static void p()
{
using (var powershell = PowerShell.Create())
{
powershell.AddCommand("Get-AppvVirtualProcess");
powershell.Invoke();
}
}
You could try to iterate through all the running process, and find those that loaded either AppVEntSubsystems32.dll or AppVEntSubsystems64.dll.
You can read more about this here: https://blogs.msdn.microsoft.com/gladiator/2014/09/04/app-v-5-on-application-launch/

How to run Restart-Computer in PowerShell using C#?

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);
}
}
}
}

Categories

Resources