Из любого скрипта PowerShell можно сделать службу Windows, которая работает в фоновом режиме и запускается автоматически при загрузке сервера. Вы можете создать службу Windows с помощью утилит srvany.exe и instsrv.exe (из состава Windows Server Resource 2003 Kit), позволяющих запустить процесс powershell.exe с параметром в виде пути к ps1 файлу скрипта. Основной недостаток такого способа создания службы — srvany.exe не контролирует выполнение приложения (скрипта PowerShell в нашем случае) и, если приложение падает (зависает), то служба это не видит и продолжает работать. В этой статье для создания службы Windows из файла со скриптом PowerShell мы будем использовать утилиту NSSM (Non-Sucking Service Manager – оставим без перевода…:)), которая лишена этих недостатков.
Вы можете скачать и установить NSSM вручную или через Chocolately. Сначала нужно разрешить запуск PS1 скриптов в сесиии и установить сам Choco:
Set-ExecutionPolicy Bypass -Scope Process -Force; `
iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))
Затем установим пакет NSSM:
choco install nssm
В этом примере мы будем в реальном времени отслеживать изменения определенной группы AD (скрипт из этой статьи) и при изменении оповещать администратора безопасности всплывающим уведомлением и письмом.
Итак, у нас имеется код, который нужно сохранить в PS1 файл. Добавим бесконечный цикл, который раз в минуту выполняет проверку:
while($true) {
#Ваш PS код
Start-Sleep –Seconds 60
}
Создать службу из скрипта PowerShell при помощи NSSM можно прямо из PowerShell :):
$NSSMPath = (Get-Command "C:\tools\nssm\win64\nssm.exe").Source
$NewServiceName = “CheckADGroupSrv”
$PoShPath= (Get-Command powershell).Source
$PoShScriptPath = “C:\tools\CheckADGroup\checkad.ps1”
$args = '-ExecutionPolicy Bypass -NoProfile -File "{0}"' -f $PoShScriptPath
& $NSSMPath install $NewServiceName $PoShPath $args
& $NSSMPath status $NewServiceName
Запустим новую службу:
Start-Service $NewServiceName
Проверим статус службы с помощью PowerShell:
Get-Service $NewServiceName
Итак, вы создали и запустили новую службу Windows. Проверим, что она появилась в консоли управления службами services.msc
Служба CheckADGroupSrv действительно появилась, она настроена на автоматический запус и в данный момент запущена (Running). Как вы видите, ваш PowerShell скрипт запущен внутри процесса nssm.exe.
Чтобы служба могла отображать уведомления в сеанс пользователя (взаимодействовать с рабочим столом) нужно на вкладке “Вход в систему” (Log on) включить опцию “Разрешить взаимодействие с рабочим столом” (Allow service to interact with desktop).
Start-Service -Name ui0detect
Однако в Windows 10 1803 службу Interactive Services Detection Service полностью убрали из системы, и вы более не можете переключиться в нулевую сессию (Session 0), так что вы просто не увидите окна, которые выводятся из-под аккаунта System.
Вы можете изменить описание службы командой:
& $NSSMPath set $NewServiceName description “Мониторинг изменений группы AD”
Чтобы удалить созданную службу можете воспользоваться командой sc delete или
nssm remove CheckADGroupSrv
А можно как то подготовить данную службу как бы дистрибутивом, чтобы можно было групповыми политиками распространить на компьютеры домена?
Наверно проще скопировать нужные файлы (exe и ps1) на все компьютеры домена через Logon скрипт или GPO (https://winitpro.ru/index.php/2020/03/05/copy-files-folders-with-gpo/), а затем следующим логон скриптом (с кодом из этой статьи) установить и запустить службу.
Желательно сначала в скрипте проверить, что сервис уже установлен.
В этом случае файл C:\tools\CheckADGroup\checkad.ps1 должен постоянно присутствовать на диске?
Да, файл должен быть на месте при при старте NSSM службы. Загружается ли он в память или каждый раз читается с диска — сказать не смогу. Под рукой такого стенда уже нет.
PS C:\Users\user\Desktop> $NSSMPath = (Get-Command «C:\tools\nssm\win64\nssm.exe»).Source
Get-Command : Имя «C:\tools\nssm\win64\nssm.exe» не распознано как имя командлета, функции, файла сценария или выполняе
мой программы. Проверьте правильность написания имени, а также наличие и правильность пути, после чего повторите попытк
у.
строка:1 знак:14
+ $NSSMPath = (Get-Command «C:\tools\nssm\win64\nssm.exe»).Source
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (C:\tools\nssm\win64\nssm.exe:String) [Get-Command], CommandNotFoundExce
ption
+ FullyQualifiedErrorId : CommandNotFoundException,Microsoft.PowerShell.Commands.GetCommandCommand
Проверьте, что путь существует и кавычки:
$NSSMPath = (Get-Command "C:\tools\nssm\win64\nssm.exe").Source
Start-Service : Service ‘HostExtractorSrv (HostExtractorSrv)’ cannot be started due to the following error:
Cannot open HostExtractorSrv service on computer ‘.’.
At C:\program\srv-setup.ps1:21 char:9
+ Start-Service $NewServiceName
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OpenError: (System.ServiceProcess.ServiceController:ServiceController) [Start-Serv
ice], ServiceCommandException
+ FullyQualifiedErrorId : CouldNotStartService,Microsoft.PowerShell.Commands.StartServiceCommand
Никак не пойму, почему не стартует служба. Только вручную запускается.
Из-под кого запускается служба? Если от пользователя, возможно просто прав недостаточно
Добрьій вечер!
Запущенньій скрипт в PowerShell загружает программу как App.
Тот же скрипт из под NSSM загружает программу как Background Process.
Как сделать так что бьі программа загружалась как App?
Спасибо.
Выражение, расположенное после «&» в элементе конвейера, выдало недопустимый объект. Результатом выражения должно быть имя команды, блок сценария или объект CommandInfo.
строка:6 знак:3
+ & $NSSMPath install $NewServiceName $PoShPath $args
+ ~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : BadExpression