Автоматический перезапуск сервера с помощью PowerShell

Тема в разделе "Dedicated Server", создана пользователем Essence, 2 апр 2018.

  1. Essence

    Essence Солдат

    Многие администраторы серверов сталкиваются с проблемой падения или зависания сервера в случае каких-либо ошибок.
    Для автоматического перезапуска сервера существуют так называемые антикраш скрипты.
    Пример такого скрипта можно посмотреть здесь.
    Однако, подобный батник не сможет перезапустить сервер в случае ошибки GetPathName, из-за которой консоль сервера остаётся активной.
    Зато антикраш скрипт для PowerShell сможет.

    Основное.
    1. Переименовываем для удобства (или на случай наличия нескольких серверов) ucc.exe
    Например, в my_ucc.exe
    2. В батнике, с помощью которого мы запускаем сервер, пишем следующее:
    powershell ./Start_myServer.ps1
    3. Открываем Windows PowerShell и вставляем туда такой код:
    Код:
    $path = "D:\MyServer\System\my_ucc.exe" // Указываем путь к исполняемому файлу.
    $arg = "server KF-Farm.rom?game=KFMod.KFGameType?VACSecured=false?Mutator=MutLoader.MutLoader -log=server.log" // Указываем параметры запуска сервера.
    if( -not (get-process | where {$_.ProcessName -eq 'my_ucc'}))
    {
        for($i = 0; $i -lt 100; $i++)
        {
            'Starting process'
            $date = Get-Date -format yyyy_MM_dd_HH_mm
            $log = [string]::Concat('Log_',$date,'.x')
            $current_arg=[string]::Concat($arg,$log)
            Start-Process -FilePath $path -ArgumentList $current_arg
            $ps=get-process | where-object { $_.Name -eq 'my_ucc' }
            do {Start-Sleep -s 1} while ($ps.HasExited -eq $false)
            'Restarting'
            Start-Sleep -s 1
            $ps.Kill()
            Start-Sleep -s 1
        }
    }
    else
    {'Already exist'}
    Сохраняем как Start_myServer.ps1. Кладём в папку System.
    Запуск сервера производится с помощью всё того же батника.
    Утилита создаёт свои логи с названием, в котором содержится время его создания, то есть логи не будут затираться и вы сможете спокойно просматривать их, следя за работой сервера.

    Для тех, кому интересно, как это работает.
    Для создания новой переменной или для изменения значения переменной используется инструкция присваивания в следующем формате:
    Код:
    $<переменная> = <значение>

    Для начала создадим переменную, в которой будем хранить путь к исполняемому файлу.
    Код:
    $path = "D:\MyServer\System\my_ucc.exe"

    В этой переменной укажем параметры запуска сервера.
    Код:
    $arg = "server KF-Farm.rom?game=KFMod.KFGameType?VACSecured=false?Mutator=MutLoader.MutLoader -log=server.log"

    Дальше у нас идёт условие.
    Код:
    if( -not (get-process | where {$_.ProcessName -eq 'my_ucc'}))

    Код:
    -not
    Логический оператор (Запись операторов начинается знаком "-"). Изменяет результат оценки условия последующей инструкции на противоположный.

    Код:
    get-process
    Командлет получает процессы, выполняющиеся на локальном или удаленном компьютере.

    Код:
    |
    Отделяем один командлет от другого. Тем самым получаем конвейер - последовательность командлетов, записанную в одной строке и выполняемую особым образом.

    Код:
    where
    Результат выполнения любого командлета — это объект. А зачастую не один а объект, а массив объектов. Для фильтрации только определенных объектов в Powershell используется Where. На самом деле Where — это алиас для командлета Where-Object.

    Код:
    {}
    Дальше у нас используется параметр FilterScript. Значение FilterScript представляет собой блок сценария — одну или несколько команд Windows PowerShell, заключенных в фигурные скобки {}, — результатом которого могут быть значения True или False. Такие блоки сценариев могут быть очень простыми, но для их создания требуется понимание другой концепции Windows PowerShell, а именно операторов сравнения. При использовании данного способа после Where в фигурных скобках указывается условие, которое обращается к свойствам объекта через переменную $_. Переменная $_ содержит текущий объект просматриваемый в конвейере. Обращение к свойствам текущего объекта осуществляется через точку.

    Код:
    $_.ProcessName
    Наименование процесса.

    Код:
    -eq
    Оператор сравнения. Равенство. Распространяется на случай совпадения значений.

    Код:
    'my_ucc'
    Имя нашего процесса.
    То есть, наше условие будет выглядеть примерно так: Если процесс my_ucc не запущен на компьютере, то...
    То дальше мы запускаем цикл.

    Код:
    for($i = 0; $i -lt 100; $i++)

    Код:
    -lt
    Оператор сравнения. Меньше.
    В данном случае, цикл может выполнится 100 раз, можно, конечно, выставить число побольше, но это ни к чему, и 100 хватит.

    Код:
    'Starting process'
    Выводим информацию о том, что процесс запущен.

    Создаём переменную, в которой будет хранится дата запуска сервера.
    Код:
    $date = Get-Date -format yyyy_MM_dd_HH_mm

    Код:
    Get-Date
    Командлет получает объект DateTime, содержащий текущую или заданную дату.

    Код:
    -format
    При использовании параметра Format оболочка Windows PowerShell возвращает только те свойства объекта DateTime, которые требуются для отображения даты в указанном формате.

    yyyy - год, MM - месяц, dd - день, HH - минута, mm - секунда.

    Создадим переменную, в которой будем хранить время запуска сервера.
    Код:
    $log = [string]::Concat('Log_',$date,'.x')
    Метод Concat используется для объединения нескольких строк. Методы – это действия, имеющие отношение к данным объекта, такие как удаление или перемещение файла.

    В качестве примера у нас получится такая строка:
    Код:
    Log_2018_04_02_11_55.x

    Сам файл с логом будет называться так:
    Код:
    server.logLog_2018_04_02_11_55.x

    Создадим переменную, в которой объединим строку запуска сервера и строку, содержащую время запуска сервера.
    Код:
    $current_arg=[string]::Concat($arg,$log)

    Запускаем процесс.
    Код:
    Start-Process -FilePath $path -ArgumentList $current_arg

    Код:
    Start-Process
    Запускает один или несколько процессов на локальном компьютере.

    Код:
    -FilePath
    Задает путь и имя файла программы, выполняемой в процессе.

    Код:
    -ArgumentList
    Задает параметры или значения параметров, используемые при запуске процесса.

    Получаем объект процесса.
    Код:
    $ps=get-process | where-object { $_.Name -eq 'my_ucc' }

    Дальше имеем следующее:
    Код:
    do {Start-Sleep -s 1} while ($ps.HasExited -eq $false)

    Код:
    do
    Выполняет список инструкций один или несколько раз в зависимости от условия While.

    Код:
    Start-Sleep
    Командлет приостанавливает выполнение скрипта или сеанса на указанный период времени.

    Код:
    -s
    Секунды, в данном случае - одна.

    Код:
    $ps.HasExited
    Примет значение true, если запущенный процесс операционной системы (в данном случае наш сервер) был завершен; в противном случае — значение false.
    То есть, наше условие будет выглядеть следующим образом: Приостанавливаем выполнение скрипта на одну секунду (Проще говоря, находимся в спящем режиме), если процесс активен.
    Если процесс завершится или зависнет, произойдёт выход из while.

    Код:
    'Restarting'
    Выводим информацию о том, что процесс перезапускается.

    Код:
    Start-Sleep -s 1
    Спим одну секунду.

    Код:
    $ps.Kill()
    Останавливаем процесс.

    Код:
    Start-Sleep -s 1
    Спим ещё одну секунду.

    Код:
    else {'Already exist'}
    Eсли процесс уже существует, не выполняем скрипт, выводим информацию о том, что сервер уже запущен.

    После этого наступит следующий цикл и сервер снова запустится.

    Автор скрипта: Flame
    Автор статьи: Essence
    Ссылка на PowerShell файл: Start_myServer.ps1
     
    RaideN- и STaJIKeR нравится это.
  2. STaJIKeR

    STaJIKeR Капо

    Титанический труд, господа!