diff --git a/src/System.Management.Automation/DscSupport/CimDSCParser.cs b/src/System.Management.Automation/DscSupport/CimDSCParser.cs
index ea7501a8a2d..3079155097f 100644
--- a/src/System.Management.Automation/DscSupport/CimDSCParser.cs
+++ b/src/System.Management.Automation/DscSupport/CimDSCParser.cs
@@ -469,6 +469,47 @@ internal void ValidateInstanceText(string classText)
namespace Microsoft.PowerShell.DesiredStateConfiguration.Internal
{
+ ///
+ ///
+ [SuppressMessage("Microsoft.MSInternal", "CA903:InternalNamespaceShouldNotContainPublicTypes",
+ Justification = "Needed Internal use only")]
+ internal class DscClassCacheEntry
+ {
+ ///
+ /// Store the RunAs Credentials that this DSC resource will use
+ ///
+ public DSCResourceRunAsCredential DscResRunAsCred;
+
+ ///
+ /// If we have implicitly imported this resource, we will set this field to true. This will
+ /// only happen to InBox resources.
+ ///
+ public bool IsImportedImplicitly;
+
+ ///
+ /// A CimClass instance for this resource
+ ///
+ public Microsoft.Management.Infrastructure.CimClass CimClassInstance;
+
+ ///
+ /// Default constructor to initiale variables with default values
+ ///
+ public DscClassCacheEntry() : this(DSCResourceRunAsCredential.Default, false, null) { }
+
+ ///
+ /// Constructor used in code to initialze all values
+ ///
+ ///
+ ///
+ ///
+ public DscClassCacheEntry(DSCResourceRunAsCredential aDSCResourceRunAsCredential, bool aIsImportedImplicitly, Microsoft.Management.Infrastructure.CimClass aCimClassInstance)
+ {
+ DscResRunAsCred = aDSCResourceRunAsCredential;
+ IsImportedImplicitly = aIsImportedImplicitly;
+ CimClassInstance = aCimClassInstance;
+ }
+ }
+
///
///
[SuppressMessage("Microsoft.MSInternal", "CA903:InternalNamespaceShouldNotContainPublicTypes",
@@ -486,6 +527,7 @@ public static class DscClassCache
private const int IndexModuleName = 0;
private const int IndexModuleVersion = 1;
private const int IndexClassName = 2;
+ private const int IndexFriendlyName = 3;
// Create a list of classes which are not actual DSC resources similar to what we do inside PSDesiredStateConfiguration.psm1
private static readonly string[] s_hiddenResourceList =
@@ -505,15 +547,15 @@ public static class DscClassCache
///
/// DSC class cache for this runspace.
- /// Cache stores the DSCRunAsBehavior for the class along with actual cim class.
+ /// Cache stores the DSCRunAsBehavior, cim class and boolean to indicate if an Inbox resource has been implicitly imported.
///
- private static Dictionary> ClassCache
+ private static Dictionary ClassCache
{
get
{
if (t_classCache == null)
{
- t_classCache = new Dictionary>(StringComparer.OrdinalIgnoreCase);
+ t_classCache = new Dictionary(StringComparer.OrdinalIgnoreCase);
}
return t_classCache;
@@ -521,7 +563,7 @@ public static class DscClassCache
}
[ThreadStatic]
- private static Dictionary> t_classCache;
+ private static Dictionary t_classCache;
///
/// DSC classname to source module mapper.
@@ -727,12 +769,12 @@ public static void Initialize(Collection errors, List moduleP
}
// Load Regular and DSC PS modules
- bool isInboxResource = false;
+ bool importInBoxResourcesImplicitly = false;
List modulePaths = new List();
if (modulePathList == null || modulePathList.Count == 0)
{
modulePaths.Add(Path.Combine(configSystemPath, inboxModulePath));
- isInboxResource = true;
+ importInBoxResourcesImplicitly = true;
}
else
{
@@ -750,7 +792,7 @@ public static void Initialize(Collection errors, List moduleP
}
}
- LoadDSCResourceIntoCache(errors, modulePaths, isInboxResource);
+ LoadDSCResourceIntoCache(errors, modulePaths, importInBoxResourcesImplicitly);
}
}
@@ -759,10 +801,10 @@ public static void Initialize(Collection errors, List moduleP
///
/// Collection of any errors encountered during initialization.
/// Module path from where DSC PS modules will be loaded.
- ///
+ ///
/// if module is inbox.
///
- private static void LoadDSCResourceIntoCache(Collection errors, List modulePathList, bool isInboxResource)
+ private static void LoadDSCResourceIntoCache(Collection errors, List modulePathList, bool importInBoxResourcesImplicitly)
{
foreach (string moduleDir in modulePathList)
{
@@ -779,7 +821,7 @@ private static void LoadDSCResourceIntoCache(Collection errors, List<
continue;
}
- Tuple moduleInfo = GetModuleInfoHelper(moduleDir, isInboxResource, isPsProviderModule: false);
+ Tuple moduleInfo = GetModuleInfoHelper(moduleDir, importInBoxResourcesImplicitly, isPsProviderModule: false);
if (moduleInfo == null)
{
continue;
@@ -787,7 +829,7 @@ private static void LoadDSCResourceIntoCache(Collection errors, List<
foreach (string schemaFile in schemaFiles)
{
- ImportClasses(schemaFile, moduleInfo, errors);
+ ImportClasses(schemaFile, moduleInfo, errors, importInBoxResourcesImplicitly);
}
}
}
@@ -800,17 +842,17 @@ private static void LoadDSCResourceIntoCache(Collection errors, List<
///
/// Path to the module folder
///
- ///
- /// if module is inbox.
+ ///
+ /// if module is inbox and we are importing resources implicitly
///
///
/// Indicate a internal DSC module
///
///
- private static Tuple GetModuleInfoHelper(string moduleFolderPath, bool isInboxResource, bool isPsProviderModule)
+ private static Tuple GetModuleInfoHelper(string moduleFolderPath, bool importInBoxResourcesImplicitly, bool isPsProviderModule)
{
string moduleName = "PsDesiredStateConfiguration";
- if (!isInboxResource)
+ if (!importInBoxResourcesImplicitly)
{
moduleName = Path.GetFileName(moduleFolderPath);
}
@@ -875,12 +917,12 @@ private static Tuple GetModuleInfoHelper(string moduleFolderPat
// Callback implementation...
private static CimClass MyClassCallback(string serverName, string namespaceName, string className)
{
- foreach (KeyValuePair> cimClass in ClassCache)
+ foreach (KeyValuePair cimClass in ClassCache)
{
string cachedClassName = cimClass.Key.Split(Utils.Separators.Backslash)[IndexClassName];
if (string.Compare(cachedClassName, className, StringComparison.OrdinalIgnoreCase) == 0)
{
- return cimClass.Value.Item2;
+ return cimClass.Value.CimClassInstance;
}
}
@@ -893,8 +935,9 @@ private static CimClass MyClassCallback(string serverName, string namespaceName,
///
///
///
+ ///
///
- public static List ImportClasses(string path, Tuple moduleInfo, Collection errors)
+ public static List ImportClasses(string path, Tuple moduleInfo, Collection errors, bool importInBoxResourcesImplicitly = false)
{
if (string.IsNullOrEmpty(path))
{
@@ -926,12 +969,14 @@ public static List ImportClasses(string path, Tuple m
{
// Only add the class once...
var className = c.CimSystemProperties.ClassName;
- string moduleQualifiedResourceName = GetModuleQualifiedResourceName(moduleInfo.Item1, moduleInfo.Item2.ToString(), className);
- Tuple cimClassInfo;
+ string alias = GetFriendlyName(c);
+ var friendlyName = string.IsNullOrEmpty(alias) ? className : alias;
+ string moduleQualifiedResourceName = GetModuleQualifiedResourceName(moduleInfo.Item1, moduleInfo.Item2.ToString(), className, friendlyName);
+ DscClassCacheEntry cimClassInfo;
if (ClassCache.TryGetValue(moduleQualifiedResourceName, out cimClassInfo))
{
- CimClass cimClass = cimClassInfo.Item2;
+ CimClass cimClass = cimClassInfo.CimClassInstance;
// If this is a nested object and we already have exactly same nested object, we will
// allow sharing of nested objects.
if (!IsSameNestedObject(cimClass, c))
@@ -956,14 +1001,19 @@ public static List ImportClasses(string path, Tuple m
if (!CacheResourcesFromMultipleModuleVersions)
{
// Find & remove the previous version of the resource.
- List>> resourceList = FindResourceInCache(moduleInfo.Item1, className);
+ List> resourceList = FindResourceInCache(moduleInfo.Item1, className, friendlyName);
if (resourceList.Count > 0 && !string.IsNullOrEmpty(resourceList[0].Key))
{
ClassCache.Remove(resourceList[0].Key);
+ // keyword is already defined and it is a Inbox resource, remove it
+ if (DynamicKeyword.ContainsKeyword(friendlyName) && resourceList[0].Value.IsImportedImplicitly)
+ {
+ DynamicKeyword.RemoveKeyword(friendlyName);
+ }
}
}
- ClassCache[moduleQualifiedResourceName] = new Tuple(DSCResourceRunAsCredential.Default, c);
+ ClassCache[moduleQualifiedResourceName] = new DscClassCacheEntry(DSCResourceRunAsCredential.Default, importInBoxResourcesImplicitly, c);
ByClassModuleCache[className] = moduleInfo;
}
@@ -1023,10 +1073,11 @@ public static void ClearCache()
///
///
///
+ ///
///
- private static string GetModuleQualifiedResourceName(string moduleName, string moduleVersion, string className)
+ private static string GetModuleQualifiedResourceName(string moduleName, string moduleVersion, string className, string resourceName)
{
- return string.Format(CultureInfo.InvariantCulture, "{0}\\{1}\\{2}", moduleName, moduleVersion, className);
+ return String.Format(CultureInfo.InvariantCulture, "{0}\\{1}\\{2}\\{3}", moduleName, moduleVersion, className, resourceName);
}
///
@@ -1034,22 +1085,25 @@ private static string GetModuleQualifiedResourceName(string moduleName, string m
///
/// Module name.
/// Resource type name.
+ /// Resource friendly name
/// List of found resources in the form of Dictionary{moduleQualifiedName, cimClass}, otherwise empty list.
- private static List>> FindResourceInCache(string moduleName, string className)
+ private static List> FindResourceInCache(string moduleName, string className, string resourceName)
{
return (from cacheEntry in ClassCache
let splittedName = cacheEntry.Key.Split(Utils.Separators.Backslash)
let cachedClassName = splittedName[IndexClassName]
let cachedModuleName = splittedName[IndexModuleName]
- where string.Compare(cachedClassName, className, StringComparison.OrdinalIgnoreCase) == 0
- && string.Compare(cachedModuleName, moduleName, StringComparison.OrdinalIgnoreCase) == 0
+ let cachedResourceName = splittedName[IndexFriendlyName]
+ where ((string.Compare(cachedResourceName, resourceName, StringComparison.OrdinalIgnoreCase) == 0)
+ || (string.Compare(cachedClassName, className, StringComparison.OrdinalIgnoreCase) == 0
+ && string.Compare(cachedModuleName, moduleName, StringComparison.OrdinalIgnoreCase) == 0))
select cacheEntry).ToList();
}
///
///
///
- public static List> GetCachedClasses()
+ private static List GetCachedClasses()
{
return ClassCache.Values.ToList();
}
@@ -1063,11 +1117,11 @@ where string.Compare(cachedClassName, className, StringComparison.OrdinalIgnoreC
{
List cachedClasses = new List();
var moduleQualifiedName = string.Format(CultureInfo.InvariantCulture, "{0}\\{1}", module.Name, module.Version.ToString());
- foreach (var pair in ClassCache)
+ foreach (var dscClassCacheEntry in ClassCache)
{
- if (pair.Key.StartsWith(moduleQualifiedName, StringComparison.OrdinalIgnoreCase))
+ if(dscClassCacheEntry.Key.StartsWith(moduleQualifiedName, StringComparison.OrdinalIgnoreCase))
{
- cachedClasses.Add(pair.Value.Item2);
+ cachedClasses.Add(dscClassCacheEntry.Value.CimClassInstance);
}
}
@@ -1231,13 +1285,13 @@ public static Collection GetCachedKeywords()
{
Collection keywords = new Collection();
- foreach (KeyValuePair> cachedClass in ClassCache)
+ foreach (KeyValuePair cachedClass in ClassCache)
{
string[] splittedName = cachedClass.Key.Split(Utils.Separators.Backslash);
string moduleName = splittedName[IndexModuleName];
string moduleVersion = splittedName[IndexModuleVersion];
- var keyword = CreateKeywordFromCimClass(moduleName, Version.Parse(moduleVersion), cachedClass.Value.Item2, null, cachedClass.Value.Item1);
+ var keyword = CreateKeywordFromCimClass(moduleName, Version.Parse(moduleVersion), cachedClass.Value.CimClassInstance, null, cachedClass.Value.DscResRunAsCred);
if (keyword != null)
{
keywords.Add(keyword);
@@ -1577,9 +1631,9 @@ private static void LoadDefaultCimKeywords(Dictionary funct
foreach (var cimClass in GetCachedClasses())
{
- var className = cimClass.Item2.CimSystemProperties.ClassName;
+ var className = cimClass.CimClassInstance.CimSystemProperties.ClassName;
var moduleInfo = ByClassModuleCache[className];
- CreateAndRegisterKeywordFromCimClass(moduleInfo.Item1, moduleInfo.Item2, cimClass.Item2, functionsToDefine, cimClass.Item1);
+ CreateAndRegisterKeywordFromCimClass(moduleInfo.Item1, moduleInfo.Item2, cimClass.CimClassInstance, functionsToDefine, cimClass.DscResRunAsCred);
}
// And add the Node keyword definitions
@@ -3090,20 +3144,26 @@ private static void ProcessMofForDynamicKeywords(PSModuleInfo module, ICollectio
foreach (var c in parser.ParseSchemaMofFileBuffer(mof))
{
var className = c.CimSystemProperties.ClassName;
+ string alias = GetFriendlyName(c);
+ var friendlyName = string.IsNullOrEmpty(alias) ? className : alias;
if (!CacheResourcesFromMultipleModuleVersions)
{
// Find & remove the previous version of the resource.
- List>> resourceList =
- FindResourceInCache(module.Name, className);
+ List> resourceList = FindResourceInCache(module.Name, className, friendlyName);
if (resourceList.Count > 0 && !string.IsNullOrEmpty(resourceList[0].Key))
{
ClassCache.Remove(resourceList[0].Key);
+ // keyword is already defined and it is a Inbox resource, remove it
+ if (DynamicKeyword.ContainsKeyword(friendlyName) && resourceList[0].Value.IsImportedImplicitly)
+ {
+ DynamicKeyword.RemoveKeyword(friendlyName);
+ }
}
}
- var moduleQualifiedResourceName = GetModuleQualifiedResourceName(module.Name, module.Version.ToString(), className);
- ClassCache[moduleQualifiedResourceName] = new Tuple(runAsBehavior, c);
+ var moduleQualifiedResourceName = GetModuleQualifiedResourceName(module.Name, module.Version.ToString(), className, friendlyName);
+ ClassCache[moduleQualifiedResourceName] = new DscClassCacheEntry(runAsBehavior, false, c);
ByClassModuleCache[className] = new Tuple(module.Name, module.Version);
resourcesFound.Add(className);
CreateAndRegisterKeywordFromCimClass(module.Name, module.Version, c, functionsToDefine, runAsBehavior);
@@ -3171,6 +3231,7 @@ public static bool ImportCimKeywordsFromModule(PSModuleInfo module, string resou
foreach (var c in classes)
{
CreateAndRegisterKeywordFromCimClass(module.Name, module.Version, c, functionsToDefine, DSCResourceRunAsCredential.Default);
+ ClearImplicitlyImportedFlagFromResourceInClassCache(module, c);
}
}
@@ -3204,6 +3265,7 @@ public static bool ImportCimKeywordsFromModule(PSModuleInfo module, string resou
if (string.Equals(alias, resourceName, StringComparison.OrdinalIgnoreCase))
{
CreateAndRegisterKeywordFromCimClass(module.Name, module.Version, c, functionsToDefine, DSCResourceRunAsCredential.Default);
+ ClearImplicitlyImportedFlagFromResourceInClassCache(module, c);
return true;
}
}
@@ -3221,6 +3283,21 @@ public static bool ImportCimKeywordsFromModule(PSModuleInfo module, string resou
return false;
}
+
+ ///
+ /// Clear the 'IsImportedImplicitly' flag when explicitly importing a resource
+ ///
+ ///
+ ///
+ private static void ClearImplicitlyImportedFlagFromResourceInClassCache(PSModuleInfo module, CimClass cimClass)
+ {
+ var className = cimClass.CimSystemProperties.ClassName;
+ var alias = GetFriendlyName(cimClass);
+ var friendlyName = string.IsNullOrEmpty(alias) ? className : alias;
+ var moduleQualifiedResourceName = GetModuleQualifiedResourceName(module.Name, module.Version.ToString(), className, friendlyName);
+ ClassCache[moduleQualifiedResourceName].IsImportedImplicitly = false;
+ }
+
///
/// Imports configuration keywords from a .psm1 file.
///