I’m Back


Bueno, heme aquí de nuevo.
Igual y el segmento de personas que entran es un ápice de lo que en un inicio pretendía ser, sin embargo aqui continúa el proyecto de pie.
Desde Febrero había quedado fuera por tema de hosting, realmente no había costos competitivos y aunque GoDaddy era bueno, el costo para renovación es demasiado elevado.
Al final, puse en marcha habilidades de negociación y técnicas, ya con eso se levanto el muertito, como siempre, espero tener tiempo de escribir más por acá.

Les dejo foto de una amiga, en el patio de la casa el fin de semana pasado.
Disfruten, es gratis.

View this post on Instagram

Una amiga #butterfly

A post shared by Ⓝⓐⓝⓓⓘⓣⓞ (@fermman) on

9 Reglas del Pensamiento Escéptico.


Ergo el tema del robo de combustible y la guerra mediática de todos los que llevan puesta la camiseta de un partido político (y en muchos varios casos, de los que no), les dejo una información que bien podría ayudarles a discernir de manera correcta la situación y viene directo de la mano de Carl Sagan:

  • Siempre que sea posible debe haber una confirmación independiente de los «hechos».
  • Estimular un exhaustivo debate involucrando a los defensores y detractores mejor informados, desde todos los puntos de vista.
  • Los argumentos de autoridad tienen poco peso. Las «autoridades» han cometido errores en el pasado. Lo harán de nuevo en el futuro. Puede que sea mas correcto decir que en la ciencia no hay autoridades; como máximo, hay expertos.
  • Barajar más de una hipótesis. Si hay algo que explicar, piense en todas las diferentes formas en las que se podría hacer. Luego piense en formas con las que poner a prueba y poder refutar sistemáticamente cada una de las alternativas. Lo que sobrevive, la hipótesis que resiste la refutación en esta selección darwiniana entre «múltiples hipótesis de trabajo», tiene la mejor oportunidad de ser la respuesta correcta que si simplemente se hubiera quedado con la primera idea que pasó por su mente.
  • Intente no encariñarse con una hipótesis sólo porque es la suya. No es más que una estación de paso en la búsqueda del conocimiento. Pregúntese por qué le gusta la idea. Compárela a fondo con las alternativas. Vea si se pueden encontrar razones para rechazarla. Si usted no lo hace, otros si lo harán.
  • Cuantificar. Si aquello a lo que se busca explicación es susceptible de medirse, de atribuirle alguna cantidad numérica, tendrá mucha más capacidad para ser discriminada entre hipótesis rivales. Lo que es ambiguo y cualitativo está abierto a muchas explicaciones. Por supuesto que hay verdades que han de ser buscadas en numerosos ámbitos cualitativos a los que estamos obligados a enfrentarnos, pero encontrarlas es más difícil.
  • Si hay una cadena de argumentos, todos los eslabones deben ser correctos (incluyendo la premisa) —no sólo la mayoría de ellos .
  • Navaja de Occam. Esta conveniente regla de oro nos insta a elegir la solución más simple cuando se enfrentan dos hipótesis, que explican igualmente bien los datos.
  • Siempre pregúntese si la hipótesis puede ser, al menos en principio, falsable. Las proposiciones que son incontrastables o infalsables no sirven de mucho. Considérese la abrumadora idea de que nuestro universo y todo en él es sólo una partícula elemental —un electrón, por ejemplo— en un cosmos mucho más grande.Pero, si nunca podemos adquirir información de fuera de nuestro universo, ¿cómo se puede saber si es cierto o no? Se ha de ser capaz de verificar las afirmaciones. Hasta el mayor de los escépticos ha de tener la oportunidad de seguir su razonamiento, de forma que pueda repetir el experimento y ver si consigue el mismo resultado.

Así que dejémonos de hacer chaquetas mentales y pensar que por que nos pusimos la cachucha de un partido político nos las sabemos todas.

Emmanuel

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.