Powershell cкрипт для массового отображения/изменения ACL на файловом сервере

Привет! Понадобилось мне недавно провести вручную операцию по удалению из ACL лишней записи. Проблема была в том, что таких папок было около 50 штук. Спасало только то, что это нужно было сделать в папке с одним и тем же именем в разных директориях с одним общим корнем. Я это сделал вручную, так как задачу надо было выполнить быстро, но решил для себя написать скрипт, чтобы можно было быстро править ACL-листы папок в Windows. Необходимо только, чтобы на сервере был Powershell и немного его знания, так как скрипт практически не оттестирован и не проверен в реальной работе на большом количестве данных.
Вот он сам, по комментариям внутри него думаю будет понятно, что надо делать.

function Print_Dir($list_catalogs)
    {
         $Table = New-Object system.Data.DataTable “$Table_Security”  <#Создание таблицы для отображения ACL#>
         $column1 = New-Object system.Data.DataColumn Директория,([string])
         $column2 = New-Object system.Data.DataColumn ACL,([string])
         $column3 = New-Object system.Data.DataColumn Владелец,([string])
         $table.columns.add($column1)
         $table.columns.add($column2)
         $table.columns.add($column3)
         foreach ($Foundfolder in $list_catalogs) 
            {
                $Access = (Get-Acl $Foundfolder.FullName).AccessToString  
                $row = $table.NewRow()
                $row.Директория = $Foundfolder.FullName
                $row.ACL = “$Access”
                $row.Владелец = $AccessACL.Owner
                $table.Rows.Add($row)
            } 
         $table | format-table -Wrap
        
    }

function Found_Folder()
    {
                $Root_Path = Read-Host 'Введите корневую директорию'   <#Директория в которой производится поиск по-умолчанию#>
                $Target_Folder = Read-Host 'Введите название папки'    <#папка для поиска по-умолчанию #>
                $FFolder = Get-ChildItem $Root_Path -Recurse -Directory -Force -ErrorAction SilentlyContinue -Filter "$Target_Folder" <#Найденные папки#>
                return $FFolder
    }

While ($KEY='1')
{
$ACL_Key = Read-Host 'Что необходимо сделать? (1 - Вывести текущие значения ACL; 2 - Добавление; 3 - Удаление; 4 - Выход из программы)'
switch ($ACL_Key)
{
    1 
        {
                $Found_Folder = Found_Folder
                Print_Dir($Found_Folder)
        }
    2
        {
                $Found_Folder = Found_Folder
                $AccessRuleAdd = New-Object System.Security.AccessControl.FileSystemAccessRule "ONIX\TestAV", "Modify","ContainerInherit,ObjectInherit", "None","Allow" <#ACL, которую требуется добавить в папки#>
                foreach ($Foundfolder in $Found_Folder)
                    {
                        $ACL = $Foundfolder.GetAccessControl("Access")  
                        $ACL.AddAccessRule($AccessRuleAdd)
                        $Foundfolder.SetAccessControl($ACL)
                    } 
                Print_Dir($Found_Folder)
        }
    3
        {
                $Found_Folder = Found_Folder
                $AccessRuleDel = New-Object System.Security.AccessControl.FileSystemAccessRule "ONIX\TestAV", "Modify","ContainerInherit,ObjectInherit", "None","Allow" <#ACL, которую требуется добавить в папки#>
                foreach ($Foundfolder in $Found_Folder)
                    {
                        $ACL = $Foundfolder.GetAccessControl("Access")  
                        $ACL.RemoveAccessRule($AccessRuleDel)
                        $Foundfolder.SetAccessControl($ACL)
                    } 
                Print_Dir($Found_Folder)
        }
    4   
        {
            exit
        }
} 
}

Автоматическое восстановление базы данных SQL из Veeam Backup

Понадобилось автоматически восстанавливать MS SQL базу данных из Veeam Backup & Replication 9.5. Задание должно было запускаться сразу после того, как заканчивалось резервное копирование и восстановление должно было происходить на другой сервер. Вот какой скрипт у меня получился:

Add-PSSnapin VeeamPSSnapIn

$source_host        = "SQL_Original"
$source_db1         = "DB1"
$source_db2         = "DB2"
$source_db3         = "DB3"
$source_db4         = "DB4"
$target_host        = "SQL_Target"
$target_cred        = Get-VBRCredentials -Name "onix\onix_backup"
$target_instance    = "test"

$target_db1    = $source_db1
$target_db2    = $source_db2
$target_db3    = $source_db3
$target_db4    = $source_db4

$(
$restorepoint = Get-VBRApplicationRestorePoint -SQL -Name $source_host| Sort-Object creationtime -Descending | Select-Object -First 1
$database1 = Get-VBRSQLDatabase -ApplicationRestorePoint $restorepoint -Name $source_db1
$database2 = Get-VBRSQLDatabase -ApplicationRestorePoint $restorepoint -Name $source_db2
$database3 = Get-VBRSQLDatabase -ApplicationRestorePoint $restorepoint -Name $source_db3
$database4 = Get-VBRSQLDatabase -ApplicationRestorePoint $restorepoint -Name $source_db4
$restore_session = Start-VBRSQLDatabaseRestore -Database $database1 -ServerName $target_host -InstanceName $target_instance -DatabaseName $target_db1 -GuestCredentials $target_cred -SqlCredentials $target_cred -Force -Wait
$restore_session = Start-VBRSQLDatabaseRestore -Database $database2 -ServerName $target_host -InstanceName $target_instance -DatabaseName $target_db2 -GuestCredentials $target_cred -SqlCredentials $target_cred -Force -Wait
$restore_session = Start-VBRSQLDatabaseRestore -Database $database3 -ServerName $target_host -InstanceName $target_instance -DatabaseName $target_db3 -GuestCredentials $target_cred -SqlCredentials $target_cred -Force -Wait
$restore_session = Start-VBRSQLDatabaseRestore -Database $database4 -ServerName $target_host -InstanceName $target_instance -DatabaseName $target_db4 -GuestCredentials $target_cred -SqlCredentials $target_cred -Force -Wait
) *>&1 >> "C:\SQLRestore_errors.log"

Все достаточно просто: берется оригинальный хост с базами данных, список баз для восстановления, хост на который надо восстановить, учетная запись от имени которой будет восстановление (должна быть сохранена в «Manage Credentials» и целевой инстанс SQL если требуется). Находится последняя точка резервного копирования базы (на точку восстановления с проигрыванием логов восстановиться можно, но не получится это сделать автоматически) и восстанавливается. Если происходят ошибки, то они выводятся в текстовый файл (в консоли Veeam ошибки работы скрипта показаны не будут).

Остается в задаче, которая бекапит SQL-сервер, настроить запуск скрипта, делаем это в «Advanced Settings». Задаем так строку C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -noninteractive -file «C:\Scripts\SQLRestore.ps1»

Сброс пароля в Kaspersky Endpoint Security 10

Понадобилось вчера переустановить антивирус Касперского в доменной среде, при незнании пароля, установленного в KSC для блокирования изменения настроек. К сожалению bat -файл с раздела технической поддержки Касперского, который сбрасывает пароль, не работает на серверных операционных системах, поэтому пришлось искать другой способ. Оказывается он совсем простой, достаточно только также загрузиться в безопасный режим и в реестре найти ветку HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\KasperskyLab\protected\KES10\settings (для Win x64) или HKEY_LOCAL_MACHINE\SOFTWARE\KasperskyLab\protected\KES10\settings (для Win x32) и изменить ключ на следующее значение:

"EnablePswrdProtect"=dword:00000000

После этого перезагружаемся опять в безопасный режим и можно смело удалять антивирус, пароль уже не потребуется. Для удаления я воспользовался утилитой kavremvr.exe. от того же Касперского. Делал я по той причине, что Касперский никак не хотел ставиться после обновления системы на новую версию, ошибка в логах была «Failed to extract stream: mklifx64nt602.cab Error 0x80070006»

Перенос WordPress на Debian с NGINX.

Привет! На днях решил заняться этим блогом. Решил немного попрактиковаться с web-сервером на linux-машине. Был выбран Debian 9 и nginx. Пришлось немного повозиться, наступить на различные грабли, но самое главное я добился своей цели. Не буду здесь писать инструкции как я это осуществил, так как в интернете полно материалов на данную тему. Могу лишь только сказать, что для начинающего администратора это может оказаться сложным. Если у кого-то будут вопросы по мигрированию или созданию новых блогов на данной платформе, то прошу вас, обращайтесь ко мне через комментарии к этой заметке или через обратную форму на главной странице.

P.S. Среднее время загрузки главной страницы сайта у меня теперь составляет менее 500 мс, хотя ранее на Windows с IIS web-сервером эта цифра составляла 3-4 секунды.

Ошибка «We couldn’t create a new partition or locate an existing one» при установке Windows Server 2012R2 на ProLiant BL460c G7

Привет! Первый раз столкнулся с проблемой установки серверной системы Microsoft на сервер HP. Вот возможные варианты решения данной проблемы:

  1. внедрить драйвера дискового контроллера в образ Windows
  2. драйвера дискового контроллера подсунуть на флешке, подключив ее  перед запуском установки системы
  3. самый оптимальный для ленивых админов:
    • нажать Shift+F10 в момент, когда появилось сообщение об ошибке.
    • В cmd набрать команды:
      diskpart
      list disk
      select disk 0 (номер диска куда устанавливается система)
      clean
      create partition primary
      format fs=ntfs quick
      assign
      active
      list volume (смотрим какая буква назначилась разделу и какая буква принадлежит iso с дистрибутивом)
      exit
      cd D: (переходим в каталог, где лежит дистрибутив системы)
      xcopy d: c:/e/h/k (копируем дистрибутив на раздел куда будем устанавливать систему)
  • после завершения копирования отключаем ISO-образ от сервера и перезагружаемся
  • запустится инсталлятор системы непосредственно с дисковой подсистемы сервера. В процессе установки указываем тот же раздел, в который копировали установщик
  • После завершения установки и входа в систему надо очистить корень системного диска С: от файлов и папок установщика.
  • правим загрузчик системы., иначе по-умолчанию в его настройках будет 2 записи, одна из которых будет ссылаться на установочные файлы. Для этого в загруженной системе открываем cmd и пишем:
    bcdedit 
    Находим запись об установщике Windows Setup и копируем его идентификатор
    bcdedit /delete <ID> 
    Удаляем запись с нужным идентификатором
    После этого установленная система не будет отличаться от той, что была бы установлена по 1 или 2 способу.

Перенос физического сервера FreeBSD в виртуальную машину

В моем случае сервер FreeBSD 9.1, виртуальная машина будет находится на хосте ESXi 6.5, впрочем это совсем не важно. Выполняем следующие шаги:

1) Подготавливаем новый сервер (виртуальную машину).
2) Запускаем установщик сервера (достаточен bootonly ISO-образ FreeBSD).
3) Установщик спрашивает в начале что будем делать: устанавливать, запустить Shell или запустить Live CD. Выбираем «запуск Shell«
4) Настраиваем сеть: ifconfig em0 10.9.96.5/24
Добавляем маршрут по-умолчанию: route add default 10.9.96.1
Проверяем, что сервер, который требуется перенести может пинговать наш новый сервер.
5) Запускаем SSH. Для этого нужны следующие шаги:
mkdir /tmp/etc
mount_unionfs /tmp/etc /etc

Правим файл настроек SSH для возможности подключения root к серверу:
ee /etc/ssh/sshd_config
Правим строку. Должно быть:
PermitRootLogin yes
SSH-готов для запуска:
/etc/rc.d/sshd onestart
6) Меняем пароль у root-пользователя во времено загруженной системы: passwd
7) Командой sysctl kern.disks проверяем наличие дисков в системе. Находим тот, который будет выделен под систему.
Командой gpart show <имя диска> смотрим, что на этом диске есть. Если разделов нет или они отличаются от разделов на исходном сервере, то командой gpart destroy -F <имя диска> уничтожаем всё на диске.
8) Командой geom disk list на целевом сервере проверяем размер сектора диска. Если установка производится на современные жесткие диски, у которых размер сектора = 4 кб, то при создании разделов необходимо использовать выравнивание.
9) Командами gpart create -s <BSD|GPT|MBR> <имя диска> создадим одну из схем (геометрию) на диске.
10) Командой gpart add -t <freebsd-ufs|freebsd-boot|freebsd-swap> <имя диска> создаем раздел на диске (если нужно выравнивание, то используем дополнительные ключи)
11) Форматируем корневой раздел командой newfs -U <имя раздела>. Ключ -U включает Soft Updates
12) Делаем диск загрузочным: для этого выполняем команду gpart bootcode -b /boot/boot <имя диска> (для схемы BSD). Для других схем команды будут: gpart bootcode -b /boot/mbr <имя диска> и
gpart bootcode -b /boot/pmbr <имя диска>
gpart bootcode -p /boot/gptboot -i 1 <имя диска>

13) Монтируем раздел mount <имя раздела> /mnt
14) На исходной машине выполняем команду: dump -0Lf - / | ssh root@10.9.96.5 "cd /mnt ;restore -rf -". Если сервер пишет «Cannot create snapshot. Snapshots are not yet supported when running with journaled soft updates.», то тогда нужно загрузиться в Single Mode и выполнить команды:
tunefs -J disable /dev/ada0
tunefs -n disable /dev/ada0
tunefs -j disable /dev/ada0

После этого перезагружаемся и снова выполняем команду dump. Дожидаемся надписи «DUMP IS DONE»
Если сервер нет возможности перезагрузить в безопасный режим, то тогда из команды dump убираем ключ -L. Чтобы данные были как можно более консистенты на новом сервере, на исходном сервере перед дампом выключаем все сервисы. В моем случае это:
service apache22 stop; service nginx stop; service sendmail stop; service mysql-server stop
15) Перезагружаем конечный сервер. Если он не может подмонтировать корневую файловую систему, но еще раз загружаемся с ISO-образа, монтируем том, куда мы скопировали сервер и в нем открываем файл ee /etc/fstab. Там меняем название раздела для корневой системы на правильное.

Удаление ярлыка с рабочего стола через GPO средствами Powershell

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

Перед тем, как настраивать GPO для запуска powershell-скрипта на компьютерах необходимо средствами групповых политик разрешить запуск PS-скриптов. По-умолчанию, на компьютере запрещен их запуск. Поэтому заходим в дефолтную GPO для домена в User Configuration — Policies — Administrative Templates — Windows Components — Windows PowerShell. Находим там политику «Turn on Script Execution«, включаем её и переводим в режим работы «Allow local scripts and remote signed scripts«.

Теперь можно настраивать политику, которая будет запускать PS-скрипт при входе пользователя в систему. Для этого заходим в созданную для этого политику в раздел User Configuration — Policies  — Windows Settings — Scripts — Logon. Выбираем вкладку «PowerShell Scripts» и нажимаем кнопку «Add». Далее нажимаем кнопку «Browse» и в открывшееся окно проводника копируем файл с powershell-скриптом. После этого выбираем этот файл и нажимаем «Open» в этом же окне и «OK» в предыдущем. Таким образом политика настроена.

А вот текст самого скрипта. Сохраняем его под расширением PS1 у себя на компе.

$DeleteItem = "Кодекс-клиент.lnk"
$Date = Get-Date
$ComputerName = $Env:Computername
$UserName = $Env:UserName
$DesktopPath = [Environment]::GetFolderPath("Desktop")
$ShortcutFiles = Get-ChildItem -Path $DesktopPath -Recurse -Include *.lnk
Write-Host "Всего найдено ярлыков:" $ShortcutFiles.Count -ForegroundColor Green
$Changed = 0
ForEach ($Shortcut in $ShortcutFiles) {
IF ($Shortcut -match $DeleteItem ) {
Remove-Item $Shortcut
$Changed ++
}
}
Write-Host "Удалено ярлыков:" $Changed -ForegroundColor Green
echo $Date $UserName "Всего найдено ярлыков:" $ShortcutFiles.Count "Удалено ярлыков:" $Changed >> \\DC-01\C$\Logs_remove_shortcut\$ComputerName.log

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

Этот же скрипт может быть взят за основу для удаления любого файла из любой директории.

Как узнать версию Exchange по дистрибутиву

У меня возникла задача установить Exchange-сервер 2016, в наличии есть какой-то древний ISO-файл. Как по нему определить какая версия Exchange в нем находится? Запускаем файл .exe внутри ISO и распаковываем дистрибутив сервера, далее заходим в директорию .\setup\serverroles\common и находим там файл version.txt, в нем и будет написано версия. В моем случае там было написано: «Version 15.01 (Build 0225.042)». Воспользовавшись поиском, узнаем, что данная версия является RTM.

Сбор статистики с принт-сервера на Windows.


В данный момент у меня есть сервер, к которому подключено более 400 принтеров и мне захотелось узнать сколько страниц ежедневно распечатывается. К сожалению, в сети большинстве своем есть только платные программы для сбора множества информации по серверу печати, поэтому решил для себя написать небольшой powershell-скрипт.

$date = get-date -format dd-MM-yyyy
$number = get-counter "\Очередь печати(_total)\Всего напечатано страниц" | Foreach-Object {$_.CounterSamples[0].CookedValue}
Convertto-html -title "Статистика печати" -PreContent "Количество распечатанных листов за $date : <b>$number</b>" >> C:\counter_print_pages.html

Всё, что он делает — это создает html файл в корне диска C:, в котором записывается информация из счетчика очереди печати со всех принтеров.

Чтобы этот скрипт выполнялся каждый день и заносил каждый раз новую информацию, нужно в «Планировщике задач» создать расписание, где в 23:59 будет выполняться данный выше кусок кода. Далее, чтобы статистика за день обнулилась, а также для того, чтобы на сервере печати очищались от заданий очереди на печать, в «Планировщик задач» добавить на выполнение в 0:00 еще один скрипт:

net stop "spooler"
del /S /Q c:\windows\system32\Spool\Printers\*
net start "spooler"

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

Настройка аудита запуска/остановки службы в Windows

Столкнулся с такой задачей: требовалось знать кто остановил критически важную службу на Windows-сервере. Как оказалось аудит этого события настраивается немного по-другому, в отличии, например, от файлового сервера. Что для этого требуется:

1) для начала скажу, что нельзя настроить аудит сразу всех служб — нужно выбрать конкретные службы для их аудита. Узнаем короткое имя службы, например, через команду PS get-service и в столбце «Name» оно будет отображено

2) в cmd выполняем команду sc sdshow [короткое имя службы]. Выведется строка примерно такого вида D:(A;;CCLCSWRPWPDTLOCRRC;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCLCSWLOCRRC;;;IU)(A;;CCLCSWLOCRRC;;;SU). Скопируйте ее в блокнот и в конце добавьте строку S:(AU;SAFA;RPWPDT;;;WD). Буква «D» в начале строки означает начало списка доступа DACL, а буква «S» — список доступа SACL, который используется при логировании. Если выводимая строка в команде «sc sdshow» уже будет содержать SACL, то удаляем ее и добавляем ту, которая указана выше.

3) выполняем в cmd команду sc sdset [короткое имя службы][получившаяся новая строка]. После этого должна появиться строка [SC] SetServiceObjectSecurity: успех


4) командой auditpol /get /category:* проверяем какой аудит включен в системе. Нам необходимо, чтобы был включен аудит для подкатегорий «Другие события доступа к объекту» и «Работа с дескриптором». В английской Windows они соответственно называются «Other Object Access Events» и  «Handle Manipulation». Если аудит не настроен, то делаем это через групповые политики, если компьютер в домене или через команды auditpol /set /subcategory:"Другие события доступа к объекту" /success:enable /failure:disable и  auditpol /set /subcategory:"Работа с дескриптором" /success:enable /failure:disable, если компьютер не в домене.

5) фильтруем журнал безопасности Windows по коду события «4656» и можем видеть событие в журнале


Аудит настроен.