Using "New-Object" cmdlet in C# - c#

I'm trying to run some Powershell cmdlet in a C# program I've been working on.
The cmdlet I've been trying to run is the following:
$cred = New-Object System.Management.Automation.PSCredential (user, (ConvertTo-SecureString pass –ASPlainText –Force));
And what I did in my C# programm was the following:
string user = textBox1.Text;
string pass = textBox2.Text;
PowerShell ps = PowerShell.Create();
ps.AddCommand("New-Object");
ps.AddArgument("System.Management.Automation.PSCredential ("+user+", (ConvertTo-SecureString "+pass+" –ASPlainText –Force))");
var cred = ps.Invoke();
But when i do this I get prompted with the following error:
A constructor was not found. Cannot find an appropriate constructor for type System.Management.Automation.PSCredential (user, (ConvertTo-SecureString pass –ASPlainText –Force)).
So my question is, how can I run this Powershell cmdlet from my C# program, and store the result in a variable inside the C# program?
Thank you!

This can be done without invoking powershell. Whether thats useful or not depends upon what you are up to.
var user = "username";
var pass = new System.Security.SecureString();
foreach (char c in "password")
{
pass.AppendChar(c);
}
var cred = new System.Management.Automation.PSCredential(user, pass);

Martin Brown's helpful answer is definitely the best solution in your case.
As for what you tried:
You didn't correctly translate your PowerShell command to a PowerShell SDK call.
Specifically, the way you add arguments is incorrect:
ps.AddArgument("System.Management.Automation.PSCredential ("+user+", (ConvertTo-SecureString "+pass+" –ASPlainText –Force))");
You must add arguments one by one, via .AddArgument(<val>), or, preferably, as named parameters via .AddParameter(<name>, <val>)).
You cannot use embedded PowerShell commands as arguments.
If we leave the issue of obtaining a SecureString instance aside and use just a dummy instance, this is what your statement would have to look like:
ps.AddCommand("New-Object")
.AddParameter("TypeName", "System.Management.Automation.PSCredential")
.AddParameter("ArgumentList", new object[] { user, new System.Security.SecureString() });
Note the use of parameter names and how parameter -ArgumentList must be passed as an array.
If you do need to execute PowerShell code via the SDK, use the .AddScript() method instead, but note that you can only pass a single string that contains the code to execute (note the use of an interpolated C# string, $"..." for embedding C# variable values):
ps.AddScript(
$"New-Object PSCredential \"{user}\", (ConvertTo-SecureString \"{pass}\" –AsPlainText –Force)"
);
Caveat: Unlike a command added with .AddCommand(), an .AddScript()-added command always fails silently on execution with .Invoke() - no exception occurs; you'll have to inspect ps.HadErrors and ps.Streams.Error to check for errors. By contrast, .AddCommand() does throw an exception if the target command reports a (statement-)terminating error (though these are rare; an example is passing an invalid parameter name).

Related

Running the PowerShell Script from the c#

I am trying to call PowerShell ISE Script from the C#.
I have command that I am running it on the PowerShell
. .\Commands.ps1; Set-Product -bProduct 'Reg' -IPPoint 'ServerAddress' -Location 'testlocation' -Terminal 3
Now I am trying to create the Command with the c# I have wrote some code Like this.
//Set Execution Policy to un restrict
powershell.AddCommand("Set-ExecutionPolicy");
powershell.AddArgument("unrestricted");
powershell.Invoke();
powershell.Commands.Clear();
powershell.AddScript("K:\\Auto\\Cases\\Location\\Commands.ps1", false);
powershell.AddArgument("Set-Product").AddParameter("bProduct ", "Reg").
AddParameter("IPPoint", "ServerAddress").
AddParameter("Location", "testlocation").AddParameter("Terminal", 3);
powershell.Invoke();
I can see its running fine. But its not updating values in my xml file. It suppose to update my values in file. When I try to run it with powershell It does run and works file. But c# code does not work.
Any hint or clue will be appreciated.
Mind the semicolon, so this is basically two statements:
1.) Dot-sourcing the script Commands.ps1
. .\Commands.ps1
2.) Invoking the cmdlet Set-Product
Set-Product -bProduct 'Reg' -IPPoint 'ServerAddress' -Location 'testlocation' -Terminal 3
So, you have to treat them as such. Also, AddScript expects code, not a file name.
powershell
// dot-source the script
.AddScript(#". 'K:\Auto\Cases\Location\Commands.ps1'")
// this is the semicolon = add another statement
.AddStatement()
// add the cmdlet
.AddCommand("Set-Product")
.AddParameter("bProduct", "Reg")
.AddParameter("IPPoint", "ServerAddress")
.AddParameter("Location", "testlocation")
.AddParameter("Terminal", 3)
// invoke all statements
.Invoke();
(Alternatively to AddStatement() you can of course split this up in two calls and call Invoke() twice.)

Invoked PS command to string

Is there way to convert invoked powershell command from C# to string?.
Let's say for example i have something like this:
PowerShell ps = PowerShell.Create();
ps.AddCommand("Add-VpnConnection");
ps.AddParameter("Name", "VPN_" + ClientName);
ps.AddParameter("ServerAddress", VPN_SERVER_IP);
ps.AddParameter("AllUserConnection");
ps.AddParameter("SplitTunneling", true);
ps.AddParameter("TunnelType", "L2tp");
And i would like to save invoked command to log file.
Can i somehow return whole command as string?
I believe what you want essentially is this.
PowerShell ps = PowerShell.Create();
ps.AddScript($"Add-VpnConnection -Name \"VPN_{ClientName}\" -ServerAddress {VPNServerIP} -AllUserConnection -SplitTunneling -TunnelType L2tp");
ps.Invoke();
The invoke return will contain a collection of PSObject so you can read it and save the information like you want in a log in c#.
Note: This answer does not solve the OP's problem. Instead, it shows how to capture a PowerShell command's output as a string in C#, formatted in the same way that the command's output would print to the display (console), if it were run in an interactive PowerShell session.
Out-String is the cmdlet that produces formatted, for-display representations of output objects as strings, as they would print to the screen in a PowerShell console.
Therefore, you simply need to use another .AddCommand() in order to pipe the output from your Add-VpnConnection call to Out-String:
string formattedOutput;
using (PowerShell ps = PowerShell.Create())
{
ps.AddCommand("Add-VpnConnection")
.AddParameter("Name", "VPN_" + ClientName)
.AddParameter("ServerAddress")
.AddParameter("AllUserConnection", VPN_SERVER_IP)
.AddParameter("SplitTunneling", true)
.AddParameter("TunnelType", "L2tp");
// Add an Out-String call to which the previous command's output is piped to.
// Use a -Width argument (column count) large enough to show all data.
ps.AddCommand("Out-String").AddParameter("Width", 512);
// Due to use of Out-String, a *single string* is effectively returned,
// as the only element of the output collection.
formattedOutput = ps.Invoke<string>()[0];
}
Console.Write(formattedOutput);

RequireSenderAuthenticationEnabled distribution group parameters

I create distribution group using PowerShell in a C# app.
I want ot change the parameter which allow external users to send mail to this group.
On the the technet I found https://technet.microsoft.com/fr-fr/library/aa998856(v=exchg.160).aspx
And I try to add a parameter to my PowerShell command. For executing PowerShell in my app I use the way :
ps.Commands = new PSCommand().AddCommand("New-DistributionGroup").AddParameter("Name", "GRP_DIF_" + textBox1.Text);
ps.Invoke();
This code create a distribution group successfully but when I want to change the parameter
RequireSenderAuthenticationEnabled
using
[...].AddParameter("RequireSenderAuthenticationEnabled", "$false")
I have an
Unknow parameter : RequireSenderAuthenticationEnabled
Is there a special way to change this parameter ?

how to pass object to PowerShell AddParameter in c#?

I wrote corresponding C# code for the following Powershell command (Works fine on Powershell commandline):
Get-VMNetworkAdapter -VM $vm
Here is the C# code:
PSObject vmFound;
// initizalize vmFound from another PowerShell cdmlet in C#
PowerShell psGetNic = PowerShell.Create();
psGetNic.AddCommand("Get-VMNetworkAdapter");
psGetNic.AddParameter("VM", vmFound);
I tried the following as second parameter - nothing works:
psGetNic.AddParameter("VM", vmFound);
psGetNic.AddParameter("VM", (object)vmFound);
psGetNic.AddParameter("VM", vmFound.ImmediateBaseObject);
psGetNic.AddParameter("VM", vmFound.BaseObject);
I do not get any return value after running the command psGetNic.Invoke(). In other words, how to convert PSObject to object and pass it as a parameter.

Powershell Pipe and Foreach-Object in c#

I am invoking a get-msoluser cmdlet of office365 and i use the following cmdlet in powershell
Get-MsolUser -UserPrincipalName user#organization.onmicrosoft.com | ForEach-Object{ $_.licenses}
The output is a collection of licenses and i wanted the same script to be run in c#. so i have written the code as follows
private void displayLicenses(){
Command cmd = new Command("Get-MsolUser");
cmd.Parameters.Add("UserPrincipalName","user#organization.onmicrosoft.com");
Command cmd2 = new Command("ForEach-Object");
cmd2.Parameters.Add("$_.licenses.AccountSku");
Pipeline pipe = Office365Runspace.CreatePipeline();
pipe.Commands.Add(cmd);
pipe.Commands.Add(cmd2);
Console.WriteLine("Before invoking the pipe");
ICollection<PSObject> result = pipe.Invoke();
CheckForErrors(pipe);
Console.WriteLine("Executed command {0} + {1} with no error", cmd.CommandText, cmd2.CommandText);
foreach(PSObject obj in result){
foreach(PSPropertyInfo propInfo in obj.Properties){
Console.WriteLine(propInfo.Name+": "+propInfo.Value+" "+propInfo.MemberType);
}
}
}
But i still get an error on executing this function saying
Unhandled Exception:
System.Management.Automation.CommandNotFoundException: The term
'ForEach-Object' is not recognized as the name of a cmdlet, function,
scrip t file, or operable program. Check the spelling of the name, or
if a path was in cluded, verify that the path is correct and try
again.
I checked that my project has a reference to System.management.Automation.dll file that contains the ForEach-Object cmdlet.
I found the dll using this cmd in powershell
(Get-Command ForEach-Object).dll
Thanks,
Satya
I figured out the problem causing for the issue. It is due to the misconfigured runspace i created.
InitialSessionState initalState = InitialSessionState.Create();
initalState.ImportPSModule(new String[] { "msonline" });
//initalState.LanguageMode = PSLanguageMode.FullLanguage;
Office365Runspace = RunspaceFactory.CreateRunspace(initalState);
Office365Runspace.Open();
i was creating the initalstate with empty one,When i changed it to default one it worked fine.On creating the default one it includes all the modules that were obtained by default.
InitialSessionState initalState = InitialSessionState.CreateDefault();
it worked fine.
Thanks,
Satya
It sounds like your're trying to run that in the remote session at the Exchange server. Those are NoLanguage constrained sessions, meaning that you can only run the Exchange cmdlets in those sessions. If you want to use PowerShell core language cmdlets (like foreach-object), you have to do that in a local session and either use Import-PSSession to import the Exchange functions into your local session (implicit remoting) , or use Invoke-Command and point it at the remote session on the Exchange server.

Categories