Contents of this directory is archived and no longer updated.

По некоторым причинам я пока не готов разговаривать об управлении безопасностью принтеров в PowerShell, поэтому продолжу начатую тему базового управления. Я обещал, что создам набор необходимых функций, для работы с принтерами и на данный момент приготовил следующие функции:

  • New-NetworkPrinter - добавляет (мапит) сетевой принтер к пользователю
  • Remove-NetworkPrinter - удаляет сетевой принтер у пользователя (удаляет только маппинг принтера)
  • Set-DefaultPrinter - устанавливает выбранный принтер принтером по умолчанию
  • Get-Printer - получение сведений о выбранном принтере. Как полный набор сведений, так и краткий
  • New-PrinterShare - расшаривает локальный принтер для общего сетевого доступа
  • Remove-PrinterShare - отменяет сетевой доступ к принтеру

Здесь я не буду подробно описывать всё подряд, а расскажу только о тех вещах, которые считаю важными для читателя. Остальное он и сам додумает ;)

Сразу хочу оговориться, что для первых 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)


Share this article:

Comments:

Степан

Вадим, добрый день. Статья очень хорошая, функции полезные, но вопрос - как я понимаю все операции с принтерами выполняются в контексте текущего пользователя. А если я хочу добавить сетевой(зашаренный на другой машине) принтер конкретному пользователю? Если выполнять эи команды с параметром -Credential то будет отказ, потому что юзер которому нужно добваить принтер урезан в правах(я имею в виду что от его имени не удаться выполнить команды PoSH на удаленной машине). Есть ли какой нибудь способ получить при запросе типа get-wmi -computername comp win32_printer принтеры сеаснса другого пользователя?

Vadims Podāns

Не думаю, что так получится.

Степан

Печально, недоработка)

Comments are closed.