我有一个 C# 类库,它提供了许多可以从 PowerShell 脚本 (.PS1) 和高级模块 (.PSM1) 调用的接口。我有一个静态方法可以使用以下命令将详细消息和调试消息写入控制台System.Console
class:
public class Write
{
public static void Verbose(string msg, string source)
{
if (Config.EnableVerbose)
{
ConsoleColor originalForeGroundColor = Console.ForegroundColor;
ConsoleColor originalBackGroundColor = Console.BackgroundColor;
Console.ForegroundColor = ConsoleColor.Yellow;
Console.BackgroundColor = ConsoleColor.Black;
Console.Write("VERBOSE: {0} {1}{2}", source, msg, Environment.NewLine);
Console.ForegroundColor = originalForeGroundColor;
Console.BackgroundColor = originalBackGroundColor;
}
}
}
但是,当这些消息显示在 PowerShell 控制台中时,无法使用重定向来捕获它们,就像使用Out-File
, >&0
甚至与Start-Transcript
.
我读过了about_Redirection
,并且使用重定向修饰符不会捕获控制台输出。例如,使用我编写的 PowerShell 高级功能(又名 Cmdlet):
Get-CommandTrace -ScriptBlock { Get-Resource } *> C:\Temp\capture.log
The Get-CommandTrace
Cmdlet 设置$VerbosePreference = 'Continue'
在 ScriptBlock 执行期间,并捕获详细信息Get-Resource
那里输出。但不捕获我的 C# 库的控制台输出。
所以,我的问题很简单:既不是 Cmdlet 类也不是继承类的 C# 类是否能够将输出写入调用它的现有 PowerShell 运行空间?
Note:
-
This is not一个完整的答案,因为它有严格的限制 - 尽管它可能适用于特定的用例。
-
该答案使用的原始形式已弃用的 PowerShell SDK 方法.CreateNestedPipeline() https://github.com/PowerShell/PowerShellStandard/issues/42#issuecomment-516255508,如果您针对的是编写代码,则不能再使用PowerShell标准库 https://github.com/PowerShell/PowerShellStandard为了实现跨平台和跨版本兼容性(应在所有受支持的平台上的 Windows PowerShell 和 PowerShell Core 中运行的代码)。
克里斯(OP)本人找到了一个兼容的替代方案,该答案的当前形式就是基于该替代方案。
挑战是写信给调用管道的输出流(正如您观察到的那样Console
与 PowerShell 的输出流无关,直接打印到控制台,无法在 PowerShell 中捕获或重定向此类输出)。
虽然您可以获得调用的参考runspace,据我所知,没有办法获得对运行管道.
使用调用运行空间,您可以通过以下方式写入 PowerShell 的输出流:new管道,但附带严重的限制:
-
You 不能直接写入调用者的成功输出流 (1
) 那样;也就是说,虽然您可以调用针对other流,例如Write-Verbose
, Write-Output
/ 隐式输出确实not work.
-
在变量中捕获此嵌套管道的输出或通过管道发送输出需要将方法调用括起来(...)
(or $(...)
or @(...)
)除了对成功输出流应用适当的重定向(例如,4>&1
对于详细流)。
详细信息请参见代码注释。
Add-Type -TypeDefinition @'
using System.Management.Automation;
public class Write
{
public static void Verbose(string msg)
{
using (PowerShell ps = PowerShell.Create(RunspaceMode.CurrentRunspace)) {
// IMPORTANT: Use .AddScript(), not .AddCommand().
// Even though .AddCommand() + .AddParameter() is arguably a cleaner way to
// formulate the command, it results in output that cannot be captured.
// As noted, Write-Output / success-stream output does NOT work.
ps.AddScript("Write-Verbose '" + msg.Replace("'", "''") + "'").Invoke();
}
}
}
'@
#"
$VerbosePreference = 'Continue'
# Regular output to the verbose stream.
Write-Verbose 'msg1'
# Verbose output via the custom type.
[Write]::Verbose('msg2')
# SUPPRESSING and REDIRECTING TO A FILE work.
[Write]::Verbose('msg3') 4> $null
[Write]::Verbose('msg4') 4> t.txt
# By default, REDIRECTING TO THE STANDARD OUTPUT STREAM (1)
# works only for the OUTSIDE, i.e. for CALLERS of this script.
[Write]::Verbose('msg5') 4>&1
# Redirecting to the standard output stream (1) can also be used to:
# * CAPTURE the result INSIDE your script
# * SEND THE RESULT THROUGH THE PIPELINE,
# additionally invoke the method call enclosed in (...) or $(...) or @(...)
$out = ([Write]::Verbose('msg6') 4>&1); "captured: [$out]"
([Write]::Verbose('msg7') 4>&1) | ForEach-Object { "piped: [$_]" }
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)