En esta publicación demostraré cómo administrar los servicios de Windows desde la base de datos de SQL Server, usando SQLCLR para realizar estas operaciones. Esto puede resultar especialmente útil al crear un seguimiento para determinados servicios.
Actualmente donde trabajo, creé una tabla de configuración de monitoreo de servicios, donde determino los datos de los servicios que pretendo monitorear, como el nombre del servidor, nombre del servicio, si necesita enviar un SMS en caso de falla y si la propia rutina debe ser responsable de iniciar el servicio automáticamente en caso de falla. Siempre se envía el email con el listado de servicios que han cambiado de estado. Una vez configurado, las recopilaciones se realizan vía trabajo cada X minutos del estado de estos servicios y estos datos se almacenan en una tabla de historial.
Con esto, es posible medir la disponibilidad de los servicios y utilizando Reporting Services 2016 para crear informes leyendo de la tabla de historial, se pueden recuperar los datos actuales de esta tabla y monitorear el estado de diferentes servicios, en diferentes servidores, desde cualquier lugar: Ya sea a través del Navegador (accediendo a la ruta de Reporting Services) o en el celular (usando la aplicación PowerBI), sin necesidad de tener una computadora cerca, conectarse a la VPN de la empresa o comprar un sistema de monitoreo, que además de tener altos costos, no siempre ofrece esto. flexibilidad.
Para realizar estas operaciones con el CLR, enumeraré dos formas diferentes de obtener esta información y, después de leer, entenderás por qué. En el código fuente que leerá a continuación, utilicé la clase Retorno para gestionar las advertencias y mensajes de error que envío a la base de datos y es un requisito previo para utilizar procedimientos almacenados para la gestión de servicios. Puedes encontrar el código fuente de la clase Return en la publicación. SQL Server: cómo enviar advertencias y mensajes de error a la base de datos usando CLR (C#).
Demostraré dos formas diferentes de hacer lo mismo. El primero de ellos utiliza binarios nativos del propio sistema operativo y, principalmente en la parte del listado de servicios, hay manipulaciones manuales de información, que en el caso de la otra clase que presentaré, esta ya está encapsulada en el framework .NET. Lo que más me motiva a utilizar esta primera alternativa es que no tiene dependencias de DLL fuera de las DLL estándar admitidas y recomendadas por Microsoft. La biblioteca System.ServiceProcess requiere varias otras DLL no compatibles de las que depende.
SQL Server: dependencias de objetos CLR Clase System.ServiceProcess ServiceController
Cuando tu banco presenta un problema y envías el error DUMP a Microsoft, lo primero que el consultor te señalará como problema son las DLL CLR no soportadas por Microsoft, como System.ServiceProcess, por lo que prefiero evitarlas. Estas DLL no compatibles son DLL que se pueden registrar manualmente, pero no en modo SEGURO, como ya hablé de esto en la publicación. Introducción a SQL CLR (Common Language Runtime) en SQL Server.
Usando la clase Process de la biblioteca System.Diagnostics
Una de las formas de realizar estas actividades a través de CLR es mediante el uso de la clase Process, que nos permite ejecutar comandos Prompt-DOS dentro de C#. Con esto, puedes usar el binario sc.exe (obtén más información al respecto) haciendo clic en este enlace) para detener e iniciar servicios, y el binario wmic.exe (obtenga más información al respecto haciendo clic en este enlace) para enumerar los servicios.
Cómo enumerar los servicios de un servidor:
using System.Collections;
using System.Data.SqlTypes;
using System.Diagnostics;
using System.Linq;
using System.Text;
public partial class UserDefinedFunctions
{
private class ServiceProperties
{
public SqlString AcceptPause;
public SqlString AcceptStop;
public SqlString Caption;
public SqlString Description;
public SqlString DesktopInteract;
public SqlString ErrorControl;
public SqlString ExitCode;
public SqlString Name;
public SqlString PathName;
public SqlString ProcessID;
public SqlString ServiceType;
public SqlString StartMode;
public SqlString StartName;
public SqlString Started;
public SqlString State;
public SqlString Status;
public ServiceProperties(SqlString acceptPause, SqlString acceptStop, SqlString caption, SqlString description, SqlString desktopInteract, SqlString errorControl,
SqlString exitCode, SqlString name, SqlString pathName, SqlString processID, SqlString serviceType, SqlString startMode, SqlString startName,
SqlString started, SqlString state, SqlString status)
{
AcceptPause = acceptPause;
AcceptStop = acceptStop;
Caption = caption;
Description = description;
DesktopInteract = desktopInteract;
ErrorControl = errorControl;
ExitCode = exitCode;
Name = name;
PathName = pathName;
ProcessID = processID;
ServiceType = serviceType;
StartMode = startMode;
StartName = startName;
Started = started;
State = state;
Status = status;
}
}
[Microsoft.SqlServer.Server.SqlFunction(
FillRowMethodName = "ListarServicos",
TableDefinition = "AcceptPause nvarchar(20), AcceptStop nvarchar(20), Caption nvarchar(2048), Description nvarchar(4000), DesktopInteract nvarchar(30), " +
"ErrorControl nvarchar(60), ExitCode nvarchar(30), Name nvarchar(1024), PathName nvarchar(1024), ProcessID nvarchar(500), " +
"ServiceType nvarchar(30), StartMode nvarchar(30), StartName nvarchar(60), Started nvarchar(256), State nvarchar(60), " +
"Status nvarchar(60)"
)]
public static IEnumerable fncServicos_Listar(string Ds_Servidor)
{
var scriptProc = new Process
{
StartInfo =
{
FileName = @"wmic",
Arguments = "/node:\"" + Ds_Servidor + "\" service get Name,Caption,Started,Status,StartMode,StartName,PathName,AcceptPause,AcceptStop,DesktopInteract,ErrorControl,ExitCode,ProcessID,ServiceType,Description,State /FORMAT:list",
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
StandardOutputEncoding = Encoding.GetEncoding(850),
CreateNoWindow = true
}
};
scriptProc.Start();
var output = scriptProc.StandardOutput.ReadToEnd();
var linhas = output.Split('\n');
var Qt_Linhas = (linhas.Length - 1);
var contador = 0;
var palavra = new ArrayList();
var ServicePropertiesCollection = new ArrayList();
for (var i = 0; i < Qt_Linhas; i++)
{
var linha = linhas[i];
if (linha.Trim().Length <= 0) continue;
contador++;
palavra.Add(linha.Split('=').Last().Trim());
if (contador != 16) continue;
ServicePropertiesCollection.Add(new ServiceProperties(
palavra[0].ToString(),
palavra[1].ToString(),
palavra[2].ToString(),
palavra[3].ToString(),
palavra[4].ToString(),
palavra[5].ToString(),
palavra[6].ToString(),
palavra[7].ToString(),
palavra[8].ToString(),
palavra[9].ToString(),
palavra[10].ToString(),
palavra[11].ToString(),
palavra[12].ToString(),
palavra[13].ToString(),
palavra[14].ToString(),
palavra[15].ToString()
));
palavra.RemoveRange(0, 16);
contador = 0;
}
return ServicePropertiesCollection;
}
public static void ListarServicos(object objServiceProperties, out SqlString acceptPause, out SqlString acceptStop, out SqlString caption, out SqlString description,
out SqlString desktopInteract, out SqlString errorControl, out SqlString exitCode, out SqlString name, out SqlString pathName, out SqlString processID,
out SqlString serviceType, out SqlString startMode, out SqlString startName, out SqlString started, out SqlString state, out SqlString status)
{
var serviceProperties = (ServiceProperties) objServiceProperties;
acceptPause = serviceProperties.AcceptPause;
acceptStop = serviceProperties.AcceptStop;
caption = serviceProperties.Caption;
description = serviceProperties.Description;
desktopInteract = serviceProperties.DesktopInteract;
errorControl = serviceProperties.ErrorControl;
exitCode = serviceProperties.ExitCode;
name = serviceProperties.Name;
pathName = serviceProperties.PathName;
processID = serviceProperties.ProcessID;
serviceType = serviceProperties.ServiceType;
startMode = serviceProperties.StartMode;
startName = serviceProperties.StartName;
started = serviceProperties.Started;
state = serviceProperties.State;
status = serviceProperties.Status;
}
};
SQL Server: SC binario CLR lista servicios de Windows Administrador de servicios de Windows
SQL Server: servicios de Windows de lista CLR binario SC
Cómo iniciar un servicio:
using System;
using System.Data.SqlTypes;
using System.Diagnostics;
using System.Text;
using Bibliotecas.Model;
public partial class StoredProcedures
{
[Microsoft.SqlServer.Server.SqlProcedure]
public static void stpServicos_Iniciar(SqlString Ds_Servidor, SqlString Ds_Servico)
{
try
{
var scriptProc = new Process
{
StartInfo =
{
FileName = @"sc.exe",
UseShellExecute = false,
Arguments = "\\\\" + Ds_Servidor.Value + " start \"" + Ds_Servico.Value + "\"",
RedirectStandardOutput = true,
RedirectStandardError = true,
StandardOutputEncoding = Encoding.GetEncoding(850),
StandardErrorEncoding = Encoding.GetEncoding(850),
CreateNoWindow = true
}
};
scriptProc.Start();
var output = scriptProc.StandardOutput.ReadToEnd();
var erro = scriptProc.StandardError.ReadToEnd();
Retorno.Mensagem("Iniciando o serviço " + Ds_Servico.Value + " no servidor " + Ds_Servidor.Value + "...");
if (output.Length > 0)
{
Retorno.Mensagem(output);
}
if (erro.Length > 0)
{
Retorno.Erro(erro);
}
}
catch (Exception e)
{
Retorno.Erro("Erro : " + e.Message);
}
}
};
SQL Server: SC binario CLR inicia los servicios de Windows2
Cómo detener un servicio:
using System;
using System.Data.SqlTypes;
using System.Diagnostics;
using Bibliotecas.Model;
using System.Text;
public partial class StoredProcedures
{
[Microsoft.SqlServer.Server.SqlProcedure]
public static void stpServicos_Parar(SqlString Ds_Servidor, SqlString Ds_Servico)
{
try
{
var scriptProc = new Process
{
StartInfo =
{
FileName = @"sc.exe",
UseShellExecute = false,
Arguments = "\\\\" + Ds_Servidor.Value + " stop \"" + Ds_Servico.Value + "\"",
RedirectStandardOutput = true,
RedirectStandardError = true,
StandardOutputEncoding = Encoding.GetEncoding(850),
StandardErrorEncoding = Encoding.GetEncoding(850),
CreateNoWindow = true
}
};
scriptProc.Start();
var output = scriptProc.StandardOutput.ReadToEnd();
var erro = scriptProc.StandardError.ReadToEnd();
Retorno.Mensagem("Parando o serviço " + Ds_Servico.Value + " no servidor " + Ds_Servidor.Value + "...");
if (output.Length > 0)
{
Retorno.Mensagem(output);
}
if (erro.Length > 0)
{
Retorno.Erro(erro);
}
}
catch (Exception e)
{
Retorno.Erro("Erro : " + e.Message);
}
}
};
SQL Server: SC binario CLR detiene los servicios de Windows
Usando la clase ServiceController de la biblioteca System.ServiceProcess
Cómo enumerar los servicios de un servidor:
using System;
using System.Data;
using System.Data.SqlTypes;
using System.ServiceProcess;
using System.Text;
using Bibliotecas.Model;
using Microsoft.SqlServer.Server;
public partial class StoredProcedures
{
[Microsoft.SqlServer.Server.SqlProcedure]
public static void stpServicos_Listar(SqlString Ds_Servidor, SqlString Ds_Servico)
{
string servico = (Ds_Servico.IsNull) ? "" : Ds_Servico.Value;
SqlMetaData[] colunas = new SqlMetaData[7];
colunas[0] = new SqlMetaData("DisplayName", SqlDbType.VarChar, 1024);
colunas[1] = new SqlMetaData("CanPauseAndContinue", SqlDbType.Int);
colunas[2] = new SqlMetaData("CanShutdown", SqlDbType.Int);
colunas[3] = new SqlMetaData("CanStop", SqlDbType.Int);
colunas[4] = new SqlMetaData("ServicesDependedOn", SqlDbType.VarChar, 1024);
colunas[5] = new SqlMetaData("ServiceType", SqlDbType.VarChar, 1024);
colunas[6] = new SqlMetaData("Status", SqlDbType.VarChar, 1024);
SqlDataRecord linhaSQL = new SqlDataRecord(colunas);
SqlPipe pipe = SqlContext.Pipe;
pipe.SendResultsStart(linhaSQL);
ServiceController[] services = ServiceController.GetServices(Ds_Servidor.Value);
foreach (ServiceController sc in services)
{
try
{
if (sc.ServiceName == servico || string.IsNullOrEmpty(servico))
{
var CanPauseAndContinue = (sc.CanPauseAndContinue) ? 1 : 0;
var CanShutdown = (sc.CanShutdown) ? 1 : 0;
var CanStop = (sc.CanStop) ? 1 : 0;
linhaSQL.SetSqlString(0, new SqlString(sc.ServiceName));
linhaSQL.SetSqlInt32(1, new SqlInt32(CanPauseAndContinue));
linhaSQL.SetSqlInt32(2, new SqlInt32(CanShutdown));
linhaSQL.SetSqlInt32(3, new SqlInt32(CanStop));
StringBuilder Ds_Dependencias = new StringBuilder();
foreach (ServiceController dependencia in sc.ServicesDependedOn)
{
Ds_Dependencias.Append(dependencia.DisplayName);
Ds_Dependencias.Append(";");
}
linhaSQL.SetSqlString(4, new SqlString(Ds_Dependencias.ToString()));
linhaSQL.SetSqlString(5, new SqlString(sc.ServiceType.ToString()));
linhaSQL.SetSqlString(6, new SqlString(sc.Status.ToString()));
pipe.SendResultsRow(linhaSQL);
}
}
catch (InvalidOperationException e)
{
//Retorno.Erro("Erro : " + e.Message);
}
}
pipe.SendResultsEnd();
}
};
SQL Server: SC binario CLR lista servicios de Windows Administrador de servicios de Windows
SQL Server: SC ServiceController Class CLR enumera servicios de Windows
Cómo iniciar un servicio:
using System;
using System.Data.SqlTypes;
using System.ServiceProcess;
using Bibliotecas.Model;
public partial class StoredProcedures
{
[Microsoft.SqlServer.Server.SqlProcedure]
public static void stpServicos_Iniciar(SqlString Ds_Servidor, SqlString Ds_Servico)
{
try
{
ServiceController sc = new ServiceController(Ds_Servico.Value, Ds_Servidor.Value);
sc.Start();
}
catch (Exception e)
{
Retorno.Erro("Erro : " + e.Message);
}
}
};
SQL Server: SC ServiceController Class CLR inicia servicios de Windows
Cómo detener un servicio:
using System;
using System.Data.SqlTypes;
using System.ServiceProcess;
using Bibliotecas.Model;
public partial class StoredProcedures
{
[Microsoft.SqlServer.Server.SqlProcedure]
public static void stpServicos_Parar(SqlString Ds_Servidor, SqlString Ds_Servico)
{
try
{
ServiceController sc = new ServiceController(Ds_Servico.Value, Ds_Servidor.Value);
sc.Stop();
}
catch (Exception e)
{
Retorno.Erro("Erro : " + e.Message);
}
}
};
SQL Server: SC ServiceController Class CLR detiene los servicios de Windows
¡Eso es todo, amigos!
Espero que te haya gustado el post. Es realmente genial crear cosas diferentes usando la base de datos.
Si tienes alguna duda déjala aquí en los comentarios.
¡Abrazo!
servidor sql clr sqlclr controlador de servicio sc wmic servicios de windows lista de servicios de windows inicio y parada vista de lista inicio y parada
servidor sql clr sqlclr controlador de servicio sc wmic servicios de windows lista de servicios de windows inicio y parada vista de lista inicio y parada
Dirceu Resende
Arquitecto de Bases de Datos y BI · Microsoft MVP · MCSE, MCSA, MCT, MTA, MCP.
Comentários (0)
Carregando comentários…