private ApplyResourceChangeResult <RegistryKeyResource> DoCreate(
            ApplyResourceChangeInput <RegistryKeyResource> input)
        {
            var newRes = input.PlannedState;
            var pState = StateHelper.Deserialize <PrivateState>(input.PlannedPrivate)
                         ?? new PrivateState();

            _log.LogInformation($"Creating registry key at [{newRes.Root}][{newRes.Path}]");
            RegistryKey root   = RegUtil.ParseRootKey(newRes.Root);
            RegistryKey newKey = root.OpenSubKey(newRes.Path, true);

            if (newKey == null)
            {
                _log.LogInformation("Existing key does not exist, creating");
                newKey = root.CreateSubKey(newRes.Path, true);
                pState.RegistryKeyCreated = true;
            }

            using (var regKey = newKey)
            {
                ApplyValueDiffs(regKey, toAdd: newRes.Entries);
            }

            return(new ApplyResourceChangeResult <RegistryKeyResource>
            {
                NewState = input.PlannedState,
                Private = StateHelper.Serialize(pState),
            });
        }
        public ApplyResourceChangeResult <RegistryKeyResource> ApplyChange(
            ApplyResourceChangeInput <RegistryKeyResource> input)
        {
            _log.LogDebug("{method}: ", nameof(ApplyChange));
            _log.LogTrace("->input = {@input}", input);

            _log.LogDebug("  * ....Config: " + JsonConvert.SerializeObject(input.Config, Formatting.Indented));
            _log.LogDebug("  * .....Prior: " + JsonConvert.SerializeObject(input.PriorState, Formatting.Indented));
            _log.LogDebug("  * ...Planned: " + JsonConvert.SerializeObject(input.PlannedState, Formatting.Indented));

            var doDel = false;
            var doAdd = false;

            if (input.PriorState?.Root != input.PlannedState?.Root)
            {
                if (string.IsNullOrEmpty(input.PlannedState?.Root))
                {
                    doDel = true;
                }
                if (string.IsNullOrEmpty(input.PriorState?.Root))
                {
                    doAdd = true;
                }
            }

            if (input.PriorState?.Path != input.PlannedState?.Path)
            {
                if (string.IsNullOrEmpty(input.PlannedState?.Path))
                {
                    doDel = true;
                }
                if (string.IsNullOrEmpty(input.PriorState?.Path))
                {
                    doAdd = true;
                }
            }

            ApplyResourceChangeResult <RegistryKeyResource> result = null;

            if (doDel)
            {
                result = DoDelete(input);
            }
            if (doAdd)
            {
                result = DoCreate(input);
            }

            if (!doDel && !doAdd)
            {
                result = DoUpdate(input);
            }

            _log.LogTrace("<-result = {@result}", result);
            return(result);
        }
        private ApplyResourceChangeResult <RegistryKeyResource> DoDelete(
            ApplyResourceChangeInput <RegistryKeyResource> input)
        {
            var oldRes = input.PriorState;
            var pState = StateHelper.Deserialize <PrivateState>(input.PlannedPrivate);

            _log.LogInformation($"Deleting registry key at [{oldRes.Root}][{oldRes.Path}]");
            RegistryKey root   = RegUtil.ParseRootKey(oldRes.Root);
            RegistryKey oldKey = root.OpenSubKey(oldRes.Path, true);

            if (oldKey != null)
            {
                string delKey = null;
                using (var regKey = oldKey)
                {
                    ApplyValueDiffs(regKey, toDel: oldRes.Entries);

                    var subKeysLen = oldKey.GetSubKeyNames()?.Length ?? 0;
                    var valuesLen  = oldKey.GetValueNames()?.Length ?? 0;
                    var forceDel   = oldRes.ForceOnDelete ?? false;

                    if (!(pState?.RegistryKeyCreated ?? false))
                    {
                        _log.LogWarning("registry key was not created by us");
                    }
                    if (subKeysLen > 0)
                    {
                        _log.LogWarning($"registry key still has [{subKeysLen}] subkey(s)");
                    }
                    if (valuesLen > 0)
                    {
                        _log.LogWarning($"registry key still has [{valuesLen}] value(s)");
                    }

                    if (!(pState?.RegistryKeyCreated ?? false) || subKeysLen > 0 || valuesLen > 0)
                    {
                        if (forceDel)
                        {
                            _log.LogWarning("forced delete specified");
                            delKey = oldKey.Name;
                        }
                        else
                        {
                            _log.LogWarning("reg key was not created by us or is not empty, SKIPPING delete");
                        }
                    }
                    else
                    {
                        delKey = oldKey.Name;
                    }
                }

                if (delKey != null)
                {
                    var openParent = RegUtil.OpenParentWithName(delKey, true);
                    if (openParent == null)
                    {
                        _log.LogWarning($"Cannot delete Registry Key [{delKey}], malformed path");
                    }
                    else
                    {
                        var(delRoot, parent, name) = openParent.Value;
                        _log.LogInformation($"Deleting Registry Key [{name}] under [{(parent??delRoot).Name}] ({delRoot.Name})");
                        using (var regKey = parent)
                        {
                            regKey.DeleteSubKeyTree(name, false);
                        }
                    }
                }
            }
            else
            {
                _log.LogInformation("Could not open existing, prior reg key, skipping");
            }

            return(new ApplyResourceChangeResult <RegistryKeyResource>
            {
                NewState = input.PlannedState,
                Private = null,
            });
        }
        public ApplyResourceChangeResult <FileResource> ApplyChange(
            ApplyResourceChangeInput <FileResource> input)
        {
            _log.LogDebug("{method}: ", nameof(ApplyChange));
            _log.LogTrace("->input = {@input}", input);

            var result = new ApplyResourceChangeResult <FileResource>();

            if (input.ChangeType != ResourceChangeType.Delete)
            {
                result.NewState = new FileResource().CopyArgumentsFrom(input.Config);
            }

            var deleteOld = input.ChangeType != ResourceChangeType.Create &&
                            input.PlannedState?.Path != input.PriorState.Path;
            var createNew = input.ChangeType != ResourceChangeType.Delete &&
                            (input.PlannedState.Path != input.PriorState?.Path ||
                             input.PlannedState.SourceOfContent != input.PriorState?.SourceOfContent);

            if (deleteOld)
            {
                // For Updates & Deletes, remove the old path
                _log.LogInformation("DELETING old path");
                File.Delete(input.PriorState.Path);
            }
            if (createNew)
            {
                // For Creates & Updates, create the new path
                _log.LogInformation("CREATING new path");
                if (!string.IsNullOrEmpty(input.Config.Content))
                {
                    File.WriteAllText(input.Config.Path,
                                      input.Config.Content);
                }
                else if (!string.IsNullOrEmpty(input.Config.ContentBase64))
                {
                    File.WriteAllBytes(input.Config.Path,
                                       Convert.FromBase64String(input.Config.ContentBase64));
                }
                else if (!string.IsNullOrEmpty(input.Config.ContentPath))
                {
                    File.Copy(input.Config.ContentPath, input.Config.Path, true);
                }
                else if (!string.IsNullOrEmpty(input.Config.ContentUrl))
                {
                    using (var wc = new WebClient())
                    {
                        wc.DownloadFile(input.Config.ContentUrl, input.Config.Path);
                    }
                }

                if (input.Config.Appends?.Count > 0)
                {
                    foreach (var cs in input.Config.Appends)
                    {
                        _log.LogInformation("APPENDING new path");
                        WebClient wc     = null;
                        Stream    source = null;
                        if (!string.IsNullOrEmpty(cs.Content))
                        {
                            source = new MemoryStream(Encoding.UTF8.GetBytes(
                                                          cs.Content));
                        }
                        else if (!string.IsNullOrEmpty(cs.ContentBase64))
                        {
                            source = new MemoryStream(Convert.FromBase64String(
                                                          cs.ContentBase64));
                        }
                        else if (!string.IsNullOrEmpty(cs.ContentPath))
                        {
                            source = new FileStream(cs.ContentPath, FileMode.Open);
                        }
                        else if (!string.IsNullOrEmpty(cs.ContentUrl))
                        {
                            wc     = new WebClient();
                            source = wc.OpenRead(cs.ContentUrl);
                        }

                        try
                        {
                            using (source)
                                using (var target = new FileStream(input.Config.Path, FileMode.Append))
                                {
                                    source.CopyTo(target);
                                }
                        }
                        finally
                        {
                            wc?.Dispose();
                        }
                    }
                }
            }

            ComputeState(input.Config, result.NewState, result);

            _log.LogTrace("<-result = {@result}", result);
            return(result);
        }