@@ -30,11 +30,11 @@ safe, and maintainable scripts. It aligns with Microsoft’s PowerShell cmdlet d
3030
3131- ** Alias Avoidance:**
3232 - Use full cmdlet names
33- - Avoid using aliases in scripts (e.g., use Get-ChildItem instead of gci)
33+ - Avoid using aliases in scripts (e.g., use ` Get-ChildItem ` instead of ` gci ` )
3434 - Document any custom aliases
3535 - Use full parameter names
3636
37- ### Example
37+ ### Example - Naming Conventions
3838
3939``` powershell
4040function Get-UserProfile {
@@ -49,6 +49,9 @@ function Get-UserProfile {
4949 )
5050
5151 process {
52+ $outputString = "Searching for: '$($Username)'"
53+ Write-Verbose -Message $outputString
54+ Write-Verbose -Message "Profile type: $ProfileType"
5255 # Logic here
5356 }
5457}
@@ -75,12 +78,14 @@ function Get-UserProfile {
7578 - Enable tab completion where possible
7679
7780- ** Switch Parameters:**
78- - Use [ switch] for boolean flags
79- - Avoid $true/$false parameters
80- - Default to $false when omitted
81- - Use clear action names
81+ - ** ALWAYS** use ` [switch] ` for boolean flags, never ` [bool] `
82+ - ** NEVER** use ` [bool]$Parameter ` or assign default values
83+ - Switch parameters default to ` $false ` when omitted
84+ - Use clear, action-oriented names
85+ - Test presence with ` .IsPresent `
86+ - Using ` $true ` /` $false ` in parameter attributes (e.g., ` Mandatory = $true ` ) is acceptable
8287
83- ### Example
88+ ### Example - Parameter Design
8489
8590``` powershell
8691function Set-ResourceConfiguration {
@@ -93,16 +98,24 @@ function Set-ResourceConfiguration {
9398 [ValidateSet('Dev', 'Test', 'Prod')]
9499 [string]$Environment = 'Dev',
95100
101+ # ✔️ CORRECT: Use `[switch]` with no default value
96102 [Parameter()]
97103 [switch]$Force,
98104
105+ # ❌ WRONG: Shows incorrect default assignment, however this is correct syntax (requires `[switch]` cast).
106+ [Parameter()]
107+ [switch]$Quiet = [switch]$true,
108+
99109 [Parameter()]
100110 [ValidateNotNullOrEmpty()]
101111 [string[]]$Tags
102112 )
103113
104114 process {
105- # Logic here
115+ # Use .IsPresent to check switch state
116+ if ($Quiet.IsPresent) {
117+ Write-Verbose "Quiet mode enabled"
118+ }
106119 }
107120}
108121```
@@ -133,7 +146,7 @@ function Set-ResourceConfiguration {
133146 - Return modified/created object with ` -PassThru `
134147 - Use verbose/warning for status updates
135148
136- ### Example
149+ ### Example - Pipeline and Output
137150
138151``` powershell
139152function Update-ResourceStatus {
@@ -163,7 +176,7 @@ function Update-ResourceStatus {
163176 Name = $Name
164177 Status = $Status
165178 LastUpdated = $timestamp
166- UpdatedBy = $ env:USERNAME
179+ UpdatedBy = "$($ env:USERNAME)"
167180 }
168181
169182 # Only output if PassThru is specified
@@ -183,8 +196,8 @@ function Update-ResourceStatus {
183196- ** ShouldProcess Implementation:**
184197 - Use ` [CmdletBinding(SupportsShouldProcess = $true)] `
185198 - Set appropriate ` ConfirmImpact ` level
186- - Call ` $PSCmdlet.ShouldProcess() ` for system changes
187- - Use ` ShouldContinue() ` for additional confirmations
199+ - Call ` $PSCmdlet.ShouldProcess() ` as close the the changes action
200+ - Use ` $PSCmdlet. ShouldContinue()` for additional confirmations
188201
189202- ** Message Streams:**
190203 - ` Write-Verbose ` for operational details with ` -Verbose `
@@ -209,69 +222,32 @@ function Update-ResourceStatus {
209222 - Support automation scenarios
210223 - Document all required inputs
211224
212- ### Example
225+ ### Example - Error Handling and Safety
213226
214227``` powershell
215- function Remove-UserAccount {
216- [CmdletBinding(SupportsShouldProcess = $true , ConfirmImpact = 'High')]
228+ function Remove-CacheFiles {
229+ [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'High')]
217230 param(
218- [Parameter(Mandatory, ValueFromPipeline)]
219- [ValidateNotNullOrEmpty()]
220- [string]$Username,
221-
222- [Parameter()]
223- [switch]$Force
231+ [Parameter(Mandatory)]
232+ [string]$Path
224233 )
225234
226- begin {
227- Write-Verbose 'Starting user account removal process'
228- $ErrorActionPreference = 'Stop'
229- }
230-
231- process {
232- try {
233- # Validation
234- if (-not (Test-UserExists -Username $Username)) {
235- $errorRecord = [System.Management.Automation.ErrorRecord]::new(
236- [System.Exception]::new("User account '$Username' not found"),
237- 'UserNotFound',
238- [System.Management.Automation.ErrorCategory]::ObjectNotFound,
239- $Username
240- )
241- $PSCmdlet.WriteError($errorRecord)
242- return
243- }
244-
245- # Confirmation
246- $shouldProcessMessage = "Remove user account '$Username'"
247- if ($Force -or $PSCmdlet.ShouldProcess($Username, $shouldProcessMessage)) {
248- Write-Verbose "Removing user account: $Username"
249-
250- # Main operation
251- Remove-ADUser -Identity $Username -ErrorAction Stop
252- Write-Warning "User account '$Username' has been removed"
253- }
254- } catch [Microsoft.ActiveDirectory.Management.ADException] {
255- $errorRecord = [System.Management.Automation.ErrorRecord]::new(
256- $_.Exception,
257- 'ActiveDirectoryError',
258- [System.Management.Automation.ErrorCategory]::NotSpecified,
259- $Username
260- )
261- $PSCmdlet.ThrowTerminatingError($errorRecord)
262- } catch {
263- $errorRecord = [System.Management.Automation.ErrorRecord]::new(
264- $_.Exception,
265- 'UnexpectedError',
266- [System.Management.Automation.ErrorCategory]::NotSpecified,
267- $Username
268- )
269- $PSCmdlet.ThrowTerminatingError($errorRecord)
235+ try {
236+ $files = Get-ChildItem -Path $Path -Filter "*.cache" -ErrorAction Stop
237+
238+ # Demonstrates WhatIf support
239+ if ($PSCmdlet.ShouldProcess($Path, 'Remove cache files')) {
240+ $files | Remove-Item -Force -ErrorAction Stop
241+ Write-Verbose "Removed $($files.Count) cache files from $Path"
270242 }
271- }
272-
273- end {
274- Write-Verbose 'User account removal process completed'
243+ } catch {
244+ $errorRecord = [System.Management.Automation.ErrorRecord]::new(
245+ $_.Exception,
246+ 'RemovalFailed',
247+ [System.Management.Automation.ErrorCategory]::NotSpecified,
248+ $Path
249+ )
250+ $PSCmdlet.WriteError($errorRecord)
275251 }
276252}
277253```
@@ -307,50 +283,77 @@ function Remove-UserAccount {
307283 - Use ` ForEach-Object ` instead of ` % `
308284 - Use ` Get-ChildItem ` instead of ` ls ` or ` dir `
309285
286+ ---
287+
310288## Full Example: End-to-End Cmdlet Pattern
311289
312290``` powershell
313- function New-Resource {
314- [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Medium ')]
291+ function Remove-UserAccount {
292+ [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'High ')]
315293 param(
316- [Parameter(Mandatory = $true,
317- ValueFromPipeline = $true,
318- ValueFromPipelineByPropertyName = $true)]
294+ [Parameter(Mandatory, ValueFromPipeline)]
319295 [ValidateNotNullOrEmpty()]
320- [string]$Name ,
296+ [string]$Username ,
321297
322298 [Parameter()]
323- [ValidateSet('Development', 'Production')]
324- [string]$Environment = 'Development'
299+ [switch]$Force
325300 )
326301
327302 begin {
328- Write-Verbose 'Starting resource creation process'
303+ Write-Verbose 'Starting user account removal process'
304+ $currentErrorActionValue = $ErrorActionPreference
305+ $ErrorActionPreference = 'Stop'
329306 }
330307
331308 process {
332309 try {
333- if ($PSCmdlet.ShouldProcess($Name, 'Create new resource')) {
334- # Resource creation logic here
335- Write-Output ([PSCustomObject]@{
336- Name = $Name
337- Environment = $Environment
338- Created = Get-Date
339- })
310+ # Validation
311+ if (-not (Test-UserExists -Username $Username)) {
312+ $errorRecord = [System.Management.Automation.ErrorRecord]::new(
313+ [System.Exception]::new("User account '$Username' not found"),
314+ 'UserNotFound',
315+ [System.Management.Automation.ErrorCategory]::ObjectNotFound,
316+ $Username
317+ )
318+ $PSCmdlet.WriteError($errorRecord)
319+ return
340320 }
321+
322+ # ShouldProcess enables -WhatIf and -Confirm support
323+ if ($PSCmdlet.ShouldProcess($Username, "Remove user account")) {
324+ # ShouldContinue provides an additional confirmation prompt for high-impact operations
325+ # This prompt is bypassed when -Force is specified
326+ if ($Force -or $PSCmdlet.ShouldContinue("Are you sure you want to remove '$Username'?", "Confirm Removal")) {
327+ Write-Verbose "Removing user account: $Username"
328+
329+ # Main operation
330+ Remove-ADUser -Identity $Username -ErrorAction Stop
331+ Write-Warning "User account '$Username' has been removed"
332+ }
333+ }
334+ } catch [Microsoft.ActiveDirectory.Management.ADException] {
335+ $errorRecord = [System.Management.Automation.ErrorRecord]::new(
336+ $_.Exception,
337+ 'ActiveDirectoryError',
338+ [System.Management.Automation.ErrorCategory]::NotSpecified,
339+ $Username
340+ )
341+ $PSCmdlet.ThrowTerminatingError($errorRecord)
341342 } catch {
342343 $errorRecord = [System.Management.Automation.ErrorRecord]::new(
343344 $_.Exception,
344- 'ResourceCreationFailed ',
345+ 'UnexpectedError ',
345346 [System.Management.Automation.ErrorCategory]::NotSpecified,
346- $Name
347+ $Username
347348 )
348349 $PSCmdlet.ThrowTerminatingError($errorRecord)
349350 }
350351 }
351352
352353 end {
353- Write-Verbose 'Completed resource creation process'
354+ Write-Verbose 'User account removal process completed'
355+ # Set ErrorActionPreference back to the value it had
356+ $ErrorActionPreference = $currentErrorActionValue
354357 }
355358}
356359```
0 commit comments