强制以表格形式输出 Powershell 脚本

强制以表格形式输出 Powershell 脚本

有没有办法强制将 PowerShell v3 脚本的输出转换为表格形式?我的脚本以线性形式输出服务列表,即使输出对象中只有 6 个字段(get-process 以表格形式输出 8 个字段)。这是我的代码:

<#
.SYNOPSIS
Gets a list of services on a given computer that are supposed to automatically start but are not currently running.
.PARAMETER ComputerName
The computer name(s) to retrieve the info from.
.PARAMETER IgnoreList
The path and filename of a text file containing a list of service names to ignore.  This file has to list actual service names and not display names.  Defaults to "StoppedServices-Ignore.txt" in the current directory.
.PARAMETER StartServices
Optional switch that when specified will cause this function to attempt to start all of the services it finds stopped.
.EXAMPLE
Get-StoppedServices -ComputerName Computer01 -IgnoreList '.\IgnoredServices.txt' -StartServices
.EXAMPLE
Get-StoppedServices –ComputerName Computer01,Computer02,Computer03
.EXAMPLE
"Computer01" | Get-StoppedServices
.EXAMPLE
Get-StoppedServices –ComputerName (Get-Content ComputerList.txt)
.EXAMPLE
Get-Content ComputerList.txt | Get-StoppedServices -IgnoreList '.\IgnoredServices.txt' -StartServices
#>
Function Get-StoppedServices {
  [CmdletBinding()]
  param(
    [Parameter(Position=0,Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)] [String[]]$ComputerName,
    [string]$IgnoreList,
    [switch]$StartServices
  )
  PROCESS {
    # Load the list of services to ignore (if specified).
    if ($IgnoreList) {
      if (Test-Path $IgnoreList) {
        $ignore = import-csv -header Service $IgnoreList
        Write-Verbose "Ignoring the following services:"
        Write-Verbose $ignore.ToString()
      } else {
        Write-Warning "Could not find ignore list $IgnoreList."
      }
    }

    # Get a list of stopped services that are set to run automatically (ie: that should be running)
    foreach ($c in $ComputerName) {
      Write-Verbose "Getting services from $($c.Name)"
      if (Test-Connection -ComputerName $c -Count 1 -Quiet) {
        Try {
          $serv += get-wmiobject -query "Select __Server,Name,DisplayName,State,StartMode,ExitCode,Status FROM Win32_Service WHERE StartMode='Auto' AND State!='Running'" -computername $c -erroraction stop
        } catch {
          Write-Warning "Could not get service list from $($c)"
        }
      }
    }

    # Create the resulting list of services by removing any that are in the ignore list.
    $results = @()
    foreach ($s in $serv) {
      Write-Verbose "Checking if $($s.name) in ignore list."
      if ($ignore -match $s.name) { 
        Write-Verbose "  *Service in ignore list."
      } else {
        Write-Verbose "  Service OK."
        $obj = New-Object -typename PSObject
        $obj | Add-Member -membertype NoteProperty -name ComputerName -value ($s.PSComputerName) -passthru |
               Add-Member -membertype NoteProperty -name ServiceName  -value ($s.Name)           -passthru |
               Add-Member -membertype NoteProperty -name DisplayName  -value ($s.DisplayName)    -passthru |
               Add-Member -membertype NoteProperty -name Status       -value ($s.Status)         -passthru |
               Add-Member -membertype NoteProperty -name State        -value ($s.State)          -passthru |
               Add-Member -membertype NoteProperty -name ExitCode     -value ($s.ExitCode)
        $results += $obj
      }
    }

    # Try and start each of the stopped services that hasn't been ignored.
    if ($StartServices) {
      foreach ($s in $results) {
        Write-Verbose "Starting '$($s.DisplayName)' ($($s.name)) on '$($s.ComputerName)..."
        Try {
          Get-Service -Name $s.name -ComputerName $s.ComputerName -erroraction stop | Start-service -erroraction stop
        } Catch {
          Write-Warning "Could not start service $($s.name) on $($s.ComputerName)."
        }
      }  
    }

    # Output the list of filtered services to the pipeline.
    write-output $results
  }
}

答案1

当一个或多个对象冒泡到主机时,PowerShell 会查看该对象具有的属性数量。

如果对象的类型可以解析为相应的Format.ps1xml文件(我们稍后会回到这个问题),则将使用该文档中描述的格式约定 - 否则,它取决于对象具有的属性数量。


如果对象具有少于 5 个属性,则默认使用Format-Table输出格式:

PS C:\> New-Object psobject -Property ([ordered]@{PropA=1;PropB=2;PropC=3;PropD=4})

PropA PropB PropC PropD
----- ----- ----- -----
    1     2     3     4

如果一个对象有更多的属性,它默认为Format-List(这是您所体验到的):

PS C:\> New-Object psobject -Property ([ordered]@{PropA=1;PropB=2;PropC=3;PropD=4;PropE=5})


PropA : 1
PropB : 2
PropC : 3
PropD : 4
PropE : 5

Get-Service现在,从或cmdlet返回的对象Get-Process似乎格式化为一个良好的、上下文相关的、超过 5 列的表的原因是 PowerShell 能够为它们找到特定类型的格式化文档。

这些格式化文件都位于 PowerShell 安装目录中,您可以使用以下命令找到默认文件:

Get-ChildItem $PSHome *.Format.ps1xml

看看Get-Help about_Format.ps1xml您是否想创建自己的格式文件。


PowerShell 通过检查隐藏属性来建立对象类型和定义的格式视图之间的链接pstypenames

PS C:\> $obj.pstypenames
System.Management.Automation.PSCustomObject
System.Object

PowerShell 只是深入研究这个祖先类型列表,以查看它是否具有该类型的对应格式视图。

这意味着您可以欺骗 PowerShell 将对象格式化为其他类型,而无需实际干预底层 .NET 类型系统。

为了说明这一点,让我们创建一个假的服务控制器 - 一个看起来像是Get-Service可以返回某些东西但实际上并非如此的对象:

PS C:\> $FauxService = New-Object psobject -Property @{
>>>   "Name"        = "FakeService3000"
>>>   "Status"      = "Faking"
>>>   "DisplayName" = "TrustworthyService"
>>>   "TrueName"    = "Really a fake"
>>>   "Author"="Clever Genius"
>>> }
PS C:\> $FauxService


Status      : Faking
Name        : FakeService3000
Author      : Clever Genius
DisplayName : TrustworthyService
TrueName    : Really a fake

如上所述,PowerShell 显示的输出,Format-List因为我们的psobject有 5 个属性。

现在,让我们尝试注入一个类型名称:

PS C:\> $FauxService.pstypenames.Insert(0,"System.ServiceProcess.ServiceController")
PS C:\> $FauxService

Status   Name               DisplayName
------   ----               -----------
Faking   FakeService3000    TrustworthyService

瞧!

相关内容