Ei, Equipe de Scripts!Os trabalhos mais simples também têm suas recompensas

The Microsoft Scripting Guys

Faça o download do código deste artigo:: HeyScriptingGuy2008_06.exe (150KB)

Durante centenas de anos, as pessoas acreditaram que o trabalho árduo compensa; um dia de trabalho honesto produz uma grande satisfação; a verdadeira felicidade está no fim, e não no meio; o... bem, acho que já deu para entender. Trabalhe arduamente e sem reclamar (lembre-se da Cinderela) que, um dia, será recompensado.

Observação: será que é verdade que se você trabalhar muito não será apenas feliz, mas, um dia, seus esforços também serão recompensados? Por que você está perguntando isso para nós?

É claro que Cinderela teve sorte; afinal, se você mora com uma madrasta malvada e duas meias-irmãs perversas, terá muitas oportunidades de trabalhar muito. Mas e se você não tiver tanta sorte assim? E se você não viver com uma madrasta malvada e duas meias-irmãs perversas? O que fará para receber a graça de ter longos e exaustivos dias de trabalho? Como encontrará a verdadeira felicidade?

Bem, se você estiver compelido e determinado a trabalhar muito, a Equipe de Scripts sugere que tente escrever um script que gere dados de saída bem-acabados, organizados e em formato tabular, como a saída mostrada na Figura 1.

Figura 1 Saída tabular

Figura 1** Saída tabular **(Clique na imagem para uma visão ampliada)

Como dissemos, Cinderela era muito afortunada: tinha de limpar a casa de cima a baixo e, quando terminava, tinha de descansar no chão da fornalha, em meio às cinzas e à fuligem. Mas até mesmo Cinderela se recusaria a escrever um script que exibisse dados em um formato tabular. Descansar sobre as cinzas e a fuligem não é nada agradável. Mas escrever um script que gera dados de saída em formato tabular é muito pior!

Observação: bem, a menos que você tenha de se sentar no chão da fornalha para escrever os scripts; aí, dá na mesma.

Por que Cinderela se recusaria a fazer essa tarefa? Por que não é brincadeira! A única maneira de exibir dados em um formato tabular em VBScript é fazer algo com estas linhas:

  • Comece determinando o tamanho máximo para cada coluna. Por exemplo, você pode querer exibir o nome de um serviço para preencher 52 espaços de caracteres.
  • Em seguida, tem de calcular o número de caracteres em um trecho de dados. Por exemplo, o nome de exibição Adobe LM Service possui 16 caracteres.
  • Se o nome de exibição exceder o limite de 52 caracteres, determine o número de caracteres que precisam ser cortados no fim da cadeia de caracteres para que ela se encaixe no espaço alocado. Se o nome de exibição não exceder o limite de 52 caracteres, determine quantos espaços em branco devem ser adicionados ao fim da cadeia de caracteres para que o comprimento seja exatamente de 52 caracteres.
  • Repita o procedimento para próximo o conjunto de dados. E o seguinte. E assim por diante.

Se você conhece a história de Cinderela, então sabe que sua fada madrinha pode aparecer de repente, transformar um mouse em um administrador de sistemas (nem vou dizer como é fácil isso acontecer) para que ele escreva o script para você. Mas talvez você não deva contar muito com isso. Provavelmente, está sozinho nessa.

Pensando no lado bom, você se sentirá a pessoa mais realizada do mundo. Isso porque também será a pessoa mais esforçada do mundo. A mais esforçada disparado.

É claro que há quem troque um pouco dessa satisfação pela oportunidade de não ter de trabalhar tanto. Se você concorda com isso, deve estar pensando: "Graças a Deus que a Equipe de Scripts existe; ela me diz como transformar um mouse em um administrador de sistemas para que ele formate a minha saída em uma tabela". Bem, temos más notícias para você: a Equipe de Scripts não faz a menor idéia de como transformar um mouse em um administrador de sistemas (embora saiba como transformar um administrador de sistemas em um covarde, se isso lhe interessa). Não sabemos o que você deve fazer para que alguém escreva scripts para você, muito menos com dados de saída em formato tabular.

Mas não tem problema. Contanto que execute o Windows® XP ou Windows Server® 2003 (que é o caso da maioria), você não precisa que um mouse escreva os scripts para você. (Não, lamentamos, mas isso não funciona no Windows Vista®.) Em vez disso, você pode fazer o trabalho sozinho, e com o mínimo de esforço, graças ao objeto Microsoft.CmdLib. Veja o script de exemplo na Figura 2.

Figure 2 Criando uma exibição tabular

Dim arrResultsArray()
i = 0

Set objCmdLib = _
  CreateObject("Microsoft.CmdLib")
Set objCmdLib.ScriptingHost = _
  WScript.Application

arrHeader = Array("Display Name", _
  "State", "Start Mode")
arrMaxLength = Array(52, 12, 12)
strFormat = "Table"
blnPrintHeader = True
arrBlnHide = Array(False, False, False)

strComputer = "."

Set objWMIService = GetObject("winmgmts:\\" _
  & strComputer & "\root\cimv2")

Set colServices = objWMIService.ExecQuery _
  ("Select * FROM Win32_Service")

For Each objService In colServices
  ReDim Preserve arrResultsArray(i)
  arrResultsArray(i) = _
  Array(objService.DisplayName, _
    objService.State,objService.StartMode)
  i = i + 1
Next
objCmdLib.ShowResults arrHeader, _
  arrResultsArray, arrMaxLength, _
  strFormat, blnPrintHeader, arrBlnHide

Caso não saiba, Microsoft.CmdLib é um objeto COM que acompanha o Windows XP e o Windows Server 2003. Esse objeto apresenta diversos recursos; para obter mais informações, digite cmdlib.wsc /? no prompt de comando e leia os comentários no arquivo de script que é aberto na tela. Hoje, estamos interessados em apenas um recurso do Microsoft.CmdLib: a capacidade de exibir dados em um formato tabular.

Isso levanta uma questão óbvia: como exibir dados em um formato tabular? Vejamos se você consegue adivinhar. Como pode ver, nosso script de exemplo começa definindo uma matriz dinâmica chamada arrResultsArray:

Dim arrResultsArray()

Em um script comum, os dados são reproduzidos na tela com a mesma rapidez que são recuperados. Mas você acha que a Equipe de Scripts faria algo de forma usual? Neste script, não iremos reproduzir os dados assim que são recuperados. Iremos armazenar todos os dados retornados em uma matriz e permitir que Microsoft.CmdLib os formate e os exiba para nós.

Em outras palavras, é por isso que começamos criando uma matriz dinâmica (quer dizer, uma matriz que pode ser redimensionada no decorrer do script). Depois de definir a matriz, especificamos 0 como o valor de uma variável de contador chamada i; usaremos essa variável para controlar o tamanho atual da matriz.

Caso esteja curioso, definimos o valor de i como 0 porque o primeiro item em uma matriz sempre recebe o número de índice 0. Conseqüentemente, quando adicionamos o primeiro item à matriz, adicionamos o item 0 em vez de 1.

Em seguida, precisamos inicializar a instância do objeto Microsoft.CmdLib; é o que estas duas linhas de código fazem:

Set objCmdLib = _
CreateObject("Microsoft.CmdLib")
Set objCmdLib.ScriptingHost = WScript.Application

E isso nos leva a este pequeno bloco de código:

arrHeader = Array("Display Name", "State", "Start Mode")
arrMaxLength = Array(52, 12, 12)
strFormat = "Table"
blnPrintHeader = True
arrBlnHide = Array(False, False, False)

Fazemos isso para definir alguns parâmetros de configuração da saída. Na primeira linha, atribuímos valores a uma matriz chamada arrHeader; como era de se esperar, eles são os cabeçalhos de cada coluna em nossa tabela de saída. Para este script de exemplo, iremos recuperar as informações sobre os serviços executados em um computador e, depois, exibiremos os valores das propriedades DisplayName, State e StartMode para cada serviço.

Obviamente, atribuímos à matriz os nomes de coluna Display Name, State e Start Mode (embora pudéssemos ter-lhes atribuído também os nomes A, B e C, Larry, Moe e Curly ou qualquer um que desejássemos; os nomes de coluna não precisam ser iguais aos nomes de propriedade).

Observação: há muitas versões da história da Cinderela, inclusive os nomes das meias-irmãs. Na versão da Disney da Cinderela, as meias-irmãs se chamam Drizela e Anastácia, que por acaso é o primeiro e segundo nomes da nossa Editora de Scripts!

Na segunda linha do código, atribuímos valores a outra matriz chamada arrMaxLength. Essa matriz mantém o tamanho de cada coluna na tabela. Na saída, queremos alocar 52 espaços de caracteres à coluna 1 (o nome de exibição do serviço); depois, queremos alocar 12 espaços ao estado de serviço e 12 ao modo de início (o Microsoft.CmdLib irá inserir automaticamente um espaço em branco entre as colunas). Para que o tamanho das colunas seja de 52, 12 e 12 espaços de caracteres (como desejamos), usamos este código:

arrMaxLength = Array(52, 12, 12)

A terceira linha especifica o formato de saída para nossos dados. Queremos que os dados sejam exibidos como uma tabela; assim, definimos o valor de strFormat (a variável que mantém o tipo de saída), como... ora, Table. Suponha que, em vez disso, desejássemos exibir os dados como uma lista de valores separados por vírgula. Nesse caso, definiríamos o formato como CSV, desta maneira:

strFormat = "CSV"

Então, teríamos uma saída semelhante a esta:

"Display Name","State","Start Mode"
"Adobe LM Service","Stopped","Manual"
"Adobe Active File Monitor V4","Stopped","Manual"
"Alerter","Stopped","Manual"
"Application Layer Gateway Service","Running","Manual"
"Apple Mobile Device","Running","Auto"
"Application Management","Stopped","Manual"

Observe que o Microsoft.CmdLib não apenas inseriu vírgulas entre os itens, mas também colocou os valores individuais entre aspas duplas. É um recurso muito mais interessante do que se pode imaginar. Afinal, para fazer isso manualmente, seria necessário usar um código como este:

Wscript.Echo Chr(34) & objService.DisplayName & Chr(34) & "," & Chr(34) & objService.State & Chr(34) & "," & Chr(34) & objService.StartMode & Chr(34)

Pois é.

O quê? Você não gosta de tabelas, mas também não quer o formato CSV? Bem, nesse caso, tente definir o formato como List, que fornece uma saída como esta:

Display Name: Adobe LM Service
State:        Stopped
Start Mode:   Manual
Display Name: Adobe Active File Monitor V4
State:        Stopped
Start Mode:   Manual

Mas nós vamos além (como costumamos fazer às vezes). Depois de definir o formato de saída, definimos o valor de uma variável chamada blnPrintHeader como True:

blnPrintHeader = True

Usaremos blnPrintHeader para instruir o Microsoft.CmdLib a imprimir os cabeçalhos de coluna. E se não quisermos imprimir os cabeçalhos de coluna? Não tem problema; nesse caso, definimos blnPrintHeader como False:

blnPrintHeader = False

Por fim, temos esta linha de código:

arrBlnHide = Array(False, False, False)

Quando se trata de exibir os dados, Microsoft.CmdLib oferece a opção de mostrar ou ocultar uma coluna. Para ocultar uma coluna (ou seja, suprimir os dados de uma propriedade específica), defina o valor para essa propriedade como True; para mostrar uma coluna, defina o valor como False.

Na nossa saída, mostraremos os valores para as propriedades DisplayName, State e StartMode, nessa ordem; por isso, usaremos os valores False, False, False na matriz. E se quiséssemos mostrar o DisplayName, ocultar o State e mostrar o StartMode? Nesse caso, usaríamos esta linha de código:

arrBlnHide = Array(False, True, False)

Lembre-se de usar False para mostrar uma coluna e True para ocultar uma coluna.

Agora, estamos prontos para gerar alguns dados de saída, ou melhor, estaríamos se realmente tivéssemos os dados. (Será que a Equipe de Scripts escreveria um script que falharia ao gerar dados de saída e ainda passaria um tempo extraordinário depurando esse script para, no fim, perceber que na verdade esqueceu de recuperar os dados? Não, claro que não; por que você acha isso?)

Com isso em mente, nossa próxima etapa é fazer a associação com o serviço WMI (Instrumentação de Gerenciamento do Windows) no computador local e usar o método ExecQuery para recuperar as informações sobre todos os serviços instalados no computador:

strComputer = "."
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")

Set colServices = objWMIService.ExecQuery ("Select * FROM Win32_Service")

Talvez devamos mencionar que você não está limitado a trabalhar com os dados WMI aqui. Com era de se esperar, o Microsoft.CmdLib pode trabalhar com qualquer tipo de dado. O WMI é apenas uma maneira útil de recuperar um monte de dados.

Assim que obtemos a nossa coleção de dados relacionados a serviço, configuramos um loop For Each para percorrer todos os serviços na coleção. Entretanto, em vez de reproduzir os valores de propriedade para cada serviço, executamos este código:

ReDim Preserve arrResultsArray(i)
arrResultsArray(i) = Array(objService.DisplayName, objService.State,objService.StartMode)
i = i + 1

O que estamos fazendo neste bloco de código? Bem, na linha 1, estamos redimensionando a matriz, usando o comando ReDim Preserve para não apenas redimensioná-la, mas também preservar quaisquer dados existentes nela. (Sem a palavra-chave Preserve, a matriz seria redimensionada, mas os dados já existentes seriam apagados.)

Qual será o tamanho da matriz? Na primeira vez que ocorre o loop, definimos o tamanho da matriz como 0; em outras palavras, criamos uma matriz contendo um elemento. E como ter certeza de que estamos criando uma matriz de tamanho 0? Porque usamos a variável de contador i, e ela é igual a 0.

Então, se estamos usando a variável i para representar o tamanho da matriz, isso significa que sempre iremos definir o tamanho como 0? Bem, deveria significar, a menos que, a cada loop, aumentássemos o valor de i em 1; como você pode ver, é isso que fazemos na linha 3 do bloco de código.

Agora, temos que nos preocupar apenas com uma linha de código:

arrResultsArray(i) = Array(objService.DisplayName, objService.State,objService.StartMode)

Aqui, simplesmente usamos os valores de propriedade que nos interessam (DisplayName, State e StartMode) e os adicionamos à matriz arrResultsArray. Observe que não adicionamos os valores de propriedade individualmente, mas como uma matriz de valores. Concordo, não é muito comum: significa que cada item da matriz arrResultsArray será outra matriz; é assim que o Microsoft.CmdLib funciona.

Obviamente, isso pode despertar novamente certa preocupação. "Uma matriz de matrizes? Como vocês esperam que eu acesse todos os valores em uma matriz cheia de matrizes?". Calma. É fácil: deixe que o Microsoft.CmdLib cuide disso para você.

Observação: infelizmente, acessar todos os valores individuais em uma matriz de matrizes praticamente é a única coisa que o Microsoft.CmdLib pode fazer por você. Entretanto, as tarefas de limpar os aposentos da sua madrasta malvada, lavar os pratos e passar a roupa das suas meias-irmãs perversas serão consideradas para a próxima versão do objeto.

Na verdade, podemos gerar os dados de saída, em um formato tabular perfeito, simplesmente chamando o método ShowResults e passando-o para todas as matrizes e variáveis configuradas anteriormente no script:

objCmdLib.ShowResults arrHeader, arrResultsArray, arrMaxLength, strFormat, blnPrintHeader, arrBlnHide

Como tudo isso ficará? Ficará como a saída perfeitamente formatada que esperávamos encontrar na Figura 1.

Nada mal, hein? Você obtém uma bela saída sem ter de se esforçar muito para isso. (E o seu próximo script será ainda mais fácil, porque você só terá que fazer algumas pequenas alterações no primeiro script.)

Agora, sem dúvida, você não ficará tão satisfeito quanto a Cinderela ficaria se trabalhasse dia e noite só para exibir a saída do script em uma tabela. E, sejamos honestos, provavelmente, você também não se casará com um príncipe; pode ter certeza de que isso não faz parte do pacote. Mas parece que esse é um pequeno preço a pagar para obter uma saída tão perfeita como essa de um script VBScript, especialmente considerando como os príncipes são hoje em dia.

E quem sabe? Talvez você encontre um príncipe. Afinal, até a realeza precisa obter informações sobre os serviços instalados em seu computador, certo?

O desafio de script do Dr. Scripto

O desafio mensal que testa não apenas sua habilidade de resolver quebra-cabeças, mas também de criar scripts.

Junho de 2008: Caminho para o PowerShell

Em cada um desses quebra-cabeças, junte as letras horizontal, vertical e diagonalmente, para formar o nome de um cmdlet do Windows PowerShell. Cada letra será usada apenas uma vez. Por exemplo:

O cmdlet criado neste quebra-cabeça é New-Alias. Agora é a sua vez. Aqui, há mais três quebra-cabeças:

ANSWER:

O desafio de script do Dr. Scripto

Respostas: Caminho para o PowerShell, junho de 2008

Read-Host

Set-AuthenticodeSignature

The Microsoft Scripting Guys trabalham para a – bem, são empregados da – Microsoft. Quando não estão jogando/treinando/assistindo beisebol (e praticando diversas outras atividades), eles administram o Script Center da TechNet. Confira no site www.scriptingguys.com.

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