Hola, chicos,
¡Buenas tardes!

En la publicación de hoy, demostraré cómo administrar (leer, enumerar, crear, cambiar y eliminar) las claves del Registro de Windows a través de la base de datos, utilizando SQL CLR y el lenguaje de programación C# (CSharp), lo que nos permite ampliar en gran medida las capacidades y funcionalidades de la base de datos de SQL Server.

Este tipo de funcionalidad es muy útil cuando se necesita consultar rápidamente alguna información en el registro de Windows de un servidor o realizar un cambio en el registro sin necesidad de conectarse al servidor, simplemente ejecutando un Procedimiento Almacenado, o incluso aplicar un cambio de registro a varias máquinas o servidores de forma automatizada.

Vale recordar que ya había hecho un post (SQL Server: consulta de información de instancia en el Registro de Windows mediante sys.dm_server_registry y xp_instance_regread) donde era posible leer cierta información del registro de Windows sin utilizar el CLR, pero relacionada solo con información sobre la instancia de SQL Server y no con la lectura general de ninguna clave de registro, ni mucho menos con la manipulación de esta información, lo que me motivó a crear este nuevo post para esta necesidad.

Algunos procedimientos almacenados a continuación requieren el uso de la clase Return, que utilizo para enviar mensajes de alerta y/o error desde CLR a la base de datos. El código fuente de esta clase se puede ver en la publicación. SQL Server: cómo enviar advertencias y mensajes de error a la base de datos usando CLR (C#)

Cómo leer y enumerar las claves del registro de Windows

Cómo leer y enumerar las claves del registro de Windows

sql-server-how-to-list-windows-registry-regedit-with-sql-clr
sql-server-cómo-listar-registro-de-windows-regedit-con-sql-clr

Para enumerar los registros de Windows, usaré la clase RegistryRow, que encapsula varios métodos de la biblioteca Microsoft.Win32.RegistryKey y la uso en la función con valores de tabla fncRegEdit_Listar, como en el ejemplo anterior, donde ingreso como parámetros el nombre de la máquina y la clave de registro que se leerá.

RegEdit.cs

using System;
using System.Collections;
using Microsoft.Win32;

namespace Bibliotecas.Model
{


    public class RegistryRow
    {

        public string Tipo;
        public string Chave;
        public string Valor;

        public RegistryRow(string tipo, string chave, string valor)
        {

            Tipo = tipo;
            Chave = chave;
            Valor = valor;

        }

        public static ArrayList RegEdit_Listar(string Ds_Servidor, string Ds_Chave)
        {

            var RegistryRowCollection = new ArrayList();


            if (string.IsNullOrEmpty(Ds_Servidor))
                Ds_Servidor = Environment.MachineName;


            var registryHive = RegistryHive.LocalMachine;

            if (Ds_Chave.Substring(0, 5).ToUpper() == "HKEY_")
            {

                var palavras = Ds_Chave.Split('\\');
                var raiz = palavras[0];

                switch (raiz)
                {

                    case "HKEY_CURRENT_CONFIG":
                        registryHive = RegistryHive.CurrentConfig;
                        break;

                    case "HKEY_CURRENT_USER":
                        registryHive = RegistryHive.CurrentUser;
                        break;

                    case "HKEY_USERS":
                        registryHive = RegistryHive.Users;
                        break;

                    case "HKEY_CLASSES_ROOT":
                        registryHive = RegistryHive.ClassesRoot;
                        break;

                    case "HKEY_LOCAL_MACHINE":
                    default:
                        registryHive = RegistryHive.LocalMachine;
                        break;

                }

                Ds_Chave = string.Join("\\", palavras, 1, palavras.Length - 1);

            }



            var myRegChave = RegistryKey.OpenRemoteBaseKey(registryHive, Ds_Servidor).OpenSubKey(Ds_Chave);
            var subKeys = myRegChave?.GetSubKeyNames();
            if (subKeys != null)
            {

                foreach (var key in subKeys)
                {

                    try
                    {

                        RegistryRowCollection.Add(new RegistryRow(
                            "Chave",
                            key,
                            ""
                        ));

                    }
                    catch (Exception e)
                    {
                        // ignored
                    }
                }

            }



            myRegChave = RegistryKey.OpenRemoteBaseKey(registryHive, Ds_Servidor).OpenSubKey(Ds_Chave);


            var valorNames = myRegChave?.GetValueNames();
            if (valorNames == null) return RegistryRowCollection;

            foreach (var chave in valorNames)
            {

                try
                {

                    var valor = myRegChave.GetValue(chave).ToString();

                    RegistryRowCollection.Add(new RegistryRow(
                        "Valor",
                        chave,
                        valor
                    ));

                }
                catch (Exception e)
                {
                    // ignored
                }

            }


            return RegistryRowCollection;


        }

    }

}

fncRegEdit_Listar.cs

using System.Collections;
using System.Data.SqlTypes;
using Bibliotecas.Model;

public partial class UserDefinedFunctions
{

    [Microsoft.SqlServer.Server.SqlFunction(
        FillRowMethodName = "FillRegistryRow",
        TableDefinition = "Ds_Tipo nvarchar(50), Ds_Chave nvarchar(max), Ds_Valor nvarchar(max)"
    )]
    public static IEnumerable fncRegEdit_Listar(string Ds_Servidor, string Ds_Chave)
    {
        var RegistryRowCollection = RegistryRow.RegEdit_Listar(Ds_Servidor, Ds_Chave);
        return RegistryRowCollection;
    }

    protected static void FillRegistryRow(object objRegistryRow, out SqlString tipo, out SqlString key, out SqlString value)
    {

        var registryRow = (RegistryRow) objRegistryRow;

        tipo = registryRow.Tipo;
        key = registryRow.Chave;
        value = registryRow.Valor;

    }

}

Cómo crear carpetas de registro de Windows

Cómo crear carpetas de registro de Windows

sql-server-how-to-list-windows-registry-regedit-with-sql-clr-2
sql-server-cómo-listar-registro-de-windows-regedit-con-sql-clr-2

sql-server-how-to-list-windows-registry-regedit-with-sql-clr-3
sql-server-cómo-listar-registro-de-windows-regedit-con-sql-clr-3

Para crear carpetas en el registro de Windows, utilizo el procedimiento almacenado stpRegEdit_Folder_Criar, como en el ejemplo anterior, que le permite crear directorios en una clave de registro de Windows.

stpRegEdit_Folder_Criar.cs

using System;
using System.Data.SqlTypes;
using Bibliotecas.Model;
using Microsoft.Win32;

public partial class StoredProcedures
{
    [Microsoft.SqlServer.Server.SqlProcedure]
    public static void stpRegEdit_Pasta_Criar(SqlString Ds_Servidor, SqlString Ds_Caminho, SqlString Ds_Chave)
    {

        try
        {

            if (Ds_Servidor.IsNull)
                Retorno.Erro("Favor informar o servidor");

            if (Ds_Caminho.IsNull)
                Retorno.Erro("Favor informar o caminho");

            if (Ds_Chave.IsNull)
                Retorno.Erro("Favor informar a chave");


            var caminho = Ds_Caminho.Value;
            var registryHive = RegistryHive.LocalMachine;

            if (caminho.Substring(0, 5).ToUpper() == "HKEY_")
            {

                var palavras = caminho.Split('\\');
                var raiz = palavras[0];

                switch (raiz)
                {

                    case "HKEY_CURRENT_CONFIG":
                        registryHive = RegistryHive.CurrentConfig;
                        break;

                    case "HKEY_CURRENT_USER":
                        registryHive = RegistryHive.CurrentUser;
                        break;

                    case "HKEY_USERS":
                        registryHive = RegistryHive.Users;
                        break;

                    case "HKEY_CLASSES_ROOT":
                        registryHive = RegistryHive.ClassesRoot;
                        break;

                    case "HKEY_LOCAL_MACHINE":
                    default:
                        registryHive = RegistryHive.LocalMachine;
                        break;

                }

                caminho = string.Join("\\", palavras, 1, palavras.Length - 1);

            }

            var registro = RegistryKey.OpenRemoteBaseKey(registryHive, Ds_Servidor.Value).OpenSubKey(caminho, true);
            registro?.CreateSubKey(Ds_Chave.Value);
            registro?.Close();

        }
        catch (Exception e)
        {
            Retorno.Erro("Erro : " + e.Message);
        }

    }

}

Cómo eliminar carpetas del Registro de Windows

Cómo eliminar carpetas del Registro de Windows

sql-server-how-to-list-windows-registry-regedit-with-sql-clr-4
sql-server-cómo-listar-registro-de-windows-regedit-con-sql-clr-4

Para eliminar carpetas en el registro de Windows, utilizo el procedimiento almacenado stpRegEdit_Folder_Apagar, como en el ejemplo anterior, que le permite eliminar directorios del registro de Windows. El indicador binario @Fl_Recursive = 1 le permite eliminar claves y subdirectorios de forma recursiva de un directorio determinado.

Si el indicador @Fl_Recursive = 0, solo será posible eliminar directorios que no tengan subdirectorios y, si lo intenta, aparecerá el mensaje de error "System.ApplicationException: Error: la clave de registro tiene subclaves y este método no admite eliminaciones recursivas".

stpRegEdit_Folder_Delete.cs

using System;
using System.Data.SqlTypes;
using Bibliotecas.Model;
using Microsoft.Win32;


public partial class StoredProcedures
{
    [Microsoft.SqlServer.Server.SqlProcedure]
    public static void stpRegEdit_Pasta_Criar(SqlString Ds_Servidor, SqlString Ds_Caminho, SqlString Ds_Chave)
    {

        try
        {

            if (Ds_Servidor.IsNull)
                Retorno.Erro("Favor informar o servidor");

            if (Ds_Caminho.IsNull)
                Retorno.Erro("Favor informar o caminho");

            if (Ds_Chave.IsNull)
                Retorno.Erro("Favor informar a chave");


            var caminho = Ds_Caminho.Value;
            var registryHive = RegistryHive.LocalMachine;

            if (caminho.Substring(0, 5).ToUpper() == "HKEY_")
            {

                var palavras = caminho.Split('\\');
                var raiz = palavras[0];

                switch (raiz)
                {

                    case "HKEY_CURRENT_CONFIG":
                        registryHive = RegistryHive.CurrentConfig;
                        break;

                    case "HKEY_CURRENT_USER":
                        registryHive = RegistryHive.CurrentUser;
                        break;

                    case "HKEY_USERS":
                        registryHive = RegistryHive.Users;
                        break;

                    case "HKEY_CLASSES_ROOT":
                        registryHive = RegistryHive.ClassesRoot;
                        break;

                    case "HKEY_LOCAL_MACHINE":
                    default:
                        registryHive = RegistryHive.LocalMachine;
                        break;

                }

                caminho = string.Join("\\", palavras, 1, palavras.Length - 1);

            }

            var registro = RegistryKey.OpenRemoteBaseKey(registryHive, Ds_Servidor.Value).OpenSubKey(caminho, true);
            registro?.CreateSubKey(Ds_Chave.Value);
            registro?.Close();

        }
        catch (Exception e)
        {
            Retorno.Erro("Erro : " + e.Message);
        }

    }

}

Cómo crear/cambiar claves de registro de Windows

Cómo crear/cambiar claves de registro de Windows

Cómo crear claves y valores en el Registro de Windows:

sql-server-how-to-list-windows-registry-regedit-with-sql-clr-5
sql-server-cómo-listar-registro-de-windows-regedit-con-sql-clr-5

Cómo cambiar claves y valores en el Registro de Windows:

sql-server-how-to-list-windows-registry-regedit-with-sql-clr-6
sql-server-cómo-listar-registro-de-windows-regedit-con-sql-clr-6

Para crear/cambiar registros de Windows, utilizo el procedimiento almacenado stpRegEdit_Chave_Criar, como se muestra arriba y el código fuente está disponible a continuación:

stpRegEdit_Chave_Criar.cs

using System;
using System.Data.SqlTypes;
using Bibliotecas.Model;
using Microsoft.Win32;

public partial class StoredProcedures
{
    [Microsoft.SqlServer.Server.SqlProcedure]
    public static void stpRegEdit_Chave_Criar(SqlString Ds_Servidor, SqlString Ds_Caminho, SqlString Ds_Chave, SqlString Ds_Valor)
    {

        try
        {

            if (Ds_Servidor.IsNull)
                Retorno.Erro("Favor informar o servidor");

            if (Ds_Caminho.IsNull)
                Retorno.Erro("Favor informar o caminho");

            if (Ds_Chave.IsNull)
                Retorno.Erro("Favor informar a chave");

            if (Ds_Valor.IsNull)
                Retorno.Erro("Favor informar o valor");


            var caminho = Ds_Caminho.Value;
            var registryHive = RegistryHive.LocalMachine;

            if (caminho.Substring(0, 5).ToUpper() == "HKEY_")
            {

                var palavras = caminho.Split('\\');
                var raiz = palavras[0];

                switch (raiz)
                {

                    case "HKEY_CURRENT_CONFIG":
                        registryHive = RegistryHive.CurrentConfig;
                        break;

                    case "HKEY_CURRENT_USER":
                        registryHive = RegistryHive.CurrentUser;
                        break;

                    case "HKEY_USERS":
                        registryHive = RegistryHive.Users;
                        break;

                    case "HKEY_CLASSES_ROOT":
                        registryHive = RegistryHive.ClassesRoot;
                        break;

                    case "HKEY_LOCAL_MACHINE":
                    default:
                        registryHive = RegistryHive.LocalMachine;
                        break;

                }

                caminho = string.Join("\\", palavras, 1, palavras.Length - 1);

            }

            var registro = RegistryKey.OpenRemoteBaseKey(registryHive, Ds_Servidor.Value).OpenSubKey(caminho, true);
            registro?.SetValue(Ds_Chave.Value, Ds_Valor.Value);
            registro?.Close();

        }
        catch (Exception e)
        {
            Retorno.Erro("Erro : " + e.Message);
        }

    }

}

Cómo eliminar claves de registro de Windows

Cómo eliminar claves de registro de Windows

sql-server-how-to-list-windows-registry-regedit-with-sql-clr-7
sql-server-cómo-listar-registro-de-windows-regedit-con-sql-clr-7

Para eliminar claves de registro de Windows, utilizo el procedimiento almacenado stpRegEdit_Chave_Apagar, utilizando los mismos estándares que los procedimientos almacenados anteriores.

stpRegEdit_Chave_Apagar.cs

using System;
using System.Data.SqlTypes;
using Bibliotecas.Model;
using Microsoft.Win32;

public partial class StoredProcedures
{
    [Microsoft.SqlServer.Server.SqlProcedure]
    public static void stpRegEdit_Chave_Apagar(SqlString Ds_Servidor, SqlString Ds_Caminho, SqlString Ds_Chave)
    {

        try
        {

            if (Ds_Servidor.IsNull)
                Retorno.Erro("Favor informar o servidor");

            if (Ds_Caminho.IsNull)
                Retorno.Erro("Favor informar o caminho");

            if (Ds_Chave.IsNull)
                Retorno.Erro("Favor informar a chave");

            
            var caminho = Ds_Caminho.Value;
            var registryHive = RegistryHive.LocalMachine;

            if (caminho.Substring(0, 5).ToUpper() == "HKEY_")
            {

                var palavras = caminho.Split('\\');
                var raiz = palavras[0];

                switch (raiz)
                {

                    case "HKEY_CURRENT_CONFIG":
                        registryHive = RegistryHive.CurrentConfig;
                        break;

                    case "HKEY_CURRENT_USER":
                        registryHive = RegistryHive.CurrentUser;
                        break;

                    case "HKEY_USERS":
                        registryHive = RegistryHive.Users;
                        break;

                    case "HKEY_CLASSES_ROOT":
                        registryHive = RegistryHive.ClassesRoot;
                        break;

                    case "HKEY_LOCAL_MACHINE":
                    default:
                        registryHive = RegistryHive.LocalMachine;
                        break;

                }

                caminho = string.Join("\\", palavras, 1, palavras.Length - 1);

            }

            var registro = RegistryKey.OpenRemoteBaseKey(registryHive, Ds_Servidor.Value).OpenSubKey(caminho, true);
            registro?.DeleteValue(Ds_Chave.Value);
            registro?.Close();

        }
        catch (Exception e)
        {
            Retorno.Erro("Erro : " + e.Message);
        }

    }

}

Si no sabías qué es CLR y te gustaría saber más al respecto, visita mi post Introducción a SQL CLR (Common Language Runtime) en SQL Server.

¡Eso es todo, amigos!
Hasta el próximo post.

servidor sql c# csharp acceso lista de acceso vista de lista ver leer registro de windows registro regedit

servidor sql c# csharp acceso lista de acceso vista de lista ver leer registro de windows registro regedit