Earvin Nill Castillo
Earvin Nill Castillo

Reputation: 70

The module 'Microsoft.PowerShell.Utility' could not be loaded. For more information, run 'Import-Module Microsoft.PowerShell.Utility'

I have a working console application in local that runs exchangeonline using CertificateThumbprint, AppID, & Organization as Credentials. The problem is when converted on function app and run locally, i received an error when importing the exchangeonline module:

[2024-10-07T03:46:44.417Z] Error during Import-Module: The module 'Microsoft.PowerShell.Utility' could not be loaded. For more information, run 'Import-Module Microsoft.PowerShell.Utility'.

I've tried searching on the browser for fix but no solutions most of the queries.

Here is my function for connecting exchange online:

public static Task GetUserMailbox(string appId, string certificatePath, string certificatePassword, string organization, string userPrincipalName, ILogger log)
{
    try
    {
        // Set TLS protocol to 1.2
        System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls12;

        // Optionally bypass SSL certificate validation (not recommended for production)
        System.Net.ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };

        // Load the certificate from the file using the password
        var certificate = new X509Certificate2(certificatePath, certificatePassword);

        var iss = InitialSessionState.CreateDefault2();
        iss.ExecutionPolicy = Microsoft.PowerShell.ExecutionPolicy.Bypass;

        using (Runspace remoteRunspace = RunspaceFactory.CreateRunspace(iss))
        {
            remoteRunspace.Open(); // Ensure the Runspace is opened

            using (PowerShell powershell = PowerShell.Create())
            {
                powershell.Runspace = remoteRunspace;

               

                // Import the Exchange Online module
                powershell.AddCommand("Import-Module")
                    .AddArgument("ExchangeOnlineManagement")
                    .Invoke();

                // Check for errors in Import-Module
                if (powershell.HadErrors)
                {
                    foreach (var error in powershell.Streams.Error)
                    {
                        log.LogError($"Error during Import-Module: {error}");
                    }
                    return Task.CompletedTask; // Stop further execution if the module import fails
                }
                log.LogInformation("Successfully imported ExchangeOnlineManagement module.");

                // Clear the previous command
                powershell.Commands.Clear();

                // Connect to Exchange Online
                powershell.AddCommand("Connect-ExchangeOnline")
                    .AddParameter("AppId", appId)
                    .AddParameter("CertificateThumbprint", certificate.Thumbprint)
                    .AddParameter("Organization", organization)
                    .AddParameter("ShowBanner", false);
                powershell.Invoke();

                // Check for errors in Connect-ExchangeOnline
                if (powershell.HadErrors)
                {
                    foreach (var error in powershell.Streams.Error)
                    {
                        log.LogError($"Error during Connect-ExchangeOnline: {error}");
                    }
                    return Task.CompletedTask; // Stop further execution if connection fails
                }
                log.LogInformation("Successfully connected to Exchange Online.");

                // Get user mailbox details using Get-CASMailbox and Select-Object
                powershell.Commands.Clear();
                powershell.AddCommand("Get-CASMailbox")
                    .AddParameter("Identity", userPrincipalName)
                    .AddCommand("Select-Object")
                    .AddParameter("Property", new string[] { "DisplayName", "UserPrincipalName", "ForwardingSmtpAddress", "OWAEnabled" });
                var mailboxResults = powershell.Invoke();

                // Check for errors in Get-CASMailbox
                if (powershell.HadErrors)
                {
                    foreach (var error in powershell.Streams.Error)
                    {
                        log.LogError($"Error during Get-CASMailbox: {error}");
                    }
                    return Task.CompletedTask; // Stop if mailbox retrieval fails
                }

                // Display results
                if (mailboxResults != null && mailboxResults.Count > 0)
                {
                    foreach (var result in mailboxResults)
                    {
                        log.LogInformation(result.ToString()); // Safely convert PSObject to string
                    }
                }
                else
                {
                    log.LogInformation("No mailbox found or no results returned.");
                }

                // Disconnect from Exchange Online
                powershell.Commands.Clear();
                powershell.AddCommand("Disconnect-ExchangeOnline")
                    .AddParameter("Confirm", false);
                powershell.Invoke();

                // Check for errors in Disconnect-ExchangeOnline
                if (powershell.HadErrors)
                {
                    foreach (var error in powershell.Streams.Error)
                    {
                        log.LogError($"Error during Disconnect-ExchangeOnline: {error}");
                    }
                }
                else
                {
                    log.LogInformation("Successfully disconnected from Exchange Online.");
                }
            }
        }
    }
}

Error Starts on importing module.

EDIT: Added importing powershell utiliy and this error comes:

Exception: Cannot find the built-in module 'Microsoft.PowerShell.Utility' that is compatible with the 'Core' edition. Please make sure the PowerShell built-in modules are available. They usually come with the PowerShell package under the $PSHOME module path, and are required for PowerShell to function properly.

Im using sdk 7.4.5

Upvotes: -1

Views: 316

Answers (1)

RithwikBojja
RithwikBojja

Reputation: 11393

As an alternative you can use System.Management.Automation module and code:

Function.cs:

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.Logging;
using System.Management.Automation.Runspaces;
using System.Management.Automation;

namespace FunctionApp232
{
    public class Function1
    {
        private readonly ILogger<Function1> ri_lg;

        public Function1(ILogger<Function1> logger)
        {
            ri_lg = logger;
        }

        [Function("Function1")]
        public IActionResult Run([HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequest req)
        {
            ri_lg.LogInformation("Hello Rithwik Bojja, The function started execution");
            var rith = InitialSessionState.CreateDefault2();
            rith.ExecutionPolicy = Microsoft.PowerShell.ExecutionPolicy.Unrestricted;

            using var cho_ps = PowerShell.Create(rith);
            var rith_out = cho_ps.AddScript(@"

            Install-PackageProvider -Name Nuget -Scope CurrentUser –Force
            Install-Module –Name PowerShellGet -Scope CurrentUser –Force
            Install-Module -Name Az -Scope CurrentUser -Repository PSGallery -Force
            Install-Module -Name Az.Resources -AllowClobber -Scope CurrentUser

            Import-Module 'Az'
            Import-Module 'Az.Accounts'
            try{
            $rith_clnt_id = 828a057
            $rith_clnt_scret = XyG86cVj
            $rith_tnt_Id = 9329c02a-4f6d
            $pwd = ConvertTo-SecureString $rith_clnt_scret -AsPlainText -Force
            $rith = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $rith_clnt_id, $pwd
            Connect-AzAccount -ServicePrincipal -Credential $rith -Tenant $rith_tnt_Id
            New-AzResourceGroup -Name 'rithwik_test_rg' -Location 'West US 2'
                }
            catch {
             Write-Host 'Not created'
             }

            ").Invoke();
            Console.WriteLine(rith_out);    
            return new OkObjectResult("Welcome to Azure Functions!");
        }
    }
}

I have used Service principal, you can use thumbprint or any other way login way.

csproj:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <AzureFunctionsVersion>v4</AzureFunctionsVersion>
    <OutputType>Exe</OutputType>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>
  <ItemGroup>
    <FrameworkReference Include="Microsoft.AspNetCore.App" />
    <PackageReference Include="Microsoft.Azure.Functions.Worker" Version="1.23.0" />
    <PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Http" Version="3.1.0" />
    <PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Http.AspNetCore" Version="1.2.1" />
    <PackageReference Include="Microsoft.Azure.Functions.Worker.Sdk" Version="1.17.4" />
    <PackageReference Include="Microsoft.ApplicationInsights.WorkerService" Version="2.22.0" />
    <PackageReference Include="Microsoft.Azure.Functions.Worker.ApplicationInsights" Version="1.2.0" />
    <PackageReference Include="System.Management.Automation" Version="7.4.5" />
  </ItemGroup>
  <ItemGroup>
    <None Update="host.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
    <None Update="local.settings.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
      <CopyToPublishDirectory>Never</CopyToPublishDirectory>
    </None>
  </ItemGroup>
  <ItemGroup>
    <Using Include="System.Threading.ExecutionContext" Alias="ExecutionContext" />
  </ItemGroup>
</Project>

Output:

enter image description here

enter image description here

For further information refer SO-Thread.

Upvotes: 1

Related Questions