Skip to content

Commit f880cf1

Browse files
author
Quoc Truong
committed
Add an extra check for CredentialAttribute for the credential rules
1 parent 3b3f0ed commit f880cf1

8 files changed

+68
-16
lines changed

Rules/AvoidUserNameAndPasswordParams.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
//
1212

1313
using System;
14+
using System.Linq;
1415
using System.Collections.Generic;
1516
using System.Management.Automation;
1617
using System.Management.Automation.Language;
@@ -55,11 +56,18 @@ public IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName)
5556
TypeInfo paramType = (TypeInfo)paramAst.StaticType;
5657
String paramName = paramAst.Name.VariablePath.ToString();
5758

59+
// if this is pscredential type, skip
5860
if (paramType == typeof(PSCredential) || (paramType.IsArray && paramType.GetElementType() == typeof (PSCredential)))
5961
{
6062
continue;
6163
}
6264

65+
// if this has credential attribute, skip
66+
if (paramAst.Attributes.Any(paramAttribute => paramAttribute.TypeName.GetReflectionType() == typeof(CredentialAttribute)))
67+
{
68+
continue;
69+
}
70+
6371
foreach (String password in passwords)
6472
{
6573
if (paramName.IndexOf(password, StringComparison.OrdinalIgnoreCase) != -1)

Rules/Strings.Designer.cs

Lines changed: 5 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Rules/Strings.resx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -217,13 +217,13 @@
217217
<value>One Char</value>
218218
</data>
219219
<data name="UsePSCredentialTypeDescription" xml:space="preserve">
220-
<value>Checks that cmdlets that have a Credential parameter accept PSCredential. This comes from the PowerShell teams best practices.</value>
220+
<value>Checks that cmdlets that have a Credential parameter accept PSCredential or has a CredentialAttribute. This comes from the PowerShell teams best practices.</value>
221221
</data>
222222
<data name="UsePSCredentialTypeError" xml:space="preserve">
223-
<value>The Credential parameter in '{0}' must be of the type PSCredential.</value>
223+
<value>The Credential parameter in '{0}' must be of the type PSCredential or has a CredentialAttribute.</value>
224224
</data>
225225
<data name="UsePSCredentialTypeErrorSB" xml:space="preserve">
226-
<value>The Credential parameter in a found script block must be of the type PSCredential.</value>
226+
<value>The Credential parameter in a found script block must be of the type PSCredential or has a CredentialAttribute.</value>
227227
</data>
228228
<data name="UsePSCredentialTypeCommonName" xml:space="preserve">
229229
<value>PSCredential</value>
@@ -511,10 +511,10 @@
511511
<value>Avoid Using Username and Password Parameters</value>
512512
</data>
513513
<data name="AvoidUsernameAndPasswordParamsDescription" xml:space="preserve">
514-
<value>Functions should only take in a credential parameter of type PSCredential instead of username and password parameters.</value>
514+
<value>Functions should only take in a credential parameter of type PSCredential or has a CredentialAttribute instead of username and password parameters.</value>
515515
</data>
516516
<data name="AvoidUsernameAndPasswordParamsError" xml:space="preserve">
517-
<value>Function '{0}' has both username and password parameters. A credential parameter of type PSCredential should be used.</value>
517+
<value>Function '{0}' has both username and password parameters. A credential parameter of type PSCredential or has a CredentialAttribute should be used.</value>
518518
</data>
519519
<data name="AvoidUsernameAndPasswordParamsName" xml:space="preserve">
520520
<value>AvoidUsingUserNameAndPassWordParams</value>

Rules/UsePSCredentialType.cs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
//
1212

1313
using System;
14+
using System.Linq;
1415
using System.Collections.Generic;
1516
using System.Management.Automation;
1617
using System.Management.Automation.Language;
@@ -50,7 +51,9 @@ public IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName)
5051
{
5152
foreach (ParameterAst parameter in funcDefAst.Parameters)
5253
{
53-
if (parameter.Name.VariablePath.UserPath.Equals("Credential", StringComparison.OrdinalIgnoreCase) && parameter.StaticType != typeof(PSCredential))
54+
if (parameter.Name.VariablePath.UserPath.Equals("Credential", StringComparison.OrdinalIgnoreCase)
55+
&& parameter.StaticType != typeof(PSCredential)
56+
&& !parameter.Attributes.Any(paramAttribute => paramAttribute.TypeName.GetReflectionType() == typeof(CredentialAttribute)))
5457
{
5558
yield return new DiagnosticRecord(string.Format(CultureInfo.CurrentCulture, Strings.UsePSCredentialTypeError, funcName), funcDefAst.Extent, GetName(), DiagnosticSeverity.Warning, fileName);
5659
}
@@ -61,7 +64,9 @@ public IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName)
6164
{
6265
foreach (ParameterAst parameter in funcDefAst.Body.ParamBlock.Parameters)
6366
{
64-
if (parameter.Name.VariablePath.UserPath.Equals("Credential", StringComparison.OrdinalIgnoreCase) && parameter.StaticType != typeof(PSCredential))
67+
if (parameter.Name.VariablePath.UserPath.Equals("Credential", StringComparison.OrdinalIgnoreCase)
68+
&& parameter.StaticType != typeof(PSCredential)
69+
&& !parameter.Attributes.Any(paramAttribute => paramAttribute.TypeName.GetReflectionType() == typeof(CredentialAttribute)))
6570
{
6671
yield return new DiagnosticRecord(string.Format(CultureInfo.CurrentCulture, Strings.UsePSCredentialTypeError, funcName), funcDefAst.Extent, GetName(), DiagnosticSeverity.Warning, fileName);
6772
}
@@ -75,7 +80,9 @@ public IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName)
7580
{
7681
foreach (ParameterAst parameter in scriptBlockAst.ParamBlock.Parameters)
7782
{
78-
if (parameter.Name.VariablePath.UserPath.Equals("Credential", StringComparison.OrdinalIgnoreCase) && parameter.StaticType != typeof(PSCredential))
83+
if (parameter.Name.VariablePath.UserPath.Equals("Credential", StringComparison.OrdinalIgnoreCase)
84+
&& parameter.StaticType != typeof(PSCredential)
85+
&& !parameter.Attributes.Any(paramAttribute => paramAttribute.TypeName.GetReflectionType() == typeof(CredentialAttribute)))
7986
{
8087
yield return new DiagnosticRecord(string.Format(CultureInfo.CurrentCulture, Strings.UsePSCredentialTypeErrorSB), scriptBlockAst.Extent, GetName(), DiagnosticSeverity.Warning, fileName);
8188
}

Tests/Rules/AvoidUserNameAndPasswordParams.tests.ps1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Import-Module PSScriptAnalyzer
22

3-
$violationMessage = "Function 'Verb-Noun' has both username and password parameters. A credential parameter of type PSCredential should be used."
3+
$violationMessage = "Function 'Verb-Noun' has both username and password parameters. A credential parameter of type PSCredential or has a CredentialAttribute should be used."
44
$violationName = "PSAvoidUsingUserNameAndPasswordParams"
55
$directory = Split-Path -Parent $MyInvocation.MyCommand.Path
66
$violations = Invoke-ScriptAnalyzer $directory\AvoidUserNameAndPasswordParams.ps1 | Where-Object {$_.RuleName -eq $violationName}

Tests/Rules/AvoidUserNameAndPasswordParamsNoViolations.ps1

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,24 @@ function MyFunction2 ($param1, $passwords)
1111
function MyFunction3 ([PSCredential]$username, $passwords)
1212
{
1313
}
14+
15+
function MyFunction4
16+
{
17+
[CmdletBinding()]
18+
[Alias()]
19+
[OutputType([int])]
20+
Param
21+
(
22+
# Param1 help description
23+
[Parameter(Mandatory=$true,
24+
ValueFromPipelineByPropertyName=$true,
25+
Position=0)]
26+
[System.Management.Automation.CredentialAttribute()]
27+
$UserName,
28+
29+
# Param2 help description
30+
[int]
31+
[System.Management.Automation.CredentialAttribute()]
32+
$Password
33+
)
34+
}

Tests/Rules/PSCredentialType.tests.ps1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
Import-Module PSScriptAnalyzer
2-
$violationMessage = "The Credential parameter in 'Credential' must be of the type PSCredential."
2+
$violationMessage = "The Credential parameter in 'Credential' must be of the type PSCredential or has a CredentialAttribute."
33
$violationName = "PSUsePSCredentialType"
44
$directory = Split-Path -Parent $MyInvocation.MyCommand.Path
55
$violations = Invoke-ScriptAnalyzer $directory\PSCredentialType.ps1 | Where-Object {$_.RuleName -eq $violationName}
Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,19 @@
11
function Credential([pscredential]$credential) {
22

3-
}
3+
}
4+
5+
function Credential2
6+
{
7+
[CmdletBinding()]
8+
[Alias()]
9+
[OutputType([int])]
10+
Param
11+
(
12+
# Param1 help description
13+
[Parameter(Mandatory=$true,
14+
ValueFromPipelineByPropertyName=$true,
15+
Position=0)]
16+
[System.Management.Automation.CredentialAttribute()]
17+
$Credential
18+
)
19+
}

0 commit comments

Comments
 (0)