Как выполнить действия с файлом при его изменении

Все об администрировании рабочих станций Windows 95/98/NT/2000/XP/7/8. То, чего не найдешь в бескрайних просторах Интернета. Решения тех проблем, которые не решаются типовыми ответами, которые можно получить в техподдержке Майкрософта - а именно: переустановить продукт или купить какой-ть другой лицензионный диск.


Модератор: UncleFather

Аватара пользователя
UncleFather
Site Admin
Сообщения: 1503
Зарегистрирован: 17 авг 2004 16:20, Вт
Контактная информация:

Как выполнить действия с файлом при его изменении

Сообщение UncleFather »

Задача:

Имеется файл, изменения которого необходимо отслеживать. При его изменении/удалении/создании нужно выполнить какое-либо действие. Операционная система Windows 7 и выше.

Решение:

Для примера возьмем файл C:\Soft\Test\MyDoc.xls, и при изменении будем его копировать на рабочий стол компьютера в ЛВС. Например, путь куда будем копировать: \\Book01\c$\Documents and Settings\User\Рабочий стол\MyDoc.xls

  1. В Локальных политиках безопасности (secpol.msc) -> Параметры безопасности -> Локальные политики -> Политика аудита -> включаем политику Аудит доступа к объектам -> Успех:

    Включение аудита:
    01.jpg

    Примечание: Здесь лучше пользоваться «Расширенной политикой аудита», которая доступна в версиях Windows начиная с Vista и выше, поскольку включение всей политики «Аудит доступа к объектам» приведет к огромному количеству ненужных записей в журнале безопасности. А «Расширенная политика аудита» позволяет настраивать аудит для конкретных событий. В данном случае нам нужно включить параметр «Доступ к объектам» -> «Аудит файловой системы». Подробнее смотрим в статье «Расширенные политики аудита».

  2. В свойствах безопасности папки, в которой находится отслеживаемый файл

    Безопасность папки:
    02.jpg

    настраиваем политику аудита для группы ВСЕ:

    • Тип - Успех;

    • Применяется к: - Здесь указываем область, для которой нужно отслеживать доступ. Если это только один файл в папке, то нужно указать: «Только для файлов», если же требуется отслеживать все содержимое, в том числе и содержимое подпапок, то указываем: «Для этой папки, ее подпапок и файлов»;

    • Общие разрешения - Запись.

    Настраиваем аудит:
    03.jpg

    Можно так же добавить аудит событий удаления подпапок и файлов (это может понадобиться, например, если наблюдаемый файл будет синхронизироваться сторонним ПО типа Яндекс.Диск):

    Аудит с удалением:
    13.jpg

    и получаем настроенный аудит для папки:

    Настроенный аудит папки:
    04.jpg
  3. Создаем PowerShell скрипт и сохраняем его, например по пути C:\Soft\Bat\MyDoc.ps1:

    Код сценария PowerShell

    Код: Выделить всё

    $login = "UserName" #Имя пользователя для подключения сетевого диска
    $pass = ConvertTo-SecureString "MyPassword" -AsPlainText -Force #Преобразуем пароль для подключения сетевого диска в защищенную строку
    $creds = New-Object System.Management.Automation.PSCredential ($login, $pass) #Преобразуем учетные данные к типу PSCredential
    New-PSDrive -Name MyDrv -PSProvider FileSystem -Root "\\Book01\c$\Documents and Settings\User" -Credential $creds #Подключаем сетевой ресурс \\Book01\c$\Documents and Settings\User как диск с именем MyDrv, используя полученные ранее учетные данные
    
    Start-Sleep -s 10 #Даем спокойно закрыться файлу и записать все события в журнал
    $SourceFile="C:\Soft\Test\MyDoc.xls" #Источник - файл, за которым следим
    $DestFile="\\Book01\c$\Documents and Settings\User\Рабочий стол\MyDoc.xls" #Файл, в который будем копировать (здесь можно использовать синтаксис с использованием подключенного сетевого диска, тогда путь будет таким: "MyDrv:\Рабочий стол\MyDoc.xls")
    #Если за последние 30 секунд в журнале "Безопасность" возникло событие 4663, содержащее в описании имя исходного файла, то 
    if (Get-WinEvent -maxevents 1 -FilterHashtable @{LogName=”Security”;ID=4663;Data=$SourceFile;StartTime=(Get-Date).AddSeconds(-30)}) {
        copy-item -path $SourceFile -destination $DestFile -Force #Копируем отслеживаемый файл в новое место
    }

    Чуть дальше, при создании триггера будет понятно, что в скрипте можно было и не фильтровать события, поскольку сам триггер у нас будет настроен именно на событие записи именно отслеживаемого файла. В принципе, из всего скрипта можно оставить только подключение сетевого диска, задержку в 10 секунд и саму операцию копирования файла. То есть можно смело вместо PowerShell использовать обычный командный файл. Но мне как-то больше приглянулся PowerShell... :)

    А можно чуть изменить скрипт. Например, при изменении файла будем отправлять его на электронную почту:

    Измененный код PowerShell:

    Код: Выделить всё

    $ConstServer = "smtp.server.ru"                                 #SMTP сервер
    $ConstSMTPPort = "25"                                           #Порт SMTP сервера
    $ConstFrom = "sender@server.ru"                                 #Адрес отправителя
    $ConstTo = "recepient@server.ru"                             #Адрес получателя
    $ConstMessageTypeHTML = $false                                  #Формат сообщения HTML (true) или обычный текст (false)
    $ConstUserName = "sender@server.ru"                             #Имя пользователя (ящика) для авторизации на SMTP сервере
    $ConstUserPass = "MyPassword"                                 #Пароль для авторизации на SMTP сервере
    $ConstMessageSubject = "Изменен файл "                          #Тема сообщения
    $ConstMessageBody = " - изменен файл "                          #Тело сообщения
    
    $SourceFile="C:\Soft\Test\MyDoc.xls" #Файл, за которым следим
    
    Start-Sleep -s 10 #Даем спокойно закрыться файлу и записать все события в журнал
    #Если за последние 30 секунд в журнале "Безопасность" возникло событие 4663, содержащее в описании имя исходного файла, то 
    if (Get-WinEvent -maxevents 1 -FilterHashtable @{LogName=”Security”;ID=4663;Data=$SourceFile;StartTime=(Get-Date).AddSeconds(-30)}) {
        #Создаем необходимые объекты и задаем переменные, необходимые для отправки и формирования SMTP сообщения:
        $SmtpClient = New-Object System.Net.Mail.SmtpClient 
        $Message = New-Object System.Net.Mail.MailMessage 
        $SmtpClient.Host = $ConstServer
        $SmtpClient.Port = $ConstSMTPPort
        $Message.From = $ConstFrom
        $Message.To.Add($ConstTo)
        $Message.BodyEncoding = [System.Text.Encoding]::UTF8
        $Message.SubjectEncoding = [System.Text.Encoding]::UTF8
        $Message.IsBodyHtml = $ConstMessageTypeHTML
        $Message.Subject = $ConstMessageSubject + """" + $SourceFile + """"
        $SmtpClient.Credentials= New-Object System.Net.NetworkCredential($ConstUserName , $ConstUserPass)
        $Message.Attachments.Add($SourceFile)
        $Message.Body = (get-date).ToString() + $ConstMessageBody + """" + $SourceFile + """"
        $SmtpClient.Send($Message) #Отправляем SMTP сообщение
        $Message.Dispose() #Отправляем сообщение QUIT на SMTP-сервер (правильно завершаем TCP-подключение и освобождаем все ресурсы, используемые текущим экземпляром класса SmtpClient)
    }
  4. В планировщике заданий создаем новую задачу:

    1. На вкладке «Общие» настраиваем параметры: Скрытая задача, Для всех пользователей, Выполнять с наивысшими правами:

      Вкладка «Общие»:
      05.jpg
    2. На вкладке «Триггеры» создаем триггер для этой задачи. В свойствах нового триггера указываем: Начинать задачу «При событии», в параметрах выбираем «Настраиваемое» и нажимаем «Создать фильтр события»:

      Настройка триггера:
      08.jpg

      В свойствах фильтра события переходим на вкладку «XML», ставим галочку «изменить запрос вручную» и копируем содержимое запроса:

      Свойства фильтра события:
      09.jpg
      Код XML запроса:

      Код: Выделить всё

      <QueryList>
        <Query Id="0" Path="Security">
          <Select Path="Security">
      ((*[System[Provider[@Name='Microsoft-Windows-Security-Auditing'] and (Level=4 or Level=0) and Task = 12800 and (band(Keywords,9007199254740992)) and (EventID=4663)]]) and (*[EventData[Data[@Name="ObjectName"] and (Data='c:\soft\Test\MyDoc.xls')]]))
      </Select>
        </Query>
      </QueryList>

      Здесь c:\soft\Test\MyDoc.xls - полный путь до контролируемого файла.

      Этот триггер отбирает все события из журнала «Безопасность» с Уровнем - Сведения, Источником - Microsoft Windows Security Auditing, Кодом - 4663, Категорией - Файловая система, Ключевым словом - Аудит успеха, у которых в данных самого события есть запись с именем «ObjectName», значение которой равно нашему контролируемому файлу c:\soft\Test\MyDoc.xls.

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

      В итоге получаем триггер с пользовательским фильтром событий:

      Получившийся триггер
      06.jpg
    3. На вкладке «Действия» создаем новую задачу с параметрами: Действие - Запуск программы, Программа или сценарий - C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe, Добавить аргументы - -WindowStyle Hidden C:\Soft\Bat\MyDoc.ps1:

      Новая задача:
      10.jpg

      То есть мы запускаем оболочку PowerShell, с параметром -WindowStyle Hidden (что означает - в скрытом режиме) и выполняем написанный нами ранее PowerShell скрипт C:\Soft\Bat\MyDoc.ps1

    4. На вкладке «Условия» снимаем все галочки, поскольку задача должна запускаться вне зависимости от условий питания и простоя:

      Условия:
      11.jpg
    5. И последняя вкладка «Параметры». Ставим галочки: Выполнять задачу по требованию, Принудительная остановка задачи, если она не прекращается по запросу, параметр «Останавливать задачу, выполняемую дольше» настраиваем на минимальное время, а параметру «Если задача уже выполняется, то применять правило» назначаем значение «Не запускать новый экземпляр»:

      Параметры:
      12.jpg

Теперь, после изменения файла C:\Soft\Test\MyDoc.xls он будет копироваться в \\Book01\c$\Documents and Settings\User\Рабочий стол\MyDoc.xls

Дополнение: в принципе, этот метод можно адаптировать и под Windows XP, но, честно говоря, эта ОС уходит в прошлое и уже просто не хочется тратить время. Тем не менее, если кому понадобится, то даю наводки - из журнала событий берем события 560 и 567 и совместно их анализируем - в 560-м имя файла, в 567-м - метод (чтение или запись). Для запроса событий журнала из PowerShell используем командлет Get-EventLog, будет запрос типа такого:

Код: Выделить всё

Get-EventLog -LogName Security -EntryType SuccessAudit -InstanceId 560 -Message *C:\Soft\Temp* -Newest 1 -Source Security

Сохраняем полученный скрипт в папке, например «c:\Soft\Bat\WriteFileAudit.ps1», ну и создаем триггер на событие 560 журнала Security так, как описано здесь, получится что-то подобное:

Код: Выделить всё

eventtriggers /create /TR "Write File" /TK "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -WindowStyle Hidden c:\Soft\Bat\WriteFileAudit.ps1" /L Security /EID 560

Alexander A. Manaeff©

Понравилась статья? Будем крайне признательны за репосты в соцсетях! Материально поддержать проект можно здесь

Мои странички:
ВКонтакте
Одноклассники
Youtube
Facebook
Instagram

Изображение
Изображение
Изображение
Изображение