/// <summary> /// A method to generate a keyword from a CIM class object. This is used for DSC. /// </summary> /// <param name="moduleName"></param> /// <param name="moduleVersion"></param> /// <param name="cimClass"></param> /// <param name="functionsToDefine">If true, don't define the keywords, just create the functions.</param> /// <param name="runAsBehavior"> To specify RunAs behavior of the class </param> private static DynamicKeyword CreateKeywordFromCimClass(string moduleName, Version moduleVersion, Microsoft.Management.Infrastructure.CimClass cimClass, Dictionary<string, ScriptBlock> functionsToDefine, DSCResourceRunAsCredential runAsBehavior) { var resourceName = cimClass.CimSystemProperties.ClassName; string alias = GetFriendlyName(cimClass); var keywordString = string.IsNullOrEmpty(alias) ? resourceName : alias; // // Skip all of the base, meta, registration and other classes that are not intended to be used directly by a script author // if (System.Text.RegularExpressions.Regex.Match(keywordString, "^OMI_Base|^OMI_.*Registration", System.Text.RegularExpressions.RegexOptions.IgnoreCase).Success) { return null; } var keyword = new DynamicKeyword() { BodyMode = DynamicKeywordBodyMode.Hashtable, Keyword = keywordString, ResourceName = resourceName, ImplementingModule = moduleName, ImplementingModuleVersion = moduleVersion, SemanticCheck = CheckMandatoryPropertiesPresent }; // If it's one of reserved dynamic keyword, mark it if (System.Text.RegularExpressions.Regex.Match(keywordString, reservedDynamicKeywords, System.Text.RegularExpressions.RegexOptions.IgnoreCase).Success) { keyword.IsReservedKeyword = true; } // see if it's a resource type i.e. it inherits from OMI_BaseResource bool isResourceType = false; for (var classToCheck = cimClass; !string.IsNullOrEmpty(classToCheck.CimSuperClassName); classToCheck = classToCheck.CimSuperClass) { if (string.Equals("OMI_BaseResource", classToCheck.CimSuperClassName, StringComparison.OrdinalIgnoreCase) || string.Equals("OMI_MetaConfigurationResource", classToCheck.CimSuperClassName, StringComparison.OrdinalIgnoreCase)) { isResourceType = true; break; } } // If it's a resource type, then a resource name is required. keyword.NameMode = isResourceType ? DynamicKeywordNameMode.NameRequired : DynamicKeywordNameMode.NoName; // // Add the settable properties to the keyword object // foreach (var prop in cimClass.CimClassProperties) { // If the property is marked as readonly, skip it... if ((prop.Flags & Microsoft.Management.Infrastructure.CimFlags.ReadOnly) == Microsoft.Management.Infrastructure.CimFlags.ReadOnly) { continue; } try { // If the property has the Read qualifier, also skip it. if (prop.Qualifiers["Read"] != null) { continue; } } catch (Microsoft.Management.Infrastructure.CimException) { // Cim exception means Read wasn't found so continue... } // If it's one of our magic properties, skip it if (IsMagicProperty(prop.Name)) { continue; } if (runAsBehavior == DSCResourceRunAsCredential.NotSupported) { if (String.Equals(prop.Name, "PsDscRunAsCredential", StringComparison.OrdinalIgnoreCase)) { // skip adding PsDscRunAsCredential to the dynamic word for the dsc resource. continue; } } // If it's one of our reserved properties, save it for error reporting if (System.Text.RegularExpressions.Regex.Match(prop.Name, reservedProperties, System.Text.RegularExpressions.RegexOptions.IgnoreCase).Success) { keyword.HasReservedProperties = true; continue; } // Otherwise, add it to the Keyword List. var keyProp = new System.Management.Automation.Language.DynamicKeywordProperty(); keyProp.Name = prop.Name; // Set the mandatory flag if appropriate if ((prop.Flags & Microsoft.Management.Infrastructure.CimFlags.Key) == Microsoft.Management.Infrastructure.CimFlags.Key) { keyProp.Mandatory = true; keyProp.IsKey = true; } // Copy the type name string. If it's an embedded instance, need to grab it from the ReferenceClassName bool referenceClassNameIsNullOrEmpty = string.IsNullOrEmpty(prop.ReferenceClassName); if (prop.CimType == CimType.Instance && !referenceClassNameIsNullOrEmpty) { keyProp.TypeConstraint = prop.ReferenceClassName; } else if (prop.CimType == CimType.InstanceArray && !referenceClassNameIsNullOrEmpty) { keyProp.TypeConstraint = prop.ReferenceClassName + "[]"; } else { keyProp.TypeConstraint = prop.CimType.ToString(); } string[] valueMap = null; foreach (var qualifier in prop.Qualifiers) { // Check to see if there is a Values attribute and save the list of allowed values if so. if (string.Equals(qualifier.Name, "Values", StringComparison.OrdinalIgnoreCase) && qualifier.CimType == Microsoft.Management.Infrastructure.CimType.StringArray) { keyProp.Values.AddRange((string[])qualifier.Value); } // Check to see if there is a ValueMap attribute and save the list of allowed values if so. if (string.Equals(qualifier.Name, "ValueMap", StringComparison.OrdinalIgnoreCase) && qualifier.CimType == Microsoft.Management.Infrastructure.CimType.StringArray) { valueMap = (string[])qualifier.Value; } // Check to see if this property has the Required qualifier associated with it. if (string.Equals(qualifier.Name, "Required", StringComparison.OrdinalIgnoreCase) && qualifier.CimType == Microsoft.Management.Infrastructure.CimType.Boolean && (bool)qualifier.Value) { keyProp.Mandatory = true; } // set the property to mandatory is specified for the resource. if (runAsBehavior == DSCResourceRunAsCredential.Mandatory) { if (String.Equals(prop.Name, "PsDscRunAsCredential", StringComparison.OrdinalIgnoreCase)) { keyProp.Mandatory = true; } } } if (valueMap != null && keyProp.Values.Count > 0) { if (valueMap.Length != keyProp.Values.Count) { s_tracer.WriteLine( "DSC CreateDynamicKeywordFromClass: the count of values for qualifier 'Values' and 'ValueMap' doesn't match. count of 'Values': {0}, count of 'ValueMap': {1}. Skip the keyword '{2}'.", keyProp.Values.Count, valueMap.Length, keyword.Keyword); return null; } for (int index = 0; index < valueMap.Length; index++) { string key = keyProp.Values[index]; string value = valueMap[index]; if (keyProp.ValueMap.ContainsKey(key)) { s_tracer.WriteLine( "DSC CreateDynamicKeywordFromClass: same string value '{0}' appears more than once in qualifier 'Values'. Skip the keyword '{1}'.", key, keyword.Keyword); return null; } keyProp.ValueMap.Add(key, value); } } keyword.Properties.Add(prop.Name, keyProp); } // update specific keyword with range constraints UpdateKnownRestriction(keyword); return keyword; }
private static void ProcessMofForDynamicKeywords(PSModuleInfo module, ICollection<string> resourcesFound, Dictionary<string, ScriptBlock> functionsToDefine, CimDSCParser parser, string mof, DSCResourceRunAsCredential runAsBehavior) { foreach (var c in parser.ParseSchemaMofFileBuffer(mof)) { var className = c.CimSystemProperties.ClassName; if (!CacheResourcesFromMultipleModuleVersions) { // Find & remove the previous version of the resource. List<KeyValuePair<string, Tuple<DSCResourceRunAsCredential, Microsoft.Management.Infrastructure.CimClass>>> resourceList = FindResourceInCache(module.Name, className); if (resourceList.Count > 0 && !string.IsNullOrEmpty(resourceList[0].Key)) { ClassCache.Remove(resourceList[0].Key); } } var moduleQualifiedResourceName = GetModuleQualifiedResourceName(module.Name, module.Version.ToString(), className); ClassCache[moduleQualifiedResourceName] = new Tuple<DSCResourceRunAsCredential, Microsoft.Management.Infrastructure.CimClass>(runAsBehavior, c); ByClassModuleCache[className] = new Tuple<string, Version>(module.Name, module.Version); resourcesFound.Add(className); CreateAndRegisterKeywordFromCimClass(module.Name, module.Version, c, functionsToDefine, runAsBehavior); } }
/// <summary> /// A method to generate a keyword from a CIM class object and register it to DynamicKeyword table. /// </summary> /// <param name="moduleName"></param> /// <param name="moduleVersion"></param> /// <param name="cimClass"></param> /// <param name="functionsToDefine">If true, don't define the keywords, just create the functions.</param> /// <param name="runAsBehavior"> To Specify RunAsBehavior of the class</param> private static void CreateAndRegisterKeywordFromCimClass(string moduleName, Version moduleVersion, Microsoft.Management.Infrastructure.CimClass cimClass, Dictionary<string, ScriptBlock> functionsToDefine, DSCResourceRunAsCredential runAsBehavior) { var keyword = CreateKeywordFromCimClass(moduleName, moduleVersion, cimClass, functionsToDefine, runAsBehavior); if (keyword == null) { return; } // keyword is already defined and we don't allow redefine it if (!CacheResourcesFromMultipleModuleVersions && DynamicKeyword.ContainsKeyword(keyword.Keyword)) { var oldKeyword = DynamicKeyword.GetKeyword(keyword.Keyword); if (oldKeyword.ImplementingModule == null || !oldKeyword.ImplementingModule.Equals(moduleName, StringComparison.OrdinalIgnoreCase) || oldKeyword.ImplementingModuleVersion != moduleVersion) { var e = PSTraceSource.NewInvalidOperationException(ParserStrings.DuplicateKeywordDefinition, keyword.Keyword); e.SetErrorId("DuplicateKeywordDefinition"); throw e; } } // Add the dynamic keyword to the table DynamicKeyword.AddKeyword(keyword); // And now define the driver functions in the current scope... if (functionsToDefine != null) { functionsToDefine[moduleName + "\\" + keyword.Keyword] = CimKeywordImplementationFunction; } }