Команда 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'.
указывает, что настраиваемый командлет был успешно импортирован в сеанс.