Invoke Powershell command from C# with different credential - c#

I need to execute a couple of powershell command from C#, and I'm using this code
Runspace rs = RunspaceFactory.CreateRunspace();
rs.Open();
PowerShell ps = PowerShell.Create();
ps.Runspace = rs;
ps.AddCommand("Add-PSSnapin").AddArgument("Citrix*");
ps.Invoke();
// other commands ...
This works correctly but now a user without sufficient rights to use powershell should execute this application. Is there a way to execute powershell code with different credentials?
I mean something like this
var password = new SecureString();
Array.ForEach("myStup1dPa$$w0rd".ToCharArray(), password.AppendChar);
PSCredential credential = new PSCredential("serviceUser", password);
// here I miss the way to link this credential object to ps Powershell object...

Untested code...but this should work for you. I use something similar to run remote powershell (Just set WSManConnectionInfo.ComputerName).
public static Collection<PSObject> GetPSResults(string powerShell, PSCredential credential, bool throwErrors = true)
{
Collection<PSObject> toReturn = new Collection<PSObject>();
WSManConnectionInfo connectionInfo = new WSManConnectionInfo() { Credential = credential };
using (Runspace runspace = RunspaceFactory.CreateRunspace(connectionInfo))
{
runspace.Open();
using (PowerShell ps = PowerShell.Create())
{
ps.Runspace = runspace;
ps.AddScript(powerShell);
toReturn = ps.Invoke();
if (throwErrors)
{
if (ps.HadErrors)
{
throw ps.Streams.Error.ElementAt(0).Exception;
}
}
}
runspace.Close();
}
return toReturn;
}

Related

MSTSC into remote desktop with credentials with powershell using c#

I'm trying to use a script like this:
$Server="remotepc"
$User="user"
$Password="password"
cmdkey /generic:$Server /user:$User /pass:$Password
mstsc /v:$Server /console
which works fine when running in powershell.
I'm trying to get this using runspace and pipeline in c#.
So this code works:
string server = "server";
string mstscScript = "mstsc /v:"+server;
Runspace runspace = RunspaceFactory.CreateRunspace();
runspace.Open();
Pipeline pipeline = runspace.CreatePipeline();
pipeline.Commands.AddScript(mstscScript);
pipeline.Invoke();
runspace.Close();
However, if I add the script with the username and password it stops working and freezes.
So this code does not work.
string username = "user";
string password = "password";
string server = "server";
string cmdScript="cmd/genaric:"+server+" /user:$" + username" +
/pass:$" + password;
string mstscScript = "mstsc /v:" + server;
Runspace runspace = RunspaceFactory.CreateRunspace();
runspace.Open();
Pipeline pipeline = runspace.CreatePipeline();
pipeline.Commands.AddScript(cmdScript);
pipeline.Commands.AddScript(mstscScript);
pipeline.Invoke();
runspace.Close();
This worked for me. I think your cmdkey has a typo.
string tsScript = $"mstsc /v:{machinename}";
string cmdKey = $"cmdkey /generic:{machinename} /user:{username} /pass:{password}";
using (Runspace rs = RunspaceFactory.CreateRunspace())
{
rs.Open();
using (Pipeline pl = rs.CreatePipeline())
{
pl.Commands.AddScript(cmdKey);
pl.Commands.AddScript(tsScript);
pl.Invoke();
}
}

c# The term 'Enable-Mailbox' is not recognized as the name of a cmdlet

All is working well on developer's computer from VS or from bin/release files of wpf app. But, when I run the same project from VS or bin/release files on another computer I'm receiving an error:"The term 'Enable-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."
Here is the code where the error is happening:
public static class ManageMailBox
{
public static bool CreateMailBox(string strUserID, string admin_user, string pword) //, string str_upn)
{
try
{
string strExchangeServer = Constants.ExchangeServer;
Uri uri = new Uri(#"http://" + strExchangeServer + #"/powershell?serializationLevel=Full"); // orig works
/// must pass secure string
char[] passwordChars = pword.ToCharArray();
SecureString password = new SecureString();
foreach (char c in passwordChars)
{
password.AppendChar(c);
}
PSCredential credential = new PSCredential("DOMAIN\\" + admin_user, password);
Runspace runspace = RunspaceFactory.CreateRunspace();
PowerShell powershell = PowerShell.Create();
PSCommand command = new PSCommand();
command.AddCommand("New-PSSession");
command.AddParameter("ConfigurationName", "Microsoft.Exchange");
command.AddParameter("ConnectionUri", uri);
command.AddParameter("Credential", credential);
command.AddParameter("Authentication", "Default");
PSSessionOption sessionOption = new PSSessionOption();
sessionOption.SkipCACheck = true;
sessionOption.SkipCNCheck = true;
sessionOption.SkipRevocationCheck = true;
command.AddParameter("SessionOption", sessionOption);
powershell.Commands = command;
try
{
// open the remote runspace
runspace.Open();
// associate the runspace with powershell
powershell.Runspace = runspace;
// invoke the powershell to obtain the results
Collection<PSSession> result = powershell.Invoke<PSSession>();
foreach (ErrorRecord current in powershell.Streams.Error)
{
throw new Exception("Exception: " + current.Exception.ToString());
throw new Exception("Inner Exception: " + current.Exception.InnerException);
}
if (result.Count != 1)
throw new Exception("Unexpected number of Remote Runspace connections returned.");
// Set the runspace as a local variable on the runspace
powershell = PowerShell.Create();
command = new PSCommand();
command.AddCommand("Set-Variable");
command.AddParameter("Name", "ra");
command.AddParameter("Value", result[0]);
powershell.Commands = command;
powershell.Runspace = runspace;
powershell.Invoke();
// First import the cmdlets in the current runspace (using Import-PSSession)
powershell = PowerShell.Create();
command = new PSCommand();
//command.AddScript("Set-ExecutionPolicy -Unrestricted");
command.AddScript("Import-PSSession -Session $ra");
powershell.Commands = command;
powershell.Runspace = runspace;
powershell.Invoke();
// Now run get-ExchangeServer
powershell = PowerShell.Create();
command = new PSCommand();
command.AddCommand("Enable-Mailbox");
command.AddParameter("Identity", strUserID);
command.AddParameter("Alias", strUserID);
command.AddParameter("Database", "IAP Mailbox Database 0948752629");
powershell.Commands = command;
powershell.Runspace = runspace;
powershell.Invoke(); // ERROR !!! The term 'Enable-Mailbox' is not recognized as the name of a cmdlet, function
return true;
}
catch(Exception ex) {
throw new Exception(ex.Message.ToString()); }
finally
{
// dispose the runspace and enable garbage collection
runspace.Dispose();
runspace = null;
// Finally dispose the powershell and set all variables to null to free
// up any resources.
powershell.Dispose();
powershell = null;
}
}
catch (Exception argex)
{
throw new ArgumentException(argex.Message.ToString());
}
}
}

How to run Import-PSSessions from .Net program

I am trying to write code in C# that get mailbox details from user via Power Shell command.
The power shell command script is:
Import-PSSession -session (New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri http://myServer.myDomain.com/Powershell)
Get-Mailbox -Identity helpdesk
The script runs OK from PowerShell.
Now my goal is to run it using C#.
This is my function:
private void button1_Click(object sender, EventArgs e)
{
m_RunSpace = RunspaceFactory.CreateRunspace();
m_RunSpace.Open();
Pipeline pipeLine = m_RunSpace.CreatePipeline();
Command newSession = new Command("New-PSSession");
newSession.Parameters.Add("-ConfigurationName", "Microsoft.Exchange");
newSession.Parameters.Add("-ConnectionUri", "http://myServer.myDomain.com/Powershell");
Command createSessionForExch = new Command("Import-PSSession");
createSessionForExch.Parameters.Add("-Session", newSession);
Command getMailbox = new Command("Get-Mailbox");
getMailbox.Parameters.Add("-Identity", "helpdesk");
pipeLine.Commands.Add(createSessionForExch);
pipeLine.Commands.Add(getMailbox);
Collection<PSObject> commandResults = pipeLine.Invoke();
foreach (PSObject cmdlet in commandResults)
{
}
}
But I receive an error that the "Get-Mailbox" command is not recognize:
Probably because the Import-PSSessions wasn't invok correctly.
I need help how to run the command Import-PSSession correctly from C#
Hope, you have found the solution. If not, please give this code a try:
String url = "http://" + ExchangeServerName + "/powershell?serializationLevel=Full";
System.Uri uri = new Uri(url);
Console.WriteLine(url);
System.Security.SecureString securePassword = String2SecureString(password);
System.Management.Automation.PSCredential creds = new System.Management.Automation.PSCredential(userName, securePassword);
Runspace runspace = System.Management.Automation.Runspaces.RunspaceFactory.CreateRunspace();
PowerShell powershell = PowerShell.Create();
PSCommand command = new PSCommand();
command.AddCommand("New-PSSession");
command.AddParameter("ConfigurationName", "Microsoft.Exchange");
command.AddParameter("ConnectionUri", uri);
command.AddParameter("Credential", creds);
command.AddParameter("Authentication", Authentication);
//PSSessionOption sessionOption = new PSSessionOption();
//sessionOption.SkipCACheck = true;
//sessionOption.SkipCNCheck = true;
//sessionOption.SkipRevocationCheck = true;
//command.AddParameter("SessionOption", sessionOption);
powershell.Commands = command;
try
{
runspace.Open();
powershell.Runspace = runspace;
Collection<PSSession> result = powershell.Invoke<PSSession>();
foreach (ErrorRecord current in powershell.Streams.Error)
Console.WriteLine("The following Error happen when opening the remote Runspace: " + current.Exception.ToString() +
" | InnerException: " + current.Exception.InnerException);
if (result.Count != 1)
throw new System.Exception("Unexpected number of Remote Runspace connections returned.");
// Set the runspace as a local variable on the runspace
powershell = PowerShell.Create();
command = new PSCommand();
command.AddCommand("Set-Variable");
command.AddParameter("Name", "ra");
command.AddParameter("Value", result[0]);
powershell.Commands = command;
powershell.Runspace = runspace;
powershell.Invoke();
// First import the cmdlets in the current runspace (using Import-PSSession)
powershell = PowerShell.Create();
command = new PSCommand();
//command.AddScript("Import-PSSession $ra");
command.AddScript("Invoke-Command -ScriptBlock { Get-Mailbox -Identity:" + MailBoxName + " } -Session $ra");
powershell.Commands = command;
powershell.Runspace = runspace;
//powershell.Commands.AddCommand("Import-Module").AddArgument("activedirectory");
powershell.Invoke();
//command = new PSCommand();
//command.AddCommand("Get-Mailbox");
////Change the name of the database
//command.AddParameter("Identity", "");
//powershell.Commands = command;
//powershell.Runspace = runspace;
Collection<PSObject> results = new Collection<PSObject>();
results = powershell.Invoke();
Full an interesting tutorial about : Access Exchange Online by PowerShell in C#
Get-Mailbox example in step 3.
Use WSManConnectionInfo class to supply the uri,schema to open the remote runspace.Please find the code :
private static string CreateConnection()
{
Runspace remoteRunspace = null;
openRunspace(
"https://pod51057psh.outlook.com/powershell-liveid?PSVersion=3.0",
"http://schemas.microsoft.com/powershell/Microsoft.Exchange",
#"xxx#xxx.com",
"xxxxx",
ref remoteRunspace
);
// Command getLicenseCommand = new Command("Get-MsolAccountSku");
//Command activityCommand = new Command("Get-GroupActivityReport");
//activityCommand.Parameters.Add(new CommandParameter("ReportType", "Daily"));
//activityCommand.Parameters.Add(new CommandParameter("StartDate", "03/4/2014"));
//activityCommand.Parameters.Add(new CommandParameter("EndDate", "03/27/2014"));
Command activityCommand = new Command("Get-Mailbox");
activityCommand.Parameters.Add("-Identity", "xxx");
StringBuilder stringBuilder = new StringBuilder();
using (PowerShell powershell = PowerShell.Create())
{
powershell.Runspace = remoteRunspace;
powershell.Commands.AddCommand(activityCommand);
powershell.Invoke();
var results = powershell.Invoke();
remoteRunspace.Close();
foreach (PSObject obj in results)
{
stringBuilder.AppendLine(obj.ToString());
}
}
remoteRunspace.Close();
return stringBuilder.ToString();
}
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.Basic;
remoteRunspace = RunspaceFactory.CreateRunspace(rri);
remoteRunspace.Open();
}

How I can create a User in AD with Powershell in a ASP.NET Webapplication

I have a question to C# and Powershell in a ASP.NET Application.
I want to create a User in our Active Directory and I want/must use a powershell for this. I had built a Webapllication that could add a mailcontact in the Exchange Server one year ago. For this I used the System.Management.Automation Namespace with the Powershell Classes. But I don't know how I can do it for the Active Directory.
the ps command that I must use:
New-ADUser %prefix-%name
-SamAccountName "%name"
-UserPrincipalName "%name#test-company.com"
-GivenName "%text1"
-SurName "%text2"
-displayname "%name"
-enabled $true
-Path '%OU'
-AllowReversiblePasswordEncryption $true
-PasswordNeverExpires $true
-AccountPassword (ConvertTo-Securestring "%name" -asplaintext -Force)
and here my cs code:
public void CreateRemoteConnectionToActiveDirectory(string Username, string password//,...comming)
{
SecureString securePassword = new SecureString();
str_password = password;
str_username = Username;
foreach (char x in str_password)
{
securePassword.AppendChar(x);
}
PSCredential cred = new PSCredential(str_username, securePassword);
// connection?
}
My Old Code for the exchange Server:
public string CreateRemoteConnectionToExchange(string UserName, string Password, string Mailbox)
{
SecureString SecurePassword = new SecureString();
string str_password = Password;
string str_username = UserName;
foreach (char x in str_password)
{
SecurePassword.AppendChar(x);
}
PSCredential cred = new PSCredential(str_username, SecurePassword);
WSManConnectionInfo connectionInfo = new WSManConnectionInfo(new Uri(ExchangeServer), Schema, cred);
connectionInfo.AuthenticationMechanism = AuthenticationMechanism.Default;
Runspace runspace = RunspaceFactory.CreateRunspace(connectionInfo);
PowerShell powershell = PowerShell.Create();
PSCommand command = new PSCommand();
command.AddCommand("New-MailContact");
command.AddParameter("ExternalEmailAddress", "SMTP:" + Mailbox + MailExtension);
command.AddParameter("Name", Mailbox);
command.AddParameter("Alias", Mailbox);
command.AddParameter("FirstName", Mailbox);
command.AddParameter("Initials", "");
command.AddParameter("LastName", "");
command.AddParameter("OrganizationalUnit", OrganizationalUnit);
command.AddParameter("DomainController", configDC);
powershell.Commands = command;
try
{
runspace.Open();
powershell.Runspace = runspace;
powershell.Invoke();
return "Der Kontakt wurde Erfolgreich erstellt";
}
catch (Exception ex)
{
///...
}
finally
{
runspace.Dispose();
runspace = null;
powershell.Dispose();
powershell = null;
}
}
How I can do this. A Example,tutorial or a tipp would me help.
Looks like your connection just needs to connect to either your AD server or another server that can actually execute the command.

Powershell and exchange in C#

I have the following code in C# that I use to connect to exchange through powershell.
The following code works fine, however there is one more command that I need in order to use the exchange cmdlets.
Here is the code I have now.
Runspace runspace = System.Management.Automation.Runspaces.RunspaceFactory.CreateRunspace();
PowerShell powershell = PowerShell.Create();
PSCommand command = new PSCommand();
command.AddCommand("New-PSSession");
command.AddParameter("ConfigurationName", "Microsoft.Exchange");
command.AddParameter("ConnectionUri", new Uri("https://ps.outlook.com/powershell/"));
command.AddParameter("Credential", creds);
command.AddParameter("Authentication", "Basic");
command.AddParameter("AllowRedirection");
powershell.Commands = command;
try
{
runspace.Open();
powershell.Runspace = runspace;
Collection<PSObject> commandResults = powershell.Invoke();
StringBuilder sb = new StringBuilder();
foreach (PSObject ps in commandResults)
{
sb.AppendLine(ps.ToString());
}
sb.AppendLine();
lbl.Text += sb.ToString();
}
finally
{
// dispose the runspace and enable garbage collection
runspace.Dispose();
runspace = null;
// Finally dispose the powershell and set all variables to null to free
// up any resources.
powershell.Dispose();
powershell = null;
}
My problem is that I still need to run the command import-pssession $session where $session is the output of my first command. However I am not sure how I can declare that output as the variable $session or something like:
PSCommand command = new PSCommand();
command.AddCommand("Import-PSSession");
command.AddParameter("Session", #Not sure how to put session info which is what the first command produces into here.);
You can try using creating a Remote Runspace instead, an example is given below. You can reference the following article http://msdn.microsoft.com/en-us/library/windows/desktop/ee706560(v=vs.85).aspx.
string schemaURI = "http://schemas.microsoft.com/powershell/Microsoft.Exchange";
Uri connectTo = new Uri("https://ps.outlook.com/powershell/");
PSCredential credential = new PSCredential(user,secureStringPassword ); // the password must be of type SecureString
WSManConnectionInfo connectionInfo = new WSManConnectionInfo(connectTo,schemaURI, credential);
connectionInfo.MaximumConnectionRedirectionCount = 5;
connectionInfo.AuthenticationMechanism = AuthenticationMechanism.Basic;
try
{
Runspace remoteRunspace = RunspaceFactory.CreateRunspace(connectionInfo);
remoteRunspace.Open();
}
catch(Exception e)
{
//Handle error
}
try the section "Remote Request using a local run space (Scripting the remote class)" in the following technet blog
http://blogs.technet.com/b/exchange/archive/2009/11/02/3408653.aspx
I believe what you are trying to achieve is:
// Set the runspace as a local variable on the runspace
powershell = PowerShell.Create();
command = new PSCommand();
command.AddCommand("Set-Variable");
command.AddParameter("Name", "ra");
command.AddParameter("Value", result[0]);
powershell.Commands = command;
powershell.Runspace = runspace;
powershell.Invoke();
Where result[0] is the result of the first remote session created. Let me know if that helps.

Categories