diff --git a/Engine/ScriptAnalyzerEngine.csproj b/Engine/ScriptAnalyzerEngine.csproj index f684df39c..395f74307 100644 --- a/Engine/ScriptAnalyzerEngine.csproj +++ b/Engine/ScriptAnalyzerEngine.csproj @@ -78,9 +78,6 @@ - - - diff --git a/Rules/AvoidShouldContinueWithoutForce.cs b/Rules/AvoidShouldContinueWithoutForce.cs new file mode 100644 index 000000000..e7a956a54 --- /dev/null +++ b/Rules/AvoidShouldContinueWithoutForce.cs @@ -0,0 +1,118 @@ +using System; +using System.Collections.ObjectModel; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Management.Automation; +using System.Management.Automation.Language; +using Microsoft.Windows.Powershell.ScriptAnalyzer.Generic; +using System.ComponentModel.Composition; +using System.Resources; +using System.Globalization; +using System.Threading; +using System.Reflection; + +namespace Microsoft.Windows.Powershell.ScriptAnalyzer.BuiltinRules +{ + /// + /// AvoidShouldContinueWithoutForceParameter: Check that if ShouldContinue is used, + /// the function should have a boolean force parameter + /// + [Export(typeof(IScriptRule))] + public class AvoidShouldContinueWithoutForce : IScriptRule + { + /// + /// AvoidShouldContinueWithoutForceCheck that if ShouldContinue is used, + /// the function should have a boolean force parameter + /// + public IEnumerable AnalyzeScript(Ast ast, string fileName) + { + if (ast == null) throw new ArgumentNullException(Strings.NullAstErrorMessage); + + // Finds all ParamAsts. + IEnumerable funcAsts = ast.FindAll(testAst => testAst is FunctionDefinitionAst, true); + + // Iterrates all ParamAsts and check if there are any force. + foreach (FunctionDefinitionAst funcAst in funcAsts) + { + IEnumerable paramAsts = funcAst.FindAll(testAst => testAst is ParameterAst, true); + bool hasForce = false; + + foreach (ParameterAst paramAst in paramAsts) + { + if (String.Equals(paramAst.Name.VariablePath.ToString(), "force", StringComparison.OrdinalIgnoreCase) + && String.Equals(paramAst.StaticType.FullName, "System.Boolean", StringComparison.OrdinalIgnoreCase)) + { + hasForce = true; + break; + } + } + + if (hasForce) + { + continue; + } + + IEnumerable imeAsts = funcAst.FindAll(testAst => testAst is InvokeMemberExpressionAst, true); + + foreach (InvokeMemberExpressionAst imeAst in imeAsts) + { + VariableExpressionAst typeAst = imeAst.Expression as VariableExpressionAst; + if (typeAst == null) continue; + + if (String.Equals(typeAst.VariablePath.UserPath, "pscmdlet", StringComparison.OrdinalIgnoreCase) + && (String.Equals(imeAst.Member.Extent.Text, "shouldcontinue", StringComparison.OrdinalIgnoreCase))) + { + yield return new DiagnosticRecord( + String.Format(CultureInfo.CurrentCulture, Strings.AvoidShouldContinueWithoutForceError, funcAst.Name, System.IO.Path.GetFileName(fileName)), + imeAst.Extent, GetName(), DiagnosticSeverity.Warning, fileName); + } + } + } + } + + /// + /// GetName: Retrieves the name of this rule. + /// + /// The name of this rule + public string GetName() + { + return string.Format(CultureInfo.CurrentCulture, Strings.NameSpaceFormat, GetSourceName(), Strings.AvoidShouldContinueWithoutForceName); + } + + /// + /// GetCommonName: Retrieves the common name of this rule. + /// + /// The common name of this rule + public string GetCommonName() + { + return string.Format(CultureInfo.CurrentCulture, Strings.AvoidShouldContinueWithoutForceCommonName); + } + + /// + /// GetDescription: Retrieves the description of this rule. + /// + /// The description of this rule + public string GetDescription() + { + return string.Format(CultureInfo.CurrentCulture, Strings.AvoidShouldContinueWithoutForceDescription); + } + + /// + /// GetSourceType: Retrieves the type of the rule: builtin, managed or module. + /// + public SourceType GetSourceType() + { + return SourceType.Builtin; + } + + /// + /// GetSourceName: Retrieves the module/assembly name the rule is from. + /// + public string GetSourceName() + { + return string.Format(CultureInfo.CurrentCulture, Strings.SourceName); + } + } +} diff --git a/Rules/AvoidUserNameAndPasswordParams.cs b/Rules/AvoidUserNameAndPasswordParams.cs index 10d6f4ef6..e3d1fc4c7 100644 --- a/Rules/AvoidUserNameAndPasswordParams.cs +++ b/Rules/AvoidUserNameAndPasswordParams.cs @@ -16,11 +16,11 @@ namespace Microsoft.Windows.Powershell.ScriptAnalyzer.BuiltinRules { /// - /// AvoidUserNameAndPasswordParams: Check that a function does not use both username and password + /// AvoidUsernameAndPasswordParams: Check that a function does not use both username and password /// parameters. /// [Export(typeof(IScriptRule))] - public class AvoidUserNameAndPasswordParams : IScriptRule + public class AvoidUsernameAndPasswordParams : IScriptRule { /// /// AnalyzeScript: Check that a function does not use both username @@ -77,8 +77,8 @@ public IEnumerable AnalyzeScript(Ast ast, string fileName) if (hasUserName && hasPwd) { yield return new DiagnosticRecord( - String.Format(CultureInfo.CurrentCulture, Strings.AvoidUserNameAndPasswordParamsError, funcAst.Name), - funcAst.Extent, GetName(), DiagnosticSeverity.Warning, fileName); + String.Format(CultureInfo.CurrentCulture, Strings.AvoidUsernameAndPasswordParamsError, funcAst.Name), + funcAst.Extent, GetName(), DiagnosticSeverity.Error, fileName); } } } @@ -89,7 +89,7 @@ public IEnumerable AnalyzeScript(Ast ast, string fileName) /// The name of this rule public string GetName() { - return string.Format(CultureInfo.CurrentCulture, Strings.NameSpaceFormat, GetSourceName(), Strings.AvoidUserNameAndPasswordParamsName); + return string.Format(CultureInfo.CurrentCulture, Strings.NameSpaceFormat, GetSourceName(), Strings.AvoidUsernameAndPasswordParamsName); } /// @@ -98,7 +98,7 @@ public string GetName() /// The common name of this rule public string GetCommonName() { - return string.Format(CultureInfo.CurrentCulture, Strings.AvoidUserNameAndPasswordParamsCommonName); + return string.Format(CultureInfo.CurrentCulture, Strings.AvoidUsernameAndPasswordParamsCommonName); } /// @@ -107,7 +107,7 @@ public string GetCommonName() /// The description of this rule public string GetDescription() { - return string.Format(CultureInfo.CurrentCulture, Strings.AvoidUserNameAndPasswordParamsDescription); + return string.Format(CultureInfo.CurrentCulture, Strings.AvoidUsernameAndPasswordParamsDescription); } /// diff --git a/Rules/ScriptAnalyzerBuiltinRules.csproj b/Rules/ScriptAnalyzerBuiltinRules.csproj index bb3955792..e1e90d498 100644 --- a/Rules/ScriptAnalyzerBuiltinRules.csproj +++ b/Rules/ScriptAnalyzerBuiltinRules.csproj @@ -58,7 +58,7 @@ - + @@ -73,6 +73,11 @@ + + True + True + Strings.resx + @@ -82,17 +87,12 @@ - - True - True - Strings.resx - Designer ResXFileCodeGenerator - Strings.cs + Strings.Designer.cs diff --git a/Rules/Strings.cs b/Rules/Strings.Designer.cs similarity index 96% rename from Rules/Strings.cs rename to Rules/Strings.Designer.cs index 6c18a9ec1..ebccf485e 100644 --- a/Rules/Strings.cs +++ b/Rules/Strings.Designer.cs @@ -214,38 +214,38 @@ internal static string AvoidInvokingEmptyMembersName { } /// - /// Looks up a localized string similar to Avoid Using ShouldContinue Or ShouldProcess Without Boolean Force Parameter. + /// Looks up a localized string similar to Avoid Using ShouldContinue Without Boolean Force Parameter. /// - internal static string AvoidShouldContinueShouldProcessWithoutForceCommonName { + internal static string AvoidShouldContinueWithoutForceCommonName { get { - return ResourceManager.GetString("AvoidShouldContinueShouldProcessWithoutForceCommonName", resourceCulture); + return ResourceManager.GetString("AvoidShouldContinueWithoutForceCommonName", resourceCulture); } } /// - /// Looks up a localized string similar to Functions that use ShouldContinue or ShouldProcess should have a boolean force parameter to allow user to bypass it.. + /// Looks up a localized string similar to Functions that use ShouldContinue should have a boolean force parameter to allow user to bypass it.. /// - internal static string AvoidShouldContinueShouldProcessWithoutForceDescription { + internal static string AvoidShouldContinueWithoutForceDescription { get { - return ResourceManager.GetString("AvoidShouldContinueShouldProcessWithoutForceDescription", resourceCulture); + return ResourceManager.GetString("AvoidShouldContinueWithoutForceDescription", resourceCulture); } } /// - /// Looks up a localized string similar to Function '{0}' in file '{1}' uses ShouldContinue or ShouldProcess but does not have a boolean force parameter. The force parameter will allow users of the script to bypass ShouldContinue prompt. + /// Looks up a localized string similar to Function '{0}' in file '{1}' uses ShouldContinue but does not have a boolean force parameter. The force parameter will allow users of the script to bypass ShouldContinue prompt. /// - internal static string AvoidShouldContinueShouldProcessWithoutForceError { + internal static string AvoidShouldContinueWithoutForceError { get { - return ResourceManager.GetString("AvoidShouldContinueShouldProcessWithoutForceError", resourceCulture); + return ResourceManager.GetString("AvoidShouldContinueWithoutForceError", resourceCulture); } } /// - /// Looks up a localized string similar to AvoidShouldContinueShouldProcessWithoutForce. + /// Looks up a localized string similar to AvoidShouldContinueWithoutForce. /// - internal static string AvoidShouldContinueShouldProcessWithoutForceName { + internal static string AvoidShouldContinueWithoutForceName { get { - return ResourceManager.GetString("AvoidShouldContinueShouldProcessWithoutForceName", resourceCulture); + return ResourceManager.GetString("AvoidShouldContinueWithoutForceName", resourceCulture); } } @@ -360,36 +360,36 @@ internal static string AvoidUnloadableModuleName { /// /// Looks up a localized string similar to Avoid Using Username and Password Parameters. /// - internal static string AvoidUserNameAndPasswordParamsCommonName { + internal static string AvoidUsernameAndPasswordParamsCommonName { get { - return ResourceManager.GetString("AvoidUserNameAndPasswordParamsCommonName", resourceCulture); + return ResourceManager.GetString("AvoidUsernameAndPasswordParamsCommonName", resourceCulture); } } /// /// Looks up a localized string similar to Functions should only take in a credential parameter of type PSCredential instead of username and password parameters.. /// - internal static string AvoidUserNameAndPasswordParamsDescription { + internal static string AvoidUsernameAndPasswordParamsDescription { get { - return ResourceManager.GetString("AvoidUserNameAndPasswordParamsDescription", resourceCulture); + return ResourceManager.GetString("AvoidUsernameAndPasswordParamsDescription", resourceCulture); } } /// /// Looks up a localized string similar to Function '{0}' has both username and password parameters. A credential parameter of type PSCredential should be used.. /// - internal static string AvoidUserNameAndPasswordParamsError { + internal static string AvoidUsernameAndPasswordParamsError { get { - return ResourceManager.GetString("AvoidUserNameAndPasswordParamsError", resourceCulture); + return ResourceManager.GetString("AvoidUsernameAndPasswordParamsError", resourceCulture); } } /// /// Looks up a localized string similar to AvoidUsingUserNameAndPassWordParams. /// - internal static string AvoidUserNameAndPasswordParamsName { + internal static string AvoidUsernameAndPasswordParamsName { get { - return ResourceManager.GetString("AvoidUserNameAndPasswordParamsName", resourceCulture); + return ResourceManager.GetString("AvoidUsernameAndPasswordParamsName", resourceCulture); } } @@ -1357,82 +1357,74 @@ internal static string UseDeclaredVarsMoreThanAssignmentsName { } /// - /// Looks up a localized string similar to Use Identical Parameters For DSC Test and Set Functions. + /// Looks up a localized string similar to Use identical mandatory parameters for DSC Get/Test/Set TargetResource functions. /// - internal static string UseIdenticalParametersDSCCommonName { + internal static string UseIdenticalMandatoryParametersDSCCommonName { get { - return ResourceManager.GetString("UseIdenticalParametersDSCCommonName", resourceCulture); + return ResourceManager.GetString("UseIdenticalMandatoryParametersDSCCommonName", resourceCulture); } } /// - /// Looks up a localized string similar to The Test and Set-TargetResource functions of DSC Resource must have the same parameters.. + /// Looks up a localized string similar to The Get/Test/Set TargetResource functions of DSC resource must have the same mandatory parameters.. /// - internal static string UseIdenticalParametersDSCDescription { + internal static string UseIdenticalMandatoryParametersDSCDescription { get { - return ResourceManager.GetString("UseIdenticalParametersDSCDescription", resourceCulture); + return ResourceManager.GetString("UseIdenticalMandatoryParametersDSCDescription", resourceCulture); } } /// - /// Looks up a localized string similar to The Test and Set-TargetResource functions of DSC Resource must have the same parameters.. + /// Looks up a localized string similar to The mandatory parameter '{0}' is not present in '{1}' DSC resource function(s).. /// - internal static string UseIdenticalParametersDSCError { + internal static string UseIdenticalMandatoryParametersDSCError { get { - return ResourceManager.GetString("UseIdenticalParametersDSCError", resourceCulture); + return ResourceManager.GetString("UseIdenticalMandatoryParametersDSCError", resourceCulture); } } /// - /// Looks up a localized string similar to UseIdenticalParametersForDSC. + /// Looks up a localized string similar to UseIdenticalMandatoryParametersForDSC. /// - internal static string UseIdenticalParametersDSCName { + internal static string UseIdenticalMandatoryParametersDSCName { get { - return ResourceManager.GetString("UseIdenticalParametersDSCName", resourceCulture); + return ResourceManager.GetString("UseIdenticalMandatoryParametersDSCName", resourceCulture); } } - + /// - /// Looks up a localized string similar to the Get/Test/Set TargetResource functions of DSC Resource must have the mandatory same parameters. + /// Looks up a localized string similar to Use Identical Parameters For DSC Test and Set Functions. /// - internal static string UseIdenticalMandatoryParametersDSCCommonName - { - get - { - return ResourceManager.GetString("UseIdenticalMandatoryParametersDSCCommonName", resourceCulture); + internal static string UseIdenticalParametersDSCCommonName { + get { + return ResourceManager.GetString("UseIdenticalParametersDSCCommonName", resourceCulture); } } - + /// - /// Looks up a localized string similar to the Get/Test/Set TargetResource functions of DSC Resource must have the mandatory same parameters. + /// Looks up a localized string similar to The Test and Set-TargetResource functions of DSC Resource must have the same parameters.. /// - internal static string UseIdenticalMandatoryParametersDSCDescription - { - get - { - return ResourceManager.GetString("UseIdenticalMandatoryParametersDSCDescription", resourceCulture); + internal static string UseIdenticalParametersDSCDescription { + get { + return ResourceManager.GetString("UseIdenticalParametersDSCDescription", resourceCulture); } } - + /// - /// Looks up a localized string similar to the Get/Test/Set TargetResource functions of DSC Resource must have the mandatory same parameters. + /// Looks up a localized string similar to The Test and Set-TargetResource functions of DSC Resource must have the same parameters.. /// - internal static string UseIdenticalMandatoryParametersDSCError - { - get - { - return ResourceManager.GetString("UseIdenticalMandatoryParametersDSCError", resourceCulture); + internal static string UseIdenticalParametersDSCError { + get { + return ResourceManager.GetString("UseIdenticalParametersDSCError", resourceCulture); } } - + /// - /// Looks up a localized string similar to UseIdenticalMandatoryParametersForDSC. + /// Looks up a localized string similar to UseIdenticalParametersForDSC. /// - internal static string UseIdenticalMandatoryParametersDSCName - { - get - { - return ResourceManager.GetString("UseIdenticalMandatoryParametersDSCName", resourceCulture); + internal static string UseIdenticalParametersDSCName { + get { + return ResourceManager.GetString("UseIdenticalParametersDSCName", resourceCulture); } } diff --git a/Rules/Strings.resx b/Rules/Strings.resx index c172d193d..3f4cf7072 100644 --- a/Rules/Strings.resx +++ b/Rules/Strings.resx @@ -342,14 +342,14 @@ Switch Parameters Should Not Default To True - - Functions that use ShouldContinue or ShouldProcess should have a boolean force parameter to allow user to bypass it. + + Functions that use ShouldContinue should have a boolean force parameter to allow user to bypass it. - - Function '{0}' in file '{1}' uses ShouldContinue or ShouldProcess but does not have a boolean force parameter. The force parameter will allow users of the script to bypass ShouldContinue prompt + + Function '{0}' in file '{1}' uses ShouldContinue but does not have a boolean force parameter. The force parameter will allow users of the script to bypass ShouldContinue prompt - - Avoid Using ShouldContinue Or ShouldProcess Without Boolean Force Parameter + + Avoid Using ShouldContinue Without Boolean Force Parameter Using Clear-Host is not recommended because the cmdlet may not work in some hosts or there may even be no hosts at all. @@ -390,8 +390,8 @@ AvoidGlobalVars - - AvoidShouldContinueShouldProcessWithoutForce + + AvoidShouldContinueWithoutForce AvoidTrapStatement @@ -510,16 +510,16 @@ UseTypeAtVariableAssignment - + Avoid Using Username and Password Parameters - + Functions should only take in a credential parameter of type PSCredential instead of username and password parameters. - + Function '{0}' has both username and password parameters. A credential parameter of type PSCredential should be used. - + AvoidUsingUserNameAndPassWordParams