private IDscRes DscResApplyConfig(IHasDiagnostics result, IDscRes config,
                                          out bool rebootRequired)
        {
            using var ses = CimSession.Create(config.ComputerName ?? DscRes.DefaultCimHostname);
            using var cls = ses.GetClass(DscRes.DscCimNamespace, config.TypeName);
            using var cim = new CimInstance(DscRes.LcmCimClassName, DscRes.DscCimNamespace);

            var mofBody = DscRes.BuildMof(config, cls);

            _log.LogDebug("Generated MOF:\n{0}", mofBody);
            var mofBodyBytes = DscRes.ToUint8(mofBody);
            var methodParams = new CimMethodParametersCollection
            {
                CimMethodParameter.Create("ModuleName", config.ModuleName, CimFlags.None),
                CimMethodParameter.Create("ResourceType", config.TypeName, CimFlags.None),
                CimMethodParameter.Create("resourceProperty", mofBodyBytes, CimFlags.None),
            };

            CimMethodResult methodResult;

            lock (_dscSync) {
                methodResult = ses.InvokeMethod(cim, "ResourceSet", methodParams);
            }
            rebootRequired = (bool)methodResult.OutParameters["RebootRequired"].Value;

            lock (_dscSync) {
                methodResult = ses.InvokeMethod(cim, "ResourceGet", methodParams);
            }
            var dscResConfigs = (CimInstance)methodResult.OutParameters["configurations"].Value;

            var state = config;

            state.Results = new Dictionary <string, string>();
            foreach (var p in dscResConfigs.CimInstanceProperties)
            {
                state.Results[p.Name] = p.Value?.ToString() ?? string.Empty;
            }

            lock (_dscSync) {
                methodResult = ses.InvokeMethod(cim, "ResourceTest", methodParams);
            }
            state.InDesiredState = (bool)methodResult.OutParameters["InDesiredState"].Value;

            return(state);
        }
        private bool DscResTestConfig(IHasDiagnostics result, IDscRes config)
        {
            using var ses = CimSession.Create(config.ComputerName ?? DscRes.DefaultCimHostname);
            using var cls = ses.GetClass(DscRes.DscCimNamespace, config.TypeName);
            using var cim = new CimInstance(DscRes.LcmCimClassName, DscRes.DscCimNamespace);

            var mofBody = DscRes.BuildMof(config, cls);

            _log.LogDebug("Generated MOF:\n{0}", mofBody);
            var mofBodyBytes = DscRes.ToUint8(mofBody);
            var methodParams = new CimMethodParametersCollection
            {
                CimMethodParameter.Create("ModuleName", config.ModuleName, CimFlags.None),
                CimMethodParameter.Create("ResourceType", config.TypeName, CimFlags.None),
                CimMethodParameter.Create("resourceProperty", mofBodyBytes, CimFlags.None),
            };

            CimMethodResult methodResult;

            lock (_dscSync) {
                methodResult = ses.InvokeMethod(cim, "ResourceTest", methodParams);
            }
            return((bool)methodResult.OutParameters["InDesiredState"].Value);
        }
        private void DscResValidateConfig(IHasDiagnostics result, IDscRes config)
        {
            using var ses = CimSession.Create(config.ComputerName ?? DscRes.DefaultCimHostname);
            using var cls = ses.GetClass(DscRes.DscCimNamespace, config.TypeName);

            _log.LogDebug("Got CIM Class: {0}", config.TypeName);
            foreach (var p in cls.CimClassProperties)
            {
                _log.LogDebug("  * {0}: {1}; {2}; {3}; {4}",
                              p.Name,
                              p.CimType,
                              p.Flags,
                              p.ReferenceClassName,
                              string.Join(",", p.Qualifiers?.Select(q => q.Name)));
            }
            if (cls.CimClassProperties.Count == 0)
            {
                result.AddError("Failed to get CIM Class properties");
            }


            // First check for required params
            foreach (var p in cls.CimClassProperties)
            {
                if (p.Qualifiers.Any(q => q.Name == "key"))
                {
                    if (!config.Properties.ContainsKey(p.Name))
                    {
                        result.AddError($"missing mandatory DSC resource property: [{p.Name}]");
                    }
                }
            }

            // Check for existence, writability and value compatibility
            foreach (var c in config.Properties)
            {
                var p = cls.CimClassProperties.FirstOrDefault(p =>
                                                              p.Name.Equals(c.Key, StringComparison.OrdinalIgnoreCase));
                if (p == null)
                {
                    result.AddError($"unknown DSC resource property [{c.Key}]");
                    continue;
                }

                if (!p.Qualifiers.Any(q => q.Name == "write" || q.Name == "key"))
                {
                    result.AddError($"cannot set readonly DSC resource property [{p.Name}]");
                    continue;
                }

                if (p.CimType == CimType.Unknown)
                {
                    result.AddError($"cannot convert DSC resource property [{p.Name}] to [{p.CimType}]");
                    continue;
                }
                if (!DscRes.CanConvertTo(c.Value, p.CimType))
                {
                    result.AddError($"cannot convert DSC resource property [{p.Name}] to [{p.CimType}]");
                    continue;
                }

                if (p.Qualifiers.FirstOrDefault(q => q.Name == "ValueMap") is CimQualifier q)
                {
                    var validValues = (IEnumerable <string>)q.Value;
                    if (p.CimType == CimType.String)
                    {
                        if (!validValues.Contains(c.Value))
                        {
                            result.AddError($"invalid DSC resource property [{p.Name}]"
                                            + $" - must be one of [{string.Join(",", validValues)}]");
                        }
                    }
                    else if (p.CimType == CimType.StringArray)
                    {
                        var canConvert = DscRes.TryConvertToArray <string>(c.Value, out var values);
                        if (values.Any(v => !validValues.Contains(v)))
                        {
                            result.AddError($"invalid DSC resource property [{p.Name}]"
                                            + $" - must restrict to [{string.Join(",", validValues)}]");
                        }
                    }
                    else
                    {
                        result.AddError($"invalid DSC resource property [{p.Name}]"
                                        + $" - don't know how to match {p.CimType} to restricted values");
                    }
                    continue;
                }
            }
        }