// documentation officielleofficial documentation

Guide Ultime
PulsiForms

Ultimate Guide
PulsiForms

Tout ce qu'il faut pour écrire du PowerShell / WinForms compatible PulsiForms — du premier contrôle posé sur le canvas jusqu'aux traitements asynchrones qui ne gèlent jamais l'interface. Chaque commande, chaque signature et chaque exemple de ce guide est vérifié directement dans le moteur PulsiForms.
Everything you need to write PulsiForms-compatible PowerShell / WinForms — from your first control on the canvas to async work that never freezes the UI. Every command, signature and example in this guide is verified directly against the PulsiForms engine.
v55 Deep AI WinForms .NET PowerShell 5.1+ PF-Script Stdlib v2.0
🤖
Une question pendant la lecture ? L'assistant IA local de l'application PulsiForms fonctionne hors-ligne : il connaît toutes les commandes PF-Script, explique chaque paramètre et propose des exemples de code prêts à coller. Demandez-lui « explique Start-PF » ou « exemple de Validate-PF ». A question while reading? The local AI assistant built into the PulsiForms app works offline: it knows every PF-Script command, explains each parameter and offers ready-to-paste code examples. Ask it "explain Start-PF" or "Validate-PF example".

Besoin de retrouver vite une signature ? L'📖 Référence des commandes présente les 28 verbes en fiches dépliables : signature, paramètres et exemple. Ce guide-ci explique quand et pourquoi les utiliser ; la référence sert d'aide-mémoire. Need to look up a signature fast? The 📖 Command reference lists all 28 verbs as collapsible cards: signature, parameters and example. This guide explains when and why to use them; the reference is the cheat sheet.

🚀
Jamais ouvert PulsiForms ? Commencez par le tutoriel pas-à-pas « Crée ta première application » : 6 étapes guidées pour construire un vrai outil Windows en 16 minutes, puis revenez ici pour approfondir. New to PulsiForms? Start with the step-by-step tutorial "Build your first app": 6 guided steps to build a real Windows tool in 16 minutes, then come back here to go deeper.

🔄 Comment PulsiForms génère le PS1How PulsiForms generates the PS1

PulsiForms n'est pas un éditeur de texte : c'est un compilateur visuel. Vos actions graphiques (drag & drop, propriétés, code d'événement) sont transformées en un script PowerShell autonome.

PulsiForms is not a text editor: it is a visual compiler. Your graphical actions (drag & drop, properties, event code) are turned into a self-contained PowerShell script.

🖱️
Canvas
Drag & Drop
→
🗄️
Modèle d'état
Modèle JSJS model
→
⚙️
Moteur d'export
GénérateurGenerator
→
📄
Script .ps1
+ Stdlib+ Stdlib

À l'export, PulsiForms injecte automatiquement la bibliothèque PF-Script Stdlib en tête du script. Vous disposez ainsi de fonctions prêtes à l'emploi (Show-PF, Get-PF, Start-PF…) sans rien réécrire.

On export, PulsiForms automatically injects the PF-Script Stdlib at the top of the script. You get ready-to-use functions (Show-PF, Get-PF, Start-PF…) without rewriting anything.

PowerShell généré — exemple ButtonGenerated PowerShell — Button example
# PulsiForms génère ceci automatiquement : $Button_1 = New-Object System.Windows.Forms.Button $Button_1.Text = "Valider" $Button_1.Location = New-Object System.Drawing.Point(50, 80) $Button_1.Size = New-Object System.Drawing.Size(120, 38) # Votre code d'événement est injecté ICI : $Button_1.Add_Click({ ### ← votre code arrive ici ### }) $cp.Controls.Add($Button_1)
💡
Le code écrit dans l'éditeur Code PS est placé à l'intérieur du bloc { ... } de l'événement. PulsiForms s'occupe de la création, du positionnement et du style.The code you write in the Code PS editor is placed inside the event's { ... } block. PulsiForms handles creation, positioning and styling.

❌ « Variable non déclarée » — le piège n°1"Variable not declared" — pitfall #1

L'erreur la plus fréquente vient d'une incompréhension du scope PowerShell. Chaque événement Add_Click({ ... }) est un scriptblock avec son propre scope : une variable créée dans un événement n'existe pas dans un autre.

The most common error comes from misunderstanding PowerShell scope. Each Add_Click({ ... }) event is a scriptblock with its own scope: a variable created in one event does not exist in another.

❌
Ce qui ne marche pas
What doesn't work
# Button_1 Click : $monNom = $TextBox_1.Text # Button_2 Click : $Label_1.Text = $monNom # vide !
✅
La bonne approche
The right approach
# Button_1 Click : $global:monNom = $TextBox_1.Text # Button_2 Click : $Label_1.Text = $global:monNom

# Les 3 scopes à connaîtreThe 3 scopes to know

🌍
$global:
Accessible partout, dans tous les événements. Pour les données partagées entre contrôles.
Accessible everywhere, in every event. For data shared between controls.
📜
$script:
Scope du script entier. Utilisé par PulsiForms pour $script:form et $script:_controls.
Whole-script scope. Used by PulsiForms for $script:form and $script:_controls.
📦
(local)
Variable sans préfixe. Valable uniquement dans le bloc { } courant.
Variable with no prefix. Valid only inside the current { } block.
⚠️
Le nom de variable du contrôle dans le panneau Propriétés est exactement ce qu'il faut écrire. Si le contrôle s'appelle TextBox_3, écrivez $TextBox_3 — pas $TextBox3, pas $tb.The control's variable name in the Properties panel is exactly what to type. If the control is named TextBox_3, write $TextBox_3 — not $TextBox3, not $tb.

# Référencer le formulaireReferencing the form

$script:form
$form.Close() # ❌ $form non défini dans ce scope $script:form.Close() # ✅ toujours $script:form $script:form.Text = "Titre" # ✅ change le titre de la fenêtre

📐 Règles fondamentalesCore rules

❌ Ne pas écrireDon't write✅ Compatible PulsiFormsPulsiForms compatible
$form.Close()$script:form.Close()
[Windows.Forms.MessageBox]::Show("x")Alert-PF "x" / Show-PF "x"
$maVar = "v" (entre 2 events)$global:maVar = "v"
Write-Host "debug"Show-PF "debug"
Start-Sleep -Seconds 3 (gèle l'UI)Sleep-PF -Ms 3000 / Wait-PF
$script:txt.Text depuis -WorkWrite-PF $script:txt "v" (thread-safe)
✅
Toutes les fonctions *-PF sont thread-safe (gestion automatique de InvokeRequired / .Invoke()) : vous pouvez les appeler depuis un callback async sans crash inter-thread.All *-PF functions are thread-safe (automatic InvokeRequired / .Invoke() handling): you can call them from an async callback without cross-thread crashes.
// le plus importantmost important

⚡ Async — ne jamais geler l'interfaceAsync — never freeze the UI

Un traitement long (lecture de fichiers, requête réseau, boucle lourde) exécuté directement dans un Add_Click gèle l'interface : la fenêtre devient blanche, Windows affiche « Ne répond pas ». PulsiForms fournit trois outils pour l'éviter. Choisissez selon ce dont vous avez besoin.

A long task (file reading, network request, heavy loop) run directly inside an Add_Click freezes the UI: the window goes white and Windows shows "Not responding". PulsiForms provides three tools to avoid this. Choose based on what you need.

Mon traitement a-t-il besoin de lire/écrire des contrôles PENDANT son exécution ?Does my task need to read/write controls DURING execution?
├─ NON · tâche de fond, je veux juste le résultat à la finbackground task, I just want the result at the end → Start-PF
├─ NON · + je veux un dialog « patientez » avec Annuler+ I want a "please wait" dialog with Cancel → Wait-PF
└─ OUI · boucle courte qui met à jour une ProgressBar en directshort loop updating a ProgressBar live → Sleep-PF
🚫
La règle d'or du runspace. Le bloc -Work de Start-PF et Wait-PF s'exécute dans un runspace isolé (autre thread). Il n'a aucun accès à $script: ni aux contrôles. Pour faire entrer des données → paramètre -With @{}. Pour récupérer le résultat → bloc -Then. The runspace golden rule. The -Work block of Start-PF and Wait-PF runs in an isolated runspace (separate thread). It has no access to $script: or controls. To pass data in → -With @{}. To get the result out → the -Then block.
⚡Start-PFTâche de fond non-bloquante, sans dialogNon-blocking background task, no dialogASYNC
Start-PF -Work {…} [-Then {…}] [-Catch {…}] [-With @{}]

-Work ScriptBlock exécuté en arrière-plan (runspace isolé). Reçoit $_shared en argument — qui contient les clés passées via -With. · -Then callback UI au succès, reçoit le résultat de -Work. · -Catch callback UI en cas d'erreur, reçoit le message. · -With hashtable de données injectées dans le runspace.

-Work ScriptBlock run in the background (isolated runspace). Receives $_shared as argument — containing the keys passed via -With. · -Then UI callback on success, receives -Work's result. · -Catch UI callback on error, receives the message. · -With hashtable of data injected into the runspace.

Start-PF
# Lire un gros fichier sans geler la fenêtre $chemin = Get-PF $TextBox_1 Start-PF -Work { param($s) # $s = $_shared $lignes = Get-Content $s.Path return $lignes.Count # transmis à -Then } -With @{ Path = $chemin } -Then { param($r) # $r = résultat Write-PF $Label_1 "$r lignes" Show-PF "Terminé !" -IsSuccess } -Catch { param($err) Alert-PF "Échec : $err" -IsError }
⏳Wait-PFAsync + dialog « patientez » avec spinner & AnnulerAsync + "please wait" dialog with spinner & CancelASYNC→ result
Wait-PF -Work {…} [-Then {…}] [-Catch {…}] [-With @{}] [-Message str] [-Title str] [-NoCancelBtn]

Même moteur que Start-PF, mais affiche un dialog modal avec spinner animé. Le worker doit tester $_shared["_canceled"] pour s'arrêter proprement si l'utilisateur clique Annuler. Retourne le résultat de -Work, ou $null si annulé/erreur.

Same engine as Start-PF, but shows a modal dialog with an animated spinner. The worker must check $_shared["_canceled"] to stop cleanly if the user clicks Cancel. Returns -Work's result, or $null if cancelled/error.

Wait-PF
$result = Wait-PF -Message "Import en cours…" -Work { param($s) foreach ($item in $s.Liste) { if ($s["_canceled"]) { break } # arrêt propre # … traitement lourd ici … } return "Terminé" } -With @{ Liste = $maListe } -Then { param($r) Show-PF $r -IsSuccess }
🔄Sleep-PFPause SYNCHRONE (thread UI) — accès direct à $script:SYNC pause (UI thread) — direct $script: accessSYNC→ bool
Sleep-PF [-Ms int] [-Message str] [-Title str] [-NoCancelBtn] [-End]

Contrairement à Wait-PF, Sleep-PF reste sur le thread UI (boucle DoEvents) : $script: et les contrôles sont accessibles directement dans la boucle appelante. Idéal pour une boucle courte qui met une ProgressBar à jour. Retourne $true si Annuler cliqué. Toujours appeler Sleep-PF -End en fin de boucle (dans un finally).

Unlike Wait-PF, Sleep-PF stays on the UI thread (DoEvents loop): $script: and controls are directly accessible in the calling loop. Ideal for a short loop updating a ProgressBar. Returns $true if Cancel was clicked. Always call Sleep-PF -End at the end of the loop (in a finally).

⚠️
Ne jamais utiliser Sleep-PF à l'intérieur d'un -Work de Start-PF/Wait-PF (runspace séparé). Sleep-PF est réservé au thread UI.Never use Sleep-PF inside a Start-PF/Wait-PF -Work block (separate runspace). Sleep-PF is for the UI thread only.
Sleep-PF — boucle avec ProgressBarSleep-PF — loop with ProgressBar
Lock-PF # verrouille la fenêtre try { for ($i = 1; $i -le 100; $i++) { Set-PF $ProgressBar_1 -Value $i # ✅ accès direct Write-PF $Label_1 "Étape $i/100" # ✅ idem if (Sleep-PF -Ms 80 -Message "Traitement $i/100…") { break } } } finally { Sleep-PF -End # ferme le dialog — garanti même si exception Unlock-PF } Show-PF "Import terminé !" -IsSuccess
📡Watch-PFStreame la sortie d'une commande EN DIRECT dans une RichTextBoxStreams a command's output LIVE into a RichTextBoxASYNCNOUVEAU
Watch-PF { commande } -Into $RichTextBox [-Then {…}] [-Append] [-NoFollow] [-NoColor]

Même moteur que Start-PF (runspace + timer) : la commande tourne en arrière-plan et un timer UI vide la file dans le contrôle, ligne par ligne. Les erreurs sont colorées en rouge (sauf -NoColor) et le contrôle défile automatiquement (sauf -NoFollow). -Then s'exécute sur le thread UI à la fin.

Same engine as Start-PF (runspace + timer): the command runs in the background and a UI timer drains the queue into the control, line by line. Errors are coloured red (unless -NoColor) and the control auto-scrolls (unless -NoFollow). -Then runs on the UI thread at the end.

⚠️
Le bloc de commande tourne dans un runspace isolé : aucun accès UI direct dedans (pas de Set-PF, Fill-PF, $ctrl.Text). Utilisez -Then.The command block runs in an isolated runspace: no direct UI access inside. Use -Then.
Watch-PF { ping "8.8.8.8" -n 10 } -Into $RichTextBox_1 Watch-PF { Get-ChildItem "C:\Temp" -Recurse } -Into $RichTextBox_1 -Then { Show-PF "Analyse terminée" -IsSuccess }

# Tableau comparatifComparison table

Start-PFWait-PFSleep-PF
ThreadThreadRunspaceRunspaceUI
Bloquant ?Blocking?Non / NoModalModalBoucle UIUI loop
DialogDialog—✅ spinner + Annuler✅ spinner + Annuler
Accès $script:$script: access❌ -With/-Then❌ -With/-Then✅ direct
UsageUsetâche de fondbackground taskopération longue avec attentelong op with waitboucle + ProgressBarloop + ProgressBar

📚 Référence des commandes PF-ScriptPF-Script command reference

Toutes ces fonctions sont injectées automatiquement à l'export. Signatures vérifiées dans le moteur (Stdlib v2.0).

All these functions are auto-injected at export. Signatures verified against the engine (Stdlib v2.0).

# Notifications & dialogsNotifications & dialogs

🔔Show-PFToast non-bloquant (3 s)Non-blocking toast (3 s)
Show-PF -Message str [-IsWarning] [-IsError] [-IsSuccess]
Show-PF "Enregistré." -IsSuccess
🪟Toast-PFNotification Windows NATIVE (centre de notifications)NATIVE Windows notification (Action Center)NOUVEAU→ bool
Toast-PF -Message str [-Title str] [-Type Info|Success|Warning|Error] [-Duration ms] [-Icon str] [-Silent] [-OnClick {…}] [-AppId str] [-PassThru]
# forme courte équivalente toast("Message") · toast("Message", { title: "…", type: "success" })

Complément de Show-PF, pas un remplaçant. Show-PF = bulle dans la fenêtre (disparaît avec elle). Toast-PF = notification du système : visible fenêtre minimisée, conservée dans le centre de notifications, sonore et cliquable. Seul verbe de notification autorisé dans un bloc -Work (il ne touche aucun contrôle WinForms). -Duration : Windows n'a que 2 paliers, ≥ 15000 ms = long (~25 s), sinon court (~7 s).

Complements Show-PF, does not replace it. Show-PF = bubble inside the window. Toast-PF = system notification: visible when minimised, kept in the Action Center, audible and clickable. The only notification verb allowed inside a -Work block. -Duration: Windows only has 2 tiers, ≥ 15000 ms = long, else short.

🖼️
Logo — réglez-le une fois pour toute l'application : bouton $form → onglet Propriétés → section Application. Placez le PNG à côté du .ps1/.msix exporté et saisissez .\logo.png. L'image n'est pas embarquée : distribuez-la avec l'application.Logo — set it once for the whole app: the $form button → Properties tab → Application section. Put the PNG next to the exported .ps1/.msix and enter .\logo.png. The image is not embedded: ship it with the app.
⚠️
Si Windows refuse la notification (identité non enregistrée, session non interactive), Toast-PF replie automatiquement sur le toast in-app — jamais d'échec silencieux. La cause est dans $script:PFToastError.If Windows refuses the notification, Toast-PF falls back to the in-app toast — never a silent failure. Reason in $script:PFToastError.
toast("Sauvegarde effectuée") # 1 ligne suffit toast("Mise à jour disponible", { title: "Pulsiforms", type: "info" }) toast("Export terminé", { type: "success", sound: false }) # muet toast("Serveur injoignable", { type: "error", onClick: { Go-PF "Journal" } }) # forme canonique + gestion d'erreur if (-not (Toast-PF -Message "Terminé" -Type "Success")) { Write-PF $Label_1 $script:PFToastError }
💬Alert-PFMessageBox thématique modaleThemed modal MessageBox
Alert-PF -Message str [-IsSuccess] [-IsWarning] [-IsError] [-Title str] [-Detail str] [-OkText str]
Alert-PF "Connexion perdue." -IsError
❓Ask-PFConfirmation Oui/NonYes/No confirmation→ bool
Ask-PF -Question str [-Title str] [-YesNo] [-Detail str] [-YesText str] [-NoText str] → $true (bouton positif) / $false
if (Ask-PF "Supprimer cet élément ?") { Clear-PF $DataGridView_1 }
⌨️Read-PFSaisie inline → string ou $nullInline input → string or $null→ string
Read-PF -Prompt str [-Default str]
⚠️
Toujours tester $null -ne $val : l'utilisateur peut cliquer Annuler.Always test $null -ne $val: the user can click Cancel.
$nom = Read-PF "Votre nom :" -Default "Dupont" if ($null -ne $nom) { Write-PF $Label_1 "Bonjour $nom" }

# Contrôles — lire, écrire, remplirControls — read, write, fill

📖Get-PFLit la valeur d'un contrôle (selon son type)Reads a control's value (per type)→ object
Get-PF $Control [-All] [-Checked] [-Index] [-Prop nom] [-Field colonne]

Sans switch : TextBox→string · CheckBox→bool · DateTimePicker→DateTime · TrackBar/NumericUpDown→nombre · Rating→note (décimale si demi-étoiles) · Gauge→nombre · KenoBalls→boules choisies (nombres ou lettres) · Timeline→index de l’étape courante · PFTreeView→texte du nœud choisi (-Index : chemin a/b/c, -All / -Checked : nœuds) ·ComboBox→SelectedItem ou Text · ListBox→SelectedItem · DataGridView→ligne liée (DataBoundItem).

Without a switch: TextBox→string · CheckBox→bool · DateTimePicker→DateTime · TrackBar/NumericUpDown→number · Rating→score (decimal with half-stars) · Gauge→number · KenoBalls→selected balls (numbers or letters) · Timeline→current step index · PFTreeView→selected node text (-Index: a/b/c path, -All / -Checked: nodes) ·ComboBox→SelectedItem or Text · ListBox→SelectedItem · DataGridView→bound row (DataBoundItem).

⚠️
La forme Get-PF ctrl Text (nom du contrôle sans $, propriété en 2e argument) n'existe pas : elle renvoie du vide sans erreur. Écrivez Get-PF $ctrl, ou Get-PF $ctrl -Prop Text.The Get-PF ctrl Text form (bare control name + property argument) does not exist: it silently returns empty. Use Get-PF $ctrl or Get-PF $ctrl -Prop Text.
$nom = Get-PF $TextBox_1 # string $ok = Get-PF $CheckBox_1 # bool $tous = Get-PF $ListBox_1 -All # TOUS les éléments $coches = Get-PF $CheckedListBox_1 -Checked $i = Get-PF $DataGridView_1 -Index # ligne sélectionnée (-1 si aucune) $lignes = Get-PF $DataGridView_1 -All # toutes les lignes en objets $v = Get-PF $DataGridView_1 -Field "Nom" $c = Get-PF $Button_1 -Prop "BackColor" # propriété .NET quelconque
✏️Write-PFÉcrit dans un contrôleWrites into a controlTHREAD-SAFE
Write-PF $Control $Text [-Append] [-Severity Informational|Success|Warning|Error]
⚡
Obligatoire pour modifier l'UI depuis un callback -Then de Start-PF/Wait-PF. Gère InvokeRequired automatiquement.Required to update the UI from a Start-PF/Wait-PF -Then callback. Handles InvokeRequired automatically.
Write-PF $Label_1 "Prêt" Write-PF $RichTextBox_1 "Ligne`n" -Append Write-PF $InfoBar_1 "Gagné !" -Severity Success
📋Fill-PFRemplit ListBox / ComboBox / DataGridView / arbreFills ListBox / ComboBox / DataGridView / tree
Fill-PF $Control $Data [-Where { … }]

Accepte un tableau de strings, de Hashtables ou de PSCustomObjects. Pour un DataGridView, les colonnes sont créées et redimensionnées automatiquement. $null vide le contrôle. -Where filtre les données à l'affichage (le bloc reçoit chaque élément dans $_) — pratique pour une barre de recherche, sans dupliquer la source.

Accepts an array of strings, Hashtables or PSCustomObjects. For a DataGridView, columns are auto-created and resized. $null clears the control. -Where filters the data at display time (the block receives each item as $_) — ideal for a search box, with no duplicated source.

Sur un arbre (PFTreeView) : des chemins "Lyon/Ventes/Julie" (les dossiers intermédiaires se créent seuls), des objets (chemin lu dans CanonicalName, DistinguishedName, FullName ou Path ; texte : -Display, sinon Name), ou les lignes Texte|icône|badge|options de la propriété Nœuds. Fill-PF remplace tout l’arbre : pour ajouter un nœud, $Arbre.FindNode("Lyon").Nodes.Add("Paul", "utilisateur").

On a tree (PFTreeView): paths "Lyon/Ventes/Julie" (intermediate folders are created for you), objects (path read from CanonicalName, DistinguishedName, FullName or Path; text: -Display, else Name), or the Texte|icône|badge|options lines of the Nodes property. Fill-PF replaces the whole tree: to add a node, $Arbre.FindNode("Lyon").Nodes.Add("Paul", "utilisateur").

Fill-PF $ComboBox_1 @("Paris", "Lyon", "Lille") $data = Import-Csv "data.csv" Fill-PF $DataGridView_1 $data # Barre de recherche : on refiltre la MÊME source à chaque frappe $q = Get-PF $TextBox_1 Fill-PF $DataGridView_1 $data -Where { $_.Nom -like "*$q*" }
➕Add-PF / Remove-PFAjouter / retirer UN élément (liste ou grille liée)Add / remove ONE item (list or bound grid)THREAD-SAFENOUVEAU
Add-PF $Control $Items · Remove-PF $Control [$Item] [-Index n]

Complément de Fill-PF, qui lui remplace tout. Sur une DataGridView liée (après Fill-PF), la ligne est ajoutée/retirée directement dans la source : plus besoin de variable miroir $script:.

Complements Fill-PF, which replaces everything. On a bound DataGridView the row is added/removed straight in the data source: no mirror $script: variable needed.

Add-PF $ListBox_1 "Nouvelle tâche" Add-PF $ComboBox_1 @("Paris", "Lyon") # plusieurs d'un coup Remove-PF $ListBox_1 "Paris" # par valeur Remove-PF $ListBox_1 -Index 0 # par position # DataGridView liée Add-PF $DataGridView_1 @{ Nom="Carol"; Age=40 } Remove-PF $DataGridView_1 -Index (Get-PF $DataGridView_1 -Index)
🎨Format-PFColore les lignes d'une DataGridView selon une valeurColors DataGridView rows by a column valueNOUVEAU
Format-PF $Control -Column "nom" -Rules @{…}

Colore la ligne entière selon la valeur d'une colonne. À appeler après Fill-PF. Couleurs = noms .NET (Green / Red / Orange / Gray…). S'abonne une fois au rendu : la couleur survit à un Fill-PF ultérieur. Ne jamais colorer via $dgv.Rows / .DefaultCellStyle — inopérant sur une grille liée (DataSource) et non certifié.

Colors the whole row by a column value. Call after Fill-PF. Colors = .NET names. Survives re-binding. Never use native $dgv.Rows / .DefaultCellStyle.

Fill-PF $DataGridView_1 $services Format-PF $DataGridView_1 -Column "Status" -Rules @{ "Running"="Green"; "Stopped"="Red" }
🗑️Clear-PFVide / réinitialise un contrôleEmpties / resets a control
Clear-PF $Control
Clear-PF $TextBox_1 # remet le placeholder (Tag) Clear-PF $DataGridView_1 Clear-PF $Arbre_1 # vide l’arbre (tous les nœuds)
📊Set-PFMaj numérique thread-safe (ProgressBar, TrackBar, NumericUpDown, Rating, Gauge)Thread-safe numeric updateTHREAD-SAFE
Set-PF $Control [-Value n] [-Add] [-Reset] [-Max] [-Prop nom valeur]

Sans -Prop, Set-PF écrit la valeur du contrôle : un nombre (ProgressBar, TrackBar, NumericUpDown, Rating, Gauge, DateTimePicker), l’étape d’une Timeline (numéro ou titre), le nœud d’un arbre PFTreeView (chemin ou texte : il est sélectionné et ses parents dépliés), l’élément d’une liste ComboBox ou ListBox (son texte ; un entier sans élément de ce texte est sa position). -Prop écrit n'importe quelle propriété .NET (Visible, Enabled, BackColor, Width…) de façon gardée et thread-safe. Pour l'apparence d'un bouton, préférez Style-PF.

Without -Prop, Set-PF writes the control's value: a number (ProgressBar, TrackBar, NumericUpDown, Rating, Gauge, DateTimePicker), a Timeline step (number or title), a PFTreeView tree node (path or text: it is selected and its parents expanded), the item of a ComboBox or ListBox list (its text; an integer with no item of that text is its position). -Prop writes any .NET property (Visible, Enabled, BackColor, Width…), guarded and thread-safe. For button looks, prefer Style-PF.

Set-PF $ProgressBar_1 -Value 75 # à 75 % Set-PF $ProgressBar_1 -Add -Value 10 Set-PF $ProgressBar_1 -Reset Set-PF $Panel_1 -Prop "Visible" $false # écriture générique
✅Validate-PFValide UN contrôle (requis / regex / min / max)Validates ONE control→ bool
Validate-PF $Control [-Required] [-Regex str] [-Min n] [-Max n] [-Message str] [-Silent]
ℹ️
S'applique à un seul contrôle à la fois. Pour valider un formulaire, chaînez plusieurs appels.Applies to a single control at a time. To validate a form, chain several calls.
if (-not (Validate-PF $TextBox_1 -Required -Message "Nom requis")) { return } if (-not (Validate-PF $TextBox_2 -Regex "^[^@]+@[^@]+\.[^@]+$" -Message "Email invalide")) { return }
👁️Toggle-PFAfficher / masquer / activer / désactiver (multi-contrôles)Show / hide / enable / disable (multi-control)THREAD-SAFE
Toggle-PF $Controls -Action Show|Hide|Enable|Disable|Toggle
Toggle-PF @($Button_1, $Button_2) -Action Disable Toggle-PF $Panel_1 -Action Hide
🔒Lock-PF / Unlock-PFVerrouille la fenêtre (ou des contrôles précis)Locks the form (or specific controls)
Lock-PF [-Controls @(…)] · Unlock-PF [-Controls @(…)]

Sans argument : verrouille tout le formulaire + curseur sablier. Avec -Controls : seulement les contrôles fournis.

No argument: locks the whole form + wait cursor. With -Controls: only the given controls.

Lock-PF # toute la fenêtre Lock-PF -Controls @($Button_1) # un seul bouton

# Données & fichiersData & files

🔗DATA-PF — Connect / Read / Write / Join-PFDataConnecter Excel (.xlsx) ou CSV à une grille, sans moduleConnect Excel (.xlsx) or CSV to a grid, no moduleNOUVEAU
Connect-PFData -Provider Excel|Csv -Path str [-Sheet str] [-Delimiter car] · Read-PFData $src [-Where {…}] · Write-PFData $src $data · Get-PFSchema $src · Join-PFData $a $b -On "Cle" [-Add …] [-Keep All|Matched]

Connecte une application à une source de données externe en PowerShell pur — aucun module à installer. Read-PFData renvoie des objets prêts pour Fill-PF ; le binding, le filtrage (-Where) et la coloration (Format-PF) restent identiques. Encore plus simple : renseignez le fichier dans l'encadré Source de données des propriétés d'une DataGridView — elle se remplit seule à l'ouverture. Nouveau : Join-PFData associe deux sources par une clé commune — jointure relationnelle façon LookUp.

Connects an app to an external data source in pure PowerShell — no module to install. Read-PFData returns objects ready for Fill-PF; binding, filtering (-Where) and colouring (Format-PF) stay the same. Even simpler: set the file in the Data source box of a DataGridView's properties — it fills itself on open. New: Join-PFData links two sources on a shared key — a relational join, LookUp-style.

$src = Connect-PFData -Provider Excel -Path "C:/Data/contacts.xlsx" -Sheet "Contacts" Fill-PF $DgvContacts (Read-PFData $src) Fill-PF $DgvContacts (Read-PFData $src -Where { $_.Actif -eq $true }) # CSV : Connect-PFData -Provider Csv -Path "clients.csv" -Delimiter ";" # Écrire la grille : Write-PFData $src (Get-PF $DgvContacts -All) # Jointure relationnelle (façon LookUp) : enrichir chaque commande du nom de son service Join-PFData $cmds $services -On "ServiceId" -RightKey "Id" -Add "Nom"
📒Bind-PFDataUn fichier Excel / CSV comme une base de donnéesAn Excel / CSV file as a databaseNOUVEAU
Bind-PFData -Grid $Grille -Path str [-Sheet str] [-Save $btn] [-Reload $btn] [-Status $lbl] [-Columns str[]]

Une seule ligne, au chargement de la fenêtre : la grille se remplit depuis un fichier .xlsx ou .csv et devient modifiable (cellules, ligne vide pour ajouter, Suppr avec confirmation). Rien n'est écrit avant le clic sur Enregistrer ; « modifications non enregistrées » et une * au titre le rappellent, et la fenêtre demande avant de se fermer. Nombres, dates et oui / non retrouvent leur type ; une saisie invalide est refusée en nommant la ligne et la colonne. Le reste du classeur est conservé (autres feuilles, mise en forme, formules), avec une copie .bak. Fichier ouvert dans Excel ou modifié ailleurs : l'application le dit et ne remplace rien sans accord.

One line, when the window loads: the grid fills from an .xlsx or .csv file and becomes editable (cells, blank row to add, Del with confirmation). Nothing is written until Save is clicked; "unsaved changes" and a * in the title say so, and the window asks before closing. Numbers, dates and yes / no get their type back; an invalid entry is refused, naming the row and column. The rest of the workbook is kept (other sheets, formatting, formulas), with a .bak copy. File open in Excel or changed elsewhere: the app says so and replaces nothing without consent.

Bind-PFData -Grid $DgvClients -Path "clients.xlsx" -Sheet "Clients" ` -Save $BtnEnregistrer -Reload $BtnRecharger -Status $LblEtat # Fichier pas encore créé : -Columns "Nom","Ville" (créé au premier enregistrement)
📤Export-PFGridExporter une grille en CSV, Excel ou PDFExport a grid to CSV, Excel or PDF
Export-PFGrid $Grille [-Path str] [-Title str] [-Header dict] [-Footer dict]

Écrit le contenu d'une DataGridView dans un fichier dont l'extension décide du format : .csv (séparateur ;, lisible par Excel en français), .xlsx (classeur Excel) ou .pdf (document). Seules les colonnes visibles sont exportées, dans l'ordre affiché — ce que l'utilisateur voit est exactement ce qu'il obtient. Sans -Path, la fenêtre « Enregistrer sous » s'ouvre. Renvoie $true si le fichier a été écrit, $false sinon (annulation, grille vide, fichier verrouillé).

Writes a DataGridView to a file whose extension picks the format: .csv (; separator, readable by French Excel), .xlsx (Excel workbook) or .pdf (document). Only visible columns are exported, in display order — what the user sees is exactly what they get. Without -Path, the “Save as” dialog opens. Returns $true if the file was written, $false otherwise (cancelled, empty grid, locked file).

PDF de document (devis, facture) : -Title remplace le titre de la fenêtre, -Header écrit un bloc sous le titre (client, adresse…), -Footer écrit les totaux en gras, alignés à droite, sur la dernière page, montants à 2 décimales. Utilisez [ordered]@{ } pour garder l'ordre des lignes. Alias : -Titre, -EnTete, -Pied / -Totaux. Un document titré n'a pas la ligne « Exporté le … », et les cellules gardent le format affiché par la grille (montants à 2 décimales).

Document PDF (quote, invoice): -Title replaces the window title, -Header writes a block under the title (customer, address…), -Footer writes the totals in bold, right-aligned, on the last page, amounts with 2 decimals. Use [ordered]@{ } to keep the lines in order. Aliases: -Titre, -EnTete, -Pied / -Totaux. A titled document has no “Exported on …” line, and cells keep the format shown by the grid (amounts with 2 decimals).

Export-PFGrid $DgvContacts -Path "C:\export\contacts.xlsx" # Laisser l'utilisateur choisir où enregistrer / let the user choose where to save $f = Pick-PF -Mode Save -Filter "PDF|*.pdf" if ($f) { $entete = [ordered]@{ Client = $client; Adresse = $adresse } $totaux = [ordered]@{ "Total HT" = $ht; "TVA 20 %" = $tva; "Total TTC" = $ttc } Export-PFGrid $DgvLignes -Path $f -Title "Devis N° 12" -Header $entete -Footer $totaux }
🧩Bind-PFGridListe + formulaire en un appelList + form in one call
Bind-PFGrid -Grid $Grille -Source nom -Fields @{…} [-Key str] [-Add $btn] [-Update $btn] [-Delete $btn] [-Required str[]] [-File str] [-OnChange {…}] [-NoConfirm]

Câble en un seul appel (au chargement de la fenêtre) toute une gestion de liste : la sélection remplit les champs, Ajouter / Modifier / Supprimer, champs obligatoires, clé unique, confirmation avant suppression, grille rafraîchie, sauvegarde JSON et rechargement au démarrage (-File). -Source est le nom de la collection : elle reste à jour pour le reste de l'application. Les boutons n'ont pas de code à eux.

Wires a whole list screen in one call (when the window loads): selection fills the fields, Add / Update / Delete, required fields, unique key, confirmation before deleting, refreshed grid, JSON save and reload at startup (-File). -Source is the collection name: it stays up to date for the rest of the app. The buttons have no code of their own.

$script:produits = @() Bind-PFGrid -Grid $DgvProduits -Source produits -Key Reference ` -Fields @{ Reference = $TxtRef; Designation = $TxtDes; Prix = $NudPrix } ` -Add $BtnAjouter -Update $BtnModifier -Delete $BtnSupprimer ` -Required Reference,Designation -File "produits.json"
📁Pick-PFSélecteur fichier / dossier natif WindowsNative Windows file / folder pickerBLOQUANT
Pick-PF [-Mode Open|Save|Folder] [-Filter str] [-Title str] [-InitialPath str] [-DefaultExt str] [-Multi]
⚠️
Tester $null -ne $result — l'utilisateur peut annuler.Test $null -ne $result — the user can cancel.
$f = Pick-PF -Mode Open -Filter "CSV|*.csv|Tous|*.*" $d = Pick-PF -Mode Folder -Title "Choisir un dossier"
💾Save-PF / Load-PFSauvegarde / chargement auto CSV ou TXTAuto CSV/TXT save / load
Save-PF -Data $obj -Path str [-Append] [-As Auto|Json|Csv|Text] · Load-PF -Path str [-As …]

Par défaut (-As Auto) : collection d'objets → CSV (UTF8), sinon → TXT ; Load-PF renifle le délimiteur (; ou ,). Précisez -As dès que le contenu compte : Json = round-trip fiable de n'importe quelle valeur (hashtable, objet imbriqué), Text = jamais reniflé en CSV. C'est -As qui pilote le format, pas l'extension du fichier.

By default (-As Auto): object collection → CSV (UTF8), else → TXT; Load-PF sniffs the delimiter. Set -As whenever content matters: Json = reliable round-trip of any value (hashtable, nested object), Text = never sniffed as CSV. The format is driven by -As, not by the file extension.

⚠️
En Auto, un texte contenant , ou ; est relu à tort comme du CSV. Utilisez -As Text (ou -As Json) pour un round-trip garanti.In Auto, text containing , or ; is wrongly parsed as CSV. Use -As Text (or -As Json) for a guaranteed round-trip.
Save-PF -Data $logs -Path "log.txt" -Append $rows = Load-PF -Path "settings.csv" # Préférences structurées — round-trip fiable Save-PF -Data @{ Ville="Lyon"; Alertes=$true } -Path "prefs.json" -As Json $p = Load-PF -Path "prefs.json" -As Json Write-PF $Label_1 $p.Ville

# Style & navigationStyle & navigation

🎨Style-PFStyle visuel d'un contrôleVisual style for a control
Style-PF $Control -Type Primary|Secondary|Danger|Search
Style-PF $Button_1 -Type Primary Style-PF $Button_2 -Type Danger
✨Set-IconPF / Set-IconTextPFIcône Segoe MDL2 Assets (code décimal)Segoe MDL2 Assets icon (decimal code)
Set-IconPF $Control -Code int [-Size int] [-TextCtrl $ctrl]
Set-IconTextPF $IconCtrl $TextCtrl -Code int -Text str [-IconSize int]
ℹ️
-Code attend un entier (notation 0xE74D acceptée), pas une chaîne hexadécimale.-Code expects an integer (0xE74D notation works), not a hex string.
Set-IconPF $Button_1 -Code 0xE74D -Size 16 # corbeille
🗂️Go-PFNaviguer vers un onglet (mode multi-pages)Navigate to a tab (multi-page mode)
Go-PF -TabName str
Go-PF "Configuration"

🎛️ Patterns de contrôles courantsCommon control patterns

# TextBox

TextBox
$valeur = Get-PF $TextBox_1 # lire (placeholder → "") Write-PF $TextBox_1 "Nouvelle valeur" # écrire Clear-PF $TextBox_1 # vider / placeholder

# DataGridView

DataGridView
# Remplir depuis un CSV $rows = Import-Csv "clients.csv" Fill-PF $DataGridView_1 $rows # Lire la ligne sélectionnée $ligne = Get-PF $DataGridView_1 # objet lié (DataBoundItem) if ($null -ne $ligne) { Show-PF $ligne.Nom } # Exporter vers CSV (on sauvegarde la source de données) $p = Pick-PF -Mode Save -Filter "CSV|*.csv" if ($null -ne $p) { Save-PF -Data $rows -Path $p }

# ComboBox / CheckBox

ComboBox & CheckBox
Fill-PF $ComboBox_1 @("Faible", "Moyen", "Élevé") $choix = Get-PF $ComboBox_1 # SelectedItem ou Text if (Get-PF $CheckBox_1) { Show-PF "Option activée" }

💼 Cas d'usage completsComplete use cases

# Formulaire avec validationForm with validation

Bouton « Valider » — Click"Submit" button — Click
# 1. Validation champ par champ if (-not (Validate-PF $TextBox_Nom -Required -Message "Le nom est requis")) { return } if (-not (Validate-PF $TextBox_Email -Regex "^[^@]+@[^@]+\.[^@]+$" -Message "Email invalide")) { return } if (-not (Validate-PF $NumericUpDown_Age -Min 18 -Max 120 -Message "Âge entre 18 et 120")) { return } # 2. Lecture + persistance $client = [PSCustomObject]@{ Nom = Get-PF $TextBox_Nom Email = Get-PF $TextBox_Email Age = Get-PF $NumericUpDown_Age } Save-PF -Data @($client) -Path "clients.csv" -Append Show-PF "Client enregistré !" -IsSuccess

# Traitement long non-bloquantLong non-blocking task

Scan de fichiers avec Wait-PFFile scan with Wait-PF
$dossier = Pick-PF -Mode Folder if ($null -eq $dossier) { return } $nb = Wait-PF -Message "Analyse du dossier…" -Work { param($s) (Get-ChildItem $s.Dir -Recurse -File).Count } -With @{ Dir = $dossier } -Then { param($r) Write-PF $Label_1 "$r fichiers trouvés" }

🤖 IA dans PulsiForms — votre clé MistralAI in PulsiForms — your Mistral key

PulsiForms s'appuie sur un assistant en ligne, Mistral AI, complété par une IA locale hors-ligne. Vous fournissez votre propre clé API — c'est le modèle BYOK (Bring Your Own Key) : vos clés ne sont jamais stockées sur nos serveurs, et nous ne vous facturons aucun jeton.

PulsiForms relies on one online assistant, Mistral AI, complemented by an offline local AI. You provide your own API key — this is the BYOK (Bring Your Own Key) model: your keys are never stored on our servers, and we never bill you for tokens.

🟢
PulsiForms Studio
Panneau latéral (Ctrl+Shift+P). Génération d'une application entière à partir d'une description, code PowerShell par contrôle, et import d'un .ps1 existant vers un projet.
Side panel (Ctrl+Shift+P). Generate a whole application from a description, per-control PowerShell code, and import an existing .ps1 into a project.
🎓
Coach PFEnginePFEngine Coach
Explique en français le verdict de certification de votre script — pourquoi une règle se déclenche et comment y répondre. Utilise la même clé Mistral, aucune seconde clé à créer.
Explains your script's certification verdict in plain language — why a rule fires and how to address it. Uses the same Mistral key, no second key to create.
🔐
Sécurité BYOK. Votre clé est chiffrée en AES-256-GCM (Web Crypto API) et stockée au choix en session chiffrée ou en mémoire pure (variable de closure, effacée à la fermeture). Elle n'est jamais écrite dans localStorage, les cookies, le DOM ou la console, et transite uniquement par en-tête (X-Mistral-Key) vers le proxy. BYOK security. Your key is encrypted with AES-256-GCM (Web Crypto API) and stored either in an encrypted session or in pure memory (closure variable, wiped on close). It is never written to localStorage, cookies, the DOM or the console, and travels only via header (X-Mistral-Key) to the proxy.

# Créer votre clé MistralCreate your Mistral key

1
Allez sur console.mistral.ai/api-keys et connectez-vous (ou créez un compte).Go to console.mistral.ai/api-keys and sign in (or create an account).
2
Activez la facturation si nécessaire (Billing) — l'API est facturée à l'usage, indépendamment d'un abonnement Le Chat.Enable billing if needed (Billing) — the API is billed per usage, separately from any Le Chat subscription.
3
Cliquez Create new key et copiez la clé (format sk-…).Click Create new key and copy the key (format sk-…).
4
Dans PulsiForms, ouvrez le Studio (Ctrl+Shift+P) ou cliquez l'icône 🔑 de la console Qualité en bas d'écran, collez votre clé et validez.In PulsiForms, open the Studio (Ctrl+Shift+P) or click the 🔑 icon in the Quality console at the bottom, paste your key and confirm.
Mistral AI
Créer la cléCreate keyconsole.mistral.ai/api-keys
FormatFormatsk-…
Modèle par défautDefault modelmistral-large-latest
Où dans PulsiFormsWhere in PulsiFormsStudio (Ctrl+Shift+P) · console Qualité 🔑Studio (Ctrl+Shift+P) · Quality console 🔑

# Dictée vocale et réponse parléeVoice dictation and spoken reply

Le Studio a un bouton « Dicter » : vous dites ce que vous voulez au lieu de le taper, et PulsiForms vous répond de vive voix. La dictée et la réponse utilisent votre clé Mistral, comme la génération.

The Studio has a "Dicter" (Dictate) button: you say what you want instead of typing it, and PulsiForms answers out loud. Dictation and the reply use your Mistral key, like generation does.

1
Décrire une application — onglet Structure, cliquez « Dicter », parlez (60 secondes au plus), puis cliquez « Arrêter ». Le texte s'ajoute au champ de description : relisez-le, corrigez-le si besoin, puis générez.Describe an application — Structure tab, click "Dicter", speak (60 seconds at most), then click "Arrêter" (Stop). The text is appended to the description field: review it, fix it if needed, then generate.
2
Demander du code pour un contrôle — sélectionnez un contrôle, onglet AI Code, dictez votre demande (par exemple « affiche les services arrêtés en rouge »), relisez, puis envoyez. La dictée remplit le champ : elle n'envoie rien toute seule.Ask for code for a control — select a control, AI Code tab, dictate your request (for example "show stopped services in red"), review it, then send. Dictation fills the field: it never sends anything by itself.
3
Écouter la réponse — après une application complète, PulsiForms annonce ce qu'il a construit. Après du code pour un contrôle, il dit en une ou deux phrases ce que fait ce code, ou vous prévient s'il ne répond pas à la demande ; la phrase s'affiche aussi dans le fil. Le code n'entre dans votre projet que lorsque vous cliquez « Valider & Injecter ».Listen to the reply — after a full application, PulsiForms announces what it built. After code for a control, it says in one or two sentences what that code does, or warns you if it does not answer the request; the sentence is also shown in the thread. The code only enters your project when you click "Valider & Injecter" (Validate & Inject).
🔊
Pas de réponse parlée ? Elle n'est donnée que si la demande a été dictée (une demande tapée au clavier reste silencieuse) et si vous avez coché « Mémoriser pour toute la session » en saisissant votre clé : sans cela, la clé est effacée après la génération et il n'y en a plus pour la réponse. Après une dictée dans l'onglet Structure, seule la portée « Projet complet » est annoncée. No spoken reply? It is only given when the request was dictated (a typed request stays silent) and when you ticked "Mémoriser pour toute la session" (Remember for the whole session) while entering your key: otherwise the key is wiped after generation and none is left for the reply. After dictating in the Structure tab, only the "Projet complet" (Full project) scope is announced.
🎙️
Votre voix et vos données. Au premier clic sur « Dicter », un encart vous explique où part votre voix et vous demande votre accord ; votre navigateur vous demande ensuite l'accès au micro. La voix est envoyée à Mistral AI avec votre clé pour être transcrite. PulsiForms ne conserve ni l'enregistrement ni le texte dicté. Selon les réglages de votre compte Mistral, vos appels peuvent servir à entraîner ses modèles : vous pouvez le vérifier et le désactiver dans votre console Mistral, rubrique Confidentialité. Le détail figure dans la politique de confidentialité. Your voice and your data. On the first click on "Dicter", a notice explains where your voice goes and asks for your consent; your browser then asks for microphone access. Your voice is sent to Mistral AI with your key to be transcribed. PulsiForms keeps neither the recording nor the dictated text. Depending on your Mistral account settings, your calls may be used to train its models: you can check and disable this in your Mistral console, under Privacy. Details are in the privacy policy.

# L'IA locale (hors-ligne)The local AI (offline)

💬
Pas de clé, pas de connexion : l'assistant local intégré à l'application PulsiForms est une base de connaissances embarquée. Il explique chaque commande PF-Script (paramètres, valeur de retour, thread-safety), propose des exemples de code prêts à coller, et peut ouvrir la carte interactive ou cette documentation. Essayez : « explique Wait-PF », « exemple Fill-PF avec un CSV », « différence Start-PF / Sleep-PF ». No key, no connection: the local assistant built into the PulsiForms app is an embedded knowledge base. It explains every PF-Script command (parameters, return value, thread-safety), offers ready-to-paste code examples, and can open the interactive map or this documentation. Try: "explain Wait-PF", "Fill-PF example with a CSV", "Start-PF vs Sleep-PF difference".

🛡️ PS.Guard v3 & Linter internePS.Guard v3 & internal linter

PulsiForms protège votre code à deux niveaux, synchronisés entre eux et avec la Stdlib.

PulsiForms protects your code at two levels, kept in sync with each other and with the Stdlib.

SystèmeSystemQuandWhenSurveilleWatches
Linter PF_*Temps réel, à l'écritureReal-time, while typingCode de l'événement (alias, variables, propriétés)Event code (aliases, variables, properties)
PS.Guard PSG-*Après export du .ps1After .ps1 exportScript complet (sécurité, qualité, perf)Whole script (security, quality, perf)

# PS.Guard v3 — 33 règles, 3 catégoriesrules, 3 categories

🔒
Sécurité (S01–S07)
Invoke-Expression, mots de passe en clair, ConvertTo-SecureString -AsPlainText, Net.WebClient, Set-ExecutionPolicy Bypass, processus cachés, Base64.
Invoke-Expression, plaintext passwords, ConvertTo-SecureString -AsPlainText, Net.WebClient, Set-ExecutionPolicy Bypass, hidden processes, Base64.
⚙️
Qualité (Q01–Q07)
Catch vide, $Error[0] dans catch, if/elseif multiples, alias (60+), cmdlets dépréciées (Get-WmiObject→Get-CimInstance…).
Empty catch, $Error[0] in catch, multiple if/elseif, aliases (60+), deprecated cmdlets (Get-WmiObject→Get-CimInstance…).
⚡
WinForms & Perf
Resize via New-Object Size, [CmdletBinding()], faux positifs perf neutralisés par PSGuard-disable/enable.
Resize via New-Object Size, [CmdletBinding()], perf false-positives silenced via PSGuard-disable/enable.

# Correction automatique « ⚡ Appliquer »Auto-fix "⚡ Apply"

Pour les règles auto-corrigeables, PS.Guard propose un bouton ⚡ Appliquer qui réécrit le code (alias → cmdlet complète, catch vide → Write-Error + throw, $Error[0] → $_…). Les règles de sécurité exigent une correction manuelle (jamais auto-corrigées, par prudence).

For auto-fixable rules, PS.Guard offers a ⚡ Apply button that rewrites the code (alias → full cmdlet, empty catch → Write-Error + throw, $Error[0] → $_…). Security rules require a manual fix (never auto-corrected, by design).

🔇
Faux positif sur un bloc statique ? Encadrez-le : # PSGuard-disable PSG-P02 … # PSGuard-enable PSG-P02.False positive on a static block? Wrap it: # PSGuard-disable PSG-P02 … # PSGuard-enable PSG-P02.

# Linter PF_* (temps réel)(real-time)

  • PF_ALIAS — alias détecté (ls, cat, rm…) → suggère la cmdlet complète.
  • PF_ALIAS — alias detected (ls, cat, rm…) → suggests the full cmdlet.
  • PF_UNDECLARED — variable utilisée sans assignation visible. Solution : $global: entre événements.
  • PF_UNDECLARED — variable used without a visible assignment. Fix: $global: across events.
  • PF_INVALID_PROP — propriété inexistante sur un contrôle (.Texte → .Text, .MaxChars → .MaxLength).
  • PF_INVALID_PROP — non-existent property on a control (.Texte → .Text, .MaxChars → .MaxLength).
ℹ️
Le linter analyse chaque événement isolément. Les contrôles du canvas et 50+ variables courantes sont en whitelist — une variable partagée entre deux événements reste signalée (utilisez $global:).The linter analyses each event in isolation. Canvas controls and 50+ common variables are whitelisted — a variable shared between two events is still flagged (use $global:).

⚠️ Top 10 des erreurs à éviterTop 10 mistakes to avoid

#❌ ErreurMistake✅ SolutionFix
1Variable partagée sans $global:Shared var without $global:$global:maVar
2$form.Close()$script:form.Close()
3Traitement long dans Add_ClickLong task in Add_ClickStart-PF / Wait-PF / Sleep-PF
4Lire $script: dans -WorkReading $script: in -Work-With @{} + -Then
5Start-Sleep -Seconds 3Sleep-PF -Ms 3000
6Sleep-PF sans -EndSleep-PF without -Endtry/finally + Sleep-PF -Endtry/finally + Sleep-PF -End
7Pas de test $null après Pick-PF / Read-PFNo $null test after Pick-PF / Read-PFif ($null -ne $r) { … }
8MessageBox::Show("x")Alert-PF "x" / Show-PF "x"
9Catch videEmpty catchcatch { Write-Error $_; throw }
10Mauvais nom de contrôle (casse)Wrong control name (case)Copier le nom des PropriétésCopy the name from Properties
🎯
En résumé : respectez les scopes ($global: / $script:), passez par les fonctions *-PF (thread-safe), ne gelez jamais l'UI (async), et laissez PS.Guard + le linter valider le reste. En cas de doute, demandez à l'IA locale de l'application PulsiForms. In short: respect scopes ($global: / $script:), go through the *-PF functions (thread-safe), never freeze the UI (async), and let PS.Guard + the linter validate the rest. When in doubt, ask the PulsiForms local AI.