Команда Powershell не распознается при вызове из C#

Это продолжение этого вопроса здесь, у меня есть команда PowerShell, которую я создал, и я могу вызвать команду в окне PowerShell, но при попытке вызова из метода C# я получаю сообщение об ошибке, поскольку командлет не распознается, Я пробовал использовать другие существующие команды и получил ту же ошибку, поэтому подозреваю, что проблема при импорте модуля, хотя я не получаю эту ошибку в потоках. Ошибка. Единственная ошибка, которую я получаю: «Get-RowAndPartitionKey не является распознанной командой, проверьте правописание ...».

Хотел бы знать, есть ли другой способ, я должен попробовать или могу отладить больше здесь, чтобы увидеть, извлекает ли мой модуль все команды или нет. прямо сейчас я не знаю, как это исправить.

       public string RunScript( string contentScript, Dictionary<string, EntityProperty> parameters )
    {
        List<string> parameterList = new List<string>();
        foreach( var item in parameters )
        {
            parameterList.Add( item.Value.ToString() );
        }
        using( PowerShell ps = PowerShell.Create() )
                       
        {
            IAsyncResult async =
             ps.AddCommand( "Import-Module" ).AddArgument( @"C:\Users\...\.D.PowerShell.dll" )
               .AddStatement()
               .AddCommand( "Get-RowAndPartitionKey" ).AddParameter( "Properties", "test" )
               .BeginInvoke();

            StringBuilder stringBuilder = new StringBuilder();
            foreach( PSObject result in ps.EndInvoke( async ) )
            {
                stringBuilder.AppendLine( result.ToString() );
            }
            return stringBuilder.ToString();
        }
    }
}

1 ответ

Ниже приводится самодостаточный пример кода:

  • Это показывает, что подход работает в принципе, как описано в этом ответе на ваш исходный вопрос.

    • Предварительные требования: пакет SDK PowerShell и среда выполнения .NET, используемые в проекте C#, который вызывает ваш пользовательский Get-RowAndPartitionKey" командлет должен быть совместим с PowerShell SDK и средой выполнения .NET, которые вы использовали для компиляции библиотеки DLL сборки, содержащей этот командлет, для импорта через.

    • Приведенный ниже пример кода гарантирует, что неявно, запустив непосредственно из PowerShell, используя <tcode id="514938"></tcode> командлет для компиляции кода C# по запросу - он работает как в Windows PowerShell, так и в PowerShell (Core) 7+.

      • На практике я обнаружил, что DLL, скомпилированная в .NET Framework (из Windows PowerShell), также работает в PowerShell (Core) (.NET (Core) 5.0), но не наоборот.
  • Здесь показаны методы устранения неполадок, а именно:

    • Добавление -Verbose переключиться на Import-Module вызов для создания подробного вывода, в котором перечислены команды, импортируемые из данного модуля (DLL).
    • Печать этих подробных сообщений (ищите // --- TROUBLESHOOTING CODE)
    • Печать любых возникших непрекращающихся ошибок PowerShell (в отличие от исключений, которые вам придется обрабатывать в коде C#).
      # Create a (temporary) assembly containing cmdlet "Get-RowAndPartitionKey".
# This assembly can directly be imported as a module from PowerShell.
# The cmdlet simply outputs "Hi from Get-RowAndPartitionKey" and
# echoes the input list's elements passed to -Properties one by one.
$tempModuleDll = Join-Path ([IO.Path]::GetTempPath()) "TempModule_$PID.dll"
Remove-Item -ErrorAction Ignore $tempModuleDll
Add-Type @'
  using System.Management.Automation;
  using System.Collections.Generic;
  [Cmdlet("Get", "RowAndPartitionKey")]
  public class GetRowAndPartitionKeyCmdlet : PSCmdlet {
    [Parameter] public List<string> Properties { get; set; }
    protected override void ProcessRecord() {
      WriteObject("Hi from Get-RowAndPartitionKey: ");
      WriteObject(Properties, true);
    }
  }
'@ -ErrorAction Stop -OutputAssembly $tempModuleDll

# Compile a C# class ad hoc to simulate your project, and call its static
# method, which imports the module and effectively calls 
#   Get-RowAndPartitionKey -Properties "foo", "bar"
(Add-Type @"
  using System;
  using System.Management.Automation;
  using System.Collections.Generic;
  using System.Text;

  public static class Foo {
    public static string RunScript(List<string> parameterList)
    {
      using (System.Management.Automation.PowerShell ps = PowerShell.Create())
      {
        IAsyncResult async =
          // Add -Verbose to the Import-Module call, so that the list of 
          // commands being imported is written to the verbose output stream.
          ps.AddCommand("Import-Module").AddArgument(@"$tempModuleDll").AddParameter("Verbose", true)
            .AddStatement()
            .AddCommand("Get-RowAndPartitionKey").AddParameter("Properties", parameterList)
            .BeginInvoke();

        StringBuilder stringBuilder = new StringBuilder();
        foreach (PSObject result in ps.EndInvoke(async))
        {
          stringBuilder.AppendLine(result.ToString());
        }
        
        // --- TROUBLESHOOTING CODE

        // Print verbose output from the Import-Module call
        foreach (var v in ps.Streams.Verbose) { Console.WriteLine("VERBOSE: " + v.ToString()); }

        // Print any errors.
        foreach (var e in ps.Streams.Error) { Console.WriteLine("ERROR: " + e.ToString()); }

        // ---

        return stringBuilder.ToString();
      }
    }
  }
"@ -ErrorAction Stop -PassThru)::RunScript(("foo", "bar"))

# Clean-up instructions:
if ($env:OS -eq 'Windows_NT') {
  Write-Verbose -vb "NOTE: Re-running this code requires you to start a NEW SESSION."
  Write-Verbose -vb "After exiting this session, you can delete the temporary module DLL(s) with:`n`n  Remove-Item $($tempModuleDll -replace '_.+', '_*.dll')`n "
} else {
  Write-Verbose -vb "NOTE: Re-running this code after modifying the embedded C# code requires you to start a NEW SESSION."
  Remove-Item $tempModuleDll
}

На моем компьютере с Windows 10, как из PowerShell (Core) 7.0.5, так и из Windows PowerShell 5.1, приведенное выше дает (инструкции по очистке опущены) следующее, показывая, что все работает по назначению:

      VERBOSE: Loading module from path 'C:\Users\jdoe\AppData\Local\Temp\TempModule_11876.dll'.
VERBOSE: Importing cmdlet 'Get-RowAndPartitionKey'.
Hi from Get-RowAndPartitionKey:
foo
bar

В частности, линия VERBOSE: Importing cmdlet 'Get-RowAndPartitionKey'. указывает, что настраиваемый командлет был успешно импортирован в сеанс.

Другие вопросы по тегам