将 powershell cmdlet 输出写入文件而不是从 c# 写入管道

write powershell cmdlet output to a file instead of writing to pipeline from c#

我正在尝试在 C# 中实现 powershell cmdlet。

我在代码中有一个 object 类似的东西。

class A{
    string Title_p;
    string Title_q;
    int Title_r;
    string[] Title_s;
}

因此,在 cmdlet 实现中,当我给出 this.WriteObject(A_obj) 时,它将 object 数据转换为美观易读的 table 格式,列标题为 object 名称。如下所示:

Title_p   Title_q  Title_r  Title_s
=======   =======  =======  =======
Hello      Bolo     12     {RR,TT,YY}

但是所有这些输出都被重定向到将从中触发最终 cmdlet 的管道。

但我还想将所有这些输出记录到一个文件中(除了打印到管道外)

我知道我可以给 CmdLet-Sud | out-file c:/data.txt。但我不想要这个。我只想触发命令 CmdLet-Sud,它应该将数据打印到管道和文件中。

那么,如何将object转换成这样的printabletable格式呢?

您可以在 C# 代码中创建 "Powershell"(使用 System.Management.Automation.Powershell)。您的 "Powershell"(class 名称 IMO 的错误选择,为了清楚起见,我将在此答案中将其称为 SMA.Powershell)可以调用 tee-object(或 append-contentset-content).然后,您可以将 class 个实例作为参数传递给 SMA.Powershell。

或者你可以只使用 System.IO 文件 space 下的 classes 并直接写入文件。您可以通过 write-object 单独写入相同的输出。

顺便说一句,将输出写入文件没有任何意义,除非您在 class 中支持序列化和反序列化。除非,您真正想要的是将 class 实例写成文本 table。在这种情况下,您的 SMA.Powershell 可以是 % { $_ | ft | set-content c:\data.txt; $_}.

Tee-Object 为我完成了工作。

PowerShell powerShellInstance = PowerShell.Create();
powerShellInstance.AddCommand("Tee-Object");
powerShellInstance.AddParameter("FilePath", filePath);
powerShellInstance.AddParameter("InputObject", obj_A);
powerShellInstance.AddParameter("Append");
powerShellInstance.Invoke();

但是,当上面的代码被多次调用时,文件写成

Title_p   Title_q  Title_r  Title_s
=======   =======  =======  =======
Hello      Bolo     12     {RR,TT,YY}

Title_p   Title_q  Title_r  Title_s
=======   =======  =======  =======
Aaaao      Colo     13     {EE,YY}

Title_p   Title_q  Title_r  Title_s
=======   =======  =======  =======
HHSAR      Dolo     14     {QQ,XX}

但是在 cmdlet 实现中,即使您使用多个 object 多次调用 this.WriteObject(),结果也会是

Title_p   Title_q  Title_r  Title_s
=======   =======  =======  =======
Hello      Bolo     12     {RR,TT,YY}
Aaaao      Colo     13     {EE,YY}
HHSAR      Dolo     14     {QQ,XX}

我想看看是否可以调整代码,即使在程序中多次调用 invoke() 命令,输出文件仍然只有一列,而不是一列 header每个 object 列 header(在最终输出文件中)

终于完成了,我想要的:

// When this method is called for the first time, it creates a table header too.
// The following is the PowerShell line that will be run in the runspace.
// Write-Output -InputObject <object_A> | Format-Table | Out-String

// For the next time, when this routine is called, the following gets executed.
// Write-Output -InputObject <object_A> | Format-Table -HideTableHeaders | Out-String

Runspace runspace = RunspaceFactory.CreateRunspace();
runspace.Open();
Pipeline pipeLine = runspace.CreatePipeline();

Command command1 = new Command("Write-Output");
command1.Parameters.Add("InputObject", object_A);

Command command2 = new Command("Format-Table");
if (this.filePath != null)
{
    // If this is not the first row, hide the table headers
    command2.Parameters.Add("HideTableHeaders");
}
Command command3 = new Command("Out-String");

pipeLine.Commands.Add(command1);
pipeLine.Commands.Add(command2);
pipeLine.Commands.Add(command3);
var results = pipeLine.Invoke();

// The resultant text from the command will have a lot of white spaces/carriage returns.
// So, let us trim the content before adding it to file.
foreach (var result in results)
{
    string data = null;
    data = string.Concat(result);
    data = data.Trim();

    // For the first time, we need to create a log file too.
    if (filePath == null)
    {
        // Call custom routine CreateLogFile() which creates a file and returns the file path as string for you
        filePath = CreateLogFile();
    }

    // Write the object row into the file.
    using (StreamWriter writer = System.IO.File.AppendText(this.filePath))
    {
        writer.WriteLine(data);
    }
}

runspace.Close();