Enviar resultados de Query en SQL Server vía Mail.


El Problema: Resulta que necesitaba hacer un gráfico de tendencia en Grafana, sin embargo el plugin de tendencia se me hacia rudimentario y la solución para implementarlo vía SQL Server que se parece a algo así (asumiendo que se tiene un ID secuencial):

create table #temp
(
entity_id int,
value int,
[date] datetime
)

insert into #temp (entity_id, value, [date])
values
(1,10,'20140102 07:00:00 AM'),
(1,20,'20140102 07:15:00 AM'),
(1,30,'20140102 07:30:00 AM'),
(2,50,'20140102 07:00:00 AM'),
(2,20,'20140102 07:47:00 AM'),
(3,40,'20140102 07:00:00 AM'),
(3,40,'20140102 07:52:00 AM')

select entity_id, 1.0*sum((x-xbar)*(y-ybar))/sum((x-xbar)*(x-xbar)) as Beta
from
(
select entity_id,
avg(value) over(partition by entity_id) as ybar,
value as y,
avg(datediff(second,'20140102 07:00:00 AM',[date])) over(partition by entity_id) as xbar,
datediff(second,'20140102 07:00:00 AM',[date]) as x
from #temp
where [date] >= '20140102 07:00:00 AM' and [date] < '20140102 08:00:00 AM' ) as Calcs group by entity_id having 1.0*sum((x-xbar)*(y-ybar))/sum((x-xbar)*(x-xbar)) > 0

La neta se me hacía muy complejo, así que pensé, ¿por que no enviar el resultado de la consulta a una hora determinada a mi correo, después aplicar tendencia con excel y finalmente insertar el resultado de excel con un bulk insert, y pues funcionó.

Para contextualizar, primero la estructura de datos en la tabla es muy simple son tres columnas Fecha, Total, FactoryID; algo así:

Fecha|Total|Planta
2018-09-28|7237.14|FACTORY1
2018-09-29|5509.88|FACTORY1
2018-09-30|4903.39|FACTORY1
2018-10-01|4498.54|FACTORY1
2018-10-02|2139.11|FACTORY1
2018-10-03|8998.51|FACTORY1
2018-10-04|5423.95|FACTORY1
2018-10-05|5354.85|FACTORY1
2018-10-06|5311.04|FACTORY1
2018-10-07|5267.23|FACTORY1

Entonces, avanzando por partes, primero necesitaba una query en SQL que me trajera sólo los últimos 7 días de esa tabla ya que tiene el acumulado de todo el año, esta es:

SET NOCOUNT ON
select * from Totales
where Fecha > CONVERT(date, GETDATE() - 8)
order by Planta, Fecha

Bien, primer parte resuelta, observamos que tiene activado SET NOCOUNT esto es importante para que no envíe el resultado de la consulta con el total de registros, ¿y ahora como demonios envíamos el resultado de esta consulta vía mail?, bien la respuesta que yo encontré (aclaro, puede haber un método mejor y más simplificado,…)

Primero una consulta (que se deja como procedimiento almacenado a ejecutarse a una hora específica), esta consulta usa dos herramientas,  xp_cmdshell y sqlcmd, ahi denle una leída a la documentación para que vean como usarlos y que pueden realizar con ellos, en este caso grosso modo el primero lo uso para ejecutar al segundo y algunos comandos adicionales, la cosa queda así:

--Se selecciona la base a usar
use TUBASE
Go
--Se declaran las variables necesarias
DECLARE @Ruta varchar(20)
DECLARE @Nombre VARCHAR(20)
DECLARE @ComandoA VARCHAR(40)
DECLARE @ComandoB VARCHAR(120)
DECLARE @ComandoC VARCHAR(120)
--Se asignan valores a las variables, en este caso para los comandos se usaron estas variables para poder:
-- 1- Eliminar todo los archivos txt de la ruta de almacenaje (para no crear garbage)
-- 2- Asignar la cadena de comando de sqlcmd concatenando la fecha como nombre del archivo
-- 3- ejecutar un script de powershell pasando como argumento el nombre del archivo generado en el paso 2
set @Ruta = 'TURUTA'
set @Nombre=CONVERT(varchar,getdate(),105)+'.txt'
set @ComandoA ='del /F /S /Q C:\TURUTA\*.txt'
set @ComandoB ='sqlcmd -i C:\TURUTA\Last7days.sql -S localhost -d TUBASE -E -s ";"  -o '+@Ruta+@Nombre
set @ComandoC = 'powershell -file C:\TURUTA\attachtrend.ps1 '+ @Ruta + @Nombre 

--  Se ejecutan los comandos, uno a la vez, easy tiger.
EXEC xp_cmdshell @comandoA
EXEC xp_cmdshell @ComandoB
EXEC xp_cmdshell @ComandoC

Como les comentaba con esta consulta se crea un procedimiento almacenado se programa a una hora y voilà.

La cereza del pastel, es el script de powershell que hace las veces de enviar el archivo TXT generado por SQLCMD, una rutina simple que toma como parametro el nombre del archivo generado:

param([string]$nombre)

    $smtpClient = new-object system.net.mail.smtpClient
    $smtpClient.Host = "TUSERVERSMTP"
    $smtpClient.Port = TUPUERTO
         
    $emailfrom = "EMAILORIGEN"
    $emailto = "EMAILDESTINO"
    $subject = "ASUNTODEMAIL"
    $body = "TEXTODEMAIL"
    
    $emailMessage = New-Object System.Net.Mail.MailMessage
    $emailMessage.From = $EmailFrom
    $emailMessage.To.Add($EmailTo)
    $emailMessage.Subject = $Subject
    $emailMessage.Body = $Body
    $emailMessage.Attachments.Add($nombre)
    $SMTPClient.Send($emailMessage)

Con todo esto como magia, me llega un txt del diario 7:30 AM, el cual modifico en excel para agregar las tendencias por los siguientes 3 días, luego lo exporto como TXT sin header (con nombre ‘trend.txt’) y lo inserto en mi tabla con un BULK insert, así:

BULK INSERT Totales
   FROM 'C:\TURUTA\trend.txt'  
   WITH   
      (  
         FIELDTERMINATOR =',',  
         ROWTERMINATOR ='\n'  
      );  

Finalmente el resultado en grafana es este:

Espero le sirva a alguien, Salu2, Emmanuel.

Bienvenidos a la Feria de Santiaguito (Odio mi Pobreza)


Antes de empezar, voy a abrir mi paraguas por que seguramente me van a llover mentadas de madre, y pues son gajes del oficio, pero los invito a leer mi argumento y si lo refutan, con gusto voy y la chingo.

En el reglamento de movilidad reza de manera íntegra en su página 2:

“Que el Secretario de Movilidad podrá tomar medidas para salvaguardar las condiciones que motivaron el otorgamiento de las concesiones, evitar se cause un perjuicio o riesgo para el servicio o el usuario, e incluso para preservar la movilidad del lugar en que se presta el mismo, incluyendo la cancelación u otorgamiento, en términos de ley.
Que las concesiones, permisos y autorizaciones del transporte público y sus servicios conexos son de interés público,por ende, se hace necesario continuar y concluir la situación en que se encuentran diversos prestadores del servicio, quienes, por diversas causas, no han finalizado sus trámites dentro del marco legal que los obliga a ser competentes y eficaces en su actividad.”

En el mismo reglamento podemos encontrar las responsabilidades respecto a los Seguros de Viajero (usuarios), en los artículos 24 sección VII, 25 sección XVII y 26 sección I; y aclaro, no es nada nuevo puesto que en este otro reglamento (observe usted la fecha) en el articulo 54 y 55 se aborda de igual manera el tema del seguro a usuarios.

Pero miren que no es berrinche, por que si volteamos a ver quienes son los pendejos tontos podemos ver la gaceta del 20 de marzo, sí esa por la que se pararon de pestañas los concesionarios y transportistas; y esta otra gaceta del 14 de Abril del 2014, observamos que los pendejos tontos somos los usuarios, por no exigir que se cumpla lo estipulado por la ley con el afán de salvaguardar la integridad de todos: operadores y usuarios.

En otro orden de ideas, les pregunto: ¿alguien aquí es corredor de seguros?, bueno si alguien lo es pendejeeme corríjame si me equivoco, pero en el caso de un accidente en el transporte público una cosa básica que se averigua, es si la unidad se operaba en condiciones normales y dentro de la norma, una de ellas el sobrecupo, si alguien a pedido uber se habrán dado cuenta que la mayoría dice máximo 4 personas, la razón es simple así fué diseñado el auto y eso es lo que cubre el seguro, para fácil un auto compacto con 8 personas arriba no aplica, lo normal son 5, 2 adelante y 3 atrás.

Y si ya llegaron hasta acá leyendo se preguntara usted amable lector ¿Que chingados tiene que ver con el título?, permítame a usted platicarle mi historia de hoy.

Yo soy pobre, tengo que usar el transporte público en la ruta Tenango-Santiaguito-Rayón, normalmente en taxi, por que aparte soy gordo y en las cajitas (Vans) no me acomodo.

Hoy de regreso realicé escala en Santiaguito, y para completar la ruta a Tenango abordé un taxi de la base “Galicia” (que al día de hoy, no me he topado con uno sólo que hable gallego), acompañado de mis 2 acreedoras (mis hijas pues) y aquí viene mi pecado y tal vez el de muchos mexicanos: la maldita pobreza. Esta última me hizo pensar que mis hijas ocupan un solo espacio de viajero (en realidad así es, la pobreza a ella las hizo flacas y a mi gordo), por lo que nos subimos en la parte de atrás, donde ya había una chica con su bebé en brazos (por favor si lees esto, corrobora la historia) entonces, antes de arrancar ya habíamos 4 católicos, un teísta agnóstico (ósea yo) y el amable/gentil operador, avanzado un tercio del viaje subió una persona más, y así llegamos nuestro destino, haga usted sus cuentas de cuantas personas en total íbamos abordo.

Me dispuse a pagar al amable/gentil operador, que tampoco hablaba gallego a Dios gracias, y aconteció lo siguiente:

Operador: Le comento que mayores de 5 años pagan pasaje
Yo: Claro, sólo por favor muéstrame tu seguro de viajero
Operador:¿Seguro de Viajero?, que es eso
Yo (con cara de “no mamar”): Sí, ósea si nos pasa algo como justificamos que pagué
Operador:No pues no traigo, pero por esta vez le voy a cobrar 2
Yo(molesto y ya descendiendo de la unidad): No cobrame 3, ¿que número de unidad tienes?
Operador: No así déjalo, pero para la próxima ya sabe
Yo: Si desde un inicio me dices que me vas a cobrar 3, ocupo 3 lugares y te pago 3, no hasta que voy a bajar

Entonces, no quiero que me den la razón, pero si hubiera pagado los 3 y hubiera acontecido un accidente, solo 5 personas hubiéramos sido cubiertas por el seguro, eso incluía forzosamente al operador (así lo establece el seguro) y 4 más, el resto hubieran sido volados.

Así que si vienen a la feria de Santiaguito, bienvenidos, pero traigansen (typo adrede) su pasaje para cualquier acompañante mayor de 5 años, ya no cuenta en piernas y de cualquier modo exijan  un cupo para 4 personas.

Aunque esto me lleva a otra lógica, la vuelta como local especial te la cobran a 45, es decir, como si fueran 5 personas, cuando el cupo es de 4, obviamente sin contar al chofer.

¿Que demonios falló ahí?, en todo caso tanto peca el que mata a la vaca, como el que le agarra la pata.

P.D. La foto cortesía de mi esposa, Te Amo Mucho.

Alertas en un Bot de Telegram con Powershell


Una de las necesidades de un Sysadmin, es  informarse en tiempo y forma de todos los errores y warnings de los servicios de misión crítica, ya que ellos implican tiempos muertos, en el peor de los casos, pero sobre todo de riesgos que se pueden remediar a través de acciones preventivas.

El visor de eventos de Windows Guindos tiene mucha información al respecto y en muchos de los casos nos da información clave para solventar un problema.

De ahí surgió la idea de enviar los eventos relevantes a través de un medio que me permitiera tenerlos ipso facto, intente primero por e-mail, pero no soy fan ni de enviar ni de recibir correos, además de que la cuenta de correo institucional, no la toco ni de chiste fuera de horas de trabajo y no quería llenarla de spam, para luego tener que depurarla.

Así que tenía instalado el Telegram y un Bot personal, que sabía que podía ocupar para eso, pero no tenía ni idea de como hacerlo, así que me puse a investigar y el resultado es el siguiente:

PRERREQUISITOS
  • Tener un Bot de telegram, sino saben como aquí está documentado
  • Tener la API Key de ese Bot
  • Tener el ChatID de un chat de tu cuenta con tu Bot, ese lo pueden obtener con un Bot que hay en Telegram, búsquenlo se llama @my_id_bot
  • Paciencia y un entorno de pruebas donde no puedas hacer mal a nadie.

A continuación el script, esta completamente documentado de manera clara, por lo que creo no debería haber dudas y si las hay, los leo en comentarios o al e-mail.

#Se declaran las variables
#Obtenemos el pool de eventos, seleccionamos el log, el origen y el ID del evento, luego se selecciona el primero (el último, más reciente)
$event = Get-EventLog -LogName System -Source "Microsoft-Windows-Directory-Services-SAM" | where {$_.eventID -eq 12294} | Select-Object -First 1
#Asiganos el valor del BotKey que nos da BotFather
$BotKey = "TUBOTKEY"
#Seleccionamos los parámetros de formato regional México
$culture = New-Object system.globalization.cultureinfo("es-MX")
#Extraemos la fecha del evento
$Fecha=Get-date $event.TimeGenerated -Format ($culture.DateTimeFormat.LongDatePattern)
#Extraemos la hora del evento
$Hora =Get-date $event.TimeGenerated -Format ($culture.DateTimeFormat.LongTimePattern)
##Extraemos el texto del evento
$mensaje = $event.Message
#Conectamos a la API de telegram con la key asignada
$GetChatID = Invoke-WebRequest -Uri "https://api.telegram.org/bot$BotKey/getUpdates"
#Se crea la función que manda el mensaje a telegram, recibiendo de parametros la BotKey, ChatID (como Array por si fueran varios) y el mensaje
function Send-TeleMessage([string] $BotKey , [array] $ChatIDs , [string] $Message)
{#Se cre la variable con la URL de la API que ejecuta el envío del mensaje
    $sendMsgLink = "https://api.telegram.org/bot$BotKey/sendMessage"
    #Se crea al bucle para cada elemento del Array
    foreach ($ID in $ChatIDs)
    {        
        try
        {#Se ejecuta el POST a la URL            
            $ExecuteInvokeWeb = Invoke-WebRequest -Uri "$sendMsgLink" -Method Post -ContentType "application/json;charset=utf-8" -Body (ConvertTo-Json -Compress -InputObject @{chat_id=$ID; text="$Message"}) -ErrorAction SilentlyContinue
            #Se recibe el resultado del POST
            $Status = (ConvertFrom-Json -InputObject $ExecuteInvokeWeb.Content)
            #Si el resultado, es ok, envia un mensaje satisfactorio, sino hace un catch del error y lo muestra.  
            if($Status.ok){Write-Host "El mensaje se envío correctamente al Chat ID : $ID (Type : $($Status.result.chat.type))" -ForegroundColor Green}
        }
        catch [Exception]
        {
            $exception = $_.Exception.ToString().Split(".")[2]
            Write-Host "Falló el envío del mensaje al Chat ID : $ID ($exception)" -ForegroundColor Red
        }
    }
}
#Se ejecuta la función con los parametros necesarios
Send-TeleMessage -BotKey $BotKey -ChatIDs "TUCHATID" -Message "$($Fecha) $($Hora) $($mensaje)"

Después de esto, hay que crear una tarea programada en windows, que ejecute este script cada que se genere un registro del evento, evidentemente el ID del evento debe coincidir para que informa de manera asertiva, el resto de las adecuaciones a sus necesidades deberían ser sencillas y el resultado es algo como esto:

Salu2, Emmanuel.

Festival V Sol 2018


Una de las cosas que se debe agradecer siempre y a quién sea, es el acercamiento de la cultura para con la sociedad, el culturizarnos, aprender y conocer, siempre nos hará mejores seres humanos.

Realmente, además del atractivo turístico claro está, es la intención de este Festival que es ya una tradición en el municipio: acercarnos a la cultura.

Están todos invitados, propios y ajenos a este festival, ¿y porque no?, se siguen con la representación de la pasión de Cristo la siguiente semana.

Les dejo el cartel para que vean horarios, fechas e invitados.

¡Estoy Viejo!


Cada vez me da más flojera estar abriendo el pinche evernote para hacer notas, que sacar el papel y boligrafo para apuntar, no sé hace algún tiempo se me hacia tan arcaíco que en juntas a las que era requerido y en la que habitualmente la gente me saca en promedio 15 años, sacaban su lápiz y papel para hacer sus notas de trabajo.

Y la neta no sé que pasa  a nivel estructura cerebral, pero definitivamente tu forma en que percibes la realidad va cambiando al pasar de los años, o te haces guevón, no sé.

De hecho mi modus vivendi son las tecnologías de la información y comunicaciones (TIC’s, pa’ los cuates), sin embargo, he entrado en una fase de aversión, que simplemente no me explico; una vez que entiendes los riesgos de tener toda la información  en computadoras y lo vulnerables que son en muchísimos sentidos, a veces quisiera declararme fan del papel/lápiz y decirle amablemente al contador que sería “Más seguro”, si hiciera su trabajo en un libro florete; pero pues de ahi trago, sería incoherente… o tal vez una certificación en seguridad informática cambiaría mi perspectiva.

Eso por el lado de las tecnologías, por el lado de la comida, me ceno dos tacos (de esos de Velázquez) y al otro día parece que me trague 2 pomos de tequila, es más creo que si me tomo los 2 de tequila amanezco mejor, el pinche metabolismo va de rodillas, tienes que controlar lo que comes por aquello del colesterol, trigliceridos, glucosa, colitis, gastritis y todo lo que termina en ITIS o lo que comienza con HIPER. No puedo comer demasiadas harinas, por que me da el mal del jabalí, en serio que si me pasó de tortillas, 20 minutos despues de la comida ya se me quieren voltear los ojos para ver que tengo por dentro en la nuca, está cabrón.

Cuando decides ponerte borracho, ya no te empedas, te gana el pinche sueño, pareces gato en el sol que de a poco se queda dormido hasta caer en coma, y si tomas cerveza, o te duele la rodilla o el brazo al otro día, y sino logras dormirte, al otro día ya tienes un apodo del tipo “Bob Esponja” por absorber tantísima cantidad de alcohol sin estallar.

Me caga que me refieran como Don o Señor, no manchen tengo 35 (por terracería y freno de mano puesto, pero 35 apenas), pero me caga más que asuman un titulo educativo, cuando soy un humilde campesino llamado Emmanuel Fernando, bueno, un campesino con suerte.

Pero vas al doctor, te toma la presión, la glucosa, el colesterol, etcetera, etcetera y lo único que traes alta es la pinche panzota y eso por que te reviso acostado, si duermes mal andas con contractura tres días… sí increible, te lesionas dormido.

Y cuando les hablo a mis hijas de las guerras de harina en las kermés, se me quedan viendo como si fuera un simio tratando de abrir una nuez con una piedra, me dicen que Contra (si el video juego) esta “Muy Antiguo” y me ganan a saltar la cuerda por resistencia, es decir, no solo estoy viejo, sino gordo jajajaja 🙁

Empiezo a ir a todo tipo de fiestas y reuniones familiares y no familiares, aún cuando odiaba asistir y le quito la grasa excente a la comida con una servilleta.

Le doy más valor al hacer, que al decir.

Me lleva la chingada.