Много копий сломано вокруг управления сетевыми принтерами на пользовательских компьютерах. В основном администраторы разбились на два лагеря: подключение логон-скриптами (bat/vbs) и управление через GPP. У обоих подходов есть свои плюсы: скрипты быстрее обрабатываются, а GPP гибче и применяется чаще, чем пользователи перезагружают компьютеры. Но когда принтеров больше сотни и разбросаны они в нескольких десятках офисов и городов, сложности будут в обоих случаях.
Нужно не только подключить правильный набор принтеров каждому пользователю, с учетом его текущего местонахождения, но и ни про один не забыть. А если иногда перемещаются не только пользователи, но и сами принтеры…
В общем, мы с коллегами для себя выбрали GPP, в первую очередь для того, чтобы кто-то кроме ведущих администраторов мог разобраться в действующем конфиге, просто посмотрев отчет GPMC. Однако, кто скажет, что его штатный интерфейс удобен для управления 100+ устройствами — пусть первый бросит в меня камень. Кроме того, при вводе в эксплуатацию очередной партии нужно проделать много рутины по настройке сетевого сканирования и добавлению на сервер печати.
А всё, что делается больше одного раза, можно автоматизировать!
Что мы сегодня будем делать?
- вести учет всех сетевых принтеров;
- автоматизировать добавление принтеров в GPP (PS/XML);
- автоматизировать добавление принтеров на принт-сервер, причем на кластерный (BAT/VBS)!
Итак, начнем.
1. Учет сетевых принтеров
Первая проблема, которая возникает при управлении большим количеством любых объектов — это учет. Без него легко запутаться, что где установлено и кому должно быть подключено.
Самое простое и универсальное решение — CSV. В конце концов, из любой системы инвентаризации, ServiceDesk или Excel-таблицы можно выгрузить в CSV и потом легко импортировать это в PowerShell, что мы и будем делать дальше.
У нас выгрузка выглядит вот так:
Поясню сразу, для чего столько полей:
- 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>