Using C# To Return Data From PowerShell - c#

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.

Related

Can not execute Powershell Script in .Net MVC Application

I have a .Net MVC application which need to check and get some information from another server via powershell command with code shown below. But app can not get information
try
{
string un = #"domainA\domainUserName";
System.Security.SecureString pw = new System.Security.SecureString();
string password = "";
string exchangeServerName = "ServerAdress/powershell";
foreach (char ch in password)
{
pw.AppendChar(ch);
}
using (PowerShell _powerShell = PowerShell.Create())
{
var credential = new PSCredential(un, pw);
_powerShell.Runspace.SessionStateProxy.SetVariable("Credential", credential);
_powerShell.AddScript($"$Session = New-PSSession –ConfigurationName Microsoft.Exchange -ConnectionUri {exchangeServerName} -Credential $Credential -Authentication Kerberos -AllowRedirection");
_powerShell.AddScript("Import-PSSession $Session");
_powerShell.Invoke();
_powerShell.AddScript(#"get-mailbox -identity " + mail + " | Select-Object ProhibitSendReceiveQuota");
var results = _powerShell.Invoke();
string size = "";
string used = "";
string size2 = "";
foreach (PSObject obj in results)
{
size = (obj.Properties["ProhibitSendReceiveQuota"].Value.ToString());
}
_powerShell.AddScript(#"Get-MailboxStatistics -Identity " + mail + " | Select-Object Totalitemsize,DatabaseProhibitSendQuota");
var results2 = _powerShell.Invoke();
_powerShell.AddScript("Remove-PSSession $Session");
_powerShell.Invoke();
//
}
}
Target server and source server are in different domains.
In local running app wroks perfectly. What can be cause this issue and how can I resolve issue.
Thank you.

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.

Some of the PowerShell module (Cluster cmdlets) does not get loaded when I create RunSpace on a localhost without providing runspaceconnectioninfo

Please refer the sample below:
RunspaceSample(string.Empty); fails with The term 'Add-VMToCluster' is not recognized as the name of a cmdlet.
Whereas the RunspaceSample("localhost") or RunspaceSample("somecomputerName") succeed. Any pointer why is it ? Does including RunspaceConnectionInfo changes the powershell version used or RunspaceConfiguration used for execution ?
Also what would be the performance impact if I create Runspace with RunSpaceConnectionInfo with ComputerName = "localhost" even for executing powershell script on a local computer ?.
Thanks
public static void RunspaceSample(string computerName)
{
Runspace rs;
if (string.IsNullOrEmpty(computerName))
{
rs = RunspaceFactory.CreateRunspace();
}
else
{
var connectionInfo = new WSManConnectionInfo
{
OperationTimeout = 10000,
OpenTimeout = 10000,
ComputerName = computerName
};
rs = RunspaceFactory.CreateRunspace(connectionInfo);
}
rs.Open();
PowerShell ps = PowerShell.Create();
ps.Runspace = rs;
string script = #"$ComputerName = 'somevm'; $null = Add-VMToCluster -Name $ComputerName -VMName $ComputerName -ErrorAction SilentlyContinue -verbose";
ps.AddScript(script);
Console.WriteLine("Script: {0}", script);
Console.WriteLine("------------------------");
foreach (PSObject result in ps.Invoke())
{
Console.WriteLine(result.ToString());
}
if (ps.HadErrors)
{
var sb = new StringBuilder();
foreach (var errorRecord in ps.Streams.Error)
{
sb.AppendFormat("\nError: {0} CategoryInfo: {1}", errorRecord.Exception.Message, (errorRecord.CategoryInfo != null) ? errorRecord.CategoryInfo.ToString() : string.Empty);
}
var errorMessage = sb.ToString();
Console.WriteLine(errorMessage);
}
}
The FailoverClusters module is only available in 64-bit PowerShell sessions. Making this assembly as 64 bit assembly resolved the module not found issue.

Error message when running a c# powershell code

When I run the code below I get the following error at Response.Write( result.Properties["name"].Value);. "use the 'new' keyword to create and object instance."
I can't figure out how to fix this problem.
String sEmailAddress;
String sPassword;
sEmailAddress = Request.QueryString["value1"];
sPassword = Request.QueryString["value2"];
lbl1.Text = sEmailAddress + " " + sPassword;
SecureString sSecurePW = new SecureString();
foreach (char c in sPassword.ToCharArray())
sSecurePW.AppendChar(c);
PSCredential Credential = new PSCredential(sEmailAddress, sSecurePW);
PowerShell powershell = PowerShell.Create();
powershell.Runspace.SessionStateProxy.SetVariable("cred", Credential);
powershell.AddScript("$s = New-PSSession -ComputerName ExchDC01 -Credential $cred -Authentication Kerberos");
powershell.AddScript("invoke-command -session $s -scriptblock {Get-ADOrganizationalUnit -LDAPFilter '(name=*)' -SearchBase 'OU=TENANTS,DC=lab,DC=local' -SearchScope OneLevel | ft Name}");
// Collection<PSObject> results = powershell.Invoke();
foreach (PSObject result in powershell.Invoke())
{
Response.Write(result.Properties["name"].Value); //<-- Error:use the 'new' keyword to create and object instance.
}
}
Thanks in advance

Categories

Resources