Войти

Показать полную графическую версию : [решено] Как ограничить количество запущенных копий приложения на терминальном сервере?


Страниц : [1] 2

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)

qpa3ep
05-06-2006, 13:31
Нужно ограничить количество одновременно запускаемых программ для пользователей терминального доступа на w2k3.
Подскажите как это можно сделать?

foss
05-06-2006, 17:46
В групповых политиках:
User Configuration\Administrative Templates\Windows Components\Windows Explorer---> Maximum number of recent documents

Maximum number of recent documents Enabled
Maximum number of recent documents 15
(15 -кол-во приложений)

Blast
06-06-2006, 16:50
http://www.oszone.net/3644/#18

ShaddyR
06-07-2006, 13:36
проверил я предложенные варианты... вопрос не решен. Озвучу промежуточные результаты:
1) указанное (http://forum.oszone.net/post-446921-3.html) foss: не то. Кто дружит с английским, поймет описание предложенного параметра:
Determines how many shortcuts the system can display in the Documents menu on the Start menu.

The Documents menu contains shortcuts to the nonprogram files the user has most recently opened. By default, the system displays shortcuts to the 10 most recently opened documents.
2) вариант скрипта vbs: более реально, но
2.1) Прежде всего, суммируются все инстанции названных процессов. То есть, если я запущу два калькулятора, то два нотепада я запустить уже не смогу
2.2) Нет возврата счетчика в обратное состояние, если одна из копий закрывается.

Ессно, я понимаю, что скрипт набросан на скорую руку. В содержимом разобрался, но с визуал бейсиком не дружен, посему:
1) можно ли создать массив из связок имя_процесса-кол-во_копий
2) можно ли добавлять в этот массив компоненты динамически, а не прописывать в скрипте
3) можно ли отслеживать завершение работы копии и делать соответствующие изменения в счетчике (с удалением единицы массива при закрытии последней из копий данного процесса)

hasherfrog
06-07-2006, 18:37
ShaddyR, я очень скоренько наборосал...
Не все проблемы решены.

Set Args = WScript.Arguments

' *******************************************

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 colMonitoredProcesses = objWMIService. _
ExecNotificationQuery("select * from __InstanceCreationEvent" _
& " within 1 where TargetInstance isa 'Win32_Process'")

Set colMonitorProcessesd = objWMIService.ExecNotificationQuery _
("SELECT * FROM __InstanceDeletionEvent " & _
"WITHIN 1 WHERE TargetInstance ISA 'Win32_Process' ")


Do While 1
Set objLatestProcess = colMonitoredProcesses.NextEvent

For psn=0 to nToWatch-1
If objLatestProcess.TargetInstance.Name = thePsArray(PSNAME, psn) Then
thePsArray(PSNUMB, psn) = thePsArray(PSNUMB, psn) - 1
' Wscript.Echo "Num: "& thePsArray(PSNUMB, psn)
If thePsArray(PSNUMB, psn) < 0 then
Wscript.Echo "Вы запустили лишнюю копию программы "& objLatestProcess.TargetInstance.Name _
& " - разрешенный лимит только " & thePsArray(PSMAXN, psn)
objLatestProcess.TargetInstance.Terminate
thePsArray(PSNUMB, psn) = thePsArray(PSNUMB, psn) + 1
End If
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 filename"
End If


Формат файла такой
имяпрограммы1.exe n1
имяпрограммы2.exe n2
имяпрограммы3.exe n3
Запускается скрипт watcher.vbs -f filename

но вот по поводу 2.2) Нет возврата счетчика в обратное состояние, если одна из копий закрывается. - это я не могу сейчас сообразить. как сделать


И вообще не уверен, что это возможно :-|

hasherfrog
06-07-2006, 19:06
А вообще нет, чего я... Можно просто пересчитывать количества процессов перед каждый новым запуском... Так, наверное.
Прошу прощения, если критично кому, но я завтра только смогу поковыряться...

Плюс второй вариант - http://www.microsoft.com/technet/scriptcenter/guide/sas_prc_evdv.mspx?mfr=true

ShaddyR
06-07-2006, 19:57
hasherfrog: я понял)
Резалты теста (назвал скрипт Processrestrict.vbs):
1) Processrestrict.vbs -f calc.exe
возвращает "File exists not."
2) Processrestrict.vbs -f "C:\WINDOWS\system32\calc.exe"
возвращает ошибку в аттаче)

hasherfrog
06-07-2006, 22:43
НЕЕЕЕЕ... Вы чего?
filename - это текстовый файл, в котором перечислены файлы, подлежащих "рестриктированию".
Там написано за кем следить - и сколько раз можно запускать.

Кстати, Вы бежите впереди паровоза :] Я как завтра хотел написать вторым вариантом решение таким образом, каким Вы сейчас предлагаете, когда на каждый файл рестрикта будет свой собственный "наблюдатель". А первым вариантом - доработать "комплексный" обработчик-рестриктизатор.

dosim
07-07-2006, 17:20
2.2) Нет возврата счетчика в обратное состояние, если одна из копий закрывается
hasherfrog

а когда сооборазите насчет возврата счетчика?? как раз то, что мне нужно.

hasherfrog
07-07-2006, 22:27
Скрипт watcher.vbs
ShaddyR> см. в прикрепленном сообщение.

ShaddyR
08-07-2006, 12:59
Спасибо, у тебя получилось!!
Единственный нюанс - терминальная система, для которой все пишется. Ибо в текущем варианте все работает на однопользовательской, а проверка в терминальной среде показала следующий глюк: запуск приложений контролируется, но
1) сообщение о лимите выводится в сеанс, в котором запущен скрипт.
2) ессно, закрытие копии в сеансе другого пользователя также не производится, вне зависимости от прав юзера, под которым скрипт запущен.

Если будет время, косметика:
1) переименуй конф-файл в .ini (с именем скрипта, но поиском и его поиском по умолчанию, если не задана командная строка)
2) добавь опцию командной строки для добавления файла и кол-ва запусков в указанный конф. файл (либо в к.ф. по-умолчанию, если ничего не указано). С удалением справятся вручную
ничего личного, все от имени и во благо юзеров ;)
А вообще - спасибо.. визуальный Барсик - сильная весчь)
dosim: есть еще пожелания к создателю скрипта?

hasherfrog
08-07-2006, 21:53
ShaddyR
Я боюсь, что Вы не совсем поняли, как это работает (или я сам не совсем понял).

1) сообщение о лимите выводится в сеанс, в котором запущен скрипт.
Конечно. Естественно. И я не знаю, а как же иначе-то?

Как я понял: Этот скрипт запускается при входе на сервер для каждого пользователя. Т.е. кто-то входит - у него запускается логон-скрипты, в том числе и этот. И для каждого, кто зашёл, действует _персональный_ лимит на количество блокнотов-калькуляторов. Не один на всех этот скрипт, а каждому - свой. Возможно, я не совсем вкурил механизм действия скрипта, но у меня нет терминал-севрера, к сожалению :-\

2) ессно, закрытие копии в сеансе другого пользователя также не производится, вне зависимости от прав юзера, под которым скрипт запущен.

И не должно, так как по замыслу (см. выше) скрипт не контролирует других пользователей, а лишь данного конкретного.

И кстати, вот какой момент. Закрытие сейчас производится _до_вывода_ сообщения "Вы превысили лимит". Т.е. пользователь запустил блокнот - скрип 1) проверил лимит, 2) _закрыл_блокнот, 3) сообщил о превышении лимита. Если поменять местами 2 и 3, пользователь может устроить затык скрипту (вообще-то, он и сейчас, наверное, сможет, при должном усердии).

---

По косметике:

1) переименуй конф-файл в .ini (с именем скрипта, но поиском и его поиском по умолчанию, если не задана командная строка)

Вроде не сложно, только несколько неоднозначностей. Где что лежит? Где (в какой папке) нужно искать конфиг?

2) добавь опцию командной строки для добавления файла и кол-ва запусков в указанный конф. файл (либо в к.ф. по-умолчанию, если ничего не указано). С удалением справятся вручную

Вот это - вообще нельзя, насколько я соображаю. Скрипт действует в своём "коконе". Чтобы кто-то смог сообщить ему об изменении политики партии ("следи, мол, ещё и за этим вот файлом"), этот кто-то должен... в общем, речь идёт о inter-process communications. (см тут (http://en.wikipedia.org/wiki/Inter-process_communication), я слишком косноязык). А вот умеет ли wscript.exe делать такие штучки - я сомневаюсь.

dosim
10-07-2006, 08:48
:o

hasherfrog я запустил этот скрипт, всё работает т.е. процесс считывает, при запуске выше лимта выходит сообщение "Вы запустили лишную копию программы " ок нажимаешь програмка закрывается, но пока ты ок не нажмёшь програмка работает. Посмотрите в чем проблема? Сделайте чтобы, сообщение выходил и процесс сразу убивал, т.е до нажатие ОК.

hasherfrog
10-07-2006, 10:18
dosim
Как но пока ты ок не нажмёшь програмка работает
соотносится с Закрытие сейчас производится _до_вывода_ сообщения "Вы превысили лимит".
?

dosim
10-07-2006, 12:30
hasherfrog Нет, пока ОК не нажмешь программа не закрывается.

ShaddyR
10-07-2006, 13:27
dosim: ты не прав. Нелимитная копия закрывается прежде сообщения, проверено на калькуляторах.
>
переименуй конф-файл в .ini (с именем скрипта, но поиском и его поиском по умолчанию, если не задана командная строка)
Вроде не сложно, только несколько неоднозначностей. Где что лежит? Где (в какой папке) нужно искать конфиг?
в папке запуска скрипта, конечно. Если не указан другой путь\имя файла конфигурации.
>
насчет терминала... мож, я переборщил, это действительно не нужно. Просто основная идея озвучена в первом сообщении, примерно таким образом:
Цель: Имея Z пользователей терминальных, и N лицензий на Office 2003, как на сервере ограничить количество загрузок приложений Office, не более N-ти одновременно?
Но, думаю, достаточно предложенного тобой скрипта.

Еще раз спасибо.

dosim
10-07-2006, 13:57
всё работает

hasherfrog
10-07-2006, 14:06
ShaddyR
Давайте по мелочам доразберёмся. У меня нет терминального сервера, поэтому придётся спрашивать у Вас.

Если данный скрипт запустит администратор, пользователи, превысившие лимит, могут открыть блокноты-калькуляторы? Дело в том, что я (кажется) придумал, как сообщать именно контретному пользователю о том, что именно он превысил лимит. Причём "ступора" не будет (а сейчас он есть, возможен).
Уберите строку Wscript.Echo "Вы запустили лишнюю копию программы "& objLatestProcess.TargetInstance.Name _
& " - разрешенный лимит только " & thePsArray(PSMAXN, psn)
и проверьте, пожалуйста.

А там, может и до IPC дойдём (есть идея).

ShaddyR
11-07-2006, 15:20
hasherfrog: честно - не понял идеи. Сделал: ничего не выводит, молча убивает в сеансе, где запущен.




© OSzone.net 2001-2012