diff --git a/Engine/Extensions.cs b/Engine/Extensions.cs
index 1db10a2b6..a4698e655 100644
--- a/Engine/Extensions.cs
+++ b/Engine/Extensions.cs
@@ -30,6 +30,18 @@ public static Range ToRange(this IScriptExtent extent)
extent.EndColumnNumber);
}
+ ///
+ /// Get the parameter Asts from a function definition Ast.
+ ///
+ /// If not parameters are found, return null.
+ ///
+ public static IEnumerable GetParameterAsts(
+ this FunctionDefinitionAst functionDefinitionAst)
+ {
+ ParamBlockAst paramBlockAst;
+ return functionDefinitionAst.GetParameterAsts(out paramBlockAst);
+ }
+
///
/// Get the parameter Asts from a function definition Ast.
///
@@ -41,6 +53,8 @@ public static IEnumerable GetParameterAsts(
this FunctionDefinitionAst functionDefinitionAst,
out ParamBlockAst paramBlockAst)
{
+ // todo instead of returning null return an empty enumerator if no parameter is found
+ // this removes the burden from the user for null checking.
paramBlockAst = null;
if (functionDefinitionAst.Parameters != null)
{
@@ -114,6 +128,16 @@ public static NamedAttributeArgumentAst GetSupportsShouldProcessAst(this Attribu
return null;
}
+
+ ///
+ /// Return the boolean value of a named attribute argument.
+ ///
+ public static bool GetValue(this NamedAttributeArgumentAst attrAst)
+ {
+ ExpressionAst argumentAst;
+ return attrAst.GetValue(out argumentAst);
+ }
+
///
/// Return the boolean value of a named attribute argument.
///
diff --git a/RuleDocumentation/UseIdenticalMandatoryParametersForDSC.md b/RuleDocumentation/UseIdenticalMandatoryParametersForDSC.md
index 04ae5c6bb..053925f16 100644
--- a/RuleDocumentation/UseIdenticalMandatoryParametersForDSC.md
+++ b/RuleDocumentation/UseIdenticalMandatoryParametersForDSC.md
@@ -4,50 +4,74 @@
## Description
-The `Get-TargetResource`, `Test-TargetResource` and `Set-TargetResource` functions of DSC Resource must have the same mandatory parameters.
+For script based DSC resources, if a property is declared with attributes `Key` of `Required` in a mof file, then is should be present as a mandatory parameter in the corresponding `Get-TargetResource`, `Set-TargetResource` and `Test-TargetResource` functions.
## How
-Correct the mandatory parameters for the functions in DSC resource.
+Make sure all the properties with `Key` and `Required` attributes have equivalent mandatory parameters in the `Get/Set/Test` functions.
## Example
+Consider the following `mof` file.
+
+```powershell
+class WaitForAny : OMI_BaseResource
+{
+ [key, Description("Name of Resource on remote machine")]
+ string Name;
+
+ [required, Description("List of remote machines")]
+ string NodeName[];
+};
+```
+
### Wrong
``` PowerShell
function Get-TargetResource
{
- [OutputType([Hashtable])]
+ [CmdletBinding()]
param
(
- [parameter(Mandatory = $true)]
+ [Parameter(Mandatory = $true)]
+ [ValidateNotNullOrEmpty()]
[String]
- $Name
+ $Message
)
- ...
}
function Set-TargetResource
{
+ [CmdletBinding()]
param
(
- [parameter(Mandatory = $true)]
+ [Parameter(Mandatory = $true)]
+ [ValidateNotNullOrEmpty()]
+ [String]
+ $Message,
+
+ [Parameter(Mandatory = $true)]
+ [ValidateNotNullOrEmpty()]
[String]
- $TargetName
+ $Name
)
- ...
}
function Test-TargetResource
{
- [OutputType([System.Boolean])]
+ [CmdletBinding()]
param
(
- [parameter(Mandatory = $true)]
+ [Parameter(Mandatory = $true)]
+ [ValidateNotNullOrEmpty()]
+ [String]
+ $Message,
+
+ [Parameter(Mandatory = $true)]
+ [ValidateNotNullOrEmpty()]
[String]
$Name
)
- ...
}
```
@@ -56,36 +80,52 @@ function Test-TargetResource
``` PowerShell
function Get-TargetResource
{
- [OutputType([Hashtable])]
+ [CmdletBinding()]
param
(
- [parameter(Mandatory = $true)]
+ [Parameter(Mandatory = $true)]
+ [ValidateNotNullOrEmpty()]
+ [String]
+ $Message,
+
+ [Parameter(Mandatory = $true)]
+ [ValidateNotNullOrEmpty()]
[String]
$Name
)
- ...
}
function Set-TargetResource
{
+ [CmdletBinding()]
param
(
- [parameter(Mandatory = $true)]
+ [Parameter(Mandatory = $true)]
+ [ValidateNotNullOrEmpty()]
+ [String]
+ $Message,
+
+ [Parameter(Mandatory = $true)]
+ [ValidateNotNullOrEmpty()]
[String]
$Name
)
- ...
}
function Test-TargetResource
{
- [OutputType([System.Boolean])]
+ [CmdletBinding()]
param
(
- [parameter(Mandatory = $true)]
+ [Parameter(Mandatory = $true)]
+ [ValidateNotNullOrEmpty()]
+ [String]
+ $Message,
+
+ [Parameter(Mandatory = $true)]
+ [ValidateNotNullOrEmpty()]
[String]
$Name
)
- ...
}
```
diff --git a/Rules/Strings.resx b/Rules/Strings.resx
index 87e87813f..f954248dc 100644
--- a/Rules/Strings.resx
+++ b/Rules/Strings.resx
@@ -619,7 +619,7 @@
The Get/Test/Set TargetResource functions of DSC resource must have the same mandatory parameters.
- The mandatory parameter '{0}' is not present in '{1}' DSC resource function(s).
+ The '{0}' parameter '{1}' is not present in '{2}' DSC resource function(s).
UseIdenticalMandatoryParametersForDSC
diff --git a/Rules/UseIdenticalMandatoryParametersDSC.cs b/Rules/UseIdenticalMandatoryParametersDSC.cs
index 396770566..60172a58b 100644
--- a/Rules/UseIdenticalMandatoryParametersDSC.cs
+++ b/Rules/UseIdenticalMandatoryParametersDSC.cs
@@ -12,13 +12,17 @@
using System;
using System.Collections.Generic;
-using System.Linq;
-using System.Management.Automation.Language;
-using Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic;
#if !CORECLR
using System.ComponentModel.Composition;
#endif
using System.Globalization;
+using System.IO;
+using System.Linq;
+using System.Management.Automation.Language;
+using Microsoft.Management.Infrastructure;
+using Microsoft.PowerShell.DesiredStateConfiguration.Internal;
+using Microsoft.Windows.PowerShell.ScriptAnalyzer.Extensions;
+using Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic;
namespace Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules
{
@@ -26,11 +30,17 @@ namespace Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules
/// UseIdenticalMandatoryParametersDSC: Check that the Get/Test/Set TargetResource
/// have identical mandatory parameters.
///
- #if !CORECLR
-[Export(typeof(IDSCResourceRule))]
+#if !CORECLR
+ [Export(typeof(IDSCResourceRule))]
#endif
public class UseIdenticalMandatoryParametersDSC : IDSCResourceRule
{
+ private bool isDSCClassCacheInitialized = false;
+ private Ast ast;
+ private string fileName;
+ private IDictionary propAttrDict;
+ private IEnumerable resourceFunctions;
+
///
/// AnalyzeDSCResource: Analyzes given DSC Resource
///
@@ -39,74 +49,53 @@ public class UseIdenticalMandatoryParametersDSC : IDSCResourceRule
/// The results of the analysis
public IEnumerable AnalyzeDSCResource(Ast ast, string fileName)
{
- if (ast == null) throw new ArgumentNullException(Strings.NullAstErrorMessage);
+ if (ast == null)
+ {
+ throw new ArgumentNullException(Strings.NullAstErrorMessage);
+ }
- // Expected TargetResource functions in the DSC Resource module
- List expectedTargetResourceFunctionNames = new List(new string[] { "Set-TargetResource", "Test-TargetResource", "Get-TargetResource" });
+ if (fileName == null)
+ {
+ throw new ArgumentNullException(nameof(fileName));
+ }
- IEnumerable functionDefinitionAsts = Helper.Instance.DscResourceFunctions(ast);
+ // Get the keys in the corresponding mof file
+ this.ast = ast;
+ this.fileName = fileName;
+ this.propAttrDict = GetKeys(fileName);
+ this.resourceFunctions = Helper.Instance.DscResourceFunctions(ast)
+ .Cast()
+ .ToArray();
- // Dictionary to keep track of Mandatory parameters and their presence in Get/Test/Set TargetResource cmdlets
- Dictionary> mandatoryParameters = new Dictionary>(StringComparer.OrdinalIgnoreCase);
+ var funcManParamMap = resourceFunctions
+ .ToDictionary(
+ f => f.Name,
+ f => Tuple.Create(
+ f,
+ GetMandatoryParameters(f)
+ .Select(p => p.Name.VariablePath.UserPath)
+ .ToArray()));
// Loop through Set/Test/Get TargetResource DSC cmdlets
- foreach (FunctionDefinitionAst functionDefinitionAst in functionDefinitionAsts)
+ foreach (var kvp in funcManParamMap)
{
- IEnumerable funcParamAsts = functionDefinitionAst.FindAll(item => item is ParameterAst, true);
-
- // Loop through the parameters for each cmdlet
- foreach (ParameterAst paramAst in funcParamAsts)
+ var functionDefinitionAst = kvp.Value.Item1;
+ var manParams = kvp.Value.Item2;
+ foreach (var key in propAttrDict.Keys.Except(manParams))
{
- // Loop through the attributes for each of those cmdlets
- foreach (var paramAstAttributes in paramAst.Attributes)
- {
- if (paramAstAttributes is AttributeAst)
- {
- var namedArguments = (paramAstAttributes as AttributeAst).NamedArguments;
- if (namedArguments != null)
- {
- // Loop through the named attribute arguments for each parameter
- foreach (NamedAttributeArgumentAst namedArgument in namedArguments)
- {
- // Look for Mandatory parameters
- if (String.Equals(namedArgument.ArgumentName, "mandatory", StringComparison.OrdinalIgnoreCase))
- {
- // Covers Case - [Parameter(Mandatory)] and [Parameter(Mandatory)=$true]
- if (namedArgument.ExpressionOmitted || (!namedArgument.ExpressionOmitted && String.Equals(namedArgument.Argument.Extent.Text, "$true", StringComparison.OrdinalIgnoreCase)))
- {
- if (mandatoryParameters.ContainsKey(paramAst.Name.VariablePath.UserPath))
- {
- mandatoryParameters[paramAst.Name.VariablePath.UserPath].Add(functionDefinitionAst.Name);
- }
- else
- {
- List functionNames = new List();
- functionNames.Add(functionDefinitionAst.Name);
- mandatoryParameters.Add(paramAst.Name.VariablePath.UserPath, functionNames);
- }
- }
- }
- }
- }
- }
- }
+ yield return new DiagnosticRecord(
+ string.Format(
+ CultureInfo.InvariantCulture,
+ Strings.UseIdenticalMandatoryParametersDSCError,
+ propAttrDict[key],
+ key,
+ functionDefinitionAst.Name),
+ Helper.Instance.GetScriptExtentForFunctionName(functionDefinitionAst),
+ GetName(),
+ DiagnosticSeverity.Error,
+ fileName);
}
}
-
- // Get the mandatory parameter names that do not appear in all the DSC Resource cmdlets
- IEnumerable paramNames = mandatoryParameters.Where(x => x.Value.Count < expectedTargetResourceFunctionNames.Count).Select(x => x.Key);
-
- if (paramNames.Count() > 0)
- {
- foreach (string paramName in paramNames)
- {
- List functionsNotContainingParam = expectedTargetResourceFunctionNames.Except(mandatoryParameters[paramName]).ToList();
- yield return new DiagnosticRecord(string.Format(CultureInfo.InvariantCulture, Strings.UseIdenticalMandatoryParametersDSCError, paramName, string.Join(", ", functionsNotContainingParam.ToArray())),
- ast.Extent, GetName(), DiagnosticSeverity.Error, fileName);
- }
-
- }
-
}
///
@@ -117,7 +106,7 @@ public IEnumerable AnalyzeDSCResource(Ast ast, string fileName
///
public IEnumerable AnalyzeDSCClass(Ast ast, string fileName)
{
- // For DSC Class based resource, this rule is N/A, since the Class Properties
+ // For DSC Class based resource, this rule is N/A, since the Class Properties
// are declared only once and available to Get(), Set(), Test() functions
return Enumerable.Empty();
}
@@ -127,7 +116,7 @@ public IEnumerable AnalyzeDSCClass(Ast ast, string fileName)
///
/// The name of this rule
public string GetName()
- {
+ {
return string.Format(CultureInfo.CurrentCulture, Strings.NameSpaceFormat, GetSourceName(), Strings.UseIdenticalMandatoryParametersDSCName);
}
@@ -173,8 +162,146 @@ public string GetSourceName()
{
return string.Format(CultureInfo.CurrentCulture, Strings.DSCSourceName);
}
- }
+ private IEnumerable GetMandatoryParameters(FunctionDefinitionAst functionDefinitionAst)
+ {
+ return functionDefinitionAst.GetParameterAsts()?.Where(IsParameterMandatory) ??
+ Enumerable.Empty();
+ }
+
+ private bool IsParameterMandatory(ParameterAst paramAst)
+ {
+ var attrAsts = from attr in paramAst.Attributes
+ where IsParameterAttribute(attr) && attr is AttributeAst
+ select (AttributeAst)attr;
+
+ return attrAsts.Any(a => a.NamedArguments.Any(IsNamedAttributeArgumentMandatory));
+ }
+
+ private bool IsParameterAttribute(AttributeBaseAst attributeBaseAst)
+ {
+ return attributeBaseAst.TypeName.GetReflectionType().Name.Equals("ParameterAttribute");
+ }
+
+ private bool IsNamedAttributeArgumentMandatory(NamedAttributeArgumentAst namedAttrArgAst)
+ {
+ return namedAttrArgAst.ArgumentName.Equals("mandatory", StringComparison.OrdinalIgnoreCase) &&
+ namedAttrArgAst.GetValue();
+ }
+
+ private IDictionary GetKeys(string fileName)
+ {
+ var moduleInfo = GetModuleInfo(fileName);
+ var emptyDictionary = new Dictionary();
+ if (moduleInfo == null)
+ {
+ return emptyDictionary;
+ }
+
+ var mofFilepath = GetMofFilepath(fileName);
+ if (mofFilepath == null)
+ {
+ return emptyDictionary;
+ }
+
+ var errors = new System.Collections.ObjectModel.Collection();
+ var keys = new List();
+ List cimClasses = null;
+ try
+ {
+ if (!isDSCClassCacheInitialized)
+ {
+ DscClassCache.Initialize();
+ isDSCClassCacheInitialized = true;
+ }
+
+ cimClasses = DscClassCache.ImportClasses(mofFilepath, moduleInfo, errors);
+ }
+ catch
+ {
+ // todo log the error
+ }
+
+ var cimClass = cimClasses?.FirstOrDefault();
+ var cimSuperClassProperties = new HashSet(
+ cimClass?.CimSuperClass.CimClassProperties.Select(p => p.Name) ??
+ Enumerable.Empty());
+
+ return cimClass?
+ .CimClassProperties?
+ .Where(p => (p.Flags.HasFlag(CimFlags.Key) ||
+ p.Flags.HasFlag(CimFlags.Required)) &&
+ !cimSuperClassProperties.Contains(p.Name))
+ .ToDictionary(
+ p => p.Name,
+ p => p.Flags.HasFlag(CimFlags.Key) ?
+ CimFlags.Key.ToString() :
+ CimFlags.Required.ToString()) ??
+ emptyDictionary;
+ }
+
+ private string GetMofFilepath(string filePath)
+ {
+ var mofFilePath = Path.Combine(
+ Path.GetDirectoryName(filePath),
+ Path.GetFileNameWithoutExtension(filePath)) + ".schema.mof";
+
+ return File.Exists(mofFilePath) ? mofFilePath : null;
+ }
+
+ private Tuple GetModuleInfo(string fileName)
+ {
+ var moduleManifest = GetModuleManifest(fileName);
+ if (moduleManifest == null)
+ {
+ return null;
+ }
+
+ var moduleName = Path.GetFileNameWithoutExtension(moduleManifest.Name);
+ Token[] tokens;
+ ParseError[] parseErrors;
+ var ast = Parser.ParseFile(moduleManifest.FullName, out tokens, out parseErrors);
+ if ((parseErrors != null && parseErrors.Length > 0) || ast == null)
+ {
+ return null;
+ }
+
+ var foundAst = ast.Find(x => x is HashtableAst, false);
+ if (foundAst == null)
+ {
+ return null;
+ }
+
+ var moduleVersionKvp = ((HashtableAst)foundAst).KeyValuePairs.FirstOrDefault(t =>
+ {
+ var keyAst = t.Item1 as StringConstantExpressionAst;
+ return keyAst != null &&
+ keyAst.Value.Equals("ModuleVersion", StringComparison.OrdinalIgnoreCase);
+ });
+
+ if (moduleVersionKvp == null)
+ {
+ return null;
+ }
+
+ var valueAst = moduleVersionKvp.Item2.Find(a => a is StringConstantExpressionAst, false);
+ var versionText = valueAst == null ? null : ((StringConstantExpressionAst)valueAst).Value;
+ Version version;
+ Version.TryParse(versionText, out version); // this handles null so no need to check versionText
+ return version == null ? null : Tuple.Create(moduleName, version);
+ }
+
+ private FileInfo GetModuleManifest(string fileName)
+ {
+ return Directory
+ .GetParent(fileName)?
+ .Parent?
+ .Parent?
+ .GetFiles("*.psd1")
+ .Where(f => Helper.IsModuleManifest(f.FullName))
+ .FirstOrDefault();
+ }
+ }
}
diff --git a/Tests/DisabledRules/ProvideVerboseMessage.tests.ps1 b/Tests/DisabledRules/ProvideVerboseMessage.tests.ps1
index 6ae8c639c..78f3d1a27 100644
--- a/Tests/DisabledRules/ProvideVerboseMessage.tests.ps1
+++ b/Tests/DisabledRules/ProvideVerboseMessage.tests.ps1
@@ -3,7 +3,7 @@ $violationMessage = [regex]::Escape("There is no call to Write-Verbose in the fu
$violationName = "PSProvideVerboseMessage"
$directory = Split-Path -Parent $MyInvocation.MyCommand.Path
$violations = Invoke-ScriptAnalyzer $directory\BadCmdlet.ps1 | Where-Object {$_.RuleName -eq $violationName}
-$dscViolations = Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue $directory\DSCResources\MyDscResource\MyDscResource.psm1 | Where-Object {$_.RuleName -eq $violationName}
+$dscViolations = Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue $directory\DSCResourceModule\DSCResources\MyDscResource\MyDscResource.psm1 | Where-Object {$_.RuleName -eq $violationName}
$noViolations = Invoke-ScriptAnalyzer $directory\GoodCmdlet.ps1 | Where-Object {$_.RuleName -eq $violationName}
Describe "ProvideVerboseMessage" {
@@ -26,4 +26,4 @@ Describe "ProvideVerboseMessage" {
$noViolations.Count | Should Be 0
}
}
-}
\ No newline at end of file
+}
diff --git a/Tests/Engine/InvokeScriptAnalyzer.tests.ps1 b/Tests/Engine/InvokeScriptAnalyzer.tests.ps1
index fab8f4bd4..77c5be507 100644
--- a/Tests/Engine/InvokeScriptAnalyzer.tests.ps1
+++ b/Tests/Engine/InvokeScriptAnalyzer.tests.ps1
@@ -321,6 +321,7 @@ Describe "Test Severity" {
It "works for dsc rules" {
$testDataPath = [System.IO.Path]::Combine($(Split-Path $directory -Parent), `
'Rules', `
+ 'DSCResourceModule', `
'DSCResources', `
'MSFT_WaitForAll', `
'MSFT_WaitForAll.psm1')
@@ -398,4 +399,4 @@ Describe "Test CustomizedRulePath" {
}
}
}
-}
\ No newline at end of file
+}
diff --git a/Tests/Engine/ModuleDependencyHandler.tests.ps1 b/Tests/Engine/ModuleDependencyHandler.tests.ps1
index 8a28d5028..166bd01e4 100644
--- a/Tests/Engine/ModuleDependencyHandler.tests.ps1
+++ b/Tests/Engine/ModuleDependencyHandler.tests.ps1
@@ -139,8 +139,9 @@ Describe "Resolve DSC Resource Dependency" {
Context "Invoke-ScriptAnalyzer without switch but with module in temp path" {
$oldEnvVars = Get-Item Env:\* | Sort-Object -Property Key
$moduleName = "MyDscResource"
- $modulePath = Join-Path (Join-Path (Join-Path (Split-Path $directory) "Rules") "DSCResources") $moduleName
- # Save the current environment variables
+ $modulePath = "$(Split-Path $directory)\Rules\DSCResourceModule\DSCResources\$moduleName"
+
+ # Save the current environment variables
$oldLocalAppDataPath = $env:LOCALAPPDATA
$oldTempPath = $env:TEMP
$oldPSModulePath = $env:PSModulePath
@@ -190,4 +191,4 @@ Describe "Resolve DSC Resource Dependency" {
Test-EnvironmentVariables($oldEnvVars)
}
}
-}
\ No newline at end of file
+}
diff --git a/Tests/Rules/AvoidGlobalOrUnitializedVars.tests.ps1 b/Tests/Rules/AvoidGlobalOrUnitializedVars.tests.ps1
index 0c5a20d63..92d396412 100644
--- a/Tests/Rules/AvoidGlobalOrUnitializedVars.tests.ps1
+++ b/Tests/Rules/AvoidGlobalOrUnitializedVars.tests.ps1
@@ -10,7 +10,7 @@ $directory = Split-Path -Parent $MyInvocation.MyCommand.Path
$violations = Invoke-ScriptAnalyzer $directory\AvoidGlobalOrUnitializedVars.ps1
# PSAvoidUninitializedVariable rule has been deprecated
-# $dscResourceViolations = Invoke-ScriptAnalyzer $directory\DSCResources\MSFT_WaitForAny\MSFT_WaitForAny.psm1 | Where-Object {$_.RuleName -eq $nonInitializedName}
+# $dscResourceViolations = Invoke-ScriptAnalyzer $directory\DSCResourceModule\DSCResources\MSFT_WaitForAny\MSFT_WaitForAny.psm1 | Where-Object {$_.RuleName -eq $nonInitializedName}
$globalViolations = $violations | Where-Object {$_.RuleName -eq $globalName}
diff --git a/Tests/Rules/DSCResourceModule/DSCResourceModule.psd1 b/Tests/Rules/DSCResourceModule/DSCResourceModule.psd1
new file mode 100644
index 000000000..192d652f1
--- /dev/null
+++ b/Tests/Rules/DSCResourceModule/DSCResourceModule.psd1
@@ -0,0 +1,123 @@
+#
+# Module manifest for module 'DSCResources'
+#
+# Generated by: kborle
+#
+# Generated on: 6/2/2017
+#
+
+@{
+
+# Script module or binary module file associated with this manifest.
+# RootModule = ''
+
+# Version number of this module.
+ModuleVersion = '1.0'
+
+# Supported PSEditions
+# CompatiblePSEditions = @()
+
+# ID used to uniquely identify this module
+GUID = 'f5e6cc2a-5500-4592-bbe2-ef033754b56f'
+
+# Author of this module
+Author = 'kborle'
+
+# Company or vendor of this module
+CompanyName = 'Unknown'
+
+# Copyright statement for this module
+Copyright = '(c) 2017 kborle. 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. This prerequisite is valid for the PowerShell Desktop edition only.
+# DotNetFrameworkVersion = ''
+
+# Minimum version of the common language runtime (CLR) required by this module. This prerequisite is valid for the PowerShell Desktop edition only.
+# 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, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export.
+FunctionsToExport = @()
+
+# Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export.
+CmdletsToExport = @()
+
+# Variables to export from this module
+VariablesToExport = '*'
+
+# Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export.
+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 = ''
+
+}
+
diff --git a/Tests/Rules/DSCResources/BadDscResource/BadDscResource.psd1 b/Tests/Rules/DSCResourceModule/DSCResources/BadDscResource/BadDscResource.psd1
similarity index 100%
rename from Tests/Rules/DSCResources/BadDscResource/BadDscResource.psd1
rename to Tests/Rules/DSCResourceModule/DSCResources/BadDscResource/BadDscResource.psd1
diff --git a/Tests/Rules/DSCResources/BadDscResource/BadDscResource.psm1 b/Tests/Rules/DSCResourceModule/DSCResources/BadDscResource/BadDscResource.psm1
similarity index 100%
rename from Tests/Rules/DSCResources/BadDscResource/BadDscResource.psm1
rename to Tests/Rules/DSCResourceModule/DSCResources/BadDscResource/BadDscResource.psm1
diff --git a/Tests/Rules/DSCResources/MSFT_WaitForAll/MSFT_WaitForAll.psm1 b/Tests/Rules/DSCResourceModule/DSCResources/MSFT_WaitForAll/MSFT_WaitForAll.psm1
similarity index 100%
rename from Tests/Rules/DSCResources/MSFT_WaitForAll/MSFT_WaitForAll.psm1
rename to Tests/Rules/DSCResourceModule/DSCResources/MSFT_WaitForAll/MSFT_WaitForAll.psm1
diff --git a/Tests/Rules/DSCResourceModule/DSCResources/MSFT_WaitForAll/MSFT_WaitForAll.schema.mof b/Tests/Rules/DSCResourceModule/DSCResources/MSFT_WaitForAll/MSFT_WaitForAll.schema.mof
new file mode 100644
index 000000000..8271cc337
--- /dev/null
+++ b/Tests/Rules/DSCResourceModule/DSCResources/MSFT_WaitForAll/MSFT_WaitForAll.schema.mof
@@ -0,0 +1,26 @@
+#pragma namespace("\\\\.\\root\\microsoft\\windows\\DesiredStateConfiguration")
+
+[ClassVersion("1.0.0"), FriendlyName("WaitForAll")]
+class MSFT_WaitForAll : OMI_BaseResource
+{
+ [key, Description("Name of Resource on remote machine")]
+ string ResourceName;
+
+ [required, Description("List of remote machines")]
+ string NodeName[];
+
+ [required, EmbeddedInstance("MSFT_Credential"), Description("Credential to access all remote machines")]
+ String Credential;
+
+ [write, Description("Time between various retries. Lower bound is 1.")]
+ Uint64 RetryIntervalSec;
+
+ [write, Description("Maximum number of retries to check the state of resource.")]
+ Uint32 RetryCount;
+
+ [write, Description("Number of machines to connect simultaneously. Default is new-cimsession default")]
+ Uint32 ThrottleLimit;
+
+ [read, Description("List of remote machines in desired state.")]
+ String NodesInDesiredState;
+};
diff --git a/Tests/Rules/DSCResources/MSFT_WaitForAll/en-US/MSFT_WaitForAll.schema.mfl b/Tests/Rules/DSCResourceModule/DSCResources/MSFT_WaitForAll/en-US/MSFT_WaitForAll.schema.mfl
similarity index 100%
rename from Tests/Rules/DSCResources/MSFT_WaitForAll/en-US/MSFT_WaitForAll.schema.mfl
rename to Tests/Rules/DSCResourceModule/DSCResources/MSFT_WaitForAll/en-US/MSFT_WaitForAll.schema.mfl
diff --git a/Tests/Rules/DSCResources/MSFT_WaitForAny/MSFT_WaitForAny.psm1 b/Tests/Rules/DSCResourceModule/DSCResources/MSFT_WaitForAny/MSFT_WaitForAny.psm1
similarity index 100%
rename from Tests/Rules/DSCResources/MSFT_WaitForAny/MSFT_WaitForAny.psm1
rename to Tests/Rules/DSCResourceModule/DSCResources/MSFT_WaitForAny/MSFT_WaitForAny.psm1
diff --git a/Tests/Rules/DSCResourceModule/DSCResources/MSFT_WaitForAny/MSFT_WaitForAny.schema.mof b/Tests/Rules/DSCResourceModule/DSCResources/MSFT_WaitForAny/MSFT_WaitForAny.schema.mof
new file mode 100644
index 000000000..fb03a004d
--- /dev/null
+++ b/Tests/Rules/DSCResourceModule/DSCResources/MSFT_WaitForAny/MSFT_WaitForAny.schema.mof
@@ -0,0 +1,27 @@
+#pragma namespace("\\\\.\\root\\microsoft\\windows\\DesiredStateConfiguration")
+
+[ClassVersion("1.0.0"), FriendlyName("WaitForAny")]
+class MSFT_WaitForAny : OMI_BaseResource
+{
+ [key, Description("Name of Resource on remote machine")]
+ string ResourceName;
+
+ [required, Description("List of remote machines")]
+ string NodeName[];
+
+ [required, EmbeddedInstance("MSFT_Credential"), Description("Credential to access all remote machines")]
+ String Credential;
+
+ [write, Description("Time between various retries. Lower bound is 1.")]
+ Uint64 RetryIntervalSec;
+
+ [write, Description("Maximum number of retries to check the state of resource.")]
+ Uint32 RetryCount;
+
+ [write, Description("Number of machines to connect simultaneously. Default is new-cimsession default")]
+ Uint32 ThrottleLimit;
+
+ [read, Description("List of remote machines in desired state.")]
+ String NodesInDesiredState;
+
+};
diff --git a/Tests/Rules/DSCResources/MSFT_WaitForAny/en-US/MSFT_WaitForAny.schema.mfl b/Tests/Rules/DSCResourceModule/DSCResources/MSFT_WaitForAny/en-US/MSFT_WaitForAny.schema.mfl
similarity index 100%
rename from Tests/Rules/DSCResources/MSFT_WaitForAny/en-US/MSFT_WaitForAny.schema.mfl
rename to Tests/Rules/DSCResourceModule/DSCResources/MSFT_WaitForAny/en-US/MSFT_WaitForAny.schema.mfl
diff --git a/Tests/Rules/DSCResourceModule/DSCResources/MSFT_WaitForAnyNoIdenticalMandatoryParameter/MSFT_WaitForAnyNoIdenticalMandatoryParameter.psm1 b/Tests/Rules/DSCResourceModule/DSCResources/MSFT_WaitForAnyNoIdenticalMandatoryParameter/MSFT_WaitForAnyNoIdenticalMandatoryParameter.psm1
new file mode 100644
index 000000000..d2aa631c7
--- /dev/null
+++ b/Tests/Rules/DSCResourceModule/DSCResources/MSFT_WaitForAnyNoIdenticalMandatoryParameter/MSFT_WaitForAnyNoIdenticalMandatoryParameter.psm1
@@ -0,0 +1,161 @@
+#
+# WaitForAny
+#
+
+#
+# The Get-TargetResource cmdlet.
+#
+function Get-TargetResource {
+
+ # This is missing `Key` properties `ResourceName` and `Dummy`
+ param
+ (
+ [parameter(Mandatory)]
+ [ValidateNotNullOrEmpty()]
+ [string[]] $NodeName,
+
+ [parameter(Mandatory)]
+ [ValidateNotNullOrEmpty()]
+ [PSCredential] $Credential,
+
+ [parameter(Mandatory)]
+ $ParamOnlyInGet,
+
+ [ValidateRange(1, [Uint64]::MaxValue)]
+ [Uint64] $RetryIntervalSec = 1,
+
+ [Uint32] $RetryCount = 0,
+
+ [Uint32] $ThrottleLimit = 32 #Powershell New-CimSession default throttle value
+ )
+
+ Write-Verbose "In Get-TargetResource"
+
+ Import-Module $PSScriptRoot\..\..\PSDSCxMachine.psm1
+
+ $b = @{"hash" = "table"}
+
+ if ($true) {
+ return $b;
+ }
+ elseif ($c) {
+ return @{"hash2" = "table2"}
+ }
+ else {
+ # can't determine type of c so error should not be raised as we're trying to be conservative
+ return $c;
+ }
+}
+
+#
+# The Set-TargetResource cmdlet.
+#
+function Set-TargetResource {
+
+ # This is missing `required` property `credential` and `key` property `Dummy`
+ param
+ (
+ [parameter(Mandatory)]
+ [ValidateNotNullOrEmpty()]
+ [string] $ResourceName,
+
+ [parameter(Mandatory)]
+ [ValidateNotNullOrEmpty()]
+ [string[]] $NodeName,
+
+ [parameter(Mandatory)]
+ $ParameterOnlyInSet,
+
+ [ValidateRange(1, [Uint64]::MaxValue)]
+ [Uint64] $RetryIntervalSec = 1,
+
+ [Uint32] $RetryCount = 0,
+
+ [Uint32] $ThrottleLimit = 32 #Powershell New-CimSession default throttle value
+ )
+
+ Write-Verbose "In Set-TargetResource"
+
+ Import-Module $PSScriptRoot\..\..\PSDSCxMachine.psm1
+
+ if ($PSBoundParameters["Verbose"]) {
+ Write-Verbose "Calling xMachine with Verbose parameter"
+
+ PSDSCxMachine\Set-_InternalPSDscXMachineTR `
+ -RemoteResourceId $ResourceName `
+ -RemoteMachine $NodeName `
+ -RemoteCredential $Credential `
+ -MinimalNumberOfMachineInState 1 `
+ -RetryIntervalSec $RetryIntervalSec `
+ -RetryCount $RetryCount `
+ -ThrottleLimit $ThrottleLimit `
+ -Verbose
+ }
+ else {
+ PSDSCxMachine\Set-_InternalPSDscXMachineTR `
+ -RemoteResourceId $ResourceName `
+ -RemoteMachine $NodeName `
+ -RemoteCredential $Credential `
+ -MinimalNumberOfMachineInState 1 `
+ -RetryIntervalSec $RetryIntervalSec `
+ -RetryCount $RetryCount `
+ -ThrottleLimit $ThrottleLimit
+ }
+}
+
+#
+# Test-TargetResource
+#
+#
+function Test-TargetResource {
+
+ # This is missing `key` property `Dummy`
+ param
+ (
+ [parameter(Mandatory)]
+ [ValidateNotNullOrEmpty()]
+ [string] $ResourceName,
+
+ [parameter(Mandatory)]
+ [ValidateNotNullOrEmpty()]
+ [string[]] $NodeName,
+
+ [parameter(Mandatory)]
+ [ValidateNotNullOrEmpty()]
+ [PSCredential] $Credential,
+
+ [parameter(Mandatory)]
+ $ParameterOnlyInTest,
+
+ [ValidateRange(1,[Uint64]::MaxValue)]
+ [Uint64] $RetryIntervalSec = 1,
+
+ [Uint32] $RetryCount = 0,
+
+ [Uint32] $ThrottleLimit = 32 #Powershell New-CimSession default throttle value
+ )
+
+ Write-Verbose "In Test-TargetResource"
+
+ Import-Module $PSScriptRoot\..\..\PSDSCxMachine.psm1
+
+ $a = $true
+ $a
+
+ if ($true) {
+ $false;
+ }
+ elseif ($b) {
+ return $a -or $true
+ }
+ elseif ($c) {
+ return $false;
+ }
+ else {
+ return $true
+ }
+}
+
+
+
+Export-ModuleMember -Function *-TargetResource
diff --git a/Tests/Rules/DSCResourceModule/DSCResources/MSFT_WaitForAnyNoIdenticalMandatoryParameter/MSFT_WaitForAnyNoIdenticalMandatoryParameter.schema.mof b/Tests/Rules/DSCResourceModule/DSCResources/MSFT_WaitForAnyNoIdenticalMandatoryParameter/MSFT_WaitForAnyNoIdenticalMandatoryParameter.schema.mof
new file mode 100644
index 000000000..2c56539c5
--- /dev/null
+++ b/Tests/Rules/DSCResourceModule/DSCResources/MSFT_WaitForAnyNoIdenticalMandatoryParameter/MSFT_WaitForAnyNoIdenticalMandatoryParameter.schema.mof
@@ -0,0 +1,31 @@
+#pragma namespace("\\\\.\\root\\microsoft\\windows\\DesiredStateConfiguration")
+
+[ClassVersion("1.0.0"), FriendlyName("WaitForAny")]
+
+class MSFT_WaitForAnyNoIdenticalMandatoryParameter : OMI_BaseResource
+{
+ [key, Description("Name of Resource on remote machine")]
+ string ResourceName;
+
+ [key, Description("dummy variable")]
+ string Dummy;
+
+ [required, Description("List of remote machines")]
+ string NodeName[];
+
+ [required, EmbeddedInstance("MSFT_Credential"), Description("Credential to access all remote machines")]
+ String Credential;
+
+ [write, Description("Time between various retries. Lower bound is 1.")]
+ Uint64 RetryIntervalSec;
+
+ [write, Description("Maximum number of retries to check the state of resource.")]
+ Uint32 RetryCount;
+
+ [write, Description("Number of machines to connect simultaneously. Default is new-cimsession default")]
+ Uint32 ThrottleLimit;
+
+ [read, Description("List of remote machines in desired state.")]
+ String NodesInDesiredState;
+
+};
diff --git a/Tests/Rules/DSCResourceModule/DSCResources/MSFT_WaitForAnyNoIdenticalMandatoryParameter/en-US/MSFT_WaitForAny.schema.mfl b/Tests/Rules/DSCResourceModule/DSCResources/MSFT_WaitForAnyNoIdenticalMandatoryParameter/en-US/MSFT_WaitForAny.schema.mfl
new file mode 100644
index 000000000..5481208e6
Binary files /dev/null and b/Tests/Rules/DSCResourceModule/DSCResources/MSFT_WaitForAnyNoIdenticalMandatoryParameter/en-US/MSFT_WaitForAny.schema.mfl differ
diff --git a/Tests/Rules/DSCResources/MyDscResource/MyDscResource.psd1 b/Tests/Rules/DSCResourceModule/DSCResources/MyDscResource/MyDscResource.psd1
similarity index 100%
rename from Tests/Rules/DSCResources/MyDscResource/MyDscResource.psd1
rename to Tests/Rules/DSCResourceModule/DSCResources/MyDscResource/MyDscResource.psd1
diff --git a/Tests/Rules/DSCResources/MyDscResource/MyDscResource.psm1 b/Tests/Rules/DSCResourceModule/DSCResources/MyDscResource/MyDscResource.psm1
similarity index 100%
rename from Tests/Rules/DSCResources/MyDscResource/MyDscResource.psm1
rename to Tests/Rules/DSCResourceModule/DSCResources/MyDscResource/MyDscResource.psm1
diff --git a/Tests/Rules/DSCResources/MSFT_WaitForAll/MSFT_WaitForAll.schema.mof b/Tests/Rules/DSCResources/MSFT_WaitForAll/MSFT_WaitForAll.schema.mof
deleted file mode 100644
index 462d987b8..000000000
Binary files a/Tests/Rules/DSCResources/MSFT_WaitForAll/MSFT_WaitForAll.schema.mof and /dev/null differ
diff --git a/Tests/Rules/DSCResources/MSFT_WaitForAny/MSFT_WaitForAny.schema.mof b/Tests/Rules/DSCResources/MSFT_WaitForAny/MSFT_WaitForAny.schema.mof
deleted file mode 100644
index fd2a10878..000000000
Binary files a/Tests/Rules/DSCResources/MSFT_WaitForAny/MSFT_WaitForAny.schema.mof and /dev/null differ
diff --git a/Tests/Rules/DscExamplesPresent.tests.ps1 b/Tests/Rules/DscExamplesPresent.tests.ps1
index 85ff335e4..3d2ff1488 100644
--- a/Tests/Rules/DscExamplesPresent.tests.ps1
+++ b/Tests/Rules/DscExamplesPresent.tests.ps1
@@ -6,12 +6,12 @@ $ruleName = "PSDSCDscExamplesPresent"
if ($PSVersionTable.PSVersion -ge [Version]'5.0.0') {
Describe "DscExamplesPresent rule in class based resource" {
-
- $examplesPath = "$currentPath\DSCResources\MyDscResource\Examples"
- $classResourcePath = "$currentPath\DSCResources\MyDscResource\MyDscResource.psm1"
+
+ $examplesPath = "$currentPath\DSCResourceModule\DSCResources\MyDscResource\Examples"
+ $classResourcePath = "$currentPath\DSCResourceModule\DSCResources\MyDscResource\MyDscResource.psm1"
Context "When examples absent" {
-
+
$violations = Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue $classResourcePath | Where-Object {$_.RuleName -eq $ruleName}
$violationMessage = "No examples found for resource 'FileResource'"
@@ -24,7 +24,7 @@ if ($PSVersionTable.PSVersion -ge [Version]'5.0.0') {
}
}
- Context "When examples present" {
+ Context "When examples present" {
New-Item -Path $examplesPath -ItemType Directory
New-Item -Path "$examplesPath\FileResource_Example.psm1" -ItemType File
@@ -40,12 +40,12 @@ if ($PSVersionTable.PSVersion -ge [Version]'5.0.0') {
}
Describe "DscExamplesPresent rule in regular (non-class) based resource" {
-
- $examplesPath = "$currentPath\Examples"
- $resourcePath = "$currentPath\DSCResources\MSFT_WaitForAll\MSFT_WaitForAll.psm1"
+
+ $examplesPath = "$currentPath\DSCResourceModule\Examples"
+ $resourcePath = "$currentPath\DSCResourceModule\DSCResources\MSFT_WaitForAll\MSFT_WaitForAll.psm1"
Context "When examples absent" {
-
+
$violations = Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue $resourcePath | Where-Object {$_.RuleName -eq $ruleName}
$violationMessage = "No examples found for resource 'MSFT_WaitForAll'"
@@ -58,7 +58,7 @@ Describe "DscExamplesPresent rule in regular (non-class) based resource" {
}
}
- Context "When examples present" {
+ Context "When examples present" {
New-Item -Path $examplesPath -ItemType Directory
New-Item -Path "$examplesPath\MSFT_WaitForAll_Example.psm1" -ItemType File
@@ -70,4 +70,4 @@ Describe "DscExamplesPresent rule in regular (non-class) based resource" {
Remove-Item -Path $examplesPath -Recurse -Force
}
-}
\ No newline at end of file
+}
diff --git a/Tests/Rules/DscTestsPresent.tests.ps1 b/Tests/Rules/DscTestsPresent.tests.ps1
index 01b85bf7b..d0d0f5e51 100644
--- a/Tests/Rules/DscTestsPresent.tests.ps1
+++ b/Tests/Rules/DscTestsPresent.tests.ps1
@@ -6,12 +6,12 @@ $ruleName = "PSDSCDscTestsPresent"
if ($PSVersionTable.PSVersion -ge [Version]'5.0.0') {
Describe "DscTestsPresent rule in class based resource" {
-
- $testsPath = "$currentPath\DSCResources\MyDscResource\Tests"
- $classResourcePath = "$currentPath\DSCResources\MyDscResource\MyDscResource.psm1"
+
+ $testsPath = "$currentPath\DSCResourceModule\DSCResources\MyDscResource\Tests"
+ $classResourcePath = "$currentPath\DSCResourceModule\DSCResources\MyDscResource\MyDscResource.psm1"
Context "When tests absent" {
-
+
$violations = Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue $classResourcePath | Where-Object {$_.RuleName -eq $ruleName}
$violationMessage = "No tests found for resource 'FileResource'"
@@ -24,7 +24,7 @@ if ($PSVersionTable.PSVersion -ge [Version]'5.0.0') {
}
}
- Context "When tests present" {
+ Context "When tests present" {
New-Item -Path $testsPath -ItemType Directory
New-Item -Path "$testsPath\FileResource_Test.psm1" -ItemType File
@@ -40,12 +40,12 @@ if ($PSVersionTable.PSVersion -ge [Version]'5.0.0') {
}
Describe "DscTestsPresent rule in regular (non-class) based resource" {
-
- $testsPath = "$currentPath\Tests"
- $resourcePath = "$currentPath\DSCResources\MSFT_WaitForAll\MSFT_WaitForAll.psm1"
+
+ $testsPath = "$currentPath\DSCResourceModule\Tests"
+ $resourcePath = "$currentPath\DSCResourceModule\DSCResources\MSFT_WaitForAll\MSFT_WaitForAll.psm1"
Context "When tests absent" {
-
+
$violations = Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue $resourcePath | Where-Object {$_.RuleName -eq $ruleName}
$violationMessage = "No tests found for resource 'MSFT_WaitForAll'"
@@ -58,7 +58,7 @@ Describe "DscTestsPresent rule in regular (non-class) based resource" {
}
}
- Context "When tests present" {
+ Context "When tests present" {
New-Item -Path $testsPath -ItemType Directory
New-Item -Path "$testsPath\MSFT_WaitForAll_Test.psm1" -ItemType File
@@ -70,4 +70,4 @@ Describe "DscTestsPresent rule in regular (non-class) based resource" {
Remove-Item -Path $testsPath -Recurse -Force
}
-}
\ No newline at end of file
+}
diff --git a/Tests/Rules/ProvideCommentHelp.tests.ps1 b/Tests/Rules/ProvideCommentHelp.tests.ps1
index 834765ec2..2a11cf062 100644
--- a/Tests/Rules/ProvideCommentHelp.tests.ps1
+++ b/Tests/Rules/ProvideCommentHelp.tests.ps1
@@ -22,7 +22,7 @@ $settings = @{
$violations = Invoke-ScriptAnalyzer $directory\BadCmdlet.ps1 | Where-Object {$_.RuleName -eq $violationName}
if ($PSVersionTable.PSVersion -ge [Version]'5.0.0') {
- $dscViolations = Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue $directory\DSCResources\MyDscResource\MyDscResource.psm1 | Where-Object {$_.RuleName -eq $violationName}
+ $dscViolations = Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue $directory\DSCResourceModule\DSCResources\MyDscResource\MyDscResource.psm1 | Where-Object {$_.RuleName -eq $violationName}
}
$noViolations = Invoke-ScriptAnalyzer $directory\GoodCmdlet.ps1 | Where-Object {$_.RuleName -eq $violationName}
diff --git a/Tests/Rules/ReturnCorrectTypesForDSCFunctions.tests.ps1 b/Tests/Rules/ReturnCorrectTypesForDSCFunctions.tests.ps1
index 36a478e3a..34b406aa5 100644
--- a/Tests/Rules/ReturnCorrectTypesForDSCFunctions.tests.ps1
+++ b/Tests/Rules/ReturnCorrectTypesForDSCFunctions.tests.ps1
@@ -4,13 +4,13 @@ $violationMessageDSCResource = "Test-TargetResource function in DSC Resource sho
$violationMessageDSCClass = "Get function in DSC Class FileResource should return object of type FileResource instead of type System.Collections.Hashtable"
$violationName = "PSDSCReturnCorrectTypesForDSCFunctions"
$directory = Split-Path -Parent $MyInvocation.MyCommand.Path
-$violations = Invoke-ScriptAnalyzer $directory\DSCResources\MSFT_WaitForAll\MSFT_WaitForAll.psm1 | Where-Object {$_.RuleName -eq $violationName}
-$noViolations = Invoke-ScriptAnalyzer $directory\DSCResources\MSFT_WaitForAny\MSFT_WaitForAny.psm1 | Where-Object {$_.RuleName -eq $violationName}
+$violations = Invoke-ScriptAnalyzer $directory\DSCResourceModule\DSCResources\MSFT_WaitForAll\MSFT_WaitForAll.psm1 | Where-Object {$_.RuleName -eq $violationName}
+$noViolations = Invoke-ScriptAnalyzer $directory\DSCResourceModule\DSCResources\MSFT_WaitForAny\MSFT_WaitForAny.psm1 | Where-Object {$_.RuleName -eq $violationName}
if ($PSVersionTable.PSVersion -ge [Version]'5.0.0')
{
- $classViolations = Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue $directory\DSCResources\BadDscResource\BadDscResource.psm1 | Where-Object {$_.RuleName -eq $violationName}
- $noClassViolations = Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue $directory\DSCResources\MyDscResource\MyDscResource.psm1 | Where-Object {$_.RuleName -eq $violationName}
+ $classViolations = Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue $directory\DSCResourceModule\DSCResources\BadDscResource\BadDscResource.psm1 | Where-Object {$_.RuleName -eq $violationName}
+ $noClassViolations = Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue $directory\DSCResourceModule\DSCResources\MyDscResource\MyDscResource.psm1 | Where-Object {$_.RuleName -eq $violationName}
}
Describe "ReturnCorrectTypesForDSCFunctions" {
@@ -49,4 +49,4 @@ if ($PSVersionTable.PSVersion -ge [Version]'5.0.0') {
}
}
}
-}
\ No newline at end of file
+}
diff --git a/Tests/Rules/UseDSCResourceFunctions.tests.ps1 b/Tests/Rules/UseDSCResourceFunctions.tests.ps1
index 306bb2718..5bffe1b46 100644
--- a/Tests/Rules/UseDSCResourceFunctions.tests.ps1
+++ b/Tests/Rules/UseDSCResourceFunctions.tests.ps1
@@ -4,13 +4,13 @@ $violationMessage = "Missing 'Get-TargetResource' function. DSC Resource must im
$classViolationMessage = "Missing 'Set' function. DSC Class must implement Get, Set and Test functions."
$violationName = "PSDSCStandardDSCFunctionsInResource"
$directory = Split-Path -Parent $MyInvocation.MyCommand.Path
-$violations = Invoke-ScriptAnalyzer $directory\DSCResources\MSFT_WaitForAll\MSFT_WaitForAll.psm1 | Where-Object {$_.RuleName -eq $violationName}
-$noViolations = Invoke-ScriptAnalyzer $directory\DSCResources\MSFT_WaitForAny\MSFT_WaitForAny.psm1 | Where-Object {$_.RuleName -eq $violationName}
+$violations = Invoke-ScriptAnalyzer $directory\DSCResourceModule\DSCResources\MSFT_WaitForAll\MSFT_WaitForAll.psm1 | Where-Object {$_.RuleName -eq $violationName}
+$noViolations = Invoke-ScriptAnalyzer $directory\DSCResourceModule\DSCResources\MSFT_WaitForAny\MSFT_WaitForAny.psm1 | Where-Object {$_.RuleName -eq $violationName}
if ($PSVersionTable.PSVersion -ge [Version]'5.0.0')
{
- $classViolations = Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue $directory\DSCResources\BadDscResource\BadDscResource.psm1 | Where-Object {$_.RuleName -eq $violationName}
- $noClassViolations = Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue $directory\DSCResources\MyDscResource\MyDscResource.psm1 | Where-Object {$_.RuleName -eq $violationName}
+ $classViolations = Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue $directory\DSCResourceModule\DSCResources\BadDscResource\BadDscResource.psm1 | Where-Object {$_.RuleName -eq $violationName}
+ $noClassViolations = Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue $directory\DSCResourceModule\DSCResources\MyDscResource\MyDscResource.psm1 | Where-Object {$_.RuleName -eq $violationName}
}
Describe "StandardDSCFunctionsInResource" {
@@ -49,4 +49,4 @@ if ($PSVersionTable.PSVersion -ge [Version]'5.0.0') {
}
}
}
-}
\ No newline at end of file
+}
diff --git a/Tests/Rules/UseIdenticalMandatoryParametersForDSC.tests.ps1 b/Tests/Rules/UseIdenticalMandatoryParametersForDSC.tests.ps1
new file mode 100644
index 000000000..4a12eff16
--- /dev/null
+++ b/Tests/Rules/UseIdenticalMandatoryParametersForDSC.tests.ps1
@@ -0,0 +1,37 @@
+Import-Module PSScriptAnalyzer
+$directory = Split-Path -Parent $MyInvocation.MyCommand.Path
+$ruleName = 'PSDSCUseIdenticalMandatoryParametersForDSC'
+$resourceBasepath = "$directory\DSCResourceModule\DSCResources"
+$badResourceFilepath = [System.IO.Path]::Combine(
+ $resourceBasepath,
+ 'MSFT_WaitForAnyNoIdenticalMandatoryParameter',
+ 'MSFT_WaitForAnyNoIdenticalMandatoryParameter.psm1');
+$goodResourceFilepath = [System.IO.Path]::Combine($resourceBasepath,'MSFT_WaitForAny','MSFT_WaitForAny.psm1');
+
+
+Describe "UseIdenticalMandatoryParametersForDSC" {
+ Context "When a mandatory parameters are not present" {
+ BeforeAll {
+ $violations = Invoke-ScriptAnalyzer -Path $badResourceFilepath -IncludeRule $ruleName
+ }
+
+ It "Should find a violations" {
+ $violations.Count | Should Be 5
+ }
+
+ It "Should mark only the function name" {
+ $violations[0].Extent.Text | Should Be 'Get-TargetResource'
+ }
+ }
+
+ Context "When all mandatory parameters are present" {
+ BeforeAll {
+ $violations = Invoke-ScriptAnalyzer -Path $goodResourceFilepath -IncludeRule $ruleName
+ }
+
+ # todo add a test to check one violation per function
+ It "Should find a violations" {
+ $violations.Count | Should Be 0
+ }
+ }
+}
diff --git a/Tests/Rules/UseIdenticalParametersDSC.tests.ps1 b/Tests/Rules/UseIdenticalParametersDSC.tests.ps1
index 0fcddaa96..9fbebb645 100644
--- a/Tests/Rules/UseIdenticalParametersDSC.tests.ps1
+++ b/Tests/Rules/UseIdenticalParametersDSC.tests.ps1
@@ -3,12 +3,12 @@
$violationMessage = "The Test and Set-TargetResource functions of DSC Resource must have the same parameters."
$violationName = "PSDSCUseIdenticalParametersForDSC"
$directory = Split-Path -Parent $MyInvocation.MyCommand.Path
-$violations = Invoke-ScriptAnalyzer $directory\DSCResources\MSFT_WaitForAll\MSFT_WaitForAll.psm1 | Where-Object {$_.RuleName -eq $violationName}
-$noViolations = Invoke-ScriptAnalyzer $directory\DSCResources\MSFT_WaitForAny\MSFT_WaitForAny.psm1 | Where-Object {$_.RuleName -eq $violationName}
+$violations = Invoke-ScriptAnalyzer $directory\DSCResourceModule\DSCResources\MSFT_WaitForAll\MSFT_WaitForAll.psm1 | Where-Object {$_.RuleName -eq $violationName}
+$noViolations = Invoke-ScriptAnalyzer $directory\DSCResourceModule\DSCResources\MSFT_WaitForAny\MSFT_WaitForAny.psm1 | Where-Object {$_.RuleName -eq $violationName}
if ($PSVersionTable.PSVersion -ge [Version]'5.0.0')
{
- $noClassViolations = Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue $directory\DSCResources\MyDscResource\MyDscResource.psm1 | Where-Object {$_.RuleName -eq $violationName}
+ $noClassViolations = Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue $directory\DSCResourceModule\DSCResources\MyDscResource\MyDscResource.psm1 | Where-Object {$_.RuleName -eq $violationName}
}
Describe "UseIdenticalParametersDSC" {
@@ -26,7 +26,7 @@ Describe "UseIdenticalParametersDSC" {
It "returns no violations" {
$noViolations.Count | Should Be 0
}
-
+
if ($PSVersionTable.PSVersion -ge [Version]'5.0.0')
{
@@ -35,4 +35,4 @@ Describe "UseIdenticalParametersDSC" {
}
}
}
-}
\ No newline at end of file
+}
diff --git a/Tests/Rules/UseOutputTypeCorrectly.tests.ps1 b/Tests/Rules/UseOutputTypeCorrectly.tests.ps1
index ca5d0eee0..eb7029a57 100644
--- a/Tests/Rules/UseOutputTypeCorrectly.tests.ps1
+++ b/Tests/Rules/UseOutputTypeCorrectly.tests.ps1
@@ -6,7 +6,7 @@ $violations = Invoke-ScriptAnalyzer $directory\BadCmdlet.ps1 | Where-Object {$_.
if ($PSVersionTable.PSVersion -ge [Version]'5.0.0')
{
- $dscViolations = Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue $directory\DSCResources\MyDscResource\MyDscResource.psm1 | Where-Object {$_.RuleName -eq $violationName}
+ $dscViolations = Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue $directory\DSCResourceModule\DSCResources\MyDscResource\MyDscResource.psm1 | Where-Object {$_.RuleName -eq $violationName}
}
$noViolations = Invoke-ScriptAnalyzer $directory\GoodCmdlet.ps1 | Where-Object {$_.RuleName -eq $violationName}
@@ -21,7 +21,7 @@ Describe "UseOutputTypeCorrectly" {
$violations[1].Message | Should Match $violationMessage
}
- if ($PSVersionTable.PSVersion -ge [Version]'5.0.0') {
+ if ($PSVersionTable.PSVersion -ge [Version]'5.0.0') {
It "Does not count violation in DSC class" {
$dscViolations.Count | Should Be 0
}
@@ -33,4 +33,4 @@ Describe "UseOutputTypeCorrectly" {
$noViolations.Count | Should Be 0
}
}
-}
\ No newline at end of file
+}
diff --git a/Tests/Rules/UseVerboseMessageInDSCResource.Tests.ps1 b/Tests/Rules/UseVerboseMessageInDSCResource.Tests.ps1
index 431188a30..d181bb628 100644
--- a/Tests/Rules/UseVerboseMessageInDSCResource.Tests.ps1
+++ b/Tests/Rules/UseVerboseMessageInDSCResource.Tests.ps1
@@ -3,9 +3,9 @@
$violationMessage = "There is no call to Write-Verbose in DSC function ‘Test-TargetResource’. If you are using Write-Verbose in a helper function, suppress this rule application."
$violationName = "PSDSCUseVerboseMessageInDSCResource"
$directory = Split-Path -Parent $MyInvocation.MyCommand.Path
-$violations = Invoke-ScriptAnalyzer $directory\DSCResources\MSFT_WaitForAll\MSFT_WaitForAll.psm1 | Where-Object {$_.RuleName -eq $violationName}
-$noViolations = Invoke-ScriptAnalyzer $directory\DSCResources\MSFT_WaitForAny\MSFT_WaitForAny.psm1 | Where-Object {$_.RuleName -eq $violationName}
-$noClassViolations = Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue $directory\DSCResources\MyDscResource\MyDscResource.psm1 | Where-Object {$_.RuleName -eq $violationName}
+$violations = Invoke-ScriptAnalyzer $directory\DSCResourceModule\DSCResources\MSFT_WaitForAll\MSFT_WaitForAll.psm1 | Where-Object {$_.RuleName -eq $violationName}
+$noViolations = Invoke-ScriptAnalyzer $directory\DSCResourceModule\DSCResources\MSFT_WaitForAny\MSFT_WaitForAny.psm1 | Where-Object {$_.RuleName -eq $violationName}
+$noClassViolations = Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue $directory\DSCResourceModule\DSCResources\MyDscResource\MyDscResource.psm1 | Where-Object {$_.RuleName -eq $violationName}
Describe "UseVerboseMessageInDSCResource" {
Context "When there are violations" {
@@ -21,6 +21,6 @@ Describe "UseVerboseMessageInDSCResource" {
Context "When there are no violations" {
It "returns no violations" {
$noViolations.Count | Should Be 0
- }
+ }
}
-}
\ No newline at end of file
+}