{"id":14373,"date":"2015-02-24T11:59:00","date_gmt":"2015-02-24T19:59:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/powershell\/2015\/02\/24\/powershell-script-analyzer-static-code-analysis-for-windows-powershell-scripts-modules\/"},"modified":"2024-02-28T13:20:04","modified_gmt":"2024-02-28T21:20:04","slug":"powershell-script-analyzer-static-code-analysis-for-windows-powershell-scripts-modules-2","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/powershell\/powershell-script-analyzer-static-code-analysis-for-windows-powershell-scripts-modules-2\/","title":{"rendered":"PowerShell Script Analyzer: Static Code analysis for Windows PowerShell scripts &amp; modules"},"content":{"rendered":"<p><strong>Introduction:<\/strong><\/p>\n<p><a href=\"http:\/\/www.microsoft.com\/en-us\/download\/details.aspx?id=45883\">Windows Management Framework 5.0 Preview February 2015<\/a> includes the addition of a new Windows PowerShell Module called PSScriptAnalyzer. This is a static code checker for Windows PowerShell modules and scripts and is installed in $env:ProgramFiles\/WindowsPowerShell\/Modules.<\/p>\n<p>&nbsp;<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/30\/2018\/10\/0882.1.jpg\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/30\/2018\/10\/0882.1.jpg\" alt=\"\" border=\"0\" \/><\/a><\/p>\n<p>&nbsp;<\/p>\n<p>PSScriptAnalyzer checks the quality of Windows PowerShell code by running a set of rules. The rules are based on PowerShell best practices identified by PowerShell Team and the community. PSScriptAnalyzer generates DiagnosticResults (errors and warnings) to inform users about potential code defects and suggests possible solutions for improvements.<\/p>\n<p>PSScriptAnalyzer is shipped with a collection of built-in rules that checks various aspects of PowerShell code such as presence of uninitialized variables, usage of PSCredential Type, usage of Invoke-Expression etc. Additional functionalities such as exclude\/include specific rules are also supported.<\/p>\n<p>Custom rules written as PowerShell scripts can be supplied to the Script Analyzer. Read more about this in the last section. Code samples are also posted.<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p><strong>Usage and Scenarios:<\/strong><\/p>\n<ul>\n<li>PSScriptAnalyzer is shipped with the following built-in rules.<\/li>\n<\/ul>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/30\/2018\/10\/5807.2.jpg\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/30\/2018\/10\/5807.2.jpg\" alt=\"\" border=\"0\" \/><\/a><\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<ul>\n<li>Excluding specified rules when using PSScriptAnalyzer<\/li>\n<\/ul>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/30\/2018\/10\/5102.3.jpg\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/30\/2018\/10\/5102.3.jpg\" alt=\"\" border=\"0\" \/><\/a><\/p>\n<p>&nbsp;<\/p>\n<p><strong>\u00a0<\/strong><\/p>\n<ul>\n<li>Run only a specific set of rules, by adding the IncludeRule parameter:<\/li>\n<\/ul>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/powershell\/wp-content\/uploads\/sites\/30\/2015\/02\/7317.4.jpg\"><img decoding=\"async\" class=\"alignnone size-full wp-image-20460\" src=\"https:\/\/devblogs.microsoft.com\/powershell\/wp-content\/uploads\/sites\/30\/2015\/02\/7317.4.jpg\" alt=\"Image 7317 4\" width=\"881\" height=\"181\" srcset=\"https:\/\/devblogs.microsoft.com\/powershell\/wp-content\/uploads\/sites\/30\/2015\/02\/7317.4.jpg 881w, https:\/\/devblogs.microsoft.com\/powershell\/wp-content\/uploads\/sites\/30\/2015\/02\/7317.4-300x62.jpg 300w, https:\/\/devblogs.microsoft.com\/powershell\/wp-content\/uploads\/sites\/30\/2015\/02\/7317.4-768x158.jpg 768w\" sizes=\"(max-width: 881px) 100vw, 881px\" \/><\/a><\/p>\n<p><strong>Authoring Custom\/External Rules as PowerShell Scripts:<\/strong><\/p>\n<p>PSScriptAnalyzer can consume modules containing definitions for rules. The requirement here is that the exported function containing the rule definition must have a parameter of type \u201c<a href=\"https:\/\/msdn.microsoft.com\/en-us\/library\/system.management.automation.language.ast%28v=vs.85%29.aspx\">Ast<\/a>\u201d or \u201c<a href=\"https:\/\/msdn.microsoft.com\/en-us\/library\/system.management.automation.language.token%28v=vs.85%29.aspx\">Token<\/a>\u201d. The engine calls into the function and supplies the Ast of the PowerShell script under analysis. The function can do the actual work of validating the Ast. Here is the usage:<\/p>\n<p>By using the \u201cCustomizedRulePath\u201d parameter in Invoke-ScriptAnalyzer cmdlet, one can point to a folder\/module containing external script rules.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/powershell\/wp-content\/uploads\/sites\/30\/2015\/02\/7824.5.jpg\"><img decoding=\"async\" class=\"alignnone size-full wp-image-20461\" src=\"https:\/\/devblogs.microsoft.com\/powershell\/wp-content\/uploads\/sites\/30\/2015\/02\/7824.5.jpg\" alt=\"Image 7824 5\" width=\"811\" height=\"253\" srcset=\"https:\/\/devblogs.microsoft.com\/powershell\/wp-content\/uploads\/sites\/30\/2015\/02\/7824.5.jpg 811w, https:\/\/devblogs.microsoft.com\/powershell\/wp-content\/uploads\/sites\/30\/2015\/02\/7824.5-300x94.jpg 300w, https:\/\/devblogs.microsoft.com\/powershell\/wp-content\/uploads\/sites\/30\/2015\/02\/7824.5-768x240.jpg 768w\" sizes=\"(max-width: 811px) 100vw, 811px\" \/><\/a><\/p>\n<p><strong>Example 1<\/strong> \u2013 Rule to detect the presence of Write-Host:<\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">&lt;#<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">.SYNOPSIS<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0 You should never use Write-Host to create any script output whatsoever.<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">.DESCRIPTION<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0 It is generally accepted that you should never use Write-Host to create any script output whatsoever, unless your script (or function, or whatever) uses the Show verb (as in, Show-Performance).<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0 That verb explicitly means \u201cshow on the screen, with no other possibilities.\u201d Like Show-Command.<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0 To fix a violation of this rule, please replace Write-Host with Write-Output in most scenarios.<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">.EXAMPLE<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0 Test-WriteHost -CommandAst $CommandAst<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">.INPUTS<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0 [System.Management.Automation.Language.CommandAst]<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">.OUTPUTS<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0 [PSCustomObject[]]<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">.NOTES<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0 Reference: Output, The Community Book of PowerShell Practices.<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">#&gt;<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">function Test-WriteHost<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">{<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0 [CmdletBinding()]<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0 [OutputType([PSCustomObject[]])]<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0 Param<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0 (<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 [Parameter(Mandatory = $true)]<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 [ValidateNotNullOrEmpty()]<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 [System.Management.Automation.Language.CommandAst]<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 $CommandAst<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0 )<\/span><\/p>\n<p>&nbsp;<\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0 Process<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0 {<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 try<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 {<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 $commandName = $CommandAst.GetCommandName()<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 # Checks command name, if the command name matches Write-Host or<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 # user-defined aliases, this rule is triggered.<\/span><\/p>\n<p>&nbsp;<\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if ($null -ne $commandName)<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 {<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 $alias = (Get-Alias -Definition &#8220;Write-Host&#8221; -ErrorAction SilentlyContinue).Name<\/span><\/p>\n<p>&nbsp;<\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 if (($commandName -eq &#8220;Write-Host&#8221;) -or<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 ($alias -eq $commandName))<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 {<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 [PSCustomObject]@{Message\u00a0 = &#8220;Avoid Using Write-Host&#8221;;<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Extent\u00a0\u00a0 = $CommandAst.Extent;<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 RuleName = $PSCmdlet.MyInvocation.InvocationName;<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Severity = &#8220;Warning&#8221;}\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 catch<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 {<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 $PSCmdlet.ThrowTerminatingError($PSItem)<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0 }<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">}<\/span><\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p><strong>Example 2<\/strong> \u2013 Rule for Try-Catch-Finally for handling terminating errors:<\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">&lt;#<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">.SYNOPSIS<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0 Considers to use try-catch-finally statements instead of using $?.<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">.DESCRIPTION<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0 When you need to examine the error that occurred, try to avoid using $?. It actually doesn\u2019t mean an error did or did not occur; it\u2019s reporting whether or not the last-run command considered itself to have completed successfully.<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0 You get no details on what happened. To fix a violation of this rule, please consider to use try-catch-finally statements.<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">.EXAMPLE<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0 Test-QuestionVariable -ScriptBlockAst $ScriptBlockAst<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">.INPUTS<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0 [System.Management.Automation.Language.ScriptBlockAst]<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">.OUTPUTS<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0 [PSCustomObject[]]<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">.NOTES<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0 Reference: Trapping and Capturing Errors, Windows PowerShell Best Practices.<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">#&gt;<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">function Test-QuestionVariable<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">{<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0 [CmdletBinding()]<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0 [OutputType([PSCustomObject[]])]<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0 Param<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0 (<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 [Parameter(Mandatory = $true)]<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 [ValidateNotNullOrEmpty()]<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 [System.Management.Automation.Language.ScriptBlockAst]<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 $ScriptBlockAst<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0 )<\/span><\/p>\n<p>&nbsp;<\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0 Process<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0 {<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 try<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 {<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 # Gets question variables<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 $questionVariables = $ScriptBlockAst.FindAll(<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 {$args[0] \u2013is [System.Management.Automation.Language.VariableExpressionAst] \u2013and\u00a0\u00a0<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 $args[0].VariablePath.UserPath -eq \u2019?\u2019},$true)<\/span><\/p>\n<p>&nbsp;<\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 foreach ($questionVariable in $questionVariables)<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 {<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 [PSCustomObject]@{Message\u00a0 = &#8220;Avoid Using Question Variable\u201d;<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Extent\u00a0\u00a0 = $questionVariable.Extent;<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 RuleName = $PSCmdlet.MyInvocation.InvocationName;<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Severity = &#8220;Warning&#8221;}<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 catch<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 {<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 $PSCmdlet.ThrowTerminatingError($PSItem)<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">\u00a0\u00a0\u00a0 }<\/span><\/p>\n<p><span style=\"color: #3366ff; font-size: small; font-family: 'courier new', courier;\">}<\/span><\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>Note that in the next release we will be moving to using a specific type (called DiagnosticRecord), instead of using PSCustomObject, when returning results of the rule.<\/p>\n<p>Also, the next blog post will talk about authoring rules in C#<\/p>\n<p><em>That\u2019s it for now!<\/em> Run this framework against your scripts\/modules and let us know of your feedback\/suggestions.<\/p>\n<p>&nbsp;<\/p>\n<p><strong>Feedback and Contact:<\/strong><\/p>\n<p><a href=\"https:\/\/connect.microsoft.com\/PowerShell\/Feedback\">https:\/\/connect.microsoft.com\/PowerShell\/Feedback<\/a><\/p>\n<p>You can also follow us @: http:\/\/blogs.msdn.com\/b\/powershell\/<\/p>\n<p>&nbsp;<\/p>\n<p>Thanks!<\/p>\n<p>Raghu Shantha [MSFT]<\/p>\n<p>PowerShell ScriptAnalyzer Team<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Introduction: Windows Management Framework 5.0 Preview February 2015 includes the addition of a new Windows PowerShell Module called PSScriptAnalyzer. This is a static code checker for Windows PowerShell modules and scripts and is installed in $env:ProgramFiles\/WindowsPowerShell\/Modules. &nbsp; &nbsp; PSScriptAnalyzer checks the quality of Windows PowerShell code by running a set of rules. The rules are [&hellip;]<\/p>\n","protected":false},"author":600,"featured_media":13641,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[3182],"class_list":["post-14373","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-powershell","tag-psscriptanalyzer"],"acf":[],"blog_post_summary":"<p>Introduction: Windows Management Framework 5.0 Preview February 2015 includes the addition of a new Windows PowerShell Module called PSScriptAnalyzer. This is a static code checker for Windows PowerShell modules and scripts and is installed in $env:ProgramFiles\/WindowsPowerShell\/Modules. &nbsp; &nbsp; PSScriptAnalyzer checks the quality of Windows PowerShell code by running a set of rules. The rules are [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/posts\/14373","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/users\/600"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/comments?post=14373"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/posts\/14373\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/media\/13641"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/media?parent=14373"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/categories?post=14373"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/tags?post=14373"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}