SkyF
15-04-2006, 16:53
Q: Можно ли на терминальном сервере Windows Server 2003 ограничить одновременное количество запусков определённой программы терминальным пользователям?
Цель: Имея Z пользователей терминальных, и N лицензий на Office 2003, как на сервере ограничить количество загрузок приложений Office, не более N-ти одновременно?
Возможно ли это?
A: Стандартных способов ограничения по количеству копий процесса я не смог найти, однако в WMI командах есть возможность выполнять отображение количество запущенных процессов. Поэтому я обратился к Центру сценариев (http://www.microsoft.com/technet/scriptcenter/default.mspx) и составил небольшой сценарий, который, работая резидентно – отслеживает процессы загрузки приложения , например блокнота (notepad.exe) или калькулятора (calc.exe) - по счетчику отслеживает количество работающих приложений. При этом, он виден как процесс wscript.exe в диспетчере задач.
В целях понимания работы программы даны всплывающие окна, потом их можно убрать.
* Для добавления других приложений можно модифицировать данные файла конфигурации (например, вместо notepad.exe указать winword.exe, добавить WinRAR и т.д.)
** Сценарий, указанный тут, предназначем для запуска в приложении Cscript.exe. Поэтому если программой для запуска сценариев по умолчанию она не является на вашей системе - вам необходимо добавить перед сценарием имя программу "cscript", например, cscript watcher.vbs.
[hr]
Скрипт watcher.vbsSet Args = WScript.Arguments
' *******************************************
' Script, that allow to limit quantity of the
' started applications on a terminal server.
' The names of applications and the maximum
' quantity of simultaneously started spears
' are stored in config file.
'
' @authors: SkyF, hasherfrog
' @site: oszone.net
'
CONST FIELDS = 3
CONST PSNAME = 0
CONST PSNUMB = 1
CONST PSMAXN = 2
Dim thePsArray ( )
Dim nToWatch
nToWatch = 0
Function AddPsToWath( name, number )
ReDim Preserve thePsArray ( FIELDS, nToWatch )
thePsArray(PSNAME, nToWatch) = name
thePsArray(PSNUMB, nToWatch) = number
thePsArray(PSMAXN, nToWatch) = number
addPsToWatch = nToWatch
nToWatch = nToWatch + 1
End Function
' *******************************************
Sub ReadPsWatchFile(filename)
Dim fso, f
' On Error Resume Next
Set fso = CreateObject("Scripting.FileSystemObject")
Set f = fso.OpenTextFile(filename, 1, False)
if Err.Number<>0 then
call Error_(0)
else
while not f.atEndOfStream
s = f.ReadLine
ms = Split(s, " ", -1, vbBinaryComapre)
s1 = ms(0)
n2 = CInt(ms(1))
n = AddPsToWath(s1, n2)
Err.Clear
wend
f.Close
end if
End Sub
' *******************************************
Sub StartUpWatcher()
strComputer = "."
Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set colMonitoredEvents = objWMIService.ExecNotificationQuery _
("SELECT * FROM __InstanceOperationEvent WITHIN 1 WHERE " _
& "Targetinstance ISA 'Win32_Process'")
Do While 1
Set objLatestProcess = colMonitoredEvents.NextEvent
For psn=0 to nToWatch-1
If objLatestProcess.TargetInstance.Name = thePsArray(PSNAME, psn) Then
Select Case objLatestProcess.Path_.Class
Case "__InstanceCreationEvent"
thePsArray(PSNUMB, psn) = thePsArray(PSNUMB, psn) - 1
If thePsArray(PSNUMB, psn) < 0 then
objLatestProcess.TargetInstance.Terminate
Wscript.Echo "Вы запустили лишнюю копию программы "& objLatestProcess.TargetInstance.Name _
& " - разрешенный лимит только " & thePsArray(PSMAXN, psn)
End If
Case "__InstanceDeletionEvent"
thePsArray(PSNUMB, psn) = thePsArray(PSNUMB, psn) + 1
End Select
End If
Next
Loop
End Sub
' *******************************************
for i=0 to Args.count-1
If Args(i) = "-f" Then
iaFilename = Args(i+1)
End If
Next
If iaFilename<>"" Then
Set fso = CreateObject("Scripting.FileSystemObject")
If (fso.FileExists(iaFilename)) Then
Call ReadPsWatchFile(iaFilename)
If nToWatch=0 Then
Wscript.Echo "File is empty."
Else
Call StartUpWatcher()
End If
Else
Wscript.Echo "File exists not."
End If
Else
Wscript.Echo "watcher.vbs -f config.txt"
End If
Запускwatcher -f config.txt
Пример config.txtnotepad.exe 2
calc.exe 3
[hr]
После запуска сценария - он запускается резидентно и выполняет перехват событий запуска процесса, сравнивает название процесса с заранее заданными и в случае совпадения - передает управление счетчику. Если лимит будет исчерпан - для нового процесса будет вызван метод завершения.
Процесс может быть запущен из любой терминальной сессии, а сценарий должен запускаться от имени системы (те при запуске ОС)
Любые изменения приветствуются!
ЗЫ полезные ссылки:
http://www.microsoft.com/technet/scriptcenter/resources/scriptshop/shop0505.mspx
http://www.microsoft.com/technet/community/columns/scripts/sg0103.mspx
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wmisdk/wmi/wmi_tasks__processes.asp (тут иной вариант - через получение списка из процессов – можно тоже попробовать)
[hr]
Благодарим за доработку скрипта (http://forum.oszone.net/post-458996-11.html) hasherfrog (http://forum.oszone.net/member.php?userid=9311)
Цель: Имея Z пользователей терминальных, и N лицензий на Office 2003, как на сервере ограничить количество загрузок приложений Office, не более N-ти одновременно?
Возможно ли это?
A: Стандартных способов ограничения по количеству копий процесса я не смог найти, однако в WMI командах есть возможность выполнять отображение количество запущенных процессов. Поэтому я обратился к Центру сценариев (http://www.microsoft.com/technet/scriptcenter/default.mspx) и составил небольшой сценарий, который, работая резидентно – отслеживает процессы загрузки приложения , например блокнота (notepad.exe) или калькулятора (calc.exe) - по счетчику отслеживает количество работающих приложений. При этом, он виден как процесс wscript.exe в диспетчере задач.
В целях понимания работы программы даны всплывающие окна, потом их можно убрать.
* Для добавления других приложений можно модифицировать данные файла конфигурации (например, вместо notepad.exe указать winword.exe, добавить WinRAR и т.д.)
** Сценарий, указанный тут, предназначем для запуска в приложении Cscript.exe. Поэтому если программой для запуска сценариев по умолчанию она не является на вашей системе - вам необходимо добавить перед сценарием имя программу "cscript", например, cscript watcher.vbs.
[hr]
Скрипт watcher.vbsSet Args = WScript.Arguments
' *******************************************
' Script, that allow to limit quantity of the
' started applications on a terminal server.
' The names of applications and the maximum
' quantity of simultaneously started spears
' are stored in config file.
'
' @authors: SkyF, hasherfrog
' @site: oszone.net
'
CONST FIELDS = 3
CONST PSNAME = 0
CONST PSNUMB = 1
CONST PSMAXN = 2
Dim thePsArray ( )
Dim nToWatch
nToWatch = 0
Function AddPsToWath( name, number )
ReDim Preserve thePsArray ( FIELDS, nToWatch )
thePsArray(PSNAME, nToWatch) = name
thePsArray(PSNUMB, nToWatch) = number
thePsArray(PSMAXN, nToWatch) = number
addPsToWatch = nToWatch
nToWatch = nToWatch + 1
End Function
' *******************************************
Sub ReadPsWatchFile(filename)
Dim fso, f
' On Error Resume Next
Set fso = CreateObject("Scripting.FileSystemObject")
Set f = fso.OpenTextFile(filename, 1, False)
if Err.Number<>0 then
call Error_(0)
else
while not f.atEndOfStream
s = f.ReadLine
ms = Split(s, " ", -1, vbBinaryComapre)
s1 = ms(0)
n2 = CInt(ms(1))
n = AddPsToWath(s1, n2)
Err.Clear
wend
f.Close
end if
End Sub
' *******************************************
Sub StartUpWatcher()
strComputer = "."
Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set colMonitoredEvents = objWMIService.ExecNotificationQuery _
("SELECT * FROM __InstanceOperationEvent WITHIN 1 WHERE " _
& "Targetinstance ISA 'Win32_Process'")
Do While 1
Set objLatestProcess = colMonitoredEvents.NextEvent
For psn=0 to nToWatch-1
If objLatestProcess.TargetInstance.Name = thePsArray(PSNAME, psn) Then
Select Case objLatestProcess.Path_.Class
Case "__InstanceCreationEvent"
thePsArray(PSNUMB, psn) = thePsArray(PSNUMB, psn) - 1
If thePsArray(PSNUMB, psn) < 0 then
objLatestProcess.TargetInstance.Terminate
Wscript.Echo "Вы запустили лишнюю копию программы "& objLatestProcess.TargetInstance.Name _
& " - разрешенный лимит только " & thePsArray(PSMAXN, psn)
End If
Case "__InstanceDeletionEvent"
thePsArray(PSNUMB, psn) = thePsArray(PSNUMB, psn) + 1
End Select
End If
Next
Loop
End Sub
' *******************************************
for i=0 to Args.count-1
If Args(i) = "-f" Then
iaFilename = Args(i+1)
End If
Next
If iaFilename<>"" Then
Set fso = CreateObject("Scripting.FileSystemObject")
If (fso.FileExists(iaFilename)) Then
Call ReadPsWatchFile(iaFilename)
If nToWatch=0 Then
Wscript.Echo "File is empty."
Else
Call StartUpWatcher()
End If
Else
Wscript.Echo "File exists not."
End If
Else
Wscript.Echo "watcher.vbs -f config.txt"
End If
Запускwatcher -f config.txt
Пример config.txtnotepad.exe 2
calc.exe 3
[hr]
После запуска сценария - он запускается резидентно и выполняет перехват событий запуска процесса, сравнивает название процесса с заранее заданными и в случае совпадения - передает управление счетчику. Если лимит будет исчерпан - для нового процесса будет вызван метод завершения.
Процесс может быть запущен из любой терминальной сессии, а сценарий должен запускаться от имени системы (те при запуске ОС)
Любые изменения приветствуются!
ЗЫ полезные ссылки:
http://www.microsoft.com/technet/scriptcenter/resources/scriptshop/shop0505.mspx
http://www.microsoft.com/technet/community/columns/scripts/sg0103.mspx
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wmisdk/wmi/wmi_tasks__processes.asp (тут иной вариант - через получение списка из процессов – можно тоже попробовать)
[hr]
Благодарим за доработку скрипта (http://forum.oszone.net/post-458996-11.html) hasherfrog (http://forum.oszone.net/member.php?userid=9311)