Powershell and exchange in C# - 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.

Related

Exception occured when call cmldet powershell c# create New-mailBox

trying to execute cmdlet exchange powershell new-mailBox failed in c# - remote access on exchange 2016 server
Add user account to the different group for access right execution
string connectionUri = "http://xxx.contosoe.com/powershell/";
string loginPassword = "password";
SecureString secpassword = new SecureString();
foreach (char c in loginPassword)
{
secpassword.AppendChar(c);
}
PSCredential credential = new PSCredential(#"doamin\user", secpassword);
Runspace runspace = RunspaceFactory.CreateRunspace(rsConfig);
PowerShell powershell = PowerShell.Create();
powershell.Commands.AddCommand("Import-Module").AddArgument("ActiveDirectory");
//
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", "KerBeros");
powershell.Commands = command;
runspace.Open();
powershell.Runspace = runspace;
Collection<PSObject> 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("Set-Variable");
command.AddParameter("Name", "ra");
command.AddParameter("Value", result[0]);
powershell.Commands = command;
powershell.Runspace = runspace;
powershell.Invoke();
powershell = PowerShell.Create();
command = new PSCommand();
command.AddScript("Import-PSSession -Session $ra");
powershell.Commands = command;
powershell.Runspace = runspace;
powershell.Invoke();
Pipeline pipeLine = runspace.CreatePipeline();
var emailCreateCommand = CreateEmailCommand("name", "displayName", "alias");
pipeLine.Commands.Add(emailCreateCommand);
Collection<PSObject> result_ = pipeLine.Invoke();
stack trace....
System.TypeInitializationException: The type initializer for 'Microsoft.Exchange.Management.Common.NewUserBase'. --->
System.UnauthorizedAccessException: Access to the registry key 'Global' is denied.
Microsoft.Win32.RegistryKey.Win32Error(Int32 errorCode, String str)
Microsoft.Win32.RegistryKey.InternalGetValue(String name, Object defaultValue, Boolean doNotExpand, Boolean checkSecurity)
Microsoft.Win32.RegistryKey.GetValue(String name)
System.Diagnostics.PerformanceMonitor.GetData(String item)
System.Diagnostics.PerformanceCounterLib.GetPerformanceData(String item)
System.Diagnostics.PerformanceCounterLib.get_CategoryTable()
System.Diagnostics.PerformanceCounterLib.CategoryExists(String machine, String category)
System.Diagnostics.PerformanceCounterCategory.Exists(String categoryName, String machineName)
Microsoft.Exchange.Management.Common.NewUserBase..cctor()
Microsoft.Exchange.Management.Common.NewUserBase.InternalBeginProcessing()
Microsoft.Exchange.Management.RecipientTasks.NewMailboxBase.InternalBeginProcessing()
Microsoft.Exchange.Management.RecipientTasks.NewMailboxOrSyncMailbox.InternalBeginProcessing()
Microsoft.Exchange.Configuration.Tasks.Task.<BeginProcessing>b__83_1()
Microsoft.Exchange.Configuration.Tasks.Task.InvokeRetryableFunc(String funcName, Action func, Boolean terminatePipelineIfFailed)

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

Invoke Powershell command from C# with different credential

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

Execute Powershell command (get-user -Identity "John Doe" | FL) in C#

I'm trying to execute _Get-User -Identity "John Doe" | FL_ command within the following C# code.
PowerShell powershell = PowerShell.Create();
powershell.AddCommand("get-user");
powershell.AddParameter("Identity", UserName.Text);
try
{
runspace.Open();
powershell.Runspace = runspace;
Collection<PSObject> results = powershell.Invoke();
var builder = new StringBuilder();
foreach (var psObject in results)
{
builder.AppendLine(psObject.ToString() + "\r\n");
}
ResultBox.Text = Server.HtmlEncode(builder.ToString());
}
Where do I add the _FL_ command?
When you add each command, it gets added to the pipeline. So if you want to do format-list, you can add that to the pipeline:
powershell.AddCommand("get-user");
powershell.AddParameter("Identity", UserName.Text);
powershell.AddCommand("format-list");'
//powershell.AddCommand("out-string");
But I am not sure what you want to do, as something like that can be done in C# using results
I have searched a lot. You can change regular powershell script instead of "WriteWhatYouWantToDo".
Runspace runspace = RunspaceFactory.CreateRunspace();
runspace.Open();
RunspaceInvoke invo = new RunspaceInvoke(runspace);
invo.Invoke("Set-ExecutionPolicy Unrestricted");
Pipeline pipeline = runspace.CreatePipeline();
Command command = new Command("get-module -listAvailable | import-module\n" + WriteWhatYouWantToDo);
pipeline.Commands.Add(command);
pipeline.Commands.Add("Out-String");
try
{
Collection<PSObject> results = pipeline.Invoke();
runspace.Close();
StringBuilder stringBuilder = new StringBuilder();
foreach (PSObject obj in results)
{
stringBuilder.AppendLine(obj.ToString());
}
string result1 = stringBuilder.ToString();
string result = result1.Substring(0, 250); //define global scope
}
catch (Exception ex)
{
}

Categories