пятница, 13 июня 2008 г.

Как очистить профиль пользователя от мусора?

В нашей компании используется контроллер домена под Linux Mandriva. Работает SAMBA. Рабочие станции работают на Windows XP и Windows 2000 Professional. Все пользователи сохраняют свои профили автоматически при перезагрузке или logoff/logon на файловом сервере.

Это очень удобно, так как позволяет пользователям "мигрировать" по сети. Также очень здорово, что все документы хранятся не только на локальных компьютерах, но и на файловом сервере. Там они автоматически бекапятся, что нивелирует риск потери важных данных людей в случает поломки, скажем жёсткого диска клиентского компьютера.

Но тут есть один неприятный момент. Люди часто используют свой профиль для того, чтобы записать туда какую-нибудь муть. Типа пачки mp3 файлов или пары фильмов по полтора гигабайта. И выложить это добро на "Рабочий стол". Профиль стремительно пухнет и гигабайты свободного места на файловом сервере начинают быстро уменьшаться.

Периодически начинаются чистки, но это происходит время от времени. Когда ситуация со свободным местом на сервере становится угрожающей.

Проблему решили просто. Написали скрипт, который запускается при старте клиентской операционной системы в logon скрипте. Схема работы его очень проста: сканируем локальный профиль, и если находим "крамольные" файлы - автоматически переносим их в корень диска, где находится профиль пользователя, с указанием полного пути к файлу. Ну и, понятное дело, параллельно чистим профиль на файловом сервере, удаляя найденные "неугодные" файлы.

А после того, как закончили работу - выдаём гневное сообщение, типа "Ай-яй-яй, нехорошо!".

Вот собственно и сам скрипт:

{===========================================
Скрипт переносит из пользовательского профиля
все медиа файлы в локальную папку с названием,
равном имени пользователя, под которым тот
залогинился в системе

24.06.2008
Gifer
============================================}
var
trashlog,home,prhome,profile,trash,user,s,st,newdir:string;
i,j:integer;

//Функция удаления имени файла из строкиfunction
function DeleteFileName(s:string):string;
var
st:string;
begin
st:=s;
while st[length(st)]<>'\' do
if st[length(st)]<>'\' then delete(st,length(st),1);
result:=st;
end;

begin
//Диск на котором расположен профиль
prhome:= GetEnvValue('HOMEDRIVE')+'\';

//Папка профиля на сервере
home:= prhome+'profile';

//Папка профиля на локальной машине пользователя
profile:= GetEnvValue('USERPROFILE')+'\';

//Имя текущего пользователя
user:= GetEnvValue('USERNAME');

//Расположение перенесенных файлов из профиля
trash:=profile[1]+':\'+user;

Deletefile(profile[1]+':\Profile_cleaner.txt');

Protocol('Пользователь '+user+' начал работу....','T:\winscript.logs\users.log',true);

//Сканирование локальной папки профиля на наличие "лишних" файлов
ExecuteEX('cmd.exe',' /c dir "'+profile+'*.avi" /s /b /c /a>trash.log', prhome,1);
ExecuteEX('cmd.exe',' /c dir "'+profile+'*.mp3" /s /b /c /a>>trash.log',prhome,1);
ExecuteEX('cmd.exe',' /c dir "'+profile+'*.mp4" /s /b /c /a>>trash.log',prhome,1);
ExecuteEX('cmd.exe',' /c dir "'+profile+'*.wmv" /s /b /c /a>>trash.log',prhome,1);
ExecuteEX('cmd.exe',' /c dir "'+profile+'*.mkv" /s /b /c /a>>trash.log',prhome,1);
ExecuteEX('cmd.exe',' /c dir "'+profile+'*.3gp" /s /b /c /a>>trash.log',prhome,1);
ExecuteEX('cmd.exe',' /c dir "'+profile+'*.wav" /s /b /c /a>>trash.log',prhome,1);
ExecuteEX('cmd.exe',' /c dir "'+profile+'*.wma" /s /b /c /a>>trash.log',prhome,1);

j:=GetTextFileLinesCount(prhome+'trash.log');

if j>0 then begin
Protocol('Пользователь '+user+' собрал мусор','T:\winscript.logs\users.log',true);
createfolder(trash);
AddLineToFile(trash+'\Profile_cleaner.txt','Ниже перечислены медиа файлы,');
AddLineToFile(trash+'\Profile_cleaner.txt','которые были перенесены из Вашего профиля в: '+trash);
AddLineToFile(trash+'\Profile_cleaner.txt','========================================================================');
for i:=1 to j do begin
LoadLineFromFile(prhome+'trash.log',i,s);

//в это условие подставляем название тех папок, которые не нужно просматривать
if (pos(profile+'Local Settings',s)=0) or (pos(profile+'Application Data',s)=0) then begin
s:=strconvert(s,4);
AddLineToFile(trash+'\Profile_cleaner.txt',s);
st:=s;
delete(s,1,length(profile)-1);
newdir:=trash+DeleteFileName(s);
//Удаление файлов с сервера
if FileExists(home+s) then DeleteFile(home+s);
//Перенос на локальный диск "лишних" файлов
ForceFolders(newdir);
MoveFile(st,trash+s,true);
end;
end;
Protocol('Пользователь '+user+' выбросил мусор.','T:\winscript.logs\users.log',true);
MsgBox('Внимание!!!','Ваш профиль был очищен от медиа файлов. Все вопросы к Яндексу :)',1);
Execute(trash+'\Profile_cleaner.txt','','');
end else Protocol('Пользователь '+user+' ничего не нашeл.','T:\winscript.logs\users.log',true);

deletefile(prhome+'trash.log');
end.

Авторство - Andrey Rakov aka Gifer (gifer17@gmail.com)

После небольшой адаптации (в скрипте все логи пишутся на диск T:\winscript.logs\users.log) можно использовать где угодно. Скрипт проверен и работает надёжно. Запускаем скрипт машину с файлового сервера, с примапленного диска - чтобы избежать неоднозначности версий.

Будут вопросы - пишите на support@nsoft-s.com, постараемся помочь. В теме укажите "WinScript".

7 комментариев:

Xternalx комментирует...

а почему нет встроенных функций для поиска файлов?
это гораздо быстрее будет работать.

Кроме того, введи определенные константы. Например, как в InnoSetup сделано, {app} - директория, в которую установлено приложение, у тебя пусть оно возвращает директорию, в которой ws.exe лежит, ну и так далее. А то без этих возможностей твой винскрипт нафик никому не нужен. Скрипты должно быть удобно писать, тому же админу не интересно будет писать процедуру для рекурсивного поиска файлов к примеру, он лучше воспользуется другим продуктом, или реализует в батнике.

А задумка неплохая у тебя

Hobit комментирует...

Окей, сделаем. Продукт для себя изначально делался - а сейчас потихоньку обрастает новыми фишками.

Предопределённые константы сделаю уже в следующей версии, поиск по маске тоже - но чуть позже.

Hobit комментирует...

P.S. Сорри за поздний ответ - не было настроено дублирование комментсов на мыло.

Xternalx комментирует...

крруто! подождем :D

а по поводу позднего ответа - ничего страшного... %).

ps:// глупый вопрос. А почему в качестве синтаксиса ты выбрал паскаль скрипт? чем тот же самый луа тебя не устраивает? :)

Hobit комментирует...

О lua ничего не знаю, а паскаль - это был первый мой язык программирования. Да и сейчас в основном пишу на Delphi. Соответственно и выбрал Pascal.

Xternalx комментирует...

дело в том, что в паскале слишком много телодвижений лишних делать нужно чтобы выполнить какие то действия. Сам с паскаля начинал, но постепенно пересел на C#. сейчас в основном кодю на C#, php, javascript, lua. Так вот, для той аудитории, на которую ты ориентируешься лучше использовать языки без строгой типизации данных, или хотя бы без гемора с объявлением каждой новой переменной в секции var;

кстати, есть идея, можно сделать так, чтобы пользователь писал скрипт в стиле C с небольшими нестандартными решениями, а твой скриптовый двигатель эти нестандартности автоматически сам приводил к стандартному виду.

например, пишу я какую то мегацункцию, и мне понадобилась еще одна переменная, но ведь так неудобно лезть в самый верх, искать секцию var, и объявлять в ней это дело. Можно сделать так, что то место, где мне потребовалась новая переменная, я бы написал что то вроде:

var newVar: string;

а препроцессор твоего скриптового двигателя перед выполнением этого кода эту строчку сам загнал бы эту строчку в секуию var. :)

Это только одна из идей :)

Hobit комментирует...

Синтаксис Pascal-я был выбран сознательно.

Дело в том, что объявление переменных в тексте или вообще переменные без типизации, а ля Variant - это источник ошибок. Кому-то, это может и мешает, но опыт показывает, что жёсткая типизация - это хорошо.

Ну а то, что нужно писать список переменных в var - дело привычки, не более.