Automate some Exchange Online functions

Viewed 45

Having that Exchange Online functions are not yet included in MS Graph, and Exchange does not have its own SDK also, the only option I found to automate some functions in Exchange Online is ExchangeOnlineManagement PowerShell.

I used it for a while but Microsoft recently ceased the Basic Authentication. I'm using the Basic Authentication because it does not require any prior package installation.

The modern authentication use Connect-ExchangeOnline and requires the ExchangeOnlineManagement to be installed prior to any call. It's easy to install it on a physical server or a VM, but I'm relying on Azure services, like azure Web app, azure Function app, where I cannot install a package. now the situation is:

  1. Basic authentication stopped working, and it's not an option anymore. This was the only option to execute exchange PowerShell commands from azure web app or function app.
  2. In modern authentication, you rely on the ExchangeOnlineManagement that must be installed prior to any call. since I work on web app, or function app, I cannot install it.
  3. there is no .net Exchange SDK.
  4. MS Graph lack Exchange functions.

So what is the valid solution to execute Exchange command? Maybe the solution is available but I'm not aware of it.

My case is simple: Every night, Upon the expiration of an Azure user account:

  • I change some user properties on Azure (Available through MS Graph)
  • I need to set an auto reply message, so sender can know the email account is no longer monitored. (NOT AVAILABLE)
1 Answers

You can use BasicAuthToOAuthConversion=true in the connection string and if for example you currently have user creds being passed in switch to using the ROPC flow with those creds and just pass the username and accesstoken where you passing the users password eg

PSCredential pSCredential = new PSCredential("user@blah.onmicrosoft.com", new NetworkCredential("", "pass##").SecurePassword);
string MailboxName = pSCredential.UserName;
string scope = "https://outlook.office365.com/.default";
string ClientId = "a0c73c16-a7e3-4564-9a95-2bdf47383716";

HttpClient Client = new HttpClient();
var TenantId = ((dynamic)JsonConvert.DeserializeObject(Client.GetAsync("https://login.microsoftonline.com/" + MailboxName.Split('@')[1] + "/v2.0/.well-known/openid-configuration").Result.Content.ReadAsStringAsync().Result)).authorization_endpoint.ToString().Split('/')[3];

PublicClientApplicationBuilder pcaConfig = PublicClientApplicationBuilder.Create(ClientId);
pcaConfig.WithTenantId(TenantId);
var TokenResult = pcaConfig.Build().AcquireTokenByUsernamePassword(new[] { scope }, pSCredential.UserName, pSCredential.Password).ExecuteAsync().Result;

System.Security.SecureString secureString = new System.Security.SecureString();

foreach (char c in ("bearer " + TokenResult.AccessToken))
    secureString.AppendChar(c);
String WSManURIConnectionString = "https://outlook.office365.com/powershell-liveid?DelegatedOrg=" + MailboxName.Split('@')[1] + "&BasicAuthToOAuthConversion=true";
PSCredential credential = new PSCredential(MailboxName, secureString);
WSManConnectionInfo connectionInfo = new WSManConnectionInfo(new Uri(WSManURIConnectionString), "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-mailbox");
gmGetMailbox.Parameters.Add("ResultSize", "Unlimited");
Pipeline plPileLine = runspace.CreatePipeline();
plPileLine.Commands.Add(gmGetMailbox);
Collection<PSObject> RsResultsresults = plPileLine.Invoke();
Dictionary<string, PSObject> gmResults = new Dictionary<string, PSObject>();
foreach (PSObject obj in RsResultsresults)
{
    Console.WriteLine(obj.Members["WindowsEmailAddress"].Value.ToString());
}
Command gmGetUser = new Command("get-user");
plPileLine.Stop();
plPileLine.Dispose();

Related