【问题标题】:PowerShell output is crossing between functionsPowerShell 输出在函数之间交叉
【发布时间】:2017-04-28 21:41:28
【问题描述】:

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

这两个功能是:

    # 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

当我在getRunningProcesses 之后调用getUsersAndGroups 时,输出如下所示(根本不输出getUsersAndGroups):

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:

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

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

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

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 ------------

非常感谢您的帮助!

【问题讨论】:

  • 我认为问题主要来自“Write-Host is not output”
  • This 可能会有所帮助。
  • @MikeShepard 说了什么。 getRunningProcesses|ftgetUsersAndGroups|ft 如果您希望输出单独格式化(提示:ftFormat-Table 的别名)
  • @MikeShepard:这通常是正确的,但它不能解释 OP 的症状。事实上,Write-Hosts同步 输出有助于追踪这种情况下的问题。
  • 不要越过溪流!

标签: powershell


【解决方案1】:

tl;博士:

使用Out-Host 强制同步输出 到控制台

getUsersAndGroups | Out-Host
getRunningProcesses | Out-Host

注意:您也可以使用Format-* cmdlet 之一,它也强制同步输出;例如,getUsersAndGroups | Format-Table

内部 PowerShell 会话

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

  • 警告:发送到Out-Host 意味着无法再捕获或重定向命令的输出;请参阅 this answer 了解 - 次优 - 解决方法。

从外部,调用 PowerShell 时 CLIpowershell -file ...powershell -command ...

  • 如果使用Out-Host,可能会发生实际数据丢失,因为如果脚本/命令以exit 结尾,挂起的异步输出可能永远无法打印;例如:

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

注意:以上所有内容也适用于 PowerShell (Core) 7+ 及其 pwsh CLI,至少为 v7.2。


本案例中 PowerShell 问题行为的解释

使用MCVE (Minimal, Complete, and Verifiable Example) 演示问题可能会有所帮助:

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-Host 绕过了正常的成功输出流,并且(实际上)直接写入控制台 - mostly, even though there are legitimate uses, Write-Host should be avoided

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

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

    • 最初生成了一个空白行。
    • 所有实际输出跟随最终的Write-Host 调用。

This helpful answer 解释了为什么会发生这种情况;简而言之:

  • 隐式输出是根据输出对象的类型进行格式化的;在本例中,隐式使用了Format-Table

  • Psv5+ 中,隐式应用 Format-Table 现在等待长达 300 毫秒。为了确定合适的列宽

    • 但是请注意,这仅适用于类型为table-formatting instructions 的输出对象未预定义;如果是,它们会提前确定列宽,并且不会发生等待。

    • 要测试全名<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)或提示用户输入before Format-Table 输出开始。

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

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


注意:这个答案最初错误地“归咎于”PSv5+ 300 毫秒。延迟可能令人惊讶的标准输出格式化行为(即发送到管道的 first 对象确定管道中 all 对象的显示格式,如果应用了表格格式 - 请参阅this answer)。

【讨论】:

  • 因为我需要将其全部输出到文件中,因此我完全删除了 Write-Host。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-31
  • 2020-01-31
相关资源
最近更新 更多