Архив

Архив раздела ‘Программирование’

Установка обновлений на Windows Server 2008 core

31 Октябрь 2011

Что-то надоело мне постоянно искать этот полезный скрипт. Решил его к себе повесить.

запуск:

 cscript WUA_SearchDownloadInstall.vbs

Example

Set updateSession = CreateObject("Microsoft.Update.Session")
Set updateSearcher = updateSession.CreateupdateSearcher()

WScript.Echo "Searching for updates..." & vbCRLF

Set searchResult = _
updateSearcher.Search("IsInstalled=0 and Type='Software'")


WScript.Echo "List of applicable items on the machine:"

For I = 0 To searchResult.Updates.Count-1
    Set update = searchResult.Updates.Item(I)
    WScript.Echo I + 1 & "> " & update.Title
Next

If searchResult.Updates.Count = 0 Then
    WScript.Echo "There are no applicable updates."
    WScript.Quit
End If

WScript.Echo vbCRLF & "Creating collection of updates to download:"

Set updatesToDownload = CreateObject("Microsoft.Update.UpdateColl")

For I = 0 to searchResult.Updates.Count-1
    Set update = searchResult.Updates.Item(I)
    WScript.Echo I + 1 & "> adding: " & update.Title
    updatesToDownload.Add(update)
Next

WScript.Echo vbCRLF & "Downloading updates..."

Set downloader = updateSession.CreateUpdateDownloader()
downloader.Updates = updatesToDownload
downloader.Download()

WScript.Echo  vbCRLF & "List of downloaded updates:"

For I = 0 To searchResult.Updates.Count-1
    Set update = searchResult.Updates.Item(I)
    If update.IsDownloaded Then
       WScript.Echo I + 1 & "> " & update.Title
    End If
Next

Set updatesToInstall = CreateObject("Microsoft.Update.UpdateColl")

WScript.Echo  vbCRLF & _
"Creating collection of downloaded updates to install:"

For I = 0 To searchResult.Updates.Count-1
    set update = searchResult.Updates.Item(I)
    If update.IsDownloaded = true Then
       WScript.Echo I + 1 & "> adding:  " & update.Title
       updatesToInstall.Add(update)
    End If
Next

WScript.Echo  vbCRLF & "Would you like to install updates now? (Y/N)"
strInput = WScript.StdIn.Readline
WScript.Echo

If (strInput = "N" or strInput = "n") Then
    WScript.Quit
ElseIf (strInput = "Y" or strInput = "y") Then
    WScript.Echo "Installing updates..."
    Set installer = updateSession.CreateUpdateInstaller()
    installer.Updates = updatesToInstall
    Set installationResult = installer.Install()
   
    'Output results of install
    WScript.Echo "Installation Result: " & _
    installationResult.ResultCode
    WScript.Echo "Reboot Required: " & _
    installationResult.RebootRequired & vbCRLF
    WScript.Echo "Listing of updates installed " & _
     "and individual installation results:"
   
    For I = 0 to updatesToInstall.Count - 1
        WScript.Echo I + 1 & "> " & _
        updatesToInstall.Item(i).Title & _
        ": " & installationResult.GetUpdateResult(i).ResultCode        
    Next
End If

Ссылка на первоисточник MSDN

Удаление всех контактов и групп у пользователя Lync

30 Сентябрь 2011

Для выполнения данной операции существует следующая SQL процедура которую можно запустить из SQL Server Management Studio или скрипта.

DECLARE @RC int
DECLARE @_Owner nvarchar(4000)

-- TODO: Set parameter values here.
--set @_Owner="account@company.com"

EXECUTE

@RC = [rtc].[dbo].[ImpDeleteContactGroups2]
   "account@company.com"
GO

Очень удобная вещь если ведется тестирование управления списком контактов.

Удаление всех таблиц в базе mysql

6 Апрель 2011

Необходимо развернуть сайт, но в базе под сайт уже куча таблиц и их надо удалить. Делать это вручную, значит себя не уважать. По этому появилась вот такая замечательная строчка для консоли:

mysqldump -p --add-drop-table --no-data database_name | grep ^DROP  | mysql -p database_name

Ищем папки куда у нас нету доступа

4 Февраль 2010

Продолжаю выполнение чужих просьб :) В этот раз попросили сделать следующее. Есть файловый сервер и на нем бордак с правами и наследование отсутствует. Нужно найти все папки где в пермишенах нету определенной группы/пользователя. Во время написания скрипта обнаружилось две проблемы. Первая заключалась в том, что нашлись папки куда у администратора вообще доступа не было. Так же нашлись папки с путем больше 256 символов. По этому был добавлен обработчик ошибок который проблемные папки выводит в два файлика для дальнейшего разбирательства. Вот собственно и сама функция:

Function Get-NotPermissions ($path,$group,$error_rights,$error_long) {
#--- очищаем лог ошибок
    $error.Clear |out-null
#--- рекурсивно перебираем все папки
    foreach ($item in Get-ChildItem -LiteralPath $path -Recurse -Force -ErrorAction  SilentlyContinue -ErrorVariable error_mass | Where-Object {$_.PSIsContainer}) {
#--- создаем массив с разрешениями
        $groups = ($item.PSPath |get-acl).Access | select -expandproperty IdentityReference
#--- проверяем есть ли в массиве интересующая нас группа
        if ($groups -notcontains $group) { '"'+$item.fullname+'"'}
    }
   
#--- проверяем существует ли файл и если чего удаляем его
    if (Test-Path $error_rights) {Remove-Item -Path $error_rights -Force -Confirm}
    if (Test-Path $error_long) {Remove-Item -Path $error_long -Force -Confirm}
   
#--- обрабатываем полученные ошибки
    foreach ($item in $error_mass ) {
#--- нету доступа
        if ($item.CategoryInfo.Reason -eq 'UnauthorizedAccessException') {
            '"' + $item.TargetObject + '"'  |Out-File -Encoding 'Unicode' -FilePath $error_rights -Append
        }
#--- длинный путь, больше 256 символов
        elseif ($item.CategoryInfo.Reason -eq 'PathTooLongException') {
            '"' + $item.TargetObject + '"'  |Out-File -Encoding 'Unicode' -FilePath $error_long -Append
        }
    }
}

Ну и конечно пример запуска:

Get-NotPermissions -path '\\titan\C$\Bin\tmp' -group 'isea\abigor' -error_rights 'D:\error_NTFS.txt' -error_long 'D:\error_long_NTFS.txt'

Скрипт создания архива конфигурационных файлов FreeBSD сервера

20 Январь 2010

Продолжаю автоматизировать работу сервера. В этот раз руки коснулись автоматизации создания архива с конфигурационными файлами. При этом задачи были поставлены следующие:
1. Пути для архивации должны лежать в отдельном файле.
2. Архивироваться должен на сетевой ресурс расшаренный под Windows Server. При этом во время архивирования он должен подключаться, а по окончании отключаться.
3. Архивы должны создавать раз в день/неделю/месяц (тут я добавил от себя, архивы будут хранится с одной ротацией)

Для написания был выбран perl и в итоге получился вот такой скрипт:

#!/usr/bin/perl

#########################################################################################
#   Created:        Zakharchenko Andrey Ruslanovich
#   Date:           2010.01.20
#   Description:    Скрипт скрипт создания архива конфигурационных файлов
#########################################################################################


#--- основные переменные
$dst = '/var/files/backup_nt/GW-01';
$dst_local = '/var/files/backup/config';
$mount_path = '/var/files/backup_nt';
chop($hostname = `hostname`);
($sec,$min,$hour,$mday,$mon,$year,$wday) = localtime(time);
$year += 1900;
$mon += 1;


#--- преобразовываем формат даты с 1 на 01
sub setformatnumber {
    if ($_[0] < 10 ) { return '0'.$_[0] }
    else { return $_[0] }
}

#--- проверка подмонтирования директории для архивов
if (!`df -Hac | grep backup_nt`) {
    system("mount $mount_path")
}

#--- проверяем на всякий случай доступность пути
if ( -d $dst ) {
#--- создаем список что архивировать
    open(list,"/root/list/backup_list");
    while($in=<list>) {
        $in=~s/\s$//;
        $what_backup=$what_backup." ".$in;
    }

#--- создаем дневной архив
    $to_backup = "$dst/day/$year-".setformatnumber($mon)."-".setformatnumber($mday).".day.$hostname.backup.config.tar.bz2";
    system("/usr/bin/tar jvcf $to_backup $what_backup");

#--- удаляем старые дневные архивы
    $rm_backup = "$dst/day/$year-".setformatnumber($mon)."-".setformatnumber($mday-2).".day.$hostname.backup.config.tar.bz2";
    if ( -e $rm_backup) {
        system ("/bin/rm -f $rm_backup");
    }

#--- создаем бак за месяц
    if ($mday eq 1 ) {
        $to_backup = "$dst/month/$year-".setformatnumber($mon)."-".setformatnumber($mday).".month.$hostname.backup.config.tar.bz2";
        system("/usr/bin/tar jvcf $to_backup $what_backup");

#--- удаляем старые месячные архивы
        $rm_backup = "$dst/month/$year-".setformatnumber($mon-2)."-".setformatnumber($mday).".day.$hostname.backup.config.tar.bz2";
        if ( -e $rm_backup ) {
            system ("/bin/rm -f $rm_backup");
        }
    }
#--- создаем недельный архив
    if ((localtime(time))[6] eq 1 ) {
        $to_backup = "$dst/week/$year-".setformatnumber($mon)."-".setformatnumber($mday).".week.$hostname.backup.config.tar.bz2";
        system("/usr/bin/tar jvcf $to_backup $what_backup");

#--- удаляем старые недельные архивы
        $rm_backup = "$dst/week/$year-".setformatnumber($mon)."-".setformatnumber($mday-14).".week.$hostname.backup.config.tar.bz2";
        if ( -e $rm_backup ) {
            system ("/bin/rm -f $rm_backup");
        }
    }
}

#--- после завершения бекапа отмонтируем директорию
if (`df -Hac | grep backup_nt`) {
    system("umount $mount_path")
}

Файл /root/list/backup_list выглядит следующим образом:

[root@gw-01 bin]# cat /root/list/backup_list
/boot
/etc
/root
/usr/local/etc
/var/named
/var/cron/tabs/root
[root@gw-01 bin]#

Скрипт геренации статистики 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

Функция поиска старых файлов

14 Январь 2010

Попросили у меня совета как можно найти в папке созданные 10 дней назад файлы и удалить их. Подумав у меня родилась вот такая простенькая функция:

Function Search-OldFiles  {
    param ($day,$path,[switch]$search)

    $help = @"
`n
`t Надо использовать следующий синтаксис функции:
`t -day - задаем кол-во дней
`t -path - указываем путь
`t -search - указываем, что необходимо только найти файлы (по умолчанию они удаляются)
`t------------------------------------------------------------------------------------
`t Пример:
`t Search-OldFiles -day 2 -path 'D:\Games' -search
"
@
#--- проверяем существование параметров функции
    if (!($day) -or !($path) ) {write-warning $help; return}
#--- рукурсивно просматриваем папки и выбираем файлы 
    foreach ($item in Get-ChildItem -LiteralPath $path -Recurse -Force | Where-Object {!$_.PSIsContainer}) {
#--- сравниваем дату создания файла
        if ((Get-Date).adddays(-$day) -ge $item.CreationTime)  {
#--- в зависимости от ключа search просто ищем или удаляем      
            if ($search) { '"' + $item.fullname + '"' }
            else { $item.fullname | Remove-Item -Force -WhatIf }
        }
    }
}

Функция для работы с 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``

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

Скрипт бекапа сайтов на 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
    }
}

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