Обнаружил недавно проблему при запросе сертификата APNs в продукте Workspace ONE (бывший Airwatch) — он выполняется слишком долго (самый первый шаг).
Начал смотреть Procmon куда лезет в файловой системе этот продукт при запросе сертификата и выяснил, что он долго обрабатывает каталог C:\Windows\ServiceProfiles\NetworkService\AppData\Roaming\Microsoft\SystemCertificates\Request\Certificates. Зашел в него и оказалось что там около 500 тыс. файлов. Через поиск в интернете быстро находится статья о проблеме со старыми версиями Airwatch https://kb.omnissa.com/s/article/82553 В результате, с помощью скрипта https://github.com/sntcz/Clear-MachineKeys перенес файлы в другой каталог и проблема медленного запроса сертификата больше не проявлялась.
Скрипт на powershell обновления прошивок iLO
Import-Csv "C:\Users\username\Desktop\servers.csv" -Delimiter ';' -Encoding UTF8 | ForEach-Object {
$con = Connect-HPEiLO -Address $_.'Интерфейс управления' -Username 'username' -Password 'password' -DisableCertificateAuthentication
IF (($con.TargetInfo.iLOGeneration -eq 'iLO4') -and ($con.TargetInfo.iLOFirmwareVersion -ne '2,82')) {
Update-HPEiLOFirmware -Connection $con -Location "C:\Users\username\Desktop\ilo4_282.bin" -UploadTimeout 700 -Confirm:$false -Force
}
IF (($con.TargetInfo.iLOGeneration -eq 'iLO5') -and ($con.TargetInfo.iLOFirmwareVersion -ne '2,99')) {
Update-HPEiLOFirmware -Connection $con -Location "C:\Users\username\Desktop\ilo5_299.bin" -UploadTimeout 700 -Confirm:$false -Force
}
}
Обратите внимание на выделенные строки, там нужно вписать правильные значения. После обновления версию прошивки можно проверить командой:
Get-HPEiLOFirmwareVersion -Connection $con | select IP, FirmwareVersion
Скрипт вывода информации о занятом и выделенном дисковом пространстве в кластере vSphere
Get-Module -ListAvailable VMware* | Import-Module
$vcservers = "адрес сервера vSphere"
$username = "имя пользователя"
$report = @()
$Used = 0
$Unused = 0
$AllUsed = 0
$AllAllocated = 0
Connect-VIServer $vcservers -User $username -Password 'пароль пользователя'
$allvms = Get-Cluster -name ‘имя кластера‘ | Get-VM
foreach ($VMName in $allvms){
$Server = Get-VM $VMName | Get-View
foreach ($size_com in $($Server.Storage.PerDatastoreUsage).Committed) {
$Used += $size_com
}
foreach ($size_uncom in $($Server.Storage.PerDatastoreUsage).Uncommitted) {
$Unused += $size_uncom
}
$Used = [math]::Round((($Used)/1024/1024/1024),2)
$Unused = [math]::Round((($Unused)/1024/1024/1024),2)
$Allocated = $Used + $Unused
$row = «» | select ‘Имя сервера’, ‘Занято(ГБ)’, ‘Выделено(ГБ)’
$row.’Имя сервера’ = $VMName
$row.’Занято(ГБ)’ = $Used
$row.’Выделено(ГБ)’ = $Allocated
$report += $row
$AllUsed += $Used
$AllAllocated += $Allocated
}
$report | ft
Write-Host «Всего занято дискового пространства (ГБ): $AllUsed»
Write-Host «Всего выделено дискового пространства (ГБ): $AllAllocated»
Disconnect-VIServer $vcservers -Confirm:$False
Скрипт вывода в CSV занятого пространства на каждом датасторе для всех включенных виртуальных машин в кластере VMware
$VCServer = 'fqdn vcenter сервера'
$VC = Connect-VIServer $VCServer -User 'учетная запись vCenter' -Password 'пароль для учетной записи'
$report = @()
$allvms = Get-Cluster VM-Cluster05 | Get-VM | where {$_.PowerState -eq "PoweredOn"}
foreach ($vm in $allvms) {
$vmview = $vm | Get-View
foreach($disk in $vmview.Storage.PerDatastoreUsage){
$dsview = (Get-View $disk.Datastore)
$dsview.RefreshDatastoreStorageInfo()
$row = "" | select VMNAME, DATASTORE, VMUSED_GB
$row.VMNAME = $vmview.Config.Name
$row.DATASTORE = $dsview.Name
$row.VMUSED_GB = [math]::round((($disk.Committed)/1024/1024/1024),0)
$report += $row
}
}
$report | Export-Csv "C:\Temp\vm_ds.csv" -NoTypeInformation
Disconnect-VIServer $VC -Confirm:$False
Контролируем доступ по RDP с помощью Telegram и Powershell
Решил я тут на днях немного упростить жизнь и заодно вспомнить что такое написание скриптов. Не буду хвалиться, скажу сразу, что за образец взял готовую статью с habr.com. Мне понадобилось с помощью телеграмм и его бота управлять правилом встроенного в windows server брандмауэра. На нём настроено ограничение на вход по RDP с конкретных подсетей (сами знаете что будет, если RDP сервис выставить в интернет без какой-либо защиты). Вот готовый скрипт, осталось только в нем вставить идентификатор бота, аккаунта с которого можно будет отправлять ему сообщения и возможно поменять название правил файервола (у меня они со стандартными именами в русской локализации). После этого добавляйте его в планировщик задач.
Читать далее «Контролируем доступ по RDP с помощью Telegram и Powershell»
Скрипт переноса общей папки на сервере с Windows
Понадобилось тут написать небольшой скрипт, после того как массово пришлось переносить папки на файловом сервере на другой диск. Выкладываю его сюда, вдруг кому-нибудь пригодится. Поменяйте только значение переменных на свои.
# Cоздание копии папки $NameFolder находящейся в $FolderPath1 в директорию $FolderPath2 и копирование ее содержимого со всеми атрибутами.
# Проверка есть ли подключения к общей папке. Если нет, то производится остановка расшаривания и докопирование содержимого. Исходная папка рекурсивно удаляется
# Логи сохраняются в папку $LogsFolderPath
$NameFolder = ‘Общая папка отдела’ #название исходной папки
$FolderSource= ‘F:\Общие папки\’ #путь к исходной папке (обязателен обратный слэш в конце пути)
$FolderDest = ‘D:\Общие папки\’ #путь к папке назначения (обязателен обратный слэш в конце пути)
$LogFolder = ‘C:\MoveFolderLogs\’ #путь к папке с логами (должна быть создана вручную)
$notshare = $false #определяем, что по-умолчанию исходная папка расшарена
$LogFile = $LogFolder + «sync-$NameFolder.log»
$FolderPath1 = $FolderSource+$NameFolder
$FolderPath2 = $FolderDest+$NameFolder
if (!(Test-Path -Path $LogFolder)){
Write-Host «Не создана папка для логов!» -ForegroundColor Yellow }
$SmbShare = Get-SmbShare | where {$_.Path -eq «$FolderPath1» }
if (!(Test-Path -Path $FolderPath2)){
$ACL = Get-Acl $FolderPath1 -Audit
Write-Host «Создание папки назначения» -ForegroundColor Green
New-Item -name $NameFolder -Path $FolderDest -ItemType Directory 1>$null
Set-Acl -AclObject $ACL -Path $FolderPath2
} else
{ Write-Host «Папка назначения уже создана» -ForegroundColor Green }
if (!($SmbShare)){
Write-Host «Исходная папка не расшарена» -ForegroundColor Yellow
$notshare = $true;
$NewSmbShareName = $NameFolder
}
if ((($SmbShare).CurrentUsers -eq «0») -or ($notshare -eq $true)){
if ($notshare -eq $false){
Write-Host «Зашаривание общей папки» -ForegroundColor Green
Remove-SmbShare -Name ($SmbShare).Name -Force
Write-Host «Начинаем копировать файлы общей папки…» -ForegroundColor Yellow -NoNewline
robocopy.exe $FolderPath1 $FolderPath2 /COPYALL /E /DCOPY:DAT /R:3 /W:5 /V /NP /NS /LOG+:$LogFile 1>$null
Write-Host «Завершено» -ForegroundColor Green
Write-Host «Расшаривание общей папки по новому расположению» -ForegroundColor Green
New-SmbShare -Name ($SmbShare).Name -Path $FolderPath2 -CachingMode None -ChangeAccess «Everyone» 1>$null
Write-Host «Удаление исходной папки» -ForegroundColor Green
Remove-Item -Path $FolderPath1 -Force -Recurse
}
else {
Write-Host «Начинаем копировать файлы общей папки…» -ForegroundColor Yellow -NoNewline
robocopy.exe $FolderPath1 $FolderPath2 /COPYALL /E /DCOPY:DAT /R:3 /W:5 /V /NP /NS /LOG+:$LogFile 1>$null
Write-Host «Завершено» -ForegroundColor Green
Write-Host «Расшаривание общей папки по новому расположению» -ForegroundColor Green
New-SmbShare -Name $NewSmbShareName -Path $FolderPath2 -CachingMode None -ChangeAccess «Everyone» 1>$null
Write-Host «Удаление исходной папки» -ForegroundColor Green
Remove-Item -Path $FolderPath1 -Force -Recurse
}
}
else {
Write-Host «Подключений к общей папке»($SmbShare).Name»:»($SmbShare).CurrentUsers -ForegroundColor Yellow
Write-Host «Начинаем копировать файлы общей папки…» -ForegroundColor Yellow -NoNewline
robocopy.exe $FolderPath1 $FolderPath2 /COPYALL /E /DCOPY:DAT /R:3 /W:5 /V /NP /NS /LOG+:$LogFile 1>$null
Write-Host «Завершено» -ForegroundColor Green
Write-Host «Запустите этот скрипт повторно после завершения активных SMB-подключений» -ForegroundColor Red
}
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»
Удаление ярлыка с рабочего стола через 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
В последней строке скрипта я сохраняю логи исполнения данного скрипта на компьютерах пользователя. У меня они сохраняются в скрытую папку на контроллере домена, у вас она будет другой, поэтому поменяйте путь до вашей папки.
Этот же скрипт может быть взят за основу для удаления любого файла из любой директории.
Сбор статистики с принт-сервера на 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"
Таким образом файл со статистикой печати будет ежедневно пополняться актуальной информацией о количестве распечатанных страниц.