Existe alguma maneira de forçar a saída de um script do PowerShell v3 para a forma tabular? Meu script está gerando uma lista de serviços em formato linear, embora haja apenas 6 campos no objeto de saída (get-process gera 8 campos em formato tabular). Aqui está o meu código:
<#
.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
}
}
Quando um ou mais objetos se aproximam do host, o PowerShell verifica o número de propriedades que o objeto possui.
Se o tipo de um objeto puder ser resolvido para um
Format.ps1xml
arquivo correspondente (voltaremos a isso em um minuto), a convenção de formatação descrita naquele documento será usada - caso contrário, dependerá do número de propriedades que um objeto possui.Se um objeto tiver menos de 5 propriedades, o padrão é usar
Format-Table
para formatação de saída:Se um objeto tiver mais propriedades, o padrão é
Format-List
(que é o que você experimenta):Agora, a razão pela qual os objetos retornados do cmdlet
Get-Service
orGet-Process
parecem formatar em uma tabela agradável, contextualmente relevante e com mais de 5 colunas é que o PowerShell conseguiu encontrar um documento de formatação específico do tipo para eles.Esses arquivos de formatação estão todos localizados no diretório de instalação do PowerShell, você pode localizar os arquivos padrão com:
Veja
Get-Help about_Format.ps1xml
se você deseja criar seus próprios arquivos de formato.A maneira como o PowerShell estabelece um vínculo entre o tipo de um objeto e as exibições de formatação definidas é inspecionando a
pstypenames
propriedade oculta:O PowerShell simplesmente examina essa lista ancestral de tipos para ver se ela possui uma exibição de formatação correspondente para esse tipo.
Isso significa que você pode enganar o PowerShell para formatar um objeto como se fosse de outro tipo, sem realmente interferir no sistema de tipo .NET subjacente.
Para mostrar isso, vamos criar um controlador de serviço falso - um objeto que parece que algo
Get-Service
poderia ter retornado, mas na verdade não é:Conforme descrito acima, o PowerShell mostra a saída de
Format-List
desde quepsobject
tem 5 propriedades.Agora, vamos tentar injetar um nome de tipo:
Voilá!