Monitoramento da disponibilidade de hosts no Powershell

Boa tarde a todos, quero compartilhar um guia simples "Como parar de pingar manualmente uma dezena de hosts. Sem registro e sem SMS!".

Monitoramento da disponibilidade de hosts no PowershellDas 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:

Monitoramento da disponibilidade de hosts no Powershell

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?.

Monitoramento da disponibilidade de hosts no Powershell

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ásica

Vamos 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.

Monitoramento da disponibilidade de hosts no Powershell

$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…

Monitoramento da disponibilidade de hosts no Powershell
E vamos adicionar um botão para que possamos atualizar as leituras.

Monitoramento da disponibilidade de hosts no Powershell

$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)

Monitoramento da disponibilidade de hosts no Powershell

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:

Monitoramento da disponibilidade de hosts no Powershell

#создаем описательную линию, на вход идут: объект 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.

Monitoramento da disponibilidade de hosts no Powershell

$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

Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS 🔥 Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS | ProHoster