diff --git a/Rules/AvoidUsingDeprecatedManifestFields.cs b/Rules/AvoidUsingDeprecatedManifestFields.cs new file mode 100644 index 000000000..8e20179cd --- /dev/null +++ b/Rules/AvoidUsingDeprecatedManifestFields.cs @@ -0,0 +1,132 @@ +// +// Copyright (c) Microsoft Corporation. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +using System; +using System.Collections.Generic; +using System.Management.Automation.Language; +using System.Management.Automation; +using Microsoft.Windows.Powershell.ScriptAnalyzer.Generic; +using System.ComponentModel.Composition; +using System.Globalization; + +namespace Microsoft.Windows.Powershell.ScriptAnalyzer.BuiltinRules +{ + /// + /// AvoidUsingDeprecatedManifestFields: Run Test Module Manifest to check that no deprecated fields are being used. + /// + [Export(typeof(IScriptRule))] + public class AvoidUsingDeprecatedManifestFields : IScriptRule + { + /// + /// AnalyzeScript: Run Test Module Manifest to check that no deprecated fields are being used. + /// + /// The script's ast + /// The script's file name + /// A List of diagnostic results of this rule + public IEnumerable AnalyzeScript(Ast ast, string fileName) + { + if (ast == null) + { + throw new ArgumentNullException(Strings.NullAstErrorMessage); + } + + if (String.Equals(System.IO.Path.GetExtension(fileName), ".psd1", StringComparison.OrdinalIgnoreCase)) + { + var ps = System.Management.Automation.PowerShell.Create(RunspaceMode.CurrentRunspace); + IEnumerable result = null; + try + { + ps.AddCommand("Test-ModuleManifest"); + ps.AddParameter("Path", fileName); + + // Suppress warnings emitted during the execution of Test-ModuleManifest + // ModuleManifest rule must catch any violations (warnings/errors) and generate DiagnosticRecord(s) + ps.AddParameter("WarningAction", ActionPreference.SilentlyContinue); + ps.AddParameter("WarningVariable", "Message"); + ps.AddScript("$Message"); + result = ps.Invoke(); + + } + catch + {} + + if (result != null) + { + foreach (var warning in result) + { + if (warning.BaseObject != null) + { + yield return + new DiagnosticRecord( + String.Format(CultureInfo.CurrentCulture, warning.BaseObject.ToString()), ast.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.AvoidUsingDeprecatedManifestFieldsName); + } + + /// + /// GetCommonName: Retrieves the common name of this rule. + /// + /// The common name of this rule + public string GetCommonName() + { + return String.Format(CultureInfo.CurrentCulture, Strings.AvoidUsingDeprecatedManifestFieldsCommonName); + } + + /// + /// GetDescription: Retrieves the description of this rule. + /// + /// The description of this rule + public string GetDescription() + { + return String.Format(CultureInfo.CurrentCulture, Strings.AvoidUsingDeprecatedManifestFieldsDescription); + } + + /// + /// Method: Retrieves the type of the rule: builtin, managed or module. + /// + public SourceType GetSourceType() + { + return SourceType.Builtin; + } + + /// + /// GetSeverity: Retrieves the severity of the rule: error, warning of information. + /// + /// + public RuleSeverity GetSeverity() + { + return RuleSeverity.Warning; + } + + /// + /// Method: Retrieves the module/assembly name the rule is from. + /// + public string GetSourceName() + { + return string.Format(CultureInfo.CurrentCulture, Strings.SourceName); + } + } +} diff --git a/Rules/ScriptAnalyzerBuiltinRules.csproj b/Rules/ScriptAnalyzerBuiltinRules.csproj index 9f553cb06..087930117 100644 --- a/Rules/ScriptAnalyzerBuiltinRules.csproj +++ b/Rules/ScriptAnalyzerBuiltinRules.csproj @@ -59,6 +59,7 @@ + diff --git a/Rules/Strings.Designer.cs b/Rules/Strings.Designer.cs index 3f8180b6c..00f24aa6f 100644 --- a/Rules/Strings.Designer.cs +++ b/Rules/Strings.Designer.cs @@ -1,7 +1,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34209 +// Runtime Version:4.0.30319.35317 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -510,6 +510,33 @@ internal static string AvoidUsingConvertToSecureStringWithPlainTextName { } } + /// + /// Looks up a localized string similar to Avoid Using Deprecated Manifest Fields. + /// + internal static string AvoidUsingDeprecatedManifestFieldsCommonName { + get { + return ResourceManager.GetString("AvoidUsingDeprecatedManifestFieldsCommonName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to "ModuleToProcess" is obsolete in the latest PowerShell version. Please update with the latest field "RootModule" in manifest files to avoid PowerShell version inconsistency.. + /// + internal static string AvoidUsingDeprecatedManifestFieldsDescription { + get { + return ResourceManager.GetString("AvoidUsingDeprecatedManifestFieldsDescription", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to AvoidUsingDeprecatedManifestFields. + /// + internal static string AvoidUsingDeprecatedManifestFieldsName { + get { + return ResourceManager.GetString("AvoidUsingDeprecatedManifestFieldsName", resourceCulture); + } + } + /// /// Looks up a localized string similar to Avoid Using Empty Catch Block. /// @@ -1114,7 +1141,7 @@ internal static string ProvideDefaultParameterValueCommonName { } /// - /// Looks up a localized string similar to Parameters must have a default value. To fix a violation of this rule, please specify a default value for parameters. + /// Looks up a localized string similar to Parameters must have a default value. To fix a violation of this rule, please specify a default value for all parameters. /// internal static string ProvideDefaultParameterValueDescription { get { @@ -1123,7 +1150,7 @@ internal static string ProvideDefaultParameterValueDescription { } /// - /// Looks up a localized string similar to Parameter '{0}' is not initialized. Parameters must have a default value. To fix a violation of this rule, please specify a default value for parameters. + /// Looks up a localized string similar to Parameter '{0}' is not initialized. Parameters must have a default value. To fix a violation of this rule, please specify a default value for all parameters. /// internal static string ProvideDefaultParameterValueError { get { diff --git a/Rules/Strings.resx b/Rules/Strings.resx index da0010853..7686518a9 100644 --- a/Rules/Strings.resx +++ b/Rules/Strings.resx @@ -726,4 +726,13 @@ ProvideDefaultParameterValue + + Avoid Using Deprecated Manifest Fields + + + "ModuleToProcess" is obsolete in the latest PowerShell version. Please update with the latest field "RootModule" in manifest files to avoid PowerShell version inconsistency. + + + AvoidUsingDeprecatedManifestFields + \ No newline at end of file diff --git a/Tests/Rules/AvoidUsingDeprecatedManifestFields.tests.ps1 b/Tests/Rules/AvoidUsingDeprecatedManifestFields.tests.ps1 new file mode 100644 index 000000000..f5729024b --- /dev/null +++ b/Tests/Rules/AvoidUsingDeprecatedManifestFields.tests.ps1 @@ -0,0 +1,19 @@ +Import-Module PSScriptAnalyzer +$violationName = "PSAvoidUsingDeprecatedManifestFields" +$directory = Split-Path -Parent $MyInvocation.MyCommand.Path +$violations = Invoke-ScriptAnalyzer $directory\TestBadModule\TestDeprecatedManifestFields.psd1 | Where-Object {$_.RuleName -eq $violationName} +$noViolations = Invoke-ScriptAnalyzer $directory\TestGoodModule\TestGoodModule.psd1 | Where-Object {$_.RuleName -eq $violationName} + +Describe "AvoidUsingDeprecatedManifestFields" { + Context "When there are violations" { + It "has 1 violations" { + $violations.Count | Should Be 1 + } + } + + Context "When there are no violations" { + It "returns no violations" { + $noViolations.Count | Should Be 0 + } + } +} \ No newline at end of file diff --git a/Tests/Rules/TestBadModule/TestBadModule.psd1 b/Tests/Rules/TestBadModule/TestBadModule.psd1 index 44d52f161..b8d7bea6c 100644 Binary files a/Tests/Rules/TestBadModule/TestBadModule.psd1 and b/Tests/Rules/TestBadModule/TestBadModule.psd1 differ diff --git a/Tests/Rules/TestBadModule/TestDeprecatedManifestFields.psd1 b/Tests/Rules/TestBadModule/TestDeprecatedManifestFields.psd1 new file mode 100644 index 000000000..768d5454e --- /dev/null +++ b/Tests/Rules/TestBadModule/TestDeprecatedManifestFields.psd1 @@ -0,0 +1,120 @@ +# +# Module manifest for module 'Deprecated Module manifest fields" +# +# Generated by: Microsoft PowerShell Team +# +# Generated on: 5/18/2015 +# + +@{ + +# Script module or binary module file associated with this manifest. +ModuleToProcess ='psscriptanalyzer' + +# Version number of this module. +ModuleVersion = '1.0' + +# ID used to uniquely identify this module +GUID = 'a9f79c02-4503-4300-a022-5e8c01f3449f' + +# Author of this module +Author = '' + +# Company or vendor of this module +CompanyName = '' + +# Copyright statement for this module +Copyright = '(c) 2015 Microsoft. All rights reserved.' + +# Description of the functionality provided by this module +# Description = '' + +# Minimum version of the Windows PowerShell engine required by this module +# PowerShellVersion = '' + +# Name of the Windows PowerShell host required by this module +# PowerShellHostName = '' + +# Minimum version of the Windows PowerShell host required by this module +# PowerShellHostVersion = '' + +# Minimum version of Microsoft .NET Framework required by this module +# DotNetFrameworkVersion = '' + +# Minimum version of the common language runtime (CLR) required by this module +# CLRVersion = '' + +# Processor architecture (None, X86, Amd64) required by this module +# ProcessorArchitecture = '' + +# Modules that must be imported into the global environment prior to importing this module +# RequiredModules = @() + +# Assemblies that must be loaded prior to importing this module +# RequiredAssemblies = @() + +# Script files (.ps1) that are run in the caller's environment prior to importing this module. +# ScriptsToProcess = @() + +# Type files (.ps1xml) to be loaded when importing this module +# TypesToProcess = @() + +# Format files (.ps1xml) to be loaded when importing this module +# FormatsToProcess = @() + +# Modules to import as nested modules of the module specified in RootModule/ModuleToProcess +# NestedModules = @() + +# Functions to export from this module +FunctionsToExport = '*' + +# Cmdlets to export from this module +CmdletsToExport = '*' + +# Variables to export from this module +VariablesToExport = '*' + +# Aliases to export from this module +AliasesToExport = '*' + +# DSC resources to export from this module +# DscResourcesToExport = @() + +# List of all modules packaged with this module +# ModuleList = @() + +# List of all files packaged with this module +# FileList = @() + +# Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable +#with additional module metadata used by PowerShell. +PrivateData = @{ + + PSData = @{ + + # Tags applied to this module. These help with module discovery in online galleries. + # Tags = @() + + # A URL to the license for this module. + # LicenseUri = '' + + # A URL to the main website for this project. + # ProjectUri = '' + + # A URL to an icon representing this module. + # IconUri = '' + + # ReleaseNotes of this module + # ReleaseNotes = '' + + } # End of PSData hashtable + +} # End of PrivateData hashtable + +# HelpInfo URI of this module +# HelpInfoURI = '' + +# Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix. +# DefaultCommandPrefix = '' + +} \ No newline at end of file