¡Hola a todos! Quiero compartir una sencilla guía 'Cómo dejar de hacer ping manualmente a una docena de hosts. ¡Sin registro ni SMS!'.
Desde los rincones de Internet
Importante: No soy programador ni administrador de sistemas, pero me encuentro trabajando simultáneamente con un gran conjunto servidores de servicios y este script lo escribí para mi propia comodidad.
A todos los que puedan encontrar esto útil, les invito a seguir leyendo.
¿Por qué Powershell?Tengo experiencia escribiendo programas simples en Python, pero este requiere un intérprete instalado o el derecho a ejecutar .exe, lo cual no siempre es posible en el marco de mi trabajo. En cambio, un script en Powershell suele encontrar la manera de ejecutarse.
No a todos les gusta la consola/terminal
Creo que no hay contradicción en esto; de lo contrario, todos seguirían usando clientes de correo en consola y en sistemas *nix no habría aparecido GUI.
Dado que en mi día a día debo usar Powershell de manera bastante primitiva, al principio traté de entender si era posible implementar una GUI. Resulta que sí, y bastante sencillo:

Add-Type -assembly System.Windows.Forms #Conectamos la biblioteca
$main_form = New-Object System.Windows.Forms.Form #Creamos un objeto con nuestra "ventana"
#Establecemos sus parámetros
$main_form.Text ='Links up' #Nombre en el encabezado
$main_form.Width = 300 #Ancho de la ventana
$main_form.Height = 200 #Altura de la ventana
$main_form.AutoSize = $true #Le damos la posibilidad de redimensionarse automáticamente si es necesario
$main_form.ShowDialog() #Llamamos a la "ventana"
Añadimos a esto un elemento de salida y obtenemos una simple ventana de Windows, ¿tautología?.

Add-Type -assembly System.Windows.Forms #Conectamos la biblioteca
$main_form = New-Object System.Windows.Forms.Form #Creamos una variable con nuestra "ventana"
#Asignamos parámetros a la ventana
$main_form.Text ='Links up' #Nombre en el encabezado
$main_form.Width = 300 #Ancho de la ventana
$main_form.Height = 200 #Altura de la ventana
$main_form.AutoSize = $true #Permitimos que cambie de tamaño automáticamente si es necesario
$Label = New-Object System.Windows.Forms.Label #Todos los elementos del formulario se almacenarán en variables, pero en realidad son objetos, como cualquier otra variable en Powershell
$Label.Text = "¡Hola! Soy una ventana sencilla de Windows, ¿y tú qué has logrado?" #Texto mostrado
$Label.Location = New-Object System.Drawing.Point(10,65) #Ubicación del objeto en el formulario (x,y)
$Label.AutoSize = $true
$main_form.Controls.Add($Label) #Agregamos el objeto creado al formulario para que no se pierda durante la ejecución del script
$main_form.ShowDialog() #Mostramos la ventana sencillaAgreguemos dinámicas
Así que la herramienta con la que "hice pings a Yandex" y monté *.iso ahora tiene una GUI independiente, pero eso no es suficiente. De manera similar, se puede mostrar información sobre la disponibilidad, pero para el monitoreo, será necesario reiniciar el script cada vez.
Primero dibujemos dos íconos y agreguemos la capacidad de mostrar imágenes.

$PictureBox = New-Object system.Windows.Forms.PictureBox #El objeto para mostrar imágenes tiene un nombre bastante lógico
$PictureBox.width = 10
$PictureBox.height = 10
$PictureBox.location = New-Object System.Drawing.Point(178,12)
#Aquí pasamos a la acción vinculando la imagen que se mostrará al resultado de la verificación de la disponibilidad del nodo utilizando el cmdlet
#<b>test-connection</b>, donde:
#-Count - transmite el número de solicitudes
#-computer - IP o nombre de dominio para la solicitud
#-quiet - para que solo se nos devuelva un valor Booleano
if ((test-connection -Count 1 -computer ya.ru -quiet) -eq $True) {
$PictureBox.imageLocation = "C:Testyes.png" #El objeto hace referencia a la imagen correspondiente
}
Else {
$PictureBox.imageLocation = "C:Testno.png" #El objeto hace referencia a la imagen correspondiente
}
$PictureBox.SizeMode = [System.Windows.Forms.PictureBoxSizeMode]::zoom
$main_form.Controls.Add($PictureBox)
Nuestros DNS están fallando de nuevo...

Y agregaré un botón para que podamos actualizar las lecturas.

$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 = "Recargar"
# Asociamos el evento de clic del botón a cada PictureBox según la 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)

Genial, ¿ahora a producción?
Escribiendo manualmente alrededor de media docena de hosts, de repente comprendí una cosa: este proyecto tiene que terminar, los hosts cambiarán y tendré que corregir el script cada vez. Por un lado, no es nada grave, es una solución para mí mismo. Por otro lado, esta solución para mí mismo, mírenlo:
Una vista no apta para cardiacos
Add-Type -assembly System.Windows.Forms #Conectamos la biblioteca
$main_form = New-Object System.Windows.Forms.Form #Creamos una variable para nuestra "ventana"
#Establecemos sus parámetros mediante parámetros
$main_form.Text ='Links up' #Nombre en el encabezado
$main_form.Width = 300 #Ancho de la ventana
$main_form.Height = 200 #Altura de la ventana
$main_form.AutoSize = $true #Le damos la capacidad de cambiar de tamaño automáticamente, si es necesario
$Label = New-Object System.Windows.Forms.Label #Todos los elementos del formulario se almacenarán en variables, pero en realidad son objetos, como cualquier otra variable en Powershell
$Label.Text = "ya.ru ............................" #Texto mostrado
$Label.Location = New-Object System.Drawing.Point(15,10) #Ubicación del objeto dentro del formulario en horizontal y vertical (x,y)
$Label.AutoSize = $true
$Label1 = New-Object System.Windows.Forms.Label #Todos los elementos del formulario se almacenarán en variables, pero en realidad son objetos, como cualquier otra variable en Powershell
$Label1.Text = "8.8.8.8 ............................" #Texto mostrado, DNS de Google
$Label1.Location = New-Object System.Drawing.Point(15,30) #Ubicación del objeto dentro del formulario en horizontal y 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 #El objeto para mostrar imágenes se llama bastante lógicamente
$PictureBox.width = 10
$PictureBox.height = 10
#Aquí comenzamos a unir la imagen mostrada con el resultado de la verificación de disponibilidad del nodo usando el cmdlet
#<b>test-connection</b>, donde:
#-Count - transmite el número de solicitudes
#-computer - IP o nombre de dominio para la solicitud
#-quiet - para que solo se nos devuelva un 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" # El objeto se refiere a la imagen correspondiente
}
Else {
$PictureBox.imageLocation = "C:Testno.png" # El objeto se refiere a la imagen correspondiente
}
$PictureBox.SizeMode = [System.Windows.Forms.PictureBoxSizeMode]::zoom
$PictureBox1 = New-Object system.Windows.Forms.PictureBox # Objeto para mostrar imágenes llamado 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" # El objeto se refiere a la imagen correspondiente
}
Else {
$PictureBox1.imageLocation = "C:Testno.png" # El objeto se refiere a la imagen correspondiente
}
$PictureBox1.SizeMode = [System.Windows.Forms.PictureBoxSizeMode]::zoom
$PictureBox2 = New-Object system.Windows.Forms.PictureBox # Objeto para mostrar imágenes llamado 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" # El objeto se refiere a la imagen correspondiente
}
Else {
$PictureBox2.imageLocation = "C:Testno.png" # El objeto se refiere a la imagen correspondiente
}
$PictureBox2.SizeMode = [System.Windows.Forms.PictureBoxSizeMode]::zoom
$PictureBox3 = New-Object system.Windows.Forms.PictureBox # Objeto para mostrar imágenes llamado 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" # El objeto se refiere a la imagen correspondiente
}
Else {
$PictureBox3.imageLocation = "C:Testno.png" # El objeto se refiere a la imagen correspondiente
}
$PictureBox3.SizeMode = [System.Windows.Forms.PictureBoxSizeMode]::zoom
$PictureBox4 = New-Object system.Windows.Forms.PictureBox # Objeto para mostrar imágenes llamado 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" # El objeto se refiere a la imagen correspondiente
}
Else {
$PictureBox4.imageLocation = "C:Testno.png" # El objeto se refiere a la imagen correspondiente
}
$PictureBox1.SizeMode = [System.Windows.Forms.PictureBoxSizeMode]::zoom
$PictureBox5 = New-Object system.Windows.Forms.PictureBox # Objeto para mostrar imágenes llamado 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" # El objeto se refiere a la imagen correspondiente
}
Else {
$PictureBox5.imageLocation = "C:Testno.png" # El objeto se refiere a la imagen correspondiente
}
$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 = "Recargar"
# Se asigna el evento del botón para llamar a cada PictureBox según la 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) # Agregamos el objeto creado al formulario para que no se pierda durante la ejecución del 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() # Llamamos a la ventana de diálogo elemental
Incluso si se mantiene la limpieza y se sigue la estructura, la edición periódica provocará sensaciones poco agradables.
Para comenzar, sacamos la verificación de disponibilidad en una función separada y la ruta al directorio en una variable aparte:
$script_path = "C:TestPS ping"
# Pasamos a la función el objeto PictureBox ya creado y la dirección IP que necesitamos verificar.
# Al final, cambia la imagen mostrada.
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"}
}
Sacaremos los datos del host a un archivo externo path.txt, registrándolos en el formato "ip/host-nombre-funcional/", y los aceptaremos en arreglos en el documento. También haremos el cálculo de la posición en Y de manera más automatizada. Todo esto nos permite crear Labels y checkboxes llamando a la función:

#создаем описательную линию, на вход идут: объект 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
}
Agregaremos un espacio para mostrar la hora de la última verificación, porque es conveniente, y también mejoraremos un poco la acción al presionar el botón.

$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
})
También he agregado una pequeña característica que, al detectar un host no disponible, no solo indica el cambio en el indicador, sino que también grita desde los altavoces.
Add-Type -AssemblyName System.Speech
$voice = New-Object System.Speech.Synthesis.SpeechSynthesizer
$voice.Rate = 5
$voice.Speak("¡Advertencia! ¡Advertencia! ¡La base está bajo ataque!")
Entonces, después de algunas embellecidas y ajustarlo a un formato legible y cómodo, quedó así:
Código completo del 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
#Pasamos a la función el objeto PictureBox ya creado y la dirección IP que se necesita verificar.
#Al salir, cambia la imagen cargada.
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("¡Error! El host " + $path_ip + ", no está disponible!")
}
}
#creamos una línea descriptiva, se reciben como entrada: objeto Label, dirección IP, descripción y posición en el eje 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
}
#creamos un indicador para la línea descriptiva, se reciben como entrada: objeto PictureBox, dirección IP y posición en el eje 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 ='Enlaces activos' #Nombre en el encabezado
$main_form.Width = 300 #Ancho de la ventana
$main_form.Height = 200 #Altura de la ventana
$main_form.AutoSize = $true #Le damos la oportunidad de cambiar de tamaño automáticamente, si es necesario
$main_form.TopMost = $true #Esto es muy importante, permite fijar la ventana sobre otras
$line = Get-content -LiteralPath $script_path"path.txt" #Extraemos datos sobre los hosts necesarios
$len = $line.Length #calculamos la longitud, más precisamente la matriz de longitudes de cada línea
$i = 0
#A continuación, declaramos arrays que se necesitarán más adelante
$ip = @() #array ip
$capt = @() #array de descripciones
$Labels =@() #array Label
$PictureBoxs =@() #array PictureBox
while($i -lt $len){
$f = $line[$i].IndexOf("/") #calculamos la posición de inicio de la descripción
$l = $line[$i].LastIndexOf("/") #calculamos la posición de fin de la descripción
$ip += $line[$i].Substring(0,$f) #extraemos la ip
$capt += $line[$i].Substring($f+1,$l-$f-1) #extraemos la descripción
#creamos el campo Label
Create_line -label ($label_obj = New-Object System.Windows.Forms.Label) -path_ip $ip[$i] -caption $capt[$i] -top $label_from_top
#creamos el 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 #hacemos el "paso" en el eje Y
$Labels += $label_obj #agregamos el Label creado al array general
$PictureBoxs += $PictureBox_obj #agregamos el PictureBox creado al array general
$main_form.Controls.Add($Labels[$i])
$main_form.Controls.Add($PictureBoxs[$i])
$i +=1
}
#este es el campo con el último tiempo de verificación
$Label0 = New-Object System.Windows.Forms.Label
$Label0.Text = Get-Date
$Label0.Location = New-Object System.Drawing.Point(80,180)
$Label0.AutoSize = $true
# Asignamos al evento de clic de cada PictureBox la 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 = "Recargar"
$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()
Póscrito
Espero que este tutorial sea útil para alguien. Si has estado haciendo esto desde que eras un niño, ¡felicitaciones! Yo no lo he hecho. Pero estoy listo para escuchar tus comentarios y sugerencias.
Para mí fue agradable investigar y reunir esta pequeña pero útil herramienta para el hogar. Planeo implementar funciones para añadir y eliminar nodos desde la GUI, así como también la capacidad de actualizar estados automáticamente, sin necesidad de presionar un botón y asegurándome de que no cuelgue 'powershell.exe'.
La última versión del script está en GitHub
Fuente: habr.com
