« Powershell » : différence entre les versions

De Banane Atomic
Aller à la navigationAller à la recherche
(Page redirigée vers PowerShell)
 
(Redirection supprimée vers PowerShell)
Balise : Redirection supprimée
Ligne 1 : Ligne 1 :
#REDIRECTION [[PowerShell]]
[[Category:Windows]]
= Liens =
* [https://www.powershellgallery.com Powershell Gallery]
* [https://docs.microsoft.com/en-us/powershell/dsc/overview DSC]
* [[Powershell_configuration|Powershell configuration]]
 
= Script template =
À placer au début du script (en dessous de Param).
<kode lang='ps'>
# Renforce les règles de vérification et créé une erreur si elles ne sont pas respectées
Set-StrictMode -Version Latest
 
# Stop le script à la première erreur (par défaut à Continue)
$ErrorActionPreference = "Stop"
# en ligne de commande: .\MyScript.ps1 -ErrorAction Stop
 
# Force tous les Cmdlet à s'arrêter à la première erreur
$PSDefaultParameterValues['*:ErrorAction'] = 'Stop'
</kode>
 
* [https://docs.microsoft.com/en-us/powershell/module/Microsoft.PowerShell.Core/Set-StrictMode?view=powershell-5.1 Set-StrictMode]
* [https://learn-powershell.net/2013/12/11/using-psdefaultparametervalues-in-powershell PSDefaultParameterValues]
 
= Astuces =
<kode lang=powershell>
# commentaire
<# commentaires
  commentaires #>
 
# multilines command
command -option1 `
        -option2
 
# tester une commande: affiche le résultat mais n’exécute pas la commande
Commande -WhatIf
 
# exécuter un fichier depuis la console cmd.exe
powershell -file MonFichier.ps1
# exécuter une commande depuis la console cmd.exe
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -command "& 'C:\dossier\script.ps1' args"
 
# appeler un autre script powershell
& 'C:\dossier\script.ps1' args
 
# Supprimer l'attribut Read-Only
sp file.txt IsReadOnly $false
 
# ouvrir explorer (Invoke-Item)
ii .
 
# lancer internet explorer
$ie = New-Object -ComObject InternetExplorer.Application
$ie.Navigate2("http://www.google.com")
$ie.Visible = $true
 
# tester si la console est en mode admin
[bool](([System.Security.Principal.WindowsIdentity]::GetCurrent()).groups -match "S-1-5-32-544")
</kode>
 
= Variables =
{{warn | Pas de {{boxx|-}} dans les noms des variables.}}
<kode lang='ps'>
$my_var = "value"
</kode>
 
== [https://ss64.com/ps/syntax-automatic-variables.html Environment Variables] ==
<kode lang='ps'>
# list all environment variables
Get-Childitem env:
</kode>
 
{| class="wikitable wtp wtmono1"
| $env:USERPROFILE || C:\Users\<user>
|-
| ${env:APPDATA} || C:\Users\<user>\AppData\Roaming
|-
| [environment]::getfolderpath("mydocuments") || C:\Users\<user>\Documents
|}
 
== [https://ss64.com/ps/syntax-automatic-variables.html Automatic Variables] ==
{| class="wikitable wtp wtmono1"
|-
| $_ || the current object in the pipeline
|-
| $Home || C:\Users\<user>
|-
| $Pwd || full path of the current directory
|-
| $PSCommandPath || path of the script file that is being executed
|-
| $PSScriptRoot || path of the script directory that is being executed
|}
 
= echo, Write-Host =
<kode lang='ps'>
echo 'my text'
 
# saut de ligne
echo line1 line2
echo line1`nline2
echo line1([system.environment]::newline)line2
 
# colors
Write-Host -foregroundcolor green -backgroundcolor black Mon Message
 
# erreur
Write-Error "Error!"
</kode>
 
{| class="wikitable wtp"
|+ Couleurs disponibles
| Black || Blue || Cyan || DarkBlue
|-
| DarkCyan || DarkGray || DarkGreen || DarkMagenta
|-
|DarkRed || DarkYellow || Gray || Green
|-
| Magenta || Red || White || Yellow
|}
 
{{info | {{boxx|echo}} is an alias of {{boxx|Write-Output}}}}
 
== [https://evotec.xyz/hub/scripts/pswritecolor PSWriteColor] ==
<kode lang='powershell'>
# installation du module (console administrateur)
Install-Module -Name PSWriteColor
 
Import-Module PSWriteColor
 
Write-Color "Red ", "Green ", "Yellow " -Color Red, Green, Yellow
wc "Red ", "Green ", "Yellow " -C Red, Green, Yellow
# -StartTab 1    ajoute une tabulation avant d'afficher le texte
# -LinesBefore 1  passe une ligne avant d'afficher le texte
# -LinesAfter 1  passe une ligne après avoir afficher le texte
# -LogFile "C:\log.txt"  écrit dans un fichier de log [YYYY-MM-DD HH:mm:ss]Texte
</kode>
 
= Read input =
<kode lang='ps'>
# lire l'entrée clavier
$input = Read-Host 'Question?'
 
# Press any key to continue
Write-Host -NoNewLine 'Press any key to continue...';
$null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown');
</kode>
 
= GridView =
<kode lang='ps'>
# afficher une fenêtre avec une grille
New-Object Net.Webclient | Get-Member | Out-GridView
 
# permettre de séléctionner des éléments dans la grille et de s'en servir comme paramètres d'entrée
Get-Service |
    Where Status -eq Stopped |
    Out-GridView -PassThru |
    Start-Service
</kode>
 
= Types =
== String ==
<kode lang='ps'>
echo "Escape `"double-quotes`""
echo "Retour à la ligne `r`n"
 
# concaténation de string
echo 'Text1 - ' + "Text2: ${Var1}, $Var2"
echo "Text: $(command)"
 
# here-string: multiline string
echo @"
First line
Second line
"Quotes don't need to be escaped"
Plus, you can include variables: $MyVar
"@
 
'ABC'.replace('B', '')  # AC
'abc'.toupper()  # ABC
</kode>
 
=== Test string ===
<kode lang='ps'>
if ($MyString.startswith('xxx'))
 
if ($MyString)  # not null and not empty
if (!$MyString)  # null or empty
</kode>
 
== Date ==
<kode lang='ps'>
Get-Date -Format 'yyyy-MM'  # 2020-01
</kode>
 
== Tableau / array ==
<kode lang='ps'>
$myArray = @()  # empty
$myArray = 1, 2, 3
$myArray += 4
 
$myArray[1..2]  # 2 3
$myArray[-1]    # 4
 
$myArray -ne 2  # 1 3 4
$myArray -gt 2  # 3 4
 
[array]::Reverse($myArray)  # 4 3 2 1
 
$one, $two, $rest = $myArray  # $one = 1, $two = 2, $rest = 3, 4
</kode>
 
== Hash table ==
<kode lang='ps'>
$myHashTable = @{}  # empty
$myHashTable.Key1 = "Value1"
$myHashTable = @{
    Key1 = "Value1"
    Key2 = "Value2"
}
 
$myValue = $myHashTable.$myKey
 
"All keys: $($myHashTable.keys)"
"All values: $($myHashTable.values)"
 
if (!$myHashTable.contains($myKey))
</kode>
 
== PSObject ==
<kode lang='ps'>
$obj = New-Object PSObject -Property @{
    Prop1 = "Value1"
    Prop2 = "Value2"
}
</kode>
 
= if else =
<kode lang=powershell>
$nombre = 10
if ($nombre -eq 10) {
    "Le nombre est 10."
}
elseif (($nombre -gt 5) -and ($nombre -lt 10) -or ($nombre -eq 222)) {
    "Le nombre est entre 5 et 10 ou égal à 222."
}
elseif (!($nombre -eq 333)) {
    "Le nombre est différent de 333."
}
else { "Surement 333" }
</kode>
{| class="wikitable wtp"
! Opérateur
! Description
! Opérateur
! Description
|-
| -eq || == || -ceq || == case senstivie
|-
| -ne || !=
|-
| -lt || < || -le || <=
|-
| -gt || > || -ge || >=
|-
| -not ! || !
|-
| -and || && || -or || <nowiki>||</nowiki>
|-
| -band || & || -bor || <nowiki>|</nowiki>
|}
 
== Test string ==
<kode lang=bash>
if ([string]::IsNullOrEmpty($monString))
</kode>
[https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-powershell-1.0/ee692804(v=technet.10) The String’s the Thing]
 
= [https://kevinmarquette.github.io/2018-01-12-Powershell-switch-statement/#switch-statement switch] =
<kode lang='powershell'>
$result = switch ($stringVariable)
{
    Word1
    {
        'Value1'
    }
    Word2
    {
        'Value2'
    }
    ''
    {
        'Value3'
    }
    default
    {
        'Default Value'
    }
}
</kode>
 
= [http://technet.microsoft.com/en-us/library/ee176955.aspx Select] =
<kode lang=powershell>
# parmi les résultats de command, n'affiche que UnePropriété (select = Select-Object)
command | select UnePropriété
# afficher seulement la valeur de UnePropriété (exp = expand = ExpandProperty)
(command).UnePropriété
command | select -exp UnePropriété
# parmi les résultats de command, n'affiche que les 10 premiers résultats
command | select -first 10
</kode>
 
= [http://technet.microsoft.com/en-us/library/ee177028.aspx Where ?] =
<kode lang=powershell>
1..4 | ? {$_ % 2 -eq 0}  # 2 4
</kode>
{{info | Alias: {{boxx|Where-Object}} {{boxx|where}} {{boxx|?}}}}
 
= ForEach % =
<kode lang='ps'>
1..4 | % { $_ * 2 }  # 2 4 6 8
</kode>
 
= [http://blog.hand-net.com/sharepoint/2013-04-16-powershell-simplifier-la-creation-de-fonction-avec-les-bons-arguments.htm Fonctions] =
<kode lang=powershell>
Function TestName {
    param(
        [Parameter(Mandatory=$true, ValueFromPipeline=$true)]
        [string]
        $nom
    )
    if ($nom -eq "moi")
    {
        return $true
    }
    return $false
}
 
TestName "moi"
# True
</kode>
{{info | La fonction doit être déclarée avant son utilisation.}}
 
= Paramètres et Arguments =
<kode lang=powershell>
# doit se situer à la première ligne exécutable
Param (
  # avec une valeur par défaut
  [string] $Name = "initial value",
 
  # paramètre obligatoire
  # position permet de définir le paramètre sans son nom
  [Parameter(Mandatory = $true, Position = 0)]
  [string] $Name,
 
  # True par défaut. Valeurs: $true ou $false. switch est équivalent à bool
  [Parameter(Position = 1)]
  [bool] $BooleanValue,
 
  # avec des alias (-e -ef)
  [Alias('e','ef')]
  [string] $excludeFolder
)
 
# utilisation avec les noms des paramètres
.\MonScript.ps1 -Name MyName -BooleanValue $false
 
# utilisation avec les positions
.\MonScript.ps1 MyName $false
</kode>
 
{{info | {{boxx|1= Mandatory = $true}} , demande de manière interactive les paramètres s'ils ne sont pas spécifiés.}}
{{warn | {{boxx|$args}} fonctionne avec les arguments passés à une fonction mais pas avec ceux passés à un script.}}
 
== Exclusive groups of mandatory elements ==
<kode lang=powershell>
# ok: .\MyScript -Environment env1
# ok: .\MyScript -Server srv1 -Database db1
# ko: .\MyScript -Environment env1 -Server srv1 -Database db1
[CmdletBinding(DefaultParameterSetName='Env')]  # by default, Env is used
Param (
    [Parameter(ParameterSetName = 'Env', Mandatory = $true)]
    [string] $Environment,
    [Parameter(ParameterSetName = 'Srv', Mandatory = $true)]
    [string] $Server
    [Parameter(ParameterSetName = 'Srv', Mandatory = $true)]
    [string] $Database
)
 
# to know which ParameterSetName has been used
echo $PSCmdlet.ParameterSetName  # Env or Srv
</kode>
 
== [https://nancyhidywilson.wordpress.com/2011/11/21/powershell-using-common-parameters Common parameters] ==
{| class="wikitable wtp wtmono1"
! Parameter
|-
| -Debug
|-
| -ErrorAction
|-
| -ErrorVariable
|-
| -OutBuffer
|-
| -OutVariable
|-
| -Verbose
|-
| -WarningAction
|-
| -WarningVariable
|}
 
<kode lang='ps'>
[CmdletBinding()]  # add this line at the top of the script file
Param ()
 
if ($PSBoundParameters['Verbose'])  # test if Verbose has been passed as parameter
</kode>
 
= Files and folders =
== [https://technet.microsoft.com/fr-fr/library/hh849800%28v=wps.620%29.aspx List] ==
<kode lang='ps'>
# display names only
ls C:\Dossier -Name
 
# display fullnames (C:\Dossier\filename.ext)
ls C:\Dossier | % FullName
 
# display names without the extension
ls C:\Dossier | % BaseName
 
# filter
ls C:\Dossier *.txt
# exclude *.txt et *.dll
ls C:\Dossier -exclude *.txt, *.dll
 
# filter against RegEx (-NotMatch, -NotLike)
ls C:\Dossier | ? Name -Match "\.txt$"  # RegEx
ls C:\Dossier | ? Name -Like "*.txt"  # Wildcard Expression
 
# lister toutes les DLL et EXE avec leurs versions
ls *.dll,*.exe | % { "{0}`t{1}" -f $_.Name, [System.Diagnostics.FileVersionInfo]::GetVersionInfo($_).FileVersion }
</kode>
 
{{info | {{boxx|ls}} {{boxx|dir}} {{boxx|gci}} are aliases of {{boxx|Get-ChildItem}}}}
{{warn | {{boxx|filter}} et {{boxx|exclude}} ne fonctionnent pas en même temps.<br>
Utiliser * dans le chemin à la place de {{boxx|filter}}}}
{{warn | {{boxx|-exclude}} only applies to basenames of items {{boxx|myfile.txt}}, not the fullname {{boxx|C:\folder\myfile.txt}}}}
 
== [https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/sort-object?view=powershell-6 sort] ==
<kode lang='ps'>
# sort by name
ls C:\Dossier | sort
 
# sort by LastWriteTime, last modified first
ls C:\Dossier | sort -property LastWriteTime -Descending
</kode>
 
== Search by name ==
<kode lang='ps'>
# look recursively for all the *.txt files
ls -r -ErrorAction SilentlyContinue "*.txt"
</kode>
 
== Search by file content ==
<kode lang='ps'>
# look recursively for files which contains xxx
ls -r C:\Dossier | sls "xxx" | group path | % name
 
# display all the occurences of xxx with 2 lines before and after
ls -r C:\Dossier | sls "xxx" -context 2
</kode>
{{info | {{boxx|sls}} is an alias of {{boxx|Select-String}}}}
{{warn | {{boxx|context}} ne semble plus fonctionner}}
 
== [https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.management/get-content Read / Get content] ==
<kode lang='ps'>
# return an array of newline-delimited strings
$content = Get-Content .\file.txt
 
# return a string
$content = Get-Content .\file.txt -raw
 
# tail equivalent: display what is appended to the file in realtime
Get-Content .\file.txt -Wait -Tail 1
</kode>
 
== [https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.management/set-content?view=powershell-7 Write / Set content] ==
<kode lang='ps'>
Set-Content -Encoding UTF8 -Path .\file.txt -Value 'Text'
</kode>
{| class="wikitable wtp"
|+ [https://docs.microsoft.com/en-us/dotnet/api/microsoft.powershell.commands.filesystemcmdletproviderencoding Encoding values]
|-
| Default || UTF-8 without BOM
|-
| UTF8 || UTF-8 with BOM
|}
 
== Replace content ==
{{info | The default encoding is UTF-8 without BOM}}
<kode lang='ps'>
(Get-Content .\file.txt) -replace 'Text', 'Content' | Set-Content .\file.txt
(Get-Content .\file.txt) -replace 'var=(\w+);', "var=$new_value;" | Set-Content .\file.txt
</kode>
 
== Delete files based on pattern ==
<kode lang='ps'>
# delete all the *.txt files
ls *.txt | Remove-Item
</kode>
 
== [https://technet.microsoft.com/en-us/library/ee176914.aspx Créer / supprimer un dossier] ==
<kode lang=ps>
# suppression d'un dossier et de son contenu
rm -r -fo C:\Dossier
# -r  / -recurse
# -fo / -force
# -ErrorAction Continue
 
# test before delete to avoid error
if (test-path C:\Dossier) { rm -r C:\Dossier }
 
# | Out-Null permet de masquer la sortie
ni C:\Dossier -type directory | Out-Null
 
# -force écrase le fichier s'il existe déjà, pour un dossier cela permet juste d'éviter l'erreur « Item already exists »
ni C:\Dossier -type directory -force
</kode>
{{info | Alias de Remove-Item: del, erase, rd, ri, rm, rmdir<br>
Alias de New-Item: ni}}
[https://technet.microsoft.com/fr-fr/library/hh849765%28v=wps.620%29.aspx Remove-Item]
 
= Path =
<kode lang=powershell>
# dossier1\dossier2
join-path dossier1 dossier2
join-path -path dossier1 -childpath dossier2 
join-path -path dossier1\ -childpath \dossier2\
join-path -path dossier1 -childpath (join-path -path dossier2 -childpath dossier3)
# dossier1\dossier2\dossier3
 
# utilisation du Framework .NET
[System.IO.Path]::Combine("C:\Dossier1", "Dossier2", "Dossier3")
# C:\Dossier1\Dossier2\Dossier3
# test si le chemin c:\dossier existe
if (Test-Path C:\Dossier -PathType Container) { }
 
# test si le chemin c:\dossier existe
if (Test-Path C:\Dossier\file.txt -PathType Leaf) { }
</kode>
 
* [https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.management/test-path Test-Path]
 
= [http://technet.microsoft.com/fr-fr/library/hh849793%28v=wps.620%29.aspx Copy-Item] =
<kode lang=powershell>
# copie de Fichier.txt dans Dossier2 sous le nom de Fichier2.txt
# dans ce cas Dossier2 n'est pas créé s'il n'existe pas
cp C:\Dossier\Fichier.txt C:\Dossier2\Fichier2.txt
# copie récursive de Dossier dans Dossier2 (création de Dossier2 s'il n'existe pas)
cp -recurse C:\Dossier C:\Dossier2
# copie récursive de l'arborescence de Dossier dans Dossier2 et copie des fichiers *.txt exclusivement
cp C:\Dossier C:\Dossier2 -recurse -filter *.txt
 
# copie tous les *.txt en excluant les *.bak.txt
cp C:\Dossier\*.txt C:\Dossier2 -exclude *.bak.txt
 
# copie récursive avec exclusion
$from = convert-path (join-path $Path1 '..\Dossier') # convert-path pour supprimer les ..
ls -r $from -exclude *.pdb, *.xml | % {
    cp $_.FullName (join-path $to $_.FullName.Substring($from.length))
}
</kode>
{{info | Alias {{boxx|Copy-Item}} {{boxx|copy}} {{boxx|cp}} {{boxx|cpi}}}}
{{warn | Exclude ne fonctionne pas avec les répertoires}}
 
= Measure / Count =
<kode lang=powershell>
ls | measure
# Count    : 8 
# Average  :   
# Sum      :   
# Maximum  :   
# Minimum  :   
# Property :   
 
# compter le nombre d'éléments dans le dossier courant
(ls | measure).Count;
</kode>
 
= Log =
<kode lang='ps'>
# log in MyProgram.log in the same folder
Start-Transcript -path $PSCommandPath.replace('.ps1', '.log')
</kode>
 
= [https://ss64.com/ps/syntax-esc.html Échapper les caractères spéciaux] =
<kode lang='powershell'>
echo '$dollar'  # $dollar
echo `$dollar  # $dollar
</kode>
 
= Encoding =
Si la sortie affiche des caractères inattendus, utiliser l'encodage UTF-8 avec BOM.
 
= [http://ss64.com/ps/syntax-regex.html Expressions rationnelles] =
 
= Shutdown - Restart =
<kode lang='ps'>
Stop-Computer
Restart-Computer
</kode>
[[Batch#Shutdown.2C_restart.2C_sleep|Batch commands]]
 
= Active Directory =
* Installer [https://www.microsoft.com/en-us/download/confirmation.aspx?id=45520 Remote Server Administration Tools]
<kode lang='powershell'>
Import-Module activedirectory
 
Get-ADUser -filter *
</kode>
* [[Azure#PowerShell|Azure Active Directory]]
 
= [https://4sysops.com/archives/managing-services-the-powershell-way-part-3 Services] =
<kode lang=powershell>
# affiche l'état d'un service
get-service 'SQLBrowser'
# Stopped / Running
 
$ServiceName = 'MSSQL$SQLEXPRESS'
if ((get-service $ServiceName).Status -eq 'Stopped') {
    # démarrer un service, nécessite les droits administrateur
    start-service $ServiceName -PassThru
    # PassThru force l'affichage d'un message de sortie
}
else {
    echo "$ServiceName est déjà démarré."
}
</kode>
 
= MessageBox =
<kode lang=powershell>
[void][Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
[void][System.Windows.Forms.MessageBox]::Show("Hello !")
</kode>
 
= Web =
<kode lang='powershell'>
# get the content and detect the output format: XML or JSON
Invoke-RestMethod http://www.domain.net/api/values | % { $_ | select Prop1, Prop2 | Out-GridView }
 
Invoke-RestMethod http://localhost:111/api/values -Method POST -Body @{value='2'}
 
Invoke-WebRequest http://localhost:111/api/values -H @{"accept"="application/xml"} | Select-Object -Expand Content
 
$content = (New-Object Net.WebClient).DownloadString("http://www.google.fr")
</kode>
 
== Target HTML ==
<kode lang='ps'>
$url = "http://www.domain.net"
$result = Invoke-WebRequest $url
 
$result.AllElements |
    Where Class -eq "some css class" |
    Select -First 1 -ExpandProperty innerText
</kode>
 
= [http://www.computerperformance.co.uk/powershell/powershell_registry.htm Registre] =
<kode lang='powershell'>
$RegKey ="HKCU:\Control Panel\Cursors"
# Obtenir la valeur de la clé IBeam
Get-ItemProperty -Path "HKCU:\Control Panel\Cursors" | select -ExpandProperty IBeam
# Changement de la valeur de la clé IBeam
Set-ItemProperty -Path $RegKey -Name IBeam -Value "%SystemRoot%\cursors\beam_r.cur"
</kode>
 
= Use C# code =
<kode lang='ps'>
Add-Type -TypeDefinition @"
public class Compute {
    public int Add(int n1, int n2) {
        return n1 + n2;
    }
}
"@
 
# load an assembly
Add-Type -Path C:\Folder\Compute.dll
 
$compute = New-Object Compute
$compute.Add(6, 4)  # 10
</kode>
 
= Exemples =
== Recherche de texte dans tous les fichiers - rg - ripgrep ==
<kode lang='powershell' collapsed>
Function rg {
    param(
        [Parameter(Mandatory=$true, ValueFromPipeline=$true)]
        [string]
        $pattern
    )
    ls -r | sls $pattern -context 2 |
foreach {
"{0} : {1:00}" -f $_.Path, $_.LineNumber
if ($_.Context.PreContext) {"  {0}" -f $_.Context.PreContext }
"> {0}" -f $_.Line
if ($_.Context.PostContext) { "  {0}" -f $_.Context.PostContext }
""
}
}
</kode>
 
== [https://social.technet.microsoft.com/wiki/contents/articles/4546.working-with-passwords-secure-strings-and-credentials-in-windows-powershell.aspx Stocker et récupérer un mot de passe] ==
<kode lang='powershell' collapsed>
# store password
$Password = "Password123!@#"
$SecurePassword = $Password | ConvertTo-SecureString -AsPlainText -Force  # SecureString
# ou demande du password
$SecurePassword = Read-Host -Prompt "Enter password" -AsSecureString
# ou demande du password avec Get-Credential
$Credential = Get-Credential -Message "Enter password" -Username "-"
$SecurePassword = $Credential.Password
$SecureStringAsPlainText = $SecurePassword | ConvertFrom-SecureString  # String
Set-Content "C:\Dossier\Password.txt" $SecureStringAsPlainText
 
# get the password
$SecureStringAsPlainText = Get-Content "C:\Dossier\Password.txt"  # String
$SecurePassword = $SecureStringAsPlainText | ConvertTo-SecureString  # SecureString
$Credential = New-Object PSCredential "user",$SecurePassword
$PlainPassword = $Credential.GetNetworkCredential().Password  # password en clair
</kode>
 
== [https://blogs.technet.microsoft.com/heyscriptingguy/2013/01/17/use-powershell-to-change-the-mouse-pointer-scheme/ Modifier le pointeur de la sourie] ==
<kode lang='powershell' collapsed>
# changement du pointeur Text Selection
$RegKey ="HKCU:\Control Panel\Cursors"
Set-ItemProperty -Path $RegKey -Name IBeam -Value "%SystemRoot%\cursors\beam_r.cur"
 
# Rafraichissement des curseurs pour prendre en compte le changement
$CSharpSig = @'
[DllImport("user32.dll", EntryPoint = "SystemParametersInfo")]
public static extern bool SystemParametersInfo(
  uint uiAction,
  uint uiParam,
  uint pvParam,
  uint fWinIni);
'@
 
$CursorRefresh = Add-Type -MemberDefinition $CSharpSig -Name WinAPICall -Namespace SystemParamInfo –PassThru
 
$CursorRefresh::SystemParametersInfo(0x0057,0,$null,0)
</kode>
 
== [https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/get-filehash?view=powershell-6 SHA1] ==
<kode lang='powershell'>
function sha1 {
    param(
        [Parameter(Mandatory=$true, ValueFromPipeline=$true)]
        [string]
        $file
    )
    (Get-FileHash -Algorithm SHA1 "$file")."Hash"
}
</kode>
 
== Lister les processus qui utilisent un port ==
<kode lang='ps'>
Get-Process -Id (Get-NetTCPConnection -LocalPort 135).OwningProcess
</kode>
 
= [https://www.raydbg.com/2017/Call-Native-Win32-API-in-PowerShell/ Windows API] =
== [https://stackoverflow.com/questions/43187787/change-wallpaper-powershell Set Wallpaper] ==
<kode lang='ps'>
# C# wrapper around Windows API SystemParametersInfo
Add-Type -TypeDefinition @"
using System.Runtime.InteropServices;
 
namespace WinAPI {
    public class DesktopWallpaper
    {
        public const int SetDesktopWallpaper = 0x14;
        public const int UpdateIniFile = 0x01;
        public const int SendWinIniChange = 0x02;
   
        [DllImport("user32.dll", SetLastError=true, CharSet=CharSet.Auto)]
        public static extern int SystemParametersInfo (int uAction,
                                                      int uParam,
                                                      string lpvParam,
                                                      int fuWinIni);
                                                     
        public static void SetWallpaper(string path)
        {
            SystemParametersInfo(SetDesktopWallpaper, 0, path, UpdateIniFile | SendWinIniChange);
        }
    }
}
"@
 
[WinAPI.DesktopWallpaper]::SetWallpaper('C:\image.jpg')
</kode>
 
= [https://mathieubuisson.github.io/powershell-linux-bash/ Équivalents bash] =
* [[Powershell_configuration#Bash_tools|Bash tools]] for Windows
 
== find ==
<kode lang='ps'>
# find . -type f -iname "filename"
Get-ChildItem -Filter "*filename*" -Recurse -File
ls -r -file *filename*
</kode>
 
== sed ==
{{warn | File encoding is changed to UTF-8 without BOM}}
<kode lang='ps'>
# sed 's/txt_to_replace/replacement_text/' -i file.txt
(Get-Content file.txt) -replace 'txt_to_replace', 'replacement_text' | Set-Content file.txt
(Get-Content file.txt) -replace '^(group1).*(group2)$', '$1 text $2' | Set-Content file.txt
</kode>
 
== grep ==
<kode lang='ps'>
# ls | grep *.txt
ls | % fullname | findstr -i "\.txt\>"
# -i  Ignores the case of the characters when searching for the string
# -v  Prints only lines that do not contain a match
 
# transforme la sortie objets en stream pour y faire une recherche
ls | out-string -stream | sls "\.txt"
</kode>
 
* [https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/findstr findstr]
 
== which ==
<kode lang='powershell'>
(Get-Command notepad).Source
# C:\WINDOWS\system32\notepad.exe
 
function which($name) {
    Get-Command $name | Select-Object -ExpandProperty Definition
}
</kode>

Version du 25 juin 2020 à 19:47

Liens

Script template

À placer au début du script (en dessous de Param).

Ps.svg
# Renforce les règles de vérification et créé une erreur si elles ne sont pas respectées
Set-StrictMode -Version Latest

# Stop le script à la première erreur (par défaut à Continue)
$ErrorActionPreference = "Stop"
# en ligne de commande: .\MyScript.ps1 -ErrorAction Stop

# Force tous les Cmdlet à s'arrêter à la première erreur
$PSDefaultParameterValues['*:ErrorAction'] = 'Stop'

Astuces

Powershell.svg
# commentaire
<# commentaires 
   commentaires #>

# multilines command
command -option1 `
        -option2

# tester une commande: affiche le résultat mais n’exécute pas la commande
Commande -WhatIf

# exécuter un fichier depuis la console cmd.exe
powershell -file MonFichier.ps1
# exécuter une commande depuis la console cmd.exe
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -command "& 'C:\dossier\script.ps1' args"

# appeler un autre script powershell
& 'C:\dossier\script.ps1' args

# Supprimer l'attribut Read-Only
sp file.txt IsReadOnly $false

# ouvrir explorer (Invoke-Item)
ii .

# lancer internet explorer
$ie = New-Object -ComObject InternetExplorer.Application
$ie.Navigate2("http://www.google.com")
$ie.Visible = $true

# tester si la console est en mode admin
[bool](([System.Security.Principal.WindowsIdentity]::GetCurrent()).groups -match "S-1-5-32-544")

Variables

Pas de - dans les noms des variables.
Ps.svg
$my_var = "value"

Environment Variables

Ps.svg
# list all environment variables
Get-Childitem env:
$env:USERPROFILE C:\Users\<user>
${env:APPDATA} C:\Users\<user>\AppData\Roaming
[environment]::getfolderpath("mydocuments") C:\Users\<user>\Documents

Automatic Variables

$_ the current object in the pipeline
$Home C:\Users\<user>
$Pwd full path of the current directory
$PSCommandPath path of the script file that is being executed
$PSScriptRoot path of the script directory that is being executed

echo, Write-Host

Ps.svg
echo 'my text'

# saut de ligne
echo line1 line2
echo line1`nline2
echo line1([system.environment]::newline)line2

# colors
Write-Host -foregroundcolor green -backgroundcolor black Mon Message

# erreur
Write-Error "Error!"
Couleurs disponibles
Black Blue Cyan DarkBlue
DarkCyan DarkGray DarkGreen DarkMagenta
DarkRed DarkYellow Gray Green
Magenta Red White Yellow
echo is an alias of Write-Output

PSWriteColor

Powershell.svg
# installation du module (console administrateur)
Install-Module -Name PSWriteColor

Import-Module PSWriteColor

Write-Color "Red ", "Green ", "Yellow " -Color Red, Green, Yellow
wc "Red ", "Green ", "Yellow " -C Red, Green, Yellow
# -StartTab 1     ajoute une tabulation avant d'afficher le texte
# -LinesBefore 1  passe une ligne avant d'afficher le texte
# -LinesAfter 1   passe une ligne après avoir afficher le texte
# -LogFile "C:\log.txt"  écrit dans un fichier de log [YYYY-MM-DD HH:mm:ss]Texte

Read input

Ps.svg
# lire l'entrée clavier
$input = Read-Host 'Question?'

# Press any key to continue
Write-Host -NoNewLine 'Press any key to continue...';
$null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown');

GridView

Ps.svg
# afficher une fenêtre avec une grille
New-Object Net.Webclient | Get-Member | Out-GridView

# permettre de séléctionner des éléments dans la grille et de s'en servir comme paramètres d'entrée
Get-Service |
    Where Status -eq Stopped |
    Out-GridView -PassThru |
    Start-Service

Types

String

Ps.svg
echo "Escape `"double-quotes`""
echo "Retour à la ligne `r`n"

# concaténation de string
echo 'Text1 - ' + "Text2: ${Var1}, $Var2"
echo "Text: $(command)"

# here-string: multiline string
echo @"
First line
Second line
"Quotes don't need to be escaped"
Plus, you can include variables: $MyVar
"@

'ABC'.replace('B', '')  # AC
'abc'.toupper()  # ABC

Test string

Ps.svg
if ($MyString.startswith('xxx'))

if ($MyString)  # not null and not empty
if (!$MyString)  # null or empty

Date

Ps.svg
Get-Date -Format 'yyyy-MM'  # 2020-01

Tableau / array

Ps.svg
$myArray = @()  # empty
$myArray = 1, 2, 3
$myArray += 4

$myArray[1..2]  # 2 3
$myArray[-1]    # 4

$myArray -ne 2  # 1 3 4
$myArray -gt 2  # 3 4

[array]::Reverse($myArray)  # 4 3 2 1

$one, $two, $rest = $myArray  # $one = 1, $two = 2, $rest = 3, 4

Hash table

Ps.svg
$myHashTable = @{}  # empty
$myHashTable.Key1 = "Value1"
$myHashTable = @{
    Key1 = "Value1"
    Key2 = "Value2"
}

$myValue = $myHashTable.$myKey

"All keys: $($myHashTable.keys)"
"All values: $($myHashTable.values)"

if (!$myHashTable.contains($myKey))

PSObject

Ps.svg
$obj = New-Object PSObject -Property @{
    Prop1 = "Value1"
    Prop2 = "Value2"
}

if else

Powershell.svg
$nombre = 10
if ($nombre -eq 10) {
    "Le nombre est 10."
}
elseif (($nombre -gt 5) -and ($nombre -lt 10) -or ($nombre -eq 222)) {
    "Le nombre est entre 5 et 10 ou égal à 222."
}
elseif (!($nombre -eq 333)) {
    "Le nombre est différent de 333."
}
else { "Surement 333" }
Opérateur Description Opérateur Description
-eq == -ceq == case senstivie
-ne !=
-lt < -le <=
-gt > -ge >=
-not ! !
-and && -or ||
-band & -bor |

Test string

Bash.svg
if ([string]::IsNullOrEmpty($monString))

The String’s the Thing

switch

Powershell.svg
$result = switch ($stringVariable)
{
    Word1
    {
        'Value1'
    }
    Word2
    {
        'Value2'
    }
    ''
    {
        'Value3'
    }
    default 
    {
        'Default Value'
    }
}

Select

Powershell.svg
# parmi les résultats de command, n'affiche que UnePropriété (select = Select-Object)
command | select UnePropriété
# afficher seulement la valeur de UnePropriété (exp = expand = ExpandProperty)
(command).UnePropriété
command | select -exp UnePropriété
 
# parmi les résultats de command, n'affiche que les 10 premiers résultats
command | select -first 10

Where ?

Powershell.svg
1..4 | ? {$_ % 2 -eq 0}  # 2 4
Alias: Where-Object where ?

ForEach %

Ps.svg
1..4 | % { $_ * 2 }  # 2 4 6 8

Fonctions

Powershell.svg
Function TestName {
    param(
        [Parameter(Mandatory=$true, ValueFromPipeline=$true)]
        [string]
        $nom
    )
    if ($nom -eq "moi")
    {
        return $true
    }
    return $false
}

TestName "moi"
# True
La fonction doit être déclarée avant son utilisation.

Paramètres et Arguments

Powershell.svg
# doit se situer à la première ligne exécutable
Param (
  # avec une valeur par défaut
  [string] $Name = "initial value",

  # paramètre obligatoire
  # position permet de définir le paramètre sans son nom
  [Parameter(Mandatory = $true, Position = 0)]
  [string] $Name,

  # True par défaut. Valeurs: $true ou $false. switch est équivalent à bool
  [Parameter(Position = 1)]
  [bool] $BooleanValue,

  # avec des alias (-e -ef)
  [Alias('e','ef')]
  [string] $excludeFolder
)

# utilisation avec les noms des paramètres
.\MonScript.ps1 -Name MyName -BooleanValue $false

# utilisation avec les positions
.\MonScript.ps1 MyName $false
Mandatory = $true , demande de manière interactive les paramètres s'ils ne sont pas spécifiés.
$args fonctionne avec les arguments passés à une fonction mais pas avec ceux passés à un script.

Exclusive groups of mandatory elements

Powershell.svg
# ok: .\MyScript -Environment env1
# ok: .\MyScript -Server srv1 -Database db1
# ko: .\MyScript -Environment env1 -Server srv1 -Database db1
[CmdletBinding(DefaultParameterSetName='Env')]  # by default, Env is used
Param (
    [Parameter(ParameterSetName = 'Env', Mandatory = $true)]
    [string] $Environment,
    [Parameter(ParameterSetName = 'Srv', Mandatory = $true)]
    [string] $Server
    [Parameter(ParameterSetName = 'Srv', Mandatory = $true)]
    [string] $Database
)

# to know which ParameterSetName has been used
echo $PSCmdlet.ParameterSetName  # Env or Srv

Common parameters

Parameter
-Debug
-ErrorAction
-ErrorVariable
-OutBuffer
-OutVariable
-Verbose
-WarningAction
-WarningVariable
Ps.svg
[CmdletBinding()]  # add this line at the top of the script file
Param ()

if ($PSBoundParameters['Verbose'])  # test if Verbose has been passed as parameter

Files and folders

List

Ps.svg
# display names only
ls C:\Dossier -Name

# display fullnames (C:\Dossier\filename.ext)
ls C:\Dossier | % FullName

# display names without the extension
ls C:\Dossier | % BaseName

# filter
ls C:\Dossier *.txt
# exclude *.txt et *.dll
ls C:\Dossier -exclude *.txt, *.dll

# filter against RegEx (-NotMatch, -NotLike)
ls C:\Dossier | ? Name -Match "\.txt$"  # RegEx
ls C:\Dossier | ? Name -Like "*.txt"  # Wildcard Expression

# lister toutes les DLL et EXE avec leurs versions
ls *.dll,*.exe | % { "{0}`t{1}" -f $_.Name, [System.Diagnostics.FileVersionInfo]::GetVersionInfo($_).FileVersion }
ls dir gci are aliases of Get-ChildItem
filter et exclude ne fonctionnent pas en même temps.
Utiliser * dans le chemin à la place de filter
-exclude only applies to basenames of items myfile.txt, not the fullname C:\folder\myfile.txt

sort

Ps.svg
# sort by name
ls C:\Dossier | sort

# sort by LastWriteTime, last modified first
ls C:\Dossier | sort -property LastWriteTime -Descending

Search by name

Ps.svg
# look recursively for all the *.txt files
ls -r -ErrorAction SilentlyContinue "*.txt"

Search by file content

Ps.svg
# look recursively for files which contains xxx
ls -r C:\Dossier | sls "xxx" | group path | % name

# display all the occurences of xxx with 2 lines before and after
ls -r C:\Dossier | sls "xxx" -context 2
sls is an alias of Select-String
context ne semble plus fonctionner

Read / Get content

Ps.svg
# return an array of newline-delimited strings
$content = Get-Content .\file.txt

# return a string
$content = Get-Content .\file.txt -raw

# tail equivalent: display what is appended to the file in realtime
Get-Content .\file.txt -Wait -Tail 1

Write / Set content

Ps.svg
Set-Content -Encoding UTF8 -Path .\file.txt -Value 'Text'
Encoding values
Default UTF-8 without BOM
UTF8 UTF-8 with BOM

Replace content

The default encoding is UTF-8 without BOM
Ps.svg
(Get-Content .\file.txt) -replace 'Text', 'Content' | Set-Content .\file.txt
(Get-Content .\file.txt) -replace 'var=(\w+);', "var=$new_value;" | Set-Content .\file.txt

Delete files based on pattern

Ps.svg
# delete all the *.txt files
ls *.txt | Remove-Item

Créer / supprimer un dossier

Ps.svg
# suppression d'un dossier et de son contenu
rm -r -fo C:\Dossier
# -r  / -recurse
# -fo / -force
# -ErrorAction Continue

# test before delete to avoid error
if (test-path C:\Dossier) { rm -r C:\Dossier }

# | Out-Null permet de masquer la sortie
ni C:\Dossier -type directory | Out-Null

# -force écrase le fichier s'il existe déjà, pour un dossier cela permet juste d'éviter l'erreur « Item already exists »
ni C:\Dossier -type directory -force
Alias de Remove-Item: del, erase, rd, ri, rm, rmdir
Alias de New-Item: ni

Remove-Item

Path

Powershell.svg
# dossier1\dossier2
join-path dossier1 dossier2
join-path -path dossier1 -childpath dossier2  
join-path -path dossier1\ -childpath \dossier2\
 
join-path -path dossier1 -childpath (join-path -path dossier2 -childpath dossier3)
# dossier1\dossier2\dossier3

# utilisation du Framework .NET
[System.IO.Path]::Combine("C:\Dossier1", "Dossier2", "Dossier3")
# C:\Dossier1\Dossier2\Dossier3
 
# test si le chemin c:\dossier existe
if (Test-Path C:\Dossier -PathType Container) { }

# test si le chemin c:\dossier existe
if (Test-Path C:\Dossier\file.txt -PathType Leaf) { }

Copy-Item

Powershell.svg
# copie de Fichier.txt dans Dossier2 sous le nom de Fichier2.txt
# dans ce cas Dossier2 n'est pas créé s'il n'existe pas
cp C:\Dossier\Fichier.txt C:\Dossier2\Fichier2.txt
 
# copie récursive de Dossier dans Dossier2 (création de Dossier2 s'il n'existe pas)
cp -recurse C:\Dossier C:\Dossier2
 
# copie récursive de l'arborescence de Dossier dans Dossier2 et copie des fichiers *.txt exclusivement
cp C:\Dossier C:\Dossier2 -recurse -filter *.txt

# copie tous les *.txt en excluant les *.bak.txt
cp C:\Dossier\*.txt C:\Dossier2 -exclude *.bak.txt

# copie récursive avec exclusion
$from = convert-path (join-path $Path1 '..\Dossier') # convert-path pour supprimer les ..
ls -r $from -exclude *.pdb, *.xml | % {
    cp $_.FullName (join-path $to $_.FullName.Substring($from.length))
}
Alias Copy-Item copy cp cpi
Exclude ne fonctionne pas avec les répertoires

Measure / Count

Powershell.svg
ls | measure
# Count    : 8   
# Average  :     
# Sum      :     
# Maximum  :     
# Minimum  :     
# Property :     

# compter le nombre d'éléments dans le dossier courant
(ls | measure).Count;

Log

Ps.svg
# log in MyProgram.log in the same folder
Start-Transcript -path $PSCommandPath.replace('.ps1', '.log')

Échapper les caractères spéciaux

Powershell.svg
echo '$dollar'  # $dollar
echo `$dollar   # $dollar

Encoding

Si la sortie affiche des caractères inattendus, utiliser l'encodage UTF-8 avec BOM.

Expressions rationnelles

Shutdown - Restart

Ps.svg
Stop-Computer
Restart-Computer

Batch commands

Active Directory

Powershell.svg
Import-Module activedirectory

Get-ADUser -filter *

Services

Powershell.svg
# affiche l'état d'un service
get-service 'SQLBrowser'
# Stopped / Running

$ServiceName = 'MSSQL$SQLEXPRESS'
if ((get-service $ServiceName).Status -eq 'Stopped') {
    # démarrer un service, nécessite les droits administrateur
    start-service $ServiceName -PassThru
    # PassThru force l'affichage d'un message de sortie
}
else {
    echo "$ServiceName est déjà démarré."
}

MessageBox

Powershell.svg
[void][Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
[void][System.Windows.Forms.MessageBox]::Show("Hello !")

Web

Powershell.svg
# get the content and detect the output format: XML or JSON
Invoke-RestMethod http://www.domain.net/api/values | % { $_ | select Prop1, Prop2 | Out-GridView }

Invoke-RestMethod http://localhost:111/api/values -Method POST -Body @{value='2'}

Invoke-WebRequest http://localhost:111/api/values -H @{"accept"="application/xml"} | Select-Object -Expand Content

$content = (New-Object Net.WebClient).DownloadString("http://www.google.fr")

Target HTML

Ps.svg
$url = "http://www.domain.net"
$result = Invoke-WebRequest $url

$result.AllElements |
    Where Class -eq "some css class" |
    Select -First 1 -ExpandProperty innerText

Registre

Powershell.svg
$RegKey ="HKCU:\Control Panel\Cursors"
# Obtenir la valeur de la clé IBeam
Get-ItemProperty -Path "HKCU:\Control Panel\Cursors" | select -ExpandProperty IBeam
# Changement de la valeur de la clé IBeam
Set-ItemProperty -Path $RegKey -Name IBeam -Value "%SystemRoot%\cursors\beam_r.cur"

Use C# code

Ps.svg
Add-Type -TypeDefinition @"
public class Compute {
    public int Add(int n1, int n2) {
        return n1 + n2;
    }
}
"@

# load an assembly
Add-Type -Path C:\Folder\Compute.dll

$compute = New-Object Compute
$compute.Add(6, 4)  # 10

Exemples

Recherche de texte dans tous les fichiers - rg - ripgrep

Powershell.svg
Function rg {
    param(
        [Parameter(Mandatory=$true, ValueFromPipeline=$true)]
        [string]
        $pattern
    )
    ls -r | sls $pattern -context 2 |
		foreach {
			"{0} : {1:00}" -f $_.Path, $_.LineNumber
			if ($_.Context.PreContext) {"  {0}" -f $_.Context.PreContext }
			"> {0}" -f $_.Line
			if ($_.Context.PostContext) { "  {0}" -f $_.Context.PostContext }
			""
		} 
}

Stocker et récupérer un mot de passe

Powershell.svg
# store password
$Password = "Password123!@#"
$SecurePassword = $Password | ConvertTo-SecureString -AsPlainText -Force  # SecureString
# ou demande du password
$SecurePassword = Read-Host -Prompt "Enter password" -AsSecureString
# ou demande du password avec Get-Credential
$Credential = Get-Credential -Message "Enter password" -Username "-"
$SecurePassword = $Credential.Password
$SecureStringAsPlainText = $SecurePassword | ConvertFrom-SecureString  # String
Set-Content "C:\Dossier\Password.txt" $SecureStringAsPlainText

# get the password
$SecureStringAsPlainText = Get-Content "C:\Dossier\Password.txt"  # String
$SecurePassword = $SecureStringAsPlainText | ConvertTo-SecureString  # SecureString
$Credential = New-Object PSCredential "user",$SecurePassword
$PlainPassword = $Credential.GetNetworkCredential().Password  # password en clair

Modifier le pointeur de la sourie

Powershell.svg
# changement du pointeur Text Selection
$RegKey ="HKCU:\Control Panel\Cursors"
Set-ItemProperty -Path $RegKey -Name IBeam -Value "%SystemRoot%\cursors\beam_r.cur"

# Rafraichissement des curseurs pour prendre en compte le changement
$CSharpSig = @'
[DllImport("user32.dll", EntryPoint = "SystemParametersInfo")]
public static extern bool SystemParametersInfo(
  uint uiAction,
  uint uiParam,
  uint pvParam,
  uint fWinIni);
'@

$CursorRefresh = Add-Type -MemberDefinition $CSharpSig -Name WinAPICall -Namespace SystemParamInfo –PassThru

$CursorRefresh::SystemParametersInfo(0x0057,0,$null,0)

SHA1

Powershell.svg
function sha1 { 
    param(
        [Parameter(Mandatory=$true, ValueFromPipeline=$true)]
        [string]
        $file
    )
    (Get-FileHash -Algorithm SHA1 "$file")."Hash"
}

Lister les processus qui utilisent un port

Ps.svg
Get-Process -Id (Get-NetTCPConnection -LocalPort 135).OwningProcess

Windows API

Set Wallpaper

Ps.svg
# C# wrapper around Windows API SystemParametersInfo
Add-Type -TypeDefinition @"
using System.Runtime.InteropServices;

namespace WinAPI {
    public class DesktopWallpaper
    {
        public const int SetDesktopWallpaper = 0x14;
        public const int UpdateIniFile = 0x01;
        public const int SendWinIniChange = 0x02;
    
        [DllImport("user32.dll", SetLastError=true, CharSet=CharSet.Auto)] 
        public static extern int SystemParametersInfo (int uAction, 
                                                       int uParam, 
                                                       string lpvParam, 
                                                       int fuWinIni);
                                                       
        public static void SetWallpaper(string path)
        {
            SystemParametersInfo(SetDesktopWallpaper, 0, path, UpdateIniFile | SendWinIniChange);
        }
    }
}
"@

[WinAPI.DesktopWallpaper]::SetWallpaper('C:\image.jpg')

Équivalents bash

find

Ps.svg
# find . -type f -iname "filename"
Get-ChildItem -Filter "*filename*" -Recurse -File
ls -r -file *filename*

sed

File encoding is changed to UTF-8 without BOM
Ps.svg
# sed 's/txt_to_replace/replacement_text/' -i file.txt
(Get-Content file.txt) -replace 'txt_to_replace', 'replacement_text' | Set-Content file.txt
(Get-Content file.txt) -replace '^(group1).*(group2)$', '$1 text $2' | Set-Content file.txt

grep

Ps.svg
# ls | grep *.txt
ls | % fullname | findstr -i "\.txt\>"
# -i  Ignores the case of the characters when searching for the string
# -v  Prints only lines that do not contain a match

# transforme la sortie objets en stream pour y faire une recherche
ls | out-string -stream | sls "\.txt"

which

Powershell.svg
(Get-Command notepad).Source
# C:\WINDOWS\system32\notepad.exe

function which($name) {
    Get-Command $name | Select-Object -ExpandProperty Definition
}