Инструменты пользователя

Инструменты сайта


scripts:ps

Различия

Показаны различия между двумя версиями страницы.

Ссылка на это сравнение

Предыдущая версия справа и слеваПредыдущая версия
Следующая версия
Предыдущая версия
scripts:ps [26.10.2024 03:53] – [Замена нескольких пустых строк на одну] viacheslavscripts:ps [23.04.2025 10:51] (текущий) – [Псевдонимы (алиасы)] viacheslav
Строка 1: Строка 1:
 +===== Настройка =====
 +==== Псевдонимы (алиасы) ====
 +На примере клиента Openshift.
 +<code powershell>
 +# Создать файл профиля, если его нет, и открыть в редакторе
 +if (!(Test-Path $profile)) {New-Item $profile -Force}
 +start $profile
 +# Вставить текст. Алиас - только сам .exe, остальное - функции.
 +New-Alias oc 'C:\scripts\oc.exe'
 +function logintest {
 +  $cred = Get-Credential -UserName $env:USERNAME -Message "Enter your password"
 +  oc login https://openshift.example.com:9443 --username $cred.UserName --password $cred.GetNetworkCredential().Password --namespace project-test
 +  Remove-Variable cred
 +  }
 +function ogp {oc get po}
 +function ol {oc logs}
 +function olf {oc logs -f}
 +</code>
 +:!: Файл профиля свой у каждого приложения - Powershell, Powershell ISE, VSCode и т. п., поэтому создавать алиасы нужно для всех.
  
 +<code powershell>
 +# Отредактировать алиасы
 +start $profile
 +# Перечитать алиасы без закрытия текущей сессии
 +& $profile
 +</code>
 +https://devblogs.microsoft.com/scripting/powertip-reload-your-powershell-profile/
 +===== Active Directory =====
 +==== Показать значение атрибута msDS-cloudExtensionAttribute1 текущего пользователя ====
 +<code powershell>
 +# Import AD Module
 +Import-Module ActiveDirectory
 +get-aduser $env:UserName -Properties * | Select msDS-cloudExtensionAttribute1
 +# Имя компа:
 +# $env:computername
 +# Имя домена:
 +# $env:DomainName
 +</code>
 +
 +==== Вывести список пользователей и показать логин и msDS-cloudExtensionAttribute1 ====
 +<code powershell>
 +# Из 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
 +</code>
 +==== Извлечь атрибут msDS-CloudExtensionAttribute1 у пользователей "Рогов и копыт", и добавить значения в группу "Компьютеры для тестирования" ====
 +<code powershell>
 +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 $_)}
 +</code>
 +
 +==== Извлечь компы из выгрузки из KSC и поместить их в соответствующие группы в AD для установки новых версий Хрома ====
 +<code powershell>
 +$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
 +</code>
 +==== Имя компьютера, время входа в AD + файл ====
 +<code powershell>
 +# 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()
 +</code>
 +На пользовательских машинах не установлены RSAT, поэтому
 +<code powershell>
 +Set-ADUser $env:username -Add @{'msDS-cloudExtensionAttribute1'="$env:computername"}
 +</code>
 +не пройдёт.
 +
 +Дополнительно - примеры запросов к AD:
 +<code powershell>
 +#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
 +</code>
 +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 по части ФИО и показать информацию ====
 +<code powershell>
 +[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
 +</code>
 +
 +==== Генератор паролей ====
 +<code powershell>
 +$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
 +</code>
 +
 +<code powershell>
 +# x = length in characters
 +# y = minimum number of non-alphanumeric characters
 +Add-Type -AssemblyName System.web
 +[System.Web.Security.Membership]::GeneratePassword(x,y)
 +</code>
 +==== ФИО в логин ====
 +<code powershell>
 +$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
 +</code>
 +==== Скопировать группы, содержащие "КТ " из одной учётки в другую ====
 +<code powershell>
 +[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
 +</code>
 +==== Добавить комп в группу ====
 +<code powershell>
 +[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)
 +</code>
 +
 +==== Показать включённых юзеров с датой входа более 2 недель ====
 +<code powershell>
 +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
 +</code>
 +
 +==== Лог входов в систему ====
 +<code powershell>
 +$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
 +</code>
 +Запуск из GPO:
 +<code dos>
 +%WINDIR%\System32\WindowsPowerShell\v1.0\powershell.exe -ExecutionPolicy Bypass -File \\path-to-server\scripts\logon-log.ps1
 +</code>
 +
 +==== Список учёток с неправильно заполненными инициалами ====
 +<code powershell>
 +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
 +</code>
 +
 +==== Поставить галку "Защитить объект от случайного удаления" для всех OU домена ====
 +<code powershell>
 +Get-ADOrganizationalUnit -filter * |Set-ADOrganizationalUnit -ProtectedFromAccidentalDeletion $true
 +</code>
 +
 +===== Настройка локальных машин =====
 +==== Отключение энергосбережения для сетевого адаптера ====
 +<code powershell>
 +# 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}
 +</code>
 +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-соединениям ====
 +<code powershell>
 +$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
 +}
 +</code>
 +<code>
 +--- 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]}    
 +</code>
 +===== Таблички, отчёты, массивы =====
 +<WRAP round important >
 +''+='' удаляет старый и создаёт новый массив, т. к. он фиксированного размера, и при большом кол-ве элементов работает очень медленно.\\
 +Лучше использовать ''[System.Collections.ArrayList]'' или ''[System.Collections.Generic.List[]]''
 +
 +https://batishchev.ru/blog/all/arraylist-i-proizvoditelnost-massivov-v-powershell/\\
 +https://adamtheautomator.com/powershell-array/
 +</WRAP>
 +
 +<code powershell>
 +$arrayList = [System.Collections.ArrayList]::new()
 +$arrayList.add("aaa") > $null
 +</code>
 +
 +''[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.
 +
 +<code powershell>
 +$a = [System.Collections.Generic.List[int]]::new() # числовой массив
 +$a = [System.Collections.Generic.List[string]]::new() # строковый массив
 +$a = [System.Collections.Generic.List[object]]::new() # любой тип объектов
 +</code>
 +==== Добавить строку в отчёт с двумя столбцами ====
 +<code powershell>
 +$report += New-Object -TypeName psobject -Property @{folder="Всего каталогов"; sizeMB="$($report.folder.count)"}
 +</code>
 +==== Цвет затенения для строк ====
 +Для использования в html для фонового цвета перемежающихся строк
 +
 +  * #EDEDED - очень светлый серый.
 +  * #D9D9D9 - серый чуть потемнее.
 +  * #DBDBDB - серый. У Экселя есть шаблон, где он перемежается с #EDEDED.
 +  * #A5A5A5 - серый темнее. Лучше пользоваться уже белым шрифтом.
 +  * #7B7B7B - тёмно-серый. У Экселя есть шаблон, где он перемежается с #A5A5A5.
 +
 +==== Массив русского алфавита с индексом ====
 +Почему не ''[char[]](0..65535) -clike '[а-я]''' - там не будет буквы ё. Поэтому
 +<code powershell>
 +$alfabetRus = @("а","б","в","г","д","е","ё","ж","з","и","й","к","л","м","н","о",
 +"п","р","с","т","у","ф","х","ц","ч","ш","щ","ъ","ы","ь","э","ю","я")
 +$alfabetRus |select @{n="letter";e={$_}},@{n="index";e={$alfabetRus.indexof($_)+1}}
 +
 +letter index
 +------ -----
 +а          1
 +б          2
 +в          3
 +...
 +</code>
 +
 +Можно вычислить индексы символов и потом вставить их в массив для выбора
 +<code powershell>
 +$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}}
 +</code>
 +
 +<code powershell>
 +[char[]](1072..1103+1105) # русский алфавит строчные + буква ё
 +[char[]](1040..1071+1025) # русский алфавит заглавные + буква Ё
 +[char[]](1040..1103+1025+1105) # русский алфавит строчные и заглавные + буквы Ё и ё
 +</code>
 +
 +==== Разбить массив на части определённого размера ====
 +<code powershell>
 +$list = 1..1018
 +$chunkSize = 100
 +
 +$c = [pscustomobject]@{Value = 0}
 +$groups = $list |group {[math]::Floor($c.Value++ / $chunkSize)}
 +
 +$groups[0].group
 +</code>
 +https://stackoverflow.com/questions/13888253/powershell-break-a-long-array-into-a-array-of-array-with-length-of-n-in-one-line
 +
 +===== Файловые операции =====
 +==== Удалять из папки все файлы старше текущего месяца, кроме файлов от 1, 15 и последнего дня месяца ====
 +<code powershell>
 +$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
 +    }
 +}
 +</code>
 +==== Удалить все файлы, кроме последних 10 ====
 +<code powershell>
 +gci | sort CreationTime | select -skip 10 | Remove-item -Force
 +</code>
 +
 +==== Пакетное переименование файлов ====
 +Дано:\\
 +Pet Shop Boys - Happiness-47208322.mp3\\
 +Pet Shop Boys - The Pop Kids-47208325.mp3
 +
 +<code powershell>
 +[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
 +</code>
 +Результат:\\
 +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
 +
 +<code powershell>
 +$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
 +}
 +</code>
 +Результат:\\
 +001 - Introduction.mp4\\
 +010 - Lesson 1 Lab.mp4\\
 +100 - Understanding Why Decoupling is Important.mp4
 +==== Сортировка ====
 +Если отсортировать файлы вида file1.txt - file100.txt, то выйдет
 +<code>
 +file1.txt
 +file10.txt
 +file11.txt
 +...
 +file18.txt
 +file19.txt
 +file2.txt
 +file20.txt
 +file21.txt
 +и т. д.
 +</code>
 +Чтобы отсортировать по-человечески:
 +<code powershell>
 +dir "C:\temp\folder\*.txt" |sort {[int]($_.basename -replace '\D')}
 +</code>
 +
 +==== Посмотреть квоты на файловом сервере ====
 +<code powershell>
 +Get-FSRMQuota |? path -Match 'отдел' |select @{n='Путь';e={$_.path}},@{n='Использовано (ГБ)';e={$_.usage / 1GB -as [int]}},@{n='Всего (ГБ)';e={$_.size / 1GB -as [int]}}
 +</code>
 +
 +==== Ожидание снятия блокировки файла и копирование ====
 +<code powershell>
 +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)"
 +</code>
 +https://stackoverflow.com/questions/24992681/powershell-check-if-a-file-is-locked
 +
 +==== Создание тестовых файлов с датами изменения и создания в прошлом ====
 +<code powershell>
 +$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
 +}
 +</code>
 +
 +==== Удалить файл из корзины ====
 +<code powershell>
 +$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
 +</code>
 +
 +==== Копирование файлов robocopy + splatting ====
 +Подстановка значений, введённых пользователем, в команду.
 +<code powershell>
 +$ext = @((Read-Host "Введите расширения файлов через запятую, например, mp3,avi,txt") -split ',' -replace '^','*.')
 +robocopy "$env:userprofile\Downloads" "C:\temp\out" $ext /R:1 /W:1
 +</code>
 +===== Работа с текстом =====
 +Программа для создания большого файла txt: [[https://www.mynikko.com/dummy/|Dummy File Creator]].
 +==== Конвертировать строку во время ====
 +<code powershell>
 +$folder = "D:\temp\20211025"
 +$reportDate = [datetime]::parseexact($folder.Split("\")[-1], 'yyyyMMdd', $null)
 +
 +25 октября 2021 г. 0:00:00
 +</code>
 +https://stackoverflow.com/questions/38717490/convert-a-string-to-datetime-in-powershell\\
 +[[https://learn.microsoft.com/ru-ru/dotnet/standard/base-types/custom-date-and-time-format-strings|Строки пользовательского формата даты и времени]]
 +
 +==== Убрать из файла все строки, содержащие плюс ====
 +<code powershell>
 +(Get-Content "C:\temp\test.txt") -notmatch '\+' |Set-Content "C:\temp\test-out.txt"
 +</code>
 +http://stackoverflow.com/questions/39828780/delete-lines-containing-specific-character-in-text-file
 +
 +==== Каждое слово с большой буквы ====
 +<code powershell>
 +(Get-Culture).TextInfo.ToTitleCase('текст, каждое слово которого будет начинаться с большой буквы')
 +</code>
 +==== Фильтр отчётов Cobian Backup ====
 +<code powershell>
 +cd D:\Downloads
 +Expand-Archive .\Журналы.zip
 +cd .\Журналы
 +gc *.txt |Select-String ERR |out-file -width 30000 .\errors.txt
 +Invoke-Item .\errors.txt
 +</code>
 +
 +==== Выбрать каждую N строку в файле ====
 +<code powershell>
 +# каждую 1, 5, 9, 13, 17 и т. д.
 +gc "D:\temp\test.txt" |? {($_.ReadCount % 4) -eq 1}
 +</code>
 +
 +==== Замена ошибок в тексте (afterscan) ====
 +FIXME
 +<code powershell>
 +-replace '([\.\,\?\!])(\w)','$1 $2' ` # Добавить пробел между знаками препинания и следующим словом
 +-replace '\s+([\.\,\?\!])','$1' ` # Убрать пробел между словом и знаком препинания
 +-replace "\s+$" ` # Убрать пробелы в конце строки
 +-replace "…","..." ` # Заменить символ троеточия на реальные три точки
 +-replace '(\d)(\D)','$1 $2' ` # Добавить пробел между числом и следующим за ним словом
 +-replace "\.$",".`n" # Добавить пустую строку, если строка заканчивается точкой
 +
 +-replace '(?<=\d)(\s+)?([\.\:])(\s+)?(\d+)','$2$4' # Убрать пробелы в датах (где между цифрами . и :)
 +</code>
 +
 +==== Обработка больших файлов ====
 +Надо применять методы .NET и упаковывать regex, т. к. ''get-content'' очень медленный.
 +<code powershell>
 +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\chunk2.log" -regex "10.0.0.8"
 +</code>
 +
 +
 +[[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]]
 +
 +Быстрое чтение файла в массив:
 +<code powershell>
 +[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'))
 +</code>
 +
 +==== Склонение слов в предложении с числительным ====
 +<code powershell>
 +function Get-Declension ($pre1,$n,$w1,$w2,$w5) {
 +    switch -Regex ($n) {
 +        '(?<!1)1$'     {$p = $pre1 -replace ''; $w = $w1}
 +        '(?<!1)[234]$' {$p = $pre1 -replace '(а|(?<![ао]))$','о'; $w = $w2}
 +        default        {$p = $pre1 -replace '(а|(?<![ао]))$','о'; $w = $w5}
 +    }
 +if ($pre1) {"$p $n $w"}
 +else {"$n $w"}
 +}
 +
 +"Машина проехала $(Get-Declension -n 2 -w1 километр -w2 километра -w5 километров)"
 +"Одобрено $(Get-Declension -n 101 -w1 обновление -w2 обновления -w5 обновлений)"
 +"Всего $(Get-Declension -n 22 -w1 "активный пользователь" -w2 "активных пользователя" -w5 "активных пользователей")"
 +"$(Get-Declension -pre1 Удален -n 221 -w1 "каталог" -w2 "каталога" -w5 "каталогов")"
 +"$(Get-Declension -pre1 Удалена -n 11 -w1 "папка" -w2 "папки" -w5 "папок")"
 +"$(Get-Declension -pre1 Посажен -n 2511 -w1 "дуб" -w2 "дуба" -w5 "дубов")"
 +"$(Get-Declension -pre1 Разбито -n 4 -w1 "яйцо" -w2 "яйца" -w5 "яиц")"
 +Машина проехала 2 километра
 +Одобрено 101 обновление
 +Всего 22 активных пользователя
 +Удален 221 каталог
 +Удалено 11 папок
 +Посажено 2511 дубов
 +Разбито 4 яйца
 +</code>
 +
 +==== Список модулей PHP из буфера по алфавиту и с переносом строки ====
 +<code powershell>
 +$list = (Get-Clipboard) -replace '\s+\\$' |sort
 +$total = $list.count
 +$c = 1
 +$list |% {
 +    if ($c -eq $total) {$_}
 +    else {$_ + " \"}
 +$c++
 +} |Set-Clipboard
 +</code>
 +
 +<WRAP group>
 +<WRAP half column>
 +Исходный список
 +<code>
 +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
 +</code>
 +</WRAP>
 +
 +<WRAP half column>
 +Результат
 +<code>
 +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
 +</code>
 +</WRAP>
 +</WRAP>
 +
 +==== Замена многострочного блока ====
 +<code>
 +Управление групповой политикой
 +
 +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; } }
 +
 +Путь размещения параметров:
 +
 +Объяснение
 +</code>
 +
 +<code powershell>
 +(gc 'D:\Downloads\file.txt' -Raw) -replace 'body((.|\n)*)\} \}'
 +</code>
 +
 +==== Замена нескольких пустых строк на одну ====
 +<code powershell>
 +(gc 'D:\Downloads\file.txt' -Raw) -replace '(\r?\n){2,}', '$1$1'
 +</code>
 +
 +==== Преобразование строк в таблицу ====
 +<code>
 +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
 +
 +</code>
 +
 +Вычистить ненужные строки и мусор, разделить текст на сегменты, создать структурированные объекты. Разделителем для ''ConvertFrom-StringData'' должен быть ''=''.
 +<code powershell>
 +(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
 +}
 +</code>
 +
 +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
 +
 +==== Поиск значений ASCII для символов ====
 +
 +<code powershell>
 +[char[]]"абвгдяё" |select @{n='Char';e={$_}},@{n='Code';e={[int]$_}}
 +
 +Char Code
 +---- ----
 +   а 1072
 +   б 1073
 +   в 1074
 +   г 1075
 +   д 1076
 +   я 1103
 +   ё 1105
 +</code>
 +https://rakhesh.com/powershell/getting-the-ascii-utf-8-value-of-a-string/
 +
 +==== json ====
 +Удобное создание json
 +<code powershell>
 +$json = @{
 +  repoName = "project-maven-prod"
 +  name = "artifact"
 +  version = "2.2.26"
 +} |ConvertTo-Json -Compress
 +# Результат: {"name":"artifact","version":"2.2.26","repoName":"project-maven-prod"}
 +
 +# Применение, например, в API-запросе
 +$response = Invoke-RestMethod -Uri "$url/script/getVersion/run" `
 +-Headers @{"Authorization" = "Basic $basic"; "Accept" = "application/json"} `
 +-Method Post -Body $json -ContentType "application/json"
 +
 +</code>
 +
 +===== Графика =====
 +==== Диаграммы ====
 +На примере ежечасно снимаемых логов вошедших по VPN пользователей.
 +<code powershell>
 +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")
 +</code>
 +
 +{{: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
 +
 +===== Интернет =====
 +==== Скачать файлы по списку ====
 +<code powershell>
 +$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\$_"
 +}
 +</code>
 +
 +==== Отправить письмо ====
 +Без запроса пароля.
 +<code powershell>
 +# Сохранение шифрованного пароля в файл
 +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
 +</code>
 +
 +==== Игнорировать самоподписанный сертификат SMTP ====
 +<code powershell>
 +[System.Net.ServicePointManager]::ServerCertificateValidationCallback = { return $true }
 +Send-MailMessage -SmtpServer "mail.example.com" -from "script@example.com" -to "user@example.com" -Subject "Hello" -body "<H1>Hello</H1>" -BodyAsHtml -Encoding UTF8 -UseSsl
 +</code>
 +
 +
 +==== Письмо с картинкой в тексте ====
 +<code powershell>
 +Send-MailMessage -To "testovtt@domain.ru" -From "birthday@domain.ru" `
 +-SmtpServer "mail.domain.ru" -Subject "С днём рожденья!" `
 +-Body "
 +<h3>Уважаемый Тест Тестович!</h3>
 +<p>Поздравляю вас с днём рождения!</p>
 +<img src='cid:birthday.jpg'>
 +<p><i>С уважением, скрипт.</i></p>
 +" -Attachments "C:\scripts\birthday.jpg" -BodyAsHtml -Encoding utf8
 +</code>
 +https://stackoverflow.com/questions/52837468/embed-images-in-email-and-send-via-powershell
 +==== Сколько дней осталось до окончания действия SSL-сертификата ====
 +С помощью curl (надо [[https://curl.se/windows/|скачивать с сайта]], встроенный в винду многого не умеет)
 +<code powershell>
 +$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 'Конец срока действия'
 +</code>
 +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-объекты определённого класса ====
 +<code powershell>
 +$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
 +</code>
 +https://stackoverflow.com/a/17625740
 +===== Информация =====
 +Вывод системной информации:
 +<code powershell>
 +# 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"
 +</code>
 +
 +==== Список установленных программ ====
 +<code powershell>
 +# Узнать удалённо, что стоит на 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%'"
 +</code>
 +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
 +
 +
 +==== Создание окон ====
 +<code powershell>
 +[System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
 +[System.Windows.Forms.MessageBox]::Show("Message Text","Title",1,48)
 +</code>
 +<WRAP group>
 +<WRAP half column>
 +Первое число:\\
 +0 OK\\
 +1 OKCancel\\
 +2 AbortRetryIgnore\\
 +3 YesNoCancel\\
 +4 YesNo\\
 +5 RetryCancel
 +</WRAP>
 +
 +<WRAP half column>
 +Второе число:\\
 +0 None\\
 +16 Hand\\
 +16 Error\\
 +16 Stop\\
 +32 Question\\
 +48 Exclamation\\
 +48 Warning\\
 +64 Asterisk\\
 +64 Information
 +</WRAP>
 +</WRAP>
 +
 +https://michlstechblog.info/blog/powershell-show-a-messagebox/\\
 +https://winitpro.ru/index.php/2018/10/02/uvedomleniya-polzovateley-is-powershell/
 +
 +==== Температура процессора ====
 +<code powershell>
 +((gwmi -Namespace root\wmi MSAcpi_ThermalZoneTemperature).CurrentTemperature |sort |select -last 1) / 100
 +</code>
 +CMD:
 +<code dos>
 +@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
 +</code>
 +==== Аптайм ====
 +<code powershell>
 +read-host "Имя компа" |Set-Variable n
 +gcim win32_operatingsystem  -computername $n |
 +select Caption,Version,@{Name="Uptime";Expression={(Get-Date) - $_.lastBootUpTime}},PScomputername
 +</code>
 +
 +==== Даты установки Windows ====
 +<code powershell>
 +$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
 +</code>
 +
 +==== Состояние диска ====
 +FIXME
 +Добавить проверку и отправку писем, если статус не ОК
 +<code powershell>
 +$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}
 +</code>
 +
 +==== Total LBAs Written в мегабайты/гигабайты/терабайты ====
 +<code powershell>
 +[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")) ТБ"
 +</code>
 +
 +==== Сокращение десятичных знаков, округление ====
 +<code powershell>
 +@{n='Size(MB)';e={($_.Length/1MB).ToString("#.##")}} # строка
 +[math]::round((0.4265867),2) # число
 +0,43
 +</code>
 +==== Внешний IP ====
 +<code powershell>
 +curl https://2ip.ru
 +</code>
 +
 +==== Поиск свободного IP в сети ====
 +<code powershell>
 +1..254 |% {
 +$ip = "10.1.0.$_"
 +    if (-not (Test-Connection $ip -Count 1 -Quiet)) {
 +    $ip
 +    }
 +}
 +</code>
 +==== Потребление памяти несколькими одноимёнными процессами ====
 +<code powershell>
 +get-process firefox |group name |select name,@{n='Memory(MB)';e={(($_.group.workingset |measure -sum).sum / 1mb).ToString('#.##')}}
 +</code>
 +
 +==== Пути каталогов в профиле и системе ====
 +<code powershell>
 +# Перечислить
 +[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
 +</code>
 +
 +===== Реестр =====
 +<code powershell>
 +$regPath = "HKCU:\Software\Microsoft\Office\16.0\Outlook\Options\Mail"
 +New-ItemProperty -Path $regPath -Name JunkMailImportLists -PropertyType Dword -Value 1 -Force > $null
 +</code>
 +
 +Список значений ''-PropertyType''.
 +<code>
 +Binary REG_BINARY
 +DWord REG_DWORD
 +ExpandString REG_EXPAND_SZ
 +MultiString REG_MULTI_SZ
 +None No data type
 +QWord REG_QWORD
 +String REG_SZ
 +</code>
 +https://learn.microsoft.com/en-us/dotnet/api/microsoft.win32.registryvaluekind
 +===== Прочее =====
 +==== Таймер ====
 +<code powershell>
 +$timer = [system.diagnostics.stopwatch]::StartNew()
 +[math]::round(($timer.Elapsed.TotalSeconds),2)
 +$timer.IsRunning
 +True
 +$timer.Stop()
 +</code>
 +https://www.pluralsight.com/blog/tutorials/measure-powershell-scripts-speed
 +
 +==== Секунды в dd.hh:mm:ss ====
 +<code powershell>
 +[timespan]::fromseconds("336621").tostring()
 +3.21:30:21
 +</code>
 +==== Текст в речь ====
 +<code powershell>
 +$currentdate = (get-date).ToLongDateString()
 +$currenttime = (get-date).ToLongTimeString()
 +Add-Type -AssemblyName System.speech
 +$speak = New-Object System.Speech.Synthesis.SpeechSynthesizer
 +$speak.Speak("Сегодня $currentdate, текущее время $currenttime")
 +</code>
 +https://learn-powershell.net/2013/12/04/give-powershell-a-voice-using-the-speechsynthesizer-class/
 +
 +==== Скриншот ====
 +<code powershell>
 +[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"
 +</code>
 +https://www.reddit.com/r/PowerShell/comments/9y9689/take_a_screenshot_with_powershell/
 +
 +==== Установить/обновить Powershell 7 ====
 +Windows:
 +<code powershell>
 +iex "& { $(irm https://aka.ms/install-powershell.ps1) } -UseMSI"
 +</code>
 +Linux:
 +<code bash>
 +wget https://aka.ms/install-powershell.sh; sudo bash install-powershell.sh; rm install-powershell.sh
 +</code>
 +https://www.thomasmaurer.ch/2019/07/how-to-install-and-update-powershell-7/
 +
 +==== Запуск скрипта Powershell из-под PSExec ====
 +<code dos>
 +@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"
 +</code>
 +
 +==== Обработка объектов, перетащенных на ярлык ====
 +<code powershell>
 +# Ярлык
 +powershell -f "C:\temp\drag-drop.ps1"
 +# вариант
 +powershell -noexit -noprofile -f "C:\temp\drag-drop.ps1"
 +</code>
 +При перетаскивании на ярлык в ''$args'' попадают полные пути объектов.
 +<code powershell>
 +# Получить список файлов
 +$inputFiles = @()
 +$args |% {
 +    if ((get-item "$_").mode -match "^d") {
 +    $inputFiles += dir "$_" -File -Recurse
 +    }
 +    else {
 +    $inputFiles += get-item "$_"
 +    }
 +}
 +</code>
 +
 +==== Out-Null ====
 +Никогда не нужно пользоваться командлетом Out-Null, он тормозной. Вместо него (по убыванию быстродействия)
 +<code powershell>
 +$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 
 +</code>
 +https://powershell-guru.com/powershell-best-practice-12-avoid-out-null/
 +
 +==== Путь к файлу процесса на удалённой машине ====
 +''Get-Process'' не умеет получать путь с удалённой машины. Нужно через WMI:
 +<code powershell>
 +Get-WmiObject -Class win32_process -ComputerName $MyServer -Filter 'name like "%iexplore%"' | select processname,path
 +</code>
 +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/

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki