Всем доброго времени суток, хочу поделиться простой инструкцией «Как можно перестать вручную пинговать десяток хостов. Без регистрации и СМС!».
С просторов Интернета
Важно: я не программист и не системный администратор, но мне приходиться работать одновременно с большим набором серверов и сервисов и данный скрипт я написал для собственного удобства.
Всех кому это может бытьполезно любопытно, прошу под кат.
Думаю в этом нет противоречия, в противном случае все бы до сих пользовались консольными почтовыми клиентами и в *nix-системах не появился GUI.
Поскольку в повседневности мне приходится использовать Powershell достаточно примитивно, то для начала я попытался понять, а можно ли к нему прикрутить GUI. Оказывается можно, да еще и достаточно просто:

Добавляем к этому элемент вывода и получаем элементарное Windwows-окнотавтология?.

Так инструмент которым я «пинговал Яндекс» и монтировал *.iso обзавёлся обособленным GUI, но этого мало. Подобным образом можно вывести информацию о доступности, но для мониторинга придется каждый раз перезапускать скрипт.
Для начала нарисуем две иконки и добавим возможность выводить изображения.

Опять наши DNS-ники шалят...

И еще добавим кнопку, чтобы была возможность обновлять показания.


Чудесно, теперь в продакшн!
Вручную прописав около полудюжины хостов я вдруг понял одну вещь — а ведь этот проект закончиться, хосты поменяют и мне придется каждый раз править скрипт. С одной стороны ничего страшного, это же решение для себя любимого. С другой стороныэто решение для себя любимого вы взгляните на то что получается:
Даже если соблюдать чистоту и придерживаться структуры то периодическое редактирование будет вызывать не самые приятные ощущения.
Для начала выносим проверку доступности в отдельную функцию, а путь к каталогу в отдельную переменную:
Вынесем данные о хосте во внешний файл path.txt, записывая в виде «ip/host-functional-name/», а в документе будем принимать их в массивы. Так же сделаем расчет положения по Y более автоматизированным. Все это дает нам возможность создавать Label`ы и checkbox`ы вызовом функции:

Добавим место для вывода времени последней проверки, потому что это удобно, и немого дополним действие при нажатии на кнопку.

А так же я присоединил небольшую фитчуне баг, которая при обнаружении недоступного хоста сообщало не только изменением индикатора, но и вопило из динамиков.
Так что после нескольких украшательств и приведения к читабельномуудобному мне виду, получилось вот так:
Надеюсь кому-то данный туториал будет полезен. Если же вы такое чуть-ли не с пеленок делали, то поздравляю, я — не делал. Но я готов выслушать ваши комментарии и предложения.
Для меня самого было приятно покопаться и собрать вот такую небольшую, но полезную в быту утилиту. В планах еще стоит реализовать добавления и удаления узлов из GUI, а так же сделатьтаки то что должно было быть реализованно в первую очередь автоматическое обновление статусов без необходимости «тыкать» кнопку и чтобы оно не вешало «powershell.exe».
Последняя версия скрипта на GitHub

Важно: я не программист и не системный администратор, но мне приходиться работать одновременно с большим набором серверов и сервисов и данный скрипт я написал для собственного удобства.
Всех кому это может быть
Почему Powershell
У меня есть опыт написания простых программ на Python, но он требует либо установленного интерпретатора, либо права на запуск .exe, что, в рамках моей работы не всегда возможно. А вот скрипт на Powershell чаще находит возможность запустить.
Не все любят консоль/терминал
Думаю в этом нет противоречия, в противном случае все бы до сих пользовались консольными почтовыми клиентами и в *nix-системах не появился GUI.
Поскольку в повседневности мне приходится использовать Powershell достаточно примитивно, то для начала я попытался понять, а можно ли к нему прикрутить GUI. Оказывается можно, да еще и достаточно просто:

Add-Type -assembly System.Windows.Forms #Подключим библиотеку $main_form = New-Object System.Windows.Forms.Form #Создаем объект с нашим "окном" #Задаем для него параметры $main_form.Text ='Links up' #Имя в заголовке $main_form.Width = 300 #Ширина окна $main_form.Height = 200 #Высота окна $main_form.AutoSize = $true #Даем ему возможность самостоятельно изменять размер, при необходимости $main_form.ShowDialog() #Вызываем "окно"
Добавляем к этому элемент вывода и получаем элементарное Windwows-окно

Add-Type -assembly System.Windows.Forms #Подключим библиотеку $main_form = New-Object System.Windows.Forms.Form #Создаем переменную с нашим "окном" #Задаем для него параметры через параметры $main_form.Text ='Links up' #Имя в заголовке $main_form.Width = 300 #Ширина окна $main_form.Height = 200 #Высота окна $main_form.AutoSize = $true #Даем ему возможность самостоятельно изменять размер, при необходимости $Label = New-Object System.Windows.Forms.Label #Все элементы формы будут заноситься в переменные, но по факту это объекты, как любые другие переменные в Powershell $Label.Text = "Привет! Я элементарное Windows-окно, а чего добился ты?" #Выводимый текст $Label.Location = New-Object System.Drawing.Point(10,65) #Расположение объекта внутри формы по горизонтали и вертикали (x,y) $Label.AutoSize = $true $main_form.Controls.Add($Label) #добавляем созданный объект к форме, чтобы он не потерялся при выполнении скрипта $main_form.ShowDialog() #Вызываем оскорбительно элементарное окно
Добавим динамики
Так инструмент которым я «пинговал Яндекс» и монтировал *.iso обзавёлся обособленным GUI, но этого мало. Подобным образом можно вывести информацию о доступности, но для мониторинга придется каждый раз перезапускать скрипт.
Для начала нарисуем две иконки и добавим возможность выводить изображения.

$PictureBox = New-Object system.Windows.Forms.PictureBox #Объект для вывода изображений называется вполне логично $PictureBox.width = 10 $PictureBox.height = 10 $PictureBox.location = New-Object System.Drawing.Point(178,12) #Вот тут мы переходим к делу привязываем выводимую картинку к результату проверки доступности узла используя командлет #<b>test-connection</b>, где: #-Count - передает кол-во запросов #-computer - IP или доменное имя для запроса #-quiet - для того чтобы нам вернулось только Boolean значение if ((test-connection -Count 1 -computer ya.ru -quiet) -eq $True) { $PictureBox.imageLocation = "C:\Test\yes.png" #Объект обращается к соответствующей картинке } Else { $PictureBox.imageLocation = "C:\Test\no.png" #Объект обращается к соответствующей картинке } $PictureBox.SizeMode = [System.Windows.Forms.PictureBoxSizeMode]::zoom $main_form.Controls.Add($PictureBox)

И еще добавим кнопку, чтобы была возможность обновлять показания.

$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 = "Reload" # Вешаем на событие нажатия кнопки обращение каждого PictureBox согласно ранее описанной логике $Button.Add_Click({ if ((Test-Connection -Count 1 -computer ya.ru -quiet) -eq $True) {$PictureBox.imageLocation = "C:\Test\yes.png"} Else {$PictureBox.imageLocation = "C:\Test\no.png"} if ((Test-Connection -Count 1 -computer 8.8.8.8 -quiet) -eq $True) {$PictureBox1.imageLocation = "C:\Test\yes.png"} Else {$PictureBox1.imageLocation = "C:\Test\no.png"} }) $main_form.Controls.Add($Button)

Чудесно, теперь в продакшн!?
Вручную прописав около полудюжины хостов я вдруг понял одну вещь — а ведь этот проект закончиться, хосты поменяют и мне придется каждый раз править скрипт. С одной стороны ничего страшного, это же решение для себя любимого. С другой стороны
Зрелище не для слабонервных
Add-Type -assembly System.Windows.Forms #Подключим библиотеку $main_form = New-Object System.Windows.Forms.Form #Создаем переменную с нашим "окном" #Задаем для него параметры через параметры $main_form.Text ='Links up' #Имя в заголовке $main_form.Width = 300 #Ширина окна $main_form.Height = 200 #Высота окна $main_form.AutoSize = $true #Даем ему возможность самостоятельно изменять размер, при необходимости $Label = New-Object System.Windows.Forms.Label #Все элементы формы будут заноситься в переменные, но по факту это объекты, как любые другие переменные в Powershell $Label.Text = "ya.ru ............................" #Выводимый текст $Label.Location = New-Object System.Drawing.Point(15,10) #Расположение объекта внутри формы по горизонтали и вертикали (x,y) $Label.AutoSize = $true $Label1 = New-Object System.Windows.Forms.Label #Все элементы формы будут заноситься в переменные, но по факту это объекты, как любые другие переменные в Powershell $Label1.Text = "8.8.8.8 ............................" #Выводимый текст googl-овский DNS-ник $Label1.Location = New-Object System.Drawing.Point(15,30) #Расположение объекта внутри формы по горизонтали и вертикали (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 #Объект для вывода изображений называется вполне логично $PictureBox.width = 10 $PictureBox.height = 10 #Вот тут мы переходим к делу привязываем выводимую картинку к результату проверки доступности узла используя командлет #<b>test-connection</b>, где: #-Count - передает кол-во запросов #-computer - IP или доменное имя для запроса #-quiet - для того чтобы нам вернулось только Boolean значение $PictureBox.location = New-Object System.Drawing.Point(235,12) if ((test-connection -Count 1 -computer ya.ru -quiet) -eq $True) { $PictureBox.imageLocation = "C:\Test\yes.png" #Объект обращается к соответствующей картинке } Else { $PictureBox.imageLocation = "C:\Test\no.png" #Объект обращается к соответствующей картинке } $PictureBox.SizeMode = [System.Windows.Forms.PictureBoxSizeMode]::zoom $PictureBox1 = New-Object system.Windows.Forms.PictureBox #Объект для вывода изображений называется вполне логично $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:\Test\yes.png" #Объект обращается к соответствующей картинке } Else { $PictureBox1.imageLocation = "C:\Test\no.png" #Объект обращается к соответствующей картинке } $PictureBox1.SizeMode = [System.Windows.Forms.PictureBoxSizeMode]::zoom $PictureBox2 = New-Object system.Windows.Forms.PictureBox #Объект для вывода изображений называется вполне логично $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:\Test\yes.png" #Объект обращается к соответствующей картинке } Else { $PictureBox2.imageLocation = "C:\Test\no.png" #Объект обращается к соответствующей картинке } $PictureBox2.SizeMode = [System.Windows.Forms.PictureBoxSizeMode]::zoom $PictureBox3 = New-Object system.Windows.Forms.PictureBox #Объект для вывода изображений называется вполне логично $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:\Test\yes.png" #Объект обращается к соответствующей картинке } Else { $PictureBox3.imageLocation = "C:\Test\no.png" #Объект обращается к соответствующей картинке } $PictureBox3.SizeMode = [System.Windows.Forms.PictureBoxSizeMode]::zoom $PictureBox4 = New-Object system.Windows.Forms.PictureBox #Объект для вывода изображений называется вполне логично $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:\Test\yes.png" #Объект обращается к соответствующей картинке } Else { $PictureBox4.imageLocation = "C:\Test\no.png" #Объект обращается к соответствующей картинке } $PictureBox1.SizeMode = [System.Windows.Forms.PictureBoxSizeMode]::zoom $PictureBox5 = New-Object system.Windows.Forms.PictureBox #Объект для вывода изображений называется вполне логично $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:\Test\yes.png" #Объект обращается к соответствующей картинке } Else { $PictureBox5.imageLocation = "C:\Test\no.png" #Объект обращается к соответствующей картинке } $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 = "Reload" # Вешаем на событие нажатия кнопки обращение каждого PictureBox согласно ранее описанной логике $Button.Add_Click({ if ((Test-Connection -Count 1 -computer ya.ru -quiet) -eq $True) {$PictureBox.imageLocation = "C:\Test\yes.png"} Else {$PictureBox.imageLocation = "C:\Test\no.png"} if ((Test-Connection -Count 1 -computer 8.8.8.8 -quiet) -eq $True) {$PictureBox1.imageLocation = "C:\Test\yes.png"} Else {$PictureBox1.imageLocation = "C:\Test\no.png"} if ((Test-Connection -Count 1 -computer 192.168.x.x -quiet) -eq $True) {$PictureBox2.imageLocation = "C:\Test\yes.png"} Else {$PictureBox2.imageLocation = "C:\Test\no.png"} if ((Test-Connection -Count 1 -computer 192.168.x.x -quiet) -eq $True) {$PictureBox3.imageLocation = "C:\Test\yes.png"} Else {$PictureBox3.imageLocation = "C:\Test\no.png"} if ((Test-Connection -Count 1 -computer 10.0.x.x -quiet) -eq $True) {$PictureBox4.imageLocation = "C:\Test\yes.png"} Else {$PictureBox4.imageLocation = "C:\Test\no.png"} if ((Test-Connection -Count 1 -computer 162.102.x.x -quiet) -eq $True) {$PictureBox5.imageLocation = "C:\Test\yes.png"} Else {$PictureBox5.imageLocation = "C:\Test\no.png"} }) $main_form.Controls.Add($Label) #добавляем созданный объект к форме, чтобы он не потерялся при выполнении скрипта $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() #Вызываем оскорбительно элементарное окно
Даже если соблюдать чистоту и придерживаться структуры то периодическое редактирование будет вызывать не самые приятные ощущения.
Для начала выносим проверку доступности в отдельную функцию, а путь к каталогу в отдельную переменную:
$script_path = "C:\Test\PS ping" #Переезжаем в финкцию уже созданный объект PictureBox и IP-адресс который нужно проверить. #На выходе оно меняет подгружаемую картинку. 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"} }
Вынесем данные о хосте во внешний файл path.txt, записывая в виде «ip/host-functional-name/», а в документе будем принимать их в массивы. Так же сделаем расчет положения по Y более автоматизированным. Все это дает нам возможность создавать Label`ы и checkbox`ы вызовом функции:

#создаем описательную линию, на вход идут: объект 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 }
Добавим место для вывода времени последней проверки, потому что это удобно, и немого дополним действие при нажатии на кнопку.

$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 })
А так же я присоединил небольшую фитчу
Add-Type -AssemblyName System.Speech $voice = New-Object System.Speech.Synthesis.SpeechSynthesizer $voice.Rate = 5 $voice.Speak("Ворнинг! Ворнинг! Байз из андер аттак!")
Так что после нескольких украшательств и приведения к читабельному
Полный код скрипта
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 #Переезжаем в финкцию уже созданный объект PictureBox и IP-адресс который нужно проверить. #На выходе оно меняет подгружаемую картинку. 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("Ошибка! Хост " + $path_ip + ", недоступен!") } } #создаем описательную линию, на вход идут: объект 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 } $main_form = New-Object System.Windows.Forms.Form $main_form.Text ='Links up' #Имя в заголовке $main_form.Width = 300 #Ширина окна $main_form.Height = 200 #Высота окна $main_form.AutoSize = $true #Даем ему возможность самостоятельно изменять размер, при необходимости $main_form.TopMost = $true #Это очень важная штука, она дает возможность закрепить окно поверх других $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 } #это поле с последним временем проверки $Label0 = New-Object System.Windows.Forms.Label $Label0.Text = Get-Date $Label0.Location = New-Object System.Drawing.Point(80,180) $Label0.AutoSize = $true # Вешаем на событие нажатия кнопки обращение каждого PictureBox согласно ранее описанной логике $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 = "Reload" $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()
Послесловие
Надеюсь кому-то данный туториал будет полезен. Если же вы такое чуть-ли не с пеленок делали, то поздравляю, я — не делал. Но я готов выслушать ваши комментарии и предложения.
Для меня самого было приятно покопаться и собрать вот такую небольшую, но полезную в быту утилиту. В планах еще стоит реализовать добавления и удаления узлов из GUI, а так же сделать
Последняя версия скрипта на GitHub