Вопрос или проблема
У меня есть служба Windows, которая использует базу данных SQL Server. Я не имею контроля над установкой службы, но хотел бы добавить зависимость к этой службе, чтобы она запускалась после того, как SQL Server уже запущен. (SQL Server работает на той же машине, что и рассматриваемая служба)
Есть ли инструмент для добавления зависимости или, возможно, редактирование реестра напрямую?
Это также можно сделать через с повышенными правами командную строку, используя команду sc
. Синтаксис следующий:
sc config [service name] depend= <Dependencies(separated by / (forward slash))>
Примечание: Пробел есть после знака равенства, и его нет перед ним.
Предупреждение: Параметр depend=
перезапишет существующий список зависимостей, а не добавит к нему. Например, если ServiceA уже зависит от ServiceB и ServiceC, и вы выполняете depend= ServiceD
, теперь ServiceA будет зависеть только от ServiceD. (Спасибо Matt!)
Примеры
Зависимость от одной другой службы:
sc config ServiceA depend= ServiceB
Вышеуказанное означает, что ServiceA не запустится, пока не будет запущена ServiceB. Если вы остановите ServiceB, ServiceA автоматически остановится.
Зависимость от нескольких других служб:
sc config ServiceA depend= ServiceB/ServiceC/ServiceD/"Service Name With Spaces"
Вышеуказанное означает, что ServiceA не запустится, пока не будут запущены ServiceB, ServiceC и ServiceD. Если вы остановите любую из служб ServiceB, ServiceC или ServiceD, ServiceA автоматически остановится.
Чтобы удалить все зависимости:
sc config ServiceA depend= /
Чтобы просмотреть текущие зависимости:
sc qc ServiceA
Вы можете добавить зависимости службы, добавив значение “DependOnService” в реестре с помощью команды regedit
, службы можно найти по пути HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\<Service name>
.
Подробности можно найти в статье 193888 на сайте Microsoft.
Чтобы добавить зависимость:
-
Выберите подраздел службы, нажмите правой кнопкой мыши на имени службы и выберите “Новый” -> “Множественная строка” (REG_MULTI_SZ)
-
Создайте новое значение с именем “DependOnService” (без кавычек) и нажмите OK.
-
Когда появится окно ввода данных, введите имя или имена служб, которые вы предпочитаете запускать перед этой службой, с одной записью на каждой строке, и нажмите OK.
Я искал чисто метод с помощью PowerShell (без regedit или sc.exe), который может работать на 2008R2/Win7 и новее, и пришел к следующему:
Простой способ – сделать regedit с помощью PowerShell:
Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Services\LanmanWorkstation' -Name DependOnService -Value @('Bowser','MRxSmb20','NSI')
Или используя WMI:
$DependsOn = @('Bowser','MRxSmb20','NSI','') #оставьте пустой элемент массива в конце
$svc = Get-WmiObject win32_Service -filter "Name="LanmanWorkstation""
$svc.Change($null,$null,$null,$null,$null,$null,$null,$null,$null,$null,$DependsOn)
Метод Change класса Win32_Service помог указать на решение:
uint32 Change(
[in] string DisplayName,
[in] string PathName,
[in] uint32 ServiceType,
[in] uint32 ErrorControl,
[in] string StartMode,
[in] boolean DesktopInteract,
[in] string StartName,
[in] string StartPassword,
[in] string LoadOrderGroup,
[in] string LoadOrderGroupDependencies[],
[in] string ServiceDependencies[]
);
Я написал простое .NET приложение для управления зависимостями служб, если вас это заинтересует. Это бесплатно.
http://webpages.charter.net/bushman4/servicedependencymanager.html
В C++ (ATL) я сделал следующее
bool ModifyDependOnService(void)
{
CRegKey R;
if (ERROR_SUCCESS == R.Open(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\services\\MyService"))
{
bool depIsThere = false;
// определяем, установлена ли другая служба, если да, то добавляем в список зависимостей.
SC_HANDLE hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
if (hSCManager)
{
SC_HANDLE hService = OpenService(hSCManager, L"OtherService", SERVICE_QUERY_STATUS);
if (hService)
{
depIsThere = true;
CloseServiceHandle(hService);
}
CloseServiceHandle(hSCManager);
}
std::wstring key = L"DependOnService";
if (depIsThere )
{
const wchar_t deps[] = L"RPCSS\0OtherService\0";
R.SetValue(key.c_str(), REG_MULTI_SZ, deps, sizeof(deps));
}
R.Close();
return true;
}
return false;
}
Создал пакет “svcDependDelAdd.BAT” для удаления и/или добавления зависимости к службе, он не добавит, если не существует. Можно вызвать. Преимущества над принятым ответом в том, что он не удаляет другие зависимости, просто удаляет (или добавляет) нужную. Включена помощь:
@echo off
set PARAM=%* _& REM _ избегайте, если PARAM пустой при отсутствии параметров, %* это остальные параметры
rem https://serverfault.com/questions/24821/how-to-add-dependency-on-a-windows-service-after-the-service-is-installed/1165202#1165202
IF not "%PARAM:/noh=%"=="%PARAM%" goto :noHelp
echo .
echo . svcDependDelAdd v24.0915
echo . Удаляет и/или добавляет зависимую службу, можно указать "none":
echo .
echo . svcDependDelAdd targetSvc [[dependSvcToDelete] dependSvcToAdd] [/switches]
echo .
echo .
echo . переключатели:
echo . /noHelp: не показывать это
echo . /noPause: в конце
echo .
echo . Примеры:
echo . svcDependDelAdd nlaSvc /noh/nop (список зависимостей nlaSvc разделен на \0^)
echo . svcDependDelAdd nlaSvc eventLog (Удаляет зависимость eventLog от nlaSvc^)
echo . svcDependDelAdd none eventLog (Добавляет зависимость eventLog к nlaSvc^)
echo .
echo .
:noHelp
setlocal enableextensions enableDelayedExpansion & REM получить значение переменной на Exec с !varNm!
rem Целевая служба, напр.: "nlaSvc"; или "aelookupsvc" не имеет зависимостей
set "targSvc=%1"
rem установите на "none", если это пусто, или если оно имеет слэш {/ switch}
IF not "!targSvc:/=!"=="!targSvc!" set "targSvc=none"
rem Зависимость для удаления, может быть пустым/недействительным/неопределенным, напр.: "Eventlog"
set "delDep=%2"
IF not "!delDep:/=!"=="!delDep!" set "delDep=none"
rem Зависимость для добавления, может быть пустым/нет/неопределенным, не добавит несуществующую службу
set "addDep=%3"
IF not "!addDep:/=!"=="!addDep!" set "addDep=none"
rem echo "%targSvc%" "%delDep%" "%addDep%"
rem проверить существование услуги
if not "!targSvc:none=!"=="" ( rem не "none" и не пуст
sc qc "!targSvc!" >nul 2>&1
if errorlevel 1 ( set errMsg=Svc "%targSvc%" не найден & goto :error )
) else ( set errMsg=Служба не указана & goto :error )
rem Получить список зависимостей %targSvc%
set depList=\0
for /f "usebackq tokens=1,2,*" %%x in (`reg query HKLM\System\CurrentControlSet\Services\%targSvc% /v DependOnService`) do (
if "%%y"=="REG_MULTI_SZ" set "depList=%%z\0"
) & rem endList
rem удалить: найдите его и установите новый список зависимостей
set "newDep=!depList!" & rem новый список зависимостей для установки
if "!depList!"=="\0" (
echo %targSvc% зависимости не найдены!
) else (
echo "%targSvc%" список зависимостей: "!depList!"
rem удалить зависимость из нового списка
if not "!delDep:none=!"=="" (
set "newDep=!depList:%delDep%\0=!"
rem set "newDep=!newDep:\0\0=\0!"
if "!newDep!"=="!depList!" (
echo "%delDep%" не найден в "%targSvc%"
) else echo удалить найденный "%delDep%"
) & rem delDep
)
rem добавить: найти и установить новый список зависимостей
if not "!addDep:none=!"=="" if "!newDep:%addDep%\0=!"=="!newDep!" (
rem не нет/пусто, и не уже присутствует в новом списке
reg query HKLM\System\CurrentControlSet\Services\%addDep% 1>nul 2>&1
if errorlevel 1 ( echo добавить "%addDep%" не найден
) else (
echo добавить найденный "%addDep%"
set "newDep=!newDep!%addDep%\0" & rem добавить в список
if "!depList!"=="\0" set "newDep=%addDep%" & rem оригинальный список был пустой
)
) else echo добавить "%addDep%" уже присутствует
rem записать новый список зависимостей
if "!newDep!"=="!depList!" ( echo Нечего делать... ) else (
echo список новых зависимостей "!newDep!" ...
reg add HKLM\System\CurrentControlSet\Services\%targSvc% /v DependOnService /t REG_MULTI_SZ /d "!newDep!" /f
if errorlevel 1 ( set errMsg=не удалось обновить ключ зависимости "%targSvc%" DependOnService & goto :error )
)
echo -ГОТОВО-
goto :fin
:error
echo\ Ошибка: !errMsg!
:fin
echo\
IF "%PARAM:/nop=%"=="%PARAM%" pause
.
Ответ или решение
Как добавить зависимость к Службе Windows после её установки
Введение зависимости для службы Windows может быть необходимым шагом для гарантии, что ваша служба запускается после всех необходимых компонентов, например, после SQL Server, который используется вашей службой и находится на одной машине. Есть несколько подходов к решению этой задачи, включая использование командной строки, правки реестра и написание скриптов на PowerShell. Рассмотрим каждый из них подробнее.
Теория
Прежде всего, следует понять, что служба Windows может зависеть от одной или нескольких других служб. Это обозначается свойством DependOnService, и позволяет гарантировать, что ваша служба не начнется до тех пор, пока все службы, от которых она зависит, не будут активированы. Это полезно в случаях, когда порядок запуска критически важен для корректной работы программы.
Пример
-
Использование инструмента командной строки
sc
:
Командаsc config
позволяет вам настроить параметры уже существующей службы. Исправление зависимости выполняется как:sc config [имя вашей службы] depend= [список зависимостей через /]
Например, если ваша служба называется ServiceA, и вы хотите, чтобы она зависела от MSSQLSERVER, вы можете использовать:
sc config ServiceA depend= MSSQLSERVER
Обратите внимание на важность пробела после
depend=
и отсутствие пробела перед ним. Учтите, что эта команда перезаписывает существующий список зависимостей, так что если ваша служба уже имеет другие зависимости, их потребуется указать повторно. -
Редактирование реестра Windows:
Вы можете вручную внести изменения в реестр для добавления зависимости. Шаги следующие:- Запустите
regedit
от имени администратора. - Перейдите в раздел
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\[имя вашей службы]
. - Найдите (или создайте) значение DependOnService (типа REG_MULTI_SZ).
- Внесите имена всех необходимых служб в отдельные строки для каждой зависимости.
Этот метод дает больше контроля и позволяет избежать перезаписывания других существующих зависимостей.
- Запустите
-
Скрипты PowerShell:
PowerShell предлагает гораздо более гибкие инструменты для администрирования систем. Используйте командлетSet-ItemProperty
для непосредственной работы с реестром:Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Services\[имя вашей службы]' -Name DependOnService -Value @('MSSQLSERVER')
Или вы можете воспользоваться объектами WMI для обновления зависимостей программно:
$DependsOn = @('MSSQLSERVER', '') $svc = Get-WmiObject win32_Service -filter "Name='[имя вашей службы]'" $svc.Change($null, $null, $null, $null, $null, $null, $null, $null, $null, $null, $DependsOn)
Применение
После того как вы выбрали подходящий метод, можно приступить к внесению изменений. Обязательно убедитесь, что у вас есть права администратора на машине, на которой производится изменение. Резервное копирование текущих настроек реестра может быть хорошей практикой, чтобы избежать случайных ошибок.
На практике, для обеспечения минимального простоя служб, рекомендуется использовать PowerShell, так как он предоставляет наибольшую гибкость и возможность интеграции с другими административными задачами и расписаниями. Однако, для более быстрого развертывания изменений на нескольких машинах, написание скриптов на основе sc
или правка реестра могут стать эффективными решениями.
Заключение
Изменение зависимостей службы Windows после её установки — это несложный, но очень важный процесс, который может иметь значительное влияние на работу вашего приложения, особенно в крупных системах, где несколько служб работают в тесной интеграции. Выбор определенного метода зависит от ваших потребностей и уровня доступа в системе, но следуя данным указаниям, вы сможете осуществить необходимые изменения надежно и безопасно.