PowerShell: Делим службы по процессам и собираем обратно в один процесс (svchost.exe)
Немного переписал свою статью. Выделил функции, чтобы иметь возможность выделять в отдельные процессы как все службы, так и конкретные. Пример задачи, где мне пришлось делить группу служб, работающих в одном процессе, на несколько процессов, уже описывал.
P.S. Описываемый PowerShell модуль опубликовал в своём SVN репозитории.
Делим группу на самостоятельные процессы (по рецепту, описанному в статье):
(Get-ItemProperty ` -path HKLM:'\Software\Microsoft\Windows NT\CurrentVersion\Svchost' ` -name netsvcs ` ).netsvcs ` | ? {Test-Path HKLM:"\SYSTEM\CurrentControlSet\Services\$($_)"} ` | % { $newSvcGroupKey = New-ItemProperty ` -path HKLM:'\Software\Microsoft\Windows NT\CurrentVersion\Svchost' ` -name "netsvc_$($_)" ` -value ([System.String[]]@($_)) ` -force ` ; Set-ItemProperty ` -path HKLM:"\SYSTEM\CurrentControlSet\Services\$($_)" ` -name ImagePath ` -value “%systemroot%\system32\svchost.exe -k netsvc_$($_)” ` -force ` ; }; Set-ItemProperty ` -path HKLM:'\Software\Microsoft\Windows NT\CurrentVersion\Svchost' ` -name netsvcs ` -value ([System.String[]]@()) ` -force;
И собираем обратно в одну группу (один процесс):
$svcs = ($svcGroups = get-itemProperty ` -path HKLM:'\Software\Microsoft\Windows NT\CurrentVersion\Svchost' ` ) ` | get-member -memberType NoteProperty ` | ? {$_.name -match 'netsvc_(?<svc>.+)'} ` | % { $svc = $matches['svc']; invoke-expression "`$svcGroups.$($_.name)"; Remove-ItemProperty ` -path HKLM:'\Software\Microsoft\Windows NT\CurrentVersion\Svchost' ` -name $_.name ` ; }; $svcs = ` (Get-ItemProperty ` -path HKLM:'\Software\Microsoft\Windows NT\CurrentVersion\Svchost' ` -name netsvcs ` ).netsvcs + $svcs ` | sort -unique ; Set-ItemProperty ` -path HKLM:'\Software\Microsoft\Windows NT\CurrentVersion\Svchost' ` -name netsvcs ` -value $svcs ` -force ; $svcs ` | ? {Test-Path HKLM:"\SYSTEM\CurrentControlSet\Services\$($_)"} ` | % { Set-ItemProperty ` -path HKLM:"\SYSTEM\CurrentControlSet\Services\$($_)" ` -name ImagePath ` -value “%systemroot%\system32\svchost.exe -k netsvcs” ` -force ` ; };
Надеюсь, эти сценарии помогут Вам в отладке.
А теперь оформим приведённые выше сценарии “правильными” командлетами:
function Get-ServicesWithOwnProcess { <# .Synopsis Возвращает массив идентификаторов служб, выделенных нами в отдельный процесс. .Description Возвращает массив идентификаторов служб, выделенных нами в отдельный процесс. .Example Get-ServicesWithOwnProcess ` | Set-ServiceCommonProcess #> get-itemProperty ` -path HKLM:'\Software\Microsoft\Windows NT\CurrentVersion\Svchost' ` | get-member -memberType NoteProperty ` | ? {$_.name -match 'netsvc_(?<svc>.+)'} ` | % { $matches['svc']; }; }; function Get-ServicesWithCommonProcess { <# .Synopsis Возвращает массив идентификаторов служб, использующих процесс svchost.exe (группа netsvcs). .Description Возвращает массив идентификаторов служб, использующих процесс svchost.exe (группа netsvcs). .Example Get-ServicesWithCommonProcess ` | Set-ServiceOwnProcess #> (Get-ItemProperty ` -path HKLM:'\Software\Microsoft\Windows NT\CurrentVersion\Svchost' ` -name netsvcs ` ).netsvcs ` | ? {Test-Path HKLM:"\SYSTEM\CurrentControlSet\Services\$($_)"} ` ; }; function Set-ServiceOwnProcess { <# .Synopsis Выделение для указанного сервиса собственного процесса svchost.exe. .Description Выделение для указанного сервиса собственного процесса svchost.exe. .Parameter service Идентификатор службы .Example Set-ServiceOwnProcess ` -service 'AppMgmt' #> [CmdletBinding( SupportsShouldProcess = $true, ConfirmImpact = 'Low' )] param ( [Parameter( Mandatory=$true, Position=0, ValueFromPipeline=$true, HelpMessage="Идентификатор службы." )] [string]$service ) $service ` | ? {Test-Path HKLM:"\SYSTEM\CurrentControlSet\Services\$($_)"} ` | ? { (Get-ItemProperty ` -path HKLM:'\Software\Microsoft\Windows NT\CurrentVersion\Svchost' ` -name netsvcs ` ).netsvcs -contains $_ ` } ` | % { $newSvcGroupKey = New-ItemProperty ` -path HKLM:'\Software\Microsoft\Windows NT\CurrentVersion\Svchost' ` -name "netsvc_$($_)" ` -value ([System.String[]]@($_)) ` -force ` ; Set-ItemProperty ` -path HKLM:"\SYSTEM\CurrentControlSet\Services\$($_)" ` -name ImagePath ` -value “%systemroot%\system32\svchost.exe -k netsvc_$($_)” ` -force ` ; Set-ItemProperty ` -path HKLM:'\Software\Microsoft\Windows NT\CurrentVersion\Svchost' ` -name netsvcs ` -value ( ` (Get-ItemProperty ` -path HKLM:'\Software\Microsoft\Windows NT\CurrentVersion\Svchost' ` -name netsvcs ` ).netsvcs -notmatch $_ ` ) ` -force ` ; }; }; function Set-ServiceCommonProcess { <# .Synopsis Возвращаем сервис в "групповой" процесс svchost.exe (группа netsvc). .Description Возвращаем сервис в "групповой" процесс svchost.exe (группа netsvc). .Parameter service Идентификатор службы .Example Set-ServiceCommonProcess ` -service 'AppMgmt' #> [CmdletBinding( SupportsShouldProcess = $true, ConfirmImpact = 'Low' )] param ( [Parameter( Mandatory=$true, Position=0, ValueFromPipeline=$true, HelpMessage="Идентификатор службы." )] [string]$service ) $service ` | ? {Test-Path HKLM:"\SYSTEM\CurrentControlSet\Services\$($_)"} ` | ? { (Get-ItemProperty ` -path HKLM:'\Software\Microsoft\Windows NT\CurrentVersion\Svchost' ` -name netsvcs ` ).netsvcs -notcontains $_ ` } ` | % { Set-ItemProperty ` -path HKLM:'\Software\Microsoft\Windows NT\CurrentVersion\Svchost' ` -name netsvcs ` -value ( ` (Get-ItemProperty ` -path HKLM:'\Software\Microsoft\Windows NT\CurrentVersion\Svchost' ` -name netsvcs ` ).netsvcs + $_ ` | sort -unique ` ) ` -force ` ; Set-ItemProperty ` -path HKLM:"\SYSTEM\CurrentControlSet\Services\$($_)" ` -name ImagePath ` -value “%systemroot%\system32\svchost.exe -k netsvcs” ` -force ` ; Remove-ItemProperty ` -path HKLM:'\Software\Microsoft\Windows NT\CurrentVersion\Svchost' ` -name "netsvc_$($_)" ` ; }; };
Теперь имеем возможность выделить службе свой процесс буквально одной строкой, и вернуть её обратно – также одной строкой. Модуль назвал ITG.SvcHostManagement.psm1.
Отзывы » (1)
RSS комментарии
Обратная ссылка
С помощью этого трюка смог найти и локализовать «виновника» утечки дескрипторов — службу Application Management. Именно в этой службе при определённом стечении обстоятельств (вся и суть в том, что не всегда это происходит) возникают утечки дескрипторов и общее количество открытых дескрипторов доходит до 44000+. При этом отваливаются сетевые ресурсы, недоступен контроллер домена, DFS ресурсы и так далее. Теперь же достаточно убить процесс, хостящий службу Application Management, и запустить её заново (она сама поднимется при очередном применении политик) — и можно работать дальше.
Итого, рекомендую Вам указанным выше способом выдеить как минимум службу Application Management в отдельный процесс, и повесть в расписание периодический перезапуск данной службы хотя бы раз в сутки — и эту проблему таким образом мы обойдём.