I am trying to write a C# console app which will set the out of office replies for users on Office 365. Let's say that I have an account alice@domain.com
with global admin privileges on O365 trying to set the OOF reply for a non-admin bob@domain.com
.
I can successfully get and set the OOF for Bob using Powershell, with the following commands:
$UserCredential = Get-Credential #Sign in as Alice
$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://outlook.office365.com/powershell-liveid/ -Credential $UserCredential -Authentication Basic -AllowRedirection
Import-PSSession $Session
Get-MailboxAutoReplyConfiguration -Identity bob@domain.com
Set-MailboxAutoReplyConfiguration -Identity bob@domain.com -AutoReplyState Enabled -InternalMessage "I'm out of office"
So I've tried to do a similar thing in my C# app with the following code:
SecureString password = ...
var service = new ExchangeService
{
Credentials = new NetworkCredential("alice@domain.com", password),
Url = new Uri("https://outlook.office365.com/EWS/Exchange.asmx")
};
var settings = service.GetUserOofSettings("bob@domain.com");
...
service.SetUserOofSettings("bob@domain.com", newSettings)
However, for both the get and the set I just end up with a Microsoft.Exchange.WebServices.Data.ServiceResponseException
with the message 'Access is denied. Check credentials and try again., The process failed to get the correct properties.'
. Also note that I can successfully get and set Alice's OOF with this method, just not Bob's. Does anyone know why I would have permission to do this with Powershell but not with C#, and how I could go about fixing this?
I have also tried setting the ImpersonatedUserId
field of the service, but then I get the error message 'The account does not have permission to impersonate the requested user.'
, and I don't really want to have to enable Alice to impersonate every user whose OOF I need to set.
It needs to work in C# because I am doing a lot of other stuff in my app which wouldn't be easy to write up in a Powershell script. The only other thing I can think of is to just use my C# code to directly send Powershell commands, as detailed in this post, but that seems a bit long-winded and error-prone.
When your using the Exchange Management Shell cmdlets Set-MailboxAutoReplyConfiguration you can take advantage of the Delegation provided through RBAC. EWS however is a User Mailbox API and RBAC rights have no meaning so being a Global Admin (or any sort of admin) will mean nothing to this API. This is the same for MAPI, ActiveSync.
To be able to set the OOF setting via EWS you will need to grant Full Mailbox Access to the Target Mailbox via Add-MailboxPermission. However a better alternative is just use the EMS cmdlets from C# eg
String UserName = "username@om";
String Password = "dd@#";
System.Security.SecureString secureString = new System.Security.SecureString();
foreach (char c in Password)
secureString.AppendChar(c);
PSCredential credential = new PSCredential(UserName, secureString);
WSManConnectionInfo connectionInfo = new WSManConnectionInfo(new Uri("https://outlook.office365.com/powershell"), "http://schemas.microsoft.com/powershell/Microsoft.Exchange", credential);
connectionInfo.AuthenticationMechanism = AuthenticationMechanism.Basic;
connectionInfo.SkipCACheck = true;
connectionInfo.SkipCNCheck = true;
connectionInfo.MaximumConnectionRedirectionCount = 4;
Runspace runspace = System.Management.Automation.Runspaces.RunspaceFactory.CreateRunspace(connectionInfo);
runspace.Open();
// Make a Get-Mailbox requst using the Server Argument
Command gmGetMailbox = new Command("Get-MailboxAutoReplyConfiguration");
gmGetMailbox.Parameters.Add("Identity", "jcool@datarumble.com");
Pipeline plPileLine = runspace.CreatePipeline();
plPileLine.Commands.Add(gmGetMailbox);
Collection<PSObject> RsResultsresults = plPileLine.Invoke();
foreach (PSObject obj in RsResultsresults)
{
Console.WriteLine(obj.Members["AutoReplyState"].Value.ToString());
}
plPileLine.Stop();
plPileLine.Dispose();