Limpiando \Windows\Installer

Desde que instalé windows en mi equipo he visto que la carpeta del sistema C:\Windows\Installer crecía y crecía a medida que iba pasando el tiempo,..

Este comportamiento puede que para la mayoría de personas no sea un problema, pero en los equipos con una partición de sistema reducida (discos ssd, hostings vps,..) o en tablets puede llegar a colapsar el equipo.

Tras pasar CCleaner y varias herramientas más de liberación de espacio esa carepta seguia ocupando alrededor de 50GB, según Microsoft, esta carpeta contiene copias de seguridad de librerias y archivos del sistema que usan los instaladores y desinstaladores de las apliaciones del equipo.

Cuando una aplicación se desinstala es posible que no se eliminen correctamente este tipo de archivos, por lo que van quedando restos y la carpeta va creciendo.

Navegando un poco encontré la herramienta patchcleaner que busca archivos huerfanos y los elimina.

Se puede descargar de:

http://download.cnet.com/PatchCleaner/3000-2094_4-76399133.html?part=dl-10218687&subj=dl&tag=button

Con esta aplicación pude eliminar 30Gb de esa carpeta dejando espacio disponible para mis documentos y archivos.

Espero que os sirva de ayuda

Tratando logs con awk

Hoy en el trabajo me he encontrado con una problemática bastante común cuando tratamos de filtrar logs: mucha información que no nos interesa.

Para solventar este problema, habitualmente, la primera aproximación sería con grep y cut pero habitualmente se quedan cortos ya que es complicado usarlos para filtrar por fecha/hora.

En este ejemplo se usará un archivo de log del estilo

2016/06/29 17:10:35.838:Fatal error core dumped
2016/06/29 17:15:35.838:Fatal error core dumped
2016/06/29 17:20:35.838:Fatal error core dumped
2016/06/29 17:30:35.838:Fatal error core dumped

Para poder filtrar por hora, podemos usar awk, en el siguiente script contaremos el numero de líneas que hay en un intervalo de tiempo determinado (por defecto, los últimos 15 min).

#!/bin/awk -f

BEGIN {

if(minutos==""){minutos=15 }
    umbral = minutos *60  # Miramos los ultimos N segundos del log 
    now = strftime("%H:%M:%S",systime())
    counter=0;
    debug=0
 }
{ 
    split($2,chunks,".");
    hour=chunks[1];
    m=split(hour,w,":")
    n=split(now,t,":")
    FIRSTTIME= (t[1]*3600) + (t[2]*60) + t[3]
    SECONDTIME= (w[1]*3600) + (w[2]*60) + w[3]
    DIFFTIME=(FIRSTTIME - SECONDTIME)
    if (debug == 1){
        printf("%s|%s|%s\n",FIRSTTIME,SECONDTIME,DIFFTIME)
    }
    if(DIFFTIME < umbral ){
        counter++;
    }
}
END { print  counter }

Para ejecutarlo bastaría con ejecutar:

cat mylog.log | awk -f script.awk -v minutos=8

Y el resultado sería

echo '2016/06/29 17:10:35.838:Fatal error core dumped
2016/06/29 17:15:35.838:Fatal error core dumped
2016/06/29 17:20:35.838:Fatal error core dumped
2016/06/29 17:30:35.838:Fatal error core dumped' | awk -f /var/www/scripts/countSuperacionesAma.awk -v minutos=8
1

Pues de este modo tan sencillo podemos tratar logs en función del tiempo.

Streaming procesos en php

En determinadas ocasiones he necesitado generar una web que me ejecute un proceso del sistema operativo que tarda bastante. Es bastante frustrante tener que esperar a que el proceso termine para saber como se está ejecutando, si eres tan impaciente como yo, este es tu código.

<?php
header('Content-Type: text/html; charset=utf-8');
header('Cache-Control: no-cache');
ini_set('max_execution_time', 600);
echo '<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />';
echo "<style type='text/css'>
 body{
 background:#000;
 color: #7FFF00;
 font-family:'Lucida Console',sans-serif !important;
 font-size: 12px;
 }
 </style></head><body>";
?>

El primer paso es configurar el timeout de la aplicación para que PHP no cierre el proceso, acto seguido indicamos al navegador que esta web no se debe cachear. Y para darle un poco de formato generamos el estilo de una consola de MSDOS.

El siguiente paso es preparar la salida de PHP para que vaya enviando por el socket HTTP la información que se genera sin esperar a que finalice la ejecución del script.

<?php

function disable_ob() {
    // Turn off output buffering
    ini_set('output_buffering', 'off');
    // Turn off PHP output compression
    ini_set('zlib.output_compression', false);
    // Implicitly flush the buffer(s)
    ini_set('implicit_flush', true);
    ob_implicit_flush(true);
	ob_end_flush();
    // Clear, and turn off output buffering
    while (ob_get_level() > 0) {
        // Get the curent level
        $level = ob_get_level();
        // End the buffering
        ob_end_clean();
        // If the current level has not changed, abort
        if (ob_get_level() == $level) break;
    }
    // Disable apache output buffering/compression
    if (function_exists('apache_setenv')) {
        apache_setenv('no-gzip', '1');
        apache_setenv('dont-vary', '1');
    }
}

// tell php to automatically flush after every output
// including lines of output produced by shell commands
disable_ob();
flush();
?>

Para finalizar sólo nos queda ejecutar el comando e ir imprimiendo su salida. En este caso voy a ejecutar un script en python “unbufered” para que el intérprete no se guarde la salida estándar hasta que termina de ejecutar el comando:


$cmd = 'python -u automate.py 2>&1'; 
$pid = popen( $cmd,"r");
 
echo "<body><pre>";
while( !feof( $pid ) )
{
 echo fread($pid, 256);
 flush();
 //ob_flush();
 echo "<script>window.scrollTo(0,99999);</script>";
 usleep(100000);
}
pclose($pid);

Con las líneas:

 echo "<script>window.scrollTo(0,99999);</script>";
 usleep(100000);

Conseguimos el navegador haga scroll hasta la última linea impresa y que PHP no consuma más recursos de los necesarios ya que no es necesario que esté todo el tiempo comprobando la salida estándar del proceso ejecutado.

Resultado:

Console

Matar un proceso en Windows

Esta tarde un compañero me ha pedido si conocía si se podía matar un proceso dependiendo de la RAM que consumía y relanzarlo sin utilizar nada más que no fuera BATCH en Windows XP,… si señores BATCH 🙂

Pues evidentemente le dije que no lo sabía pero que lo investigaría. Y este ha sido el resultado, este script mata cualquier cmd.exe que consuma más de 4000Kb de RAM.

@echo off
set process=cmd.exe
set memLimit=4000
tasklist /FI "IMAGENAME eq %process%" | findstr  %process% > tmp
for /f "tokens=5" %%x in (tmp) do set memUsage=%%x
echo "Memusage %memUsage%"
if %memUsage% gtr %memLimit% goto killme
goto end 
:killme
taskkill /f /FI "IMAGENAME eq %process%"
%process%
:end
echo "fin"
del tmp

Sé que se puede mejorar el uso de archivos temporales pero.. como le dije a mi compñero BATCH no es mi fuerte

Snippet Consultar Active directory / LDAP

Este post trata de como consultar de una manera sencilla el Active Directory/LDAP corporativo, en concreto se extraerá la fecha de caducidad de una cuenta conociendo el login.

Antes de nada, hay que tener en cuenta que LDAP almacena las fechas a partir de los segundos transcurridos desde el 1 de enero de 1601. Por ello vamos a introducir en el código la siguiente función que nos ayudará a tratar con este tipo de fechas:

/// <summary>
/// Esta función convierte el tiempo de LDAP (AD) en una variable DateTime
/// </summary>
/// <param name="accountExpires">LDAP time</param>
/// <returns>La representación datetime del LDAP</returns>
static DateTime longToDatetime(Int64 accountExpires) {
      DateTime expireDate = DateTime.MaxValue;
      if (!accountExpires.Equals(Int64.MaxValue))
           expireDate = DateTime.FromFileTime(accountExpires);

       return expireDate;
   }

A continuación viene el código que tiene algo más de chicha, el acceso a AD:

public class UserResult {
        public String Name;
        public DateTime ExpireDate;
    }
 static UserResult GetUser(String userId)
        {
            UserResult res;
            DirectoryEntry searchRoot = new DirectoryEntry(dominio, "user","password");
            DirectorySearcher search = new DirectorySearcher(searchRoot);
            search.Filter = "(&(objectClass=user)(samaccountname="+userId+"))";
            search.PropertiesToLoad.Add("accountExpires");
            search.PropertiesToLoad.Add("samaccountname");
            SearchResult result;
            SearchResultCollection resultCol = search.FindAll();
            if (resultCol == null) { return null; }
            result = resultCol[0];
            res = new UserResult();
            res.ExpireDate = longToDatetime((Int64)result.Properties["accountExpires"][0]);
            res.Name = (string)result.Properties["samaccountname"][0];
            return res;
            
        }

El codigo anterior se conecta al active directory especificado por la variable dominio y por un usuario que tenga privilegios en el AD.

El string de domintio tiene que tener la forma:

const string dominio= "LDAP://DC=organizacion,DC=com";

Solucionar problemas de underscan y overscan en Windows 10

En este post se va a tratar el problema del underscan y el overscan que sufren algunas tarjetas de vídeo al conectarse a pantallas de alta definición habitualmente por HDMI.

Este tipo de problemas generan una reducción del espacio efectivo de la pantalla (underscan). Comprime la imagen y al rededor genera un marco negro no permitiendo aprovechar el 100% de la pantalla.

El overscan es el problema contrario expande la imagen y por esta razón deja de caber en la pantalla.

Si tenemos una tarjeta ATI, desde el ATI Catalyst Center se puede modificar este comportamiento, siempre que no tengamos Windows 10 y una tarjeta antigua o sin soporte. En mi caso era una ATI HD4650.
Sigue leyendo