PowerShell и Group Policy Preferences, когда счет принтеров на сотни

Много копий сломано вокруг управления сетевыми принтерами на пользовательских компьютерах. В основном администраторы разбились на два лагеря: подключение логон-скриптами (bat/vbs) и управление через GPP. У обоих подходов есть свои плюсы: скрипты быстрее обрабатываются, а GPP гибче и применяется чаще, чем пользователи перезагружают компьютеры. Но когда принтеров больше сотни и разбросаны они в нескольких десятках офисов и городов, сложности будут в обоих случаях.

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

В общем, мы с коллегами для себя выбрали GPP, в первую очередь для того, чтобы кто-то кроме ведущих администраторов мог разобраться в действующем конфиге, просто посмотрев отчет GPMC. Однако, кто скажет, что его штатный интерфейс удобен для управления 100+ устройствами — пусть первый бросит в меня камень. Кроме того, при вводе в эксплуатацию очередной партии нужно проделать много рутины по настройке сетевого сканирования и добавлению на сервер печати.

А всё, что делается больше одного раза, можно автоматизировать!

Что мы сегодня будем делать?

  • вести учет всех сетевых принтеров;
  • автоматизировать добавление принтеров в GPP (PS/XML);
  • автоматизировать добавление принтеров на принт-сервер, причем на кластерный (BAT/VBS)!

Итак, начнем.

1. Учет сетевых принтеров

Первая проблема, которая возникает при управлении большим количеством любых объектов — это учет. Без него легко запутаться, что где установлено и кому должно быть подключено.
Самое простое и универсальное решение — CSV. В конце концов, из любой системы инвентаризации, ServiceDesk или Excel-таблицы можно выгрузить в CSV и потом легко импортировать это в PowerShell, что мы и будем делать дальше.

У нас выгрузка выглядит вот так:

image

Поясню сразу, для чего столько полей:

  • Name — сетевое имя принтера, оно прописывается в DNS и на сервере печати
  • ByGroup — поле определяет, подключать принтер всем, кто находится в соответствующей подсети или только тем, кто входит в группу AD. Также по группе задаются ACL.
  • Subnet — подсеть, в которой должен находиться пользователь для работы с принтером
  • Location — строка расположения принтера, по которой ищет виндовый мастер добавления принтеров
    Как устроен поиск принтеров по локации

    Многие не знают, что происходит при поиске принтера стандартным мастером «Установка принтера». А происходит вот что. Мастер берет поле Location (Расположение) из атрибутов компьютера в AD, и выбирает из опубликованных в AD принтеров все, у которых расположение начинается с той же строки. То есть, если у компьютера пользователя в расположении указано «Омск/Офис на Ленина», то в поиске отобразятся принтеры с расположениями «Омск/Офис на Ленина/», «Омск/Офис на Ленина/Кабинет 404» и «Омск/Офис на Ленина/Приёмная»
  • Driver — имя драйвера, который будет указан при добавлении на сервер печати. Этот драйвер должен быть уже установлен на сервере. Обычно у всех производителей, поставляющих более-менее серьезную печатную технику, есть универсальные драйвера, и они устанавливаются максимум один раз на партию, и то, если вендор поменялся, поэтому эту часть я не автоматизировал.
  • Type — просто описание принтера, чтобы пользователи легко выбирали нужный принтер по его возможностям при необходимости.
  • Model — модель принтера или МФУ. Здесь с помощью вспомогательных таблиц по этому полю заполняются предыдущие два.
  • UID — а это часть сегодняшнего торта. Этим UID-ом помечаются объекты в GPP, упрощенно — чтобы не переустанавливать принтер при каждом обновлении групповых политик.

Этого набора данных достаточно, чтобы не хардкодить их в Powershell. Можно начинать веселье.

2. Автоматизируем GPP

В общем случае файл Printers.xml в объекте GPP выглядит примерно так:

<?xml version="1.0" encoding="utf-8"?> <Printers clsid="{1F577D12-3D1B-471e-A1B7-060317597B9C}">   <SharedPrinter   clsid="{9A5E9697-9095-436d-A0EE-4D128FDFBCE5}"   name="PRN-BARAB-061"   status="PRN-BARAB-061"   image="2"   uid="{43231EA0-A4A3-4F1A-8A25-95BC4FEFBCC6}"   userContext="1"   bypassErrors="1">     <Properties action="U" comment="" path="\\print-cluster-1.common.domain\PRN-BARAB-061" default="0" port="" />     <Filters>       <FilterGroup bool="AND" not="0" name="COMDOM\PRN-BARAB-061" sid="S-1-5-21-210359847-7924152125-768726458-48993" userContext="1" />       <FilterIpRange bool="AND" not="0" min="192.168.142.1" max="192.168.142.254" />     </Filters>   </SharedPrinter> </Printers> 

Первоисточник формата можно изучить здесь: [MS-GPPREF]: Printers и здесь: [MS-GPPREF]: Common XML Attributes.

Практически же, я думаю, вы без труда сопоставите названия полей в этом файле с чекбоксами в интерфейсе GPP, но ключевые моменты я отмечу:

clsid — это фиксированные значения классов Group Policy Preferences, их можно (и нужно) оставить как есть.

Name/Status — это отображаемые имена элементов в консоли GPP
uid — а вот это уникальный идентификатор объекта, который вы видели в таблице выше.

Если он будет меняться при каждом обновлении списка принтеров, принтер будет заново подключаться у всех пользователей, что может вызывать разные побочные эффекты.
Path — UNC-путь к принтеру
FilterGroup, FilterIpRange — элементы нацеливания (Targeting) по членству пользователя в группе AD и по нахождению компьютера в диапазоне IP-адресов.

2.1. Импортируем данные и создадим базовую структуру XML-документа:

Для этого используем системный класс [System.Xml.XmlDocument]:

$PrintersCSV = Import-Csv -Delimiter ";" ".\Printers.csv" -Encoding Default  [System.Xml.XmlDocument]$PrintersGPP = New-Object System.Xml.XmlDocument $PrintersGPP.PrependChild($PrintersGPP.CreateXmlDeclaration("1.0", "utf-8", $null)) | Out-Null $Printers = $PrintersGPP.AppendChild($PrintersGPP.CreateElement("Printers")) $Printers.SetAttribute("clsid","{1F577D12-3D1B-471e-A1B7-060317597B9C}") 

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

Создание элемента принтера:

Function NewSharedPrinter {     [CmdletBinding()]     param (         $SharedPrinter,         $clsid = "{9A5E9697-9095-436d-A0EE-4D128FDFBCE5}", 		$uid,         $name,         $action     )      $image     switch ($action){         "C" {$image = 0}         "R" {$image = 1}         "U" {$image = 2}         "D" {$image = 3}     }      $SharedPrinter.SetAttribute("clsid",$clsid)     $SharedPrinter.SetAttribute("name",$name)     $SharedPrinter.SetAttribute("status",$name)     $SharedPrinter.SetAttribute("image",$image) 	$SharedPrinter.SetAttribute("uid",$uid)     $SharedPrinter.SetAttribute("userContext",1)     $SharedPrinter.SetAttribute("bypassErrors",1)      $SharedPrinterProperties = $SharedPrinter.AppendChild($PrintersGPP.CreateElement("Properties"))     $SharedPrinterProperties.setattribute("action",$action)     $SharedPrinterProperties.setattribute("comment","")     $SharedPrinterProperties.setattribute("path","\\print-cluster-1.common.domain\$name")     $SharedPrinterProperties.setattribute("default",0)     $SharedPrinterProperties.setattribute("port","") } 

Создание элементов фильтрации (нацеливания) по группе и по подсети:

 Function NewFilterGroup{     [CmdletBinding()]     param (         $FilterGroup,         $bool = "AND",         $not = 0,         $name,         $sid     )     $FilterGroup.SetAttribute("bool",$bool)     $FilterGroup.SetAttribute("not",$not)     $FilterGroup.SetAttribute("name","COMDOM\"+$name)     $FilterGroup.SetAttribute("sid",$sid)     $FilterGroup.SetAttribute("userContext",1) }  Function NewFilterSubnet{     [CmdletBinding()]     param (         $FilterIPRange,         $bool = "AND",         $not = 0,         $start,         $end     )         $FilterIPRange.SetAttribute("bool",$bool)         $FilterIPRange.SetAttribute("not",$not)         $FilterIPRange.SetAttribute("min",$start)         $FilterIPRange.SetAttribute("max",$end) } 

Все три функции работают напрямую с передаваемым объектом PS и ничего не возвращают. Ремарка для перфекционистов: на момент написания скрипта так было проще и быстрее, я не стремился написать идеальный объектно-ориентированный код, мне просто нужно было, чтобы работало. Так что да, в коде есть, что улучшать, но главное — он работает!

2.3. И, наконец, основной цикл, добавление элементов управления принтерами

Для каждого принтера создается два элемента: один на добавление, если пользователь в группе и в подсети, и один на удаление принтера, если пользователь не входит в группу или находится в другой подсети.

Если по какой-то причине в CSV-файле нет UID принтера, он сгенерируется и будет выведен в консоль.

Для перевода подсети из нотации CIDR в диапазон адресов я позаимствовал замечательный командлет PSipcalc.

ForEach ($PrinterItem in ($PrintersCSV | Sort-Object Name)) {      if (!$PrinterItem.uid){         $uid = "{"+([guid]::NewGuid()).Guid.ToUpper()+"}"         Write-Host "Printer $($PrinterItem.Name) is new. Policy item ID: $uid"     } else {         $uid = $PrinterItem.uid     }          $SharedPrinter = $PrintersGPP.CreateElement("SharedPrinter")     NewSharedPrinter -SharedPrinter $SharedPrinter -name $PrinterItem.Name -action "U" -uid $uid          $Filters = $SharedPrinter.AppendChild($PrintersGPP.CreateElement("Filters"))     if ($PrinterItem.ByGroup -ieq "yes") {         try {             Get-ADGroup -Identity $PrinterItem.Name | Out-Null         } catch {             Write-Host "Creating group $($PrinterItem.Name)"             New-ADGroup -Name $PrinterItem.Name `                 -Path "OU=Доступ к принтерам и МФУ,OU=User Groups,DC=DOM,DC=COM" -GroupScope DomainLocal         }         $FilterGroup = $PrintersGPP.CreateElement("FilterGroup")         NewFilterGroup -FilterGroup $FilterGroup -name $PrinterItem.Name -sid (Get-ADGroup -Identity $PrinterItem.Name).SID.Value         $Filters.AppendChild($FilterGroup) | Out-Null     }      $FilterNetwork = .\PSipcalc.ps1 -NetworkAddress $PrinterItem.Subnet      $FilterIPRange = $PrintersGPP.CreateElement("FilterIpRange")     NewFilterSubnet -FilterIPRange $FilterIPRange -start $FilterNetwork.HostMin -end $FilterNetwork.HostMax     $Filters.AppendChild($FilterIPRange) | Out-Null      $Printers.AppendChild($SharedPrinter) | Out-Null      $RevertSharedPrinter = $PrintersGPP.CreateElement("SharedPrinter")     NewSharedPrinter -SharedPrinter $RevertSharedPrinter -name $PrinterItem.Name -action "D" -uid $uid          if ($PrinterItem.ByGroup -ieq "yes") {         $bool = "OR"     } else {         $bool = "AND"     }      $Filters = $RevertSharedPrinter.AppendChild($PrintersGPP.CreateElement("Filters"))     if ($PrinterItem.ByGroup -ieq "yes") {         $FilterGroup = $PrintersGPP.CreateElement("FilterGroup")         NewFilterGroup -FilterGroup $FilterGroup -name $PrinterItem.Name -sid (Get-ADGroup -Identity $PrinterItem.Name).SID.Value -bool "AND" -not 1         $Filters.AppendChild($FilterGroup) | Out-Null     }      $FilterIPRange = $PrintersGPP.CreateElement("FilterIpRange")     NewFilterSubnet -FilterIPRange $FilterIPRange -start $FilterNetwork.HostMin -end $FilterNetwork.HostMax -bool $bool -not 1     $Filters.AppendChild($FilterIPRange) | Out-Null      $Printers.AppendChild($RevertSharedPrinter) | Out-Null } 

2.4. И теперь выводим результат в файл

Не вижу ничего плохого в том, чтобы сэкономить немного минут и сразу записать в политику:

$PrintersGPP.Save("\\COMDOM\SysVol\COMMON.DOMAIN\Policies\{f985a9ae-cb71-468b-8a99-e2c7f428aa2f}\User\Preferences\Printers\Printers.xml")

3. Добавление принтеров на сервер печати

В Windows есть довольно малоизвестный набор vbs-скриптов для управления принтерами. Причем он есть даже в клиентских версиях. Расположен он в каталоге %SystemRoot%\System32\Printing_Admin_Scripts\en-US, мурзилку можно почитать здесь.

Нас интересуют три утилиты из набора:

prnport.vbs — для создания порта принтера на сервере печати
prnmngr.vbs — для создания самого принтера
prncnfg.vbs — для задания настроек и включения общего доступа к принтеру
Также нам понадобится утилита SetACL для задания прав доступа на принтеры.

3.1. Создаем принтер на сервере печати

Для этого создадим скрипт CreateRemotePrinter.bat.

В качестве аргументов он будет принимать, по порядку:
%1 — Имя принтера;
%2 — Имя драйвера;
%3 — Расположение (Location);
%4 — Описание принтера.

@echo off SET PRTOOLS="c:\Windows\System32\Printing_Admin_Scripts\en-US" SET SETACL="SetACL.exe"  cscript /nologo %PRTOOLS%\prnport.vbs -s print-cl-node-1 -a -r %1 -h %1.common.domain -t -o raw -me cscript /nologo %PRTOOLS%\prnmngr.vbs -s print-cl-node-1 -a -p %1 -m %2 -r %1 cscript /nologo %PRTOOLS%\prncnfg.vbs -s print-cl-node-1 -t -p %1 -h %1 -l %3 -m %4 +shared %SETACL% -on \\print-cl-node-1\%1 -ot prn -actn ace -ace "n:STN-TN\%1;p:man_docs,print" 

В общем случае этого достаточно. Но у нас сервер печати размещен на кластере MSCS, а указанный выше набор vbs-скриптов с кластерами работать не умеет. Поэтому придется сделать еще кое-что.

3.2. Переносим принтер с обычного сервера печати на кластеризованный

При обращении к кластеру скрипты из набора выше просто создают порт и принтер на текущей активной ноде, и на кластере они не появляются. Как раз на такой случай у Майкрософт припасен еще один инструмент — PrintBRM (Print queue Backup/Recovery/Migration). Официальной документации на него я не нашел, поэтому делюсь тем, что есть: Справка по параметрам на SS64.

Продолжаем скрипт CreateRemotePrinter.bat.

Утилита PrintBRM умеет корректно копировать конфигурацию принтера вместе с портами на кластер, однако если просто сделать копию (запустить с ключом -b) и восстановить (-r), то никакого чуда не будет.

Поэтому сейчас будет немного магии. Она подробно описана в блоге MS Performance Team Blog.
Сначала мы делаем резервную копию принтера в файл temp.printerexport.

Затем распаковываем в подкаталог printerexport, удаляем каталоги LMONS и PRTPROCS, а также обнуляем содержимое нескольких XML-файлов. Не буду вдаваться в подробности, но эти файлы содержат конфигурацию, специфичную для конкретного сервера и мешают восстановлению принтера на другой сервер, особенно кластерный.

После этого запаковываем отредактированную конфигурацию обратно в файл temp.printerexport и загружаем на кластер:

SET PRNBRM="C:\Windows\System32\spool\tools\PrintBrm.exe"  %PRNBRM% -b -nobin -s print-cl-node-1 -f temp.printerexport %PRNBRM% -r -d printerexport -f temp.printerexport  del /f /q temp.printerexport del /s /f /q printerexport\LMONS printerexport\PRTPROCS echo ^<SpoolerAttrib /^>			> printerexport\BrmSpoolerAttrib.xml echo ^<PPROCS /^>					> printerexport\PProcs.xml echo ^<PRINTERDRIVERS /^>			> printerexport\BrmDrivers.xml echo ^<LMONS Arch="Windows x64"/^>	> printerexport\BRMLMons.xml  %PRNBRM% -b -d printerexport -f temp.printerexport del /s /f /q printerexport  %PRNBRM% -r -s print-cluster-1 -f temp.printerexport -p all -o force del /f /q temp.printerexport  cscript /nologo %PRTOOLS%\prnmngr.vbs -s print-cl-node-1 -d -p %1 cscript /nologo %PRTOOLS%\prnport.vbs -s print-cl-node-1 -d -r %1 

3.3. Добавляем принтеры одновременно в GPP и на сервер/кластер

Теперь нужно органично вписать этот скрипт в цикл обработки CSV-списка принтеров.

Добавим перед основным циклом запрос списка уже существующих на сервере:

$ActualPrintersList = Get-WmiObject -Class win32_share -computer print-cluster-1 | Where-Object Name -like "*PRN*" | Select-Object -ExpandProperty Name 

И в теле цикла запустим наш Bat-ничек:

    if ("\\print-cluster-1\$($PrinterItem.Name)" -NotIn $ActualPrintersList) {         Write-Host "Adding printer $($PrinterItem.Name) to print-cluster-1..."         Start-Process -FilePath .\CreateRemotePrinter.bat -ArgumentList "$($PrinterItem.Name) `"$($PrinterItem.Driver)`" `"$($PrinterItem.Location)`" `"$($PrinterItem.Type)`"" -Wait     } 

4. Собираем все воедино, запускаем, получаем результат

Исходные данные в CSV

Name;ByGroup;Subnet;Location;Driver;Type;Model;uid
PRN-NALTA-028;yes;192.168.192.0/24;Новоалтайск/;HP Universal Printing PCL 6 (v5.6.0);МФУ А4 ЧБ — HP LaserJet Pro M425dn;HP LaserJet Pro M425dn;{35F6CF36-2A24-4A81-B061-8BE71CEC27EA}
PRN-TARUS-002;yes;192.168.128.0/23;Таруса/;HP Universal Printing PCL 6 (v5.6.0);МФУ А4 ЧБ — HP LaserJet M3027 MFP;HP LaserJet M3027 MFP;{398F4A94-530C-4E3B-8A30-4288D5E8854D}
PRN-KIRILL-081;;192.168.196.0/24;Кириллов/;HP Universal Printing PCL 6 (v5.6.0);МФУ А4 ЧБ — HP LaserJet 3390;HP LaserJet 3390;{421FC2DE-2E97-49FC-AEB0-3070B0166AD5}
PRN-BARAB-061;yes;192.168.142.0/24;Барабинск/;HP Universal Printing PCL 6 (v5.6.0);МФУ А4 ЧБ — HP LaserJet Pro M425dn;HP LaserJet Pro M425dn;{43231EA0-A4A3-4F1A-8A25-95BC4FEFBCC6}
PRN-PYSHM-004;;192.168.143.0/24;Верхняя Пышма/;KX DRIVER for Universal Printing;МФУ А4 ЧБ — Kyocera ECOSYS M2540dn;Kyocera ECOSYS M2540dn;{45509B48-E7BC-4497-9665-86D4E1E96FE1}
PRN-BUY---001;yes;192.168.44.0/24;Буй/;HP Universal Printing PCL 6 (v5.6.0);Принтер А4 ЧБ — HP LaserJet Pro M402dn;HP LaserJet Pro M402dn;{457DB3FE-E35F-450E-B1D6-912F0D831573}
PRN-BATAY-042;yes;192.168.128.0/23;Батайск/;HP Universal Printing PCL 6 (v5.6.0);Принтер А4 ЧБ — HP LaserJet P2015 Series;HP LaserJet P2015 Series;{4740604B-C403-4511-91B0-689A197260F3}
PRN-EMPTY-002;yes;192.168.199.0/24;Пустошка/;HP Universal Printing PCL 6 (v5.6.0);МФУ А4 ЧБ — HP LaserJet Pro M425dn;HP LaserJet Pro M425dn;{475578CB-689F-463B-9710-AE207973146C}
PRN-LIPKI-003;;192.168.44.0/24;Липки/;KX DRIVER for Universal Printing;МФУ А4 ЧБ — Kyocera ECOSYS M2540dn;Kyocera ECOSYS M2540dn;{4794D22E-6586-4A81-A85D-A21FB8B209CF}
PRN-KOTOV-013;yes;192.168.128.0/23;Котово/;HP Universal Printing PCL 6 (v5.6.0);МФУ А4 ЧБ — HP LaserJet Pro M425dn;HP LaserJet Pro M425dn;{4DFFBA1F-48D2-4824-B2EB-0AAD12B6A9D6}
PRN-ELAB-064;;192.168.140.0/24;Елабуга/;HP Universal Printing PCL 6 (v5.6.0);МФУ А4 ЧБ — HP LaserJet Pro M425dn;HP LaserJet Pro M425dn;{52069D45-EF86-442D-A157-368D7510A1CF}
GeneratePrintersXml.ps1

$PrintersCSV = Import-Csv -Delimiter ";" ".\Printers.csv" -Encoding Default  [System.Xml.XmlDocument]$PrintersGPP = New-Object System.Xml.XmlDocument $PrintersGPP.PrependChild($PrintersGPP.CreateXmlDeclaration("1.0", "utf-8", $null)) | Out-Null $Printers = $PrintersGPP.AppendChild($PrintersGPP.CreateElement("Printers")) $Printers.SetAttribute("clsid","{1F577D12-3D1B-471e-A1B7-060317597B9C}")      $DelPrinters = $Printers.AppendChild($PrintersGPP.CreateElement("SharedPrinter"))     NewSharedPrinter -SharedPrinter $DelPrinters -name "Delete All" -action "D" -uid "{21097DBD-285D-48C3-B042-7746D7E6DA1B}"     $Filters = $DelPrinters.AppendChild($PrintersGPP.CreateElement("Filters"))     $FilterRunOnce = $Filters.AppendChild($PrintersGPP.CreateElement("FilterRunOnce"))     $FilterRunOnce.SetAttribute("id","{F2537B78-C7D7-43DF-98D6-B32E90644825}")     $FilterRunOnce.SetAttribute("hidden",1)     $FilterRunOnce.SetAttribute("not",0)     $FilterRunOnce.SetAttribute("bool","AND")  Function NewSharedPrinter {     [CmdletBinding()]     param (         $SharedPrinter,         $clsid = "{9A5E9697-9095-436d-A0EE-4D128FDFBCE5}",         $uid,         $name,         $action     )      $image     switch ($action){         "C" {$image = 0}         "R" {$image = 1}         "U" {$image = 2}         "D" {$image = 3}     }      $SharedPrinter.SetAttribute("clsid",$clsid)     $SharedPrinter.SetAttribute("name",$name)     $SharedPrinter.SetAttribute("status",$name)     $SharedPrinter.SetAttribute("image",$image)     $SharedPrinter.SetAttribute("uid",$uid)     $SharedPrinter.SetAttribute("userContext",1)     $SharedPrinter.SetAttribute("bypassErrors",1)      $SharedPrinterProperties = $SharedPrinter.AppendChild($PrintersGPP.CreateElement("Properties"))     $SharedPrinterProperties.setattribute("action",$action)     $SharedPrinterProperties.setattribute("comment","")     $SharedPrinterProperties.setattribute("path","\\print-cluster-1.common.domain\$name")     $SharedPrinterProperties.setattribute("default",0)     $SharedPrinterProperties.setattribute("port","") }  Function NewFilterGroup{     [CmdletBinding()]     param (         $FilterGroup,         $bool = "AND",         $not = 0,         $name,         $sid     )     $FilterGroup.SetAttribute("bool",$bool)     $FilterGroup.SetAttribute("not",$not)     $FilterGroup.SetAttribute("name","COMDOM\"+$name)     $FilterGroup.SetAttribute("sid",$sid)     $FilterGroup.SetAttribute("userContext",1) }  Function NewFilterSubnet{     [CmdletBinding()]     param (         $FilterIPRange,         $bool = "AND",         $not = 0,         $start,         $end     )         $FilterIPRange.SetAttribute("bool",$bool)         $FilterIPRange.SetAttribute("not",$not)         $FilterIPRange.SetAttribute("min",$start)         $FilterIPRange.SetAttribute("max",$end) }  $ActualPrintersList = Get-WmiObject -Class win32_share -computer print-cluster-1 | Where-Object Name -like "*PRN*" | Select-Object -ExpandProperty Name  ForEach ($PrinterItem in ($PrintersCSV | Sort-Object Name)) {      if (!$PrinterItem.uid){         $uid = "{"+([guid]::NewGuid()).Guid.ToUpper()+"}"         Write-Host "Printer $($PrinterItem.Name) is new. Policy item ID: $uid"     } else {         $uid = $PrinterItem.uid     }          $SharedPrinter = $PrintersGPP.CreateElement("SharedPrinter")     NewSharedPrinter -SharedPrinter $SharedPrinter -name $PrinterItem.Name -action "U" -uid $uid          $Filters = $SharedPrinter.AppendChild($PrintersGPP.CreateElement("Filters"))     if ($PrinterItem.ByGroup -ieq "yes") {         try {             Get-ADGroup -Identity $PrinterItem.Name | Out-Null         } catch {             Write-Host "Creating group $($PrinterItem.Name)"             New-ADGroup -Name $PrinterItem.Name `                 -Path "OU=Доступ к принтерам и МФУ,OU=User Groups,DC=DOM,DC=COM" -GroupScope DomainLocal         }         $FilterGroup = $PrintersGPP.CreateElement("FilterGroup")         NewFilterGroup -FilterGroup $FilterGroup -name $PrinterItem.Name -sid (Get-ADGroup -Identity $PrinterItem.Name).SID.Value         $Filters.AppendChild($FilterGroup) | Out-Null     }      $FilterNetwork = .\PSipcalc.ps1 -NetworkAddress $PrinterItem.Subnet      $FilterIPRange = $PrintersGPP.CreateElement("FilterIpRange")     NewFilterSubnet -FilterIPRange $FilterIPRange -start $FilterNetwork.HostMin -end $FilterNetwork.HostMax     $Filters.AppendChild($FilterIPRange) | Out-Null      $Printers.AppendChild($SharedPrinter) | Out-Null      $RevertSharedPrinter = $PrintersGPP.CreateElement("SharedPrinter")     NewSharedPrinter -SharedPrinter $RevertSharedPrinter -name $PrinterItem.Name -action "D" -uid $uid          if ($PrinterItem.ByGroup -ieq "yes") {         $bool = "OR"     } else {         $bool = "AND"     }      $Filters = $RevertSharedPrinter.AppendChild($PrintersGPP.CreateElement("Filters"))     if ($PrinterItem.ByGroup -ieq "yes") {         $FilterGroup = $PrintersGPP.CreateElement("FilterGroup")         NewFilterGroup -FilterGroup $FilterGroup -name $PrinterItem.Name -sid (Get-ADGroup -Identity $PrinterItem.Name).SID.Value -bool "AND" -not 1         $Filters.AppendChild($FilterGroup) | Out-Null     }      $FilterIPRange = $PrintersGPP.CreateElement("FilterIpRange")     NewFilterSubnet -FilterIPRange $FilterIPRange -start $FilterNetwork.HostMin -end $FilterNetwork.HostMax -bool $bool -not 1     $Filters.AppendChild($FilterIPRange) | Out-Null      $Printers.AppendChild($RevertSharedPrinter) | Out-Null          if ("\\print-cluster-1\$($PrinterItem.Name)" -NotIn $ActualPrintersList) {         Write-Host "Adding printer $($PrinterItem.Name) to print-cluster-1..."         Start-Process -FilePath .\CreateRemotePrinter.bat -ArgumentList "$($PrinterItem.Name) `"$($PrinterItem.Driver)`" `"$($PrinterItem.Location)`" `"$($PrinterItem.Type)`"" -Wait     } }  $PrintersGPP.Save("\\COMDOM\SysVol\COMMON.DOMAIN\Policies\{f985a9ae-cb71-468b-8a99-e2c7f428aa2f}\User\Preferences\Printers\Printers.xml") $PrintersGPP.Save(".\Printers.xml")
CreateRemotePrinter.bat

@echo off SET PRTOOLS="c:\Windows\System32\Printing_Admin_Scripts\en-US" SET SETACL="SetACL.exe" SET PRNBRM="C:\Windows\System32\spool\tools\PrintBrm.exe"  cscript /nologo %PRTOOLS%\prnport.vbs -s print-cl-node-1 -a -r %1 -h %1.common.domain -t -o raw -me cscript /nologo %PRTOOLS%\prnmngr.vbs -s print-cl-node-1 -a -p %1 -m %2 -r %1 cscript /nologo %PRTOOLS%\prncnfg.vbs -s print-cl-node-1 -t -p %1 -h %1 -l %3 -m %4 +shared %SETACL% -on \\print-cl-node-1\%1 -ot prn -actn ace -ace "n:STN-TN\%1;p:man_docs,print"  %PRNBRM% -b -nobin -s print-cl-node-1 -f temp.printerexport %PRNBRM% -r -d printerexport -f temp.printerexport  del /f /q temp.printerexport del /s /f /q printerexport\LMONS printerexport\PRTPROCS echo ^<SpoolerAttrib /^>			> printerexport\BrmSpoolerAttrib.xml echo ^<PPROCS /^>					> printerexport\PProcs.xml echo ^<PRINTERDRIVERS /^>			> printerexport\BrmDrivers.xml echo ^<LMONS Arch="Windows x64"/^>	> printerexport\BRMLMons.xml  %PRNBRM% -b -d printerexport -f temp.printerexport del /s /f /q printerexport  %PRNBRM% -r -s print-cluster-1 -f temp.printerexport -p all -o force del /f /q temp.printerexport  cscript /nologo %PRTOOLS%\prnmngr.vbs -s print-cl-node-1 -d -p %1 cscript /nologo %PRTOOLS%\prnport.vbs -s print-cl-node-1 -d -r %1 
Итоговый файл Printers.xml

<?xml version="1.0" encoding="utf-8"?> <Printers clsid="{1F577D12-3D1B-471e-A1B7-060317597B9C}">   <SharedPrinter clsid="{9A5E9697-9095-436d-A0EE-4D128FDFBCE5}" name="Delete All" status="Delete All" image="3" uid="{21097DBD-285D-48C3-B042-7746D7E6DA1B}" bypassErrors="1" disabled="1">     <Properties action="D" path="" default="0" deleteAll="1" port="" />     <Filters>       <FilterRunOnce id="{F2537B78-C7D7-43DF-98D6-B32E90644825}" hidden="1" not="0" bool="AND" />     </Filters>   </SharedPrinter>   <SharedPrinter clsid="{9A5E9697-9095-436d-A0EE-4D128FDFBCE5}" name="PRN-BARAB-061" status="PRN-BARAB-061" image="2" uid="{43231EA0-A4A3-4F1A-8A25-95BC4FEFBCC6}" userContext="1" bypassErrors="1">     <Properties action="U" comment="" path="\\print-cluster-1.common.domain\PRN-BARAB-061" default="0" port="" />     <Filters>       <FilterGroup bool="AND" not="0" name="COMDOM\PRN-BARAB-061" sid="" userContext="1" />       <FilterIpRange bool="AND" not="0" min="192.168.142.1" max="192.168.142.254" />     </Filters>   </SharedPrinter>   <SharedPrinter clsid="{9A5E9697-9095-436d-A0EE-4D128FDFBCE5}" name="PRN-BARAB-061" status="PRN-BARAB-061" image="3" uid="{43231EA0-A4A3-4F1A-8A25-95BC4FEFBCC6}" userContext="1" bypassErrors="1">     <Properties action="D" comment="" path="\\print-cluster-1.common.domain\PRN-BARAB-061" default="0" port="" />     <Filters>       <FilterGroup bool="AND" not="1" name="COMDOM\PRN-BARAB-061" sid="" userContext="1" />       <FilterIpRange bool="OR" not="1" min="192.168.142.1" max="192.168.142.254" />     </Filters>   </SharedPrinter>   <SharedPrinter clsid="{9A5E9697-9095-436d-A0EE-4D128FDFBCE5}" name="PRN-BATAY-042" status="PRN-BATAY-042" image="2" uid="{4740604B-C403-4511-91B0-689A197260F3}" userContext="1" bypassErrors="1">     <Properties action="U" comment="" path="\\print-cluster-1.common.domain\PRN-BATAY-042" default="0" port="" />     <Filters>       <FilterGroup bool="AND" not="0" name="COMDOM\PRN-BATAY-042" sid="" userContext="1" />       <FilterIpRange bool="AND" not="0" min="192.168.128.1" max="192.168.129.254" />     </Filters>   </SharedPrinter>   <SharedPrinter clsid="{9A5E9697-9095-436d-A0EE-4D128FDFBCE5}" name="PRN-BATAY-042" status="PRN-BATAY-042" image="3" uid="{4740604B-C403-4511-91B0-689A197260F3}" userContext="1" bypassErrors="1">     <Properties action="D" comment="" path="\\print-cluster-1.common.domain\PRN-BATAY-042" default="0" port="" />     <Filters>       <FilterGroup bool="AND" not="1" name="COMDOM\PRN-BATAY-042" sid="" userContext="1" />       <FilterIpRange bool="OR" not="1" min="192.168.128.1" max="192.168.129.254" />     </Filters>   </SharedPrinter>   <SharedPrinter clsid="{9A5E9697-9095-436d-A0EE-4D128FDFBCE5}" name="PRN-BUY---001" status="PRN-BUY---001" image="2" uid="{457DB3FE-E35F-450E-B1D6-912F0D831573}" userContext="1" bypassErrors="1">     <Properties action="U" comment="" path="\\print-cluster-1.common.domain\PRN-BUY---001" default="0" port="" />     <Filters>       <FilterGroup bool="AND" not="0" name="COMDOM\PRN-BUY---001" sid="" userContext="1" />       <FilterIpRange bool="AND" not="0" min="192.168.44.1" max="192.168.44.254" />     </Filters>   </SharedPrinter>   <SharedPrinter clsid="{9A5E9697-9095-436d-A0EE-4D128FDFBCE5}" name="PRN-BUY---001" status="PRN-BUY---001" image="3" uid="{457DB3FE-E35F-450E-B1D6-912F0D831573}" userContext="1" bypassErrors="1">     <Properties action="D" comment="" path="\\print-cluster-1.common.domain\PRN-BUY---001" default="0" port="" />     <Filters>       <FilterGroup bool="AND" not="1" name="COMDOM\PRN-BUY---001" sid="" userContext="1" />       <FilterIpRange bool="OR" not="1" min="192.168.44.1" max="192.168.44.254" />     </Filters>   </SharedPrinter>   <SharedPrinter clsid="{9A5E9697-9095-436d-A0EE-4D128FDFBCE5}" name="PRN-ELAB-064" status="PRN-ELAB-064" image="2" uid="{52069D45-EF86-442D-A157-368D7510A1CF}" userContext="1" bypassErrors="1">     <Properties action="U" comment="" path="\\print-cluster-1.common.domain\PRN-ELAB-064" default="0" port="" />     <Filters>       <FilterIpRange bool="AND" not="0" min="192.168.140.1" max="192.168.140.254" />     </Filters>   </SharedPrinter>   <SharedPrinter clsid="{9A5E9697-9095-436d-A0EE-4D128FDFBCE5}" name="PRN-ELAB-064" status="PRN-ELAB-064" image="3" uid="{52069D45-EF86-442D-A157-368D7510A1CF}" userContext="1" bypassErrors="1">     <Properties action="D" comment="" path="\\print-cluster-1.common.domain\PRN-ELAB-064" default="0" port="" />     <Filters>       <FilterIpRange bool="AND" not="1" min="192.168.140.1" max="192.168.140.254" />     </Filters>   </SharedPrinter>   <SharedPrinter clsid="{9A5E9697-9095-436d-A0EE-4D128FDFBCE5}" name="PRN-EMPTY-002" status="PRN-EMPTY-002" image="2" uid="{475578CB-689F-463B-9710-AE207973146C}" userContext="1" bypassErrors="1">     <Properties action="U" comment="" path="\\print-cluster-1.common.domain\PRN-EMPTY-002" default="0" port="" />     <Filters>       <FilterGroup bool="AND" not="0" name="COMDOM\PRN-EMPTY-002" sid="" userContext="1" />       <FilterIpRange bool="AND" not="0" min="192.168.199.1" max="192.168.199.254" />     </Filters>   </SharedPrinter>   <SharedPrinter clsid="{9A5E9697-9095-436d-A0EE-4D128FDFBCE5}" name="PRN-EMPTY-002" status="PRN-EMPTY-002" image="3" uid="{475578CB-689F-463B-9710-AE207973146C}" userContext="1" bypassErrors="1">     <Properties action="D" comment="" path="\\print-cluster-1.common.domain\PRN-EMPTY-002" default="0" port="" />     <Filters>       <FilterGroup bool="AND" not="1" name="COMDOM\PRN-EMPTY-002" sid="" userContext="1" />       <FilterIpRange bool="OR" not="1" min="192.168.199.1" max="192.168.199.254" />     </Filters>   </SharedPrinter>   <SharedPrinter clsid="{9A5E9697-9095-436d-A0EE-4D128FDFBCE5}" name="PRN-KIRILL-081" status="PRN-KIRILL-081" image="2" uid="{421FC2DE-2E97-49FC-AEB0-3070B0166AD5}" userContext="1" bypassErrors="1">     <Properties action="U" comment="" path="\\print-cluster-1.common.domain\PRN-KIRILL-081" default="0" port="" />     <Filters>       <FilterIpRange bool="AND" not="0" min="192.168.196.1" max="192.168.196.254" />     </Filters>   </SharedPrinter>   <SharedPrinter clsid="{9A5E9697-9095-436d-A0EE-4D128FDFBCE5}" name="PRN-KIRILL-081" status="PRN-KIRILL-081" image="3" uid="{421FC2DE-2E97-49FC-AEB0-3070B0166AD5}" userContext="1" bypassErrors="1">     <Properties action="D" comment="" path="\\print-cluster-1.common.domain\PRN-KIRILL-081" default="0" port="" />     <Filters>       <FilterIpRange bool="AND" not="1" min="192.168.196.1" max="192.168.196.254" />     </Filters>   </SharedPrinter>   <SharedPrinter clsid="{9A5E9697-9095-436d-A0EE-4D128FDFBCE5}" name="PRN-KOTOV-013" status="PRN-KOTOV-013" image="2" uid="{4DFFBA1F-48D2-4824-B2EB-0AAD12B6A9D6}" userContext="1" bypassErrors="1">     <Properties action="U" comment="" path="\\print-cluster-1.common.domain\PRN-KOTOV-013" default="0" port="" />     <Filters>       <FilterGroup bool="AND" not="0" name="COMDOM\PRN-KOTOV-013" sid="" userContext="1" />       <FilterIpRange bool="AND" not="0" min="192.168.128.1" max="192.168.129.254" />     </Filters>   </SharedPrinter>   <SharedPrinter clsid="{9A5E9697-9095-436d-A0EE-4D128FDFBCE5}" name="PRN-KOTOV-013" status="PRN-KOTOV-013" image="3" uid="{4DFFBA1F-48D2-4824-B2EB-0AAD12B6A9D6}" userContext="1" bypassErrors="1">     <Properties action="D" comment="" path="\\print-cluster-1.common.domain\PRN-KOTOV-013" default="0" port="" />     <Filters>       <FilterGroup bool="AND" not="1" name="COMDOM\PRN-KOTOV-013" sid="" userContext="1" />       <FilterIpRange bool="OR" not="1" min="192.168.128.1" max="192.168.129.254" />     </Filters>   </SharedPrinter>   <SharedPrinter clsid="{9A5E9697-9095-436d-A0EE-4D128FDFBCE5}" name="PRN-LIPKI-003" status="PRN-LIPKI-003" image="2" uid="{4794D22E-6586-4A81-A85D-A21FB8B209CF}" userContext="1" bypassErrors="1">     <Properties action="U" comment="" path="\\print-cluster-1.common.domain\PRN-LIPKI-003" default="0" port="" />     <Filters>       <FilterIpRange bool="AND" not="0" min="192.168.44.1" max="192.168.44.254" />     </Filters>   </SharedPrinter>   <SharedPrinter clsid="{9A5E9697-9095-436d-A0EE-4D128FDFBCE5}" name="PRN-LIPKI-003" status="PRN-LIPKI-003" image="3" uid="{4794D22E-6586-4A81-A85D-A21FB8B209CF}" userContext="1" bypassErrors="1">     <Properties action="D" comment="" path="\\print-cluster-1.common.domain\PRN-LIPKI-003" default="0" port="" />     <Filters>       <FilterIpRange bool="AND" not="1" min="192.168.44.1" max="192.168.44.254" />     </Filters>   </SharedPrinter>   <SharedPrinter clsid="{9A5E9697-9095-436d-A0EE-4D128FDFBCE5}" name="PRN-NALTA-028" status="PRN-NALTA-028" image="2" uid="{35F6CF36-2A24-4A81-B061-8BE71CEC27EA}" userContext="1" bypassErrors="1">     <Properties action="U" comment="" path="\\print-cluster-1.common.domain\PRN-NALTA-028" default="0" port="" />     <Filters>       <FilterGroup bool="AND" not="0" name="COMDOM\PRN-NALTA-028" sid="" userContext="1" />       <FilterIpRange bool="AND" not="0" min="192.168.192.1" max="192.168.192.254" />     </Filters>   </SharedPrinter>   <SharedPrinter clsid="{9A5E9697-9095-436d-A0EE-4D128FDFBCE5}" name="PRN-NALTA-028" status="PRN-NALTA-028" image="3" uid="{35F6CF36-2A24-4A81-B061-8BE71CEC27EA}" userContext="1" bypassErrors="1">     <Properties action="D" comment="" path="\\print-cluster-1.common.domain\PRN-NALTA-028" default="0" port="" />     <Filters>       <FilterGroup bool="AND" not="1" name="COMDOM\PRN-NALTA-028" sid="" userContext="1" />       <FilterIpRange bool="OR" not="1" min="192.168.192.1" max="192.168.192.254" />     </Filters>   </SharedPrinter>   <SharedPrinter clsid="{9A5E9697-9095-436d-A0EE-4D128FDFBCE5}" name="PRN-PYSHM-004" status="PRN-PYSHM-004" image="2" uid="{45509B48-E7BC-4497-9665-86D4E1E96FE1}" userContext="1" bypassErrors="1">     <Properties action="U" comment="" path="\\print-cluster-1.common.domain\PRN-PYSHM-004" default="0" port="" />     <Filters>       <FilterIpRange bool="AND" not="0" min="192.168.143.1" max="192.168.143.254" />     </Filters>   </SharedPrinter>   <SharedPrinter clsid="{9A5E9697-9095-436d-A0EE-4D128FDFBCE5}" name="PRN-PYSHM-004" status="PRN-PYSHM-004" image="3" uid="{45509B48-E7BC-4497-9665-86D4E1E96FE1}" userContext="1" bypassErrors="1">     <Properties action="D" comment="" path="\\print-cluster-1.common.domain\PRN-PYSHM-004" default="0" port="" />     <Filters>       <FilterIpRange bool="AND" not="1" min="192.168.143.1" max="192.168.143.254" />     </Filters>   </SharedPrinter>   <SharedPrinter clsid="{9A5E9697-9095-436d-A0EE-4D128FDFBCE5}" name="PRN-TARUS-002" status="PRN-TARUS-002" image="2" uid="{398F4A94-530C-4E3B-8A30-4288D5E8854D}" userContext="1" bypassErrors="1">     <Properties action="U" comment="" path="\\print-cluster-1.common.domain\PRN-TARUS-002" default="0" port="" />     <Filters>       <FilterGroup bool="AND" not="0" name="COMDOM\PRN-TARUS-002" sid="" userContext="1" />       <FilterIpRange bool="AND" not="0" min="192.168.128.1" max="192.168.129.254" />     </Filters>   </SharedPrinter>   <SharedPrinter clsid="{9A5E9697-9095-436d-A0EE-4D128FDFBCE5}" name="PRN-TARUS-002" status="PRN-TARUS-002" image="3" uid="{398F4A94-530C-4E3B-8A30-4288D5E8854D}" userContext="1" bypassErrors="1">     <Properties action="D" comment="" path="\\print-cluster-1.common.domain\PRN-TARUS-002" default="0" port="" />     <Filters>       <FilterGroup bool="AND" not="1" name="COMDOM\PRN-TARUS-002" sid="" userContext="1" />       <FilterIpRange bool="OR" not="1" min="192.168.128.1" max="192.168.129.254" />     </Filters>   </SharedPrinter> </Printers> 
Результат на сервере печати

image
FavoriteLoadingДобавить в избранное
Posted in Без рубрики

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *