Каков правильный способ получить вывод для этой Powershell на С #

Я не получаю никаких сообщений об ошибках ниже, но я также не получаю вывод. Ниже приведены cmd Powershell и вызывающий его метод C#. Я хотел бы знать, правильно ли он написан и как я могу получить результат, исходящий от powershell. Он отлично работает, когда я запускаю из окна PowerShell

Pwsh cmd:

      public class GetRowAndPartitionKeys : Cmdlet
    {
        [Parameter(Mandatory = false)]
        public List<string> Properties { get; set; } = new List<string>();
    }

    [Cmdlet( VerbsCommon.Get, "RowAndPartitionKeys" )]
    public class GetRowAndPartitionKeyCmd : GetRowAndPartitionKeys

    {
        protected override void ProcessRecord()
        {            
            WriteObject ("Hi");
        }
    }

}

C# метод:

       public async Task<IEnumerable<object>> RunScript(  )
        {
            // create a new hosted PowerShell instance using the default runspace.
            // wrap in a using statement to ensure resources are cleaned up.
           string scriptContents = "Import-Module 'C:\Users\...\Powershell.dll";
            using( PowerShell ps = PowerShell.Create() )
            {
                // specify the script code to run.
            ps.AddScript( scriptContents ).AddCommand( "Get-RowAndPartitionKeys" );


            // execute the script and await the result.
            var pipelineObjects = await ps.InvokeAsync().ConfigureAwait( false );
           
            foreach( var item in pipelineObjects )
            {
                Console.WriteLine( item.BaseObject.ToString() );
            }
            return pipelineObjects;
        }

1 ответ

Подобно ответу на ваш предыдущий вопрос , следующий автономный пример кода демонстрирует, что подход работает в принципе после исправления следующих проблем в вашем коде:

  • An .AddStatement() звонок отсутствует между .AddScript() и .AddCommand()вызов; это необходимо для (сценария блочного) Import-Modulecall и call должны рассматриваться как отдельные утверждения .

  • Строка псевдокода string scriptContents = "Import-Module 'C:\Users\...\Powershell.dll"; отсутствует закрытие ' (возможно, просто артефакт публикации здесь).

  • Кроме того, ниже добавлен код устранения неполадок.

Хотя код оркестрации находится в PowerShell, используются реальные проекты C #, скомпилированные с помощью .NET SDK , в сочетании с версией 7.1.2из (ядра) пакета SDK PowerShell, <tcode id="1472893"></tcode>.

После запуска кода, который создает и запускает тестовые проекты, вы можете самостоятельно проверить их и поэкспериментировать ( ./module это проект для модуля DLL, который определяет Get-RowAndPartitionKeys командлет, ./app это проект для вызывающего его приложения):

      $tmpDir = (New-Item -Force -Type Directory (Join-Path temp: $PID)).FullName

$tmpModuleDir = (New-Item -Force -Type Directory (Join-Path $tmpDir module)).FullName
$tmpAppDir = (New-Item -Force -Type Directory (Join-Path $tmpDir app)).FullName
$tmpPublishDir = (New-Item -Force -Type Directory (Join-Path $tmpDir publish)).FullName

$tmpModuleDll = Join-Path $tmpPublishDir module.dll

Push-Location

# ---

Write-Verbose -vb "Creating module DLL with sample cmdlet..."

Set-Location $tmpModuleDir

dotnet new classlib --force >$null || $(exit $LASTEXITCODE)

dotnet add package Microsoft.PowerShell.SDK >$null || $(exit $LASTEXITCODE)

@'
using System;
using System.Collections.Generic;
using System.Management.Automation;

namespace demo {
    public class GetRowAndPartitionKeys : Cmdlet 
    {
      public List<string> Properties { get; set; }
    }
    
    [Cmdlet( VerbsCommon.Get, "RowAndPartitionKeys" )]
    public class GetRowAndPartitionKeyCmd : GetRowAndPartitionKeys
    {
      protected override void ProcessRecord()
      {
          WriteObject ("Hi");
      }
    }
}
'@ | Set-Content Class1.cs

dotnet publish -o $tmpPublishDir >$null || $(exit $LASTEXITCODE)

# ---

Write-Verbose -vb "Creating console application that imports the module DLL and calls the sample cmdlet..."
Set-Location $tmpAppDir

dotnet new console --force >$null  || $(exit $LASTEXITCODE)

dotnet add package Microsoft.PowerShell.SDK >$null || $(exit $LASTEXITCODE)

@"
using System;
using System.Collections.Generic;
using System.Management.Automation;
using System.Threading.Tasks;

namespace demo {

    public static class App {
        static void Main(string[] args)
        {
            var unused = new Foo().RunScript().Result;
        }
    }    

    public class Foo {
        public async Task<IEnumerable<object>> RunScript()
        {
            string scriptContents = @"Import-Module -Verbose ""$tmpModuleDll""";
            using(PowerShell ps = PowerShell.Create())
            {
                ps.AddScript(scriptContents).AddStatement().AddCommand("Get-RowAndPartitionKeys");
                var pipelineObjects = await ps.InvokeAsync().ConfigureAwait( false );
                
                // --- 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()); }
        
                // ---                

                foreach (var item in pipelineObjects)
                {
                    Console.WriteLine(item.BaseObject.ToString());
                }

                return pipelineObjects;
            }
        }
    }
}
"@ | Set-Content Program.cs

# ---

Write-Verbose -vb "Compiling and invoking the console application..."
dotnet run 

Pop-Location

Write-Verbose -vb @"
The test projects are located in $tmpDir.
To clean up, run:

   Remove-Item "$tmpdir" -Recurse
 
"@

На моем компьютере с Windows 10 (работающем с PowerShell 7.1.2) я получаю:

Как вы видете:

  • подробный вывод подтверждает, что командлет был правильно импортирован
  • то Hi показывает, что командлет был успешно вызван.
Другие вопросы по тегам