This browser is no longer supported.
Upgrade to Microsoft Edge to take advantage of the latest features, security updates, and technical support.
Note
Access to this page requires authorization. You can trysigning in orchanging directories.
Access to this page requires authorization. You can trychanging directories.
PSScriptAnalyzer uses theManaged Extensibility Framework (MEF) to import all rules defined inthe assembly. It can also consume rules written in PowerShell scripts.
When callingInvoke-ScriptAnalyzer, users can specify custom rules using theCustomizedRulePath parameter.
This article provides a basic guide for creating your own customized rules.
Include the.DESCRIPTION field. This becomes the description for the customized rule.
<#.SYNOPSIS Name of your rule..DESCRIPTION This would be the description of your rule. Please refer to Rule Documentation for consistent rule messages..EXAMPLE.INPUTS.OUTPUTS.NOTES#>[OutputType([Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord[]])]The name of theAst parameter name must end withAst.
Param( [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [System.Management.Automation.Language.ScriptBlockAst] $testAst)The name of theToken parameter name must end withToken.
Param( [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [System.Management.Automation.Language.Token[]] $testToken)TheDiagnosticRecord should have at least four properties:
$result = [Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord[]]@{ "Message" = "This is a sample rule" "Extent" = $ast.Extent "RuleName" = $PSCmdlet.MyInvocation.InvocationName "Severity" = "Warning"}Since version 1.17.0, you can include aSuggestedCorrections property of typeIEnumerable<CorrectionExtent>. Make sure to specify the correct type. For example:
[int]$startLineNumber = $ast.Extent.StartLineNumber[int]$endLineNumber = $ast.Extent.EndLineNumber[int]$startColumnNumber = $ast.Extent.StartColumnNumber[int]$endColumnNumber = $ast.Extent.EndColumnNumber[string]$correction = 'Correct text that replaces Extent text'[string]$file = $MyInvocation.MyCommand.Definition[string]$optionalDescription = 'Useful but optional description text'$objParams = @{ TypeName = 'Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.CorrectionExtent' ArgumentList = $startLineNumber, $endLineNumber, $startColumnNumber, $endColumnNumber, $correction, $file, $optionalDescription}$correctionExtent = New-Object @objParams$suggestedCorrections = New-Object System.Collections.ObjectModel.Collection[$($objParams.TypeName)]$suggestedCorrections.add($correctionExtent) | Out-Null[Microsoft.Windows.Powershell.ScriptAnalyzer.Generic.DiagnosticRecord]@{ "Message" = "This is a rule with a suggested correction" "Extent" = $ast.Extent "RuleName" = $PSCmdlet.MyInvocation.InvocationName "Severity" = "Warning" "Severity" = "Warning" "RuleSuppressionID" = "MyRuleSuppressionID" "SuggestedCorrections" = $suggestedCorrections}Export-ModuleMember -Function (FunctionName)<# .SYNOPSIS Uses #Requires -RunAsAdministrator instead of your own methods. .DESCRIPTION The #Requires statement prevents a script from running unless the Windows PowerShell version, modules, snap-ins, and module and snap-in version prerequisites are met. From Windows PowerShell 4.0, the #Requires statement let script developers require that sessions be run with elevated user rights (run as Administrator). Script developers does not need to write their own methods any more. To fix a violation of this rule, please consider using #Requires -RunAsAdministrator instead of your own methods. .EXAMPLE Measure-RequiresRunAsAdministrator -ScriptBlockAst $ScriptBlockAst .INPUTS [System.Management.Automation.Language.ScriptBlockAst] .OUTPUTS [Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord[]] .NOTES None#>function Measure-RequiresRunAsAdministrator{ [CmdletBinding()] [OutputType([Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord[]])] Param ( [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [System.Management.Automation.Language.ScriptBlockAst] $ScriptBlockAst ) Process { $results = @() try { #region Define predicates to find ASTs. # Finds specific method, IsInRole. [ScriptBlock]$predicate1 = { param ([System.Management.Automation.Language.Ast]$Ast) [bool]$returnValue = $false if ($Ast -is [System.Management.Automation.Language.MemberExpressionAst]) { [System.Management.Automation.Language.MemberExpressionAst]$meAst = $Ast if ($meAst.Member -is [System.Management.Automation.Language.StringConstantExpressionAst]) { [System.Management.Automation.Language.StringConstantExpressionAst]$sceAst = $meAst.Member if ($sceAst.Value -eq 'isinrole') { $returnValue = $true } } } return $returnValue } # Finds specific value, [system.security.principal.windowsbuiltinrole]::administrator. [ScriptBlock]$predicate2 = { param ([System.Management.Automation.Language.Ast]$Ast) [bool]$returnValue = $false if ($Ast -is [System.Management.Automation.Language.AssignmentStatementAst]) { [System.Management.Automation.Language.AssignmentStatementAst]$asAst = $Ast if ($asAst.Right.ToString() -eq '[system.security.principal.windowsbuiltinrole]::administrator') { $returnValue = $true } } return $returnValue } #endregion #region Finds ASTs that match the predicates. [System.Management.Automation.Language.Ast[]]$methodAst = $ScriptBlockAst.FindAll($predicate1, $true) [System.Management.Automation.Language.Ast[]]$assignmentAst = $ScriptBlockAst.FindAll($predicate2, $true) if ($null -ne $ScriptBlockAst.ScriptRequirements) { if ((!$ScriptBlockAst.ScriptRequirements.IsElevationRequired) -and ($methodAst.Count -ne 0) -and ($assignmentAst.Count -ne 0)) { $result = [Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord]@{ 'Message' = $Messages.MeasureRequiresRunAsAdministrator 'Extent' = $assignmentAst.Extent 'RuleName' = $PSCmdlet.MyInvocation.InvocationName 'Severity' = 'Information' } $results += $result } } else { if (($methodAst.Count -ne 0) -and ($assignmentAst.Count -ne 0)) { $result = [Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord]@{ 'Message' = $Messages.MeasureRequiresRunAsAdministrator 'Extent' = $assignmentAst.Extent 'RuleName' = $PSCmdlet.MyInvocation.InvocationName 'Severity' = 'Information' } $results += $result } } return $results #endregion } catch { $PSCmdlet.ThrowTerminatingError($PSItem) } }}More examples can be found in theCommunityAnalyzerRules folder on GitHub.
Was this page helpful?
Need help with this topic?
Want to try using Ask Learn to clarify or guide you through this topic?
Was this page helpful?
Want to try using Ask Learn to clarify or guide you through this topic?