有没有办法强制将 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
瞧!