PowerShell Скрипты - примеры автоматизации

powershell скрипты

В этой записи буду складировать свои (и не только свои) небольшие PowerShell скрипты, которые не настолько велики, чтоб им посвящать отдельную запись.

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

Windows Powershell - оснастка командной строки и скриптовый язык для различной автоматизации задач и администрирования в windows. Официальный сайт - microsoft.com/powershell

Удаление всех бекапов кроме трех последних

На сервере локально сохраняются бекапы, где папки именуются таким образом: "klbackup2014-01-22#23-00-00". PowerShell скрипт переносит эти папки на сетевой диск и хранить не более 3-х последних бекапов.

Copy-Item "C:\backups\klbackup*\" "\\Server\Backups\klBackup\" -force -recurse -ErrorAction stop
Remove-Item "C:\backups\klbackup*" -force -recurse
$folders = Get-ChildItem "\\Server\Backups\klBackup\klbackup*"
$i = 0
While ($i -lt $folders.count-3) {
   Remove-Item $folders[$i] -force -recurse
   $i++
}

Удаляем файлы старше трех месяцев

$date = (Get-Date).AddMonths(-3)
Get-ChildItem -Path D:\Files\Common | where {!$_.PSIsContainer} |
foreach {
   if ($_.LastWriteTime -lt $date) {
      # в тестовых целях указываем -whatif
      # когда убедимся что все корректно работает то убираем его
      Remove-Item $_ -whatif
   }
}

Разрешение скачанного изображения

PowerShell скрипт скачивает изображение из Интернета и отображает ее разрешение

Function Get-Image{
   begin{[void][System.Reflection.Assembly]::LoadWithPartialName("System.Drawing") |Out-Null}
   process{
      $fi=[System.IO.FileInfo]$_
      if( $fi.Exists){
         $img = [System.Drawing.Image]::FromFile($_)
         $img.Clone()
         $img.Dispose()
      }else{Write-Host "File not found: $_" -fore yellow }
   }
   end{}
}

#Скачиваем файл
$webclient = New-Object System.Net.WebClient
$url = "http://cs418720.userapi.com/v418720852/20d0/DiSlb-_mVBg.jpg"
$file = "D:\ImageSize.jpg"
$webclient.DownloadFile($url,$file)

#Получаем ширину и высоту изображения
$image = $file | Get-Image
$Width = $image.Width
$Height = $image.Height
#Вывод на экран
write-output “Width:$Width, Height:$Height"

Среднее арифметическое трех последних чисел

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

$date = Get-Date -format yyyy-MM-dd
$filename = "C:\Program Files\Zabbix\CheckHost_INET-" + $date + ".res"
$file = Get-Content $filename #считываем файл в переменную. В файле каждая строка содержит по числу.
$lenght = $file.count #получаем количество строк файла
$avg=([int]$file[$lenght-1]+[int]$file[$lenght-2]+[int]$file[$lenght-3])/3 #вычисляем арифметическое среднее трех последних чисел
Write-Host([int]$avg) #выводим среднее арифметическое с откидыванием дроби

Количество файлов в папках и размер папок

PowerShell скрипт выводит на экран и в файл D:\CountFiles.csv информацию о том, сколько содержит файлов каждая папка и подпапки в директории D:\Photos, а также размер этих папок и подпапок. csv файл можно импортировать в exel или гугл-таблицы и отсортировать столбцы по возрастанию или спаданию. Скрипт может пригодиться при оптимизации файлового хранилища.

$source="D:\Photos"
Get-ChildItem $source -recurse -force | where {$_.psIscontainer} | foreach {
   $count = Get-ChildItem $_.fullname -recurse | where {$_.length} | Measure-Object -property length -Sum
   Write-Host($_.FullName)
   $FilesSize = '{0:F}' -f ((($count.Sum)/1024)/1024)
   Write-Host("Files: " + $count.count )
   Write-Host("Size: " + $FilesSize + " MB")
   '"' + $_.FullName + '","' + $count.count + '","' + $FilesSize + '"' | Out-File D:\CountFiles.csv -Append
}

Случайный афоризм из файла

#Автор скрипта: https://elims.org.ua
#читаем содержимое файла в масив построчно и берем случайную строку
$file = Get-Content "C:\aphorism.txt"
$aphorism = Get-Random -input $file #берем случайный афоризм из массива афоризмов
$tag = Get-Random -input " #афоризмы"," #цитаты", " #цитаты" #берем случайный тег
$aphorism = $aphorism + $tag
Write-Host($aphorism)

Отображение mp3-файлов с низким битрейтом

PowerShell скрипт выводит список mp3-файлов, которые находятся в папке D:\vk-music\ и имеют битрейт мене 320

#скрипт выводит список mp3-файлов, которые находятся в папке D:\vk-music\ и имеют битрейт мене 320 
$objShell = New-Object -ComObject Shell.Application
$mp3files = Get-ChildItem "D:\vk-music\" -include "*.mp3" -recurse #получили список mp3-файлов
foreach($mp3Item in $mp3files){ #для каждого файла из списка
 $file = split-path $mp3Item -leaf #из полного имени вырезали имя файла
 $path = split-path $mp3Item #из полного имени вырезали адрес папки
 $objFolder = $objShell.namespace($path)
 $objFile = $objFolder.parsename($file)
 if ($objFolder.getDetailsOf($objFile, 28)) { # 28 - номер свойства файла, в котором хранится информация о битрейте
  $bitrate = [int]$objFolder.getDetailsOf($objFile, 28).Substring(1,3) #из строки, где хранится битрейт, вырезаем числовое значение битрейта
  if ($bitrate -lt 320) { #если битрейт меньше 320
   "№" + ++$i + ' bitrate: ' + $bitrate + " file: " + [string]$mp3Item #выводим битрейт и полное имя файла
  }
 }
}

Удаление изображений с плохим качеством

Удаляем в указанных папках (рекурсивно) изображения jpg с худшим качеством чем HD Ready

Function Get-Image{
 begin{[System.Reflection.Assembly]::LoadWithPartialName("System.Drawing") |Out-Null}
 process{
 $fi=[System.IO.FileInfo]$_
 if( $fi.Exists){
 $img = [System.Drawing.Image]::FromFile($_)
 $img.Clone()
 $img.Dispose()
 }else{Write-Host "File not found: $_" -fore yellow }
 }
 end{}
}

$paths = @()
$paths = $paths + "D:\Folder1\"
$paths = $paths + "E:\Folder2"
$paths = $paths + "X:\Folder3\"

Foreach ($path in $paths) { 
 Get-ChildItem -Path $path -recurse -filter *.jpg | where {!$_.PSIsContainer} | foreach {
 #Получаем ширину и высоту изображения
 $image = $_.FullName | Get-Image
 $Width = $image.Width
 $Height = $image.Height
 #Вывод на экран 
 $pixels = $Width*$Height
 $hd_ready = 1280*720
 $string = $_.FullName+' Width:'+$Width+' Height:'+$Height + " Pixels:"+$pixels 
 $image.dispose()
 if ($pixels -le $hd_ready) {
 Remove-Item $_.FullName 
 write-host $string
 } 
 }
}

Копирование бекапов на резервную площадку

Если PowerShell скрипт запущен в определенное время и определенный день, то он начинает копировать файлы из указанных папок. Ход процесса записывается в лог файл.

После окончания работы:

  • присылается письмо в котором указано:
    • свободное место на локальных дисках (до старта и после окончания), объем бекапа
    • время старта и окончания, длительность бекапа
    • средняя скорость копирования
  • компьютер выключается

Компьютер выключается потому, что он в основном выключен. Для резервного копирования он автоматически включается (настройка в биосе).

$StartTimeHour = (Get-Date).Hour #Запоминаем когда запустилась задача
$Day_of_week = [int]((Get-Date).DayofWeek) #текущий день недели
if ((($Day_of_week -eq 2)-or($Day_of_week -eq 4)-or($Day_of_week -eq 6))-and($StartTimeHour -eq 11)) {
#старт копирования если сейчас вторник, среда, суббота и при этом 11 часов
 $StartTime = Get-Date -Format "yyyy.MM.dd HH:mm:ss" #время старта копирования 
 $Free_Space_Start = Get-WMIObject Win32_LogicalDisk -Filter "DeviceID='D:'" | ForEach-Object {[math]::truncate($_.freespace / 1GB)} #свободное место до бекапа
 $Free_Space_Start_Bytes = Get-WMIObject Win32_LogicalDisk -Filter "DeviceID='D:'" | ForEach-Object {$_.freespace} #свободное место до бекапа
 $log_file = "D:\Backups\log.txt" #лог файл скрипта, можно понять на каком этапе работа скрипта
 $date = "{0:yyyy-MM-dd}" -f (get-date) #текущая дата для имени папки
 $path = "D:\Backups\" + $date + "\" #имя папки
 if (-not(Test-Path $path)) { #если папка не существует
 write-host "создаем папку: " + $path 
 $result = New-Item -ItemType directory -Path $path #создаем папку
 }
 #копируем резервные копии медка
 $time = "{0:yyyy-MM-dd HH:mm:ss}" -f (get-date)
 $string = $time + " Start Copy \\172.16.13.1\Backups\Medoc"
 "##################################################" | Out-File -Append $log_file -Encoding UTF8
 $string | Out-File -Append $log_file -Encoding UTF8 
 & robocopy \\172.16.13.1\Backups\Medoc D:\Backups\Medoc /e /log:"D:\Backups\robocopy_log.txt"
 #копируем резервные копии разных устройств и ПО
 $time = "{0:yyyy-MM-dd HH:mm:ss}" -f (get-date)
 $string = $time + " Start Copy \\172.16.13.1\Backups\Other"
 $string | Out-File -Append $log_file -Encoding UTF8
 & robocopy \\172.16.13.1\Backups\Other D:\Backups\Other /e /log:"D:\Backups\robocopy_log.txt"
 #копируем резервные копии Windows с 1-го сервера
 $path = $path + "WindowsImageBackup"
 $time = "{0:yyyy-MM-dd HH:mm:ss}" -f (get-date)
 $string = $time + " Start Copy \\172.16.13.1\Backups\WindowsImageBackup"
 $string | Out-File -Append $log_file -Encoding UTF8
 & robocopy \\172.16.13.1\Backups\WindowsImageBackup $path /e /log:"D:\Backups\robocopy_log.txt"
 #копируем резервные копии Windows с 2-го сервера
 $time = "{0:yyyy-MM-dd HH:mm:ss}" -f (get-date)
 $string = $time + " Start Copy \\172.16.13.2\Backups\WindowsImageBackup"
 $string | Out-File -Append $log_file -Encoding UTF8
 & robocopy \\172.16.13.2\Backups\WindowsImageBackup $path /e /log:"D:\Backups\robocopy_log.txt"
 #запись в лог-файл окончания работы
 $time = "{0:yyyy-MM-dd HH:mm:ss}" -f (get-date)
 $string = $time + " Finish Backup"
 $string | Out-File -Append $log_file -Encoding UTF8
 "##################################################" | Out-File -Append $log_file -Encoding UTF8
 #Формируем данные для письма
 $EndTime = Get-Date -Format "yyyy.MM.dd HH:mm:ss"
 $Free_Space_End = Get-WMIObject Win32_LogicalDisk -Filter "DeviceID='D:'" | ForEach-Object {[math]::truncate($_.freespace / 1GB)} #свободное место после бекапа
 $Free_Space_End_Bytes = Get-WMIObject Win32_LogicalDisk -Filter "DeviceID='D:'" | ForEach-Object {$_.freespace} #свободное место до бекапа 
 $backup_Size = $Free_Space_Start-$Free_Space_End
 $backup_Size_Bytes = $Free_Space_Start_Bytes-$Free_Space_End_Bytes
 $Work_time = $(NEW-TIMESPAN –Start $StartTime –End $EndTime)
 $Work_time_seconds = $Work_time.TotalSeconds
 $NetworkSpeed = '{0:N1}' -f ((($backup_Size_Bytes / $Work_time_seconds) / (1024*1024)) * 8)
 $Mail_String = "Свободное место до бекапа: " + $Free_Space_Start + " ГБ | `r`n"
 $Mail_String = $Mail_String + "Свободное место после бекапа:" + $Free_Space_End + " ГБ | `r`n"
 $Mail_String = $Mail_String + "Размер бекапа: " + $backup_Size + " ГБ | `r`n"
 $Mail_String = $Mail_String + "Старт бекапа: " + $StartTime + " | `r`n"
 $Mail_String = $Mail_String + "Конец бекапа: " + $EndTime + " | `r`n"
 $Mail_String = $Mail_String + "Время выполнения: " + $Work_time + " | `r`n"
 $Mail_String = $Mail_String + "Средняя скорость копирования: " + $NetworkSpeed + " Мбит в секунду `r`n" 
 Write-host $Mail_String 
 #Заголовки письма и данные почтового ящика
 $From = "admin-notify@домен.com.ua"
 $To = "admin@домен.ком.ua"
 $SMTPServer = "адрес.сервера.com.ua"
 $SMTPPort = "25"
 $Username = "admin-notify@домен.ком.ua"
 $Password = "тут_пароль"
 $subject = "Copy Backups to ReserveServer" 
 $body = $Mail_String 
 #формируем сообщение в формате html:
 $message = New-Object System.Net.Mail.MailMessage $From, $To
 $message.Subject = $subject
 $message.IsBodyHTML = $true
 $message.Body = $body
 #Отправляем:
 Write-host "Отправляем письмо"
 $smtp = New-Object System.Net.Mail.SmtpClient($SMTPServer, $SMTPPort)
 $smtp.EnableSSL = $true
 $smtp.Credentials = New-Object System.Net.NetworkCredential($Username, $Password)
 $smtp.Send($message)
 Write-host "Письмо отправленно"
 & shutdown -s -t 300 #выключаем компьютер через 5 минут
}

Информация об обновлениях WSUS

Этот Powershell скрипт получает информацию со WSUS и показывает:

  • количество обновлений по заданных критериям
  • краткую сводную информацию об обновлениях
  • имена обновлений
  • отображает список обновлений по заданным критериям для каждого компьютера по отдельности
$WSUSServer = 'SERVER_NAME' #WSUS-сервер
$PortNumber = 8530 #http порт wsus
[void][reflection.assembly]::LoadWithPartialName("Microsoft.UpdateServices.Administration")
$wsus = [Microsoft.UpdateServices.Administration.AdminProxy]::getUpdateServer($WSUSServer,$False,$PortNumber)
$UpdateScope = New-Object Microsoft.UpdateServices.Administration.UpdateScope
#$UpdateScope.ApprovedStates = 'NotApproved' #указываем критерии апдейтов: не одобренные
#$UpdateScope.IncludedInstallationStates = 'NotInstalled' #указываем критерии апдейтов: не проинсталированные
$UpdateScope.IncludedInstallationStates = 'Installed' #указываем критерии апдейтов: проинсталированные
$UpdateScope #просматриваем сформированные критерии апдейтов
$wsus.GetUpdateCount($updatescope) #получаем и выводим количество апдейтов
$wsus.GetUpdateStatus($updatescope,$False) #получаем и выводим краткую информацию об обновлениях
$wsus.GetUpdates($updatescope).Title #выводим имена апдейтов

$computers = $wsus.GetComputerTargets() #все компьютеры со wsus
ForEach ($computer in $computers){ #для каждого компьютера
 $Computername = $computer.fulldomainname #получаем его имя 
 $updates = $computer.GetUpdateInstallationInfoPerUpdate($updateScope) #получаем апдейты по указаным критериям
 $UpdateCount = $updates.Count #количество апдейтов для текущего компьютера
 write-host $Computername $UpdateCount #выводим имя компьютера и количество апдейтов
 $i = 0
 ForEach ($update in $updates) { #для каждого апдейта выводим подробную информацию 
 $i++
 $update_info = $update.GetUpdate() #запрашиваем инфо об апдейте
 $UpdateTitle = $update_info.Title #имя апдейта
 $IsApproved = $update_info.IsApproved #является ли он одобренным 
 write-host $Computername $i "of" $UpdateCount $IsApproved $UpdateTitle 
 }
}

Лочим экран и произносим текст

Задача: если в заббиксе сработал тригер и он не потвержден, то необходимо лочить экран и произность этот тригер.

Тригеры из заббикса запрашиваются утилитой zabbixctl и выводяться в текстовый файл, который опубликован по веб-адресу.

Сам powershell скрипт:

Add-Type -AssemblyName System.speech
$speak = New-Object System.Speech.Synthesis.SpeechSynthesizer
$request = (New-Object System.Net.WebClient).DownloadString("http://server/status.txt") #получаем тригеры
$speak.Rate = -2 #Замедляем скорость произношения
$zabbix_message = ($request -split '\n')[0] #первая строка - первый тригер
if ($zabbix_message.length -ge 1) { #если строка не пустая
 cmd /c rundll32.exe user32.dll,LockWorkStation #лочим экран
 $speak.Speak("zabbix. " + $zabbix_message) #произносим текст
 $Time = Get-Date -Format "yyyy.MM.dd HH:mm:ss" 
 $log_message = $Time + " " + $zabbix_message
 $log_message | Out-File -Append "c:\WINDOWS\scripts\log.txt" -Encoding UTF8 #записываем в лог-файл
}

Вывод размера какой-либо веб страницы

$web = New-Object System.Net.WebClient
"{0} bytes" -f ($web.DownloadString("https://elims.org.ua/")).length.toString("###,###,##0")

Остальные Powershell-скрипты:

Понравилось? =) Поделись с друзьями:

Обсуждение записи “PowerShell Скрипты - примеры автоматизации”

  1. Владимир (4remind.ru) says:

    Об Владимир, спсибо за готовые скрипты. Я вот никогда с PowerShell не работал (как-то надобности не было), но вот сейчас глянул эту статью и пригляделся к скрипту для закачки файлов, и уже нашел ему применение. Это конечно можно было бы и на Perl написать, но его же еще дополнительно ставить нужно.

  2. Владимир Демянович (elims.org.ua) says:

    Владимир, вот-вот) Посему на windows считаю powershell более универсальным средством, ничего не нужно устанавливать и можно быть уверенным что скрипт будет работать на других компьютера с этой ОС

  3. Владимир (4remind.ru) says:

    Да мне если честно PowerShell пока не сильно то и нужен, кроме пары готовых скриптов, и кроме того, чтобы в нем себя хорошо чувствовать, нужно им заниматься постоянно, а не время от времени. Но все же поленая он штука.

  4. alkash says:

    Владимир, скрипт «Вывод количества файлов в папках и размера папок» пропускает файлы с аттрибутом hidden, возможно и с другими «не стандартными» аттрибутами.

  5. Владимир Демянович (elims.org.ua) says:

    alkash, действительно, нужно тогда вот так: Get-ChildItem $source -recurse -force

  6. Arafegetk says:

    Большое спасибо автору блога! Много хороших публикаций у Вас в блоге. Добавила в закладки теперь буду чаще заглядывать.

  7. Дмитрий says:

    Большое спасибо автору. Очень познавательно.
    Коллеги, нужна помощь.
    Начальник поставил задачу написать скрипт по сравнению двух Excel-файлов.
    Требования:
    1. Сравнение ТОЛЬКО через массив («так быстрее работать будет»). данные из обоих файлов заносятся в массивы и стравниваются
    2. Путь к файлам надо запрашивать через отдельное окно
    3. Результат работы — третий файл с результатами сравнения

    Примеры файлов есть. Если кто-то захочет помочь — пишите в личку: korwin1979@mail.ru

Обсудить