Could not run PS-script - No commands are specified - c#

I'm currently trying to remotely invoke a PowerShell script via my C# code but somehow I´m constantly failing to achieve my goal and my Google searches have so far turned up unsuccessful.
I have tried adding each parameter as "command.AddParameter" and by using ".AddParameter" but I'm still getting the same problem and I´m running out of ideas.
PSCredential credential = new PSCredential(LSUUser, password);
var command = new PSCommand();
command.AddCommand("Invoke-Command")
.AddParameter("ComputerName", computerName)
.AddParameter("Credential", credential)
.AddParameter("ScriptBlock", ScriptBlock.Create(#"param(${process}) Stop-Process ${process}"))
.AddParameter("Argumentlist", new object[] { process });
//Tried this as well, but no success :(
//command.AddParameter("Scriptblock", ScriptBlock.Create(#"param($comp, $cred, $pro) -Computername $comp -Credential $cred Stop-Process $pro"));
//command.AddParameter("ArgumentList", new object[] {computerName, credential, process});
The error-message: ("vid" is the swedish word for "at", no idea why my debugger translates parts of my error messages since I run VS in English)
Could not run PS-script: System.Management.Automation.PSInvalidOperationException: No commands are specified.
at System.Management.Automation.PowerShell.Prepare[TInput,TOutput](PSDataCollection`1 input, PSDataCollection`1 output, PSInvocationSettings settings, Boolean shouldCreateWorker)
at System.Management.Automation.PowerShell.CoreInvokeHelper[TInput,TOutput](PSDataCollection`1 input, PSDataCollection`1 output, PSInvocationSettings settings)
at System.Management.Automation.PowerShell.CoreInvoke[TInput,TOutput](PSDataCollection`1 input, PSDataCollection`1 output, PSInvocationSettings settings)
at System.Management.Automation.PowerShell.CoreInvoke[TOutput](IEnumerable input, PSDataCollection`1 output, PSInvocationSettings settings)
at System.Management.Automation.PowerShell.Invoke(IEnumerable input, PSInvocationSettings settings)
at System.Management.Automation.PowerShell.Invoke()
at <projectname>.TerminateProcess(String computerName, String process)
Any ideas to what I´m doing wrong would be greatly appreciated!
Sidenote: I would rather not use an external PS-file but I may be forced to if no solution is found.
Edit: Whole function for clarification.
Currently i´m just logging the PSOutputs to see what´s going on.
public void TerminateProcess(string computerName, string process)
{
SecureString password = new SecureString();
foreach(char c in LSUPass)
{
password.AppendChar(c);
}
try
{
//using (Runspace runspace = RunspaceFactory.CreateRunspace())
//{
using (PowerShell powerShellInstance = PowerShell.Create())
{
PSCredential credential = new PSCredential(LSUUser, password);
ScriptBlock scriptBlock = ScriptBlock.Create(#"param(${process}) Stop-Process ${process}");
var command = new PSCommand();
command.AddCommand("invoke-command");
command.AddParameter("ComputerName", computerName);
command.AddParameter("Credential", credential);
command.AddParameter("ScriptBlock", scriptBlock);
command.AddParameter("Argumentlist", new object[] { process });
//Tried this as well, but no success :(
//command.AddParameter("Scriptblock", ScriptBlock.Create(#"param($comp, $cred, $pro) -Computername $comp -Credential $cred Stop-Process $pro"));
//command.AddParameter("ArgumentList", new object[] {computerName, credential, process});
string PSDebug = "";
foreach(object com in command.Commands)
{
PSDebug = PSDebug + com.ToString();
}
Logger("INFO", PSDebug);
Collection<PSObject> PSOutput = powerShellInstance.Invoke();
if (powerShellInstance.Streams.Error.Count > 0)
{
foreach(ErrorRecord error in powerShellInstance.Streams.Error)
{
Logger("ERROR", error.ToString());
}
}
foreach (PSObject outputItem in PSOutput)
{
if (outputItem != null)
{
Logger("INFO", outputItem.BaseObject.GetType().FullName);
}
}
}
//}
}
catch (Exception e)
{
Logger("ERROR", "Could not run PS-script: " + e.ToString());
}
}

As PetSerAI pointed out in the comments, I had forgot to hook the command to the instance itself. After adding the last line of code it seems to be working (well still got access errors but that´s something I should be able to figure out). :)
PSCredential credential = new PSCredential(LSUUser, password);
ScriptBlock scriptBlock = ScriptBlock.Create(#"param(${process}) Stop-Process ${process}");
var command = new PSCommand();
command.AddCommand("invoke-command");
command.AddParameter("ComputerName", computerName);
command.AddParameter("Credential", credential);
command.AddParameter("ScriptBlock", scriptBlock);
command.AddParameter("Argumentlist", new object[] { process });
powerShellInstance.Commands = command;

Related

Unable to run Disable-Mailbox Powershell in C#

I'm trying to reproduce the following working chunk of Powershell in C#.
We are connecting on an Exchange2010 instance.
$ExURI = "http://ExchangeUrl/PowerShell/"
$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri $ExURI -Authentication Kerberos
$userName = "patatem"
Import-PSSession $Session -AllowClobber -EA SilentlyContinue | Out-Null
Get-Recipient $userName
Disable-Mailbox -Identity $userName -Confirm:$False
#enable-mailbox -identity $userName -Alias $userName -database "AnExchangeDatabase"
remove-PSSession $Session
I've been following the steps referenced here : https://blogs.msdn.microsoft.com/wushuai/2016/09/18/access-exchange-online-by-powershell-in-c/
In the following block of code, I get positive results when I call Get-Mailbox, Get-Recipient.
When calling Disable-Mailbox, I get the following error
The term 'Disable-Mailbox' 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.
Why is it recognizing Get-Mailbox but not Disable-Mailbox?
(I've tried adding another chunk of code to do the Import session section of Powershell but that didn't change anything.)
public void EnableCommand(string identity, string database)
{
if (!string.IsNullOrWhiteSpace(identity))
{
using (var runspace = RunspaceFactory.CreateRunspace())
{
runspace.Open();
var powershell = PowerShell.Create();
var command = new PSCommand();
command.AddCommand("New-PSSession");
command.AddParameter("ConfigurationName", "Microsoft.Exchange");
command.AddParameter("ConnectionUri", new Uri(Constants.DefaultOutLookUrl));
command.AddParameter("Authentication", "Kerberos");
powershell.Commands = command;
powershell.Runspace = runspace;
var result = powershell.Invoke();
if (powershell.Streams.Error.Count > 0 || result.Count != 1)
{
throw new Exception("Fail to establish the connection");
}
powershell = PowerShell.Create();
command = new PSCommand();
command.AddCommand("Invoke-Command");
command.AddParameter("ScriptBlock", System.Management.Automation.ScriptBlock.Create("Get-Mailbox"));
command.AddParameter("Session", result[0]);
powershell.Commands = command;
powershell.Runspace = runspace;
var mailBoxes = powershell.Invoke();
// This will give me a result
var returnValue = new StringBuilder();
foreach (var item in mailBoxes)
{
returnValue.AppendLine(item.ToString());
}
// check the other output streams (for example, the error stream)
if (powershell.Streams.Error.Count > 0)
{
returnValue.AppendLine($"{powershell.Streams.Error.Count} errors: ");
foreach (var err in powershell.Streams.Error)
{
returnValue.AppendLine($"{err.ToString()}");
}
}
// This will also work
powershell = PowerShell.Create();
command = new PSCommand();
command.AddCommand("Invoke-Command");
command.AddParameter("ScriptBlock", System.Management.Automation.ScriptBlock.Create("Get-Recipient SomeEmail"));
command.AddParameter("Session", result[0]);
powershell.Commands = command;
powershell.Runspace = runspace;
var mailBoxes2 = powershell.Invoke();
foreach (var item in mailBoxes2)
{
returnValue.AppendLine(item.ToString());
}
if (powershell.Streams.Error.Count > 0)
{
returnValue.AppendLine($"{powershell.Streams.Error.Count} errors: ");
foreach (var err in powershell.Streams.Error)
{
returnValue.AppendLine($"{err.ToString()}");
}
}
// this will give me The term 'Disable-Mailbox' 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.
powershell = PowerShell.Create();
command = new PSCommand();
command.AddCommand("Invoke-Command");
command.AddParameter("ScriptBlock", System.Management.Automation.ScriptBlock.Create("Disable-Mailbox -Identity patatem -Confirm:$False"));
command.AddParameter("Session", result[0]);
powershell.Commands = command;
powershell.Runspace = runspace;
var mailBoxes3 = powershell.Invoke();
foreach (var item in mailBoxes3)
{
returnValue.AppendLine(item.ToString());
}
// check the other output streams (for example, the error stream)
if (powershell.Streams.Error.Count > 0)
{
returnValue.AppendLine($"{powershell.Streams.Error.Count} errors: ");
foreach (var err in powershell.Streams.Error)
{
returnValue.AppendLine($"{err.ToString()}");
}
}
Console.WriteLine(returnValue);
}
}
The term 'Disable-Mailbox' 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.
If the user attempting to run the Disable-Mailbox-cmdlet has insufficient permissions to disable a mailbox (RBAC), this nonspecific error message is issued.
Run your code with sufficient permissions and it should work.
TechNet article: Understanding Role Based Access Control

Using PowerShell to Read Office 365 Group Members in C#

I'm attempting to connect to an Office 365 Group and list the membership of the Group using Powershell through a C# Project.
From this article, I've determined the command I need to use is
Get-UnifiedGroupLinks –Identity groupalias –LinkType Members
Here is my current code:
string connectionUri = "https://outlook.office365.com/powershell-liveid/";
SecureString secpassword = new SecureString();
foreach (char c in Password)
{
secpassword.AppendChar(c);
}
PSCredential credential = new PSCredential(UserName, secpassword);
Runspace runspace = RunspaceFactory.CreateRunspace();
PSObject SessionHolder = null;
using (PowerShell powershell = PowerShell.Create())
{
PSCommand command = new PSCommand();
command.AddCommand("New-PSSession");
command.AddParameter("ConfigurationName", "Microsoft.Exchange");
command.AddParameter("ConnectionUri", new Uri(connectionUri));
command.AddParameter("Credential", credential);
command.AddParameter("Authentication", "Basic");
powershell.Commands = command;
runspace.Open();
powershell.Runspace = runspace;
Collection<System.Management.Automation.PSObject> result = powershell.Invoke();
if (powershell.Streams.Error.Count > 0 || result.Count != 1)
{
throw new Exception("Fail to establish the connection");
}
else
SessionHolder = result[0];
}
using (PowerShell powershell = PowerShell.Create())
{
PSCommand command = new PSCommand();
// –Identity groupalias –LinkType Members
command = new PSCommand();
command.AddCommand("Invoke-Command");
command.AddParameter("ScriptBlock", System.Management.Automation.ScriptBlock.Create("Get-UnifiedGroupLinks"));
command.AddParameter("Session", SessionHolder);
command.AddParameter("Identity", groupAddress);
command.AddParameter("LinkType", "Members");
powershell.Commands = command;
powershell.Runspace = runspace;
Collection<PSObject> PSOutput = powershell.Invoke();
// loop through each output object item
foreach (PSObject outputItem in PSOutput)
{
}
}
Variables used above, declaration not shown: "UserName", "Password", "groupAddress"
I am able to make a connection to the service, but when I try to get the group members I get the error "A parameter cannot be found that matches parameter name 'Identity'"
I'm not sure how to proceed in troubleshooting my code. I've tried the Group email, Group Alias, and Group Display Name in the Identity parameter. Perhaps I have something else wrong?
I'm using the following Libraries in Visual Studio 2017 on a Windows 10 machine:
using System.Management.Automation;
using System.Management.Automation.Runspaces;
Usually I get that error when I'm passing the variable with some extra characters. Check how the variable is being passed, if its just "email" or if it contains other info like #{"email"}. Very common in Powershell.
Hope that sheds some light. Because the command is very simple:
Get-UnifiedGroupLinks -Identity [name] -LinkType members
I found a bit of code that makes things work... It slows it down, so I'm not sure if there is a better way, but here is my updated code:
string connectionUri = "https://outlook.office365.com/powershell-liveid/";
SecureString secpassword = new SecureString();
foreach (char c in Password)
{
secpassword.AppendChar(c);
}
PSCredential credential = new PSCredential(UserName, secpassword);
Runspace runspace = RunspaceFactory.CreateRunspace();
PSObject SessionHolder = null;
using (PowerShell powershell = PowerShell.Create())
{
string connectionUri = "https://outlook.office365.com/powershell-liveid/";
SecureString secpassword = new SecureString();
foreach (char c in Password)
{
secpassword.AppendChar(c);
}
PSCredential credential = new PSCredential(UserName, secpassword);
PSCommand command = new PSCommand();
command.AddCommand("New-PSSession");
command.AddParameter("ConfigurationName", "Microsoft.Exchange");
command.AddParameter("ConnectionUri", new Uri(connectionUri));
command.AddParameter("Credential", credential);
command.AddParameter("Authentication", "Basic");
powershell.Commands = command;
runspace.Open();
powershell.Runspace = runspace;
Collection<System.Management.Automation.PSObject> result = powershell.Invoke();
if (powershell.Streams.Error.Count > 0 || result.Count != 1)
throw new Exception("Fail to establish the connection");
else
SessionHolder = result[0];
PSCommand ImportSession = new PSCommand();
ImportSession.AddCommand("Import-PSSession");
ImportSession.AddParameter("Session", SessionHolder);
powershell.Commands = ImportSession;
powershell.Invoke();
PSCommand GrabGroup = new PSCommand();
GrabGroup.AddCommand("Get-UnifiedGroupLinks");
GrabGroup.AddParameter("Identity", GroupAddress);
GrabGroup.AddParameter("LinkType", "Members");
powershell.Commands = GrabGroup;
Collection<PSObject> PSOutput_GroupMembers = powershell.Invoke();
foreach (PSObject outputItem in PSOutput_GroupMembers)
{
//Process Members
}
}
The key seems to be that I need to Import the session before I can begin using it.

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.

Error while running AD commandlets in powershell from C#

I have tried executing AD commandlets in powershell using C# from the same machine. This works fine.
static void Main(string[] args)
{
InitialSessionState iss = InitialSessionState.CreateDefault();
iss.ImportPSModule(new string[] { "activedirectory" });
Runspace myRunSpace = RunspaceFactory.CreateRunspace(iss);
myRunSpace.Open();
Pipeline pipeLine = myRunSpace.CreatePipeline();
Command myCommand = new Command("Get-ADUser");
myCommand.Parameters.Add("Filter", "sAMAccountName -eq 'user1'");
//myCommand.Parameters.Add("IncludeDeletedObjects");
pipeLine.Commands.Add(myCommand);
//Command restoreCommand = new Command("Restore-ADObject");
//pipeLine.Commands.Add(restoreCommand);
Console.WriteLine("Before Invoke");
Collection<PSObject> commandResults = pipeLine.Invoke();
Console.WriteLine("After Invoke");
foreach (PSObject cmdlet in commandResults)
{
//Console.WriteLine("Inside foreach");
string cmdletName = cmdlet.BaseObject.ToString();
System.Diagnostics.Debug.Print(cmdletName);
Console.WriteLine(cmdletName);
}
Console.ReadLine();
}
But while trying to run the same command remotely using the invoke command it gives the error The term 'Get-ADUser' is not recognized as the name of a cmdlet, function, script file, or operable program.
The following is my program :
static void Main(string[] args)
{
string shellUri = "http://schemas.microsoft.com/powershell/Microsoft.PowerShell";
string userName = "Domain\\Administrator";
string password = "Password";
SecureString securePassword = new SecureString();
foreach (char c in password)
{
securePassword.AppendChar(c);
}
PSCredential credential = new PSCredential(userName, securePassword);
WSManConnectionInfo connectionInfo = new WSManConnectionInfo(false, "machinename", 5985, "/wsman", shellUri, credential);
using (Runspace runspace = RunspaceFactory.CreateRunspace(connectionInfo))
{
runspace.Open();
using (PowerShell powershell = PowerShell.Create())
{
powershell.Runspace = runspace;
PSCommand new1 = new PSCommand();
new1.AddCommand("Get-ADUser");
new1.AddParameter("identity", "CN=user1,DC=example,DC=com");
powershell.Commands = new1;
Collection<PSObject> results = powershell.Invoke();
foreach (PSObject obj in results)
{
PSMemberInfoCollection<PSPropertyInfo> propInfos = obj.Properties;
Console.WriteLine("********************");
foreach (PSPropertyInfo propInfo in propInfos)
{
string propInfoValue = (propInfo.Value == null) ? "" : propInfo.Value.ToString();
Console.WriteLine("{0} --> {1}", propInfo.Name, propInfoValue);
}
}
}
}
}
How can I achieve calling AD commandlets remotely?
Is there a way to invoke commands remotely using InitialSessionState rather than WSManConnectionInfo .
If I use invoke-command -computername $DC -ScriptBlock {Remove-ADUser -identity "user1"} -credential $cred - i get the error The term 'Remove-ADUser' is not recognized as the name of a cmdlet, function, script file, or operable program.
But it is possible to use command Remove-ADUser -identity "user1" -server $DC -credential $cred .How to directly execute the AD command in powershell from C# client?
You need to import the ActiveDirectory module in the remote runspace before executing the AD command e.g.:
powershell.Commands.AddCommand("Import-Module").AddArgument("ActiveDirectory");
powershell.Invoke();
powershell.Commands.Clear();

C# Remote Powershell SharePoint 2010

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.

Categories

Resources