Posts on this page:
Update 28.10.2010: исправлена ошибка с назначением права ManageDocuments.
Вот и пришло время закрыть тему управления принтерами и их списками ACL в PowerShell с использованием WMI. Я в блоге уже расписывал решение частных задач по основным задачам управления принтеров и по управлению их ACL списками. В этом посте я сложу все наработки по этому вопросу в единый концептуальный скрипт, который будет называться PrinterUtils.ps1 с достаточно объёмным набором функций, которые нацелены на упрощение для администраторов автоматизации принтеров с использованием PowerShell. Если кто-то захочет разобраться в работе скрипта и понять используемые приёмы, то предлагаю ознакомиться с следующими ссылками:
В качестве основы я использовал свои предыдущие наработки с SecurityDescriptor в предыдущем блоге, когда разбирал вопрос управления SharePermissions из PowerShell:
Материала у меня на эту тему набралось достаточно много, чтобы проникнуться в идею работы классов WMI и SecurityDescriptor, который не раз пытался посадить меня в лужу :) Однако версия скрипта ShareUtils чётко говорит о том, что скрипт далеко не идеален и не оптимален, имеет свои недостатки, т.к. это был мой первый опыт работы с функциями. Сейчас я значительно переработал структуру работы скрипта (оставив только Core работы с SecurityDescriptor), добавив удалённое управление (в разумных пределах) и, главное (как мне кажется), реализовал работу функций в конвейере. Примеры использования скрипта распишу чуть ниже. Итак, представляю набор функций, которые реализованы в скрипте:
Данная секция представляет собой базовые возможности по управлению принтерами и полностью работоспособна в среде Windows XP/Windows Server 2003. А вот секция управления ACL списками принтеров доступна только в среде Windows Vista/Windows Server 2008. Сюда входят следующие функции:
Для этих функций полностью реализована поддержка удалённой работы и работа в конвейере. Синтаксис команд используется примерно следующий:
Итак, как я и обещал, я вернулся к вопросу изменения ACL принтеров в PowerShell. В первой части (Странности метода SetSecurityDescriptor класса Win32_Printer) я изложил проблематику вопроса. В конечном итоге я сегодня смог найти решение, которое оказалось не совсем понятным, но относительно предсказуемым.
Вернёмся снова к документации MSDN: SetSecurityDescriptor Method of the Win32_Printer Class
Это, конечно же, было моим попустительством, что не указал флаг управления SE_DACL_PRESENT и не включил привилегии SeSecurityPrivilege ("умение читать - первое умение системного администратора" (c) Peter.G). Понимание этого факта пришло после очередного прочтения поста о смене владельца папки (Смена владельца папки или файла в PowerShell (часть 2)). Что касается флагов управления, то выложу здесь значения флагов:
Как-то давно Александр Станкевич просил у меня вариант скрипта, который бы менял владельца файла или папки из PowerShell. В своё время я занимался этим вопросом и результат моих исследований:
Что-то меня натолкнуло снова вернуться к этому вопросу. Учитывая проблематику, изложенных в предыдущих статьях, я перестал искать нативный способ изменения владельца в PowerShell через .NET и решил поискать его в WMI (что означает очередные мучения многострадального SecurityDescriptor :( ). Итак, у WMI есть несколько классов для работы с ACL (AccessControlList) файлов и папок. Например:
Навеяно темой на форуме: http://forum.sysfaq.ru/index.php?showtopic=13274
Итак, есть задача отслеживать события удаления объектов (файлов и/или папок) с файлового сервера. Итак, для начала необходимо настроить аудит на файловом сервере. Приведу рекомендации коллеги WindowsNT:
Учитывая сопутствующую проблематику удалений, что для части программ при работе нормально удалять файлы при сохранении было предложено фиксировать 5 событий удаления в секунду. Такая схема вполне сгодится для среднестатистического решения. В любом случае предложенный скрипт можно будет изменить под свои нужды вполне свободно. За основу будет взят пост из моего предыдущего блога (Аудит входов на сервере терминалов с использованием PowerShell), но с некоторыми доработками.
Итак, задача разбивается на 4 составные части:
Итак, давайте пробовать решить все этапы:
1) получение массива эвентов по коду 560:
$Events = Get-EventLog security | ?{$_.eventid -eq 560 -and $_.EntryType -eq "SuccessAudit" -and $_.message -like "*Object Name:`tD:\Shared Documents\*" -and $_.message -like "*Accesses:`t%delete*" }
Итак, здесь я сделал 3 фильтра: код события - 560, Тип аудита Success Audit (т.к. под кодом 560 регистрируются и неуспешные аудиты), имя корневой папки, которая нас будет интересовать (только для случаев, если настроено несколько аудитов на различных папках) и явно будем интересоваться действием $Delete. Теперь из этого массива нужно получить массив уникального времени:
$UniqueTime = $Events | select -Unique TimeGenerated | %{($_.timegenerated).datetime}
Здесь я получил массив с набором уникального времени. Отмечу, что я взял свойство DateTime, которое даст нам точность до 1 секунды. Массив мы делаем затем, чтобы потом считать сколько событий удаления зафиксировано с этим временем (отличить легальное удаление от нелегального). Теперь при помощи полученной переменной соберём кол-во эвентов удаления на момент уникального времени. Иными словами мы берём отметку времени, когда зафиксирован лог удаления файла или папки и посмотрим, сколько ещё логов было зафиксировано за эту секунду:
[object[]]$SelectedEvents = $Events | ?{($_.timegenerated).datetime -eq UniqueTime} $SelectedEvents.count
Переменная $SelectedEvents будет содержать все эвенты удаления в течении секунды. И их количество можно посчитать свойством Count. И дальше можно проводить сравнительный анализ по кол-ву эвентов. Если их за секунду зафиксировано больше 5 (вероятность нелегального удаления файлов), то продолжаем разбирать переменную $SelectedEvents. Разбирается скрипт по той же схеме, что и в упомянутой выше статье по аудиту доступа на терминальный сервер. В итоге мы получим такой скрипт:
######################################################## # FileServerDeleteAudit.ps1 # Version 1.0 # # Windows Server 2003 eventlog parser # # Vadims Podans (c) 2008 # http://www.sysadmins.lv/ ######################################################## $Data = New-Object System.Management.Automation.PSObject $Data | Add-Member NoteProperty Time ($null) $Data | Add-Member NoteProperty UserName ($null) $Data | Add-Member NoteProperty FileName ($null) $Data | Add-Member NoteProperty EventCount ($null) $Events = Get-EventLog security | ?{$_.eventid -eq 560 -and $_.EntryType -eq "SuccessAudit" -and $_.message -like "*Object Name:`tD:\Shared Documents\*" -and $_.message -like "*Accesses:`t%delete*" } $UniqueTime = $Events | select -Unique TimeGenerated | %{($_.timegenerated).datetime} foreach ($time in $UniqueTime) {[object[]]$SelectedEvents = $Events | ?{($_.timegenerated).datetime -eq $time} if ($SelectedEvents.count -ge 5) { $Data.EventCount = $SelectedEvents.Count $SelectedEvents | %{ $message = $_.message.split("`n") | %{$_.trim()} $Data.time = $_.TimeGenerated if ($message -like "Primary User Name:`t*$") { $Data.UserName = ($message | ?{$_ -like "Client User Name:*"} | %{$_ -replace "^.+`t *"})} else { $Data.UserName = ($message | ?{$_ -like "Primary User Name:*"} | %{$_ -replace "^.+`t *"})} $Data.FileName = ($message | ?{$_ -like "Object Name:*"} | %{$_ -replace "^.+`t *"}) $Data } } }
Что касается поля $Data.UserName, то здесь я сделал проверку поля Primary User Name. Если файл или папка были удалены с компьютера локально, то данное поле заполняется именем пользователя. Если же файл или папку удалили по сети, то в данном поле будет указано имя компьютера в формате ComputerName$, а имя пользователя будет отражено в поле Client User Name. Поэтому если в поле Primary User Name будет встречаться знак доллара ($), то мы в поле $Data.UserName записываем имя пользователя из поля эвентлога Client User Name. Жирным в скрипте я отметил те места, которые в зависимости от местных условий могут изменяться. В первом случае отмечена корневая папка, которая будет изучаться и кол-во инцидентов удаления в секунду описывает порог срабатывания скрипта. И результат работы скрипта:
Time UserName FileName EventCount ---- -------- -------- ---------- 2008.11.15. 23:33:44 Administrator C:\New Folder\dasblog 140 2008.11.15. 23:33:44 Administrator C:\New Folder\dasblog\bin 140 2008.11.15. 23:33:44 Administrator C:\New Folder\dasblog\bin\AR 140 2008.11.15. 23:33:44 Administrator C:\New Folder\dasblog\bin\... 140 2008.11.15. 23:33:44 Administrator C:\New Folder\dasblog\bin\... 140 2008.11.15. 23:33:44 Administrator C:\New Folder\dasblog\bin\BG 140 2008.11.15. 23:33:44 Administrator C:\New Folder\dasblog\bin\... 140 2008.11.15. 23:33:44 Administrator C:\New Folder\dasblog\bin\... 140 2008.11.15. 23:33:44 Administrator C:\New Folder\dasblog\bin\DA 140 2008.11.15. 23:33:44 Administrator C:\New Folder\dasblog\bin\... 140 2008.11.15. 23:33:44 Administrator C:\New Folder\dasblog\bin\... 140
Enjoy!
В первой и второй части я рассказал про основные моменты управления принтерами в PowerShell и теперь хочу поговорить о правах на принтеры. Т.к. принтеры управляются с помощью классов WMI, то управление правами доступа к ним будет превращаться в очередную эпохальную эпопею, которую я исследовал при изучении безопасности Share Permissions (вот ссылка на эти статьи в моём прежнем блоге: http://vpodans.spaces.live.com/lists/cns!BB1419A2CFC1E008!178). Однако, с принтерами оказалось всё печальней :( Мне так и не удалось заставить работать метод SetSecurityDescriptor. Итак, я расскажу о своих кратких исследованиях и в чём же мы имеем проблему.
Для чтения прав доступа принтера потребуется метод GetSecurityDescriptor: