Архив

Архив раздела ‘Работа’

Скрипт геренации статистики squid

15 Январь 2010

Заказчик заказал чтоб логи каждый день создавалась по следующими свойству, каждые 24 часов за прошлый день и ложись в пути ${dst}/2010/01/14 и в каждого первого числа создавалась за месяц по адресу ${dst}/2010/01/month. Было принято решение написать не большой sh скрипт и поместить его в cron

#!/bin/sh
#########################################################################################
#   Created:        Zakharchenko Andrey Ruslanovich
#   Date:           2010.01.16
#   Description:    Скрипт генерации статистики squid по средствам sarg
#########################################################################################

#--- основные переменные
dst='/usr/local/www/data/stat'
sarg='/usr/local/bin/sarg'
create_dir='/bin/mkdir -p'
ddate='/bin/date'
check=0

#--- переменные для дат
current_month_number=`${ddate} "+%m"`
last_month_number=${current_month_number}

current_year_number=`${ddate} "+%y"`
last_year_number=${current_year_number}

current_day_number=`${ddate} "+%d"`
last_day_number=${current_day_number}

#--- составляем основотую команду
command="${ddate} -v${current_day_number}d -v${last_month_number}m -v${last_year_number}y -v-1d "

#--- если сегодня 2010.01.01
if ([ `${ddate} +%m`  -eq 1 ] && [ `${ddate} +%d` -eq 1 ])
then
    ${create_dir} ${dst}/`$command +%Y`/`$command +%m`/"month"
    ${sarg} -d 01/`$command +%m`/`$command +%Y`-`$command +%d`/`$command +%m`/`$command +%Y` -o ${dst}/`$command +%Y`/`$command +%m`/`$command +%d`
    ${create_dir} ${dst}/`$command +%Y`/`$command +%m`/`$command +%d`
    ${sarg} -d `$command +%d`/`$command +%m`/`$command +%Y`-`$command +%d`/`$command +%m`/`$command +%Y` -o ${dst}/`$command +%Y`/`$command +%m`/`$command +%d`
    check=1
#--- если сегодня первое число любого месяца кроме января
elif ([ `${ddate} +%d`  -eq 1 ] && [ ${check} -ne 1 ] && [ `${ddate} +%m` -ne 1 ])
then
    ${create_dir} ${dst}/`$command +%Y`/`$command +%m`/month
    ${sarg} -d 01/`$command +%m`/`$command +%Y`-`$command +%d`/`$command +%m`/`$command +%Y` -o ${dst}/`$command +%Y`/`$command +%m`/`$command +%d`
    ${create_dir} ${dst}/`$command +%Y`/`$command +%m`/`$command +%d`
    ${sarg} -d `$command +%d`/`$command +%m`/`$command +%Y`-`$command +%d`/`$command +%m`/`$command +%Y` -o ${dst}/`$command +%Y`/`$command +%m`/`$command +%d`
#--- любое число кроме 1
elif [ `${ddate} +%d` -ne 1 ]
    then
    ${create_dir} ${dst}/`$command +%Y`/`$command +%m`/`$command +%d`
    ${sarg} -d `${ddate} -v-1d +%d/%m/%Y`-`${ddate} -v-1d +%d/%m/%Y` -o ${dst}/`${command} +%Y`/`${command} +%m`/`${command} +%d`
fi

Функция для работы с MySQL

13 Январь 2010

Начнем с MySQL. С ним оказалось не все так просто. Для работы с ним необходимо на компьютер где будет работать функция/скрипт установить Connector/Net от MySQL соответствующий версии вашего сервера. Прочитав доку в общем получается одна функция для select/inserd/delete/update.

Function Connect-ToMySQL {
    param([String]$query,[String]$database,[String]$hostmysql,[String]$login,[String]$password)
#--- загрудаем компоненты mysql
    [void][system.reflection.Assembly]::LoadWithPartialName("MySql.Data")
#--- открываем подключение
    $connStr = "server=$hostmysql;port=3306;uid=$login;pwd=$password;database=$database;Pooling=False"
    $conn = New-Object MySql.Data.MySqlClient.MySqlConnection($connStr)
    $conn.Open()
#--- создаем объекты для выполнения запроса
    $cmd = New-Object MySql.Data.MySqlClient.MySqlCommand($query, $conn)
    $da = New-Object MySql.Data.MySqlClient.MySqlDataAdapter($cmd)
    $ds = New-Object System.Data.DataSet
#--- получение запроса
    $da.Fill($ds) | Out-Null
#--- ну и вывод на экран
    $ds.Tables[0]
#--- закрываем подключени
    $conn.close()
}

В итоге получаем вот такой результат:

[PS] <16> C:\Bin>$inquiry = 'SELECT  `domain-id`,username,active FROM users WHERE username="abigor@isea.ru"'
[PS] <17> C:\Bin>Connect-ToMySQL -database 'mail-server' -login 'usertest' -password 'pass' -hostmysql 'sqlsrv' -query $inquiry

domain-id   username    active
---------   --------    ------
1       abigor@isea.ru  true

[PS] <18> C:\Bin>
[PS] <18> C:\Bin>$inquiry = 'update users set active="false" WHERE username="abigor@isea.ru"'
[PS] <19> C:\Bin>Connect-ToMySQL -database 'mail-server' -login 'usertest' -password 'pass' -hostmysql 'sqlsrv' -query $inquiry

[PS] <20> C:\Bin>$inquiry = 'SELECT  `domain-id`,username,active FROM users WHERE username="abigor@isea.ru"'
[PS] <21> C:\Bin>Connect-ToMySQL -database 'mail-server' -login 'usertest' -password 'pass' -hostmysql 'sqlsrv' -query $inquiry

 domain-id  username    active
 ---------  --------    ------
 1      abigor@isea.ru  false

[PS] <22> C:\Bin>

Все бы хорошо. но есть одна проблема. Если у вас запрос в стоит в апострофе, то экранировать имена полей с дефисом надо одинарными обратным апострофом

`domain-id`

. Если же в запрос взят в кавычки, то экранировать надо двумя обратными апострофами

``domain-id``

. Понятно почему так получается. Из-за того, что все кавычки позволяют раскрыть содержимое, а все что в апострофах воспринимается как текст.

Перенос WSUS сервера на другой сервер.

9 Ноябрь 2009

Попросил меня тут товарищ развернуть сервер WSUS у него на халтуре по средством копирования скаченного контента на моей работе, так как у него трафик платный, а за раз утянуть 17-20 гигов у него нету возможности. По этому он обратился ко мне за помощью. Первой же мыслю как это не странно было зайти на technet. Там как раз оказалась дока на тему: «как провести синхронизацию между двумя WSUS серверами без сетевого подключения». В этом случаи все оказалось достаточно просто. Для этого нужно воспользоваться имеющийся в комплекте утилитой. По этому опишу ход действий:

1. cd "C:\Program Files\Update Services\Tools"
2. wsusutil.exe export export.cab export.log (Экспортирует метаданные обновления (но не файлы содержимого, одобрения
или параметры сервера) в файл экспортного пакета.)
этого пакета на другой WSUS-сервер позволяет выполнить синхронизацию
3. Создаем бекап папки где лежит сам скаченный контент
4. На новом сервере устанавливаем новый WSUS сервер, пропускаю запрос мастера на настройку.
5. Разворачиваем бекам в папку с контентом нового WSUS, не забываем поправить права если просто копировали.
6. wsusutil.exe import export.cab export.log (Импортирует метаданные обновления (но не файлы содержимого, одобрения
или параметры сервера) на этот сервер.)
7. Дальше запускаем оснастку WSUS и настраиваем что вам необходимо

Вот в общем и все. В итоге мы получили сервер скажем в филиале, где не надо скачивать по новой все 17-20 гигов обновлений.
В общем все хорошо, но тут у меня появилась мысль, а не перенести ли наш корпоративный сервер в виртуальную машину на Hyper-V раз такая пьянка пошла. Только вот не хочется опять ждать присоединения всех машин в сети и по новой тыкать одобрения. Начал по этому искать выход. Он оказался достаточно простой:

1. На новом сервере устанавливаем WSUS и так же отказываемся от мастера.
2. С помощью SQL Server Management Studio делаем бекап базы и логов на основном сервере.
3. Остановив службу Update services на исходном сервере, копируем скаченный контент на целевой сервер
и кладем куда следует. Так же не забываем про права и про то, что на целевом сервере служба Update services
так же должна быть выключена.
4. Импортируем новую базу SUSM
5. Запускаем службу Update services на целевом сервере
6. Если папка с обновления на целевом сервере совпадает с местом на исходном, то ни чего делать не надо,
если нет, то командуем wsusutil movecontent "D:\WSUS Updates" -skipcopy (Вот тут странно как-то получилось. Когда я
пробовал так сказать на кошках. У меня не заработала без этого. А когда уже все переносил все подхватилось само.)
7. wsusutil reset

После этого можно запустить оснастку управления WSUS сервером и у вас должна получиться копия исходного сервера.

Так же последний, и думаю самый правильный способ. Это сделать следующее. Открыть оснастку WSUS открыть «Параметры -> Источник обновлений и прокси-сервер». Установить переключатель в «Синхронизировать с другим сервером Windows Server Update Services», указать старый исходный сервер, и установить флажок «Данный сервер является репликой вышестоящего сервер» После репликации возвращаем флаг на «Синхронизировать с центром обновления Microsoft»

Вот такими путями можно переносить wsus сервер. Если я где-то не прав или допустил не точности, прошу поправить в комментариях.

Author: Categories: Работа, Саморазвитие Tags:

Скрипт бекапа сайтов на web сервере

8 Октябрь 2009

Захотелось автоматизировать создание баков на веб сервере. Для этого у всех учеток изменил описание на hosting, что можно было всех махом выдернуть из /etc/passwd. В итоге получился такой скрипт который не зависит от вновь заведенных сайтов. Он сам обработает новых товарищей.

#!/bin/sh
#########################################################################################
#   Created:        Zakharchenko Andrey Ruslanovich
#   Date:           2009.09.16
#   Description:    Скрипт создания резервных копий сайтов отдельными арховами
#########################################################################################

#--- приветствие так сказать
/bin/echo "1. Backup hosting folders start. Time start: `/bin/date +%Y:%m:%d:%H:%M:%S`"
/bin/echo ""
#--- цикле перебираем /etc/passwd и получаем путь до домашних папок
for i in `cat /etc/passwd |awk -F: '$5~"hosting" {print($6)}'`;
#--- создаем целевую папку для архивов
do mkdir -p /var/files/backups/hosting/`date +%Y/%m/%d`&& \
#--- выводим информацию о том какой сайт архивируется и когда начал архивироваться
    /bin/echo "Backup hosting folders: `/bin/echo $i`  start. Time start: `/bin/date +%Y:%m:%d:%H:%M:%S`" && \
#--- список исключений которые не попадут в архив
    tar --exclude *access.log --exclude *error.log --exclude tmp --exclude php-cgi.core \
#--- ну и собственно чего архивируем и куда кладем
    -cjf /var/files/backups/hosting/`date +%Y/%m/%d`/`date +%Y.%m.%d.%H%M`-`\
    echo $i |awk -F '/' '{print($5)}'`.tar.bz2 $i;
done

Вот такой получился маленький и удобный скриптец :)

Изменения разрешения на вход пользователей во всем домене

16 Сентябрь 2009

Был у нас когда-то совсем давно сервер с именем MAAT и с ролью web сервера. Время шло и мы его убили. В место него появились два сервера IIS-01 и IIS-02 с теми же ролями. Так же для пользователей, которые используют особо важные программы отдела АСУ был ограничен вход на компьютеры. Ну и как говорится началась глупая работа по замене старого сервера на новые. После третьего звонка я не выдержал и набросал вот такой скрипт. Который ищет в домене пользователей у которых в свойстве userWorkstations есть компьютер MAAT и заменяет его на нужные значения.

#Requires -Version 2.0
#Requires -PSSnapin Quest.ActiveRoles.ADManagement

#########################################################################################
#   Created:        Zakharchenko Andrey Ruslanovich
#   Date:           2009.09.16
#   Description:    Скрипт ищет всех пользователей с определенным компьютером в свойстве
#                        userworkstations и заменяет их нужными именами компьютеров
#########################################################################################

Function Search-MAAT ($listcomputers) {
#--- создаем пустой масив
    $mass = New-Object System.Collections.ArrayList
#--- заполняем массив
    Foreach ($i in $listcomputers -split ',') { $mass.Add($i) | Out-Null }

    $i = 0
    While ($i -ne $mass.Count+1) {
#--- ищем совпадения и устанвливаем флаг
        if (($mass[$i] -match 'maat') -and ($listcomputers -match 'IIS-01') `
                                    -and ($listcomputers -match 'IIS-02')) {
#--- тут флага нету, так как мы сразу удаяем не нежный элемент массива
            $mass.Removeat($i)
        }
        if (($mass[$i] -match 'maat') -and ($listcomputers -match 'IIS-01')) {
            $check = 'iis-02'
        }
        if (($mass[$i] -match 'maat') -and ($listcomputers -match 'IIS-02')) {
            $check = 'iis-01'
        }
        if (($mass[$i] -match 'maat') -and ($listcomputers -notmatch 'IIS-01') `
                                    -and ($listcomputers -notmatch 'IIS-02')) {
            $check = 'all'
        }

#--- обрабатываемт полученные флаги
        switch ($check) {
            'all' { $mass[$i] = 'IIS-01,IIS-02' }
            'iis-01' { $mass[$i] = 'IIS-01' }
            'iis-02' { $mass[$i] = 'IIS-02' }
            default { }
        }
#--- удаляем при каждом прохоте на всякий случай переменную с флагом
        if($check) {Remove-Variable check}
        $i++
    }
#--- собираем массив в строку с разделителем ','
$mass -join ','
}

$root = 'DC=isea,DC=ru'
Foreach ($user in Get-QADUser * -IncludedProperties 'userWorkstations' -SizeLimit 0 -SearchRoot $root) {
    if ( $user.userWorkstations -match 'maat' ) {
        Write-Host "Работы проводится над следующим пользователем: $($user.DisplayName)"
        Set-QADUser $user  -ObjectAttributes @{'userworkstations'=$(Search-MAAT $user.userworkstations)} |Out-Null
    }
}

Собственно лень двигатель прогресса :) Имена компьютеров можно изменить и использовать скрипт повторно.

Установка FreeBSD с диска LiveFS

9 Сентябрь 2009

Предыстория. У меня есть сервер с 4 гигабайтами памяти. В дальнейшем предполагается нарастить ее до 8 гигабайт. По этому будем ставить amd64. Так же как не смешно, у меня нету установочного диска с этой версией FreeBSD. Но есть LiveFS диск «7.2-RELEASE-amd64-livefs.iso». Так же в сети есть свой cvsup сервер на котором так сказать есть все исходники. По этому в планах:
1. загрузиться с диска
2. разметить винчестер и смонтировать его
3. создать в памяти раздел
4. скачать src мира и собрать его в памяти
5. установить собранный мир на винчестер
Это предварительный план чего хочется сделать. Так же зачем это все делается? Конечно можно просто с ftp скачать установочный диск и забыть о таких проблемах. Можно создать загрузочную флешку и установить все с нее. Можно по сети подмапить src и собрать на ней же. Но хочется получить experience и заработать levalup так сказать :) Читать далее…

Функция определения какие роли хранятся на каких контроллерах домена

8 Сентябрь 2009

В продолжение прошлого поста публикую функцию отображения где какие роли находятся. Я понимаю что подобных скриптов уже полно. НО как говорится хотелось сделать самому, да и разобраться с этим делом. А не использовать безвольно уже готовое.

#########################################################################################
#   Created:        Zakharchenko Andrey Ruslanovich
#   Date:           2009.09.07
#   Description:    Функция получения ролей хранящихся на контроллерах домена
#########################################################################################

Function Get-DomainRoles {
    param($domain)
#--- если домен не задан получает текущий домен
    if (!$domain) {
        $domain = (Get-WmiObject -ComputerName '.' -Query 'Select domain From Win32_ComputerSystem').Domain
    }
#--- подключаемся к указанному домену и осуществляем получение информации
    $context = new-object System.DirectoryServices.ActiveDirectory.DirectoryContext(”Domain”,$domain)
    $dclist = [System.DirectoryServices.ActiveDirectory.DomainController]::findall($context)
#--- разбираем ролученные данные
    Foreach ( $chek in $dclist ) {
#--- отфильтровывает КД на которых нету ролей
        if ($chek.Roles -ne "" ) {
            $i = 0
#--- ну и самое вкусное
            while ($i -ne $chek.Roles.Count) {
                switch ($chek.Roles[$i]) {
                    'SchemaRole' { $role = 'Хозяин схемы' }
                    'NamingRole' { $role = 'Хозяин именования домена' }
                    'PdcRole' { $role = 'Эмуляция главного контроллера домена (PDC)' }
                    'RidRole' { $role = 'Хозяин относительных идентификаторов (RID)' }
                    'InfrastructureRole' { $role = 'Хранитель инфраструктуры' }
                }
                $tmp = "" | Select @{n='Roles';e={$($role)}},@{n='DC';e={$($chek.name.ToLower())}}
                $tmp
                $i++
            }
        }
    }
}

Ну и собственно пример работы:

[PS] <7> C:\Bin>Get-DomainRoles

Roles                                                       DC
-----                                                       --
Эмуляция главного контроллера домена (PDC)                  dc-01.isea.ru
Хозяин относительных идентификаторов (RID)                  dc-01.isea.ru
Хозяин схемы                                                dc-02.isea.ru
Хозяин именования домена                                    dc-02.isea.ru
Хранитель инфраструктуры                                    dc-02.isea.ru


[PS] <8> C:\Bin>
[PS] <8> C:\Bin>Get-DomainRoles -domain "student.isea.ru"

Roles                                                       DC
-----                                                       --
Эмуляция главного контроллера домена (PDC)                  dc-03.student.isea.ru
Хозяин относительных идентификаторов (RID)                  dc-03.student.isea.ru
Хранитель инфраструктуры                                    dc-03.student.isea.ru


[PS] <9> C:\Bin>

Несколько полезных функций на PowerShell

7 Сентябрь 2009

Первая функция получает необходимые свойства объекта из Active Directory

#########################################################################################
#   Created:        Zakharchenko Andrey Ruslanovich
#   Date:           2009.09.07
#   Description:    Функция получения свойства объект[а|ов] из Active Directory
#########################################################################################

Function Get-ADProperty  {
    param ($name, $type, $property, $domain)
#--- если не задан домен, то получаем его самостоятельно
    if (!$domain) {
        $domain = ([adsi]"").DistinguishedName
    }
#--- собственно сам фильтр  
    $strFilter = "(&(objectCategory=$type)(cn=$name))"
    $objDomain = New-Object System.DirectoryServices.DirectoryEntry("LDAP://$domain")
   
    $objSearcher = New-Object System.DirectoryServices.DirectorySearcher
#--- обозначаем корень поиска
    $objSearcher.SearchRoot = $objDomain
#--- чтоб случайно не задосить Active Directory
    $objSearcher.PageSize = 1000
#--- применяем фильтр
    $objSearcher.Filter = $strFilter
#--- ищем
    $colResults = $objSearcher.FindAll()
#--- выводим результат
    Foreach ($objResult in $colResults) {
        $objResult.Properties.$($property.tolower())
    }

Пример запуска и получаемого результата:

[PS] <25> C:\Bin>Get-ADProperty -type "user" -name "Захарченко Андрей" -property "homeDirectory"
\\balance.isea.ru\homes$\abigor
[PS] <26> C:\Bin>Get-ADProperty -type "group" -name "пользовате*" -property "DistinguishedName" -domain "DC=student,DC=isea,DC=ru"
CN=Пользователи,CN=Builtin,DC=student,DC=isea,DC=ru
CN=Пользователи DCOM,CN=Builtin,DC=student,DC=isea,DC=ru
CN=Пользователи домена,CN=Users,DC=student,DC=isea,DC=ru
CN=Пользователи журналов производительности,CN=Builtin,DC=student,DC=isea,DC=ru
CN=Пользователи системного монитора,CN=Builtin,DC=student,DC=isea,DC=ru
CN=Пользователи удаленного рабочего стола,CN=Builtin,DC=student,DC=isea,DC=ru
[PS] <27> C:\Bin>

Следующая функция получает название текущего домена в формате domain.com

Function Get-Domain {
    (Get-WmiObject -ComputerName '.' -Query 'Select domain From Win32_ComputerSystem').Domain
}

Смена регистра текста

Понадобилось мне приводить название подразделений к стандартизованному виду. Который был заложен еще до меня. В базе по сотрудникам их подразделения написаны все в верхнем регистре. Что согласитесь в Active Directory это бы смотрелось не очень хорошо. По этому у меня появилась необходимость автоматизировать этот процесс. В ходе чего на свет появилась такая функция:

#########################################################################################
#   Created:        Zakharchenko Andrey Ruslanovich
#   Date:           2009.07.17
#   Description:    Функция смена регистра подразделений/текста.
#                   Приведение его к общему стандарту.
#########################################################################################

Function Replace-Register ($text) {
#--- в цикле разрезаем текст на слова
    Foreach ($var in  ($text).Split(' ')) {
#--- проверяем если слово состоит из одного символа, делаем нижний регистр
        if ($var.Length -eq 1) {
            $j = $var.ToLower()
        }
#--- если слово разделено "-" то отдельно с ним работаем
        elseif ($var -cmatch '-') {
#--- переключатель
            $switch = 0
#--- разделяем слово по "-"
            Foreach ( $var1 in $var.Split('-')) {
#--- если это первое слово, то в конец добавляем "-"
                if ($switch -eq 0 ) {
                    $j1 = $(($var1.Substring(0,1)).ToUpper()) + $(($var1.Substring(1)).ToLower()) + '-'
                }
                else {
                    $j1 = $(($var1.Substring(0,1)).ToUpper()) + $(($var1.Substring(1)).ToLower())
                }
#--- собираем в строку
                $j = $j + $j1
                $switch++
            }
        }
#--- работа над обычными словами не подошедшими не под один фильтр
        else {
            $j = $(($var.Substring(0,1)).ToUpper()) + $(($var.Substring(1)).ToLower())
        }
#--- собираем текст в строку
        $textuot = $textuot + ' ' + $j
        Remove-Variable j
    }
#--- выводим результат
    $textuot.Trim()
}

Ну и проверим чего у нас получилось:

[PS] <42> C:\>Replace-Register 'ИРКУТСКИЙ И БРАТСКИЙ ТОРГОВО-ЭКОНОМИЧЕСКИЕ КОЛЛЕДЖИ'
Иркутский и Братский Торгово-Экономические Колледжи
[PS] <43> C:\>Replace-Register 'иркутский и братский торгово-экономические колледжи'
Иркутский и Братский Торгово-Экономические Колледжи
[PS] <44> C:\>

Скрипт создания файла экспорта данных для Live@Edu

14 Июль 2009

Наш вуз стал участником программы от Microsoft под название Live@Edu. Это нечто бесплатной почтовой системы с ящиком в 25Gb и в дальнейшем с тесной интеграцией с продуктами Microsoft. При этом в систему можно загрузить необходимых пользователей через csv файл и тем самым завести всех кому необходима данная система. Пока был написан простенький скрипт для генерации csv файла с необходимыми данными внутри и для последующей его отсылки человеку который нас курирует. Так как до 2009.07.01 необходимо было завести не меньше 500 учеток для подтверждения внедрения данного продукта в организации. По этому скрипт очень простой. В дальнейшем он будет дописан и расширен функционал.

#Requires -PSSnapin Quest.ActiveRoles.ADManagement

#########################################################################################
#   Created:        Zakharchenko Andrey Ruslanovich
#   Date:           2009.06.28
#   Description:    Экспорт сотрудников в CSV для создания почтовых ящиков в систему Live@Edu
#########################################################################################

#--- функция генерации пароля
Function New-Password ([int]$intPasswordLength){
#--- проверяем что пароль больше 4 символов
    if ($intPasswordLength -lt 4) {return "password cannot be <4 chars"}
#--- наборы символов для генерации
    $strNumbers = "1234567890"
    $strCapitalLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    $strLowerLetters = "abcdefghjkmnpqrstuvwxyz"
    $strSymbols = "!%^&*()+=/?{}[]~,.<>:"

#--- собственно сама генерация пароля
    $rand = new-object random
    for ($a=1; $a -le $intPasswordLength; $a++){
        if ($a -gt 3){
            $b = $rand.next(0,4) + $a
            $b = $b % 3 + 1}
        else { $b = $a }
        switch ($b){
        "1" {$b = "$strNumbers"}
        "2" {$b = "$strCapitalLetters"}
        "3" {$b = "$strLowerLetters"}
        "4" {$b = "$strSymbols"}}
        $charset = $($b)
        $number = $rand.next(0,$charset.Length)
        $RandomPassword += $charset[$number]
    }
    return $RandomPassword
}

#--- объявляем переменные
$SQLServer = "SQLSERVER"
$DBName = "DB_SOTRUDNIC"
$i = 0
$domain = 'bguep.info'

#--- создаем подключение к Microsoft SQL Server
$SQLConnection = new-object System.Data.SqlClient.SqlConnection("Initial Catalog=$DBName;Data Source=$SQLServer;Integrated Security=SSPI")
$SQLConnection.Open()

#--- основной цикл выполнения
ForEach ($user in Get-QADUser -searchroot "OU=БГУЭП,DC=isea,DC=ru" -IncludedProperties WebPage,LogonName,AccountIsDisabled -SizeLimit 0 ) {
#ForEach ($user in Get-QADUser -searchroot "OU=Информационное Управление,OU=БГУЭП,DC=isea,DC=ru" -IncludedProperties WebPage,LogonName,AccountIsDisabled -SizeLimit 0 ) {
    if ($user.webpage){
        if (!($user.webpage -match "^Q")) {
#--- ищем, что пользователь является сотрудником вуза (проверяем по "рег. номеру")
            $query = "SELECT TOP (1) регном FROM dbo.BankCustomer WHERE регном = " + $($user.WebPage -replace "[^0-9 \d]") + ""
            $SQLCommand = New-Object System.Data.SqlClient.SqlCommand($query, $SQLConnection)
            $SQLReader = $SQLCommand.ExecuteScalar()
#--- вытаскиваем должность сотрудника
            $query = "SELECT TOP (1) Должность FROM dbo.Customer WHERE регном= " + $($user.WebPage -replace "[^0-9 \d]") + ""
#--- проверяем, что "рег. номер" не пустой и пользователь не отключен в AD
            if ($SQLReader -and !$user.AccountIsDisabled) {
#--- создаем объект для дальнейщего экспорта
                $export = "" | Select-Object @{name='EmployeeID';expression={$user.webpage}}, `
                                        @{name='FullName';expression={$user.DisplayName}}, `
#                                       @{name='Post';expression={(New-Object System.Data.SqlClient.SqlCommand(("SELECT TOP (1) Должность FROM dbo.Customer WHERE регном= " + $($user.WebPage -replace "[^0-9 \d]") + ""), $SQLConnection)).ExecuteScalar()}}, `
                                        @{name='Email';expression={(($user.LogonName).ToLower() + "@$domain")}}, `
                                        @{name='Password';expression={(New-Password (10))}}
                $export  
                $i++
            }
        }
    }
}

Write-Output "Итого пользователей: $($i)"
$SQLConnection.Close()