По некоторым причинам я пока не готов разговаривать об управлении безопасностью принтеров в PowerShell, поэтому продолжу начатую тему базового управления. Я обещал, что создам набор необходимых функций, для работы с принтерами и на данный момент приготовил следующие функции:
Здесь я не буду подробно описывать всё подряд, а расскажу только о тех вещах, которые считаю важными для читателя. Остальное он и сам додумает ;)
Сразу хочу оговориться, что для первых 3-х функций реализована только локальная поддержка (т.е. использовать функции по отношению к другим компьютерам нельзя). Сделано это почему: дело в том, что все WMI операции выполняются (даже на удалённых машинах) в контексте того пользователя, который запустил скрипт. Очень сомнительный смысл мапить для себя принтер на другой машине. Ко всему прочему в классе Win32_Printer не реализована даже поддержка удалённого маппинга принтера. Сейчас я это продемонстрирую:
В классе Win32_Printer есть замечательный метод AddPrinterConnection, который подключает сетевой принтер к пользователю. Если в MSDN написано, что он есть, значит таконо и есть. Посмотрим:
[vPodans] gwmi Win32_Printer | gm -membertype method TypeName: System.Management.ManagementObject#root\cimv2\Win32_Printer Name MemberType Definition ---- ---------- ---------- CancelAllJobs Method System.Management.ManagementBaseObject CancelAllJobs() GetSecurityDescriptor Method System.Management.ManagementBaseObject GetSecurityDescriptor() Pause Method System.Management.ManagementBaseObject Pause() PrintTestPage Method System.Management.ManagementBaseObject PrintTestPage() RenamePrinter Method System.Management.ManagementBaseObject RenamePrinter(System.String NewPrinterName) Reset Method System.Management.ManagementBaseObject Reset() Resume Method System.Management.ManagementBaseObject Resume() SetDefaultPrinter Method System.Management.ManagementBaseObject SetDefaultPrinter() SetPowerState Method System.Management.ManagementBaseObject SetPowerState(System.UInt16 PowerState, Syst... SetSecurityDescriptor Method System.Management.ManagementBaseObject SetSecurityDescriptor(System.Management.Mana... [vPodans]
Здесь я выбрал список методов объекта Win32_Printer. Но метода AddPrinterConnection мы там не наблюдаем! Почему? А всё потому, что ни один объект Win32_Printer не содержит данный метод! Метод AddPrinterConnection есть только внутри самого класса Win32_Printer и ни одним объектом не наследуется. Чтобы убедиться в этом, я вызову новый инстанс класса (не существующего объекта) и просмотрю его методы:
[vPodans] [wmiClass]'Win32_Printer' | gm -membertype method TypeName: System.Management.ManagementClass#ROOT\cimv2\Win32_Printer Name MemberType Definition ---- ---------- ---------- AddPrinterConnection Method System.Management.ManagementBaseObject AddPrinterConnection(System.String Name) [vPodans]
Вуаля, вот и наш метод! Ещё раз обратите внимание, что в первом случае я просматривал методы существующего объекта Win32_Printer, во втором же случае я просмотрел методы самого класса и увидел искомый метод. В принципе, можно создать новый инстанс класса на удалённой машине, но я, всё же, не вижу в этом реальной необходимости, поэтому я решил оставить это всё как есть. У кого энтузиазма больше - может поупражняться в этом.
Что касается удаления примапленного принтера, то я рассказывал об этом в первой части. Чтобы не было вопросов, откуда взялся метод Delete, которого мы здесь не увидели (а так же не увидим на сайте MSDN), то сразу отвечу, что это не чистый метод, а скриптметод. Его можно найти, выполнив лишь команду:
gwmi Win32_Printer | gm -membertype scriptmethod
И там он будет. Поехали дальше. Что касается расшаривания принтера для предоставления общего доступа и его отмены. Мы не имеем ни единого метода или скриптметода, который бы это делал. Но если ещё раз и внимательно изучить класс Win32_Printer на MSDN (ещё раз даю ссылку), то можно заметить, что некоторые свойства объектов имеют Access Type: Read/Write. Именно этим мы и воспользуется:
[System32] (gwmi Win32_Printer -Filter "name='CutePDF Writer'").shared False [System32] $a = gwmi Win32_Printer -Filter "name='CutePDF Writer'" [System32] $a.shared = $True [System32] $a.put() Path : \\localhost\root\cimv2:Win32_Printer.DeviceID="CutePDF Writer" RelativePath : Win32_Printer.DeviceID="CutePDF Writer" Server : localhost NamespacePath : root\cimv2 ClassName : Win32_Printer IsClass : False IsInstance : True IsSingleton : False [System32] (gwmi Win32_Printer -Filter "name='CutePDF Writer'").shared True [System32]
Итак, что же я сделал. Первой строкой я просмотрел свойство Shared для принтера CutePDF Writer и получил его значение - False. Это значит, что принтер просто локальный и не предоставлен в общий доступ. Далее, я изменил свойство Shared на True, предоставив его в общий доступ. Но это я только изменил свойство в переменной $a, но не в самом объекте. Чтобы записать изменения в объект я выполняю скриптметод put() и изменения уже записываются в сам объект принтера. Для верности я снова просмотрел свойство Shared и увидел мои изменения (вместо False получил True), т.е. принтер расшарился. Отмена предоставления принтера в общий доступ делается с точностью наоборот, а именно - свойство Shared выставляется обратно в False и изменения записываются командой put().
При первом расшаривании принтера, кроме свойства Shared следует заполнить свойство ShareName, под которым он будет виден в сети. Так же выставив свойство Published в True мы можем опубликовать принтер в службе Active Directory.
На основе вышеизложенного материала напишем 6 несложных функций, которые обеспечивают базовый (это далеко не всё, что мы можем сделать с классом Win32_Printer) функционал по управлению принтерами:
######################################################## # BasicPrinterUtils.ps1 # Version 1.0 # # Functions for basic printer management # # Vadims Podans (c) 2008 # http://www.sysadmins.lv/ ######################################################## function New-NetworkPrinter ($computer, $name) { ([wmiclass]'Win32_Printer').AddPrinterConnection("\\$computer\$name") } function Remove-NetworkPrinter ($name) { if ($name) { (gwmi Win32_Printer -Filter "sharename='$name'").delete() } else { (gwmi Win32_Printer -Filter "local='$false'").delete() } } function Set-DefaultPrinter ($name) { if (!$name) { Write-Host "Не указано имя принтера. Операция прервана" } else { $internal = gwmi win32_Printer -Filter "name='$name'" $internal.setdefaultprinter() } } function Get-Printer ($computer, $name, $full) { $internal = gwmi Win32_Printer -ComputerName $computer -Filter "name='$name'" # здесь я предлагаю получить как полный набор свойств, так и упрощённый вывод сведений. if ($full) {$internal | select *} else {Write-Host $internal} } function New-PrinterShare ($computer, $name, $ShareName) { $internal = gwmi win32_Printer -ComputerName $computer -Filter "name='$name'" if ($internal) { $internal.shared = $true $internal.ShareName = $ShareName $internal.put() } else {Write-Host "Указано неверное имя принтера"} } function Remove-PrinterShare ($computer, $name) { if ($name) { $internal = gwmi Win32_Printer -Filter "name='$name'" $internal.shared = $false $internal.put() } else { gwmi Win32_Printer -Filter "shared='$true'" | %{$_.shared = $false; $_.put()} } }
Полагаю, что здесь комментировать особо нечего, т.к. тут всё очень просто и понятно. На этом пока всё. Продолжение, полагаю, следует. :)
BasicPrinterUtils.ps1 (1,6 KB)
Вадим, добрый день. Статья очень хорошая, функции полезные, но вопрос - как я понимаю все операции с принтерами выполняются в контексте текущего пользователя. А если я хочу добавить сетевой(зашаренный на другой машине) принтер конкретному пользователю? Если выполнять эи команды с параметром -Credential то будет отказ, потому что юзер которому нужно добваить принтер урезан в правах(я имею в виду что от его имени не удаться выполнить команды PoSH на удаленной машине). Есть ли какой нибудь способ получить при запросе типа get-wmi -computername comp win32_printer принтеры сеаснса другого пользователя?
Не думаю, что так получится.
Печально, недоработка)
Comments: