PowerShell

De knowledge
Aller à la navigation Aller à la recherche

PowerShell on aime ou on aime pas (moi j'aime pas) mais quoi qu'il en soit il faut l'utiliser si on a un PC sous Windows. Donc voila une page dans ce but.

Introduction à PowerShell

Contrairement aux shells Unix traditionnels (Bash, Korn Shell, Zsh, etc.), PowerShell n'a pas été conçu comme un interpréteur de commandes manipulant principalement du texte.

La philosophie de PowerShell repose sur une idée simple :

Tout est objet.

Lorsqu'une commande produit un résultat, elle ne renvoie généralement pas du texte mais des objets .NET contenant des propriétés et des méthodes.

Par exemple, sous Linux :

ps -ef | grep python

Les différentes commandes échangent des lignes de texte qu'il faut ensuite analyser.

Sous PowerShell :

Get-Process |
    Where-Object ProcessName -eq "python"

Les commandes manipulent directement des objets représentant des processus. Il n'est donc pas nécessaire d'extraire ou de parser du texte.

Les cmdlets

Les commandes PowerShell sont appelées cmdlets (prononcer "command lets").

Elles suivent généralement la convention :

Verbe-Nom

Exemples :

Get-Process
Get-Service
Get-ChildItem

Start-Process
Stop-Service

New-Item
Remove-Item

Cette convention permet de deviner facilement le rôle d'une commande.

Par exemple :

Get-Command *Process*

affichera les commandes permettant de manipuler des processus.

Le pipeline d'objets

Le caractère | conserve le même rôle général que sous Unix : transmettre le résultat d'une commande à la suivante.

Cependant, la nature des données transmises est différente.

Sous Linux :

ps -ef | grep chrome

Le pipeline transporte du texte.

Sous PowerShell :

= Alias, fonctions et profil utilisateur =

== Introduction ==

PowerShell dispose d'un mécanisme similaire aux fichiers ''~/.profile'', ''~/.bash_profile'' ou ''~/.bashrc'' sous Linux.

Le profil PowerShell permet de définir automatiquement :

* des alias ;
* des fonctions ;
* des variables d'environnement ;
* des personnalisations du terminal.

Le script est exécuté à chaque ouverture d'une session PowerShell.

== Le fichier de profil PowerShell ==

Le chemin du profil courant est stocké dans la variable :

<syntaxhighlight lang="powershell">
$PROFILE

Exemple :

C:\Users\jp38c44n\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1

Afficher le chemin :

$PROFILE

Vérifier si le profil existe :

Test-Path $PROFILE

Créer le répertoire et le fichier si nécessaire :

mkdir (Split-Path $PROFILE) -Force
notepad $PROFILE

Recharger le profil sans fermer le terminal :

. $PROFILE

Correspondance avec Linux

Linux PowerShell
~/.bashrc Microsoft.PowerShell_profile.ps1
alias ll='ls -la' function ll { Get-ChildItem -Force }
export VAR=valeur $env:VAR = "valeur"
source ~/.bashrc . $PROFILE

Créer un alias simple

Alias temporaire pour la session courante :

Set-Alias vi vim

Afficher tous les alias :

Get-Alias

Afficher un alias particulier :

Get-Alias vi

Limitation des alias

Un alias ne peut pointer que vers une seule commande.

Ceci fonctionne :

Set-Alias ll Get-ChildItem

Ceci ne fonctionne pas :

Set-Alias gm '$env:NODE_USE_SYSTEM_CA = 1; gemini'

Pour exécuter plusieurs instructions, il faut utiliser une fonction.

Créer une fonction

Exemple :

function ll {
    Get-ChildItem -Force
}

Fonction acceptant des arguments :

function grep {
    Select-String @args
}

Utilisation :

grep erreur fichier.log

Exemples

Lancer Gemini avec NODE_USE_SYSTEM_CA

C'est utile pour les entreprises qui utilisent un proxy interne pour l'utilisation de Google Gemini code assis CLI par exemple.

Dans le profil :

function sgm {
    $env:NODE_USE_SYSTEM_CA = 1
    gemini @args
}

Utilisation :

sgm

ou :

sgm "Explique les alias PowerShell"

Script automatique pour gérer un mini écran.

J'ai acheté un mini écran HDMI pour avoir une console d'urgence pour mes Raspberry PI. Mais, entre deux urgences je l'utilise comme second ou troisième écran sur mon laptop.

Je l'utilise souvent pour afficher une page de liens et qui donne l'heure. Mais c'est fastidieux de lancer chrome à chaque coup de le déplacer dans l'écran en question...

Je me suis dit qu'un script powerShell serait idéal. Plusieurs questions :

  1. Comment l'écrire alors que je ne suis pas expert en PowerShell (énumérer les écrans, détecter celui qui fait 600x1024 etc.)
  2. Comment le lancer automatiquement le script (y'a plus d'autoexec.bat et cela me surprendrais que ce soit un .profile dans $HOME)

Alors j'ai demandé a mon ami Copilot qui sait tout.

Lancer un script automatiquement

Non il n'y a plus de autoexec.bat sous Windows depuis... très longtemps. Il y a une variable d'environnement : shell:startup

Soit on tape shell:startup dans la barre d'adresse du l'explorer, soit on lance la commande PowerShell:

explorer.exe shell:startup

dans les deux cas ca ouvre l'explorateur à l'endroit ou on doit mettre les trucs a lancer au démarrage.

Moi ca me donne un truc du genre:

C:\Users\<<USER>>\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup

On est chez Microsoft pourquoi faire simple?

On pourrait se dire : "zou je balance mon script .ps1 dans ce répertoire et roule!". Et bien NON! L'action par défaut sous Windows pour les fichiers .ps1 c'est... Notepad!

Donc si on pose le script .ps1 dans shell:startup, et bien au login ça... ouvre le fichier dans notepad. Il faut, soit changer le programme par défaut des .ps1 soit créer un moche raccourci soit faire un script "cmd" qui lui même appelle le .ps1.

Je sais pas laquelle est la plus crade; mais j'ai choisit la dernière solution.

Je crée seulement un script cmd pour lancer le script ps1 qui lui même va lancer chrome!

Le script pour lancer le script :

@echo off
powershell.exe -ExecutionPolicy Bypass -WindowStyle Hidden -File "C:\Users\<<MONREP>>\screen-auto.ps1"

Le @echo off on connait c'est vieux comme MSDOS 2.0 (peut être 1.0 j'ai jamais connu).

Les options de powershell.exe
-ExecutionPolicy Bypass

Définit temporairement la politique d'exécution pour cette instance PowerShell uniquement.

Sans cette option, ton script peut être bloqué par la politique de sécurité de la machine.

Les valeurs les plus courantes sont :

Valeur Signification
Restricted Aucun script autorisé
RemoteSigned Les scripts téléchargés doivent être signés
Unrestricted Tout autorisé avec avertissement
Bypass Tout autorisé, aucun avertissement

Avec :

PowerShell

-ExecutionPolicy Bypass

PowerShell exécute le script sans poser de question, même si la politique normale de la machine est restrictive.

C'est très courant pour les scripts lancés automatiquement au démarrage.

-WindowStyle Hidden

Demande à PowerShell de masquer sa propre fenêtre.

Sans cette option : On verras une fenêtre noire apparaître quelques instants et c'est très moche...

Avec : PowerShell -WindowStyle Hidden

le script s'exécute en arrière-plan sans fenêtre visible.

Pratique pour :

  • scripts de démarrage
  • automatisations

À noter que cela ne masque pas les programmes lancés par le script. Si le script ouvre Chrome, Chrome sera visible.

-File

Indique à PowerShell que ce qui suit est un fichier .ps1 à exécuter.

Exemple :

PowerShell

-File "C:\Users\<<MONREP>>\screen-auto.ps1"

PowerShell charge et exécute ce fichier.

Sans -File, PowerShell interprète les arguments différemment.

Bon maintenant qu'on a fait le script pour lancer le script, on va écrire le script pour lancer chrome.

Lancer Crome, sur le bon écran en plein écran.

Le script que Copilot m'a mitonné:

Add-Type -AssemblyName System.Windows.Forms

# Recherche de l'écran portrait 600x1024
$targetScreen = [System.Windows.Forms.Screen]::AllScreens |
    Where-Object {
        ($_.Bounds.Width -eq 600 -and $_.Bounds.Height -eq 1024) -or
        ($_.Bounds.Width -eq 1024 -and $_.Bounds.Height -eq 600)
    } |
    Select-Object -First 1

if (-not $targetScreen) {
    Write-Host "Petit écran non détecté."
    exit
}

$url = "https://scratch.pinon-hebert.fr/"

$chrome = Start-Process `
    chrome.exe `
    -ArgumentList `
        "--user-data-dir=$env:TEMP\ChromeDashboard", `
        "--new-window", `
        "--kiosk", `
        $url `
    -PassThru

Start-Sleep -Seconds 5

$hwnd = $null

for ($i = 0; $i -lt 20; $i++) {
    $proc = Get-Process chrome |
        Where-Object MainWindowHandle -ne 0 |
        Select-Object -First 1

    if ($proc) {
        $hwnd = $proc.MainWindowHandle
        break
    }

    Start-Sleep -Milliseconds 500
}

if (-not $hwnd) {
    exit
}

Add-Type @"
using System;
using System.Runtime.InteropServices;

public class Win32 {
    [DllImport("user32.dll")]
    public static extern bool MoveWindow(
        IntPtr hWnd,
        int X,
        int Y,
        int nWidth,
        int nHeight,
        bool bRepaint
    );

    [DllImport("user32.dll")]
    public static extern bool ShowWindow(
        IntPtr hWnd,
        int nCmdShow
    );
}
"@

$x = $targetScreen.Bounds.X
$y = $targetScreen.Bounds.Y
$w = $targetScreen.Bounds.Width
$h = $targetScreen.Bounds.Height

[Win32]::MoveWindow($hwnd, $x, $y, $w, $h, $true)

# Maximiser
[Win32]::ShowWindow($hwnd, 3)

Toute une partie de la ruse est dans les options de chrome (c'est pas du PowerShell là) :

chrome.exe `
    -ArgumentList `
        "--user-data-dir=$env:TEMP\ChromeDashboard", `
        "--new-window", `
        "--kiosk", `
        $url `

Les arguments sont :

  • --user-data-dir=$env:TEMP\ChromeDashboard pour faire démarrer une session séparée
  • --new-window comme son nom l'indique c'est pour ouvrir la page dans une nouvelle fenêtre sinon ca va faire un onglet dans un chrome partagé
  • --kiosk c'est pour l'ouvrir en mode kiosque. Envoyer un F11 pour l'avoir en plein écran était possible mais super lourd. (et je suis pas une bête en powerShell)
  • $url... c'est l'URL à ouvrit

Voila un bien joli script!