powershellazure-web-app-serviceexchange-online

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.


Solution

  • 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:

    
        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.