===== Active Directory ===== ==== Показать значение атрибута msDS-cloudExtensionAttribute1 текущего пользователя ==== # Import AD Module Import-Module ActiveDirectory get-aduser $env:UserName -Properties * | Select msDS-cloudExtensionAttribute1 # Имя компа: # $env:computername # Имя домена: # $env:DomainName ==== Вывести список пользователей и показать логин и msDS-cloudExtensionAttribute1 ==== # Из OU get-aduser -Filter * -SearchBase "OU=Руководство,DC=domain,DC=local" -Properties Enabled,msDS-cloudExtensionAttribute1 | select Name,SamAccountName,msDS-cloudExtensionAttribute1 | ft -AutoSize # По группе Get-ADGroupMember "CN=Заместители директоров,OU=Groups,DC=domain,DC=local" | get-aduser -Properties Enabled,msDS-cloudExtensionAttribute1 | select Name,SamAccountName,msDS-cloudExtensionAttribute1 | ft -AutoSize ==== Извлечь атрибут msDS-CloudExtensionAttribute1 у пользователей "Рогов и копыт", и добавить значения в группу "Компьютеры для тестирования" ==== get-aduser -Filter {Company -eq "Рога и копыта"} -SearchBase "OU=Users,DC=domain,DC=local" -Properties * | Select -expand msDS-CloudExtensionAttribute1 | foreach {Add-ADGroupMember -Identity "CN=Компьютеры для тестирования,OU=Группы компьютеров,OU=Resource,DC=domain,DC=local" -Members (Get-ADComputer $_)} ==== Извлечь компы из выгрузки из KSC и поместить их в соответствующие группы в AD для установки новых версий Хрома ==== $comps = Import-Csv "C:\Users\user\Desktop\Chrome.csv" -Delimiter "`t" |select -expand "Имя компьютера" | % {Get-ADComputer $_ -properties operatingsystem} $legacy,$new = $comps.where({$_.operatingsystem -match "XP|2003"}, 'Split') "Компьютеры для установки Google Chrome (Windows XP)" |Add-ADGroupMember -Members $legacy "Компьютеры для установки Google Chrome" |Add-ADGroupMember -Members $new ==== Имя компьютера, время входа в AD + файл ==== # write to file $file = "\\server\logons\$env:USERNAME.csv" $exist = Test-Path $file $t = get-date -Format "yyyy.MM.dd;HH:mm:ss" if ($exist -ne $true) {echo "Дата;Время;Логин;Компьютер" |Out-File $file -Encoding utf8} echo "$t;$env:USERNAME;$env:COMPUTERNAME" |Out-File $file -Encoding utf8 -Append # write last logged-on comp name to msds-cloudextensionattribute10 $Searcher = New-Object DirectoryServices.DirectorySearcher $Searcher.Filter = "(&(objectCategory=person)(anr=$env:username))" $Searcher.SearchRoot = 'LDAP://DC=domain,DC=ru' $path = $Searcher.FindOne() |select -expand path $user = [ADSI]"$path" $user.Put("msds-cloudextensionattribute10", "$env:computername") # write last bootup time to msds-cloudextensionattribute11 $boottime = Get-WmiObject win32_operatingsystem $boottime = $boottime.ConverttoDateTime($boottime.lastbootuptime) $boottime = $boottime.toString("dd.MM.yyyy HH:mm:ss") $user.Put("msds-cloudextensionattribute11", "$boottime") $user.SetInfo() На пользовательских машинах не установлены RSAT, поэтому Set-ADUser $env:username -Add @{'msDS-cloudExtensionAttribute1'="$env:computername"} не пройдёт. Дополнительно - примеры запросов к AD: #user properties $san = 'user' $getad = (([adsisearcher]"(&(objectCategory=User)(samaccountname=$san))").findall()).properties $getad #Computer properties $pc = 'computername' $getad = (([adsisearcher]"(&(objectCategory=Computer)(name=$pc))").findall()).properties $getad https://social.technet.microsoft.com/Forums/Lync/en-US/fd0b0a1c-b6dc-4657-8a95-21b6a11377df/using-ad-module-without-loading-rsat?forum=winserverpowershell\\ https://social.technet.microsoft.com/wiki/contents/articles/4231.working-with-active-directory-using-powershell-adsi-adapter.aspx\\ https://social.technet.microsoft.com/Forums/en-US/646ffe45-5ba5-461c-895f-a557e35cbc0d/need-to-set-extensionattribute1-of-an-adgroup-through-powershell ==== Найти пользователя в AD по части ФИО и показать информацию ==== [CmdletBinding()] Param( [Parameter(Mandatory=$True)] $user ) $cusers = get-aduser -Filter "(ObjectClass -eq 'user') -AND (SamAccountName -notlike '*.crm')" -SearchBase "dc=domain,dc=ru" |? Name -like "*$user*" foreach ($cuser in $cusers) { Get-ADUser $cuser -Properties * | select @{n="ФИО"; e={$_.Name}}, ` @{n="Логин"; e={$_.sAMAccountName}}, ` @{n="Кабинет"; e={$_.physicalDeliveryOfficeName}}, ` @{n="Телефон"; e={$_.telephoneNumber}}, ` @{n="Компания"; e={$_.'msDS-cloudextensionAttribute1'}}, ` @{n="Управление"; e={$_.'msDS-cloudextensionAttribute2'}}, ` @{n="Дирекция"; e={$_.'msDS-cloudextensionAttribute3'}}, ` @{n="Отдел"; e={$_.'msDS-cloudextensionAttribute4'}}, ` @{n="Служба"; e={$_.'msDS-cloudextensionAttribute5'}}, ` @{n="Группа"; e={$_.'msDS-cloudextensionAttribute6'}}, ` @{n="Должность"; e={$_.'msDS-cloudextensionAttribute7'}}, ` @{n="Имя компьютера"; e={$_.'msDS-cloudextensionAttribute10'}}, ` @{n="Время последней загрузки"; e={$_.'msDS-cloudextensionAttribute11'}} } pause ==== Генератор паролей ==== $length = 32 [int]$quarter = $length/4 [int]$residual = $length-$quarter*2 # if special are used # [int]$residual = $length-$quarter*3 $cletters = [char[]](0..255) -clike '[A-Z]' -notmatch "I|O|B" # except I, O, B $letters = [char[]](0..255) -clike '[a-z]' -notmatch "l" # except l $numbers = [char[]](0..255) -clike '[0-9]' -notmatch "1|0|8" # except 1, 0, 8 # $special = @("!","-","#","$","%","^","&","_",".",";") # add more if you need $rcletters = Get-Random -InputObject $cletters -count $quarter $rnumbers = Get-Random -InputObject $numbers -count $quarter # $rspecial = Get-Random -InputObject $special -count $quarter $rletters = Get-Random -InputObject $letters -count $residual $password = $rcletters + $rletters + $rnumbers # $password = $rcletters + $rletters + $rnumbers + $rspecial $password = (Get-Random -InputObject $password -count $length) -join "" $password # x = length in characters # y = minimum number of non-alphanumeric characters Add-Type -AssemblyName System.web [System.Web.Security.Membership]::GeneratePassword(x,y) ==== ФИО в логин ==== $src = Import-Excel 'C:\scripts\Список сотрудников.xlsx' -StartRow 4 -StartColumn 2 |select -expand ФИО $alldata = @() foreach ($fio in $src) { $login = $fio -split " " $f = $login[0] $i = ($login[1]).substring(0,1) $o = ($login[2]).substring(0,1) $login = $f + $i + $o # ьи, ье, ьё - Ильин, yuyu, yaya - Юлия Юрьевна $login = $login -replace 'ий','y' -replace 'ый','y' -replace 'ьи','yi' -replace 'ье','ye' -replace 'ьё','ye' ` -replace 'а','a' -replace 'б','b' -replace 'в','v' -replace 'г','g' -replace 'д','d' -replace 'е','e' ` -replace 'ё','e' -replace 'ж','zh' -replace 'з','z' -replace 'и','i' -replace 'й','y' -replace 'к','k' ` -replace 'л','l' -replace 'м','m' -replace 'н','n' -replace 'о','o' -replace 'п','p' -replace 'р','r' ` -replace 'с','s' -replace 'т','t' -replace 'у','u' -replace 'ф','f' -replace 'х','kh' -replace 'ц','ts' ` -replace 'ч','ch' -replace 'ш','sh' -replace 'щ','sch' -replace 'ь' -replace 'ы','y' -replace 'ъ' ` -replace 'э','e' -replace 'ю','yu' -replace 'я','ya' -replace 'yuyu','yy' -replace 'yaya','yy' ` -join "" $raw = [pscustomobject]@{ FIO = $fio Login = $login } $alldata += $raw } $alldata # $alldata |Export-Csv c:\temp\logins.csv -Delimiter ';' -Encoding utf8 -NoTypeInformation ==== Скопировать группы, содержащие "КТ " из одной учётки в другую ==== [CmdletBinding()] Param( [Parameter(Mandatory=$True)] $from, [Parameter(Mandatory=$True)] $to ) $CopyFromUser = Get-ADPrincipalGroupMembership $from |where {$_.name -like '*КТ *'} $CopyToUser = Get-ADPrincipalGroupMembership $to $CopyFromUser | Where{$CopyToUser -notcontains $_} | Add-ADGroupMember -Member $to ==== Добавить комп в группу ==== [CmdletBinding()] Param( [Parameter(Mandatory=$True)] $comp ) add-ADGroupMember -Identity "Компьютеры для установки КриптоПро CSP 4.0.9944" -Members (get-adcomputer $comp) # Добавить много компов "Имя группы" |Add-ADGroupMember -Members ` ("pc1722","pc1723","pc1724","pc1725","pc1726","pc1727","pc1728","pc1729","pc1730","pc1731" |Get-ADComputer) ==== Показать включённых юзеров с датой входа более 2 недель ==== get-aduser -SearchBase "OU=Административный департамент,OU=Users,domain,DC=ru" -Properties lastlogondate -Filter {enabled -eq $true} | ? Lastlogondate -lt (Get-Date).Adddays(-14) |sort lastlogondate -Descending |ft name,lastlogondate ==== Лог входов в систему ==== $file = "\\server\logon-log\$env:USERNAME.csv" $exist = Test-Path $file $t = get-date -Format "yyyy.MM.dd;HH:mm:ss" if ($exist -ne $true ) { echo "Дата;Время;Логин;Компьютер" |Out-File $file -Encoding utf8 } echo "$t;$env:USERNAME;$env:COMPUTERNAME" |Out-File $file -Encoding utf8 -Append Запуск из GPO: %WINDIR%\System32\WindowsPowerShell\v1.0\powershell.exe -ExecutionPolicy Bypass -File \\path-to-server\scripts\logon-log.ps1 ==== Список учёток с неправильно заполненными инициалами ==== Get-ADUser -filter 'name -like "*на" -or name -like "*ич"' -SearchBase "OU=1_Users,OU=test,DC=domain,DC=ru" -Properties initials | ? initials -notmatch '\w\. \w\.' |select -expand name |sort ==== Поставить галку "Защитить объект от случайного удаления" для всех OU домена ==== Get-ADOrganizationalUnit -filter * |Set-ADOrganizationalUnit -ProtectedFromAccidentalDeletion $true ===== Настройка локальных машин ===== ==== Отключение энергосбережения для сетевого адаптера ==== # Disable "Allow the computer to turn off the device to save power" foreach ($id in (gwmi win32_networkadapter |? {$_.physicaladapter -and $_.name -notmatch "virtual|wireless|microsoft" -and $_.Manufacturer -ne "Microsoft"}).deviceid) { Set-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Control\Class\{4d36e972-e325-11ce-bfc1-08002be10318}\$('{0:d4}' -f [int]$id)" -Name PnPCapabilities -Value 24 } # Вариант выборки сетевого адаптера: # gwmi Win32_NetworkAdapter |? {$_.PNPDeviceID -notlike "ROOT\*" -and $_.Manufacturer -ne "Microsoft" -and $_.ConfigManagerErrorCode -eq 0} https://support.microsoft.com/en-us/help/2740020/information-about-power-management-setting-on-a-network-adapter\\ https://techcommunity.microsoft.com/t5/exchange-team-blog/do-you-have-a-sleepy-nic/ba-p/590996\\ https://gallery.technet.microsoft.com/scriptcenter/Disable-turn-off-this-f74e9e4a ==== Информация по TCP-соединениям ==== $comps = "PC1708","PC1163" foreach ($comp in $comps) { Invoke-Command -ComputerName $comp -ScriptBlock { netstat -vb } |Out-File c:\temp\$comp.txt } foreach ($comp in $comps) { "--- $comp ---" (gc c:\temp\$comp.txt) -match '\[.*\]' |group } --- PC1708 --- Count Name Group ----- ---- ----- 33 [svchost.exe] { [svchost.exe], [svchost.exe], [svchost.exe], [svchost.exe]...} 1 [1cv8c.exe] { [1cv8c.exe]} 492 [Iwproxy.exe] { [Iwproxy.exe], [Iwproxy.exe], [Iwproxy.exe], [Iwproxy.exe]...} 1 [1cv8.exe] { [1cv8.exe]} 5 [OUTLOOK.EXE] { [OUTLOOK.EXE], [OUTLOOK.EXE], [OUTLOOK.EXE], [OUTLOOK.EXE]...} 244 [chrome.exe] { [chrome.exe], [chrome.exe], [chrome.exe], [chrome.exe]...} 4 [IWDeployAgent.exe] { [IWDeployAgent.exe], [IWDeployAgent.exe], [IWDeployAgent.exe], [IWDeployAgent.exe]} 6 [iwdmc.exe] { [iwdmc.exe], [iwdmc.exe], [iwdmc.exe], [iwdmc.exe]...} 2 [iwshcs.exe] { [iwshcs.exe], [iwshcs.exe]} 2 [LMS.exe] { [LMS.exe], [LMS.exe]} 2 [DM.Client.exe] { [DM.Client.exe], [DM.Client.exe]} --- PC1163 --- 456 [Iwproxy.exe] { [Iwproxy.exe], [Iwproxy.exe], [Iwproxy.exe], [Iwproxy.exe]...} 3 [OUTLOOK.EXE] { [OUTLOOK.EXE], [OUTLOOK.EXE], [OUTLOOK.EXE]} 1 [spoolsv.exe] { [spoolsv.exe]} 1 [1cv8c.exe] { [1cv8c.exe]} 1 [1cv8.exe] { [1cv8.exe]} 228 [chrome.exe] { [chrome.exe], [chrome.exe], [chrome.exe], [chrome.exe]...} 4 [IWDeployAgent.exe] { [IWDeployAgent.exe], [IWDeployAgent.exe], [IWDeployAgent.exe], [IWDeployAgent.exe]} 6 [iwdmc.exe] { [iwdmc.exe], [iwdmc.exe], [iwdmc.exe], [iwdmc.exe]...} 2 [iwshcs.exe] { [iwshcs.exe], [iwshcs.exe]} 2 [DM.Client.exe] { [DM.Client.exe], [DM.Client.exe]} ===== Таблички, отчёты, массивы ===== ''+='' удаляет старый и создаёт новый массив, т. к. он фиксированного размера, и при большом кол-ве элементов работает очень медленно.\\ Лучше использовать ''[System.Collections.ArrayList]'' или ''[System.Collections.Generic.List[]]'' https://batishchev.ru/blog/all/arraylist-i-proizvoditelnost-massivov-v-powershell/\\ https://adamtheautomator.com/powershell-array/ $arrayList = [System.Collections.ArrayList]::new() $arrayList.add("aaa") > $null ''[System.Collections.Generic.List[]]'' - [[https://learn.microsoft.com/ru-ru/powershell/scripting/learn/deep-dives/everything-about-arrays?view=powershell-7.4#generic-list|универсальный список]] с возможностью указания типа массива. Что удобно - в отличие от ArrayList метод Add не возвращает значение, поэтому для него не нужно выполнять void. $a = [System.Collections.Generic.List[int]]::new() # числовой массив $a = [System.Collections.Generic.List[string]]::new() # строковый массив $a = [System.Collections.Generic.List[object]]::new() # любой тип объектов ==== Добавить строку в отчёт с двумя столбцами ==== $report += New-Object -TypeName psobject -Property @{folder="Всего каталогов"; sizeMB="$($report.folder.count)"} ==== Цвет затенения для строк ==== Для использования в html для фонового цвета перемежающихся строк * #EDEDED - очень светлый серый. * #D9D9D9 - серый чуть потемнее. * #DBDBDB - серый. У Экселя есть шаблон, где он перемежается с #EDEDED. * #A5A5A5 - серый темнее. Лучше пользоваться уже белым шрифтом. * #7B7B7B - тёмно-серый. У Экселя есть шаблон, где он перемежается с #A5A5A5. ==== Массив русского алфавита с индексом ==== Почему не ''[char[]](0..65535) -clike '[а-я]''' - там не будет буквы ё. Поэтому $alfabetRus = @("а","б","в","г","д","е","ё","ж","з","и","й","к","л","м","н","о", "п","р","с","т","у","ф","х","ц","ч","ш","щ","ъ","ы","ь","э","ю","я") $alfabetRus |select @{n="letter";e={$_}},@{n="index";e={$alfabetRus.indexof($_)+1}} letter index ------ ----- а 1 б 2 в 3 ... Можно вычислить индексы символов и потом вставить их в массив для выбора $allchars = [char[]](0..65535) ($allchars |select @{n="letter";e={$_}},@{n="index";e={$allchars.indexof($_)}}) -cmatch '[а-яё]' # А-Я 1140..1071 # а-я 1072..1103 # Ё,ё 1025,1105 # A-Z 65..90 # a-z 97..122 $alfabetRus = [char[]](1072..1077+1105+1078..1103) $alfabetRus |select @{n="letter";e={$_}},@{n="index";e={$alfabetRus.indexof($_)+1}} ==== Разбить массив на части определённого размера ==== $list = 1..1018 $chunkSize = 100 $c = [pscustomobject]@{Value = 0} $groups = $list |group {[math]::Floor($c.Value++ / $chunkSize)} $groups[0].group https://stackoverflow.com/questions/13888253/powershell-break-a-long-array-into-a-array-of-array-with-length-of-n-in-one-line ===== Файловые операции ===== ==== Удалять из папки все файлы старше текущего месяца, кроме файлов от 1, 15 и последнего дня месяца ==== $path="\\server\backups\folder" $files=get-childitem $path $currentmonth=(get-date).Month foreach ($file in $files) { if (($file.lastwritetime).Month -ne $currentmonth -and ($file.lastwritetime).day -ne 15 -and ($file.lastwritetime).day -ne 1 -and ($file.lastwritetime).Month -eq (($file.lastwritetime).adddays(1)).Month) { Remove-Item $path\$file -Force -Recurse } } ==== Удалить все файлы, кроме последних 10 ==== gci | sort CreationTime | select -skip 10 | Remove-item -Force ==== Пакетное переименование файлов ==== Дано:\\ Pet Shop Boys - Happiness-47208322.mp3\\ Pet Shop Boys - The Pop Kids-47208325.mp3 [int]$n = 1 $files = dir 'D:\music\Pet Shop Boys - Super (2016)' -File |sort creationtime foreach($file in $files) { $a = $n.ToString("00") Rename-Item $file -NewName ($file.name -replace "^","$a ") $n = $n+1 } dir |Rename-Item -NewName {$_.name -replace "-\d+"} # сделать плейлист с именем как у текущего каталога $plsname = (Get-ItemProperty .).name (dir -file *.mp3).name |out-file .\"$plsname.m3u" -Encoding UTF8 Результат:\\ 01 Pet Shop Boys - Happiness.mp3\\ 02 Pet Shop Boys - The Pop Kids.mp3 https://devblogs.microsoft.com/scripting/hey-scripting-guy-how-can-i-use-leading-zeroes-when-displaying-a-value-in-windows-powershell/ Дано:\\ 1 - Introduction.mp4\\ 10 - Lesson 1 Lab.mp4\\ 100 - Understanding Why Decoupling is Important.mp4 $files = dir 'D:\Видео\Video Collection' foreach ($file in $files) { $num,$rest = $file.name -split ' - ',2 Rename-Item $file.FullName -NewName "$(([int]$num).ToString("000")) - $rest" #-WhatIf } Результат:\\ 001 - Introduction.mp4\\ 010 - Lesson 1 Lab.mp4\\ 100 - Understanding Why Decoupling is Important.mp4 ==== Сортировка ==== Если отсортировать файлы вида file1.txt - file100.txt, то выйдет file1.txt file10.txt file11.txt ... file18.txt file19.txt file2.txt file20.txt file21.txt и т. д. Чтобы отсортировать по-человечески: dir "C:\temp\folder\*.txt" |sort {[int]($_.basename -replace '\D')} ==== Посмотреть квоты на файловом сервере ==== Get-FSRMQuota |? path -Match 'отдел' |select @{n='Путь';e={$_.path}},@{n='Использовано (ГБ)';e={$_.usage / 1GB -as [int]}},@{n='Всего (ГБ)';e={$_.size / 1GB -as [int]}} ==== Ожидание снятия блокировки файла и копирование ==== function Test-FileLock { param ( [parameter(Mandatory=$true)][string]$Path ) $oFile = New-Object System.IO.FileInfo $Path if ((Test-Path -Path $Path) -eq $false) { return $false } try { $oStream = $oFile.Open([System.IO.FileMode]::Open, [System.IO.FileAccess]::ReadWrite, [System.IO.FileShare]::None) if ($oStream) { $oStream.Close() } return $false } catch { return $true # file is locked by a process } } $from = '\\example.com\share\users\Mihailov-20230320.pst' $to = '\\pc01\c$\Users\Soloviev\Documents\Файлы Outlook' do { sleep 30 } until (-not (Test-FileLock $from)) Write-Host -fore green "Copying..." cp $from $to # Test-Path "$to\$((Get-Item $from).name)" https://stackoverflow.com/questions/24992681/powershell-check-if-a-file-is-locked ==== Создание тестовых файлов с датами изменения и создания в прошлом ==== $t = Get-Date $folder = "D:\temp\from" 1..100 |% { $fileTime = $t.AddDays(-$_) $fileBaseName = $fileTime.ToString("yyyy.MM.dd") $filePath = "$folder\$fileBaseName.txt" $file = New-Item $filePath -ItemType File Set-Content $filePath -Value $fileBaseName $file.CreationTime = $fileTime $file.LastWriteTime = $fileTime } ==== Удалить файл из корзины ==== $file = 'C:\temp\out — копия (3).txt' (New-Object -ComObject Shell.Application).NameSpace(0x0a).Items() |? { ($_.ExtendedProperty("{9B174B33-40FF-11D2-A27E-00C04FC30871} 2") + '\' + $_.name + '.' + ($_.path -replace '.*\.')) -eq $file } |del ===== Работа с текстом ===== Программа для создания большого файла txt: [[https://www.mynikko.com/dummy/|Dummy File Creator]]. ==== Конвертировать строку во время ==== $folder = "D:\temp\20211025" $reportDate = [datetime]::parseexact($folder.Split("\")[-1], 'yyyyMMdd', $null) 25 октября 2021 г. 0:00:00 https://stackoverflow.com/questions/38717490/convert-a-string-to-datetime-in-powershell ==== Убрать из файла все строки, содержащие плюс ==== (Get-Content "C:\temp\test.txt") -notmatch '\+' |Set-Content "C:\temp\test-out.txt" http://stackoverflow.com/questions/39828780/delete-lines-containing-specific-character-in-text-file ==== Каждое слово с большой буквы ==== (Get-Culture).TextInfo.ToTitleCase('текст, каждое слово которого будет начинаться с большой буквы') ==== Фильтр отчётов Cobian Backup ==== cd D:\Downloads Expand-Archive .\Журналы.zip cd .\Журналы gc *.txt |Select-String ERR |out-file -width 30000 .\errors.txt Invoke-Item .\errors.txt ==== Выбрать каждую N строку в файле ==== # каждую 1, 5, 9, 13, 17 и т. д. gc "D:\temp\test.txt" |? {($_.ReadCount % 4) -eq 1} ==== Замена ошибок в тексте (afterscan) ==== FIXME -replace '([\.\,\?\!])(\w)','$1 $2' ` # Добавить пробел между знаками препинания и следующим словом -replace '\s+([\.\,\?\!])','$1' ` # Убрать пробел между словом и знаком препинания -replace "\s+$" ` # Убрать пробелы в конце строки -replace "…","..." ` # Заменить символ троеточия на реальные три точки -replace '(\d)(\D)','$1 $2' ` # Добавить пробел между числом и следующим за ним словом -replace "\.$",".`n" # Добавить пустую строку, если строка заканчивается точкой -replace '(?<=\d)(\s+)?([\.\:])(\s+)?(\d+)','$2$4' # Убрать пробелы в датах (где между цифрами . и :) ==== Обработка больших файлов ==== Надо применять методы .NET и упаковывать regex, т. к. ''get-content'' очень медленный. function ExtractTo-Chunk ($in,$out,$regex) { [regex]$regex = $regex [System.IO.File]::AppendAllText("$out", ([System.IO.File]::ReadAllLines("$in") -match $regex -join [Environment]::NewLine)) } ExtractTo-Chunk -in "C:\temp\big.log" -out "C:\temp\chunk1.log" -regex "192.168.1.10" ExtractTo-Chunk -in "C:\temp\big.log" -out "C:\temp\chunk1.log" -regex "10.0.0.8" [[https://www.serverbrain.org/system-administration/reading-large-text-files-with-powershell.html|Reading large text files with Powershell]]\\ [[https://stackoverflow.com/questions/55468899/speed-issue-on-match-operation-for-large-text-file|Speed issue on -match operation for large text file]]\\ [[https://learn.microsoft.com/en-us/powershell/scripting/dev-cross-plat/performance/script-authoring-considerations?view=powershell-7.3|PowerShell scripting performance considerations]] Быстрое чтение файла в массив: [io.file]::readalllines("C:\temp\file.txt") [io.file]::readalllines("C:\temp\file.txt",[System.Text.Encoding]::UTF8) [io.file]::readalllines("C:\temp\file.txt",[System.Text.Encoding]::GetEncoding('windows-1251')) ==== Склонение слов в предложении с числительным ==== function Get-Declension ($pre1,$n,$w1,$w2,$w5) { switch -Regex ($n) { '(? ==== Список модулей PHP из буфера по алфавиту и с переносом строки ==== $list = (Get-Clipboard) -replace '\s+\\$' |sort $total = $list.count $c = 1 $list |% { if ($c -eq $total) {$_} else {$_ + " \"} $c++ } |Set-Clipboard Исходный список php81-fpm \ php81-phar \ php81-iconv \ php81-mbstring \ php81-openssl \ php81-curl \ php81-dom \ php81-pdo_mysql \ php81-exif \ php81-pcntl \ php81-bcmath \ php81-ctype \ php81-gd \ php81-soap \ php81-zip \ php81-sockets \ php81-session \ php81-fileinfo \ php81-tokenizer \ php81-simplexml \ php81-xml \ php81-xmlreader \ php81-xmlwriter php81-redis Результат php81-bcmath \ php81-ctype \ php81-curl \ php81-dom \ php81-exif \ php81-fileinfo \ php81-fpm \ php81-gd \ php81-iconv \ php81-mbstring \ php81-openssl \ php81-pcntl \ php81-pdo_mysql \ php81-phar \ php81-redis \ php81-session \ php81-simplexml \ php81-soap \ php81-sockets \ php81-tokenizer \ php81-xml \ php81-xmlreader \ php81-xmlwriter \ php81-zip ==== Замена многострочного блока ==== Управление групповой политикой body { font-size:68%;font-family:MS Shell Dlg; margin:0px,0px,0px,0px; border: 1px solid #666666; background:#F6F6F6; width:100%; ... overflow:visible; } button { display:none; } .head { color:#000000; background:#FFFFFF; border:1px solid #000000; } } Путь размещения параметров: Объяснение (gc 'D:\Downloads\file.txt' -Raw) -replace 'body((.|\n)*)\} \}' ==== Замена нескольких пустых строк на одну ==== (gc 'D:\Downloads\file.txt' -Raw) -replace '(\r?\n){2,}', '$1$1' ==== Преобразование строк в таблицу ==== Opera Hotlist version 2.0 Options: encoding = utf8, version=3 #CONTACT ID=11 NAME=Justynka CREATED=1195505237 MAIL=JUSTYNA66@gmail.com ICON=Contact0 #CONTACT ID=12 NAME=Leszek CREATED=1195677687 MAIL=Leszek@domena.pl ICON=Contact0 #CONTACT ID=13 NAME=Iwona Kwiatkowska CREATED=1196277590 MAIL=iwon.kwiat@op.pl ICON=Contact0 #FOLDER ID=15 NAME=Kosz CREATED=1195505227 TRASH FOLDER=YES UNIQUEID=EAF22324295C86499476802CC76DE41E - #CONTACT ID=16 NAME=Ania CREATED=1195505237 MAIL=Ania.Nowak@poczta.com ICON=Contact0 Вычистить ненужные строки и мусор, разделить текст на сегменты, создать структурированные объекты. Разделителем для ''ConvertFrom-StringData'' должен быть ''=''. (Get-Content .\opera.adr -Raw) -replace '^Opera[\s\S]*?#CONTACT' -split '#CONTACT|#FOLDER' |% { $props = ConvertFrom-StringData -StringData ($_ -replace '\n-\s+') New-Object PSOBject -Property $props |select Name, Mail } https://powershellmagazine.com/2014/09/09/using-the-convertfrom-string-cmdlet-to-parse-structured-text/\\ https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/convertfrom-stringdata?view=powershell-5.1 ===== Графика ===== ==== Диаграммы ==== На примере ежечасно снимаемых логов вошедших по VPN пользователей. Add-Type -AssemblyName System.Windows.Forms Add-Type -AssemblyName System.Windows.Forms.DataVisualization $Chart = New-Object -TypeName System.Windows.Forms.DataVisualization.Charting.Chart $Chart.Size = '800,400' $ChartArea = New-Object -TypeName System.Windows.Forms.DataVisualization.Charting.ChartArea $ChartArea.AxisX.Title = 'Часы' $ChartArea.AxisY.Title = 'Кол-во пользователей' $ChartArea.AxisX.Interval = '1' $ChartArea.AxisX.LabelStyle.Enabled = $true $ChartArea.AxisX.LabelStyle.Angle = 90 $ChartArea.AxisX.MajorGrid.Enabled = $false # No grid $ChartArea.AxisY.MajorGrid.Enabled = $false # No grid $Chart.ChartAreas.Add($ChartArea) $Chart.Series.Add('VPNUsers') > $null $Chart.Series['VPNUsers'].IsValueShownAsLabel = $true # Show values on columns' tops # Chart type - Column $Chart.Series['VPNUsers'].ChartType = [System.Windows.Forms.DataVisualization.Charting.SeriesChartType]::Column # Looping files $txtFiles |% { $hour = $_.BaseName -replace ".*-" -replace "\d{4}$" $usersCount = (gc $_.FullName |% {($_ -split "'")[1]} |sort -Unique).count $Value = $Chart.Series['VPNUsers'].Points.AddXY("$hour","$usersCount") } # Title $Title = New-Object -TypeName System.Windows.Forms.DataVisualization.Charting.Title $Chart.Titles.Add($Title) $Chart.Titles[0].Text = 'Статистика по часам' # Saving PNG file $png = "$env:temp\VPNUsersChart.png" $Chart.SaveImage("$png", "PNG") {{:scripts:pasted:20200813-150710.png?450}}{{:scripts:pasted:20200814-150314.png?600}} https://www.powershellbros.com/building-first-chart-report-powershell/\\ https://learn-powershell.net/2016/09/18/building-a-chart-using-powershell-and-chart-controls/\\ https://stackoverflow.com/questions/6413182/how-to-display-values-in-asp-net-chart-control\\ https://stackoverflow.com/questions/1058572/hiding-the-gridlines-on-an-asp-net-chart-control/1368853 ===== Интернет ===== ==== Скачать файлы по списку ==== $url = "https://reasonstation.nl/downloads/yamaha/mp3-midi/" $pattern = ".MID" (curl $url).links |select -expand href |Select-String -SimpleMatch "$pattern" | % { $f = $url + $_ curl $f -OutFile "$env:userprofile\Downloads\$_" } ==== Отправить письмо ==== Без запроса пароля. # Сохранение шифрованного пароля в файл Read-Host -AsSecureString | ConvertFrom-SecureString | Out-File C:\temp\securestring.txt $pass = cat C:\temp\securestring.txt | convertto-securestring $mycred = new-object -typename System.Management.Automation.PSCredential -argumentlist "username",$pass # С Яндекса Send-MailMessage -SmtpServer smtp.yandex.ru -UseSsl -Encoding utf8 -From "username@yandex.ru" -Subject "Test message" -Body "Body of test message" -To "username@domain.com" -Credential $mycred ==== Игнорировать самоподписанный сертификат SMTP ==== [System.Net.ServicePointManager]::ServerCertificateValidationCallback = { return $true } Send-MailMessage -SmtpServer "mail.example.com" -from "script@example.com" -to "user@example.com" -Subject "Hello" -body "

Hello

" -BodyAsHtml -Encoding UTF8 -UseSsl
==== Письмо с картинкой в тексте ==== Send-MailMessage -To "testovtt@domain.ru" -From "birthday@domain.ru" ` -SmtpServer "mail.domain.ru" -Subject "С днём рожденья!" ` -Body "

Уважаемый Тест Тестович!

Поздравляю вас с днём рождения!

С уважением, скрипт.

" -Attachments "C:\scripts\birthday.jpg" -BodyAsHtml -Encoding utf8
https://stackoverflow.com/questions/52837468/embed-images-in-email-and-send-via-powershell ==== Сколько дней осталось до окончания действия SSL-сертификата ==== С помощью curl (надо [[https://curl.se/windows/|скачивать с сайта]], встроенный в винду многого не умеет) $urls = @( "google.com" "mail.ru" "yandex.ru" "kubernetes.io" ) #$urls = gc "C:\temp\sites.txt" |sort $t = get-date function Decode-UnicodeEscaped { param([string]$str) # decode if unicode escaped strings # https://stackoverflow.com/questions/18450218/unescape-unicode-string-powershell [Regex]::Replace($str, "\\[Uu]([0-9A-Fa-f]{4})", {[char]::ToString([Convert]::ToInt32($args[0].Groups[1].Value, 16))} ) } $report = @() $urls |% { $dump = & C:\scripts\curl\curl.exe "https://$_" -Iv --stderr - $issuer = $dump -match "issuer:" -replace ".+: " $expdate = $dump -match "expire date:" -replace ".+: " -replace "\s+"," " $expdate = Get-Date $("{0} {3} {1} {2} {4}" -f "$expdate".Split()) $obj = [pscustomobject]@{ Сайт = $_ 'Конец срока действия' = $expdate 'Осталось дней' = if ($expdate) {($expdate - $t).days}; 'УЦ' = Decode-UnicodeEscaped $issuer } $report += $obj Remove-Variable dump,expdate,issuer } $report |sort 'Конец срока действия' https://nickjanetakis.com/blog/using-curl-to-check-an-ssl-certificate-expiration-date-and-details Рабочие методы в чистом Powershell: https://habr.com/ru/company/t1_cloud/blog/661107/\\ Ранее работавший метод: https://stackoverflow.com/a/20014855 ==== Получить HTML-объекты определённого класса ==== $url = "https://jut.su/naruuto/season-2/episode-301.html" # Нужно указать первый элемент [0], даже если он единственный. (iwr $url).ParsedHtml.body.getElementsByClassName('header_video anime_padding_for_title_post_naruto')[0].innertext https://stackoverflow.com/a/17625740 ===== Информация ===== Вывод системной информации: # Computer name $comp = $env:COMPUTERNAME # login $login = $env:username # Full user name $fullusername = ([adsi]"WinNT://$env:userdomain/$env:username,user").fullname # IP address $ip = Get-NetIPAddress -AddressFamily IPv4 | where {$_.interfacealias -NotLike '*Loopback*' -AND $_.interfacealias -NotLike '*virtual*'} | select ipaddress -ExpandProperty ipaddress # MAC $mac = Get-NetAdapter -Physical | select macaddress -ExpandProperty macaddress # IP и MAC для PoSH старых версий # Get-WmiObject -Class Win32_NetworkAdapterConfiguration -Filter "IPEnabled = True" | where {$_.description -notlike '*virtual*'} |select IPAddress,MACAddress |fl @{n="IP"; e={$_.IPAddress}},@{n="MAC"; e={$_.MACAddress}} # Time mark $mark = get-date -UFormat "%d.%m.%Y %H:%M" echo "Имя компьютера: $comp" echo "Логин пользователя: $login" echo "ФИО пользователя: $fullusername" echo "IP: $ip" echo "MAC: $mac" echo "Время подготовки отчёта: $mark" ==== Список установленных программ ==== # Узнать удалённо, что стоит на server1 Invoke-Command -cn server1 -ScriptBlock {Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* | select DisplayName,DisplayVersion,Publisher,InstallDate,UninstallString} # Для 32-битных приложений на 64-битной ОС: # HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* # Вариант через Get-WmiObject (медленно) gwmi win32_product -ComputerName server1 -Filter "Name like 'Microsoft Office%'" https://devblogs.microsoft.com/scripting/use-powershell-to-find-installed-software/\\ https://social.technet.microsoft.com/Forums/en-US/dc42dd1d-737e-4f64-8fe2-e421f655836f/powershell-script-to-identify-office-version-on-a-remote-system-using-computer-name?forum=ITCG Универсальный вариант: https://serverfault.com/questions/1111419/how-to-get-a-complete-list-of-all-installed-software-via-powershell ==== Создание окон ==== [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") [System.Windows.Forms.MessageBox]::Show("Message Text","Title",1,48) Первое число:\\ 0 OK\\ 1 OKCancel\\ 2 AbortRetryIgnore\\ 3 YesNoCancel\\ 4 YesNo\\ 5 RetryCancel Второе число:\\ 0 None\\ 16 Hand\\ 16 Error\\ 16 Stop\\ 32 Question\\ 48 Exclamation\\ 48 Warning\\ 64 Asterisk\\ 64 Information https://michlstechblog.info/blog/powershell-show-a-messagebox/ ==== Температура процессора ==== ((gwmi -Namespace root\wmi MSAcpi_ThermalZoneTemperature).CurrentTemperature |sort |select -last 1) / 100 CMD: @echo off for /f "skip=1 tokens=2 delims==" %%A in ('wmic /namespace:\\root\wmi PATH MSAcpi_ThermalZoneTemperature get CurrentTemperature /value') do set /a "HunDegCel=(%%~A*10)-27315" echo %HunDegCel:~0,-2%.%HunDegCel:~-2% Degrees Celsius pause ==== Аптайм ==== read-host "Имя компа" |Set-Variable n gcim win32_operatingsystem -computername $n | select Caption,Version,@{Name="Uptime";Expression={(Get-Date) - $_.lastBootUpTime}},PScomputername ==== Даты установки Windows ==== $report = gci -Path HKLM:\System\Setup\Source* |% { Get-ItemProperty -Path Registry::$_} | select ProductName, ReleaseID, CurrentBuild, @{n="InstallDate"; e={([DateTime]'1/1/1970').AddSeconds($_.InstallDate)}} | sort {[int]($_.CurrentBuild)} $report += gcim Win32_OperatingSystem |select @{n='ProductName';e={($_.Caption -replace 'майкрософт').Trim()}},ReleaseID,@{n='CurrentBuild';e={$_.BuildNumber}},InstallDate $report ProductName ReleaseID CurrentBuild InstallDate ----------- --------- ------------ ----------- Windows 10 Pro 10240 08.02.2016 7:39:56 Windows 10 Pro 1511 10586 08.02.2016 8:51:37 Windows 10 Pro 1607 14393 04.09.2016 14:17:50 Windows 10 Pro 1703 15063 10.07.2017 7:48:10 Windows 10 Pro 1709 16299 18.10.2017 19:55:47 Windows 10 Pro 1803 17134 04.05.2018 3:53:16 Windows 10 Pro 1809 17763 23.12.2018 20:11:00 Windows 10 Pro 1909 18363 06.12.2019 18:23:14 Windows 10 Pro 2009 19044 06.06.2020 6:43:13 Windows 11 Pro 22000 23.02.2022 12:42:49 ==== Состояние диска ==== FIXME Добавить проверку и отправку писем, если статус не ОК $i = gcim Win32_DiskDrive |? Partitions -gt 0 | select SystemName,Model,@{n='Size(GB)';e={$_.Size / 1GB -as [int]}},InterfaceType,Status,MediaType,SerialNumber if ($i.Status -ne "OK") {Write-Host "Что-то с жёстким диском!";$i} ==== Total LBAs Written в мегабайты/гигабайты/терабайты ==== [single]$lbaWritten = Read-Host "Введите кол-во записанных LBA" [single]$lbaSize = Read-Host "Введите размер блока, если он отличается от стандартного 512 КБ" if (-not $lbaSize) {$lbaSize = 512} $bytes = $lbaWritten * $lbaSize Write-Host -fore Yellow "`nЗаписано на диск:" "$($bytes / 1MB -as [int]) МБ" "$($bytes / 1GB -as [int]) ГБ" "$(($bytes / 1TB).tostring("0.00")) ТБ" ==== Сокращение десятичных знаков, округление ==== @{n='Size(MB)';e={($_.Length/1MB).ToString("#.##")}} # строка [math]::round((0.4265867),2) # число 0,43 ==== Внешний IP ==== curl https://2ip.ru ==== Поиск свободного IP в сети ==== 1..254 |% { $ip = "10.1.0.$_" if (-not (Test-Connection $ip -Count 1 -Quiet)) { $ip } } ==== Потребление памяти несколькими одноимёнными процессами ==== get-process firefox |group name |select name,@{n='Memory(MB)';e={(($_.group.workingset |measure -sum).sum / 1mb).ToString('#.##')}} ==== Пути каталогов в профиле и системе ==== # Перечислить [enum]::getnames([environment+specialfolder]) AdminTools ApplicationData CDBurning CommonAdminTools CommonApplicationData CommonDesktopDirectory CommonDocuments CommonMusic ... # Вывести путь [environment]::getfolderpath('startup') C:\Users\username\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup ===== Реестр ===== $regPath = "HKCU:\Software\Microsoft\Office\16.0\Outlook\Options\Mail" New-ItemProperty -Path $regPath -Name JunkMailImportLists -PropertyType Dword -Value 1 -Force > $null Список значений ''-PropertyType''. Binary REG_BINARY DWord REG_DWORD ExpandString REG_EXPAND_SZ MultiString REG_MULTI_SZ None No data type QWord REG_QWORD String REG_SZ https://learn.microsoft.com/en-us/dotnet/api/microsoft.win32.registryvaluekind ===== Прочее ===== ==== Таймер ==== $timer = [system.diagnostics.stopwatch]::StartNew() [math]::round(($timer.Elapsed.TotalSeconds),2) $timer.IsRunning True $timer.Stop() https://www.pluralsight.com/blog/tutorials/measure-powershell-scripts-speed ==== Секунды в dd.hh:mm:ss ==== [timespan]::fromseconds("336621").tostring() 3.21:30:21 ==== Текст в речь ==== $currentdate = (get-date).ToLongDateString() $currenttime = (get-date).ToLongTimeString() Add-Type -AssemblyName System.speech $speak = New-Object System.Speech.Synthesis.SpeechSynthesizer $speak.Speak("Сегодня $currentdate, текущее время $currenttime") https://learn-powershell.net/2013/12/04/give-powershell-a-voice-using-the-speechsynthesizer-class/ ==== Скриншот ==== [void][reflection.assembly]::loadwithpartialname("system.windows.forms") [system.windows.forms.sendkeys]::sendwait('{PRTSC}') Get-Clipboard -Format Image | ForEach-Object -MemberName Save -ArgumentList "c:\temp\screenshot.png" https://www.reddit.com/r/PowerShell/comments/9y9689/take_a_screenshot_with_powershell/ ==== Установить/обновить Powershell 7 ==== Windows: iex "& { $(irm https://aka.ms/install-powershell.ps1) } -UseMSI" Linux: wget https://aka.ms/install-powershell.sh; sudo bash install-powershell.sh; rm install-powershell.sh https://www.thomasmaurer.ch/2019/07/how-to-install-and-update-powershell-7/ ==== Запуск скрипта Powershell из-под PSExec ==== @echo off title Install Powershell 5.1 set /P COMP=computername: psexec.exe \\%COMP% /s /h cmd /c powershell -executionpolicy bypass -file "\\domain.ru\share\Powershell\Win7-install-PS51.ps1" ==== Обработка объектов, перетащенных на ярлык ==== # Ярлык powershell -f "C:\temp\drag-drop.ps1" # вариант powershell -noexit -noprofile -f "C:\temp\drag-drop.ps1" При перетаскивании на ярлык в ''$args'' попадают полные пути объектов. # Получить список файлов $inputFiles = @() $args |% { if ((get-item "$_").mode -match "^d") { $inputFiles += dir "$_" -File -Recurse } else { $inputFiles += get-item "$_" } } ==== Out-Null ==== Никогда не нужно пользоваться командлетом Out-Null, он тормозной. Вместо него (по убыванию быстродействия) $array = New-Object -TypeName System.Collections.ArrayList # $null (assigned to $null) - RECOMMENDED $null = $array.Add('A') # [void] (cast to void) - RECOMMENDED [void]$array.Add('B') # $null (redirected to $null) $array.Add('C') > $null  https://powershell-guru.com/powershell-best-practice-12-avoid-out-null/ ==== Путь к файлу процесса на удалённой машине ==== ''Get-Process'' не умеет получать путь с удалённой машины. Нужно через WMI: Get-WmiObject -Class win32_process -ComputerName $MyServer -Filter 'name like "%iexplore%"' | select processname,path https://stackoverflow.com/questions/49348230/finding-path-of-process-on-remote-machine ==== Работа с PDF ==== https://www.mikesdotnetting.com/article/80/create-pdfs-in-asp-net-getting-started-with-itextsharp https://www.timatlee.com/post/powershell-itext/