
Powershell Expert
- 1 installs
- 404 repo stars
- Updated August 5, 2026
- aiskillstore/marketplace
powershell-expert is a Claude Code skill for developing PowerShell scripts, tools, modules, and GUIs following Microsoft best practices.
About
powershell-expert is a Claude Code skill for writing production-quality PowerShell scripts, tools, modules, and GUIs following Microsoft conventions. It provides templates for script structure, parameter validation, pipeline handling, error management, and Windows Forms/WPF interfaces. A developer uses it when authoring PowerShell code or getting cmdlet and PowerShell Gallery module recommendations, with live-doc verification when accuracy matters.
- Develops PowerShell scripts, modules, and GUIs following Microsoft best practices
- Covers Verb-Noun naming, CmdletBinding, pipeline handling, and -WhatIf/-Confirm patterns
- Windows Forms/WPF GUI templates and PowerShell Gallery module search/install
Powershell Expert by the numbers
- 1 all-time installs (skills.sh)
- Ranked #1,980 of 2,715 Automation & Workflows skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
powershell-expert capabilities & compatibility
Free; a pattern/reference skill for PowerShell development
- Capabilities
- automation · scripting · gui development
- Use cases
- devops
- Platforms
- Windows
- Pricing
- Free
What powershell-expert says it does
Develop PowerShell scripts, tools, modules, and GUIs following Microsoft best practices.
You MUST verify information against live sources when accuracy is critical. Do not rely solely on training data for module availability or cmdlet syntax.
npx skills add https://github.com/aiskillstore/marketplace --skill powershell-expertAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 1 |
|---|---|
| repo stars | ★ 404 |
| Last updated | August 5, 2026 |
| Repository | aiskillstore/marketplace ↗ |
What it does
Write PowerShell scripts, modules, and GUIs with Microsoft best practices and verified module recommendations.
Who is it for?
Authoring idiomatic PowerShell scripts, modules, and Windows GUIs
Skip if: Non-Windows shells or languages other than PowerShell
When should I use this skill?
Writing PowerShell code, creating Windows Forms/WPF interfaces, or needing cmdlet/module recommendations
What you get
Production-quality PowerShell using approved verbs, validation, pipeline support, and -WhatIf/-Confirm.
- PowerShell scripts and modules
- Windows Forms/WPF GUIs
- verified module recommendations
By the numbers
- requires PowerShell version 5.1
- lists 6 module categories with recommendations
Files
PowerShell Expert
Develop production-quality PowerShell scripts, tools, and GUIs using Microsoft best practices and the PowerShell ecosystem.
Quick Reference
Script Structure
#Requires -Version 5.1
<#
.SYNOPSIS
Brief description.
.DESCRIPTION
Detailed description.
.PARAMETER Name
Parameter description.
.EXAMPLE
Example-Usage -Name 'Value'
#>
[CmdletBinding()]
param(
[Parameter(Mandatory, ValueFromPipeline)]
[ValidateNotNullOrEmpty()]
[string[]]$Name,
[switch]$Force
)
begin {
# One-time setup
}
process {
foreach ($item in $Name) {
# Per-item processing
}
}
end {
# Cleanup
}Function Template
function Verb-Noun {
[CmdletBinding(SupportsShouldProcess)]
param(
[Parameter(Mandatory, Position = 0)]
[string]$Name,
[Parameter(ValueFromPipelineByPropertyName)]
[Alias('CN')]
[string]$ComputerName = $env:COMPUTERNAME,
[switch]$PassThru
)
process {
if ($PSCmdlet.ShouldProcess($Name, 'Action')) {
# Implementation
if ($PassThru) { Write-Output $result }
}
}
}Workflow
1. Script Development
Follow naming and parameter conventions:
- Verb-Noun format with approved verbs (
Get-Verb) - Strong typing with validation attributes
- Pipeline support via
ValueFromPipeline - -WhatIf/-Confirm for destructive operations
See best-practices.md for complete guidelines.
2. GUI Development
Windows Forms for simple dialogs, WPF/XAML for complex interfaces:
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
$form = New-Object System.Windows.Forms.Form -Property @{
Text = 'Title'
Size = New-Object System.Drawing.Size(400, 300)
StartPosition = 'CenterScreen'
}See gui-development.md for controls, events, and templates.
3. PowerShell Gallery Integration
Search and install modules using PSResourceGet:
# Search gallery
Find-PSResource -Name 'ModuleName' -Repository PSGallery
# Install module
Install-PSResource -Name 'ModuleName' -Scope CurrentUser -TrustRepositoryUse scripts/Search-Gallery.ps1 for enhanced search.
See powershellget.md for full cmdlet reference.
Key Patterns
Error Handling
try {
$result = Get-Content -Path $Path -ErrorAction Stop
}
catch [System.IO.FileNotFoundException] {
Write-Error "File not found: $Path"
return
}
catch {
throw
}Splatting for Readability
$params = @{
Path = $sourcePath
Destination = $destPath
Recurse = $true
Force = $true
}
Copy-Item @paramsPipeline Best Practices
# Stream output immediately
foreach ($item in $collection) {
Process-Item $item | Write-Output
}
# Accept pipeline input
param(
[Parameter(ValueFromPipeline)]
[string[]]$InputObject
)
process {
foreach ($obj in $InputObject) {
# Process each
}
}Module Recommendations
When recommending modules, search the PowerShell Gallery:
| Category | Popular Modules |
|---|---|
| Azure | Az, Az.Compute, Az.Storage |
| Testing | Pester, PSScriptAnalyzer |
| Console | PSReadLine, Terminal-Icons |
| Secrets | Microsoft.PowerShell.SecretManagement |
| Web | Pode (web server), PoshRSJob (async) |
| GUI | WPFBot3000, PSGUI |
Live Verification
You MUST verify information against live sources when accuracy is critical. Do not rely solely on training data for module availability or cmdlet syntax.
Tools to use:
- WebFetch: Retrieve and parse specific documentation URLs (PowerShell Gallery pages, Microsoft Docs)
- WebSearch: Find correct URLs when the exact path is unknown or to verify module existence
When Verification is Required
| Scenario | Action |
|---|---|
| User asks "does module X exist?" | MUST verify via PowerShell Gallery |
| Recommending a specific module | MUST verify it exists and isn't deprecated |
| Providing exact cmdlet syntax | SHOULD verify against Microsoft Docs |
| Module version requirements | MUST check gallery for current version |
| General best practices | Static references are sufficient |
Step 1: Verify Module on PowerShell Gallery
When recommending or checking a module, use the WebFetch tool to verify it exists:
WebFetch call:
- URL:
https://www.powershellgallery.com/packages/{ModuleName} - Prompt:
Extract: module name, latest version, last updated date, total downloads, and whether it shows any deprecation warning or 'unlisted' status
If WebFetch returns 404 or error: The module likely doesn't exist. Use the WebSearch tool to confirm:
- Query:
{ModuleName} PowerShell module site:powershellgallery.com
Step 2: Verify Cmdlet Syntax (When Needed)
Microsoft Docs URLs vary by module. Use the WebSearch tool to find the correct documentation page:
WebSearch call:
- Query:
{Cmdlet-Name} cmdlet site:learn.microsoft.com/en-us/powershell
Then use WebFetch on the returned URL with prompt:
- Prompt:
Extract the complete cmdlet syntax, required vs optional parameters, and PowerShell version requirements
Step 3: Fallback Strategies
If the WebFetch or WebSearch tools are unavailable or return errors:
1. For module verification: Execute Search-Gallery.ps1 from this skill:
~/.claude/skills/powershell-expert/scripts/Search-Gallery.ps1 -Name 'ModuleName'2. For cmdlet syntax: Suggest the user run locally:
Get-Help Cmdlet-Name -Full
Get-Command Cmdlet-Name -Syntax3. Clearly state uncertainty: If verification fails, tell the user:
"I wasn't able to verify this against live documentation. Please confirm
the module exists by running: Find-PSResource -Name 'ModuleName'"Verification Examples
Good (verified with live data):
"The ImportExcel module (v7.8.10, updated Oct 2024, 17M+ downloads)
provides Export-Excel for creating spreadsheets without Excel installed."
Bad (unverified claim):
"Use the Excel-Tools module to export data." ← May not exist!
Documentation Resources
- PowerShell Docs: https://learn.microsoft.com/en-us/powershell/
- Module Browser: https://learn.microsoft.com/en-us/powershell/module/
- PowerShell Gallery: https://www.powershellgallery.com
- GitHub Docs: https://github.com/MicrosoftDocs/PowerShell-Docs
References
- [best-practices.md](references/best-practices.md) - Naming, parameters, pipeline, error handling, code style
- [gui-development.md](references/gui-development.md) - Windows Forms, WPF, controls, events, templates
- [powershellget.md](references/powershellget.md) - Find, install, update, publish modules
PowerShell Best Practices Reference
Table of Contents
1. Naming Conventions 2. Parameter Design 3. Pipeline Support 4. Error Handling 5. Output Patterns 6. Code Style
---
Naming Conventions
Cmdlet/Function Names
- Verb-Noun format: Always use approved verbs from
Get-Verb - Pascal Case: Capitalize first letter of verb and all noun terms
- Singular Nouns: Even for cmdlets operating on multiple items
- Specific Nouns: Use product-specific nouns, not generic terms
# Good
Get-SQLServer
New-AzureStorageAccount
Remove-UserSession
# Bad
Get-Server # Too generic
Get-Servers # Plural noun
get-sqlserver # Wrong caseParameter Names
- Pascal Case:
ErrorAction, noterrorAction - Singular Names: Unless parameter always accepts arrays
- Standard Names: Use established parameter names with aliases
param(
[Parameter(Mandatory)]
[string]$Name,
[Alias('ComputerName', 'CN')]
[string]$Server,
[string[]]$Tags # Plural - accepts array
)Variable Names
- $PascalCase for script/global scope
- $camelCase acceptable for local scope
- Descriptive names over abbreviations
---
Parameter Design
Use Strong Typing
param(
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[string]$Name,
[ValidateRange(1, 100)]
[int]$Count = 10,
[ValidateSet('Debug', 'Info', 'Warning', 'Error')]
[string]$LogLevel = 'Info',
[switch]$Force,
[nullable[bool]]$Enabled # Three states: true, false, unspecified
)Parameter Sets
[CmdletBinding(DefaultParameterSetName = 'ByName')]
param(
[Parameter(ParameterSetName = 'ByName', Position = 0)]
[string]$Name,
[Parameter(ParameterSetName = 'ByID')]
[int]$ID,
[Parameter(ParameterSetName = 'ByObject', ValueFromPipeline)]
[PSObject]$InputObject
)Common Parameters to Support
| Parameter | Use Case |
|---|---|
-Force | Override warnings/protections |
-PassThru | Return modified objects |
-WhatIf | Preview changes without executing |
-Confirm | Prompt before executing |
-Verbose | Detailed operational info |
Path Parameters
param(
[Parameter(ParameterSetName = 'Path')]
[SupportsWildcards()]
[string[]]$Path,
[Parameter(ParameterSetName = 'LiteralPath')]
[Alias('PSPath')]
[string[]]$LiteralPath
)---
Pipeline Support
Accept Pipeline Input
param(
[Parameter(ValueFromPipeline)]
[string[]]$Name,
[Parameter(ValueFromPipelineByPropertyName)]
[Alias('FullName')]
[string]$Path
)
process {
foreach ($item in $Name) {
# Process each item immediately
Write-Output $result
}
}Write Objects Immediately
# Good - stream output
foreach ($item in $collection) {
$result = Process-Item $item
Write-Output $result
}
# Bad - buffer then output
$results = @()
foreach ($item in $collection) {
$results += Process-Item $item
}
$results---
Error Handling
Use Try/Catch with Specific Errors
try {
$result = Get-Content -Path $Path -ErrorAction Stop
}
catch [System.IO.FileNotFoundException] {
Write-Error "File not found: $Path"
return
}
catch [System.UnauthorizedAccessException] {
Write-Error "Access denied: $Path"
return
}
catch {
Write-Error "Unexpected error: $_"
throw
}Terminating vs Non-Terminating Errors
# Terminating - stops execution
throw "Critical error occurred"
$PSCmdlet.ThrowTerminatingError($errorRecord)
# Non-terminating - continues execution
Write-Error "Problem with item: $item"
$PSCmdlet.WriteError($errorRecord)Feedback Methods
# Warnings - potential unintended consequences
Write-Warning "File will be overwritten"
# Verbose - detailed operational info (requires -Verbose)
Write-Verbose "Processing file: $Path"
# Debug - troubleshooting info (requires -Debug)
Write-Debug "Variable state: $($var | ConvertTo-Json)"
# Progress - long-running operations
Write-Progress -Activity "Processing" -Status "Item $i of $total" -PercentComplete (($i / $total) * 100)---
Output Patterns
Return Typed Objects
# Create custom objects with type name
[PSCustomObject]@{
PSTypeName = 'MyModule.ServerInfo'
Name = $server.Name
Status = $server.Status
IPAddress = $server.IP
}PassThru Pattern
function Set-ItemProperty {
[CmdletBinding()]
param(
[string]$Name,
[string]$Value,
[switch]$PassThru
)
# Modify the item
$item.Property = $Value
if ($PassThru) {
Write-Output $item
}
}ShouldProcess Pattern
function Remove-Item {
[CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'High')]
param([string]$Path)
if ($PSCmdlet.ShouldProcess($Path, 'Delete')) {
# Perform deletion
}
}---
Code Style
Avoid Aliases in Scripts
# Good
Get-ChildItem | Where-Object { $_.Length -gt 1MB } | ForEach-Object { $_.Name }
# Bad
gci | ? { $_.Length -gt 1MB } | % { $_.Name }Use Explicit Parameter Names
# Good
Get-Process -Name 'notepad' -ComputerName 'Server01'
# Bad (positional)
Get-Process 'notepad' 'Server01'Splatting for Readability
$params = @{
Path = $sourcePath
Destination = $destPath
Recurse = $true
Force = $true
ErrorAction = 'Stop'
}
Copy-Item @paramsLine Continuation
# Good - natural breaks after operators
Get-Process |
Where-Object { $_.CPU -gt 100 } |
Sort-Object CPU -Descending |
Select-Object -First 10
# Avoid backticks for continuationComment-Based Help
function Get-ServerStatus {
<#
.SYNOPSIS
Gets the status of specified servers.
.DESCRIPTION
Retrieves operational status including CPU, memory,
and network information from remote servers.
.PARAMETER Name
The server name(s) to query.
.EXAMPLE
Get-ServerStatus -Name 'Server01'
Gets status for Server01.
.EXAMPLE
'Server01', 'Server02' | Get-ServerStatus
Gets status for multiple servers via pipeline.
#>
[CmdletBinding()]
param(
[Parameter(Mandatory, ValueFromPipeline)]
[string[]]$Name
)
# Implementation
}PowerShell GUI Development Reference
Table of Contents
1. Windows Forms Basics 2. Common Controls 3. Layout Patterns 4. Event Handling 5. WPF with XAML 6. GUI Templates
Note: GUI development works on Windows platforms only.
---
Windows Forms Basics
Required Assemblies
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.DrawingForm Creation Pattern
$form = New-Object System.Windows.Forms.Form -Property @{
Text = 'Application Title'
Size = New-Object System.Drawing.Size(400, 300)
StartPosition = 'CenterScreen'
FormBorderStyle = 'FixedDialog'
MaximizeBox = $false
MinimizeBox = $false
Topmost = $true
}Form Properties Reference
| Property | Values | Description |
|---|---|---|
StartPosition | CenterScreen, Manual, CenterParent | Initial position |
FormBorderStyle | FixedDialog, Sizable, None, FixedSingle | Window chrome |
WindowState | Normal, Minimized, Maximized | Initial state |
ShowInTaskbar | $true, $false | Taskbar visibility |
Display and Result Handling
# Modal dialog - blocks until closed
$result = $form.ShowDialog()
if ($result -eq [System.Windows.Forms.DialogResult]::OK) {
# Process OK action
}
elseif ($result -eq [System.Windows.Forms.DialogResult]::Cancel) {
# Process Cancel action
}
# Non-modal - returns immediately
$form.Show()---
Common Controls
Button
$button = New-Object System.Windows.Forms.Button -Property @{
Location = New-Object System.Drawing.Point(10, 10)
Size = New-Object System.Drawing.Size(100, 30)
Text = 'Click Me'
DialogResult = [System.Windows.Forms.DialogResult]::OK
}
$form.Controls.Add($button)
$form.AcceptButton = $button # Enter key triggers this buttonTextBox
# Single-line
$textBox = New-Object System.Windows.Forms.TextBox -Property @{
Location = New-Object System.Drawing.Point(10, 50)
Size = New-Object System.Drawing.Size(200, 20)
MaxLength = 100
}
# Multi-line
$textArea = New-Object System.Windows.Forms.TextBox -Property @{
Location = New-Object System.Drawing.Point(10, 80)
Size = New-Object System.Drawing.Size(300, 150)
Multiline = $true
ScrollBars = 'Vertical'
WordWrap = $true
}
# Password field
$passwordBox = New-Object System.Windows.Forms.TextBox -Property @{
Location = New-Object System.Drawing.Point(10, 240)
Size = New-Object System.Drawing.Size(200, 20)
PasswordChar = '*'
}Label
$label = New-Object System.Windows.Forms.Label -Property @{
Location = New-Object System.Drawing.Point(10, 10)
Size = New-Object System.Drawing.Size(280, 20)
Text = 'Enter your name:'
AutoSize = $true
}ComboBox (Dropdown)
$comboBox = New-Object System.Windows.Forms.ComboBox -Property @{
Location = New-Object System.Drawing.Point(10, 40)
Size = New-Object System.Drawing.Size(200, 20)
DropDownStyle = 'DropDownList' # Read-only selection
}
$comboBox.Items.AddRange(@('Option 1', 'Option 2', 'Option 3'))
$comboBox.SelectedIndex = 0ListBox
$listBox = New-Object System.Windows.Forms.ListBox -Property @{
Location = New-Object System.Drawing.Point(10, 70)
Size = New-Object System.Drawing.Size(200, 100)
SelectionMode = 'MultiExtended' # Allow multiple selection with Ctrl/Shift
}
$listBox.Items.AddRange(@('Item 1', 'Item 2', 'Item 3'))CheckBox
$checkBox = New-Object System.Windows.Forms.CheckBox -Property @{
Location = New-Object System.Drawing.Point(10, 180)
Size = New-Object System.Drawing.Size(200, 20)
Text = 'Enable feature'
Checked = $true
}RadioButton
$groupBox = New-Object System.Windows.Forms.GroupBox -Property @{
Location = New-Object System.Drawing.Point(10, 210)
Size = New-Object System.Drawing.Size(200, 80)
Text = 'Select Option'
}
$radio1 = New-Object System.Windows.Forms.RadioButton -Property @{
Location = New-Object System.Drawing.Point(10, 20)
Size = New-Object System.Drawing.Size(150, 20)
Text = 'Option A'
Checked = $true
}
$radio2 = New-Object System.Windows.Forms.RadioButton -Property @{
Location = New-Object System.Drawing.Point(10, 45)
Size = New-Object System.Drawing.Size(150, 20)
Text = 'Option B'
}
$groupBox.Controls.AddRange(@($radio1, $radio2))DateTimePicker
$datePicker = New-Object System.Windows.Forms.DateTimePicker -Property @{
Location = New-Object System.Drawing.Point(10, 300)
Size = New-Object System.Drawing.Size(200, 20)
Format = 'Short'
Value = Get-Date
}MonthCalendar
$calendar = New-Object System.Windows.Forms.MonthCalendar -Property @{
Location = New-Object System.Drawing.Point(10, 10)
ShowTodayCircle = $true
MaxSelectionCount = 1
}
# Get selected date: $calendar.SelectionStartProgressBar
$progressBar = New-Object System.Windows.Forms.ProgressBar -Property @{
Location = New-Object System.Drawing.Point(10, 330)
Size = New-Object System.Drawing.Size(300, 20)
Minimum = 0
Maximum = 100
Value = 0
Style = 'Continuous' # or 'Marquee' for indeterminate
}DataGridView
$dataGrid = New-Object System.Windows.Forms.DataGridView -Property @{
Location = New-Object System.Drawing.Point(10, 10)
Size = New-Object System.Drawing.Size(400, 200)
AutoSizeColumnsMode = 'Fill'
ReadOnly = $true
AllowUserToAddRows = $false
}
# Bind data
$data = Get-Process | Select-Object Name, CPU, WorkingSet -First 10
$dataGrid.DataSource = [System.Collections.ArrayList]@($data)---
Layout Patterns
Anchoring (Resize Handling)
$textBox.Anchor = [System.Windows.Forms.AnchorStyles]::Top -bor
[System.Windows.Forms.AnchorStyles]::Left -bor
[System.Windows.Forms.AnchorStyles]::Right
# Anchors: Top, Bottom, Left, Right
# Combine with -bor for multiple anchorsDocking
$panel.Dock = [System.Windows.Forms.DockStyle]::Top # Top, Bottom, Left, Right, FillTableLayoutPanel
$tableLayout = New-Object System.Windows.Forms.TableLayoutPanel -Property @{
Location = New-Object System.Drawing.Point(10, 10)
Size = New-Object System.Drawing.Size(380, 200)
ColumnCount = 2
RowCount = 3
}
$tableLayout.ColumnStyles.Add((New-Object System.Windows.Forms.ColumnStyle('Percent', 30)))
$tableLayout.ColumnStyles.Add((New-Object System.Windows.Forms.ColumnStyle('Percent', 70)))
$tableLayout.Controls.Add($label, 0, 0) # Column 0, Row 0
$tableLayout.Controls.Add($textBox, 1, 0) # Column 1, Row 0---
Event Handling
Button Click
$button.Add_Click({
[System.Windows.Forms.MessageBox]::Show('Button clicked!', 'Info')
})Form Events
$form.Add_Load({
# Runs when form loads
$textBox.Focus()
})
$form.Add_Shown({
# Runs after form is displayed
$textBox.Select()
})
$form.Add_FormClosing({
param($sender, $e)
$result = [System.Windows.Forms.MessageBox]::Show(
'Are you sure?', 'Confirm', 'YesNo', 'Question'
)
if ($result -eq 'No') {
$e.Cancel = $true
}
})TextBox Events
$textBox.Add_TextChanged({
# Validate input as user types
$button.Enabled = $textBox.Text.Length -gt 0
})
$textBox.Add_KeyDown({
param($sender, $e)
if ($e.KeyCode -eq 'Enter') {
# Handle Enter key
}
})Timer for Background Updates
$timer = New-Object System.Windows.Forms.Timer
$timer.Interval = 1000 # 1 second
$timer.Add_Tick({
$label.Text = "Time: $(Get-Date -Format 'HH:mm:ss')"
})
$timer.Start()
# Don't forget: $timer.Stop() when done---
WPF with XAML
Basic WPF Pattern
Add-Type -AssemblyName PresentationFramework
[xml]$xaml = @"
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="WPF Application" Height="300" Width="400"
WindowStartupLocation="CenterScreen">
<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Label Grid.Row="0" Content="Enter text:"/>
<TextBox Grid.Row="1" x:Name="InputText" Margin="0,5"/>
<StackPanel Grid.Row="2" Orientation="Horizontal" HorizontalAlignment="Right">
<Button x:Name="OKButton" Content="OK" Width="75" Margin="5"/>
<Button x:Name="CancelButton" Content="Cancel" Width="75" Margin="5"/>
</StackPanel>
</Grid>
</Window>
"@
$reader = New-Object System.Xml.XmlNodeReader $xaml
$window = [Windows.Markup.XamlReader]::Load($reader)
# Get controls by name
$inputText = $window.FindName('InputText')
$okButton = $window.FindName('OKButton')
$cancelButton = $window.FindName('CancelButton')
# Add event handlers
$okButton.Add_Click({
$script:result = $inputText.Text
$window.DialogResult = $true
$window.Close()
})
$cancelButton.Add_Click({
$window.DialogResult = $false
$window.Close()
})
# Show dialog
$null = $window.ShowDialog()WPF Advantages over WinForms
- Better styling and theming
- Data binding support
- MVVM pattern compatibility
- Vector graphics support
- Modern controls (ribbon, etc.)
---
GUI Templates
Input Dialog Template
function Show-InputDialog {
param(
[string]$Title = 'Input',
[string]$Prompt = 'Enter value:',
[string]$DefaultValue = ''
)
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
$form = New-Object System.Windows.Forms.Form -Property @{
Text = $Title
Size = New-Object System.Drawing.Size(350, 150)
StartPosition = 'CenterScreen'
FormBorderStyle = 'FixedDialog'
MaximizeBox = $false
MinimizeBox = $false
}
$label = New-Object System.Windows.Forms.Label -Property @{
Location = New-Object System.Drawing.Point(10, 15)
Size = New-Object System.Drawing.Size(320, 20)
Text = $Prompt
}
$textBox = New-Object System.Windows.Forms.TextBox -Property @{
Location = New-Object System.Drawing.Point(10, 40)
Size = New-Object System.Drawing.Size(310, 20)
Text = $DefaultValue
}
$okButton = New-Object System.Windows.Forms.Button -Property @{
Location = New-Object System.Drawing.Point(160, 75)
Size = New-Object System.Drawing.Size(75, 23)
Text = 'OK'
DialogResult = [System.Windows.Forms.DialogResult]::OK
}
$form.AcceptButton = $okButton
$cancelButton = New-Object System.Windows.Forms.Button -Property @{
Location = New-Object System.Drawing.Point(245, 75)
Size = New-Object System.Drawing.Size(75, 23)
Text = 'Cancel'
DialogResult = [System.Windows.Forms.DialogResult]::Cancel
}
$form.CancelButton = $cancelButton
$form.Controls.AddRange(@($label, $textBox, $okButton, $cancelButton))
$form.Add_Shown({ $textBox.Select() })
if ($form.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK) {
return $textBox.Text
}
return $null
}File Browser Template
function Show-FileBrowser {
param(
[string]$Title = 'Select File',
[string]$Filter = 'All files (*.*)|*.*',
[string]$InitialDirectory = [Environment]::GetFolderPath('Desktop'),
[switch]$MultiSelect
)
Add-Type -AssemblyName System.Windows.Forms
$dialog = New-Object System.Windows.Forms.OpenFileDialog -Property @{
Title = $Title
Filter = $Filter
InitialDirectory = $InitialDirectory
Multiselect = $MultiSelect
}
if ($dialog.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK) {
if ($MultiSelect) {
return $dialog.FileNames
}
return $dialog.FileName
}
return $null
}
# Usage
$file = Show-FileBrowser -Title 'Select Script' -Filter 'PowerShell (*.ps1)|*.ps1|All (*.*)|*.*'Folder Browser Template
function Show-FolderBrowser {
param(
[string]$Description = 'Select folder',
[string]$RootFolder = 'Desktop'
)
Add-Type -AssemblyName System.Windows.Forms
$dialog = New-Object System.Windows.Forms.FolderBrowserDialog -Property @{
Description = $Description
RootFolder = $RootFolder
}
if ($dialog.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK) {
return $dialog.SelectedPath
}
return $null
}PowerShellGet & Gallery Reference
Table of Contents
1. Overview 2. Setup 3. Finding Modules 4. Installing Modules 5. Managing Modules 6. Publishing Modules
---
Overview
PowerShell Gallery (https://www.powershellgallery.com) is the central repository for PowerShell modules, scripts, and DSC resources.
PSResourceGet (Microsoft.PowerShell.PSResourceGet) is the modern replacement for PowerShellGet:
- Ships with PowerShell 7.4+
- Faster and more reliable than legacy PowerShellGet
- Uses
*-PSResourcecmdlet naming
Legacy vs Modern Cmdlets
| Legacy (PowerShellGet) | Modern (PSResourceGet) |
|---|---|
Find-Module | Find-PSResource |
Install-Module | Install-PSResource |
Update-Module | Update-PSResource |
Uninstall-Module | Uninstall-PSResource |
Get-InstalledModule | Get-InstalledPSResource |
Publish-Module | Publish-PSResource |
---
Setup
Check Installed Version
Get-Module -Name PowerShellGet -ListAvailable
Get-Module -Name Microsoft.PowerShell.PSResourceGet -ListAvailableInstall/Update PSResourceGet
# Install modern PSResourceGet
Install-Module -Name Microsoft.PowerShell.PSResourceGet -Force
# Or update if already installed
Update-Module -Name Microsoft.PowerShell.PSResourceGetConfigure Repository
# View registered repositories
Get-PSResourceRepository
# Register PSGallery if not present
Register-PSResourceRepository -PSGallery
# Set repository priority (lower = higher priority)
Set-PSResourceRepository -Name PSGallery -Priority 50---
Finding Modules
Basic Search
# Search by name
Find-PSResource -Name 'Az.Compute'
# Search with wildcards
Find-PSResource -Name 'Az.*'
# Search by tag
Find-PSResource -Tag 'Azure', 'Cloud'Find-PSResource Parameters
| Parameter | Description | Example |
|---|---|---|
-Name | Module name (wildcards allowed) | 'PSReadLine' |
-Type | Resource type | Module, Script |
-Version | Version or range | '2.0.0', '[1.0,2.0)' |
-Prerelease | Include prereleases | Switch |
-Tag | Filter by tags | 'DSC', 'Azure' |
-Repository | Target repository | 'PSGallery' |
-CommandName | Find by command | 'Get-AzVM' |
-DscResourceName | Find by DSC resource | 'File' |
Version Range Syntax (NuGet)
| Syntax | Meaning |
|---|---|
1.0.0 | Exact version |
[1.0,2.0] | >= 1.0 AND <= 2.0 |
[1.0,2.0) | >= 1.0 AND < 2.0 |
(1.0,) | > 1.0 |
[,2.0] | <= 2.0 |
Search Examples
# Find all versions
Find-PSResource -Name 'Pester' -Version '*'
# Find specific version range
Find-PSResource -Name 'Az' -Version '[5.0,7.0)' -Prerelease
# Find by command name
Find-PSResource -CommandName 'Invoke-RestMethod'
# Find DSC resources
Find-PSResource -DscResourceName 'File' -Repository PSGallery
# Include dependencies
Find-PSResource -Name 'Az.Accounts' -IncludeDependencies---
Installing Modules
Basic Installation
# Install latest stable
Install-PSResource -Name 'Az.Compute'
# Install specific version
Install-PSResource -Name 'Pester' -Version '5.0.0'
# Install prerelease
Install-PSResource -Name 'Az' -Prerelease
# Install for current user only
Install-PSResource -Name 'PSReadLine' -Scope CurrentUser
# Install for all users (requires admin)
Install-PSResource -Name 'PSReadLine' -Scope AllUsersInstall-PSResource Parameters
| Parameter | Description |
|---|---|
-Name | Module name(s) |
-Version | Version or range |
-Prerelease | Include prerelease |
-Scope | CurrentUser or AllUsers |
-Repository | Source repository |
-TrustRepository | Skip trust prompt |
-Reinstall | Force reinstall |
-SkipDependencyCheck | Don't install dependencies |
-NoClobber | Don't overwrite commands |
Trusted Repository
# Trust PSGallery to avoid prompts
Set-PSResourceRepository -Name PSGallery -Trusted
# Or use -TrustRepository per install
Install-PSResource -Name 'Module' -TrustRepository---
Managing Modules
List Installed Modules
# All installed
Get-InstalledPSResource
# Filter by name
Get-InstalledPSResource -Name 'Az.*'
# Specific version
Get-InstalledPSResource -Name 'Pester' -Version '5.0.0'Update Modules
# Update specific module
Update-PSResource -Name 'Az.Compute'
# Update all
Update-PSResource -Name '*'
# Include prerelease updates
Update-PSResource -Name 'Module' -PrereleaseUninstall Modules
# Uninstall specific version
Uninstall-PSResource -Name 'Pester' -Version '4.0.0'
# Uninstall all versions
Uninstall-PSResource -Name 'Pester' -Version '*'
# Skip dependency check
Uninstall-PSResource -Name 'Module' -SkipDependencyCheckSave Modules (Download without install)
# Save to path for offline use
Save-PSResource -Name 'Az.Compute' -Path 'C:\OfflineModules'
# Include dependencies
Save-PSResource -Name 'Az' -Path 'C:\OfflineModules' -IncludeXml---
Publishing Modules
Prepare Module
# Module manifest requirements
@{
RootModule = 'MyModule.psm1'
ModuleVersion = '1.0.0'
GUID = 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
Author = 'Your Name'
Description = 'Module description'
PowerShellVersion = '5.1'
FunctionsToExport = @('Get-MyFunction', 'Set-MyFunction')
Tags = @('Utility', 'Automation')
LicenseUri = 'https://opensource.org/licenses/MIT'
ProjectUri = 'https://github.com/user/project'
}Publish
# Get API key from https://www.powershellgallery.com/account/apikeys
$apiKey = 'your-api-key'
# Publish module
Publish-PSResource -Path './MyModule' -ApiKey $apiKey -Repository PSGallery
# Dry run (validate without publishing)
Publish-PSResource -Path './MyModule' -ApiKey $apiKey -WhatIf---
Common Patterns
Install if Missing
function Ensure-Module {
param([string]$Name, [string]$MinVersion)
$installed = Get-InstalledPSResource -Name $Name -ErrorAction SilentlyContinue
if (-not $installed -or ($MinVersion -and $installed.Version -lt $MinVersion)) {
Install-PSResource -Name $Name -Scope CurrentUser -TrustRepository
}
Import-Module $Name
}
Ensure-Module -Name 'Az.Compute' -MinVersion '5.0.0'Bulk Install from List
$modules = @(
@{ Name = 'Pester'; Version = '5.0.0' }
@{ Name = 'PSReadLine' }
@{ Name = 'Az.Accounts' }
)
foreach ($mod in $modules) {
$params = @{
Name = $mod.Name
Scope = 'CurrentUser'
TrustRepository = $true
}
if ($mod.Version) { $params.Version = $mod.Version }
Install-PSResource @params
}Search Gallery for Popular Modules
# Find most downloaded modules (sort by download count not available via cmdlet)
# Use web API or browse powershellgallery.com/stats/packages
# Find recently updated
Find-PSResource -Name '*' -Repository PSGallery |
Sort-Object PublishedDate -Descending |
Select-Object -First 20---
Useful Links
- PowerShell Gallery: https://www.powershellgallery.com
- Gallery Status: https://aka.ms/psgallery-status
- Gallery Issues: https://aka.ms/psgallery-issues
- Module Browser: https://learn.microsoft.com/en-us/powershell/module/
- PSResourceGet Docs: https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.psresourceget/
<#
.SYNOPSIS
Search PowerShell Gallery for modules, scripts, or DSC resources.
.DESCRIPTION
Enhanced search wrapper for Find-PSResource with formatted output
and common search patterns.
.PARAMETER Name
Module name pattern. Supports wildcards (*).
.PARAMETER Tag
Filter by tags (comma-separated).
.PARAMETER Command
Find modules containing a specific command.
.PARAMETER DscResource
Find modules containing a specific DSC resource.
.PARAMETER Type
Resource type: Module, Script, or All.
.PARAMETER Prerelease
Include prerelease versions.
.PARAMETER First
Number of results to return. Default: 20.
.EXAMPLE
.\Search-Gallery.ps1 -Name 'Az.*'
Search for all Azure modules.
.EXAMPLE
.\Search-Gallery.ps1 -Tag 'Azure', 'Cloud' -First 10
Search by tags.
.EXAMPLE
.\Search-Gallery.ps1 -Command 'Invoke-RestMethod'
Find modules containing a specific command.
#>
[CmdletBinding(DefaultParameterSetName = 'ByName')]
param(
[Parameter(ParameterSetName = 'ByName', Position = 0)]
[string]$Name = '*',
[Parameter(ParameterSetName = 'ByName')]
[string[]]$Tag,
[Parameter(ParameterSetName = 'ByCommand', Mandatory)]
[string]$Command,
[Parameter(ParameterSetName = 'ByDsc', Mandatory)]
[string]$DscResource,
[ValidateSet('Module', 'Script', 'All')]
[string]$Type = 'Module',
[switch]$Prerelease,
[int]$First = 20
)
# Ensure PSResourceGet is available
$psrg = Get-Module -Name Microsoft.PowerShell.PSResourceGet -ListAvailable
if (-not $psrg) {
Write-Warning "Microsoft.PowerShell.PSResourceGet not found. Using legacy Find-Module."
$useLegacy = $true
}
# Build search parameters
$searchParams = @{
Repository = 'PSGallery'
}
if ($Prerelease) {
$searchParams.Prerelease = $true
}
# Execute search based on parameter set
$results = switch ($PSCmdlet.ParameterSetName) {
'ByName' {
$searchParams.Name = $Name
if ($Tag) { $searchParams.Tag = $Tag }
if ($Type -ne 'All') { $searchParams.Type = $Type }
if ($useLegacy) {
Find-Module @searchParams -ErrorAction SilentlyContinue |
Select-Object -First $First
} else {
Find-PSResource @searchParams -ErrorAction SilentlyContinue |
Select-Object -First $First
}
}
'ByCommand' {
if ($useLegacy) {
Find-Module -Command $Command -Repository PSGallery -ErrorAction SilentlyContinue |
Select-Object -First $First
} else {
Find-PSResource -CommandName $Command -Repository PSGallery -ErrorAction SilentlyContinue |
Select-Object -First $First
}
}
'ByDsc' {
if ($useLegacy) {
Find-Module -DscResource $DscResource -Repository PSGallery -ErrorAction SilentlyContinue |
Select-Object -First $First
} else {
Find-PSResource -DscResourceName $DscResource -Repository PSGallery -ErrorAction SilentlyContinue |
Select-Object -First $First
}
}
}
if (-not $results) {
Write-Host "No results found." -ForegroundColor Yellow
return
}
# Format output
$results | ForEach-Object {
[PSCustomObject]@{
Name = $_.Name
Version = $_.Version
Description = if ($_.Description.Length -gt 80) {
$_.Description.Substring(0, 77) + '...'
} else {
$_.Description
}
Author = $_.Author
Downloads = if ($_.AdditionalMetadata.downloadCount) {
$_.AdditionalMetadata.downloadCount
} else {
'N/A'
}
}
} | Format-Table -AutoSize -Wrap
Write-Host "`nTotal: $($results.Count) results" -ForegroundColor Cyan
Write-Host "Install: Install-PSResource -Name '<ModuleName>' -Scope CurrentUser" -ForegroundColor DarkGray
{
"schema_version": "2.0",
"meta": {
"generated_at": "2026-01-17T05:59:02.340Z",
"slug": "hmohamed01-powershell-expert",
"source_url": "https://github.com/hmohamed01/powershell-expert/tree/main/powershell-expert",
"source_ref": "main",
"model": "claude",
"analysis_version": "3.0.0",
"source_type": "community",
"content_hash": "c142ea22a482f8670690b8bca68e86ec2ff28133a5b78c9e27eeaa6cfbf262c4",
"tree_hash": "7ac86c4065ea01fda69dcff023ff73857b1bbad060762b8a3f809422cde7cb64"
},
"skill": {
"name": "powershell-expert",
"description": "Develop PowerShell scripts, tools, modules, and GUIs following Microsoft best practices. Use when writing PowerShell code, creating Windows Forms/WPF interfaces, working with PowerShell Gallery modules, or needing cmdlet/module recommendations. Covers script development, parameter design, pipeline handling, error management, and GUI creation patterns. Verifies module availability and cmdlet syntax against live documentation when accuracy is critical.",
"summary": "Develop PowerShell scripts, tools, modules, and GUIs following Microsoft best practices. Use when wr...",
"icon": "terminal",
"version": "1.0.0",
"author": "hmohamed01",
"license": "MIT",
"category": "coding",
"tags": [
"powershell",
"windows",
"scripting",
"automation"
],
"supported_tools": [
"claude",
"codex",
"claude-code"
],
"risk_factors": [
"external_commands"
]
},
"security_audit": {
"risk_level": "safe",
"is_blocked": false,
"safe_to_publish": true,
"summary": "This is a documentation and reference skill containing PowerShell code examples and best practices. All static findings are FALSE POSITIVES - the security scanner misinterpreted markdown documentation containing PowerShell examples as executed code. The skill contains no malicious patterns, only educational content about PowerShell development.",
"risk_factor_evidence": [
{
"factor": "external_commands",
"evidence": [
{
"file": "SKILL.md",
"line_start": 1,
"line_end": 255
},
{
"file": "references/best-practices.md",
"line_start": 1,
"line_end": 301
},
{
"file": "references/gui-development.md",
"line_start": 1,
"line_end": 477
},
{
"file": "references/powershellget.md",
"line_start": 1,
"line_end": 304
},
{
"file": "scripts/Search-Gallery.ps1",
"line_start": 1,
"line_end": 142
}
]
}
],
"critical_findings": [],
"high_findings": [],
"medium_findings": [],
"low_findings": [],
"dangerous_patterns": [],
"files_scanned": 6,
"total_lines": 1778,
"audit_model": "claude",
"audited_at": "2026-01-17T05:59:02.340Z"
},
"content": {
"user_title": "Create PowerShell scripts and modules",
"value_statement": "This skill provides expert guidance for PowerShell development including script templates, best practices for parameters and error handling, Windows Forms and WPF GUI creation patterns, and PowerShell Gallery integration for module management.",
"seo_keywords": [
"powershell",
"powershell scripting",
"claude code",
"claude",
"codex",
"windows automation",
"powershell modules",
"powershell gallery",
"windows forms",
"wpf gui"
],
"actual_capabilities": [
"Creates production-quality PowerShell scripts with proper structure, parameters, and error handling",
"Develops Windows Forms and WPF GUIs with controls, events, and layout patterns",
"Searches and manages PowerShell Gallery modules using PSResourceGet",
"Implements pipeline support and splatting for clean, efficient PowerShell code",
"Applies Microsoft best practices for naming conventions and code style"
],
"limitations": [
"This is a guidance skill and does not execute PowerShell code directly",
"GUI development examples are Windows-only due to System.Windows.Forms dependency",
"Requires PowerShell 5.1 or newer for full feature compatibility"
],
"use_cases": [
{
"target_user": "System administrators",
"title": "Automate Windows tasks",
"description": "Create scripts to automate user management, file operations, and system configuration tasks."
},
{
"target_user": "DevOps engineers",
"title": "Build deployment tools",
"description": "Develop module-based tools for infrastructure automation and environment configuration."
},
{
"target_user": "PowerShell developers",
"title": "Improve script quality",
"description": "Apply best practices for error handling, pipeline support, and module design patterns."
}
],
"prompt_templates": [
{
"title": "Script template",
"scenario": "Generate a function",
"prompt": "Create a PowerShell function named Get-ServerInfo that accepts a ComputerName parameter, connects via CIM, and returns OS version, disk space, and memory info."
},
{
"title": "GUI development",
"scenario": "Create a form",
"prompt": "Write a Windows Forms PowerShell script that creates a login dialog with username and password fields, OK and Cancel buttons, and validates inputs before closing."
},
{
"title": "Module help",
"scenario": "Find PowerShell modules",
"prompt": "Find PowerShell modules on the Gallery for Azure resource management. Include module name, version, and install command."
},
{
"title": "Best practices",
"scenario": "Review script patterns",
"prompt": "Review this PowerShell script for best practices: does it use proper naming, error handling, pipeline support, and WhatIf/Confirm parameters?"
}
],
"output_examples": [
{
"input": "Create a function to copy files with progress",
"output": [
"Use Copy-Item with -Filter and -Recurse for directory copies",
"Implement Write-Progress for visual feedback during long operations",
"Add -Force parameter to overwrite existing files",
"Support WhatIf/Confirm for safe previews of destructive operations"
]
},
{
"input": "Build a simple settings dialog",
"output": [
"Create System.Windows.Forms.Form with FixedDialog style",
"Add Label, TextBox, and Button controls",
"Use ShowDialog() for modal behavior",
"Return dialog result and user input via script-scoped variables"
]
},
{
"input": "Find modules for REST API calls",
"output": [
"Microsoft.PowerShell.WebRequests.Native HTTP cmdlets built into PowerShell",
"Invoke-RestMethod and Invoke-WebRequest for API calls",
"No external module needed for basic REST operations"
]
}
],
"best_practices": [
"Use Verb-Noun naming with approved verbs from Get-Verb and PascalCase for all identifiers",
"Implement proper error handling with try/catch blocks and specific exception types",
"Support common parameters like -WhatIf, -Confirm, -Verbose, and -ErrorAction"
],
"anti_patterns": [
"Avoid using generic noun names like Get-Data or Set-Config without specificity",
"Do not skip error handling or use -ErrorAction SilentlyContinue without logging",
"Avoid mixing Write-Host with Write-Output in functions that produce pipeline output"
],
"faq": [
{
"question": "What PowerShell version is required?",
"answer": "The skill targets PowerShell 5.1 and newer. Some features like PSResourceGet require PowerShell 7+."
},
{
"question": "Does this run PowerShell code?",
"answer": "No. This skill provides guidance, templates, and best practices. It does not execute or install code."
},
{
"question": "Can I create GUIs for Linux?",
"answer": "Windows Forms and WPF examples require Windows. For cross-platform GUIs, consider web-based approaches."
},
{
"question": "How do I verify module recommendations?",
"answer": "The skill includes a Search-Gallery.ps1 helper script. Always verify modules exist on PowerShell Gallery before installing."
},
{
"question": "What about script execution policy?",
"answer": "The skill does not modify execution policy. Users must run Set-ExecutionPolicy or use -Bypass to run scripts."
},
{
"question": "Can this help with module publishing?",
"answer": "Yes. The references/powershellget.md file covers publishing modules to the PowerShell Gallery."
}
]
},
"file_structure": [
{
"name": "references",
"type": "dir",
"path": "references",
"children": [
{
"name": "best-practices.md",
"type": "file",
"path": "references/best-practices.md",
"lines": 326
},
{
"name": "gui-development.md",
"type": "file",
"path": "references/gui-development.md",
"lines": 487
},
{
"name": "powershellget.md",
"type": "file",
"path": "references/powershellget.md",
"lines": 305
}
]
},
{
"name": "scripts",
"type": "dir",
"path": "scripts",
"children": [
{
"name": "Search-Gallery.ps1",
"type": "file",
"path": "scripts/Search-Gallery.ps1",
"lines": 142
}
]
},
{
"name": "SKILL.md",
"type": "file",
"path": "SKILL.md",
"lines": 255
}
]
}
Related skills
FAQ
How does powershell-expert name functions?
Verb-Noun format using approved verbs from Get-Verb, with strong typing and validation attributes.
Does it verify modules exist?
Yes - it uses WebFetch/WebSearch to verify module availability and cmdlet syntax against live docs when accuracy is critical.