Powershell -> exe -> PowerScript Сбой записи в журнал консоли хоста - PullRequest
0 голосов
/ 20 января 2020

TLDW: для поддержки определенного c процесса мне нужно go из экземпляров / модуля powershell, чтобы запустить известный безопасный исполняемый файл для некоторого c# magi c, который затем, в свою очередь, должен ударить и выполнить сценарий powershell перед выходом.

Точка входа в Powershell {Известно, что хорошо {Powershell Work To Do}}}

Теперь в идеале все это должно выполняться из одного экземпляра консоли, чтобы все на выходе просто посмотреть. Ведение журнала exe -> powershell все работает нормально и, как и ожидалось, при использовании powershell.Streams .... Все команды write-hosts в PowerShell работают в консоли, и я получаю всю необходимую информацию.

powerShell.Streams.Information.DataAdded + = LogMessage;

Проблема возникает, когда вводится внешний модуль powershell. Это необходимо, потому что родительский процесс и среда выполнения, из которой он работает, - powershell. Как только весь этот стек запущен из экземпляра powershell, я получаю логирование консоли из внешнего PowerShell и из exe. НО все записи-хосты из внутренних модулей powershell исчезают.

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

PowerShell Внешний:

$C#Exe = Join-Path $PSScriptRoot $C#ExePath
$C#Args = @()


Write-Host "Hello world" # will show up

& $C#Exe  $C#Args

C# Exe Код:

public static void Main(string[] args)
{
    Console.WriteLine("Hello world"); #Will show up

    var powerShell = PowerShell.Create().AddScript("PowerShellInner.ps1");

    powerShell.Streams.Information.DataAdded += LogMessage<InformationRecord>;
    powerShell.Streams.Warning.DataAdded += LogMessage<WarningRecord>;
    powerShell.Streams.Error.DataAdded += LogMessage<ErrorRecord>;
    powerShell.Streams.Verbose.DataAdded += LogMessage<VerboseRecord>;
    powerShell.Streams.Debug.DataAdded += LogMessage<DebugRecord>;


    StringBuilder resultString = new StringBuilder();

    foreach (dynamic item in powerShell.Invoke().ToList())
    {
        resultString.AppendLine(item.ToString());
    }

    Console.WriteLine(resultString.ToString());

}

private static void LogMessage<T>(object sender, DataAddedEventArgs e)
{
    var data = (sender as PSDataCollection<T>)[e.Index];
    Console.WriteLine($"[{typeof(T).Name}] {Convert.ToString(data)}");
}

PowerShell Внутренний:

Write-Host "Hello world" #Wont show up

1 Ответ

1 голос
/ 20 января 2020

ОБНОВЛЕНИЕ 1/22/2020

Я не могу полностью объяснить, почему вы испытываете то, что видите, но следующий код работает.

Вывод из выполнения PowerShellOuter.ps1

enter image description here

Код

Примечания:

  • Ваша c# программа не показывает никакого кода, манипулирующего входными аргументами,
    , поэтому я этого не сделал t моделировать любые входные аргументы

  • Вы неправильно использовали метод AddScript. Требуется текст сценария, а не имя сценария

  • В приведенном ниже коде предполагается, что c# exe и два сценария PS находятся в одной папке

  • В PowerShellInner.ps1 используйте запись-вывод. write-host не выводит данные в PowerShell Objectflow Engine, а, скорее всего, как следует из названия, записывает данные напрямую в хост и ничего не отправляет механизму PowerShell для пересылки командам позже в конвейере. См. Запись-вывод или запись-хост в PowerShell

PowerShellOuter.ps1

cls
$CSharpExe = Join-Path $PSScriptRoot "PowerShellExecutionSample.exe"
Write-Host "Hello from PowerShellOuter.ps1"
&$CSharpExe
pause

PowerShellInner.ps1

Write-Output "Hello from PowerShellInner.ps1"

Код для PowerShellExecutionSample.exe

using System;
using System.Collections.ObjectModel;
using System.IO;
using System.Management.Automation;

namespace PowerShellExecutionSample
{
    class Program
    {
        static void Main(string[] args)
        {
            PowerShellExecutor t = new PowerShellExecutor();
            t.ExecuteSynchronously();
        }
    }

    /// <summary>
    /// Provides PowerShell script execution examples
    /// </summary>
    class PowerShellExecutor
    {
        public void ExecuteSynchronously()
        {
            using (PowerShell PowerShellInstance = PowerShell.Create())
            {
                //You mis-used the AddScript method. It needs the text of the script, not the script name
                string scriptText = File.ReadAllText(string.Format(@"{0}\PowerShellInner.ps1", Environment.CurrentDirectory));

                PowerShellInstance.AddScript(scriptText);
                Collection <PSObject> PSOutput = PowerShellInstance.Invoke();

                // loop through each output object item
                foreach (PSObject outputItem in PSOutput)
                {
                    // if null object was dumped to the pipeline during the script then a null
                    // object may be present here. check for null to prevent potential NRE.
                    if (outputItem != null)
                    {
                        Console.WriteLine(outputItem.BaseObject.ToString() + "\n");
                    }
                }
            }
        }
    }
}

Оригинальный ответ от 1/21/2020

Обновление вашего вопроса, чтобы вывести ваш код, помогло - спасибо.

Я думаю, у вас есть две проблемы:

1) Измените вашу программу c#, чтобы получать потоки, поступающие из PowerShell Inner, и заставьте вашу программу c# повторно отправлять данные из выходных потоков PowerShell Inner. Вот запись в блоге Microsoft, которую я использовал, чтобы взломать тот же самый гадость: Выполнение сценариев PowerShell из C#

2) Измените внешний вид PowerShell для получения потоков, поступающих из программы c# , Вот запись в блоге, которая, кажется, ломает эту гайку: Как перенаправить вывод консольной программы в файл в PowerShell . Суть этого заключается в выполнении следующего из вашей PowerShell Outer:

cmd /c XXX.exe ^>log.txt 2^>^&1

Примечание: ^ действительно обратные помехи

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...