Powershell para desenvolvedores – Parte 1 – Conhecendo…

Publicado em 31/01/2011

10


Olá pessoal, tudo certo?

Sempre senti falta de um bom Shell em ambientes Microsoft.

Quem usa Windows sempre careceu de uma alternativa interessante que pudesse ser, pelo menos minimamente, comparada com o Bash dos sistemas Unix-like. Ao meu ver, esta alternativa é o Powershell!

Há quem considere o Powershell demasiadamente vervboso. Há quem não goste do Powershell por sua “dependência” com  o .NET Framework. Eu gosto do Powershell por essas mesmas duas razões.

Nessa nova série pretendo demonstrar boas funcionalidades do Powershell para desenvolvedores. No post de hoje, mostro alguns conceitos fundamentais.

O que é o Powershell?

Windows Powershell é a promessa (ainda?!) da Microsoft para revolucionar o mundo da gestão de sistemas por meio de shells baseados em linha de comando. Através de pipelines baseadas em objetos, do ponto de vista de administradores de sistema, Powershell constitui um enorme salto em produtividade e potencialidade.

Powershell é mais que uma versão aprimorada do Prompt de Comandos do Windows. Powershell é voltado a scripts e é parte integrande do Windows em versões posteriores ao 2008. Se o seu Windows não possui Powershell, baixe-o aqui.

Considerações importantes para o Powershell

Alguns aspectos do Powershell são muito relevantes para quem está começando. Considere:

  • Powershell funciona muito bem com comandos e aplicações padrões do Windows. Isso significa que não é necessário descartar qualquer conhecimento que você já possua sobre como utilizar o Prompt de Comandos do Windows;
  • Powershell apresenta um tipo interiramente novo de comandos: os cmdlets. Esses comandos obedecem uma sintaxe padrão baseada em “Verbo-Substântivo” fácil de lembrar;
  • Powershell entende e consegue manipular objetos. Na prática, podemos instanciar e manipular objetos .NET diretamente no shell;
  • Powershell é auto-explicativo. Com apenas três comandos o usuário consegue obter informações sobre como utilizar e o funcionamento das funcionalidades que o Powershell oferece;
  • Powershell facilita a construção de scripts permitindo a automação de tarefas simples;
  • Powershell tem suporte nativo para muitas tecnologias. Com ele é fácil trabalhar com .NET, COM, WMI, XML, AD, …;
  • Powershell simplifica a utilização de depósitos de dados. Um mesmo modelo de trabalho é utilizado para manipular, por exemplo, o registro do windows e a estrutura de arquivos e pastas.

Iniciando o Powershell

Carregar o Powershell é muito fácil. Na prática, basta iniciar o Powershell.exe no lugar de cmd.exe. Você também encontra o Powershell em “Iniciar – > Todos os Programas –> Acessórios –> Windows Powershell”.

image

 

Além dessa versão (simples), há um ambiente mais “carregado”: Windows Powershell ISE:

image

Pessoalmente, recomendaria começar com o prompt mais simples.

Primeiros passos (diretórios)

Considere a seguinte listagem:

1 PS C:\Users\Elemar> pushd 2 PS C:\Users\Elemar> cd \ 3 PS C:\> popd 4 PS C:\Users\Elemar>

Já aqui, podemos começar a observar o “poder” do powershell. Observe:

  • Na linha 1, podemos observar um novo comando do Powershell: pushd (que é um alias para o comando Push-Location). O que ele faz? Salva o diretório atual em uma “pilha”.
  • Na linha 2, mudamos o diretório atual.
  • Na linha 3, o comando que complementa pushd: popd (que é um alias para Pop-Location). O que ele faz? Retira o diretório armazenado no topo da pilha tornando-o atual.

Para que serve? Bem, podemos mudar o diretório atual facilitando a utilização de comandos subsequentes, podendo voltar ao diretório que era atual no início das operações rapidamente e sem traumas.

Conhecendo os Cmdlets (comandos estruturados do Powershell)

Além dos aplicativos (executáveis) suportados nativamente, Powershell apresenta um novo tipo, mais poderoso, de comandos conhecidos comando cmdlet (pronuncia-se Command-Let).

Todos os cmdlets estão nomeados obedecendo ao padrão “Verbo-Substantivo”, como Get-Process, Get-Content,…, Stop-Process. Observe:

1 PS >Start-Process notepad 2 PS >Get-Process notepad 3 4 Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName 5 ------- ------ ----- ----- ----- ------ -- ----------- 6 56 8 2512 7176 74 0,05 7888 notepad 7 56 7 2212 6812 73 0,11 10416 notepad 8 9 10 PS >

O que ocorreu? Na linha 1, iniciamos um processo (Sim, poderia ter digitado notepad diretamente). Na linha 2, obtive a lista de todos os processos com nome Notepad.

O padrão adotado pelo Powershell, embora verboso, simplifica a compreensão e o aprendizado. Uma vez que você se familiarize com o “trabalho” realizado por alguns verbos (como, por exemplo: Get, Set, Start e Stop), fica mais fácil entender como operar alguns novos “substantivos”.

Além disso, não é necessário lembrar, ou escrever, o “nome completo” de todos os Cmdlets. Podemos utilizar a tecla TAB para auto-completar os nomes dos comandos e de seus argumentos (Get-Pro<TAB> notepad !!)

Os mais conservadores podem dizer que, mesmo com o TAB, digita-se muito no Powershell. Para ajudar a melhorar a eficiência:

  • Powershell define aliases para todos os comandos mais comuns;
  • Permite que o usuário defina os seus próprios aliases;
  • Totalmente case-insensitive. Isso significa que você pode usar Get-Process, get-process, GET-PROCESS (whatever) ;

Suporte nativo a objetos

Powershell possui suporte rico a objetos. Observe:

1 PS >"Hello World" 2 Hello World 3 PS >"Hello World".Length 4 11 5 PS >notepad 6 PS >$notepad = Get-Process notepad 7 PS >$notepad.kill() 8 PS >

Comecemos pela linha 1. Basicamente, criamos um objeto “string”. Entendido? O bacana é que esse objeto string é o mesmo que você já conhece do .NET… Isso fica evidente nas linhas 3 e 4.

Na linha 5, abro um notepad. Na linha 6, recupero o processo com nome notepad (espero que haja somente um) e o armazeno em uma variável chamada $notepad (todas as variáveis em Powershell devem iniciar com  um $). Na linha 7 disparo uma chamada ao método Kill ($notepad tem um objeto do tipo Process) fechando o notepad.

Uma caluladora interativa

O Powershell é uma calculadora nativa. Observe:

1 PS >2+2 2 4 3 PS >1mb 4 1048576 5 PS >6gb/650mb 6 9,45230769230769 7 PS >

Podemos realizar operações simples (como na linha 1). Quantos bytes há em um MB? Resposta solicitada e obtida nas linhas 3 e 4. Quandos CDs preciso para guardar 6 gigabytes? Respostas nas linhas 5 e 6.

1 PS >[DateTime]::Now 2 3 segunda-feira, 31 de janeiro de 2011 19:28:01 4 5 6 PS >[DateTime] "09/06/1979" 7 8 quinta-feira, 6 de setembro de 1979 00:00:00 9 10 11 PS >$howOld = [DateTime]::Now - [DateTime]"06/09/1979" 12 PS >$howOld 13 14 15 Days : 11559 16 Hours : 19 17 Minutes : 29 18 Seconds : 54 19 Milliseconds : 949 20 Ticks : 9987497949490640 21 TotalDays : 11559,6041082068 22 TotalHours : 277430,498596962 23 TotalMinutes : 16645829,9158177 24 TotalSeconds : 998749794,949064 25 TotalMilliseconds : 998749794949,064 26 27 28 PS >$howOld.Days 29 11559 30 PS >

Mais funcionalidades? Observe que consigo “acessar” um tipo do .NET colocando seu nome entre colchetes. Para acessar um membro estático, utilizo a notação com dois “dois pontos” (linha 1). Que dia é hoje? Linha 1 pergunta e linha 3 responde.

Powershell também oferece Cast simples. Que dia da semana eu nasci? Linha 6 pergunta, linha 8 responde.

Que idade eu tenho? Linha 11 pergunta, linhas 12 a 25 respondem. Observe na linha 28 que acessar propriedades do objeto é muito simples.

Combinando Comandos

Sempre que um comando gerar uma saída, podemos usar um pipe para passar esse resultado como entrada para outro comando. Se o segundo comando entender os objetos produzidos pelo primeiro comando, podera operar com os resultados.

Considere o seguinte comando (para fins de clareza, em várias linhas):

1 PS >Get-Process | 2 Sort-Object -desc WorkingSet | 3 Select-Object -First 10 | 4 Format-Table ProcessName, WorkingSet -auto

O cmdlet da linha 1 carrega a lista de todos os processos executando na máquina. Observe que a saída é uma coleção de objetos “Process” (que herdam de object), logo, são acessíveis para um comando que espera “objetos”.

Na linha 2, utilizo um cmdlet para ordenação. Por causa da pipe, esse cmdlet recebe a lista completa de objetos Process. Especifico que desejo que a saída seja esses objetos em sequência ordenada descendente pelo tamanho do workingset.

Na linha 3, utilizo um cmdlet para seleção. Por causa da pipe, esse cmdlet recebe uma lista de objetos Process ordenada. Especifico que desejo apenas os 10 primeiros elementos.

Na linha 4, utilizo um cmdlet para apresentação. Por causa da pipe, esse cmdlet recebe a lista com os 10 processes com maior workingset. Faço com que a saída seja uma tabela apenas com o nome do processo e o WorkingSet.

Obtendo ajuda em 3 comandos: Aprendendo Cmdlets

Na hora de “trabalhar” com uma nova tecnologia é que a “coisa pega”. Por sorte, Powershell ajuda a entender o sistema. Considere:

1 PS >Get-Command Format-* 2 3 CommandType Name 4 ----------- ---- 5 Cmdlet Format-Custom 6 Cmdlet Format-List 7 Cmdlet Format-Table 8 Cmdlet Format-Wide

Na linha 1, solicitei a lista de comandos com nomes compatíveis com a máscara especificada.

Para saber detalhes de funcionamento de um comando, utilizamos o cmdlet Get-Help. Observe:

1 PS >Get-Help Format-Table 2 3 NOME 4 Format-Table 5 6 SINOPSE 7 Formata a saída como uma tabela. 8 9 .. (continua)

Se temos um objeto, e desejamos saber o que podemos fazer com ele, usamos Get-Member. Observe:

1 PS >$notepad = Get-Process notepad 2 PS >$notepad | Get-Member 3 4 5 TypeName: System.Diagnostics.Process 6 7 Name MemberType Definition 8 ---- ---------- ---------- 9 Handles AliasProperty Handles = Handlecount 10 Name AliasProperty Name = ProcessName 11 NPM AliasProperty NPM = NonpagedSystemMemorySize 12 PM AliasProperty PM = PagedMemorySize 13 VM AliasProperty VM = VirtualMemorySize 14 WS AliasProperty WS = WorkingSet 15 .. (continua)

Scripting…

Powerhell trata comandos digitados diretamente pelo usuário da mesma forma que os trataria em scripts. Observe:

1 PS >$ws = 0 2 PS >foreach ($process in Get-Process) {$ws+=$process.WorkingSet} 3 PS >$ws 4 3222622208 5 PS >

Crio uma variável (chamada $ws) para acomodar o total de a soma dos workingsets de todos os processos. Utilizo o comando foreach (na linha 2) para percorrer todos os processos abertos somando seus workingsets em $ws.

Outro bom exemplo:

1 PS >$wc = New-Object System.Net.WebClient 2 PS >$feed = $wc.DownloadString("http://elemarjr.net/rss") 3 PS >$feed 4 <?xml version="1.0" encoding="UTF-8"?><rss version="0.92"> 5 <channel> 6 <title>Elemar DEV</title> 7 <link>http://elemarjr.net</link> 8 <description>Tecnologia e desenvolvimento .net</description> 9 ... (continua)

Na linha 1, crio um WebClient, depois, faço o download do RSS do meu blog. Observe que faço tudo isso de forma interativa. Agora, observe:

1 PS >Clear-History 2 PS >$wc = New-Object System.Net.WebClient 3 PS >$feed = $wc.DownloadString("http://elemarjr.net/rss") 4 PS >Get-History | ForEach-Object {$_.CommandLine} > c:\temp\getfeed.ps1 5 PS >notepad c:\temp\getfeed.ps1 6 PS >c:\temp\getfeed.ps1 7 PS >

Começo limpando o histórico de comandos (linha 1). Depois, executo, de forma interativa, os comandos que desejo incluir em meu script. Por fim (linha 4), salvo a sequência de comandos em um arquivo de scripts (geralmente extensão .ps1). Na linha 5, abro o notepad para fazer eventuais retoques (como retirar o cmdlet Clear-History da primeira linha).

Suporte nativo a tipos especiais

Como já foi dito, Powershell oferece suporte nativo a diversas tecnologias. Entre elas, XML. Observe:

1 PS >$wc = New-Object System.Net.WebClient 2 PS >$content = $wc.DownloadString("http://elemarjr.net/rss") 3 PS >$xml = [xml]$content 4 PS >$xml 5 6 xml rss 7 --- --- 8 version="1.0" encoding="UTF-8" rss 9 10 PS >$xml.rss.channel.item | select Title 11 12 title 13 ----- 14 MSBuild 101 - Parte 4 - Simple Conditions 15 Escrevendo um Engine para Xadrez - Parte 11 - Mais Bitboards, Xeques e Escapadas 16 MSBuild 101 - Parte 3 -Items 17 Escrevendo um Engine para Xadrez - Parte 10 - PieceSet, Side, AttackMoves, Rays e 18 MSBuild 101 - Parte 2 - Conhecendo Tasks, Targets e Properties 19 Escrevendo um Engine para Xadrez - Parte 9 - Refactoring e Redesign 20 Sudoku - Backtracking e Pruning 21 Feedback para Desenvolvedores 22 Escrevendo um Engine para Xadrez - Parte 8 - Bispo e Dama 23 Escrevendo um Engine para Xadrez - Parte 7 - O movimento da torre 24 25 26 PS >

Na linha 3, declaro para o Powershell que o conteúdo da variável $content é xml. Depois disso, cada nodo é tratado pelo powershell como uma propriedade. Veja como, no exemplo, recupero os títulos de meus posts providos por RSS de maneira fácil e transparente.

Outro exemplo bacana, é a navegação pelo registro. Observe:

1 PS >Set-Location HKLM:\Software 2 PS >Get-ChildItem 3 4 Hive: HKEY_LOCAL_MACHINE\Software 5 6 SKC VC Name Property 7 --- -- ---- -------- 8 2 0 Alps {} 9 1 0 Apple Computer, Inc. {} 10 1 0 ATI Technologies {} 11 1 0 Axalto {} 12 2 0 BioAPI {} 13 0 1 BROADCOM {HostStoragePath} 14 312 0 Classes {} 15 8 0 Clients {} 16 2 0 Creative Tech {} 17 1 0 Cyberlink {} 18 1 0 Debug {} 19 1 0 Dell {} 20 1 0 Dell Computer Corporation {} 21 1 0 DeviceVM {} 22 1 0 GEAR Software {} 23 7 0 IDT {} 24 1 0 IM Providers {} 25 1 0 InstalledOptions {} 26 8 2 Intel {LogElapsedTime, GUISettings} 27 4 0 JavaSoft {} 28 192 1 Microsoft {(default)}

Os cmdlets Set-Location e Get-ChildItem são usados, geralmente, para tratar do filesystem. Aqui, você pode ver esses mesmos comandos “navegando” pelo registro do Windows. Observe os aliases para esses comandos em ação:

1 PS >cd HKLM:\Software 2 PS >dir

O resultado é idêntico!

Por hoje, era isso!

Smiley piscando

Etiquetado:,
Publicado em: Sem categoria