Рубрика:
Администрирование /
Серверная
|
Facebook
Мой мир
Вконтакте
Одноклассники
Google+
|
ИВАН КОРОБКО
Управление сетевой печатью в Windows 2000 Часть 2
В предыдущей статье был описан процесс установки и настройки сетевого принтера в домене Windows. Эта статья посвящена созданию сценария регистрации пользователей в сети, который будет автоматически управлять подключением и отключением сетевых принтеров.
Сценарий регистрации пользователей в сети
Основной задачей скрипта является автоматизация процессов, связанных с подключением рабочих станций к сети, уменьшения затрат на администрирование и конфигурирование рабочих станций.
Перечислим некоторые задачи, которые могут быть решены с помощью сценария загрузки:
- Инвентаризация. Включает в себя сбор информации о регистрирующемся в сети пользователе, рабочей станции и формирование файла отчета.
- Автоматическое подключение сетевых ресурсов: принтеров и дисков.
- Автоматическое конфигурирование рабочих станций.
- Обеспечение интерактивности работы скрипта. В ходе выполнения скрипта на экране отображается соответствующая информация. После его выполнения пользователь может ознакомиться с подключенными к нему ресурсами, информацией о его рабочей станции и т. д.
Из всех этих языков рекомендуется остановить свой выбор на языке KIXtart (http://kixtart.org), поскольку, обладая огромными возможностями, он распространяется бесплатно. Это интерпретируемый язык программирования, разработанный в 1991 году для создания сценариев загрузки. Простота, скорость и отсутствие конкурентов быстро сделали его популярным среди администраторов. KIXtart является бесплатным и поставляется вместе с Microsoft Resoure Kit. В настоящее время используется KIXtart ver 4.2х, который поддерживается Microsoft Windows Server 2003, XP, 2000, NT 3.x/4.x, 95, 98, Millennium. KIXtart 4.21 поддерживает 48 команд, 56 макросов-функций, 100 функций и обладает следующим функционалом:
- вывод информации в виде диалоговых сообщений;
- подключение сетевых ресурсов;
- чтение информации из входного потока;
- расширенная поддержка редактирования реестра;
- поддержка INI-файлов;
- расширенная поддержка операций со строками и массивами;
- сбор информации о пользователе и рабочей станции;
- поддержка OLE-объектов;
- операции с файлами и каталогами;
- создание ярлыков Windows.
В данной статье рассмотрен лишь небольшой фрагмент скрипта, обеспечивающий автоматизированное управление сетевыми принтерами. Рассмотрим основные принципы его работы.
Соглашение об именах
Имя должно содержать как можно больше информации о принтере, при этом быть удобным для использования. На рабочих станциях под управлением операционной системы Windows пользователь имеет дело с двумя именами – именем принтера и его сетевым именем. Имя принтера – это имя, назначаемое принтеру во время установки. Его длина ограничивается 220 символами. Сетевое имя назначается принтеру для использования устройства в сети. Максимальная длина сетевого имени составляет 80 символов, хотя его не рекомендуется делать длиннее 8 символов для обеспечения совместимости с клиентами MS-DOS и Windows 3.x. Существует еще одно ограничение: некоторые приложения не могут работать с принтерами, у которых полное составное имя (имя компьютера, объединенное с сетевым именем принтера по шаблону Server ShareName) длиннее 31 символа.
Чаще всего имя, назначаемое принтеру, представляет собой реальное имя принтера с порядковым номером, если есть несколько принтеров одинаковой модели, например, HP LaserJet 1200 (1), HP LaserJet 2300 (2). Такой способ именования рекомендуется использовать в небольших организациях. В крупных корпорациях принцип именования принтеров может быть другим. Например, названия могут быть даны по именам отделов и офисов, где территориально находится принтер, скажем, «Краснодар ОКС» или «Ростов АТС-34».
Сетевое имя, как отмечено ранее, должно быть более коротким, но при этом не должно терять смысловой нагрузки. Оно чаще всего представляет собой общую характеристику принтера, например HP1200_1, HP2300_2.
Предварительная настройка принтера и AD
Работа сценария строится на анализе и обработке данных, содержащихся в Active Directory и пользовательском реестре. На основе полученных данных осуществляется подключение и отключение принтера в зависимости от членства пользователя в соответствующих группах безопасности. Для того чтобы сценарий мог считывать и сопоставлять полученные данные из Active Directory, необходимо одновременное выполнение нескольких условий.
Первое условие – названия принтеров, групп безопасности должны удовлетворять соглашению об именах.
Второе – сетевые принтеры, подключением и отключением которых должен управлять скрипт, должны быть опубликованы в Active Directory.
Третье – названия групп безопасности должны строиться в соответствии со следующим шаблоном: название одной из групп, члены которой могут только выводить задания на печать, образуется добавлением к сетевому имени принтера через дефис слова Print, например, «HP2300_1 – Print». Название другой группы строится аналогично, с той разницей, что слово «Print» заменяют на словосочетание «Print Managers». Члены этой группы могут управлять очередью печати и принтером. Таким образом, принтеру с сетевым именем «HP1200_1» соответствуют следующие названия групп: имя первой группы «HP1200_1 – Print», второй «HP1200_1 – Print Managers» (см. рис. 1).
Четвертое – должны быть определены параметры безопасности принтера. В свойствах принтера (см. рис. 2) на сервере печати во вкладке «Security» (безопасность) должна быть удалена группа «Everyone» (в противном случае скрипт будет подключать этот принтер всем пользователям сети) и добавлены две группы безопасности, соответствующие данному принтеру: «HP1200_1 – Print» и «HP1200_1 – Print Managers». Для группы «HP1200_1 – Print» должен быть установлен в разделе «Permissions» (разрешения) флажок напротив свойства «Print» (см. рис. 2), а для группы «HP1200_1 – Print Managers» – флажки напротив «Print» (печать) и «Manage Documents» (управление документами). Ставить флажок напротив «Manage Printers» не рекомендуется, поскольку управление принтерами подразумевает возможность изменять настройки принтера, удалять его. По мнению автора, такими привилегиями может обладать только системный администратор.
Рисунок 1
Рисунок 2
Итак, работа сценария строится на анализе данных, содержащихся в Active Directory и пользовательском реестре. Его работу можно разбить на три этапа.
На первом этапе формируется список принтеров, которые должны быть подключены пользователю. На втором этапе – список сетевых принтеров, уже установленных на рабочей станции пользователя.Наконец, на третьем – осуществляется приведение этих списков в соответствие.
Этап 1. Формирование списка принтеров, которые необходимо подключить пользователю
Определение имени текущего домена
Имя текущего домена определяется с помощью функции GetObject(). Используя функцию GetObject(), осуществляется чтение корня пространства имен, в данном случае текущего домена.
Пример определения текущего домена:
$rootDSE_ = GetObject("LDAP://RootDSE")
$domain_ = "LDAP://" + $rootDSE_.Get("defaultNamingContext")
Переменная domain_ имеет вид «dc=microsoft,dc=com», если домен «microsoft.com».
Имя текущего домена, полученного с помощью провайдера WinNT, нельзя использовать, поскольку с помощью него можно получить только сокращенное имя домена (в данном случае «microsoft»). В том случае если все же указано сокращенное имя домена в строке с SQL-запросом, то при выполнении скрипта произойдет ошибка. В сообщении о ней будет сказано, что по указанному пути база не обнаружена, поэтому установить с ней соединение невозможно.
Построение запроса SQL
Запрос SQL используется для осуществления процедуры поиска объектов при заданном типе объекта. В общем случае запрос SQL выглядит следующим образом:
SELECT поле_1, поле_2, …, поле_n FROM “LDAP://dc=домен_1,dc=домен_2…,domen_n” WHERE objectClass=’тип_объекта’
В разделе SELECT указываются поля, по которым идет выборка. Поля перечисляются через запятую, «пробелы» после запятой обязательны. Полный список полей объектов AD можно получить с помощью утилиты ADSI Edit, которая размещается в дистрибутиве Microsoft Windows 2000 в директории /Support/Tools (см. статью «Программное управление ADSI: LDAP» в журнале «Системный Администратор», №3(16) март 2004 г.).
В разделе FROM указывается путь к объекту. В данном случае известен только домен. При описании данного раздела пробелы не допускаются.
В разделе WHERE указывается тип объекта, к которому адресован запрос. Данное поле является фильтром. Провайдер LDAP поддерживает несколько типов объектов, которые в запросе SQL определяются переменной objectClass: PrintQueue – массив принтеров, опубликованных в AD; Group – группы, созданные в AD; User – пользователи, созданные в AD; Computer – массив компьютеров, зарегистрированных в AD. Пример использования запроса SQL см. в разделе «Поиск опубликованных принтеров в AD».
Поиск опубликованных принтеров в AD
Поиск объектов в Active Directory с помощью провайдера LDAP реализуется через ADODB-соединение. После создания соединения формируется SQL-запрос и осуществляется поиск по заданным критериям. Результатом поиска является массив, который содержит значения полей, которые указаны в параметре SELECT SQL-запроса. Затем происходит вывод данных на экран. В приведенном примере осуществляется поиск всех опубликованных принтеров в текущем домене и вывод на экран названия принтера, его сетевого имени (ShareName):
$strADSQuery = "SELECT shortservername, portname,
$objConnection = CreateObject("ADODB.Connection")
$objCommand = CreateObject("ADODB.Command")
$objConnection.CommandTimeout = 120
$objConnection.Provider = "ADsDSOObject"
$objConnection.Open ("Active Directory Provider")
$objCommand.ActiveConnection = $objConnection
$objCommand.CommandText = $strADSQuery
$st = $objCommand.Execute
$st.Movefirst
$i=0
Do
$server_enum=""
$name_enum=""
$shares_enum=""
$server_enum = $St.Fields("shortservername").Value
$name_enum = $St.Fields("printername").Value
$shares=$St.Fields("printsharename").Value
for each $share in $shares
$shares_enum = $shares_enum + $share
next
for each $desc in $descrs
Next
$st.MoveNext
MessageBox($temp,"Характеристики принтера",0,0)
$temp=""
Until $st.EOF
В Active Directory объектом класса printQueue является принтер. Этот объект имеет свойства, значение которых может быть двух типов: строкой и массивом. В приведенном примере поле, содержащее название принтера, является строковой переменной, а сетевое имя принтера – массивом.
Ниже приведена таблица, содержащая названия и описания часто используемых полей, соответствующий им тип и формат данных:
Таблица 1
Поле |
Описание |
Тип |
Пример |
|
Описание принтера |
Array |
Принтер формата А4 |
Location |
Физическое место размещения принтера |
String |
2 эт., 10 комн. |
PrinterName |
То же, что и Name |
String |
PrinterName |
PrintShareName |
Имя принтера для подключение |
Array |
Printer |
ServerName |
Полное имя сервера, к которому подключен принтер |
String |
Server.Domain.Ru |
ShortServerName |
Краткое имя cервера |
String |
Server |
Формирование массива
После того как в Active Directory найден очередной опубликованный принтер и прочитаны его свойства, для него формируется UNC-путь (serversharename). Затем осуществляется попытка подключить пользователю принтер и считывать код функции, производящей подключение.
Если функция подключения возвращает код ошибки 0 (подключение к принтеру прошло успешно), то пользователь является членом одной из двух групп безопасности, перечисленных в свойствах принтера на сервере печати. Для тех принтеров, на которые пользователь имеет право печатать (как минимум), формируется массив, например $access_array[$i]. Формат элементов массива следующий: «,,server,printername», где server – короткое имя сервера, printername – локальное имя принтера.
$path_enum_connect = "" + $server_enum + "" + $shares_enum
$connect_flag = addprinterconnection( $path_enum_connect )
if $connect_flag=0
$path_full =",," + $server_enum + "," + $name_enum
$access_array[$i] = lcase($path_full)
$i=$i+1
Endif
Этап 2. Формирование списка сетевых принтеров, подключенных пользователю
Процесс определения подключенных пользователю сетевых принтеров основан на анализе ветви HKCU локального реестра (см. рис.3).
Рисунок 3
С помощью функции ENUM осуществляется чтение названий папок, содержащих в себе короткое имя сервера и полное имя принтера. На основе полученной информации формируется массив, элементами которого являются строки, имеющие следующий формат: «,,server,printername», где server – короткое имя сервера, printername – локальное имя принтера. Для удобства сравнения обоих массивов (подключенных принтеров и принтеров, на которые пользователь имеет права) необходимо, чтобы форматы элементов массивов совпадали. Формат элементов продиктован особенностью построения реестра Windows 2000 (см. рис. 3).
$Index=0
DO
$connected_array[$index]= lcase(ENUMKEY("HKEY_CURRENT_USERPrintersConnections", $Index))
$Index = $Index + 1
UNTIL Len($Group) =0
Необходимо отметить, что после формирования второго массива между ними соблюдаются следующее неравенство: М2 і М1, где М2 – массив, элементами которого являются названия подключенных принтеров, M1 – принтеров, на которые пользователь имеет права. На третьем, заключительном, этапе добиваются выполнения следующего условия: М1 = М2.
Этап 3. Приведение созданных списков принтеров в соответствие
Сопоставление массивов М1 и М2 осуществляется с помощью функции ASCAN. В том случае если функция возвращает значение -1, то элемент, найденный в одном массиве, не является элементом другого. Поэтому принтер, соответствующий этому элементу, должен быть отключен.
for $i=0 to ubound($connected_array)
$flag_p=0
$flag_p=Ascan($access_array,$connected_array[$i])
if $flag_p=-1
………..
endif
next
Удаление принтера осуществляется с помощью соответствующей функции, параметром которой является UNC-путь принтера. Для того чтобы сформировать этот путь, осуществляется анализ ветви HKLM (см. рис. 4):
if $flag_p=-1
$group=$connected_array[$i]
$name_=right($group, len($group)-instrrev($group,","))
$server_=right(left($group,len($group)-len($name_)-1), len(left($group,len($group)-len($name_)-1))-2)
$share_=readvalue("HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindows NTCurrentVersionPrintProvidersLanMan Print ServicesServers"+$server_+"Printers "+$name_,"Share Name")
$disconnect_ =""+$server_+""+$share_
$r=DelPrinterConnection( $disconnect_ )
endif
Полный синтаксис скрипта приведен в «Приложении 1».
Рисунок 4
Внедрение скрипта в эксплуатацию
Скрипт выполняется каждый раз при регистрации пользователя в сети, если он указан в разделе Profile свойствах пользователя (см. рис. 5) службы Active Directory: Users and Computers.
Рисунок 5
Описанный скрипт не будет работать под Windows 9x, поскольку Windows 2k и Windows 9x обладают различными системами печати. Однако, поскольку данный скрипт является частью большого скрипта, рассмотрим случай, в котором в сети присутствуют рабочие станции под управлением и Windows 9x, и Windows 2k. Следует отметить, что для работы KIXtart под Windows 9х необходимо наличие нескольких файлов на жестком диске рабочей станции в каталоге WindowsSystem.
Для автоматизации установки KIXtart на рабочих станциях домена предлагается следующее: в папку Netlogon поместить файлы:
- KIX32.EXE;
- SCRIPT.KIX;
- START.BAT;
- Подкаталог Win9x, содержит файлы KX16.DLL и KX32.DLL.
В ходе выполнения файла START.BAT определяется тип операционной системы, установленной на рабочей станции, и запускает скрипт. В зависимости от версии ОС происходит копирование файлов, необходимых для поддержки KIX этой операционной системой.
Листинг файла start.bat
@ECHO OFF
if c:\%os%==c:\ goto win9x
if not c:\%os%==c:\ goto winnt
:winnt
start /wait Kix32.exe Script.kix
goto kix
:win9x
copy %0\..\win9x\*.dll c:\windows\system /y
%0\..\Kix32.exe %0\..\Script.kix
goto kix
:kix
@echo End Of Batch File
le
Пояснения к синтаксису файла START.BAT:
- Принцип определения операционной системы основан на том, что в Windows 9x отсутствует переменная окружения %os%; в Windows 2k переменная %os%=WindowsNT.
- С помощью строки «start /wait Kix32.exe Script.kix2 добиваются последовательной загрузки – сначала скрипт, затем рабочий стол и т. д., а не одновременной. То есть во время выполнения скрипта многозадачность «отключается».
- Это делается для того, чтобы до окончания действия скрипта дальнейшая загрузка операционной системы не производилась.
- Для корректной работы Windows 9x в качестве пути к файлу необходимо указывать «%0\..\filename.ext\». Windows XP не воспринимает относительного пути «%0/./», поэтому для Windows семейства 2k необходимо указать только имя файла, который находится в папке Netlogon.
На время выполнения скрипта необходимо скрыть CMD-панель, в которой выполняется cкрипт, и приостановить загрузку рабочего стола до окончания всего скрипта. Этого результата добиваются с помощью групповой политики, распространяющейся на домен («Default Domain Controllers Policy»). В разделе групповой политики «User Configuration» необходимо соответственно включить «Run legacy logon script synhronously» (запускать сценарий загрузки синхронно) и «Run legasy script hidden» (запускать сценарий скрыто). Для этого необходимо проделать следующее:
- Зарегистрироваться на сервере с помощью учетной записи, имеющей административные права.
- Загрузить в Active Directory Users and Computers («Start –> Programs –> Administrative Tools») и войти в свойства контроллера домена (см. рис. 6).
Рисунок 6
- Перейти во вкладку «Group Policy» и загрузить «Default Dоmain Policy» (см. рис. 7).
Рисунок 7
- В загруженной групповой политике (Default Domain Policy) необходимо в «User Configuration» (настройках пользователя) войти в «Administrative Templates» (административные настройки). Там выбрать раздел «System» (система), вкладку «logon/logoff» (войти/выйти) и включить ранее оговоренные политики (см. рис. 8).
Рисунок 8
Приложение 1
Листинг сценария загрузки script.kix
$rootDSE_ = GetObject("LDAP://RootDSE")
$domain_ = "LDAP://" + $rootDSE_.Get("defaultNamingContext")
$strADSQuery = "SELECT shortservername, portname, servername, printername, printsharename, location, description FROM '" +$domain_+"' WHERE objectClass='printQueue'"
$objConnection = CreateObject("ADODB.Connection")
$objCommand = CreateObject("ADODB.Command")
$objConnection.CommandTimeout = 120
$objConnection.Provider = "ADsDSOObject"
$objConnection.Open ("Active Directory Provider")
$objCommand.ActiveConnection = $objConnection
$objCommand.CommandText = $strADSQuery
$st = $objCommand.Execute
$st.Movefirst
dim $access_array[200]
dim $connected_array[200]
$i=0
Do
$server_enum=""
$shares_enum=""
$description_enum=""
$server_enum = $St.Fields("shortservername").Value
$name_enum = $St.Fields("printername").Value
$shares=$St.Fields("printsharename").Value
for each $share in $shares
$shares_enum = $shares_enum + $share
next
$descrs=$St.Fields("description").Value
for each $desc in $descrs
$description_enum = $description_enum + $desc
next
$path_enum_connect = "\\" + $server_enum + "\" + $shares_enum
$connect_flag = addprinterconnection( $path_enum_connect )
if $connect_flag=0
$path_full =",," + $server_enum + "," + $name_enum
$print_sysinfo=$print_sysinfo+$shares_enum+":"+$description_enum+chr(13)
$access_array[$i] = lcase($path_full)
$i=$i+1
endif
$st.MoveNext
Until $st.EOF
$Index=0
DO
$connected_array[$index]= lcase(ENUMKEY("HKEY_CURRENT_USER\Printers\Connections\", $Index))
$Index = $Index + 1
UNTIL Len($Group) =0
if $i=0
redim PRESERVE $access_array[0]
else
redim PRESERVE $access_array[$i-1]
endif
if $index=1
redim PRESERVE $connected_array[0]
else
redim PRESERVE $connected_array[$index-2]
endif
for $i=0 to ubound($connected_array)
$flag_p=0
$flag_p=Ascan($access_array,$connected_array[$i])
if $flag_p=-1
$group=$connected_array[$i]
$name_=right($group, len($group)-instrrev($group,","))
$server_=right(left($group,len($group)-len($name_)-1),len(left($group,len($group)-len($name_)-1))-2)
$share_=readvalue("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Print\Providers\LanMan Print Services\Servers\"+$server_+"\Printers\ "+$name_,"Share Name")
$disconnect_ ="\\"+$server_+"\"+$share_
$r=DelPrinterConnection( $disconnect_ )
endif
next
MessageBox("Подключение сетевых принтеров завершено","",0,0)
Facebook
Мой мир
Вконтакте
Одноклассники
Google+
|