Boa tarde a todos, quero compartilhar um guia simples "Como parar de pingar manualmente uma dezena de hosts. Sem registro e sem SMS!".
Das vastidões da Internet
Importante: não sou programador nem administrador de sistemas, mas preciso trabalhar simultaneamente com um grande conjunto servidores de serviços e escrevi este script para meu próprio conforto.
Para todos que possam achar isso útil, convido a ler mais.
Por que PowershellTenho experiência na escrita de programas simples em Python, mas ele requer um interpretador instalado ou permissões para executar .exe, o que nem sempre é possível no meu trabalho. Já o script em Powershell frequentemente consegue ser executado.
Nem todos gostam do console/terminal
Acredito que isso não é contraditório, caso contrário, todos ainda usariam clientes de email baseados em console e não haveria GUI nos sistemas *nix.
Como costumo usar o Powershell de forma bem simples, resolvi primeiro entender se era possível adicionar uma GUI. E a resposta é sim, e é até bastante simples:

Add-Type -assembly System.Windows.Forms #Conectando a biblioteca
$main_form = New-Object System.Windows.Forms.Form #Criando o objeto para nossa "janela"
#Definindo os parâmetros
$main_form.Text = 'Links up' #Nome no cabeçalho
$main_form.Width = 300 #Largura da janela
$main_form.Height = 200 #Altura da janela
$main_form.AutoSize = $true #Permitindo que a janela altere de tamanho automaticamente, se necessário
$main_form.ShowDialog() #Chamando a "janela"
Adicionamos um elemento de saída a isso e obtemos uma janela básica do Windows, tautologia?.

Add-Type -assembly System.Windows.Forms #Vamos conectar a biblioteca
$main_form = New-Object System.Windows.Forms.Form #Criamos uma variável com nossa "janela"
#Definimos os parâmetros dela
$main_form.Text ='Links up' #Nome no cabeçalho
$main_form.Width = 300 #Largura da janela
$main_form.Height = 200 #Altura da janela
$main_form.AutoSize = $true #Damos a ela a possibilidade de redimensionar automaticamente, se necessário
$Label = New-Object System.Windows.Forms.Label #Todos os elementos do formulário serão armazenados em variáveis, mas na verdade são objetos, como qualquer outra variável no Powershell
$Label.Text = "Olá! Sou uma janela do Windows básica, e você, o que conquistou?" #Texto exibido
$Label.Location = New-Object System.Drawing.Point(10,65) #Posição do objeto dentro da janela na horizontal e vertical (x,y)
$Label.AutoSize = $true
$main_form.Controls.Add($Label) #Adicionamos o objeto criado ao formulário, para que ele não se perca ao executar o script
$main_form.ShowDialog() #Chamamos a janela básicaVamos adicionar dinamismo
Assim, a ferramenta com a qual "fiz o ping no Yandex" e montei *.iso ganhou uma GUI separada, mas isso não é o suficiente. De maneira semelhante, é possível exibir informações sobre a disponibilidade, mas para monitoramento será necessário reiniciar o script a cada vez.
Primeiro, vamos desenhar dois ícones e adicionar a opção de exibir imagens.

$PictureBox = New-Object system.Windows.Forms.PictureBox #O objeto para exibir imagens é bem nomeado
$PictureBox.width = 10
$PictureBox.height = 10
$PictureBox.location = New-Object System.Drawing.Point(178,12)
#Aqui nós vamos ao que interessa, vinculando a imagem exibida ao resultado da verificação de acessibilidade do nó usando o cmdlet
#<b>test-connection</b>, onde:
#-Count - define a quantidade de requisições
#-computer - IP ou nome de domínio para a requisição
#-quiet - para que retorne apenas um valor booleano
if ((test-connection -Count 1 -computer ya.ru -quiet) -eq $True) {
$PictureBox.imageLocation = "C:Testyes.png" #O objeto acessa a imagem correspondente
}
Else {
$PictureBox.imageLocation = "C:Testno.png" #O objeto acessa a imagem correspondente
}
$PictureBox.SizeMode = [System.Windows.Forms.PictureBoxSizeMode]::zoom
$main_form.Controls.Add($PictureBox)
Novamente nossos DNS estão agindo de forma estranha…

E vamos adicionar um botão para que possamos atualizar as leituras.

$Button = New-Object System.Windows.Forms.Button
$Button.Location = New-Object System.Drawing.Size(100,150)
$Button.Size = New-Object System.Drawing.Size(80,30)
$Button.Text = "Recarregar"
# Associamos o evento de clique do botão a cada PictureBox conforme a lógica descrita anteriormente
$Button.Add_Click({
if ((Test-Connection -Count 1 -computer ya.ru -quiet) -eq $True)
{$PictureBox.imageLocation = "C:Testyes.png"}
Else {$PictureBox.imageLocation = "C:Testno.png"}
if ((Test-Connection -Count 1 -computer 8.8.8.8 -quiet) -eq $True)
{$PictureBox1.imageLocation = "C:Testyes.png"}
Else {$PictureBox1.imageLocation = "C:Testno.png"}
})
$main_form.Controls.Add($Button)

Maravilha, agora para a produção!?
Depois de inserir manualmente cerca de meia dúzia de hosts, percebi uma coisa — este projeto vai acabar, os hosts mudarão e terei que editar o script toda vez. Por um lado, não é nada grave, é uma solução para mim mesmo. Por outro lado, essa solução para mim mesmo, veja só o que está acontecendo:
Uma visão não para os fracos de coração
Add-Type -assembly System.Windows.Forms #Conectando a biblioteca
$main_form = New-Object System.Windows.Forms.Form #Criando uma variável para nossa "janela"
#Definindo os parâmetros dela
$main_form.Text ='Links up' #Nome no cabeçalho
$main_form.Width = 300 #Largura da janela
$main_form.Height = 200 #Altura da janela
$main_form.AutoSize = $true #Permite que ela ajuste o tamanho automaticamente, se necessário
$Label = New-Object System.Windows.Forms.Label #Todos os elementos do formulário serão armazenados em variáveis, mas na verdade são objetos, assim como qualquer outra variável no Powershell
$Label.Text = "ya.ru ............................" #Texto exibido
$Label.Location = New-Object System.Drawing.Point(15,10) #Localização do objeto dentro da janela na horizontal e vertical (x,y)
$Label.AutoSize = $true
$Label1 = New-Object System.Windows.Forms.Label #Todos os elementos do formulário serão armazenados em variáveis, mas na verdade são objetos, assim como qualquer outra variável no Powershell
$Label1.Text = "8.8.8.8 ............................" #Texto exibido DNS do Google
$Label1.Location = New-Object System.Drawing.Point(15,30) #Localização do objeto dentro da janela na horizontal e vertical (x,y)
$Label1.AutoSize = $true
$Label2 = New-Object System.Windows.Forms.Label
$Label2.Text = "192.168.x.x ............................"
$Label2.Location = New-Object System.Drawing.Point(15,50)
$Label2.AutoSize = $true
$Label3 = New-Object System.Windows.Forms.Label
$Label3.Text = "192.168.x.x ............................"
$Label3.Location = New-Object System.Drawing.Point(15,70)
$Label3.AutoSize = $true
$Label4 = New-Object System.Windows.Forms.Label
$Label4.Text = "10.0.x.x ............................"
$Label4.Location = New-Object System.Drawing.Point(15,90)
$Label4.AutoSize = $true
$Label5 = New-Object System.Windows.Forms.Label
$Label5.Text = "162.102.x.x ............................"
$Label5.Location = New-Object System.Drawing.Point(15,110)
$Label5.AutoSize = $true
$PictureBox = New-Object system.Windows.Forms.PictureBox #Objeto para exibir imagens
$PictureBox.width = 10
$PictureBox.height = 10
#Aqui estamos indo ao ponto, vinculando a imagem a ser exibida ao resultado da verificação de disponibilidade do nó usando o cmdlet
#<b>test-connection</b>, onde:
#-Count - transmite a quantidade de requisições
#-computer - IP ou nome de domínio para a requisição
#-quiet - para que nos retorne apenas o valor Booleano
$PictureBox.location = New-Object System.Drawing.Point(235,12)
if ((test-connection -Count 1 -computer ya.ru -quiet) -eq $True) {
$PictureBox.imageLocation = "C:Testyes.png" # O objeto acessa a imagem correspondente
}
Else {
$PictureBox.imageLocation = "C:Testno.png" # O objeto acessa a imagem correspondente
}
$PictureBox.SizeMode = [System.Windows.Forms.PictureBoxSizeMode]::zoom
$PictureBox1 = New-Object system.Windows.Forms.PictureBox # O objeto para exibir imagens é denominado de forma lógica
$PictureBox1.width = 10
$PictureBox1.height = 10
$PictureBox1.location = New-Object System.Drawing.Point(235,32)
if ((test-connection -Count 1 -computer 8.8.8.8 -quiet) -eq $True) {
$PictureBox1.imageLocation = "C:Testyes.png" # O objeto acessa a imagem correspondente
}
Else {
$PictureBox1.imageLocation = "C:Testno.png" # O objeto acessa a imagem correspondente
}
$PictureBox1.SizeMode = [System.Windows.Forms.PictureBoxSizeMode]::zoom
$PictureBox2 = New-Object system.Windows.Forms.PictureBox # O objeto para exibir imagens é denominado de forma lógica
$PictureBox2.width = 10
$PictureBox2.height = 10
$PictureBox2.location = New-Object System.Drawing.Point(235,52)
if ((test-connection -Count 1 -computer 192.168.x.x -quiet) -eq $True) {
$PictureBox2.imageLocation = "C:Testyes.png" # O objeto acessa a imagem correspondente
}
Else {
$PictureBox2.imageLocation = "C:Testno.png" # O objeto acessa a imagem correspondente
}
$PictureBox2.SizeMode = [System.Windows.Forms.PictureBoxSizeMode]::zoom
$PictureBox3 = New-Object system.Windows.Forms.PictureBox # O objeto para exibir imagens é denominado de forma lógica
$PictureBox3.width = 10
$PictureBox3.height = 10
$PictureBox3.location = New-Object System.Drawing.Point(235,72)
if ((test-connection -Count 1 -computer 192.168.x.x -quiet) -eq $True) {
$PictureBox3.imageLocation = "C:Testyes.png" # O objeto acessa a imagem correspondente
}
Else {
$PictureBox3.imageLocation = "C:Testno.png" # O objeto acessa a imagem correspondente
}
$PictureBox3.SizeMode = [System.Windows.Forms.PictureBoxSizeMode]::zoom
$PictureBox4 = New-Object system.Windows.Forms.PictureBox # O objeto para exibir imagens é denominado de forma lógica
$PictureBox4.width = 10
$PictureBox4.height = 10
$PictureBox4.location = New-Object System.Drawing.Point(235,92)
if ((test-connection -Count 1 -computer 10.0.x.x -quiet) -eq $True) {
$PictureBox4.imageLocation = "C:Testyes.png" # O objeto acessa a imagem correspondente
}
Else {
$PictureBox4.imageLocation = "C:Testno.png" # O objeto acessa a imagem correspondente
}
$PictureBox1.SizeMode = [System.Windows.Forms.PictureBoxSizeMode]::zoom
$PictureBox5 = New-Object system.Windows.Forms.PictureBox # O objeto para exibir imagens é denominado de forma lógica
$PictureBox5.width = 10
$PictureBox5.height = 10
$PictureBox5.location = New-Object System.Drawing.Point(235,112)
if ((test-connection -Count 1 -computer 162.102.x.x -quiet) -eq $True) {
$PictureBox5.imageLocation = "C:Testyes.png" # O objeto acessa a imagem correspondente
}
Else {
$PictureBox5.imageLocation = "C:Testno.png" # O objeto acessa a imagem correspondente
}
$PictureBox5.SizeMode = [System.Windows.Forms.PictureBoxSizeMode]::zoom
$Button = New-Object System.Windows.Forms.Button
$Button.Location = New-Object System.Drawing.Size(100,150)
$Button.Size = New-Object System.Drawing.Size(80,30)
$Button.Text = "Recarregar"
# Associamos o evento de clique do botão a cada PictureBox conforme a lógica descrita anteriormente
$Button.Add_Click({
if ((Test-Connection -Count 1 -computer ya.ru -quiet) -eq $True)
{$PictureBox.imageLocation = "C:Testyes.png"}
Else {$PictureBox.imageLocation = "C:Testno.png"}
if ((Test-Connection -Count 1 -computer 8.8.8.8 -quiet) -eq $True)
{$PictureBox1.imageLocation = "C:Testyes.png"}
Else {$PictureBox1.imageLocation = "C:Testno.png"}
if ((Test-Connection -Count 1 -computer 192.168.x.x -quiet) -eq $True)
{$PictureBox2.imageLocation = "C:Testyes.png"}
Else {$PictureBox2.imageLocation = "C:Testno.png"}
if ((Test-Connection -Count 1 -computer 192.168.x.x -quiet) -eq $True)
{$PictureBox3.imageLocation = "C:Testyes.png"}
Else {$PictureBox3.imageLocation = "C:Testno.png"}
if ((Test-Connection -Count 1 -computer 10.0.x.x -quiet) -eq $True)
{$PictureBox4.imageLocation = "C:Testyes.png"}
Else {$PictureBox4.imageLocation = "C:Testno.png"}
if ((Test-Connection -Count 1 -computer 162.102.x.x -quiet) -eq $True)
{$PictureBox5.imageLocation = "C:Testyes.png"}
Else {$PictureBox5.imageLocation = "C:Testno.png"}
})
$main_form.Controls.Add($Label) # adicionamos o objeto criado ao formulário, para que não seja perdido durante a execução do script
$main_form.Controls.Add($Label1)
$main_form.Controls.Add($Label2)
$main_form.Controls.Add($Label3)
$main_form.Controls.Add($Label4)
$main_form.Controls.Add($Label5)
$main_form.Controls.Add($PictureBox)
$main_form.Controls.Add($PictureBox1)
$main_form.Controls.Add($PictureBox2)
$main_form.Controls.Add($PictureBox3)
$main_form.Controls.Add($PictureBox4)
$main_form.Controls.Add($PictureBox5)
$main_form.Controls.Add($Button)
$main_form.ShowDialog() # Chamamos a janela de diálogo de forma simples
Mesmo mantendo a limpeza e a estrutura, a edição periódica causará sensações nada agradáveis.
Primeiro, separamos a verificação de disponibilidade em uma função separada e o caminho do diretório em uma variável separada:
$script_path = "C:TestPS ping"
#Mudamos para a função do objeto PictureBox já criado e o endereço IP que precisa ser verificado.
#Na saída, isso muda a imagem carregada.
function get_status($PictureBox,$path_ip) {
if ((Test-Connection -Count 1 -computer $path_ip -quiet) -eq $True)
{$PictureBox.imageLocation = $script_path + "yes.png"}
Else {$PictureBox.imageLocation = $script_path + "no.png"}
}
Vamos mover os dados do host para um arquivo externo path.txt, gravando-os no formato "ip/host-functional-name/" e no documento iremos recebê-los em arrays. Também vamos tornar o cálculo da posição Y mais automatizado. Isso nos permitirá criar Labels e checkboxes chamando a função:

#создаем описательную линию, на вход идут: объект Label, IP-адресс, описание и позиция по оси Y
Function Create_line($label,$path_ip,$caption, $top){
$label.Location = New-Object System.Drawing.Point(1, $top)
$label.text = $path_ip+$caption
$label.font = $font
$Label.AutoSize = $true
}
#создаем индикатор для описательной линию, на вход идут: объект PictureBox, IP-адресс и позиция по оси Y
Function Create_link($PictureBox,$path_ip, $top){
$PictureBox.width = 10
$PictureBox.height = 10
$PictureBox.location = New-Object System.Drawing.Point(210,$top)
get_status -PictureBox $PictureBox -path_ip $path_ip
$PictureBox.SizeMode = [System.Windows.Forms.PictureBoxSizeMode]::zoom
}
$line = Get-content -LiteralPath $script_path"path.txt" #вытаскиваем данные о необходимых хостах
$len = $line.Length #вычисляем длину, а точнее массив длин каждой строки
$i = 0
#далее объявляем массивы которые понадобятся дальше
$ip = @() #массив ip
$capt = @() #массив описания
$Labels =@() #массив Label
$PictureBoxs =@() #массив PictureBox
while($i -lt $len){
$f = $line[$i].IndexOf("/") #вычисляем позицию начала описания
$l = $line[$i].LastIndexOf("/") #вычисляем позицию конца описания
$ip += $line[$i].Substring(0,$f) #вытаскиваем ip
$capt += $line[$i].Substring($f+1,$l-$f-1) #вытаскиваем описание
#создаем поле Label
Create_line -label ($label_obj = New-Object System.Windows.Forms.Label) -path_ip $ip[$i] -caption $capt[$i] -top $label_from_top
#создаем поле PictureBox
Create_link -PictureBox ($PictureBox_obj = New-Object system.Windows.Forms.PictureBox) -path_ip $ip[$i] -top $label_from_top
$label_from_top += 15 #делаем "шаг" по оси Y
$Labels += $label_obj #вносим созданный Label в общий массив
$PictureBoxs += $PictureBox_obj #вносим созданный PictureBox в общий массив
$main_form.Controls.Add($Labels[$i])
$main_form.Controls.Add($PictureBoxs[$i])
$i +=1
}
Adicionaremos um espaço para exibir a hora da última verificação, pois isso é conveniente, e também acrescentaremos um pouco mais de ação ao pressionar o botão.

$Label0 = New-Object System.Windows.Forms.Label
$Label0.Text = Get-Date
$Label0.Location = New-Object System.Drawing.Point(80,180)
$Label0.AutoSize = $true
$main_form.Controls.Add($Label0)
$Button.Add_Click({
while($i -lt $len){
get_status -PictureBox $PictureBoxs[$i] -path_ip $ip[$i]
$i +=1
}
$Label0.Text = Get-Date
})
Eu também adicionei uma pequena funcionalidade de bug que, ao detectar um host indisponível, não só mudava o indicador, mas também gritava pelos alto-falantes.
Add-Type -AssemblyName System.Speech
$voice = New-Object System.Speech.Synthesis.SpeechSynthesizer
$voice.Rate = 5
$voice.Speak("Atenção! Atenção! A base está sob ataque!")
Então, após alguns embelezamentos e ajustes para ficar mais legível e conveniente, ficou assim:
Código completo do script
Add-Type -AssemblyName System.Speech
Add-Type -assembly System.Windows.Forms
$script_path = "C:PS ping"
$label_from_top = 10
$voice = New-Object System.Speech.Synthesis.SpeechSynthesizer
$voice.Rate = 5
#Mudamos para a função o objeto PictureBox já criado e o IP a ser verificado.
#No final, ele altera a imagem carregada.
function get_status($PictureBox,$path_ip) {
if ((Test-Connection -Count 1 -computer $path_ip -quiet) -eq $True) {
$PictureBox.imageLocation = $script_path + "yes.png"
}
Else {
$PictureBox.imageLocation = $script_path + "no.png"
$voice.Speak("Erro! Host " + $path_ip + ", indisponível!")
}
}
#criamos uma linha descritiva, recebendo: objeto Label, IP, descrição e posição no eixo Y
Function Create_line($label,$path_ip,$caption, $top){
$label.Location = New-Object System.Drawing.Point(1, $top)
$label.text = $path_ip+$caption
$label.font = $font
$Label.AutoSize = $true
}
#criamos um indicador para a linha descritiva, recebendo: objeto PictureBox, IP e posição no eixo Y
Function Create_link($PictureBox,$path_ip, $top){
$PictureBox.width = 10
$PictureBox.height = 10
$PictureBox.location = New-Object System.Drawing.Point(210,$top)
get_status -PictureBox $PictureBox -path_ip $path_ip
$PictureBox.SizeMode = [System.Windows.Forms.PictureBoxSizeMode]::zoom
}
$main_form = New-Object System.Windows.Forms.Form
$main_form.Text ='Links ativos' #Nome na barra de título
$main_form.Width = 300 #Largura da janela
$main_form.Height = 200 #Altura da janela
$main_form.AutoSize = $true #Permite que ela mude de tamanho automaticamente, se necessário
$main_form.TopMost = $true #Isso é muito importante, permite que a janela fique acima das outras
$line = Get-content -LiteralPath $script_path"path.txt" #extraindo os dados sobre os hosts necessários
$len = $line.Length #calculando o comprimento, ou melhor, o comprimento de cada linha do array
$i = 0
#declarações de arrays que serão necessários
$ip = @() #array de ips
$capt = @() #array de descrições
$Labels =@() #array de Labels
$PictureBoxs =@() #array de PictureBoxes
while($i -lt $len){
$f = $line[$i].IndexOf("/") #calculando a posição do início da descrição
$l = $line[$i].LastIndexOf("/") #calculando a posição final da descrição
$ip += $line[$i].Substring(0,$f) #extraindo o ip
$capt += $line[$i].Substring($f+1,$l-$f-1) #extraindo a descrição
#criando o campo Label
Create_line -label ($label_obj = New-Object System.Windows.Forms.Label) -path_ip $ip[$i] -caption $capt[$i] -top $label_from_top
#criando o campo PictureBox
Create_link -PictureBox ($PictureBox_obj = New-Object system.Windows.Forms.PictureBox) -path_ip $ip[$i] -top $label_from_top
$label_from_top += 15 #incremento no eixo Y
$Labels += $label_obj #adicionando o Label criado ao array geral
$PictureBoxs += $PictureBox_obj #adicionando o PictureBox criado ao array geral
$main_form.Controls.Add($Labels[$i])
$main_form.Controls.Add($PictureBoxs[$i])
$i +=1
}
#este campo contém a última hora de verificação
$Label0 = New-Object System.Windows.Forms.Label
$Label0.Text = Get-Date
$Label0.Location = New-Object System.Drawing.Point(80,180)
$Label0.AutoSize = $true
# Vinculamos ao evento de pressionar o botão a verificação de cada PictureBox conforme a lógica previamente descrita
$Button = New-Object System.Windows.Forms.Button
$Button.Location = New-Object System.Drawing.Size(100,200)
$Button.Size = New-Object System.Drawing.Size(80,30)
$Button.Text = "Recarregar"
$Button.Add_Click({
while($i -lt $len){
get_status -PictureBox $PictureBoxs[$i] -path_ip $ip[$i]
$i +=1
}
$i = 0
$Label0.Text = Get-Date
})
$main_form.Controls.Add($Button)
$main_form.Controls.Add($Label0)
$main_form.ShowDialog()
Epílogo
Espero que este tutorial seja útil para alguém. Se você já fez isso desde pequeno, parabéns, eu não fiz. Mas estou aberto a ouvir seus comentários e sugestões.
Foi gratificante para mim explorar e reunir essa pequena, mas útil ferramenta do dia a dia. Estou planejando também implementar adição e remoção de nós na interface gráfica, além de fazer o que deveria ter sido implementado primeiro: atualização automática de status sem a necessidade de clicar em um botão e sem travar o "powershell.exe".
A versão mais recente do script está disponível em GitHub
Fonte: habr.com
