使用 SilentlyContinue 时如何处理 Write-Information 管道输出
How to process Write-Information pipeline output when using SilentlyContinue
当 $InformationPreference
为 SilentlyContinue
时,Write-Information
似乎会在管道中输出不需要的记录。特别是因为默认值是 SilentlyContinue
,我认为这是个问题。
function foo {
$VerbosePreference = 'SilentlyContinue'
Write-Verbose "verbose silent"
$VerbosePreference = 'Continue'
Write-Verbose "verbose continue"
$InformationPreference = 'SilentlyContinue'
Write-Information "info silent"
$InformationPreference = 'Continue'
Write-Information "info continue"
}
$PSVersionTable.PSVersion.ToString()
# 5.1.15063.1805
foo
# VERBOSE: verbose continue
# info continue
foo *>&1 | % { "redirected: $_" }
# redirected: verbose continue
# redirected: info silent
# redirected: info continue
正如预期的那样,SilentlyContinue
的 $VerbosePreference
导致 Write-Verbose
不生成消息,因此没有要重定向的消息。
同样如预期的那样,SilentlyContinue
的 $InformationPreference
在控制台上正确显示任何内容,但是一条消息被重定向到管道。
这似乎是错误的,因为一旦消息进入管道,消费者如何确定是否应静默丢弃该信息消息?
InformationRecords 的流水线是否损坏,或者作为流水线消费者如何正确过滤掉不需要的 InformationRecords?
有趣。但是,有一种解决方法基于 About CommonParameters 帮助主题中的以下语句:
-InformationAction:Ignore
suppresses the informational message and
continues running the command. Unlike SilentlyContinue
,
Ignore
completely forgets the informational message; it doesn't add the informational message to the information stream.
在下面的脚本中,我做了一些改动:
将函数输出设置为变量(当然,您也可以改为传入管道;请参阅最后的脚本行 Debug-InfoAction *>&1 | ForEach-Object {"redirected: $_"}
及其结果)。
InformationAction
参数(不幸的是,值Ignore
不支持ActionPreference
变量;因此,这个调整成为解决方案的关键点)。
The InformationAction
parameter overrides, but does not replace the
value of the $InformationAction
preference variable when the
parameter is used in a command to run a script or function.
脚本:
function Debug-InfoAction {
param(
[System.Management.Automation.ActionPreference]
$InfoAction='Ignore'
)
Write-Verbose "verbose…………$InfoAction" -Verbose
Write-Information "InfoAction=$InfoAction" -InformationAction $InfoAction
}
foreach ( $InfoAction in @(
'SilentlyContinue',
'Continue',
'Ignore'
) # exclude from testing: 'Stop', 'Inquire', 'Suspend'
) {
$aux = ''
$aux = Debug-InfoAction -InfoAction $InfoAction 6>&1
'{0,16}:{1}' -f $InfoAction, $aux
}
# check newly defined default InformationAction
$InfoAction = 'Default'
$aux = ''
$aux = Debug-InfoAction 6>&1
'{0,16}:{1}' -f $InfoAction, $aux
Debug-InfoAction *>&1 | ForEach-Object { "redirected: $_" }
输出:
D:\PShell\SO303102a.ps1
VERBOSE: verbose…………SilentlyContinue
SilentlyContinue:InfoAction=SilentlyContinue
VERBOSE: verbose…………Continue
Continue:InfoAction=Continue
VERBOSE: verbose…………Ignore
Ignore:
VERBOSE: verbose…………Ignore
Default:
redirected: verbose…………Ignore
编辑。
Unfortunately it doesn't really help the core problem that if my
function is calling someone elses code that uses Write-Information
then when my code redirects (or captures) the Information stream,
then I have no way of discarding Information that was written with
SilentlyContinue
.
后面的合格谏示我的不足……下面简单截取一下:
$c = Write-Information "Continue" -InformationAction Continue 6>&1
$s = Write-Information "Silently" -InformationAction SilentlyContinue 6>&1
两者都是[System.Management.Automation.InformationRecord]
类型。我试图找到差异(即使在它们的 子属性 中)但无法找到,除了数据本身中的差异:
param(
[switch]$IncludeEqual = $false
)
begin {
Function Compare-Property {
param(
$RefObject,
$DifObject,
[switch]$IncludeEqual
)
# compare objects
Compare-Object $RefObject $DifObject -IncludeEqual |
Select-Object -Property SideIndicator,
@{N='objects';E={'Function Compare-Property'}},
InputObject
Write-Verbose $RefObject.GetType().FullName -Verbose:$IncludeEqual
# a level down: compare properties of objects individually
$cpe = $RefObject.PsObject.Properties.GetEnumerator()
$spe = $DifObject.PsObject.Properties.GetEnumerator()
While ( $cpe.MoveNext() -and $spe.MoveNext() ) {
Compare-Object $cpe.Current.Value `
$spe.Current.Value -IncludeEqual:$IncludeEqual |
Select-Object -Property SideIndicator,
@{N='objects';E={$spe.Current.Name}},
InputObject
# more level down:
# compare properties of properties of objects individually
$cpeIn = $cpe.Current.PsObject.Properties.GetEnumerator()
$speIn = $spe.Current.PsObject.Properties.GetEnumerator()
While ( $cpeIn.MoveNext() -and $speIn.MoveNext() ) {
Compare-Object $cpeIn.Current.Value `
$speIn.Current.Value -IncludeEqual:$IncludeEqual |
Select-Object -Property SideIndicator,
@{N='objects';
E={ $cpe.Current.Name + '.' + $cpeIn.Current.Name}},
InputObject
}
}
}
$c = Write-Information "Continue" -InformationAction Continue 6>&1
$s = Write-Information "Silently" -InformationAction SilentlyContinue 6>&1
}
process {
Compare-Object $c.GetType() $s.GetType() -IncludeEqual |
Select-Object -Property SideIndicator,
@{N='objects';E={'.GetType()'}}, InputObject
Compare-Object $c.PsObject.TypeNames `
$s.PsObject.TypeNames -IncludeEqual |
Select-Object -Property SideIndicator,
@{N='objects';E={'.PsObject.TypeNames'}},
InputObject
Compare-Object ($c | Get-Member -MemberType Properties -Force).PsTypeNames `
($s | Get-Member -MemberType Properties -Force).PsTypeNames `
-IncludeEqual |
Select-Object -Property SideIndicator,
@{N='objects';E={'(gm).PsTypeNames'}},
InputObject
Compare-Object $c $s -IncludeEqual |
Select-Object -Property SideIndicator,
@{N='objects';E={"$($c.GetType().Name) itself"}},
InputObject
Compare-Property -RefObject $c `
-DifObject $s -IncludeEqual:$IncludeEqual
Compare-Property -RefObject $c.PsObject `
-DifObject $s.PsObject -IncludeEqual:$IncludeEqual
}
输出:
D:\PShell\SO303102c.ps1
SideIndicator objects InputObject
------------- ------- -----------
== .GetType() System.Management.Automation.InformationRecord
== .PsObject.TypeNames System.Management.Automation.InformationRecord
== .PsObject.TypeNames System.Object
== (gm).PsTypeNames System.Object[]
== (gm).PsTypeNames System.Array
== (gm).PsTypeNames System.Object
=> InformationRecord itself Silently
<= InformationRecord itself Continue
=> Function Compare-Property Silently
<= Function Compare-Property Continue
=> MessageData Silently
<= MessageData Continue
=> MessageData.Value Silently
<= MessageData.Value Continue
== Function Compare-Property psobject {Members, Properties, Methods, Imme...
=> ImmediateBaseObject Silently
<= ImmediateBaseObject Continue
=> ImmediateBaseObject.Value Silently
<= ImmediateBaseObject.Value Continue
=> BaseObject Silently
<= BaseObject Continue
=> BaseObject.Value Silently
<= BaseObject.Value Continue
$InformationPreference
为 SilentlyContinue
时,Write-Information
似乎会在管道中输出不需要的记录。特别是因为默认值是 SilentlyContinue
,我认为这是个问题。
function foo {
$VerbosePreference = 'SilentlyContinue'
Write-Verbose "verbose silent"
$VerbosePreference = 'Continue'
Write-Verbose "verbose continue"
$InformationPreference = 'SilentlyContinue'
Write-Information "info silent"
$InformationPreference = 'Continue'
Write-Information "info continue"
}
$PSVersionTable.PSVersion.ToString()
# 5.1.15063.1805
foo
# VERBOSE: verbose continue
# info continue
foo *>&1 | % { "redirected: $_" }
# redirected: verbose continue
# redirected: info silent
# redirected: info continue
正如预期的那样,SilentlyContinue
的 $VerbosePreference
导致 Write-Verbose
不生成消息,因此没有要重定向的消息。
同样如预期的那样,SilentlyContinue
的 $InformationPreference
在控制台上正确显示任何内容,但是一条消息被重定向到管道。
这似乎是错误的,因为一旦消息进入管道,消费者如何确定是否应静默丢弃该信息消息?
InformationRecords 的流水线是否损坏,或者作为流水线消费者如何正确过滤掉不需要的 InformationRecords?
有趣。但是,有一种解决方法基于 About CommonParameters 帮助主题中的以下语句:
-InformationAction:Ignore
suppresses the informational message and continues running the command. UnlikeSilentlyContinue
,Ignore
completely forgets the informational message; it doesn't add the informational message to the information stream.
在下面的脚本中,我做了一些改动:
将函数输出设置为变量(当然,您也可以改为传入管道;请参阅最后的脚本行
Debug-InfoAction *>&1 | ForEach-Object {"redirected: $_"}
及其结果)。InformationAction
参数(不幸的是,值Ignore
不支持ActionPreference
变量;因此,这个调整成为解决方案的关键点)。
The
InformationAction
parameter overrides, but does not replace the value of the$InformationAction
preference variable when the parameter is used in a command to run a script or function.
脚本:
function Debug-InfoAction {
param(
[System.Management.Automation.ActionPreference]
$InfoAction='Ignore'
)
Write-Verbose "verbose…………$InfoAction" -Verbose
Write-Information "InfoAction=$InfoAction" -InformationAction $InfoAction
}
foreach ( $InfoAction in @(
'SilentlyContinue',
'Continue',
'Ignore'
) # exclude from testing: 'Stop', 'Inquire', 'Suspend'
) {
$aux = ''
$aux = Debug-InfoAction -InfoAction $InfoAction 6>&1
'{0,16}:{1}' -f $InfoAction, $aux
}
# check newly defined default InformationAction
$InfoAction = 'Default'
$aux = ''
$aux = Debug-InfoAction 6>&1
'{0,16}:{1}' -f $InfoAction, $aux
Debug-InfoAction *>&1 | ForEach-Object { "redirected: $_" }
输出:
D:\PShell\SO303102a.ps1
VERBOSE: verbose…………SilentlyContinue SilentlyContinue:InfoAction=SilentlyContinue VERBOSE: verbose…………Continue Continue:InfoAction=Continue VERBOSE: verbose…………Ignore Ignore: VERBOSE: verbose…………Ignore Default: redirected: verbose…………Ignore
编辑。
Unfortunately it doesn't really help the core problem that if my function is calling someone elses code that uses
Write-Information
then when my code redirects (or captures) the Information stream, then I have no way of discarding Information that was written withSilentlyContinue
.
后面的合格谏示我的不足……下面简单截取一下:
$c = Write-Information "Continue" -InformationAction Continue 6>&1
$s = Write-Information "Silently" -InformationAction SilentlyContinue 6>&1
两者都是[System.Management.Automation.InformationRecord]
类型。我试图找到差异(即使在它们的 子属性 中)但无法找到,除了数据本身中的差异:
param(
[switch]$IncludeEqual = $false
)
begin {
Function Compare-Property {
param(
$RefObject,
$DifObject,
[switch]$IncludeEqual
)
# compare objects
Compare-Object $RefObject $DifObject -IncludeEqual |
Select-Object -Property SideIndicator,
@{N='objects';E={'Function Compare-Property'}},
InputObject
Write-Verbose $RefObject.GetType().FullName -Verbose:$IncludeEqual
# a level down: compare properties of objects individually
$cpe = $RefObject.PsObject.Properties.GetEnumerator()
$spe = $DifObject.PsObject.Properties.GetEnumerator()
While ( $cpe.MoveNext() -and $spe.MoveNext() ) {
Compare-Object $cpe.Current.Value `
$spe.Current.Value -IncludeEqual:$IncludeEqual |
Select-Object -Property SideIndicator,
@{N='objects';E={$spe.Current.Name}},
InputObject
# more level down:
# compare properties of properties of objects individually
$cpeIn = $cpe.Current.PsObject.Properties.GetEnumerator()
$speIn = $spe.Current.PsObject.Properties.GetEnumerator()
While ( $cpeIn.MoveNext() -and $speIn.MoveNext() ) {
Compare-Object $cpeIn.Current.Value `
$speIn.Current.Value -IncludeEqual:$IncludeEqual |
Select-Object -Property SideIndicator,
@{N='objects';
E={ $cpe.Current.Name + '.' + $cpeIn.Current.Name}},
InputObject
}
}
}
$c = Write-Information "Continue" -InformationAction Continue 6>&1
$s = Write-Information "Silently" -InformationAction SilentlyContinue 6>&1
}
process {
Compare-Object $c.GetType() $s.GetType() -IncludeEqual |
Select-Object -Property SideIndicator,
@{N='objects';E={'.GetType()'}}, InputObject
Compare-Object $c.PsObject.TypeNames `
$s.PsObject.TypeNames -IncludeEqual |
Select-Object -Property SideIndicator,
@{N='objects';E={'.PsObject.TypeNames'}},
InputObject
Compare-Object ($c | Get-Member -MemberType Properties -Force).PsTypeNames `
($s | Get-Member -MemberType Properties -Force).PsTypeNames `
-IncludeEqual |
Select-Object -Property SideIndicator,
@{N='objects';E={'(gm).PsTypeNames'}},
InputObject
Compare-Object $c $s -IncludeEqual |
Select-Object -Property SideIndicator,
@{N='objects';E={"$($c.GetType().Name) itself"}},
InputObject
Compare-Property -RefObject $c `
-DifObject $s -IncludeEqual:$IncludeEqual
Compare-Property -RefObject $c.PsObject `
-DifObject $s.PsObject -IncludeEqual:$IncludeEqual
}
输出:
D:\PShell\SO303102c.ps1
SideIndicator objects InputObject ------------- ------- ----------- == .GetType() System.Management.Automation.InformationRecord == .PsObject.TypeNames System.Management.Automation.InformationRecord == .PsObject.TypeNames System.Object == (gm).PsTypeNames System.Object[] == (gm).PsTypeNames System.Array == (gm).PsTypeNames System.Object => InformationRecord itself Silently <= InformationRecord itself Continue => Function Compare-Property Silently <= Function Compare-Property Continue => MessageData Silently <= MessageData Continue => MessageData.Value Silently <= MessageData.Value Continue == Function Compare-Property psobject {Members, Properties, Methods, Imme... => ImmediateBaseObject Silently <= ImmediateBaseObject Continue => ImmediateBaseObject.Value Silently <= ImmediateBaseObject.Value Continue => BaseObject Silently <= BaseObject Continue => BaseObject.Value Silently <= BaseObject.Value Continue