PDA

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


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

hasherfrog
11-07-2006, 15:25
Гррр. Да я ж не скрипт новый написал :-) Я по старому хотел спросить: _уточнить_ его работу. Как он там вообще работает в полевых условиях, я ж не вижу :]

Ещё раз. У Вас скрипт запускает администратор? Один раз? Правильно? А потом скрипт умудряется контролировать всех остальных пользователей, так?

ShaddyR
11-07-2006, 15:34
hasherfrogДа я ж не скрипт новый написал :-) Я по старому хотел спросить: _уточнить_ его работу. Как он там вообще работает в полевых условиях, я ж не вижу :]
по данным бетатестеров - намана). Просто ты говорил об терминале, затем просьба удалить строки.. звиняй, попутал с контекстом.
>
У Вас скрипт запускает администратор? Один раз? Правильно? А потом скрипт умудряется контролировать всех остальных пользователей, так?
угум-с. То бишь, скрипт сечет, что процессы в терминале запущены. Но команду тушить лишний отправляет не тому юзеру либо пытается в текущем юзере тушить копию с дескриптором запущенной где-то копии. Посему у него кроме мониторинга ничего не получается.

hasherfrog
11-07-2006, 15:39
ShaddyR
Так. Теперь такой момент (я сам не могу проверить). Что если на терминал-сервере сказать "net send имяпользователя 123123123", где имяпользователя - имя какого-нибудь пользователя, подключённого в настоящий момент. Только он увидит сообщение 123123123 (и увидит ли, кстати, вообще)?

hasherfrog
11-07-2006, 16:44
Молчание...
Ok, вот новая версия, отсылающая сообщение пользователю, превысившему лимит:
Set Args = WScript.Arguments
iaFilename = "watcher.cfg"

' *******************************************
' 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
colProperties = objLatestProcess.TargetInstance.GetOwner(strNameOfUser, strUserDomain)
objLatestProcess.TargetInstance.Terminate
msg = "Вы запустили лишнюю копию программы "& objLatestProcess.TargetInstance.Name _
& " - разрешенный лимит только " & thePsArray(PSMAXN, psn)
Set objShell = CreateObject("WScript.Shell")
objShell.Exec("%COMSPEC% /k net send " & strNameOfUser & " " & msg)
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") AND (i+1 < Args.count) Then
iaFilename = Args(i+1)
End If
Next

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 "Config file is not found."
End If


Требования: У пользователя на машине должна работать "Служба сообщений".
Фичи: поддерживается дефолтный конфиг-файл watcher.cfg

hasherfrog
12-07-2006, 10:40
Я вчера писал-писал новую версию скрипта (фичи перечислю ниже) и у меня вышла кошмарная вещь. Переименовывал файл конфига, перезатёр скрипт этим конфигом. Вырвав себе полголовы волос, лёг спать :-)

Уважаемые заказчики :-) :-) :-)
Хотелось бы узнать несколько вещей.

1. В последней версии есть требование, У пользователя на машине должна работать "Служба сообщений". Это вообще нормально? приемлимо? Стоит ли мне развивать скрипт дальше, основываясь на том положении, что у пользователя на машине БУДЕТ работать "Служба сообщений"?
2. Вопрос косвенно включает в себя (и вытекает из) 1 пункт. Стоит ли разрабатывать дальше, увешивая простенький скрипт (в том виде, что сейчас) новыми штучками-дрючками, которые повлекут за собой новые требования. У кого-то сложится мнение о наигранности этого вопроса; но я серьёзно. Я вот лично не люблю программ-утилит, в которых 90% фич не использую - и на фига они?

А фичи будут такие (если надо? надо ли? я чего-то засомневался)
1. Поиск себя в памяти (работающих процессах), это не позволит запускать скрипт дважды. Но есть натяжечка - поиск идёт по имени скрипта, соответственно, возникает требование на его имя, а следом тут же возникают несколько вопросов, которые и вовсе не хотелось бы решать - например, написание подробнейшей документации на все случаи жизни.
2. Выгрузка себя из памяти. Сейчас это можно только по ошибке и/или из "Диспетчера задач", мне надоело уже; плюс - не всегда ясно, какой именно процесс выгружать. Требования те же - ограничение на имя скрипта. Захотите благозвучно переименовать скрипт, придётся лезть и в его код.
3. Поддержка добавления программ для отслеживание "на лету". Кроме уже дважды упомянутого требования на имя, возникает требование на корректность командной строки. Мне откровенно не хочется писать полномасштбную защиту от дурака, а как следствие, получится скрипт, который работает только в умелых руках. Плюс, Возникнет неоднозначность в изменении параметров уже отслеживаемых задач (пример: в конфиге ноутпад можно запускать 3 раза, пользователь запустил 2, и тут админ вносит вручную директиву использовать только 1)
4. Вывод статуса. Фича полезная (сколько загружено, какие текущие установки), но вызывает ещё более стрёмные следствия. Куда и как выводить? Если в Echo, то скрипт "встанет", и в это время пользователь может начудить. Если в блонкот - а не мы ли отслеживаем блокноты? а если лимит кончился? :] В файл? А какой?
5. Считывание и проверка при старте скрипта исполняемых процессов. Уже запущенные процессы будут "посчитаны", из этого состояния и будут дальше вестись наблюдения. Но следствие такое: а что, если админ _специально_ хотел запустить себе лишний блокнот?

Я понимаю, что многие "но" выглядят надуманными. Просто для меня это принципиально - делать функционально, но не перегруженно. Всё дело в том, чтобы не превратить удобства в неудобства. Сейчас, например, админ сам контролирует всё. А при повышении "умности" скрипта это станет невозможным.
Жду ответов...

hasherfrog
12-07-2006, 18:24
Up. Вопросы всё ещё в силе...

ShaddyR
12-07-2006, 20:00
По новой версии (http://forum.oszone.net/post-460295-24.html):
Работает, отсылает верно. Но лишнюю копию в чужом сеансе все еще не умеет закрывать.
>
Выгрузка себя из памяти.
добавь соответствующий ключ, как в свое время делали ДОСовские резиденты. Другими словами, watcher.vbs -d убивает первый встреченный процесс wscript.exe, а, скажем, watcher.vbs -x убивает ВСЕ процессы с данным именем (последнее можно использовать, если скрипт запускается для каждого пользователя терминала в отдельности).
>
Вывод статуса.
добавь, скажем, параметр -l, пусть выводит в указанный текстовый файл либо в файл с именем скрипта и расширением .log в текущей директории
>
Считывание и проверка при старте скрипта исполняемых процессов. Уже запущенные процессы будут "посчитаны", из этого состояния и будут дальше вестись наблюдения.
полезно, уже сталкивался при тестах.
В последней версии есть требование, У пользователя на машине должна работать "Служба сообщений".
если без этого не обойтись - записать как особенность работы скрипта. Мне интересно другое: даже при выключенной службе Messenger'a сообщения можно отсылать с использованием интерфейса Диспетчера Задач. Может, отсылку сообщений можно реализовать через этот механизм?
>
Минус в мелькании ДОС-окна в момент отправки сообщения пользователю. Можно прятать окно известной утилой либо реализовать другой механизм отсылки сообщений, чтобы не привязываться к статусу службы сообщений.

Итого:
1) нужна расширенная командная строка. Что-то типа
watcher.vbs
-f имя_конф_файла[.cfg]: загрузка параметров из файла конфигурации
-d : удаление первого встреченного процесса данного скрипта из памяти
-x : удаление всех найденных процессов данного скрипта из памяти
-l: имя_файла[.log]: вывод информации о текущих параметрах мониторинга процессов и значениях счетчиков
2) завершать неликвидную копию процесса в сеансе терминального клиента
3) скрывать окно сообщения net send\ попробовать другой механизм отправки сообщения

Что касается обработки ошибок - сделай минимум. Либо игнорировать их, либо, максимум - сливать их в текстовый файл, хоть и в папке temp. ИМХО скрипт не обещался быть рассчитаным на мальчиков-мажоров, а админ должен думать, что делает.

Можно еще добавить обработку режима работы, т. е. - один скрипт на всех либо по скрипту на каждого. Ессно, если разница в реализации версий не потребует полной переделки программы.

Butunin Klim
08-04-2009, 14:38
А как сделать что бы он не выдавал сообщение а переключался на прошлы процесс?
Тобишь при запуске 2 приложения он бы переключался на 1. Это удобнее нежели выдавать сообщение

slava_89
17-08-2011, 02:40
Здравствуйте! Я прочитал тему созданную и не понял немного. Как создать этот скрипт для 64 разрядную ОС, где его сохранять и как запуск проводить?

ShaddyR
17-08-2011, 11:23
Как создать этот скрипт для 64 разрядную ОС »
этому скрипту фиолетова битность ОС
>
где его сохранять »
на жестком диске? :dirol:
>
как запуск проводить »
добавить в список автозапускаемых программ строку
cscript "<путь к файлу>watcher.vbs" »

S_M
28-08-2011, 20:01
добавить в список автозапускаемых программ строку

Прошу прощения, а где это надо добавлять? Сервер 2008 SP2, пользователь Администратор логинится автоматически. Думал, в свойствах пользователя прописать файл, который запускался бы при запуске - бесполезно (выдает ошибку при логине и сеанс завершается). Добавил в папку "Автозагрузка" - не работает! Через планировщик пытался (запускаю от имени SYSTEM) - задание просто висит в статусе "Это задание выполняется в настоящий момент", в процессах он есть, но ничего не происходит :( Плюнул на все, зашел терминально под Администратором, запустил, всё работает! Только если другие пользователи запускают лишние копии, то ругань идет в сеанс Администратору. Убрал из скрипта строки:
Wscript.Echo "Вы запустили лишнюю копию программы "& objLatestProcess.TargetInstance.Name _
& " - разрешенный лимит только " & thePsArray(PSMAXN, psn)
Сообщения валить перестали, но только отключаешься от сеанса администратора (не завершаешь сеанс, а делаешь отключение) - скрипт перестает работать :(
В общем, помогите правильно прописать этот скрипт в автозагрузке (если можно в подробностях - как для дебилов).
Спасибо!

ShaddyR
28-08-2011, 21:10
в свойствах пользователя прописать файл »
не пойдет - ты его пытаешься установить как среду для запуска, это неверно.
Поставь его запуск в соотв. раздел реестра, подраздел RUN, пусть стартует под консольной учеткой, если таковая предусмотрена.

S_M
31-08-2011, 21:54
Поставь его запуск в соотв. раздел реестра, подраздел RUN

Поставил, перегрузил сервер - ничего не поменялось. В процессах программы нет, ограничения не работают.
Блин. Есть у кого-нибудь готовый кусок реестра с прописанной программулиной? Ну, капец просто. Элементарщина вроде, а не получается. Кошмар. :(

пусть стартует под консольной учеткой

Это как?

ShaddyR
31-08-2011, 22:13
Это как? »
консольная - та, под которой сервер загружается там, где стоит, не терминальная. Есть таковая?

zavulon66
17-05-2016, 06:00
Запускается на хосте один раз резидентно. Всё оттестировано и работает.

Set 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

'Протоколирование в одноимённый log файл
Sub AppLog( aMessage )
Dim fso, f, flnm, renflnm, dtmstr
flnm = Replace(Wscript.ScriptFullName,".vbs",".log")
Set fso = CreateObject("Scripting.FileSystemObject")
If (fso.FileExists(flnm)) Then
Set f = fso.GetFile(flnm)
If f.Size > 100000 then
dtmstr = Replace(Replace(Replace(FormatDateTime(Now),"/","-"),":",".")," ","-")
renflnm = Replace(flnm,".log","-" & dtmstr & ".log")
f.Move renflnm
End If
Set f = Nothing
End If
Set f = fso.OpenTextFile(flnm, 8, True)
f.WriteLine FormatDateTime(Now) & " - " & aMessage
f.Close
End Sub

'********************************************
Function CountUserProcess( ProcessName, ProcessId )
Dim strNameOfUser,strOwnerProcess,strDomain
CountUserProcess = 0
Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
Set colProcessList = objWMIService.ExecQuery("Select * from Win32_Process Where ProcessId=" & CStr(ProcessId) )
For Each objProcess in colProcessList
colProps = objProcess.GetOwner(strOwnerProcess, strDomain)
Next
AppLog "-- ProcessName-" & ProcessName & ", ProcessId-" & CStr(ProcessId) & ", strOwnerProcess-" & strOwnerProcess & ", strDomain-" & strDomain
Set colProcessList = Nothing
Set colProcessList = objWMIService.ExecQuery("Select * from Win32_Process Where Name='" & ProcessName & "'")
For Each objProcess in colProcessList
colProps = objProcess.GetOwner(strNameOfUser, strDomain)
AppLog "strNameOfUser-" & strNameOfUser
if strNameOfUser = strOwnerProcess then
CountUserProcess = CountUserProcess + 1
end if
Next
End Function

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

Sub StartUpWatcher()
Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\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
If objLatestProcess.Path_.Class = "__InstanceCreationEvent" Then
psCount = CountUserProcess(objLatestProcess.TargetInstance.Name, objLatestProcess.TargetInstance.ProcessId)
'Wscript.Echo thePsArray(PSNAME, psn), psCount
iF psCount > thePsArray(PSNUMB, psn) Then
Applog "Count of process " & objLatestProcess.TargetInstance.Name & " is " & Cstr(psCount) & "... Terminate last process."
objLatestProcess.TargetInstance.Terminate
End If
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 config.txt"
End If

Baldman73
27-09-2017, 17:15
Спасибо огромное!
Я понимаю, что тема давно забыта, но есть ситуации, когда некоторым пользователям того-же терминального сервера нельзя ограничивать ресурсы. Генеральному не объяснишь, что "нехорошо так делать"! :))
Я выкрутился добавив строки
if strNameOfUser = "Director" then
CountUserProcess = 1
end if
после подсчета процессов у пользователя.
Было бы неплохо вынести это в конфигурационный файл...




© OSzone.net 2001-2012