PowerShell 输出在函数之间交叉

PowerShell output is crossing between functions

提问人:scriptkiddie 提问时间:4/29/2017 最后编辑:mklement0scriptkiddie 更新时间:9/14/2023 访问量:1219

问:

我正在 Windows 10 上编写 5.1 版的 PowerShell 脚本,该脚本获取有关本地系统(以及最终其子网)的某些信息,并将它们输出到文本文件中。起初,我将所有方面都集中在一个函数中。我在输出和函数时遇到了输出问题,其中输出将被注入到 .getUsersAndGroupsgetRunningProcessesgetUsersAndGroupsgetRunningProcesses

这两个功能是:

    # Powershell script to get various properties and output to a text file

    Function getRunningProcesses()
    {
        # Running processes
        Write-Host "Running Processes:
    ------------ START PROCESS LIST ------------
        "
        Get-Process | Select-Object name,fileversion,productversion,company
        Write-Host "
    ------------- END PROCESS LIST -------------
    "
    }

    Function getUsersAndGroups()
    {
        # Get Users and Groups
        Write-Host "Users and Groups:"
        $adsi = [ADSI]"WinNT://$env:COMPUTERNAME"
        $adsi.Children | where {$_.SchemaClassName -eq 'user'} | Foreach-Object {
            $groups = $_.Groups() | Foreach-Object {$_.GetType().InvokeMember("Name", 'GetProperty', $null, $_, $null)}
            $_ | Select-Object @{n='Username';e={$_.Name}},@{n='Group';e={$groups -join ';'}}
        }
    }

    getRunningProcesses
    getUsersAndGroups

当我调用之后,输出如下所示(根本不输出):getUsersAndGroupsgetRunningProcessesgetUsersAndGroups

Running Processes:
        ------------ START PROCESS LIST ------------


Name                FileVersion                                       ProductVersion Company                    
----                -----------                                       -------------- -------                    
armsvc                                                                                                          
aswidsagenta                                                                                                    
audiodg                                                                                                         
AVGSvc                                                                                                          
avgsvca                                                                                                         
avguix              1.182.2.64574                                     1.182.2.64574  AVG Technologies CZ, s.r.o.               
conhost             10.0.14393.0 (rs1_release.160715-1616)            10.0.14393.0   Microsoft Corporation      
csrss                                                                                                           
csrss                                                                                                           
dasHost                                                                                                         
dwm                                                                                                             
explorer            10.0.14393.0 (rs1_release.160715-1616)            10.0.14393.0   Microsoft Corporation      
hkcmd               8.15.10.2900                                      8.15.10.2900   Intel Corporation          
Idle                                                                                                            
igfxpers            8.15.10.2900                                      8.15.10.2900   Intel Corporation          
lsass                                                                                                           
MBAMService                                                                                                     
mDNSResponder                                                                                                   
Memory Compression                                                                                              
powershell_ise      10.0.14393.103 (rs1_release_inmarket.160819-1924) 10.0.14393.103 Microsoft Corporation      
RuntimeBroker       10.0.14393.0 (rs1_release.160715-1616)            10.0.14393.0   Microsoft Corporation      
SearchFilterHost                                                                                                
SearchIndexer                                                                                                   
SearchProtocolHost                                                                                              
SearchUI            10.0.14393.953 (rs1_release_inmarket.170303-1614) 10.0.14393.953 Microsoft Corporation      
services                                                                                                        
ShellExperienceHost 10.0.14393.447 (rs1_release_inmarket.161102-0100) 10.0.14393.447 Microsoft Corporation      
sihost              10.0.14393.0 (rs1_release.160715-1616)            10.0.14393.0   Microsoft Corporation           
smss                                                                                                            
spoolsv                                                                                                         
sqlwriter                                                                                                       
svchost                                                                                                         
svchost                                                                                                         
svchost                                                                                                         
svchost                                                                                                         
svchost                                                                                                         
svchost                                                                                                         
svchost                                                                                                         
svchost                                                                                                         
svchost                                                                                                         
svchost                                                                                                         
svchost                                                                                                         
svchost                                                                                                         
svchost                                                                                                         
svchost                                                                                                         
svchost                                                                                                         
svchost             10.0.14393.0 (rs1_release.160715-1616)            10.0.14393.0   Microsoft Corporation      
System                                                                                                          
taskhostw           10.0.14393.0 (rs1_release.160715-1616)            10.0.14393.0   Microsoft Corporation      
ToolbarUpdater                                                                                                  
wininit                                                                                                         
winlogon                                                                                                        
WtuSystemSupport                                                                                                
WUDFHost                                                                                                        

        ------------ END PROCESS LIST ------------

Users and Groups:

当我在输出注入之前调用时,更糟糕的是,根本没有列出正在运行的进程,而是列出了很多空行。getUsersAndGroupsgetRunningProcessesgetUsersAndGroupsgetRunningProcesses

如何分离或控制输出,使其在输出之前输出?getUsersAndGroupsgetRunningProcesses

注入输出的输出如下所示:

Running Processes:
        ------------ START PROCESS LIST ------------

Username       Group                                                      
--------       -----                                                      
Administrator  Administrators                                             
debug255       Administrators;Hyper-V Administrators;Performance Log Users
DefaultAccount System Managed Accounts Group                              
Guest          Guests                                                     




































































        ------------ END PROCESS LIST ------------

非常感谢您的帮助!

PowerShell 控制台输出

评论

2赞 Mike Shepard 4/29/2017
我认为问题主要出在“Write-Host is not output”上
0赞 mklement0 4/29/2017
这可能会有所帮助。
1赞 Mathias R. Jessen 4/29/2017
@MikeShepard说的。 如果您希望单独格式化输出(提示:是getRunningProcesses|ftgetUsersAndGroups|ftftFormat-Table)
0赞 mklement0 4/29/2017
@MikeShepard:一般来说是正确的,但这并不能解释OP的症状。事实上,在这种情况下,的同步输出有助于跟踪问题。Write-Hosts
0赞 js2010 12/15/2019
不要越过溪流!

答:

16赞 mklement0 4/29/2017 #1

TL的;博士:

基础问题会影响 Windows PowerShell 和 PowerShell (Core) 7+,至少为 v7.3.4(在撰写本文时是最新的),并且由于它是设计行为的(不幸的)副作用,因此可能会也可能不会得到修复。

若要防止输出出现乱序,请通过显式调用 Format-Table 或 Out-Host 强制同步显示输出:

getUsersAndGroups | Format-Table
getRunningProcesses | Format-Table

两者都解决了主要的显示问题,但它们都是次优解决方案,因为它们都干扰了作为数据提供的输出Format-TableOut-Host

  • Format-Table输出格式化指令而不是数据,这仅对 PowerShell 的显示输出格式化系统有意义,即当输出转到显示器或其中一个 cmdlet 时,特别是包括 和 因此也 .生成的格式不适合编程处理。Out-*Out-File>

  • Out-Host完全不输出任何数据直接打印到显示器上,无法捕获或重定向数据。

相关 GitHub 问题


背景资料:

PowerShell 会话中

  • 主要是一个显示问题,您不需要此解决方法来捕获变量中的输出、将其重定向到文件或通过管道传递它。

  • 对于依赖显示输出按输出顺序显示的交互式脚本,您确实需要它,这主要包括确保在显示交互式提示之前打印相关信息;例如:

      # !! Without Format-table, the prompt shows *first*.
      [pscustomobject] @{ foo = 1; bar = 2 } | Format-Table
      Read-Host 'Does the above look OK?'
    

从外部调用 PowerShell CLI(powershell -file ... 或 powershell -command ...时:

  • 如果不使用 Out-Host,可能会发生实际数据丢失,因为如果脚本/命令以 - 请参阅 GitHub issue #13985;例如:exit

    # !! Prints only 'first'
    powershell.exe -command "'first'; [pscustomobject] @{ foo = 'bar' }; exit"
    
  • 但是,与 PowerShell 会话内使用不同,Format-TableOut-Host 修复了显示数据捕获/重定向问题,因为即使 的输出也会发送到 stdout,如外部调用方所看到的那样(但请注意,PowerShell 的输出格式化系统生成的 for-display 表示形式通常不适合编程处理)。[1]Out-Host

注意:以上所有内容同样适用于 PowerShell (Core) 7+ 及其 pwsh CLI,最高可达 v7.3.1。


在这种情况下,PowerShell 的问题行为的说明

使用 MCVE(最小、完整和可验证示例)演示问题可能会有所帮助:

Write-Host "-- before"
[pscustomobject] @{ one = 1; two = 2; three = 3 }
Write-Host "-- after"

在 PSv5+ 中,这将产生:

-- before

-- after
one two three
--- --- -----
  1   2     3

发生了什么事?

  • 调用同步生成输出Write-Host

    • 值得注意的是,它绕过了正常的成功输出流,并(实际上)直接写入控制台 - 大多数情况下,即使有合法用途,也应避免使用 Write-HostWrite-Host

    • 但是,请注意,即使是发送到成功输出的输出对象也可以同步显示,并且经常显示,特别是作为基元 .NET 类型(如字符串和数字)实例的对象,以及其隐式输出格式导致非表格输出的对象,以及具有与其关联的显式格式数据的类型(见下文)。

  • 隐式输出 - 由于未捕获语句的输出 - 出乎意料地不同步[pscustomobject] @{ one = 1; two = 2; three = 3 }

    • 最初生成了一行空行。
    • 所有实际输出都遵循最终调用。Write-Host

这个有用的答案解释了为什么会发生这种情况;总之:

  • 隐式输出的格式基于要输出的对象的类型;在手头的情况下,是隐式使用的。Format-Table

  • Psv5+ 中,隐式应用的 Format-Table 现在最多等待 300 毫秒,以确定合适的列宽

    • 但请注意,这仅适用于其类型表格式化指令预定义的输出对象;如果是,提前确定列宽,并且不会发生等待。

    • 若要测试具有全名的给定类型是否具有与之关联的表格式数据,可以使用以下命令:<FullTypeName>

          # Outputs $true, if <FullTypeName> has predefined table-formatting data.
          Get-FormatData <FullTypeName> -PowerShellVersion $PSVersionTable.PSVersion |
            Where-Object { 
              $_.FormatViewDefinition.Control.ForEach('GetType') -contains [System.Management.Automation.TableControl] 
            }
      
  • 不幸的是,这意味着后续命令在该时间窗口内执行,并可能产生不相关的输出(通过管道绕过输出命令,如 Write-Host)或在格式表输出开始之前提示用户输入。

    • 当从外部调用 PowerShell CLI 并在时间窗口内调用时,将有效丢弃所有挂起的输出(包括后续的同步输出)。exit

GitHub 问题 #4594 中讨论了有问题的行为;虽然仍有解决方案的希望,但很长一段时间都没有活动。


注意:此答案最初错误地将 PSv5+ 300 毫秒延迟归咎于可能令人惊讶的标准输出格式行为(即,如果应用了表格式,则发送到管道的第一个对象决定了管道中所有对象的显示格式 - 请参阅此答案)。


[1] CLI 允许您使用 -OutputFormat XML 以结构化文本格式请求输出,即基于 XML 的序列格式(称为 CLIXML)。PowerShell 后台使用这种格式跨进程序列化数据,外部程序通常不知道这种格式,这就是为什么在实践中很少使用 -OutputFormat Xml 的原因。请注意,当您使用它时,格式化表/主机解决方法将再次无效,因为原始输出对象已丢失。

评论

1赞 scriptkiddie 5/1/2017
因为我需要全部输出到一个文件中,所以出于这个原因,我完全删除了 Write-Host。谢谢!