-
Notifications
You must be signed in to change notification settings - Fork 2.2k
First add of PowerShell instructions #55
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 1 commit
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,333 @@ | ||
| --- | ||
| applyTo: "**/*.ps1,**/*.psm1" | ||
aaronpowell marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| description: "PowerShell cmdlet and scripting best practices based on Microsoft guidelines" | ||
aaronpowell marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| --- | ||
|
|
||
| # PowerShell Cmdlet Development Guidelines | ||
|
|
||
| This guide provides PowerShell-specific instructions to help GitHub Copilot generate idiomatic, safe, and maintainable scripts. It aligns with Microsoft’s PowerShell cmdlet development guidelines. | ||
|
|
||
| ## Naming Conventions | ||
|
|
||
| - **Verb-Noun Format:** | ||
| - Use approved PowerShell verbs (Get-Verb) | ||
| - Use singular nouns | ||
| - PascalCase for both verb and noun | ||
| - Avoid special characters and spaces | ||
|
|
||
| - **Parameter Names:** | ||
| - Use PascalCase | ||
| - Choose clear, descriptive names | ||
| - Use singular form unless always multiple | ||
| - Follow PowerShell standard names | ||
|
|
||
| - **Variable Names:** | ||
| - Use PascalCase for public variables | ||
| - Use camelCase for private variables | ||
| - Avoid abbreviations | ||
| - Use meaningful names | ||
|
|
||
| - **Alias Avoidance:** | ||
| - Use full cmdlet names | ||
| - Avoid using aliases in scripts (e.g., use Get-ChildItem instead of gci) | ||
| - Document any custom aliases | ||
| - Use full parameter names | ||
|
|
||
| ### Example | ||
|
|
||
| ```powershell | ||
| function Get-UserProfile { | ||
| [CmdletBinding()] | ||
| param( | ||
| [Parameter(Mandatory)] | ||
| [string]$Username, | ||
|
|
||
| [Parameter()] | ||
| [ValidateSet('Basic', 'Detailed')] | ||
| [string]$ProfileType = 'Basic' | ||
| ) | ||
|
|
||
| process { | ||
| # Logic here | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ## Parameter Design | ||
|
|
||
| - **Standard Parameters:** | ||
| - Use common parameter names (`Path`, `Name`, `Force`) | ||
| - Follow built-in cmdlet conventions | ||
| - Use aliases for specialized terms | ||
| - Document parameter purpose | ||
|
|
||
| - **Parameter Names:** | ||
| - Use singular form unless always multiple | ||
| - Choose clear, descriptive names | ||
| - Follow PowerShell conventions | ||
| - Use PascalCase formatting | ||
|
|
||
| - **Type Selection:** | ||
| - Use common .NET types | ||
| - Implement proper validation | ||
| - Consider ValidateSet for limited options | ||
| - Enable tab completion where possible | ||
|
|
||
| - **Switch Parameters:** | ||
| - Use [switch] for boolean flags | ||
| - Avoid $true/$false parameters | ||
| - Default to $false when omitted | ||
| - Use clear action names | ||
|
|
||
| ### Example | ||
|
|
||
| ```powershell | ||
| function Set-ResourceConfiguration { | ||
| [CmdletBinding()] | ||
| param( | ||
| [Parameter(Mandatory)] | ||
| [string]$Name, | ||
|
|
||
| [Parameter()] | ||
| [ValidateSet('Dev', 'Test', 'Prod')] | ||
| [string]$Environment = 'Dev', | ||
|
|
||
| [Parameter()] | ||
| [switch]$Force, | ||
|
|
||
| [Parameter()] | ||
| [ValidateNotNullOrEmpty()] | ||
| [string[]]$Tags | ||
| ) | ||
|
|
||
| process { | ||
| # Logic here | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ## Pipeline and Output | ||
|
|
||
| - **Pipeline Input:** | ||
| - Use `ValueFromPipeline` for direct object input | ||
| - Use `ValueFromPipelineByPropertyName` for property mapping | ||
| - Implement Begin/Process/End blocks for pipeline handling | ||
| - Document pipeline input requirements | ||
|
|
||
| - **Output Objects:** | ||
| - Return rich objects, not formatted text | ||
| - Use PSCustomObject for structured data | ||
| - Avoid Write-Host for data output | ||
| - Enable downstream cmdlet processing | ||
|
|
||
| - **Pipeline Streaming:** | ||
| - Output one object at a time | ||
| - Use process block for streaming | ||
| - Avoid collecting large arrays | ||
| - Enable immediate processing | ||
|
|
||
| - **PassThru Pattern:** | ||
| - Default to no output for action cmdlets | ||
| - Implement `-PassThru` switch for object return | ||
| - Return modified/created object with `-PassThru` | ||
| - Use verbose/warning for status updates | ||
|
|
||
| ### Example | ||
|
|
||
| ```powershell | ||
| function Update-ResourceStatus { | ||
| [CmdletBinding()] | ||
| param( | ||
| [Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)] | ||
| [string]$Name, | ||
|
|
||
| [Parameter(Mandatory)] | ||
| [ValidateSet('Active', 'Inactive', 'Maintenance')] | ||
| [string]$Status, | ||
|
|
||
| [Parameter()] | ||
| [switch]$PassThru | ||
| ) | ||
|
|
||
| begin { | ||
| Write-Verbose "Starting resource status update process" | ||
| $timestamp = Get-Date | ||
| } | ||
|
|
||
| process { | ||
| # Process each resource individually | ||
| Write-Verbose "Processing resource: $Name" | ||
|
|
||
| $resource = [PSCustomObject]@{ | ||
| Name = $Name | ||
| Status = $Status | ||
| LastUpdated = $timestamp | ||
| UpdatedBy = $env:USERNAME | ||
| } | ||
|
|
||
| # Only output if PassThru is specified | ||
| if ($PassThru) { | ||
| Write-Output $resource | ||
| } | ||
| } | ||
|
|
||
| end { | ||
| Write-Verbose "Resource status update process completed" | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ## Error Handling and Safety | ||
|
|
||
| - **ShouldProcess Implementation:** | ||
| - Use `[CmdletBinding(SupportsShouldProcess = $true)]` | ||
| - Set appropriate `ConfirmImpact` level | ||
| - Call `$PSCmdlet.ShouldProcess()` for system changes | ||
| - Use `ShouldContinue()` for additional confirmations | ||
|
|
||
| - **Message Streams:** | ||
| - `Write-Verbose` for operational details with `-Verbose` | ||
| - `Write-Warning` for warning conditions | ||
| - `Write-Error` for non-terminating errors | ||
| - `throw` for terminating errors | ||
| - Avoid `Write-Host` except for user interface text | ||
|
|
||
| - **Error Handling Pattern:** | ||
| - Use try/catch blocks for error management | ||
| - Set appropriate ErrorAction preferences | ||
| - Return meaningful error messages | ||
| - Use ErrorVariable when needed | ||
| - Include proper terminating vs non-terminating error handling | ||
|
|
||
| - **Non-Interactive Design:** | ||
| - Accept input via parameters | ||
| - Avoid `Read-Host` in scripts | ||
| - Support automation scenarios | ||
| - Document all required inputs | ||
|
|
||
| ### Example | ||
|
|
||
| ```powershell | ||
| function Remove-UserAccount { | ||
| [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'High')] | ||
| param( | ||
| [Parameter(Mandatory, ValueFromPipeline)] | ||
| [ValidateNotNullOrEmpty()] | ||
| [string]$Username, | ||
|
|
||
| [Parameter()] | ||
| [switch]$Force | ||
| ) | ||
|
|
||
| begin { | ||
| Write-Verbose "Starting user account removal process" | ||
| $ErrorActionPreference = 'Stop' | ||
| } | ||
|
|
||
| process { | ||
| try { | ||
| # Validation | ||
| if (-not (Test-UserExists -Username $Username)) { | ||
| Write-Error "User account '$Username' not found" | ||
| return | ||
| } | ||
|
|
||
| # Confirmation | ||
| $shouldProcessMessage = "Remove user account '$Username'" | ||
| if ($Force -or $PSCmdlet.ShouldProcess($Username, $shouldProcessMessage)) { | ||
| Write-Verbose "Removing user account: $Username" | ||
|
|
||
| # Main operation | ||
| Remove-ADUser -Identity $Username -ErrorAction Stop | ||
| Write-Warning "User account '$Username' has been removed" | ||
| } | ||
| } | ||
| catch [Microsoft.ActiveDirectory.Management.ADException] { | ||
| Write-Error "Active Directory error: $_" | ||
| throw | ||
| } | ||
| catch { | ||
| Write-Error "Unexpected error removing user account: $_" | ||
| throw | ||
| } | ||
| } | ||
|
|
||
| end { | ||
| Write-Verbose "User account removal process completed" | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ## Documentation and Style | ||
|
|
||
| - **Comment-Based Help:** Include comment-based help for any public-facing function or cmdlet. Inside the function, add a `<# ... #>` help comment with at least: | ||
| - `.SYNOPSIS` Brief description | ||
| - `.DESCRIPTION` Detailed explanation | ||
| - `.EXAMPLE` sections with practical usage | ||
| - `.PARAMETER` descriptions | ||
| - `.OUTPUTS` Type of output returned | ||
| - `.NOTES` Additional information | ||
|
|
||
| - **Consistent Formatting:** | ||
| - Follow consistent PowerShell style | ||
| - Use proper indentation (4 spaces recommended) | ||
| - Opening braces on same line as statement | ||
| - Closing braces on new line | ||
| - Use line breaks after pipeline operators | ||
| - PascalCase for function and parameter names | ||
| - Avoid unnecessary whitespace | ||
|
|
||
| - **Pipeline Support:** | ||
| - Implement Begin/Process/End blocks for pipeline functions | ||
| - Use ValueFromPipeline where appropriate | ||
| - Support pipeline input by property name | ||
| - Return proper objects, not formatted text | ||
|
|
||
| - **Avoid Aliases:** Use full cmdlet names and parameters | ||
| - Avoid using aliases in scripts (e.g., use Get-ChildItem instead of gci); aliases are acceptable for interactive shell use. | ||
| - Use `Where-Object` instead of `?` or `where` | ||
| - Use `ForEach-Object` instead of `%` | ||
| - Use `Get-ChildItem` instead of `ls` or `dir` | ||
|
|
||
| ## Full Example: End-to-End Cmdlet Pattern | ||
|
|
||
| ```powershell | ||
| function New-Resource { | ||
| [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Medium')] | ||
| param( | ||
| [Parameter(Mandatory = $true, | ||
| ValueFromPipeline = $true, | ||
| ValueFromPipelineByPropertyName = $true)] | ||
| [ValidateNotNullOrEmpty()] | ||
| [string]$Name, | ||
|
|
||
| [Parameter()] | ||
| [ValidateSet('Development', 'Production')] | ||
| [string]$Environment = 'Development' | ||
| ) | ||
|
|
||
| begin { | ||
| Write-Verbose "Starting resource creation process" | ||
| } | ||
|
|
||
| process { | ||
| try { | ||
| if ($PSCmdlet.ShouldProcess($Name, "Create new resource")) { | ||
| # Resource creation logic here | ||
| Write-Output ([PSCustomObject]@{ | ||
| Name = $Name | ||
| Environment = $Environment | ||
| Created = Get-Date | ||
| }) | ||
| } | ||
| } | ||
| catch { | ||
| Write-Error "Failed to create resource: $_" | ||
| } | ||
| } | ||
|
|
||
| end { | ||
| Write-Verbose "Completed resource creation process" | ||
| } | ||
| } | ||
| ``` | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Front matter values should use single quotes instead of double quotes. Change applyTo to use single quotes.