Как пинговать заданный IP и подавать звуковой сигнал при недоступности

Как-то возникла потребность отслеживать доступность в сети нескольких важных устройств и отвлекать оператора от кроссвордов негромким, но навязчивым писком. Дело происходило в изолированной сети, где нежелательно устанавливать сторонний софт.

Закрыть этот вопрос помог почти забытый скриптовый язык hta. Получилось довольно изящно: в 150 строчках уместились и код, и нехитрый пользовательский интерфейс, и кастомный звуковой сигнал. Скрипт делает ровно одну вещь: пингует адреса по списку и пищит через колонки, когда связь пропала. Бип!

Скрипт запускается как приложение, двойным кликом. Список адресов для проверки задаётся внутри, для этого файл нужно открыть с помощью блокнота.

post

Детали

Скрипт работает одинаково хорошо на всей линейке Windows от XP до 11-й, ничего дополнительно устанавливать не нужно.

В системе должно быть разрешено исполнение ActiveX для локальных страниц (по умолчанию разрешено). Это галочки в окне настроек internet Explorer, в разделе, связанном с безопасностью и политиками. Да, hta крутится на движке IE, который Microsoft сохранили даже в эпоху Edge.

ping

Код

Записывать в кодировке ansi:


<html>
<head>
    <title>Мониторинг связи</title>
    <HTA:APPLICATION APPLICATIONNAME="PingMonitor" SINGLEINSTANCE="yes" />
</head>
<body>
<h1>Проверка связи</h1>
<label><input type="checkbox" id="alarm" checked> Сигнал при потере связи</label>
<br><br>
<div id="grid"></div>
<div id="alarm_wrap"></div>

<script language="JScript">

// Версия 12.01.2026  
// Мониторим связь и пиликаем через колонки при сбоях     

// Список проверяемых адресов:  
var hosts = [
    {ip: "192.168.1.1", name: "Циска" },
    {ip: "192.168.1.2", name: "База данных" },
    {ip: "PetelinSasha.ru"   }  // name задавать не обязательно
];  

var pingInterval = 6000;
var pingTimeout = '1000';

// Звук бип - можно заменить на свой, это wav в base64-with-padding
var alarmBase64="UklGRuYBAABXQVZFZm10IBAAAAABAAEAESsAABErAAABAAgAZGF0YcIBAAB/gIaHd3eEeGmHlXhzi52IcYx5V3uCcoScoIJlhmZdh4CEmLCba0t6VVygm5WSq4xbT31bdKeYk46kf0ZefFiFsJSLlad0OnByWomkkYeZo3BAg29fkJ6MhZ6YYkyGYW2hk4mNpYlVXoNdeaONipCkf0xwfF6DooqIlJ90S35xYo2ahYiZmWlQh2ZpmZKEiJ2QYFuIYXSfjYeKooZVaoJdfKKJh5CifFF3eF6EnYSHlZ9xT4NsY5GXg4ialmZVh2Rsm5KHip+MW2GGXnakjYeNoIBVbYBffqKHh5GhdlB8dWCJnIOGlpxtUYVrZ5SVhYebk2NZiGNunZCGiZ6JW2OFYHehi4eNoX5Ucnxfgp+FhpKfdFF/cmOLl4SGl5lqVIdoaJaThYabj2Jch2Ryno6Fip+FWmqCYHyhh4aPoXtVd3lhhJuEh5OdcVKDb2SOl4WGl5VpVohobJiShIecjGFhhmJ2oIuFi5+CWW5/YX+eh4eQoHdSfHZhiJyFhpSZb1OFbmeRloSGmJFmWohlcJyPhImdiF5lhGF4noqGjKB/VXR9YIGfh4aRnXVTfnVjipqEhpWXbFWHa2qVk4OGmY9kXYc="

for (var i = 0; i < hosts.length; i++) {
    var host = hosts[i];
    if (!host.name) host.name = host.ip;
    host.lastSeen = "-";
    host.status = 1;
    host.lostCount = 0;
}  

var wmi=GetObject("winmgmts:root/cimv2");

function base64ToBinary(b64) {
    var xml = new ActiveXObject("MSXML2.DOMDocument.6.0");
    var el = xml.createElement("tmp");
    el.dataType = "bin.base64";
    el.text = b64;
    return el.nodeTypedValue;
}

var fso=new ActiveXObject("Scripting.FileSystemObject");
var tempFile=fso.GetSpecialFolder(2) + "\\noping.wav";
var stream = new ActiveXObject("ADODB.Stream");
stream.Type = 1;
stream.Open();
stream.Write(base64ToBinary(alarmBase64));
stream.SaveToFile(tempFile, 2);
stream.Close();

function playSound() {
    if (!document.getElementById("alarm").checked) return;
    var wrap = document.getElementById("alarm_wrap");
    var bs = document.createElement("bgsound");
    bs.loop = 1;
    bs.src = tempFile;
    wrap.innerHTML = "";
    wrap.appendChild(bs);
}

function autosize() {
    var table = document.getElementById("mainTable");
    window.resizeTo(table.offsetWidth + 140, document.body.scrollHeight + 80);
}

function decodeStatus(code) {
    switch(code) {
        case 0: return "Доступен";
        case 1: return "...";
        case 11002: return "Destination net unreachable";
        case 11003: return "Host not found";
        case 11004: return "Destination host unreachable";
        case 11010: return "Request timed out";
        default: return "Ошибка "+code;
    }
}

function render() {
    var html="<table id='mainTable' border=1 cellpadding=4 cellspacing=0>";
    html+="<tr bgcolor='#cccccc'><th>Адрес</th><th>Устройство</th><th>Когда был в сети</th><th>Состояние</th><th>Потери</th></tr>";
    for (var i=0;i<hosts.length;i++) {
        var h=hosts[i];
        var ok=(h.status==0);
        var color = ok?"#00aa00":"#aa0000";
        color = (h.status==1)?"#cccccc":color;
        html+="<tr bgcolor='"+color+"' style='color:white'>";
        html+="<td>"+h.ip+"</td>";
        html+="<td>"+h.name+"</td>";
        html+="<td>"+h.lastSeen+"</td>";
        html+="<td>"+decodeStatus(h.status)+"</td>";
        html+="<td>"+h.lostCount+"</td>";
        html+="</tr>";
    }
    html+="</table>";
    document.getElementById("grid").innerHTML=html;
}

function check() {
    var i = 0, anyFail = false;

    function nextHost() {
        if (i >= hosts.length) {
            if (anyFail) playSound();
            return setTimeout(check, pingInterval);
        }

        var host = hosts[i++];
        var res = new Enumerator(wmi.ExecQuery("SELECT * FROM Win32_PingStatus WHERE Address='" + host.ip + "' AND Timeout=" + pingTimeout));

        if (!res.atEnd()) {
            host.status = res.item().StatusCode;
            if (host.status == 0) {
                host.lastSeen = new Date().toLocaleTimeString();
            } else {
                anyFail = true;
                host.lostCount++;
            }
        } else {
            host.status = -1;
            host.lostCount++;
            anyFail = true;
        }

        render();
        setTimeout(nextHost, 50);
    }

    nextHost();
}

render();
autosize();
setTimeout(check,50);

</script>
</body></html>