diff --git a/src/System.Management.Automation/AssemblyInfo.cs b/src/System.Management.Automation/AssemblyInfo.cs
index fe3ee107e5..3c03c22e04 100644
--- a/src/System.Management.Automation/AssemblyInfo.cs
+++ b/src/System.Management.Automation/AssemblyInfo.cs
@@ -13,6 +13,7 @@ using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo(@"Microsoft.PowerShell.Security" + @",PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9")]
[assembly: InternalsVisibleTo(@"System.Management.Automation.Remoting" + @",PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9")]
[assembly: InternalsVisibleTo(@"Microsoft.PowerShell.ConsoleHost" + @",PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9")]
+[assembly: InternalsVisibleTo(@"Microsoft.PowerShell.DscSubsystem" + @",PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9")]
namespace System.Management.Automation
{
diff --git a/src/System.Management.Automation/DscSupport/JsonCimDSCParser.cs b/src/System.Management.Automation/DscSupport/JsonCimDSCParser.cs
deleted file mode 100755
index c2221cb3f3..0000000000
--- a/src/System.Management.Automation/DscSupport/JsonCimDSCParser.cs
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright (c) Microsoft Corporation.
-// Licensed under the MIT License.
-
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.Diagnostics.CodeAnalysis;
-using System.Globalization;
-using System.IO;
-using System.Management.Automation;
-using System.Security;
-
-namespace Microsoft.PowerShell.DesiredStateConfiguration.Internal.CrossPlatform
-{
- ///
- /// Class that does high level Cim schema parsing.
- ///
- internal class CimDSCParser
- {
- private readonly JsonDeserializer _jsonDeserializer;
-
- internal CimDSCParser()
- {
- _jsonDeserializer = JsonDeserializer.Create();
- }
-
- internal IEnumerable ParseSchemaJson(string filePath, bool useNewRunspace = false)
- {
- try
- {
- string json = File.ReadAllText(filePath);
- string fileNameDefiningClass = Path.GetFileNameWithoutExtension(filePath);
- int dotIndex = fileNameDefiningClass.IndexOf(".schema", StringComparison.InvariantCultureIgnoreCase);
- if (dotIndex != -1)
- {
- fileNameDefiningClass = fileNameDefiningClass.Substring(0, dotIndex);
- }
-
- IEnumerable result = _jsonDeserializer.DeserializeClasses(json, useNewRunspace);
- foreach (dynamic classObject in result)
- {
- string superClassName = classObject.SuperClassName;
- string className = classObject.ClassName;
- if (string.Equals(superClassName, "OMI_BaseResource", StringComparison.OrdinalIgnoreCase))
- {
- // Get the name of the file without schema.mof/json extension
- if (!className.Equals(fileNameDefiningClass, StringComparison.OrdinalIgnoreCase))
- {
- PSInvalidOperationException e = PSTraceSource.NewInvalidOperationException(
- ParserStrings.ClassNameNotSameAsDefiningFile, className, fileNameDefiningClass);
- throw e;
- }
- }
- }
-
- return result;
- }
- catch (Exception exception)
- {
- PSInvalidOperationException e = PSTraceSource.NewInvalidOperationException(
- exception, ParserStrings.CimDeserializationError, filePath);
-
- e.SetErrorId("CimDeserializationError");
- throw e;
- }
- }
- }
-}
diff --git a/src/System.Management.Automation/DscSupport/JsonDeserializer.cs b/src/System.Management.Automation/DscSupport/JsonDeserializer.cs
deleted file mode 100755
index 319560f0a0..0000000000
--- a/src/System.Management.Automation/DscSupport/JsonDeserializer.cs
+++ /dev/null
@@ -1,72 +0,0 @@
-// Copyright (c) Microsoft Corporation.
-// Licensed under the MIT License.
-
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.Management.Automation;
-using System.Management.Automation.Runspaces;
-
-namespace Microsoft.PowerShell.DesiredStateConfiguration.Internal.CrossPlatform
-{
- internal class JsonDeserializer
- {
- #region Constructors
-
- ///
- /// Instantiates a default deserializer.
- ///
- /// Default deserializer.
- public static JsonDeserializer Create()
- {
- return new JsonDeserializer();
- }
-
- #endregion Constructors
-
- #region Methods
-
- ///
- /// Returns schema of Cim classes from specified json file.
- ///
- /// Json text to deserialize.
- /// If a new runspace should be used.
- /// Deserialized PSObjects.
- public IEnumerable DeserializeClasses(string json, bool useNewRunspace = false)
- {
- if (string.IsNullOrEmpty(json))
- {
- throw new ArgumentNullException(nameof(json));
- }
-
- System.Management.Automation.PowerShell powerShell = null;
-
- if (useNewRunspace)
- {
- // currently using RunspaceMode.NewRunspace will reset PSModulePath env var for the entire process
- // this is something we want to avoid in DSC GuestConfigAgent scenario, so we use following workaround
- var s_iss = InitialSessionState.CreateDefault();
- s_iss.EnvironmentVariables.Add(
- new SessionStateVariableEntry(
- "PSModulePath",
- Environment.GetEnvironmentVariable("PSModulePath"),
- description: null));
- powerShell = System.Management.Automation.PowerShell.Create(s_iss);
- }
- else
- {
- powerShell = System.Management.Automation.PowerShell.Create(RunspaceMode.CurrentRunspace);
- }
-
- using (powerShell)
- {
- return powerShell.AddCommand("Microsoft.PowerShell.Utility\\ConvertFrom-Json")
- .AddParameter("InputObject", json)
- .AddParameter("Depth", 100) // maximum supported by cmdlet
- .Invoke();
- }
- }
-
- #endregion Methods
- }
-}
diff --git a/src/System.Management.Automation/DscSupport/JsonDscClassCache.cs b/src/System.Management.Automation/DscSupport/JsonDscClassCache.cs
deleted file mode 100755
index dfda9b8460..0000000000
--- a/src/System.Management.Automation/DscSupport/JsonDscClassCache.cs
+++ /dev/null
@@ -1,2503 +0,0 @@
-// Copyright (c) Microsoft Corporation.
-// Licensed under the MIT License.
-
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.Collections.ObjectModel;
-using System.Diagnostics;
-using System.Diagnostics.CodeAnalysis;
-using System.Globalization;
-using System.IO;
-using System.Linq;
-using System.Management.Automation;
-using System.Management.Automation.Language;
-using System.Reflection;
-using System.Runtime.InteropServices;
-using System.Security;
-using System.Text;
-using System.Text.RegularExpressions;
-
-using Microsoft.PowerShell.Commands;
-
-namespace Microsoft.PowerShell.DesiredStateConfiguration.Internal.CrossPlatform
-{
- ///
- /// Class that defines Dsc cache entries.
- ///
- internal class DscClassCacheEntry
- {
- ///
- /// Initializes a new instance of the class.
- ///
- public DscClassCacheEntry()
- : this(DSCResourceRunAsCredential.Default, isImportedImplicitly: false, cimClassInstance: null, modulePath: string.Empty)
- {
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// Run as credential value.
- /// Resource is imported implicitly.
- /// Class definition.
- /// Path of module defining the class.
- public DscClassCacheEntry(DSCResourceRunAsCredential dscResourceRunAsCredential, bool isImportedImplicitly, PSObject cimClassInstance, string modulePath)
- {
- DscResRunAsCred = dscResourceRunAsCredential;
- IsImportedImplicitly = isImportedImplicitly;
- CimClassInstance = cimClassInstance;
- ModulePath = modulePath;
- }
-
- ///
- /// Gets or sets the RunAs Credentials that this DSC resource will use.
- ///
- public DSCResourceRunAsCredential DscResRunAsCred { get; set; }
-
- ///
- /// Gets or sets a value indicating if we have implicitly imported this resource.
- ///
- public bool IsImportedImplicitly { get; set; }
-
- ///
- /// Gets or sets CimClass instance for this resource.
- ///
- public PSObject CimClassInstance { get; set; }
-
- ///
- /// Gets or sets path of the implementing module for this resource.
- ///
- public string ModulePath { get; set; }
- }
-
- ///
- /// DSC class cache for this runspace.
- ///
- [SuppressMessage("Microsoft.MSInternal", "CA903:InternalNamespaceShouldNotContainPublicTypes",
- Justification = "Needed Internal use only")]
- public static class DscClassCache
- {
- private static readonly HashSet s_reservedDynamicKeywords = new HashSet(new[] { "Synchronization", "Certificate", "IIS", "SQL" }, StringComparer.OrdinalIgnoreCase);
-
- private static readonly HashSet s_reservedProperties = new HashSet(new[] { "Require", "Trigger", "Notify", "Before", "After", "Subscribe" }, StringComparer.OrdinalIgnoreCase);
-
- ///
- /// Experimental feature name for DSC v3.
- ///
- public const string DscExperimentalFeatureName = "PS7DscSupport";
-
- private static readonly PSTraceSource s_tracer = PSTraceSource.GetTracer("DSC", "DSC Class Cache");
-
- // Constants for items in the module qualified name (Module\Version\ClassName)
- private const int ModuleNameIndex = 0;
- private const int ModuleVersionIndex = 1;
- private const int ClassNameIndex = 2;
- private const int FriendlyNameIndex = 3;
-
- // Create a HashSet for fast lookup. According to MSDN, the time complexity of search for an element in a HashSet is O(1)
- private static readonly HashSet s_hiddenResourceCache =
- new HashSet(StringComparer.OrdinalIgnoreCase) { "MSFT_BaseConfigurationProviderRegistration", "MSFT_CimConfigurationProviderRegistration", "MSFT_PSConfigurationProviderRegistration" };
-
- ///
- /// Gets a collection to prevent circular importing case when Import-DscResource does not have a module specified.
- ///
- private static HashSet CurrentImportDscResourceInvocations
- => t_currentImportDscResourceInvocations ??= new HashSet(StringComparer.OrdinalIgnoreCase);
-
- [ThreadStatic]
- private static HashSet t_currentImportDscResourceInvocations;
-
- ///
- /// Gets DSC class cache for this runspace.
- /// Cache stores the DSCRunAsBehavior, cim class and boolean to indicate if an Inbox resource has been implicitly imported.
- ///
- private static Dictionary ClassCache
- {
- get => t_classCache ??= new Dictionary(StringComparer.OrdinalIgnoreCase);
- }
-
- [ThreadStatic]
- private static Dictionary t_classCache;
-
- ///
- /// Gets DSC class cache for GuestConfig; it is similar to ClassCache, but maintains values between operations.
- ///
- private static Dictionary GuestConfigClassCache
- {
- get => t_guestConfigClassCache ??= new Dictionary(StringComparer.OrdinalIgnoreCase);
- }
-
- [ThreadStatic]
- private static Dictionary t_guestConfigClassCache;
-
- ///
- /// DSC classname to source module mapper.
- ///
- private static Dictionary> ByClassModuleCache
- => t_byClassModuleCache ??= new Dictionary>(StringComparer.OrdinalIgnoreCase);
-
- [ThreadStatic]
- private static Dictionary> t_byClassModuleCache;
-
- ///
- /// Default ModuleName and ModuleVersion to use.
- ///
- private static readonly Tuple s_defaultModuleInfoForResource = new Tuple("PSDesiredStateConfiguration", new Version(3, 0));
-
- ///
- /// When this property is set to true, DSC Cache will cache multiple versions of a resource.
- /// That means it will cache duplicate resource classes (class names for a resource in two different module versions are same).
- /// NOTE: This property should be set to false for DSC compiler related methods/functionality, such as Import-DscResource,
- /// because the Mof serializer does not support deserialization of classes with different versions.
- ///
- [ThreadStatic]
- private static bool t_cacheResourcesFromMultipleModuleVersions;
-
- private static bool CacheResourcesFromMultipleModuleVersions
- {
- get
- {
- return t_cacheResourcesFromMultipleModuleVersions;
- }
-
- set
- {
- t_cacheResourcesFromMultipleModuleVersions = value;
- }
- }
-
- [ThreadStatic]
- private static bool t_newApiIsUsed = false;
-
- ///
- /// Flag shows if PS7 DSC APIs were used.
- ///
- public static bool NewApiIsUsed
- {
- get
- {
- return t_newApiIsUsed;
- }
-
- set
- {
- t_newApiIsUsed = value;
- }
- }
-
- ///
- /// Initialize the class cache with the default classes in $ENV:SystemDirectory\Configuration.
- ///
- public static void Initialize()
- {
- Initialize(errors: null, modulePathList: null);
- }
-
- ///
- /// Initialize the class cache with default classes that come with PSDesiredStateConfiguration module.
- ///
- /// Collection of any errors encountered during initialization.
- /// List of module path from where DSC PS modules will be loaded.
- public static void Initialize(Collection errors, List modulePathList)
- {
- s_tracer.WriteLine("Initializing DSC class cache");
-
- // Load the base schema files.
- ClearCache();
- var dscConfigurationDirectory = Environment.GetEnvironmentVariable("DSC_HOME");
- if (string.IsNullOrEmpty(dscConfigurationDirectory))
- {
- var moduleInfos = ModuleCmdletBase.GetModuleIfAvailable(new Microsoft.PowerShell.Commands.ModuleSpecification()
- {
- Name = "PSDesiredStateConfiguration",
-
- // Version in the next line is actually MinimumVersion
- Version = new Version(3, 0, 0)
- });
-
- if (moduleInfos.Count > 0)
- {
- // to be consistent with Import-Module behavior, we use the first occurrence that we find in PSModulePath
- var moduleDirectory = Path.GetDirectoryName(moduleInfos[0].Path);
- dscConfigurationDirectory = Path.Join(moduleDirectory, "Configuration");
- }
- else
- {
- // when all else has failed use location of system-wide PS module directory (i.e. /usr/local/share/powershell/Modules) as backup
- dscConfigurationDirectory = Path.Join(ModuleIntrinsics.GetSharedModulePath(), "PSDesiredStateConfiguration", "Configuration");
- }
- }
-
- if (!Directory.Exists(dscConfigurationDirectory))
- {
- throw new DirectoryNotFoundException(string.Format(ParserStrings.PsDscMissingSchemaStore, dscConfigurationDirectory));
- }
-
- var resourceBaseFile = Path.Join(dscConfigurationDirectory, "BaseRegistration", "BaseResource.schema.json");
- ImportBaseClasses(resourceBaseFile, s_defaultModuleInfoForResource, errors, false);
- var metaConfigFile = Path.Join(dscConfigurationDirectory, "BaseRegistration", "MSFT_DSCMetaConfiguration.json");
- ImportBaseClasses(metaConfigFile, s_defaultModuleInfoForResource, errors, false);
- }
-
- ///
- /// Import base classes from the given file.
- ///
- /// Path to schema file.
- /// Module information.
- /// Error collection that will be shown to the user.
- /// Flag for implicitly imported resource.
- /// Class objects from schema file.
- public static IEnumerable ImportBaseClasses(string path, Tuple moduleInfo, Collection errors, bool importInBoxResourcesImplicitly)
- {
- if (string.IsNullOrEmpty(path))
- {
- throw PSTraceSource.NewArgumentNullException(nameof(path));
- }
-
- s_tracer.WriteLine("DSC ClassCache: importing file: {0}", path);
-
- var parser = new CimDSCParser();
-
- IEnumerable classes = null;
- try
- {
- classes = parser.ParseSchemaJson(path);
- }
- catch (PSInvalidOperationException e)
- {
- // Ignore modules with invalid schemas.
- s_tracer.WriteLine("DSC ClassCache: Error importing file '{0}', with error '{1}'. Skipping file.", path, e);
- if (errors != null)
- {
- errors.Add(e);
- }
- }
-
- if (classes != null)
- {
- foreach (dynamic c in classes)
- {
- var className = c.ClassName;
-
- if (string.IsNullOrEmpty(className))
- {
- // ClassName is empty - skipping class import
- continue;
- }
-
- 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))
- {
- if (errors != null)
- {
- PSInvalidOperationException e = PSTraceSource.NewInvalidOperationException(
- ParserStrings.DuplicateCimClassDefinition, className, path, cimClassInfo.ModulePath);
-
- e.SetErrorId("DuplicateCimClassDefinition");
- errors.Add(e);
- }
-
- continue;
- }
-
- if (s_hiddenResourceCache.Contains(className))
- {
- continue;
- }
-
- var classCacheEntry = new DscClassCacheEntry(DSCResourceRunAsCredential.NotSupported, importInBoxResourcesImplicitly, c, path);
- ClassCache[moduleQualifiedResourceName] = classCacheEntry;
- GuestConfigClassCache[moduleQualifiedResourceName] = classCacheEntry;
- ByClassModuleCache[className] = moduleInfo;
- }
-
- var sb = new System.Text.StringBuilder();
- foreach (dynamic c in classes)
- {
- sb.Append(c.ClassName);
- sb.Append(',');
- }
-
- s_tracer.WriteLine("DSC ClassCache: loading file '{0}' added the following classes to the cache: {1}", path, sb.ToString());
- }
- else
- {
- s_tracer.WriteLine("DSC ClassCache: loading file '{0}' added no classes to the cache.");
- }
-
- return classes;
- }
-
- ///
- /// Get text from SecureString.
- ///
- /// Value of SecureString.
- /// Decoded string.
- public static string GetStringFromSecureString(SecureString value)
- {
- string passwordValueToAdd = string.Empty;
-
- if (value != null)
- {
- IntPtr ptr = Marshal.SecureStringToCoTaskMemUnicode(value);
- passwordValueToAdd = Marshal.PtrToStringUni(ptr);
- Marshal.ZeroFreeCoTaskMemUnicode(ptr);
- }
-
- return passwordValueToAdd;
- }
-
- ///
- /// Clear out the existing collection of CIM classes and associated keywords.
- ///
- public static void ClearCache()
- {
- if (!ExperimentalFeature.IsEnabled(DscExperimentalFeatureName))
- {
- throw new InvalidOperationException(ParserStrings.PS7DscSupportDisabled);
- }
-
- s_tracer.WriteLine("DSC class: clearing the cache and associated keywords.");
- ClassCache.Clear();
- ByClassModuleCache.Clear();
- CacheResourcesFromMultipleModuleVersions = false;
- CurrentImportDscResourceInvocations.Clear();
- }
-
- private static string GetModuleQualifiedResourceName(string moduleName, string moduleVersion, string className, string resourceName)
- {
- return string.Format(CultureInfo.InvariantCulture, "{0}\\{1}\\{2}\\{3}", moduleName, moduleVersion, className, resourceName);
- }
-
- 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[ClassNameIndex]
- let cachedModuleName = splittedName[ModuleNameIndex]
- let cachedResourceName = splittedName[FriendlyNameIndex]
- where (string.Equals(cachedResourceName, resourceName, StringComparison.OrdinalIgnoreCase)
- || (string.Equals(cachedClassName, className, StringComparison.OrdinalIgnoreCase)
- && string.Equals(cachedModuleName, moduleName, StringComparison.OrdinalIgnoreCase)))
- select cacheEntry).ToList();
- }
-
- ///
- /// Returns class declaration from GuestConfigClassCache.
- ///
- /// Module name.
- /// Module version.
- /// Name of the class.
- /// Friendly name of the resource.
- /// Class declaration from cache.
- public static PSObject GetGuestConfigCachedClass(string moduleName, string moduleVersion, string className, string resourceName)
- {
- if (!ExperimentalFeature.IsEnabled(DscExperimentalFeatureName))
- {
- throw new InvalidOperationException(ParserStrings.PS7DscSupportDisabled);
- }
-
- var moduleQualifiedResourceName = GetModuleQualifiedResourceName(moduleName, moduleVersion, className, string.IsNullOrEmpty(resourceName) ? className : resourceName);
- DscClassCacheEntry classCacheEntry = null;
- if (GuestConfigClassCache.TryGetValue(moduleQualifiedResourceName, out classCacheEntry))
- {
- return classCacheEntry.CimClassInstance;
- }
- else
- {
- // if class was not found with current ResourceName then it may be a class with non-empty FriendlyName that caller does not know, so perform a broad search
- string partialClassPath = string.Join('\\', moduleName, moduleVersion, className, string.Empty);
- foreach (string key in GuestConfigClassCache.Keys)
- {
- if (key.StartsWith(partialClassPath))
- {
- return GuestConfigClassCache[key].CimClassInstance;
- }
- }
-
- return null;
- }
- }
-
- ///
- /// Clears GuestConfigClassCache.
- ///
- public static void ClearGuestConfigClassCache()
- {
- GuestConfigClassCache.Clear();
- }
-
- private static bool IsMagicProperty(string propertyName)
- {
- return System.Text.RegularExpressions.Regex.Match(propertyName, "^(ResourceId|SourceInfo|ModuleName|ModuleVersion|ConfigurationName)$", System.Text.RegularExpressions.RegexOptions.IgnoreCase).Success;
- }
-
- private static string GetFriendlyName(dynamic cimClass)
- {
- return cimClass.FriendlyName;
- }
-
- ///
- /// Method to get the cached classes in the form of DynamicKeyword.
- ///
- /// Dynamic keyword collection.
- public static Collection GetKeywordsFromCachedClasses()
- {
- if (!ExperimentalFeature.IsEnabled(DscExperimentalFeatureName))
- {
- throw new InvalidOperationException(ParserStrings.PS7DscSupportDisabled);
- }
-
- Collection keywords = new Collection();
-
- foreach (KeyValuePair cachedClass in ClassCache)
- {
- string[] splittedName = cachedClass.Key.Split(Utils.Separators.Backslash);
- string moduleName = splittedName[ModuleNameIndex];
- string moduleVersion = splittedName[ModuleVersionIndex];
-
- var keyword = CreateKeywordFromCimClass(moduleName, Version.Parse(moduleVersion), cachedClass.Value.CimClassInstance, cachedClass.Value.DscResRunAsCred);
- if (keyword is not null)
- {
- keywords.Add(keyword);
- }
- }
-
- return keywords;
- }
-
- private static void CreateAndRegisterKeywordFromCimClass(string moduleName, Version moduleVersion, PSObject cimClass, Dictionary functionsToDefine, DSCResourceRunAsCredential runAsBehavior)
- {
- var keyword = CreateKeywordFromCimClass(moduleName, moduleVersion, cimClass, runAsBehavior);
- if (keyword is 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 is 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;
- }
- }
-
- private static DynamicKeyword CreateKeywordFromCimClass(string moduleName, Version moduleVersion, dynamic cimClass, DSCResourceRunAsCredential runAsBehavior)
- {
- var resourceName = cimClass.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 (s_reservedDynamicKeywords.Contains(keywordString))
- {
- keyword.IsReservedKeyword = true;
- }
-
- // see if it's a resource type i.e. it inherits from OMI_BaseResource
- bool isResourceType = false;
-
- // previous version of this code was the only place that referenced CimSuperClass
- // so to simplify things we just check superclass to be OMI_BaseResource
- // with assumption that current code will not work for multi-level class inheritance (which is never used in practice according to DSC team)
- // this simplification allows us to avoid linking objects together using CimSuperClass field during deserialization
- if ((!string.IsNullOrEmpty(cimClass.SuperClassName)) && string.Equals("OMI_BaseResource", cimClass.SuperClassName, StringComparison.OrdinalIgnoreCase))
- {
- isResourceType = true;
- }
-
- // 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
- if (cimClass.ClassProperties != null)
- {
- foreach (var prop in cimClass.ClassProperties)
- {
- // If the property has the Read qualifier, skip it.
- if (string.Equals(prop.Qualifiers?.Read?.ToString(), "True", StringComparison.OrdinalIgnoreCase))
- {
- 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 (s_reservedProperties.Contains(prop.Name))
- {
- keyword.HasReservedProperties = true;
- continue;
- }
-
- // Otherwise, add it to the Keyword List.
- var keyProp = new System.Management.Automation.Language.DynamicKeywordProperty();
- keyProp.Name = prop.Name;
-
- // 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 == "Instance" && !referenceClassNameIsNullOrEmpty)
- {
- keyProp.TypeConstraint = prop.ReferenceClassName;
- }
- else if (prop.CimType == "InstanceArray" && !referenceClassNameIsNullOrEmpty)
- {
- keyProp.TypeConstraint = prop.ReferenceClassName + "[]";
- }
- else
- {
- keyProp.TypeConstraint = prop.CimType.ToString();
- }
-
- // Check to see if there is a Values attribute and save the list of allowed values if so.
- var values = prop.Qualifiers?.Values;
- if (values is not null)
- {
- foreach (var val in values)
- {
- keyProp.Values.Add(val.ToString());
- }
- }
-
- // Check to see if there is a ValueMap attribute and save the list of allowed values if so.
- var nativeValueMap = prop.Qualifiers?.ValueMap;
- List valueMap = null;
- if (nativeValueMap is not null)
- {
- valueMap = new List();
- foreach (var val in nativeValueMap)
- {
- valueMap.Add(val.ToString());
- }
- }
-
- // Check to see if this property has the Required qualifier associated with it.
- if (string.Equals(prop.Qualifiers?.Required?.ToString(), "True", StringComparison.OrdinalIgnoreCase))
- {
- keyProp.Mandatory = true;
- }
-
- // Check to see if this property has the Key qualifier associated with it.
- if (string.Equals(prop.Qualifiers?.Key?.ToString(), "True", StringComparison.OrdinalIgnoreCase))
- {
- keyProp.Mandatory = true;
- keyProp.IsKey = 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 is not null && keyProp.Values.Count > 0)
- {
- if (valueMap.Count != 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.Count,
- keyword.Keyword);
- return null;
- }
-
- for (int index = 0; index < valueMap.Count; 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 UpdateKnownRestriction(DynamicKeyword keyword)
- {
- const int RefreshFrequencyMin = 30;
- const int RefreshFrequencyMax = 44640;
-
- const int ConfigurationModeFrequencyMin = 15;
- const int ConfigurationModeFrequencyMax = 44640;
-
- if (
- string.Equals(
- keyword.ResourceName,
- "MSFT_DSCMetaConfigurationV2",
- StringComparison.OrdinalIgnoreCase)
- ||
- string.Equals(
- keyword.ResourceName,
- "MSFT_DSCMetaConfiguration",
- StringComparison.OrdinalIgnoreCase))
- {
- if (keyword.Properties["RefreshFrequencyMins"] is not null)
- {
- keyword.Properties["RefreshFrequencyMins"].Range = new Tuple(RefreshFrequencyMin, RefreshFrequencyMax);
- }
-
- if (keyword.Properties["ConfigurationModeFrequencyMins"] != null)
- {
- keyword.Properties["ConfigurationModeFrequencyMins"].Range = new Tuple(ConfigurationModeFrequencyMin, ConfigurationModeFrequencyMax);
- }
-
- if (keyword.Properties["DebugMode"] is not null)
- {
- keyword.Properties["DebugMode"].Values.Remove("ResourceScriptBreakAll");
- keyword.Properties["DebugMode"].ValueMap.Remove("ResourceScriptBreakAll");
- }
- }
- }
-
- ///
- /// Load the default system CIM classes and create the corresponding keywords.
- ///
- /// Collection of any errors encountered while loading keywords.
- public static void LoadDefaultCimKeywords(Collection errors)
- {
- LoadDefaultCimKeywords(functionsToDefine: null, errors, modulePathList: null, cacheResourcesFromMultipleModuleVersions: false);
- }
-
- ///
- /// Load the default system CIM classes and create the corresponding keywords.
- ///
- /// A dictionary to add the defined functions to, may be null.
- public static void LoadDefaultCimKeywords(Dictionary functionsToDefine)
- {
- LoadDefaultCimKeywords(functionsToDefine, errors: null, modulePathList: null, cacheResourcesFromMultipleModuleVersions: false);
- }
-
- ///
- /// Load the default system CIM classes and create the corresponding keywords.
- ///
- /// Collection of any errors encountered while loading keywords.
- /// Allow caching the resources from multiple versions of modules.
- public static void LoadDefaultCimKeywords(Collection errors, bool cacheResourcesFromMultipleModuleVersions)
- {
- LoadDefaultCimKeywords(functionsToDefine: null, errors, modulePathList: null, cacheResourcesFromMultipleModuleVersions);
- }
-
- ///
- /// Load the default system CIM classes and create the corresponding keywords.
- ///
- /// A dictionary to add the defined functions to, may be null.
- /// Collection of any errors encountered while loading keywords.
- /// List of module path from where DSC PS modules will be loaded.
- /// Allow caching the resources from multiple versions of modules.
- private static void LoadDefaultCimKeywords(
- Dictionary functionsToDefine,
- Collection errors,
- List modulePathList,
- bool cacheResourcesFromMultipleModuleVersions)
- {
- if (!ExperimentalFeature.IsEnabled(DscExperimentalFeatureName))
- {
- Exception exception = new InvalidOperationException(ParserStrings.PS7DscSupportDisabled);
- errors.Add(exception);
- return;
- }
-
- NewApiIsUsed = true;
- DynamicKeyword.Reset();
- Initialize(errors, modulePathList);
-
- // Initialize->ClearCache resets CacheResourcesFromMultipleModuleVersions to false,
- // workaround is to set it after Initialize method call.
- // Initialize method imports all the Inbox resources and internal classes which belongs to only one version
- // of the module, so it is ok if this property is not set during cache initialization.
- CacheResourcesFromMultipleModuleVersions = cacheResourcesFromMultipleModuleVersions;
-
- foreach (dynamic cimClass in ClassCache.Values)
- {
- var className = cimClass.CimClassInstance.ClassName;
- var moduleInfo = ByClassModuleCache[className];
- CreateAndRegisterKeywordFromCimClass(moduleInfo.Item1, moduleInfo.Item2, cimClass.CimClassInstance, functionsToDefine, cimClass.DscResRunAsCred);
- }
-
- // And add the Node keyword definitions
- if (!DynamicKeyword.ContainsKeyword("Node"))
- {
- // Implement dispatch to the Node keyword.
- var nodeKeyword = new DynamicKeyword()
- {
- BodyMode = DynamicKeywordBodyMode.ScriptBlock,
- ImplementingModule = s_defaultModuleInfoForResource.Item1,
- ImplementingModuleVersion = s_defaultModuleInfoForResource.Item2,
- NameMode = DynamicKeywordNameMode.NameRequired,
- Keyword = "Node",
- };
- DynamicKeyword.AddKeyword(nodeKeyword);
- }
-
- // And add the Import-DscResource keyword definitions
- if (!DynamicKeyword.ContainsKeyword("Import-DscResource"))
- {
- // Implement dispatch to the Node keyword.
- var nodeKeyword = new DynamicKeyword()
- {
- BodyMode = DynamicKeywordBodyMode.Command,
- ImplementingModule = s_defaultModuleInfoForResource.Item1,
- ImplementingModuleVersion = s_defaultModuleInfoForResource.Item2,
- NameMode = DynamicKeywordNameMode.NoName,
- Keyword = "Import-DscResource",
- MetaStatement = true,
- PostParse = ImportResourcePostParse,
- SemanticCheck = ImportResourceCheckSemantics
- };
- DynamicKeyword.AddKeyword(nodeKeyword);
- }
- }
-
- // This function is called after parsing the Import-DscResource keyword and it's arguments, but before parsing anything else.
- private static ParseError[] ImportResourcePostParse(DynamicKeywordStatementAst ast)
- {
- var elements = Ast.CopyElements(ast.CommandElements);
- var commandAst = new CommandAst(ast.Extent, elements, TokenKind.Unknown, null);
-
- const string NameParam = "Name";
- const string ModuleNameParam = "ModuleName";
- const string ModuleVersionParam = "ModuleVersion";
-
- StaticBindingResult bindingResult = StaticParameterBinder.BindCommand(commandAst, false);
-
- var errorList = new List();
- foreach (var bindingException in bindingResult.BindingExceptions.Values)
- {
- errorList.Add(new ParseError(bindingException.CommandElement.Extent, "ParameterBindingException", bindingException.BindingException.Message));
- }
-
- ParameterBindingResult moduleNameBindingResult = null;
- ParameterBindingResult resourceNameBindingResult = null;
- ParameterBindingResult moduleVersionBindingResult = null;
-
- foreach (var binding in bindingResult.BoundParameters)
- {
- // Error case when positional parameter values are specified
- var boundParameterName = binding.Key;
- var parameterBindingResult = binding.Value;
- if (boundParameterName.All(char.IsDigit))
- {
- errorList.Add(new ParseError(parameterBindingResult.Value.Extent, "ImportDscResourcePositionalParamsNotSupported", string.Format(CultureInfo.CurrentCulture, ParserStrings.ImportDscResourcePositionalParamsNotSupported)));
- continue;
- }
-
- if (NameParam.StartsWith(boundParameterName, StringComparison.OrdinalIgnoreCase))
- {
- resourceNameBindingResult = parameterBindingResult;
- }
- else if (ModuleNameParam.StartsWith(boundParameterName, StringComparison.OrdinalIgnoreCase))
- {
- moduleNameBindingResult = parameterBindingResult;
- }
- else if (ModuleVersionParam.StartsWith(boundParameterName, StringComparison.OrdinalIgnoreCase))
- {
- moduleVersionBindingResult = parameterBindingResult;
- }
- else
- {
- errorList.Add(new ParseError(parameterBindingResult.Value.Extent, "ImportDscResourceNeedParams", string.Format(CultureInfo.CurrentCulture, ParserStrings.ImportDscResourceNeedParams)));
- }
- }
-
- if (errorList.Count == 0 && moduleNameBindingResult == null && resourceNameBindingResult == null)
- {
- errorList.Add(new ParseError(ast.Extent, "ImportDscResourceNeedParams", string.Format(CultureInfo.CurrentCulture, ParserStrings.ImportDscResourceNeedParams)));
- }
-
- // Check here if Version is specified but modulename is not specified
- if (moduleVersionBindingResult != null && moduleNameBindingResult == null)
- {
- // only add this error again to the error list if resources is not null
- // if resources and modules are both null we have already added this error in collection
- // we do not want to do this twice. since we are giving same error ImportDscResourceNeedParams in both cases
- // once we have different error messages for 2 scenarios we can remove this check
- if (resourceNameBindingResult is not null)
- {
- errorList.Add(new ParseError(ast.Extent, "ImportDscResourceNeedModuleNameWithModuleVersion", string.Format(CultureInfo.CurrentCulture, ParserStrings.ImportDscResourceNeedParams)));
- }
- }
-
- string[] resourceNames = null;
- if (resourceNameBindingResult is not null)
- {
- object resourceName = null;
- if (!IsConstantValueVisitor.IsConstant(resourceNameBindingResult.Value, out resourceName, true, true) ||
- !LanguagePrimitives.TryConvertTo(resourceName, out resourceNames))
- {
- errorList.Add(new ParseError(resourceNameBindingResult.Value.Extent, "RequiresInvalidStringArgument", string.Format(CultureInfo.CurrentCulture, ParserStrings.RequiresInvalidStringArgument, NameParam)));
- }
- }
-
- System.Version moduleVersion = null;
- if (moduleVersionBindingResult is not null)
- {
- object moduleVer = null;
- if (!IsConstantValueVisitor.IsConstant(moduleVersionBindingResult.Value, out moduleVer, true, true))
- {
- errorList.Add(new ParseError(moduleVersionBindingResult.Value.Extent, "RequiresArgumentMustBeConstant", ParserStrings.RequiresArgumentMustBeConstant));
- }
-
- if (moduleVer is double)
- {
- // this happens in case -ModuleVersion 1.0, then use extent text for that.
- // The better way to do it would be define static binding API against CommandInfo, that holds information about parameter types.
- // This way, we can avoid this ugly special-casing and say that -ModuleVersion has type [System.Version].
- moduleVer = moduleVersionBindingResult.Value.Extent.Text;
- }
-
- if (!LanguagePrimitives.TryConvertTo(moduleVer, out moduleVersion))
- {
- errorList.Add(new ParseError(moduleVersionBindingResult.Value.Extent, "RequiresVersionInvalid", ParserStrings.RequiresVersionInvalid));
- }
- }
-
- ModuleSpecification[] moduleSpecifications = null;
- if (moduleNameBindingResult is not null)
- {
- object moduleName = null;
- if (!IsConstantValueVisitor.IsConstant(moduleNameBindingResult.Value, out moduleName, true, true))
- {
- errorList.Add(new ParseError(moduleNameBindingResult.Value.Extent, "RequiresArgumentMustBeConstant", ParserStrings.RequiresArgumentMustBeConstant));
- }
-
- if (LanguagePrimitives.TryConvertTo(moduleName, out moduleSpecifications))
- {
- // if resourceNames are specified then we can not specify multiple modules name
- if (moduleSpecifications is not null && moduleSpecifications.Length > 1 && resourceNames is not null)
- {
- errorList.Add(new ParseError(moduleNameBindingResult.Value.Extent, "ImportDscResourceMultipleModulesNotSupportedWithName", string.Format(CultureInfo.CurrentCulture, ParserStrings.ImportDscResourceMultipleModulesNotSupportedWithName)));
- }
-
- // if moduleversion is specified then we can not specify multiple modules name
- if (moduleSpecifications is not null && moduleSpecifications.Length > 1 && moduleVersion is not null)
- {
- errorList.Add(new ParseError(moduleNameBindingResult.Value.Extent, "ImportDscResourceMultipleModulesNotSupportedWithVersion", string.Format(CultureInfo.CurrentCulture, ParserStrings.ImportDscResourceNeedParams)));
- }
-
- // if moduleversion is specified then we can not specify another version in modulespecification object of ModuleName
- if (moduleSpecifications is not null && (moduleSpecifications[0].Version is not null || moduleSpecifications[0].MaximumVersion is not null) && moduleVersion is not null)
- {
- errorList.Add(new ParseError(moduleNameBindingResult.Value.Extent, "ImportDscResourceMultipleModuleVersionsNotSupported", string.Format(CultureInfo.CurrentCulture, ParserStrings.ImportDscResourceNeedParams)));
- }
-
- // If moduleVersion is specified we have only one module Name in valid scenario
- // So update it's version property in module specification object that will be used to load modules
- if (moduleSpecifications is not null && moduleSpecifications[0].Version is null && moduleSpecifications[0].MaximumVersion is null && moduleVersion is not null)
- {
- moduleSpecifications[0].Version = moduleVersion;
- }
- }
- else
- {
- errorList.Add(new ParseError(moduleNameBindingResult.Value.Extent, "RequiresInvalidStringArgument", string.Format(CultureInfo.CurrentCulture, ParserStrings.RequiresInvalidStringArgument, ModuleNameParam)));
- }
- }
-
- if (errorList.Count == 0)
- {
- // No errors, try to load the resources
- LoadResourcesFromModuleInImportResourcePostParse(ast.Extent, moduleSpecifications, resourceNames, errorList);
- }
-
- return errorList.ToArray();
- }
-
- // This function performs semantic checks for Import-DscResource
- private static ParseError[] ImportResourceCheckSemantics(DynamicKeywordStatementAst ast)
- {
- List errorList = null;
-
- var keywordAst = Ast.GetAncestorAst(ast.Parent);
- while (keywordAst is not null)
- {
- if (keywordAst.Keyword.Keyword.Equals("Node"))
- {
- if (errorList is null)
- {
- errorList = new List();
- }
-
- errorList.Add(new ParseError(ast.Extent, "ImportDscResourceInsideNode", string.Format(CultureInfo.CurrentCulture, ParserStrings.ImportDscResourceInsideNode)));
- break;
- }
-
- keywordAst = Ast.GetAncestorAst(keywordAst.Parent);
- }
-
- if (errorList is not null)
- {
- return errorList.ToArray();
- }
- else
- {
- return null;
- }
- }
-
- // This function performs semantic checks for all DSC Resources keywords.
- private static ParseError[] CheckMandatoryPropertiesPresent(DynamicKeywordStatementAst ast)
- {
- HashSet mandatoryPropertiesNames = new HashSet(StringComparer.OrdinalIgnoreCase);
- foreach (var pair in ast.Keyword.Properties)
- {
- if (pair.Value.Mandatory)
- {
- mandatoryPropertiesNames.Add(pair.Key);
- }
- }
-
- // by design mandatoryPropertiesNames are not empty at this point:
- // every resource must have at least one Key property.
- HashtableAst hashtableAst = null;
- foreach (var commandElementsAst in ast.CommandElements)
- {
- hashtableAst = commandElementsAst as HashtableAst;
- if (hashtableAst != null)
- {
- break;
- }
- }
-
- if (hashtableAst is null)
- {
- // nothing to validate
- return null;
- }
-
- foreach (var pair in hashtableAst.KeyValuePairs)
- {
- object evalResultObject;
- if (IsConstantValueVisitor.IsConstant(pair.Item1, out evalResultObject, forAttribute: false, forRequires: false))
- {
- var presentName = evalResultObject as string;
- if (presentName is not null)
- {
- if (mandatoryPropertiesNames.Remove(presentName) && mandatoryPropertiesNames.Count == 0)
- {
- // optimization, once all mandatory properties are specified, we can safely exit.
- return null;
- }
- }
- }
- }
-
- if (mandatoryPropertiesNames.Count > 0)
- {
- ParseError[] errors = new ParseError[mandatoryPropertiesNames.Count];
- var extent = ast.CommandElements[0].Extent;
- int i = 0;
- foreach (string name in mandatoryPropertiesNames)
- {
- errors[i] = new ParseError(
- extent,
- "MissingValueForMandatoryProperty",
- string.Format(
- CultureInfo.CurrentCulture,
- ParserStrings.MissingValueForMandatoryProperty,
- ast.Keyword.Keyword,
- ast.Keyword.Properties.First(p => StringComparer.OrdinalIgnoreCase.Equals(p.Value.Name, name)).Value.TypeConstraint,
- name));
- i++;
- }
-
- return errors;
- }
-
- return null;
- }
-
- ///
- /// Load DSC resources from specified module.
- ///
- /// Script statement loading the module, can be null.
- /// Module information, can be null.
- /// Name of the resource to be loaded from module.
- /// List of errors reported by the method.
- internal static void LoadResourcesFromModuleInImportResourcePostParse(
- IScriptExtent scriptExtent,
- ModuleSpecification[] moduleSpecifications,
- string[] resourceNames,
- List errorList)
- {
- // get all required modules
- var modules = new Collection();
- if (moduleSpecifications is not null)
- {
- foreach (var moduleToImport in moduleSpecifications)
- {
- bool foundModule = false;
- var moduleInfos = ModuleCmdletBase.GetModuleIfAvailable(moduleToImport);
-
- if (moduleInfos.Count >= 1 && (moduleToImport.Version is not null || moduleToImport.Guid is not null))
- {
- foreach (var psModuleInfo in moduleInfos)
- {
- if ((moduleToImport.Guid.HasValue && moduleToImport.Guid.Equals(psModuleInfo.Guid)) ||
- (moduleToImport.Version is not null &&
- moduleToImport.Version.Equals(psModuleInfo.Version)))
- {
- modules.Add(psModuleInfo);
- foundModule = true;
- break;
- }
- }
- }
- else if (moduleInfos.Count == 1)
- {
- modules.Add(moduleInfos[0]);
- foundModule = true;
- }
-
- if (!foundModule)
- {
- if (moduleInfos.Count > 1)
- {
- errorList.Add(
- new ParseError(
- scriptExtent,
- "MultipleModuleEntriesFoundDuringParse",
- string.Format(CultureInfo.CurrentCulture, ParserStrings.MultipleModuleEntriesFoundDuringParse, moduleToImport.Name)));
- }
- else
- {
- string moduleString = moduleToImport.Version == null
- ? moduleToImport.Name
- : string.Format(CultureInfo.CurrentCulture, "<{0}, {1}>", moduleToImport.Name, moduleToImport.Version);
-
- errorList.Add(new ParseError(scriptExtent, "ModuleNotFoundDuringParse", string.Format(CultureInfo.CurrentCulture, ParserStrings.ModuleNotFoundDuringParse, moduleString)));
- }
-
- return;
- }
- }
- }
- else if (resourceNames is not null)
- {
- // Lookup the required resources under available PowerShell modules when modulename is not specified
- // Make sure that this is not a circular import/parsing
- var callLocation = string.Join(':', scriptExtent.File, scriptExtent.StartLineNumber, scriptExtent.StartColumnNumber, scriptExtent.Text);
- if (!CurrentImportDscResourceInvocations.Contains(callLocation))
- {
- CurrentImportDscResourceInvocations.Add(callLocation);
- using (var powerShell = System.Management.Automation.PowerShell.Create(RunspaceMode.CurrentRunspace))
- {
- powerShell.AddCommand("Get-Module");
- powerShell.AddParameter("ListAvailable");
- modules = powerShell.Invoke();
- }
- }
- }
-
- // When ModuleName only specified, we need to import all resources from that module
- var resourcesToImport = new List();
- if (resourceNames is null || resourceNames.Length == 0)
- {
- resourcesToImport.Add("*");
- }
- else
- {
- resourcesToImport.AddRange(resourceNames);
- }
-
- foreach (var moduleInfo in modules)
- {
- var resourcesFound = new List();
- var exceptionList = new System.Collections.ObjectModel.Collection();
- LoadPowerShellClassResourcesFromModule(primaryModuleInfo: moduleInfo, moduleInfo: moduleInfo, resourcesToImport: resourcesToImport, resourcesFound: resourcesFound, errorList: exceptionList, functionsToDefine: null, recurse: true, extent: scriptExtent);
- foreach (Exception ex in exceptionList)
- {
- errorList.Add(new ParseError(scriptExtent, "ClassResourcesLoadingFailed", ex.Message));
- }
-
- foreach (var resource in resourcesFound)
- {
- resourcesToImport.Remove(resource);
- }
-
- if (resourcesToImport.Count == 0)
- {
- break;
- }
- }
-
- if (resourcesToImport.Count > 0)
- {
- foreach (var resourceNameToImport in resourcesToImport)
- {
- if (!resourceNameToImport.Contains('*'))
- {
- errorList.Add(new ParseError(scriptExtent, "DscResourcesNotFoundDuringParsing", string.Format(CultureInfo.CurrentCulture, ParserStrings.DscResourcesNotFoundDuringParsing, resourceNameToImport)));
- }
- }
- }
- }
-
- private static void LoadPowerShellClassResourcesFromModule(
- PSModuleInfo primaryModuleInfo,
- PSModuleInfo moduleInfo,
- ICollection resourcesToImport,
- ICollection resourcesFound,
- Collection errorList,
- Dictionary functionsToDefine = null,
- bool recurse = true,
- IScriptExtent extent = null)
- {
- if (primaryModuleInfo._declaredDscResourceExports is null || primaryModuleInfo._declaredDscResourceExports.Count == 0)
- {
- return;
- }
-
- if (moduleInfo.ModuleType == ModuleType.Binary)
- {
- throw PSTraceSource.NewArgumentException("isConfiguration", ParserStrings.ConfigurationNotSupportedInPowerShellCore);
- }
- else
- {
- string scriptPath = null;
- if (moduleInfo.RootModule is not null)
- {
- scriptPath = Path.Join(moduleInfo.ModuleBase, moduleInfo.RootModule);
- }
- else if (moduleInfo.Path is not null)
- {
- scriptPath = moduleInfo.Path;
- }
-
- LoadPowerShellClassResourcesFromModule(scriptPath, primaryModuleInfo, resourcesToImport, resourcesFound, functionsToDefine, errorList, extent);
- }
-
- if (moduleInfo.NestedModules is not null && recurse)
- {
- foreach (var nestedModule in moduleInfo.NestedModules)
- {
- LoadPowerShellClassResourcesFromModule(primaryModuleInfo, nestedModule, resourcesToImport, resourcesFound, errorList, functionsToDefine, recurse: false, extent: extent);
- }
- }
- }
-
- ///
- /// Import class resources from module.
- ///
- /// Module information.
- /// Collection of resources to import.
- /// Functions to define.
- /// List of errors to return.
- /// The list of resources imported from this module.
- public static List ImportClassResourcesFromModule(PSModuleInfo moduleInfo, ICollection resourcesToImport, Dictionary functionsToDefine, Collection errors)
- {
- if (!ExperimentalFeature.IsEnabled(DscExperimentalFeatureName))
- {
- throw new InvalidOperationException(ParserStrings.PS7DscSupportDisabled);
- }
-
- var resourcesImported = new List();
- LoadPowerShellClassResourcesFromModule(moduleInfo, moduleInfo, resourcesToImport, resourcesImported, errors, functionsToDefine);
- return resourcesImported;
- }
-
- internal static PSObject[] GenerateJsonClassesForAst(TypeDefinitionAst typeAst, PSModuleInfo module, DSCResourceRunAsCredential runAsBehavior)
- {
- var embeddedInstanceTypes = new List