skip to Main Content

I am trying to call a PowerShell script that installs and uses Az library from C# .NET 6 but I am getting the following error:

Failed to run test  because 
New-AzResourceGroup: 
Line |
   8 |      New-AzResourceGroup -Name 'TestRg123' -Location 'eastus2euap'
     |      ~~~~~~~~~~~~~~~~~~~
     | The term 'New-AzResourceGroup' is not recognized as a name of a cmdlet, function, script file, or executable program.
Check the spelling of the name, or if a path was included, verify that the path is correct and try again.

I think it’s failing to install Az or consider how fast the csharp code finishes, its just ignores the import and install commands.

Note that the actual script I am trying to does a lot more than just creating a resource group so I cannot simplify convert it to use Azure C# SDK.

App.cs

using System.Diagnostics;
using System.Management.Automation;
using System.Management.Automation.Runspaces;

var initialState = InitialSessionState.CreateDefault2();
initialState.ExecutionPolicy = Microsoft.PowerShell.ExecutionPolicy.Unrestricted;

using var ps = PowerShell.Create(initialState);
var results = ps.AddScript(@"
Install-Module -Name Az -Scope CurrentUser -Repository PSGallery -Force

# Import Azure module
Import-Module 'Az'
Import-Module 'Az.Accounts'
Import-Module 'Az.RecoveryServices'

try {
    New-AzResourceGroup -Name 'TestRg123' -Location 'eastus2euap'
}
catch
{
    $string_err = $_ | Out-String
    Write-Output ""Failed to run test $testname because $string_err""
}
").Invoke();

foreach (var outputItem in results)
{
    Debug.WriteLine(outputItem);
}

ConsoleApp.csproj

<Project Sdk="Microsoft.NET.Sdk">

    <PropertyGroup>
        <OutputType>Exe</OutputType>
        <TargetFramework>net6.0</TargetFramework>
        <ImplicitUsings>enable</ImplicitUsings>
        <Nullable>enable</Nullable>
    </PropertyGroup>

    <ItemGroup>
      <PackageReference Include="Microsoft.PowerShell.SDK" Version="7.2.6" />
      <PackageReference Include="PowerShellStandard.Library" Version="5.1.1" />
      <PackageReference Include="System.Management.Automation" Version="7.2.6" />
    </ItemGroup>

</Project>

UPDATE

This is what ps.ErrorBuffer is showing

enter image description here

2

Answers


  1. As the error suggests, is the package provider installed? I.e., is it listed under Get-PackageProvider, or is the PSGallery listed under Get-PSRepository? At the bottom of the linked page there’s a note that reads

    Important

    As of April 2020, the PowerShell Gallery no longer supports Transport
    Layer Security (TLS) versions 1.0 and 1.1. If you are not using TLS
    1.2 or higher, you will receive an error when trying to access the PowerShell Gallery. Use the following command to ensure you are using
    TLS 1.2:

    [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12

    For more information, see the announcement in the PowerShell blog.

    With that said, your first step should be ensuring the use of TLS 1.2 by running [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 then trying again. If that doesn’t work (or if not already installed), re-registering the PSGallery repository would be the next step to take.

    Unregister-PSRepository -Name 'PSGallery' # ensures no collision
    Register-PSRepository -Default # registers PSGallery when specifying the switch.
    
    Login or Signup to reply.
  2. While it takes longer initially, I would suggest using built in C# tools to call powershell. One note, you must install the powershell modules on each computer that runs the code. That could cause issues. But, you can use something like:

            public Collection<PSObject> runAzureCommands(Command _command, string _commandName)
            {
                InitialSessionState initialSession = InitialSessionState.CreateDefault();
                initialSession.ImportPSModule(new[] { "MSOnline" });
                PSCredential credential = new PSCredential(this.emailLogin, this.emailPass);
                WSManConnectionInfo connectionInfo = new WSManConnectionInfo(new Uri("https://outlook.office365.com/PowerShell-LiveID"), "http://schemas.microsoft.com/powershell/Microsoft.Exchange", credential);
                connectionInfo.AuthenticationMechanism = AuthenticationMechanism.Basic;
                System.Net.ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyerrors) => true;
                System.Net.ServicePointManager.SecurityProtocol = (System.Net.SecurityProtocolType)(0x30 | 0xc0 | 0x300 | 0xc00);
                connectionInfo.MaximumConnectionRedirectionCount = 10;
                Command connectCommand = new Command("Connect-AzureAD");
                connectCommand.Parameters.Add(new CommandParameter("Credential", credential));
    
                try
                {
                    using (Runspace runspace = RunspaceFactory.CreateRunspace(initialSession))
                    {
                        runspace.Open();
                        Pipeline pipe = runspace.CreatePipeline();
                        pipe.Commands.Add(connectCommand);
                        var results = pipe.Invoke();
                        var error = pipe.Error.ReadToEnd();
                        if (error.Count > 0)
                        {
                            foreach (PSObject err in error)
                            {
                                //Log the error as needed.
                            }
                        }
                        pipe = runspace.CreatePipeline();
                        pipe.Commands.Add(_command);
                        var results2 = pipe.Invoke();
                        var error2 = pipe.Error.ReadToEnd();
                        if (error2.Count > 0)
                        {
                            foreach (PSObject er in error2)
                            {
                                //log the error as needed.
                            }
                        }
                        return results2;
                    }
                }
                catch (Exception e)
                {
                    //Log the exception as needed.
                }
            }
    

    This lets you log errors better, and log exceptions better. it also lets you return a PS object if you need to use the created item / output.

    To use a function:

            public void addAzureGroupMember(object _group, object _user)
            {
                Command command = new Command("Add-AzureADGroupMember");
                command.Parameters.Add("ObjectId", _group);
                command.Parameters.Add("RefObjectId", _user);
                Collection<PSObject> results = runAzureCommands(command, "addAxureGroupMember");
            }
    

    Once you build the main function, it lets you create extra functions quickly. Also, when / if it breaks, you only have to change one main function, instead of fixing every single powershell script you created using the template.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search