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?
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.
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.