Windows PowerShellFiltrando e formatando dados

Don Jones

Não há dúvida de que o Windows PowerShell pode, sem muito esforço de sua parte, retornar um grande volume de informações importantes. Por exemplo, considere o simples cmdlet Get-WMIObject, o qual pode ser utilizado para retornar uma lista de serviços no computador local. A visualização padrão, a qual apresenta o status, o nome e o modo de inicialização dos

serviços em execução, é essencialmente uma visualização da linha de comando do console Serviços. O Windows PowerShell™ simplesmente facilita muito mais o acesso.

No entanto, há informações muito mais úteis disponíveis para serviços do que apenas as exibidas na visualização padrão. Tente executar este comando:

$s = get-wmiobject win32_service
$s[0] | gm

A primeira linha do comando retorna uma coleção de todos os serviços (ou, mais especificamente, todas as instâncias da classe Win32_Service da Instrumentação de Gerenciamento do Windows® ou WMI), armazenando-a na variável $s. A segunda linha utiliza o primeiro serviço nessa coleção (número zero ordinal, indicado em colchetes) e o canaliza para o cmdlet Get-Member, o qual abreviei usando o seu alias, gm. A saída resultante mostra todas as propriedades e métodos disponíveis para esse tipo de dados. Decidi utilizar a classe Win32_Service no WMI, em vez de o cmdlet Get-Service cmdlet interno no Windows PowerShell, pois na verdade o WMI expõe mais informações do que o objeto ServiceController do Microsoft® .NET, inclusive a propriedade StartName. Essa propriedade informa o nome da conta de usuário na qual o serviço está sendo executado. É possível verificar o nome de uma única instância, como a primeira, da seguinte forma:

PS C:\> $s[0].StartName
LocalSystem

No entanto, a consulta aos serviços pelo seu número ordinal na coleção não é muito útil, pois os serviços não estão em uma ordem determinada. (Geralmente, eles são apresentados em ordem alfabética, mas nem sempre.) De uma perspectiva do gerenciamento, é provável que você esteja mais interessado em uma lista com todos os serviços e a conta que cada um deles está utilizando para fazer logon. Digamos que isso seria útil, por exemplo, para uma auditoria de conformidade. Vamos fazer uma breve pausa e verificar o que a WMI está fornecendo por padrão. Utilizarei um alias Get-WMIObject abreviado, gwmi (consulte a Figura 1).

Figure 1 Usando o gwmi

PS C:\> gwmi win32_service

ExitCode  : 0
Name      : AcrSch2Svc
ProcessId : 1712
StartMode : Auto
State     : Running
Status    : OK

ExitCode  : 1077
Name      : Adobe LM Service
ProcessId : 0
StartMode : Manual
State     : Stopped
Status    : OK

Obviamente, esse é apenas um exemplo, mas é possível ver que a saída não é de fato ideal para um relatório de gerenciamento. As informações que quero obter são o nome do serviço e o StartName, que é a conta na qual o serviço está sendo executado. Além disso, quero que o relatório tenha um formato mais legível, em vez de uma lista com aparência um tanto desajeitada. É exatamente nesse ponto que os formidáveis cmdlets de formatação e filtros de dados do Windows PowerShell exercem sua função.

Como obter os dados necessários

Iniciarei filtrando os dados do Get-WMIObject, de forma que as propriedades nas quais estou interessado sejam exibidas. A melhor forma de fazer isso é utilizar o cmdlet Select-Object do Windows PowerShell ou seu simples alias, select. O alias select foi desenvolvido para aceitar uma coleção de objetos – como a coleção retornada pelo Get-WMIObject – e exibir apenas as propriedades desejadas desses objetos. Isso significa que posso canalizar a saída de gwmi para selecionar e especificar as duas propriedades nas quais estou interessado. A Figura 2 mostra os resultados, os quais incluem as propriedades Name e StartName formatadas perfeitamente como uma tabela.

Figura 2 Visualizando apenas as propriedades Name e StartName em uma tabela

Figura 2** Visualizando apenas as propriedades Name e StartName em uma tabela **(Clique na imagem para aumentar a exibição)

No entanto, se eu estivesse produzindo esse relatório para uma auditoria de conformidade, ele realmente teria muito mais informações. Alguns dos serviços estão desabilitados; portanto, provavelmente não importará para qualquer pessoa que ler a saída qual conta os serviços desabilitados teoricamente utilizariam. Por esse motivo, quero filtrar todos os serviços que tenham um tipo de inicialização Disabled – que é a propriedade StartMode da classe Win32_Service.

O Windows PowerShell executa a filtragem de objetos usando o cmdlet Where-Object ou seu alias abreviado, where. O cmdlet where aceita uma coleção de objetos de entrada e executa cada um deles por meio de um scriptblock, a fim de determinar se cada objeto estará presente ou não na saída do cmdlet com base em um conjunto de critérios definidos. Cada objeto que atender aos critérios produzirá uma comparação True e será incluído na saída; os objetos que produzirem um valor False não serão incluídos.

Dessa forma, defini que desejo somente objetos cuja propriedade StartMode seja igual a Disabled. Nos termos do Windows PowerShell, essa avaliação seria semelhante ao seguinte:

$object.StartMode –eq “Disabled”

É claro que $object é apenas um exemplo. Na verdade, não estou escrevendo um script e, portanto, não tenho uma variável nomeada $object. No entanto, no scriptblock utilizado pelo where, eu tenho o uso de uma variável especial nomeada $_, a qual representa o objeto sendo atualmente avaliado pelo cmdlet. Dessa forma, o meu scriptblock teria o seguinte formato:

$_.StartMode –eq “Disabled”

Posso testar isso facilmente:

PS C:\> gwmi win32_service | where 
{$_.StartMode -eq “Disabled”}

ExitCode  : 1077
Name      : Alerter
ProcessId : 0
StartMode : Disabled
State     : Stopped
Status    : OK

É claro, nesse rápido teste, a saída está aparecendo novamente no estilo de lista padrão. E, para conservar o espaço, incluí somente um serviço nesse exemplo. Porém, você observará que essa saída é retroativa. Incluí serviços desabilitados, em vez de excluí-los. Fiz isso devido ao fato de ter obtido retroativamente o meu scriptblock: eu preciso incluir todos os serviços nos quais o StartMode não é igual a Disabled, como mostrado pela seguinte modificação no meu exemplo:

PS C:\> gwmi win32_service | where 
{$_.StartMode -ne “Disabled”}

ExitCode  : 0
Name      : AcrSch2Svc
ProcessId : 1712
StartMode : Auto
State     : Running
Status    : OK

Isso é melhor! Agora que a saída contém somente os serviços nos quais estou de fato interessado, posso novamente canalizá-la para selecionar e especificar apenas as propriedades que desejo:

gwmi win32_service | where {$_.StartMode -ne “Disabled”} | select name,startname

Esse recurso de canalizar os dados de um cmdlet para outro e ainda para outro realmente ilustra os recursos do Windows PowerShell. Ainda não escrevi um script, mas já executei a filtragem em um complexo conjunto de dados para obter somente a saída que desejo.

A aparência correta

Você deve ter em mente que a saída de select ainda consiste em vários objetos. Quando tento recuperar uma tabela perfeitamente formatada usando o Windows PowerShell, isso é na realidade a reprodução do PowerShell.exe desses objetos. Em outras palavras, o Windows PowerShell sabe que eu, como um mero humano, não posso visualizar os objetos; portanto, ele os processa como texto. Nesse caso, ele processou os objetos como uma tabela, com uma coluna para cada propriedade, como ilustrado na Figura 2.

Isso seria suficiente para os meus objetivos de auditoria. Mas, por outro lado, talvez não. Cada pessoa tem necessidades diferentes – o Windows PowerShell não pode presumir quais sejam essas necessidades específicas. Em vez disso, ele oferece as ferramentas para que você formate a saída do modo que lhe seja mais conveniente. Quatro cmdlets internos – Format-List, Format-Custom, Format-Table e Format-Wide – foram desenvolvidos para aceitar uma coleção de objetos (como a coleção retornada por select) e formatar tais objetos de várias formas. O Format-Table é basicamente o que o Windows PowerShell já utiliza para formatar a saída do meu cmdlet select. Para obter uma aparência diferente, vamos tentar o Format-List:

gwmi win32_service | where {$_.StartMode -ne “Disabled”} | 
select name,startname | format-list

O resultado é de certa forma semelhante a este exemplo:

name      : AcrSch2Svc
startname : LocalSystem

name      : Adobe LM Service
startname : LocalSystem

O cmdlet Format-Wide foi desenvolvido para produzir uma lista com várias colunas, por padrão, da primeira propriedade de cada objeto. Por exemplo, utilize esta linha:

gwmi win32_service | where {$_.StartMode -ne “Disabled”} |
 select name,startname | format-wide

Ela produz uma lista de nomes de serviço, que não é o que eu desejo. A saída não apresenta o StartName (consulte a Figura 3), que é uma parte importante da informação que eu preciso no meu relatório de auditoria.

Figura 3 A saída exibida usando o cmdlet Format-Wide omite a principal informação – o StartName

Figura 3** A saída exibida usando o cmdlet Format-Wide omite a principal informação – o StartName **(Clique na imagem para aumentar a exibição)

Como estou lidando somente com duas propriedades, é provável que Format-Table ou Format-List seja aceitável. Mas é improvável que uma auditora fique satisfeita em visualizar essas informações na tela. Ela provavelmente preferiria um arquivo de algum tipo.

Exportando dados

Sendo assim, como um auditor gostaria de visualizar os dados? A saída da lista de serviços e nomes de login em um arquivo CSV (Comma-Separated Values, valores separados por vírgulas) deve ser suficiente, pois o arquivo pode ser facilmente aberto no Microsoft Excel®. Para criar um arquivo CSV, basta canalizar a sua saída para um cmdlet Export-CSV do Windows PowerShell:

gwmi win32_service | where {$_.StartMode -ne “Disabled”} | 
select name,startname | export-csv c:\services.csv

É claro que no mundo atual o CSV parece um pouco desatualizado. Talvez os seus auditores prefiram que os dados sejam exibidos como uma página da Web em um servidor de intranet. Para fazer isso, comece convertendo a saída para HTML, usando o cmdlet ConvertTo-HTML:

gwmi win32_service | where {$_.StartMode -ne “Disabled”} | 
select name,startname | convertto-html

O formato HTML bruto é de difícil visualização; portanto, precisarei escrever a saída em um arquivo:

gwmi win32_service | where {$_.StartMode -ne “Disabled”} | 
select name,startname | convertto-html | out-file c:\services.html

O resultado, mostrado na Figura 4, é uma página HTML bem formatada, a qual pode ser divulgada em qualquer servidor da Web sem a necessidade de modificações adicionais.

Figura 4 A saída exibida como uma página HTML bem formatada

Figura 4** A saída exibida como uma página HTML bem formatada **(Clique na imagem para aumentar a exibição)

Apenas os fatos (relevantes)

O Windows PowerShell oferece fácil acesso a uma ampla variedade de dados de gerenciamento. No entanto, em seu estado bruto, esses dados nem sempre são úteis do ponto de vista dos negócios.

Ao filtrar os dados (usando where), escolher as propriedades desejadas do objeto (usando select) e aplicar uma opção de formato apropriada (como Format-Table ou Format-List), você pode rapidamente transformar esses dados de gerenciamento em informações úteis com muito pouco esforço. E, finalmente, exportando os dados para um formato de arquivo que possa ser facilmente compartilhado, você pode usar essas informações além da sua área de trabalho e comunicar informações importantes a outras pessoas na sua empresa.

Don Jones é o diretor de projetos e serviços da SAPIEN Technologies e co-autor do Windows PowerShell: TFM (SAPIEN Press). Entre em contato com Don em seu site em www.ScriptingAnswers.com.

© 2008 Microsoft Corporation e CMP Media, LLC. Todos os direitos reservados. A reprodução parcial ou completa sem autorização é proibida..