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
Related
I am trying to connect with office365 PowerShell. I had also imported the module "ExchangeOnlineManagement". I'm getting the below exception:
"The term Connect-ExchangeOnline is not recognized as cmdlet, function , script or operable problem".
string script = #"
Set-ExecutionPolicy Unrestricted
$user = '<your username>'
$pwd = '<your password>'
$SecurePass = ConvertTo-SecureString -AsPlainText $pwd -Force
$Cred = New-Object System.Management.Automation.PSCredential -ArgumentList $user,$SecurePass
Import-Module -Name ExchangeOnlineManagement
Connect-ExchangeOnline -Credential $Cred
";
try
{
using (Runspace runspace = RunspaceFactory.CreateRunspace())
{
runspace.Open();
Pipeline pipe = runspace.CreatePipeline();
pipe.Commands.AddScript(script);
try
{
var results = pipe.Invoke();
}
catch (Exception e)
{
}
var error = pipe.Error.ReadToEnd();
if (error.Count > 0)
{
foreach (PSObject err in error)
{
//more logging not sharing that code
}
}
}
}
catch (Exception ex)
{ }
I connect to Exchange Online via C# and can run a Get-Mailbox command without problem. But when I try
Get-Mailbox | Where LitigationHoldEnabled -eq $true
I get an error
The term 'where.exe' 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.
The command runs just fine in PowerShell.
What am I missing?
PSCredential credential = new PSCredential("xxxxx#yyyyyyyy.de", secpassword);
string connectionUri = "https://outlook.office365.com/powershell-liveid/";
Runspace runspace = System.Management.Automation.Runspaces.RunspaceFactory.CreateRunspace( );
PowerShell powershell = PowerShell.Create();
PSCommand command = new PSCommand();
command.AddCommand("New-PSSession");
command.AddParameter("ConnectionUri", new Uri(connectionUri));
command.AddParameter("ConfigurationName", "Microsoft.Exchange");
command.AddParameter("Credential", credential);
command.AddParameter("Authentication", "Basic");
command.AddParameter("AllowRedirection", true);
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)
{
powershell.Dispose();
runspace.Dispose();
}
command = new PSCommand();
command.AddCommand("Invoke-Command");
command.AddParameter("ScriptBlock", System.Management.Automation.ScriptBlock.Create("Get-Mailbox | Where-Object LitigationHoldEnabled - eq $true"));
command.AddParameter("Session", result[0]);
powershell.Commands = command;
var Searches = powershell.Invoke();
....
powershell.Dispose();
runspace.Dispose();
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.
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.
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();