Peter Bennett
Peter Bennett

Reputation: 13

Is it possible to have C# invoke ExchangeOnlineManagement PowerShell Cmdlets in an Azure App Service? If so how?

I have a custom C# Restful API that includes Microsoft Graph Nuget package, and PowerShell SDK Nuget Package, etc. I want to host this in Azure somehow, preferably an App Service. The C# application invokes powershell ExchangeOnlineManagement, works fine on my laptop, because I ran elevated powershell as an administrator and installed the ExchangeOnlineManagement module for all users.

In the Azure App Service, I opened Kudu console, however I can't find a way to run it elevated as an administrator. I have an App Registration which has the permissions granted to use Exchange/Office and Graph, and I have a certificate loaded. The C# API is running as a System Managed Identity and uses a certificate to connect to Exchange and Graph. So I would need to run Kudu console as the System Managed Identity, then run Install-Module -Name ExchangeOnlineManagement -Scope CurrentUser. How do I run Kudu as the managed identity? Or how do I run Kudu as an Administrator?

I saw an article which has a reply from a Microsoft Employee about using a Requirements.txt file to install packages into an azure app service, that's for Python though. Is there something like that but for PowerShell cmdlets?

As a last resort I could consider docker/kubernetes, or using Azure Function Apps for the PowerShell stuff.

I do have ExchangeOnlineManagement installed on my laptop, can I copy the files onto the App Service or package it to run from a zip file or something?

Could the C# application run the Install-Module -Name ExchangeOnlineManagement -Scope CurrentUser, since it would already be running as the managed identity, and would that persist after restarts?

Can I use an ARM template to install the ExchangeOnlineManagement PowerShell Cmdlets into the App Service?

References https://learn.microsoft.com/en-us/answers/questions/1266111/install-powershell-module-in-azure-app-service

https://learn.microsoft.com/en-us/answers/questions/1350300/how-to-update-the-powershell-version-in-azure-app

I tried researching for a way to run Kudu Console elevated as an administrator, and explored all the menus, with no luck. I don't know how to login to the Azure Portal as the system managed identity and run Kudu Console for the App Service as the managed identity. I also tried researching other ways to install powershell modules into an app service, also looked at using something else besides an app service.

Upvotes: 1

Views: 353

Answers (1)

Agyss
Agyss

Reputation: 562

I ended up doing exactly this in an app service by storing the powershell module next to the code and shipping it with the binary. As this was the only way I got it working, it seems to be the nicest possible approach.

So what I did:

  • I downloaded the nuget package from here
  • Placed it in a subfolder in the project
  • in the C# Code I did:

    InitialSessionState iss = InitialSessionState.CreateDefault();
    var exchangeOnlinePowershellModulePath = System.IO.Path.Combine(AppContext.BaseDirectory,     $"Resources\\ExchangeOnlinePowershellModule\\ExchangeOnlineManagement.psd1");

    iss.ImportPSModule(new string[] { exchangeOnlinePowershellModulePath });
    iss.ExecutionPolicy = Microsoft.PowerShell.ExecutionPolicy.RemoteSigned;
    iss.ThrowOnRunspaceOpenError = true;

    Runspace runspace = RunspaceFactory.CreateRunspace(iss);
    runspace.Open();

    // Run the Connect-ExchangeOnline command in the runspace to create a connection with EXO.
    PowerShell ps = PowerShell.Create(runspace);
    ps.AddCommand("Connect-ExchangeOnline");
    ps.AddParameters(new Dictionary<string, object>
    {
        ["Organization"] = "contoso.onmicrosoft.com",
        ["CertificateFilePath"] = "C:\\Users\\Certificates\\mycert.pfx",
        ["CertificatePassword"] = GetPassword(),
        ["AppID"] = "a37927a4-1a1a-4162-aa29-e346d5324590"
    });
    Collection<PSObject> connectionResult = ps.Invoke();
    // Clear the connection commands before running cmdlets.
    ps.Commands.Clear();
    // Create a new command to execute an Exchange Online cmdlet.
    ps.AddCommand("Get-Mailbox");
    ps.AddParameter("Identity", "ContosoUser1");

The code above is a slight adaptation of microsofts original post here.

Upvotes: 0

Related Questions