Skip to content

Commit 7114d25

Browse files
committed
Merge pull request #120 from PowerShell/master
Forward Integrate: Master to BugFixes
2 parents 1177959 + 210c2a3 commit 7114d25

19 files changed

+1221
-3
lines changed

CHANGELOG.MD

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
## Unreleased (May.7, 2015)
2+
###Features:
3+
- Integrated with waffle.io for Project Management.
4+
- Added documentation for writing script rules.
5+
6+
###Rules:
7+
- AvoidUsingWMICmdlet rule: For PowerShell 3.0 and above, usage of WMI cmdlets is not recommended. This rule is to detect WMI cmdlet usage in scripts that are written for PS 3.0 and above.
8+
- DSCTestsPresent rule: Resource module contains Tests folder with tests for given resource.
9+
- UseOutputTypeCorrectly rule: If we can identify the type of an object that is outputted to the pipeline by a cmdlet, then that type must be listed in the OutputType attribute.
10+
11+
###Fixes:
12+
13+
- PSProvideVerboseMessage only throws warnings in non-advanced functions.
14+
- Fix the issue in importing customized rule
15+
16+
17+
18+
19+
##Relesed on Apr.24, 2015
20+
21+
###Features:
22+
- Finalized three levels of Severity - Error/Warning/Information.
23+
- Improved PSScriptAnalyzer engine behavior: emits non-terminating errors (Ex: for failed ast parse) and continues rule application when running on multiple scripts.
24+
- Added wild card supports for rules in Invoke-ScriptAnalyzer and Get-ScriptAnalyzer. Eg. Invoke-ScriptAnalyzer -IncludeRule PSAvoid* will apply all rules starting with PSAvoid* in built in rule assemblies.
25+
- Added -Severity to Get-ScriptAnalyzerRules. Get-ScriptAnalyzer -Severity will filter rules based on the severity given.
26+
- Added Suppression functionality. Users are now able to specify suppression on certain parts of the scripts by specifying "SupressMessageAttribute" in the scripts. More details and documentations will be coming soon in blog posts. Also comes with this feature is the ability for users to display a list of suppressed messages.
27+
28+
###Rules:
29+
30+
- Added DSC Rules for resources including Parameter validation, Usage of standard DSC functions and return type validation. Rule checkings also support for DSC classes. Built-in DSC rules include:
31+
+ UseStandardDSCFunctionsInResource
32+
+ UseIdenticalParametersDSC
33+
+ UseIdenticalMandatoryParametersDSC
34+
+ ReturnCorrectTypesForDSCFunctions
35+
- Added support in the engine to detect DSC configuration/resource files and disable default rule checkings on DSC configuration and resource files.
36+
- UseShouldProcessForStateChangingFunctions - If an advanced function has Verbs like New/Start/Stop/Restart/Reset/Set- that will change system state, it should support ShouldProcess attribute.
37+
38+
39+
###Fixes:
40+
41+
- Improved heuristics to detect usage of Username and Password instead of PSCredential type.
42+
- Improved accuracy in the detection of uninitialized variables.
43+
- Improved error messages to include error line numbers and file names.
44+
- Identified usage of PSBound parameters and PowerShell supplied variables such as $MyInvocation to avoid unnecessary noise in the results returned by some of the built-in rules.
45+
- Fixed terminating errors including "Illegal characters in Path".
46+

CustomizedRuleDocumentation.md

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
##Documentation for Customized Rules in PowerShell Scripts
2+
PSScriptAnalyzer uses MEF(Managed Extensibility Framework) to import all rules defined in the assembly. It can also consume rules written in PowerShell scripts. When calling Invoke-ScriptAnalyzer, users can pass customized rules using parameter -CustomizedRulePath to apply rule checkings on the scripts.
3+
4+
This documentation serves as a basic guideline on how to define customized rules.
5+
6+
###Basics
7+
- Functions should have comment-based help. Make sure .DESCRIPTION field is there, as it will be consumed as rule description for the customized rule.
8+
```
9+
<#
10+
.SYNOPSIS
11+
Name of your rule.
12+
.DESCRIPTION
13+
This would be the description of your rule. Please refer to Rule Documentation for consistent rule messages.
14+
.EXAMPLE
15+
.INPUTS
16+
.OUTPUTS
17+
.NOTES
18+
#>
19+
```
20+
21+
- Output type should be DiagnosticRecord:
22+
```
23+
[OutputType([Microsoft.Windows.Powershell.ScriptAnalyzer.Generic.DiagnosticRecord[]])]
24+
```
25+
26+
- Make sure each function takes either a Token or an Ast as a parameter
27+
```
28+
Param
29+
(
30+
[Parameter(Mandatory = $true)]
31+
[ValidateNotNullOrEmpty()]
32+
[System.Management.Automation.Language.ScriptBlockAst]
33+
$testAst
34+
)
35+
```
36+
37+
- DiagnosticRecord should have four properties: Message, Extent, RuleName and Severity
38+
```
39+
$result = [Microsoft.Windows.Powershell.ScriptAnalyzer.Generic.DiagnosticRecord[]]@{"Message" = "This is a sample rule";
40+
"Extent" = $ast.Extent;
41+
"RuleName" = $PSCmdlet.MyInvocation.InvocationName;
42+
"Severity" = "Warning"}
43+
```
44+
45+
- Make sure you export the function(s) at the end of the script using Export-ModuleMember
46+
```
47+
Export-ModuleMember -Function (FunctionName)
48+
```
49+
50+
###Example
51+
```
52+
<#
53+
.SYNOPSIS
54+
Uses #Requires -RunAsAdministrator instead of your own methods.
55+
.DESCRIPTION
56+
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.
57+
From Windows PowerShell 4.0, the #Requires statement let script developers require that sessions be run with elevated user rights (run as Administrator).
58+
Script developers does not need to write their own methods any more.
59+
To fix a violation of this rule, please consider to use #Requires -RunAsAdministrator instead of your own methods.
60+
.EXAMPLE
61+
Measure-RequiresRunAsAdministrator -ScriptBlockAst $ScriptBlockAst
62+
.INPUTS
63+
[System.Management.Automation.Language.ScriptBlockAst]
64+
.OUTPUTS
65+
[Microsoft.Windows.Powershell.ScriptAnalyzer.Generic.DiagnosticRecord[]]
66+
.NOTES
67+
None
68+
#>
69+
function Measure-RequiresRunAsAdministrator
70+
{
71+
[CmdletBinding()]
72+
[OutputType([Microsoft.Windows.Powershell.ScriptAnalyzer.Generic.DiagnosticRecord[]])]
73+
Param
74+
(
75+
[Parameter(Mandatory = $true)]
76+
[ValidateNotNullOrEmpty()]
77+
[System.Management.Automation.Language.ScriptBlockAst]
78+
$ScriptBlockAst
79+
)
80+
81+
Process
82+
{
83+
$results = @()
84+
try
85+
{
86+
#region Define predicates to find ASTs.
87+
# Finds specific method, IsInRole.
88+
[ScriptBlock]$predicate1 = {
89+
param ([System.Management.Automation.Language.Ast]$Ast)
90+
[bool]$returnValue = $false
91+
if ($Ast -is [System.Management.Automation.Language.MemberExpressionAst])
92+
{
93+
[System.Management.Automation.Language.MemberExpressionAst]$meAst = $ast;
94+
if ($meAst.Member -is [System.Management.Automation.Language.StringConstantExpressionAst])
95+
{
96+
[System.Management.Automation.Language.StringConstantExpressionAst]$sceAst = $meAst.Member;
97+
if ($sceAst.Value -eq "isinrole")
98+
{
99+
$returnValue = $true;
100+
}
101+
}
102+
}
103+
return $returnValue
104+
}
105+
106+
# Finds specific value, [system.security.principal.windowsbuiltinrole]::administrator.
107+
[ScriptBlock]$predicate2 = {
108+
param ([System.Management.Automation.Language.Ast]$Ast)
109+
[bool]$returnValue = $false
110+
if ($ast -is [System.Management.Automation.Language.AssignmentStatementAst])
111+
{
112+
[System.Management.Automation.Language.AssignmentStatementAst]$asAst = $Ast;
113+
if ($asAst.Right.ToString().ToLower() -eq "[system.security.principal.windowsbuiltinrole]::administrator")
114+
{
115+
$returnValue = $true
116+
}
117+
}
118+
return $returnValue
119+
}
120+
#endregion
121+
#region Finds ASTs that match the predicates.
122+
123+
[System.Management.Automation.Language.Ast[]]$methodAst = $ScriptBlockAst.FindAll($predicate1, $true)
124+
[System.Management.Automation.Language.Ast[]]$assignmentAst = $ScriptBlockAst.FindAll($predicate2, $true)
125+
if ($null -ne $ScriptBlockAst.ScriptRequirements)
126+
{
127+
if ((!$ScriptBlockAst.ScriptRequirements.IsElevationRequired) -and
128+
($methodAst.Count -ne 0) -and ($assignmentAst.Count -ne 0))
129+
{
130+
$result = [Microsoft.Windows.Powershell.ScriptAnalyzer.Generic.DiagnosticRecord]@{"Message" = $Messages.MeasureRequiresRunAsAdministrator;
131+
"Extent" = $assignmentAst.Extent;
132+
"RuleName" = $PSCmdlet.MyInvocation.InvocationName;
133+
"Severity" = "Information"}
134+
$results += $result
135+
}
136+
}
137+
else
138+
{
139+
if (($methodAst.Count -ne 0) -and ($assignmentAst.Count -ne 0))
140+
{
141+
$result = [Microsoft.Windows.Powershell.ScriptAnalyzer.Generic.DiagnosticRecord]@{"Message" = $Messages.MeasureRequiresRunAsAdministrator;
142+
"Extent" = $assignmentAst.Extent;
143+
"RuleName" = $PSCmdlet.MyInvocation.InvocationName;
144+
"Severity" = "Information"}
145+
$results += $result
146+
}
147+
}
148+
return $results
149+
#endregion
150+
}
151+
catch
152+
{
153+
$PSCmdlet.ThrowTerminatingError($PSItem)
154+
}
155+
}
156+
}
157+
```
158+
More examples can be found in *Tests\Engine\CommunityRules*

Engine/Helper.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2120,6 +2120,11 @@ public object VisitConvertExpression(ConvertExpressionAst convAst)
21202120
{
21212121
if (convAst != null)
21222122
{
2123+
if (convAst.Type.TypeName.GetReflectionType() != null)
2124+
{
2125+
return convAst.Type.TypeName.GetReflectionType().FullName;
2126+
}
2127+
21232128
return convAst.Type.TypeName.FullName;
21242129
}
21252130

@@ -2170,6 +2175,11 @@ public object VisitTypeConstraint(TypeConstraintAst typeAst)
21702175
{
21712176
if (typeAst != null)
21722177
{
2178+
if (typeAst.TypeName.GetReflectionType() != null)
2179+
{
2180+
return typeAst.TypeName.GetReflectionType().FullName;
2181+
}
2182+
21732183
return typeAst.TypeName.FullName;
21742184
}
21752185

@@ -2195,6 +2205,11 @@ public object VisitTypeExpression(TypeExpressionAst typeExpressionAst)
21952205
{
21962206
if (typeExpressionAst != null)
21972207
{
2208+
if (typeExpressionAst.TypeName.GetReflectionType() != null)
2209+
{
2210+
return typeExpressionAst.TypeName.GetReflectionType().FullName;
2211+
}
2212+
21982213
return typeExpressionAst.TypeName.FullName;
21992214
}
22002215

README.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
12
Introduction
23
============
34

@@ -18,7 +19,7 @@ Requirements
1819

1920
WS2012R2 / Windows 8.1 / Windows OS running **PowerShell v5.0** and **Windows Management Framework 5.0 Preview**
2021

21-
Download the latest WMF package from [Windows Management Framework 5.0 Preview February 2015](http://go.microsoft.com/fwlink/?LinkId=398175).
22+
Download the latest WMF package from [Windows Management Framework 5.0 Preview](http://go.microsoft.com/fwlink/?LinkId=398175).
2223

2324
Installation
2425
============
@@ -53,6 +54,13 @@ Pester-based ScriptAnalyzer Tests are located in ```<branch>/PSScriptAnalyzer/Te
5354
.\*.ps1 (Example - .\ AvoidConvertToSecureStringWithPlainText.ps1)
5455
*You can also run all tests under \Engine or \Rules by calling Invoke-Pester in the Engine/Rules directory.
5556

57+
Project Management Dashboard
58+
==============================
59+
60+
You can track issues, pull requests, backlog items here:
61+
62+
[![Stories in Ready](https://badge.waffle.io/PowerShell/PSScriptAnalyzer.png?label=ready&title=Ready)](https://waffle.io/PowerShell/PSScriptAnalyzer)
63+
5664

5765
Contributing to ScriptAnalyzer
5866
==============================
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
#DscExamplesPresent
2+
**Severity Level: Information**
3+
4+
5+
##Description
6+
7+
Checks that DSC examples for given resource are present.
8+
9+
##How to Fix
10+
11+
To fix a violation of this rule, please make sure Examples directory is present:
12+
* For non-class based resources it should exist at the same folder level as DSCResources folder.
13+
* For class based resources it should be present at the same folder level as resource psm1 file.
14+
15+
Examples folder should contain sample configuration for given resource - file name should contain resource's name.
16+
17+
##Example
18+
19+
### Non-class based resource
20+
21+
Let's assume we have non-class based resource with a following file structure:
22+
23+
* xAzure
24+
* DSCResources
25+
* MSFT_xAzureSubscription
26+
* MSFT_xAzureSubscription.psm1
27+
* MSFT_xAzureSubscription.schema.mof
28+
29+
In this case, to fix this warning, we should add examples in a following way:
30+
31+
* xAzure
32+
* DSCResources
33+
* MSFT_xAzureSubscription
34+
* MSFT_xAzureSubscription.psm1
35+
* MSFT_xAzureSubscription.schema.mof
36+
* Examples
37+
* MSFT_xAzureSubscription_AddSubscriptionExample.ps1
38+
* MSFT_xAzureSubscription_RemoveSubscriptionExample.ps1
39+
40+
### Class based resource
41+
42+
Let's assume we have class based resource with a following file structure:
43+
44+
* MyDscResource
45+
* MyDscResource.psm1
46+
* MyDscresource.psd1
47+
48+
In this case, to fix this warning, we should add examples in a following way:
49+
50+
* MyDscResource
51+
* MyDscResource.psm1
52+
* MyDscresource.psd1
53+
* Tests
54+
* MyDscResource_Example1.ps1
55+
* MyDscResource_Example2.ps1

RuleDocumentation/DscTestsPresent.md

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
#DscTestsPresent
2+
**Severity Level: Information**
3+
4+
5+
##Description
6+
7+
Checks that DSC tests for given resource are present.
8+
9+
##How to Fix
10+
11+
To fix a violation of this rule, please make sure Tests directory is present:
12+
* For non-class based resources it should exist at the same folder level as DSCResources folder.
13+
* For class based resources it should be present at the same folder level as resource psm1 file.
14+
15+
Tests folder should contain test script for given resource - file name should contain resource's name.
16+
17+
##Example
18+
19+
### Non-class based resource
20+
21+
Let's assume we have non-class based resource with a following file structure:
22+
23+
* xAzure
24+
* DSCResources
25+
* MSFT_xAzureSubscription
26+
* MSFT_xAzureSubscription.psm1
27+
* MSFT_xAzureSubscription.schema.mof
28+
29+
In this case, to fix this warning, we should add tests in a following way:
30+
31+
* xAzure
32+
* DSCResources
33+
* MSFT_xAzureSubscription
34+
* MSFT_xAzureSubscription.psm1
35+
* MSFT_xAzureSubscription.schema.mof
36+
* Tests
37+
* MSFT_xAzureSubscription_Tests.ps1
38+
39+
### Class based resource
40+
41+
Let's assume we have class based resource with a following file structure:
42+
43+
* MyDscResource
44+
* MyDscResource.psm1
45+
* MyDscresource.psd1
46+
47+
In this case, to fix this warning, we should add tests in a following way:
48+
49+
* MyDscResource
50+
* MyDscResource.psm1
51+
* MyDscresource.psd1
52+
* Tests
53+
* MyDscResource_Tests.ps1
54+

0 commit comments

Comments
 (0)