Utilizando connmon comprobé que no podía mostrar la ruta del fichero de procesos protegidos, así que para resolverlo he actualizado connmon a la versión v1.1, de forma que pueda mostrar este dato en esos casos. Para que lo anterior funcione es necesario iniciar connmon desde una línea de comandos con permisos de administrador local.
Otra de las mejoras que también he implementado en esta versión es la de identificar las conexiones del sistema (proceso 4) como System en la columna ProcessPath.
La versión v1.1 está disponible en este enlace.
lunes, 6 de agosto de 2018
martes, 4 de octubre de 2016
connmon v1.0 - Lista las conexiones actuales
Es muy interesante saber qué proceso se está comunicando con un host remoto en un momento dado, sobre todo en diagnósticos donde existan sospechas de algún troyano.
Existen un par de herramientas muy recomendables para averiguar la información de las conexiones activas que se están produciendo en Windows: netstat y tcpview.
Dando una vuelta a las API's de Windows que utilizan la información de la pila TCP/IP encontré la posibilidad de crear una herramienta que me proporcionara en un momento dado la información realmente relevante para llevar a cabo un diagnóstico como el mencionado antes, de forma rápida y eficiente. Esta información sería: de la parte remota la IP y el puerto, y de la parte cliente el puerto, el ID del proceso cliente y la ubicación de la imagen ejecutable del proceso.
Para ello desarrollé una pequeña herramienta que solo me proporciona esta información: connmon.exe
Y el resultado puede ser así:
De un vistazo vemos que en un momento dado el proceso de experiencia de usuario de NVIDIA se está comunicando con una IP pública (supuestamente de NVIDIA) y Google Earth hace lo mismo con otras IPs (supuestamente de Google).
Si volvemos a ejecutar connmon.exe es muy posible que esta información sea distinta. Sería como hacer una foto de las conexiones actuales y verlas.
De esta forma, en caso de sospecha, connmon.exe nos ayuda a ser rápidos.
Existen un par de herramientas muy recomendables para averiguar la información de las conexiones activas que se están produciendo en Windows: netstat y tcpview.
Dando una vuelta a las API's de Windows que utilizan la información de la pila TCP/IP encontré la posibilidad de crear una herramienta que me proporcionara en un momento dado la información realmente relevante para llevar a cabo un diagnóstico como el mencionado antes, de forma rápida y eficiente. Esta información sería: de la parte remota la IP y el puerto, y de la parte cliente el puerto, el ID del proceso cliente y la ubicación de la imagen ejecutable del proceso.
Para ello desarrollé una pequeña herramienta que solo me proporciona esta información: connmon.exe
Y el resultado puede ser así:
De un vistazo vemos que en un momento dado el proceso de experiencia de usuario de NVIDIA se está comunicando con una IP pública (supuestamente de NVIDIA) y Google Earth hace lo mismo con otras IPs (supuestamente de Google).
Si volvemos a ejecutar connmon.exe es muy posible que esta información sea distinta. Sería como hacer una foto de las conexiones actuales y verlas.
De esta forma, en caso de sospecha, connmon.exe nos ayuda a ser rápidos.
Perl6 y la capacidad de los discos
Llevo ya unos meses introducido en el mundo de Perl6 y cada vez me parece más interesante. Ya he contribuido con la traducción de la Introducción a Perl6 y por otro lado he publicado hace poco mi primer módulo de Perl6: FileSystem::Capacity::VolumesInfo.
El objetivo de este módulo es proporcionar información al usuario sobre la capacidad de los puntos de montaje o unidades (dependiendo del sistema operativo) en un momento dado. Esta información servirá de ayuda para tomar medidas cuando estas capacidades están cerca de su límite, como por ejemplo eliminar o mover archivos, y así evitar el colapso de ese punto de montaje o unidad.
Este módulo es muy útil para administradores de sistemas y tengo la idea de complementarlo con más módulos que proporcionen información útil del sistema para hacer la vida más fácil a los sysadmin, pero ¡con Perl6!
Si eres un sysadmin y todavía no has probado Perl6, ¡te animo a ello!
El objetivo de este módulo es proporcionar información al usuario sobre la capacidad de los puntos de montaje o unidades (dependiendo del sistema operativo) en un momento dado. Esta información servirá de ayuda para tomar medidas cuando estas capacidades están cerca de su límite, como por ejemplo eliminar o mover archivos, y así evitar el colapso de ese punto de montaje o unidad.
Este módulo es muy útil para administradores de sistemas y tengo la idea de complementarlo con más módulos que proporcionen información útil del sistema para hacer la vida más fácil a los sysadmin, pero ¡con Perl6!
Si eres un sysadmin y todavía no has probado Perl6, ¡te animo a ello!
jueves, 28 de julio de 2016
Mini servidor HTTP & CGI con Perl6
Después de preparar la presentación de Una introdución a Perl 6 me llamó mucho la atención las funcionalidades que ofrece Perl6 sobre programación reactiva y gestión de eventos, así que después de mostrar cómo funciona un servidor HTTP con Perl5 me propuse hacerlo también con Perl6.
Con Perl6 es un poco distinto en cuanto a sintaxis y soporte multihilo pero la forma de gestionar HTTP es la misma. En cuanto al soporte multihilo existe la clase IO::Socket::Async.listen que proporciona la creación y puesta a la escucha de sockets asíncronos con soporte multihilo, de forma que por cada conexión crea un hilo alojado en un pool que Perl6 gestiona internamente.
La prueba de concepto la puedes encontrar aquí.
Este mini servidor web funciona en Windows y GNU/Linux con Rakudo Perl6 instalado y un par de módulos de Perl6 (URI y URI::Escape) que interpretan de forma adecuada las URIs que llegan al servidor.
La parte CGI se realiza mediante módulos de Perl6 y con el resto tenemos un servidor web funcional pero muy básico (solo contempla los códigos HTTP 200 y 404).
El frontal se compone de HTML, CSS y Javascript con JQuery para gestionar la conexión asíncrona con el script CGI de Perl6 que hace de servicio web.
Con Perl6 es un poco distinto en cuanto a sintaxis y soporte multihilo pero la forma de gestionar HTTP es la misma. En cuanto al soporte multihilo existe la clase IO::Socket::Async.listen que proporciona la creación y puesta a la escucha de sockets asíncronos con soporte multihilo, de forma que por cada conexión crea un hilo alojado en un pool que Perl6 gestiona internamente.
La prueba de concepto la puedes encontrar aquí.
Este mini servidor web funciona en Windows y GNU/Linux con Rakudo Perl6 instalado y un par de módulos de Perl6 (URI y URI::Escape) que interpretan de forma adecuada las URIs que llegan al servidor.
La parte CGI se realiza mediante módulos de Perl6 y con el resto tenemos un servidor web funcional pero muy básico (solo contempla los códigos HTTP 200 y 404).
El frontal se compone de HTML, CSS y Javascript con JQuery para gestionar la conexión asíncrona con el script CGI de Perl6 que hace de servicio web.
Etiquetas:
html,
http,
javascript,
linux,
perl6,
servidores web,
web
sábado, 21 de mayo de 2016
Contando hilos en GNU\Linux
Actualmente estoy bastante interesado en Perl6, sobre todo en la parte de cómo trata la concurrencia y el manejo de hilos. Perl6 incorpora una serie de objetos de alto nivel que facilitan estas situaciones. En este enlace tienes información en relación a ello.
Mientras tanto y realizando pruebas, he visto que en GNU/Linux hay una forma bastante elegante para comprobar el número de hilos abiertos de un script de Perl6 en ejecución, o de cualquier otro proceso:
Viene a decir: cada segundo (while sleep 1) lista los procesos activos (ps -eLf), no tengas en cuenta el proceso actual de grep (grep -v grep) y busca el número de veces que aparece el texto "script.pl6" (grep -c script.pl6).
Mientras tanto y realizando pruebas, he visto que en GNU/Linux hay una forma bastante elegante para comprobar el número de hilos abiertos de un script de Perl6 en ejecución, o de cualquier otro proceso:
while sleep 1; do ps -eLf | grep -v grep | grep -c script.pl6; done
Viene a decir: cada segundo (while sleep 1) lista los procesos activos (ps -eLf), no tengas en cuenta el proceso actual de grep (grep -v grep) y busca el número de veces que aparece el texto "script.pl6" (grep -c script.pl6).
domingo, 21 de febrero de 2016
Funcionamiento de un Servidor Web
En éste documento muestro el funcionamiento de un servidor web utilizando Perl; desde cómo crear un socket y ponerlo a la escucha, cómo hablar HTTP de forma básica y cómo utilizar las capacidades multihilo para lograr la máxima rapidez y eficiencia.
lunes, 7 de diciembre de 2015
diresp v3 - Tamaños de directorios más rápido
Después de ver cómo funciona la creación y gestión de múltiples hilos (multithreading) en la API de Windows, decidí aplicarlo a la herramienta diresp, de forma que calcule el espacio de cada directorio actual en su propio hilo. El resultado es significativamente más rápido.
Puedes descargar la versión 3 de diresp (diresp3.exe) desde este enlace.
Puedes descargar la versión 3 de diresp (diresp3.exe) desde este enlace.
miércoles, 8 de abril de 2015
diresp v2 - Tamaños de directorios
Hablamos de la versión 2 de diresp.exe, la herramienta presentada en el post anterior que muestra los tamaños de los directorios que se encuentran en el directorio actual.
La versión 2 está reescrita completamente en C y en su ejecución incorpora un texto de estado mostrando los directorios detectados e informando por cual va.
Otra de las novedades es la ordenación del listado de directorios por tamaños de menor a mayor, así podemos ver antes el directorio más nutrido.
La herramienta es bastante útil en unidades NTFS cortas de espacio, para detectar rápidamente dónde se concentran los archivos más pesados y eliminarlos o moverlos para liberar espacio, o simplemente averiguar qué directorios son los más pesados.
Actualmente solo está disponible la versión 3 clicando aquí.
La versión 2 está reescrita completamente en C y en su ejecución incorpora un texto de estado mostrando los directorios detectados e informando por cual va.
Otra de las novedades es la ordenación del listado de directorios por tamaños de menor a mayor, así podemos ver antes el directorio más nutrido.
La herramienta es bastante útil en unidades NTFS cortas de espacio, para detectar rápidamente dónde se concentran los archivos más pesados y eliminarlos o moverlos para liberar espacio, o simplemente averiguar qué directorios son los más pesados.
Actualmente solo está disponible la versión 3 clicando aquí.
lunes, 20 de octubre de 2014
diresp - Tamaños de directorios
Una de las situaciones más comunes en el ámbito de los sistemas operativos donde es necesaria una intervención rápida es la falta de espacio en disco. En estos casos, los administradores de sistemas tenemos que averiguar cómo está distribuido el espacio en disco y determinar qué archivos se pueden eliminar o mover.
La forma más rápida de diagnosticar estas situaciones es averiguar el tamaño de los directorios que cuelgan de un directorio dado. De esta forma podemos comprobar si los tamaños de estos directorios son razonables o no.
Para facilitar la tarea y conseguir esta información lo antes posible, he creado la herramienta diresp.exe. La versión actualmente disponible es la 3 y puedes descargarla en éste enlace.
Para mayor comodidad, conviene copiar esta herramienta en un directorio con Path, como C:\Windows\System32, después abrir la línea de comandos cmd, ubicarse en el directorio padre donde queremos comprobar los tamaños de sus directorios y ejecutar diresp3.exe.
Es posible que tarde un poco en listar los resultados dependiendo del número de subdirectorios y archivos, pero éstos aparecen ordenados por tamaño indicando el nombre del directorio hijo correspondiente. Una vez ubicado el directorio con tamaño sospechoso, podemos acceder a él y ejecutar de nuevo la herramienta (esta vez te aseguro que irá más rápido) hasta confirmar el directorio problemático.
La forma más rápida de diagnosticar estas situaciones es averiguar el tamaño de los directorios que cuelgan de un directorio dado. De esta forma podemos comprobar si los tamaños de estos directorios son razonables o no.
Para facilitar la tarea y conseguir esta información lo antes posible, he creado la herramienta diresp.exe. La versión actualmente disponible es la 3 y puedes descargarla en éste enlace.
Para mayor comodidad, conviene copiar esta herramienta en un directorio con Path, como C:\Windows\System32, después abrir la línea de comandos cmd, ubicarse en el directorio padre donde queremos comprobar los tamaños de sus directorios y ejecutar diresp3.exe.
Es posible que tarde un poco en listar los resultados dependiendo del número de subdirectorios y archivos, pero éstos aparecen ordenados por tamaño indicando el nombre del directorio hijo correspondiente. Una vez ubicado el directorio con tamaño sospechoso, podemos acceder a él y ejecutar de nuevo la herramienta (esta vez te aseguro que irá más rápido) hasta confirmar el directorio problemático.
Etiquetas:
rapidez,
sistema de archivos,
sysadmin,
utilidades
lunes, 16 de junio de 2014
Consultas a SQLServer desde Powershell
Si necesitas lanzar una consulta a una base de datos de SQLServer y que además permita cambiarla rápidamente, puedes utilizar Powershell y la clase System.Data.SqlClient.SqlConnection de .NET de la siguiente manera:
El resultado de esta consulta lista todas las bases de datos del servidor indicado.
Si la base de datos en cuestión está contenida en una instancia nombrada, la variable $servidor debe incluir el nombre de la instancia de la siguiente manera: nombreServidor\nombreInstancia.
Este tipo de scripts es especialmente útil para incluirlos en alguna tarea programada y recibir información con un intervalo determinado.
$consulta = "SELECT Name FROM sys.databases"
$srv = "nombreServidor"
$db = "master"
$conex = New-Object System.Data.SqlClient.SqlConnection
$conex.ConnectionString = "Server=$srv;Database=$db;Integrated Security=True"
$conex.Open()
$adaptadorSQL = New-Object System.Data.SqlClient.SqlDataAdapter
$resultado = New-Object System.Data.DataTable
$cmdSQL = New-Object System.Data.SqlClient.SqlCommand
$cmdSQL.CommandText = $consulta
$cmdSQL.Connection = $conex
$adaptadorSQL.SelectCommand = $cmdSQL
$contador = $adaptadorSQL.Fill($resultado)
$resultado
$srv = "nombreServidor"
$db = "master"
$conex = New-Object System.Data.SqlClient.SqlConnection
$conex.ConnectionString = "Server=$srv;Database=$db;Integrated Security=True"
$conex.Open()
$adaptadorSQL = New-Object System.Data.SqlClient.SqlDataAdapter
$resultado = New-Object System.Data.DataTable
$cmdSQL = New-Object System.Data.SqlClient.SqlCommand
$cmdSQL.CommandText = $consulta
$cmdSQL.Connection = $conex
$adaptadorSQL.SelectCommand = $cmdSQL
$contador = $adaptadorSQL.Fill($resultado)
$resultado
- La variable $consulta contiene la cadena con la consulta que queramos realizar.
- La variable $srv indica el nombre del servidor SQLServer en cuestión donde se realizará la consulta.
- La variable $db es el nombre de la base de datos a consultar en el servidor indicado.
- La variable $resultado contiene el resultado de la consulta en formato DataTable.
El resultado de esta consulta lista todas las bases de datos del servidor indicado.
Si la base de datos en cuestión está contenida en una instancia nombrada, la variable $servidor debe incluir el nombre de la instancia de la siguiente manera: nombreServidor\nombreInstancia.
Este tipo de scripts es especialmente útil para incluirlos en alguna tarea programada y recibir información con un intervalo determinado.
sábado, 1 de marzo de 2014
miniServidor Web en Windows
Mirando un poco cómo hacer una pequeña aplicación en lenguaje C para probar Sockets y comunicar programas a través de TCP/IP, encontré que el compilador LCC-Win trae una biblioteca llamada netutils.h dejando el asunto fácil y muy interesante.
Adaptando un poco el ejemplo de la aplicación servidor que trae la documentación, decidí dar un repaso al protocolo HTTP y crear un pequeño servidor Web.
El funcionamiento de este miniServidor Web sería muy sencillo y no cumpliría mucho con el estándar, pero para ver cómo funciona por dentro está bien. Lo que hace es lo siguiente:
El código fuente sería el siguiente (servidor.c):
Una vez creado servidor.c, en la misma carpeta creamos el archivo HTML que queremos publicar en nuestro miniServidorWeb (holamundo.html), cuyo código sería el siguiente:
Asumiendo que LCC-Win está instalado en c:\lcc y que tenemos la ruta de los binarios del compilador (c:\lcc\bin) incluida en la variable PATH del sistema, ya podemos compilar y enlazar:
lcc servidor.c
lcclnk servidor.obj c:\lcc\lib\netutils.lib
Con esto tendremos el ejecutable servidor.exe creado, que es nuestro miniServidor Web. Lo ejecutamos dándole como parámetro el nombre del archivo HTML a publicar:
servidor.exe holamundo.html
Y el miniServidor Web quedará a la escucha en el puerto 10000 de la IP 127.0.0.1, datos proporcionados en el código fuente. Ahora le toca al cliente, vamos al navegador Web y tecleamos la URL:
http://127.0.0.1:10000
Con esto el navegador Web conecta con la IP indicada en el puerto 10000 y recupera nuestro HTML.
Mientras, en la ventana donde ejecutamos el miniServidor Web aparecerán los datos recibidos y los enviados en cada sesión HTTP.
Y ahí lo tienes, el servidor Web más pequeño del mundo.
Adaptando un poco el ejemplo de la aplicación servidor que trae la documentación, decidí dar un repaso al protocolo HTTP y crear un pequeño servidor Web.
El funcionamiento de este miniServidor Web sería muy sencillo y no cumpliría mucho con el estándar, pero para ver cómo funciona por dentro está bien. Lo que hace es lo siguiente:
- Leer un archivo HTML dado como parámetro.
- Iniciar una sesión de conexión a un Socket en la IP 127.0.01 en el puerto 10000.
- Esperar una conexión de un navegador web.
- Cuando reciba una conexión, visualiza la información recibida (las cabeceras HTTP del navegador).
- Preparar las cabeceras HTTP de respuesta.
- Leer el archivo HTML dado y agregarlo a las cabeceras anteriores.
- Enviar la respuesta al navegador (cabeceras HTTP y el HTML).
- Visualizar los datos enviados.
El código fuente sería el siguiente (servidor.c):
#include <stdio .h>
#include "netutils.h"
int main(int argc,char *argv[])
{
while (1)
{
FILE* pf;
if ((pf = fopen(argv[1],"rt")) == NULL)
{
puts("Error abriendo html.");
return 1;
}
Session session;
char buf[8192];
memset (&session,0,sizeof(session));
session.port = 10000;
session.Host = "127.0.0.1";
if (ServerConnect(&session)){ return 0; }
printf("Conectado...\n");
memset(buf,0,sizeof(buf));
if (Receive(&session,sizeof(buf)-1,buf)) { return 0; }
printf("Datos recibidos:\n\n %s\n",buf);
char texto[1000000] = "HTTP/1.1 200 OK\nContent-Type: text/html\n\n";
int c, i = strlen(texto);
while ( (c=getc(pf) ) != EOF){ texto[i] = c; i++; }
texto[i] = '\0';
fclose(pf);
if (Send(&session,strlen(texto),texto)){ return 0; }
printf("Datos enviados:\n\n %s\n", texto);
CloseSession(&session);
printf("\nConexion cerrada.\n");
}
}
printf("Datos recibidos:\n\n %s\n",buf);
char texto[1000000] = "HTTP/1.1 200 OK\nContent-Type: text/html\n\n";
int c, i = strlen(texto);
while ( (c=getc(pf) ) != EOF){ texto[i] = c; i++; }
texto[i] = '\0';
fclose(pf);
if (Send(&session,strlen(texto),texto)){ return 0; }
printf("Datos enviados:\n\n %s\n", texto);
CloseSession(&session);
printf("\nConexion cerrada.\n");
}
}
Una vez creado servidor.c, en la misma carpeta creamos el archivo HTML que queremos publicar en nuestro miniServidorWeb (holamundo.html), cuyo código sería el siguiente:
<html>
<head>
<title>Titulo>/title>
</head>
<body>
<p><h1>Hola Mundo</h1></p>
</body>
</html>
<head>
<title>Titulo>/title>
</head>
<body>
<p><h1>Hola Mundo</h1></p>
</body>
</html>
Asumiendo que LCC-Win está instalado en c:\lcc y que tenemos la ruta de los binarios del compilador (c:\lcc\bin) incluida en la variable PATH del sistema, ya podemos compilar y enlazar:
lcc servidor.c
lcclnk servidor.obj c:\lcc\lib\netutils.lib
Con esto tendremos el ejecutable servidor.exe creado, que es nuestro miniServidor Web. Lo ejecutamos dándole como parámetro el nombre del archivo HTML a publicar:
servidor.exe holamundo.html
Y el miniServidor Web quedará a la escucha en el puerto 10000 de la IP 127.0.0.1, datos proporcionados en el código fuente. Ahora le toca al cliente, vamos al navegador Web y tecleamos la URL:
http://127.0.0.1:10000
Con esto el navegador Web conecta con la IP indicada en el puerto 10000 y recupera nuestro HTML.
Mientras, en la ventana donde ejecutamos el miniServidor Web aparecerán los datos recibidos y los enviados en cada sesión HTTP.
Y ahí lo tienes, el servidor Web más pequeño del mundo.
sábado, 26 de octubre de 2013
Debian | Capacidad de discos y actualizaciones pendientes
Dos de las tareas más importantes para mantener un servidor disponible y seguro son:
- Comprobar la capacidad de las particiones de los discos duros.
- Comprobar si existen actualizaciones pendientes de las aplicaciones en servicio.
En el caso de un SO GNU/Linux como Debian, podemos utilizar la salida de los comandos df y apt-get, procesarlos con un script de Perl y enviar el resultado por email con formato HTML.
Para que Perl pueda enviar emails, utilizaremos el módulo MIME::Lite de CPAN. Para instalar este módulo podemos seguir estos pasos:
- Instalar las librerías básicas de compilación y enlazado: apt-get install build-essential
- Entrar en CPAN: cpan
- Instalar el módulo: install MIME::Lite
- Salir de CPAN: exit
Instalado el módulo, Perl podrá enviar emails.
Ahora el script en Perl. Lo puedes descargar clicando en éste enlace.
Las variables que tienes que personalizar en el script son:
- $servidor: nombre corto que identifique al servidor en cuestión.
- $from: dirección de email de origen (puedes inventarte una, aunque no exista).
- $smtpserver: la ip del servidor de correo (SMTP) a enviar el mensaje (el que gestione el dominio de la direccion de email de entrega).
- $to: dirección de email de entrega del mensaje (este email debe ser el real para recibir los informes).
Una vez personalizado, puedes crear una tarea programada con CRON para que ejecute el script con la frecuencia adecuada (por ejemplo, una vez al día) y esperar que te lleguen los informes por email en un bonito formato HTML.
viernes, 19 de abril de 2013
Citrix: información de sesiones
En un entorno Citrix a veces es necesario conocer rápidamente las sesiones de usuario iniciadas en un servidor concreto, como por ejemplo, para diagnosticar alguna incidencia con alguna aplicación.
Para no perder tiempo en acceder a la consola de administración y averiguar esta información, he preparado un script con PowerShell que, indicando el nombre de un servidor Citrix en la variable $nombre_host y ejecutándolo en cualquier otro host con los permisos suficientes muestra la información de las sesiones de Citrix activas:
Para no perder tiempo en acceder a la consola de administración y averiguar esta información, he preparado un script con PowerShell que, indicando el nombre de un servidor Citrix en la variable $nombre_host y ejecutándolo en cualquier otro host con los permisos suficientes muestra la información de las sesiones de Citrix activas:
# información de sesiones citrix
# nombre del servidor de Citrix
$nombre_host = hostname
# fecha/hora/minuto/segundo de la toma
$t = get-date
$anio = $t.year
$mes = $t.month
$dia = $t.day
$hora = $t.hour
$minuto = $t.minute
$segundo = $t.second
$tiempo = "$anio $mes $dia $hora $minuto $segundo"
# captura sesiones actuales del servidor de Citrix indicado
$sesiones = qwinsta /SERVER:$nombre_host
# elimina primera línea
$sesiones = $sesiones[1..$sesiones.length]
# inicia variables
$usuario = ""
$sesionid = 0
$total_cpu = 0
$mem = 0
foreach ( $sesion in $sesiones )
{
# si se trata de una sesión de citrix
if ( $sesion -match "wdica" )
{
$sesion = $sesion -replace “\s+”,” ”
$t = $sesion.split(" ")
# captura usuario e id de sesión
$usuario = $t[2]
$sesionid = $t[3]
# inicia total_cpu y mem para esta sesión/usuario
$total_cpu = 0
$mem = 0
# captura la memoria y el total de cpu de los procesos
# de cada sesión/usuario de citrix
$procesos = get-process | where {$_.sessionid -eq $sesionid}
foreach ( $proceso in $procesos )
{
$total_cpu += $proceso.cpu
$mem += $proceso.ws
}
$mem = [int]($mem / 1mb)
write-host $tiempo $nombre_host $usuario $total_cpu $mem
}
}
# nombre del servidor de Citrix
$nombre_host = hostname
# fecha/hora/minuto/segundo de la toma
$t = get-date
$anio = $t.year
$mes = $t.month
$dia = $t.day
$hora = $t.hour
$minuto = $t.minute
$segundo = $t.second
$tiempo = "$anio $mes $dia $hora $minuto $segundo"
# captura sesiones actuales del servidor de Citrix indicado
$sesiones = qwinsta /SERVER:$nombre_host
# elimina primera línea
$sesiones = $sesiones[1..$sesiones.length]
# inicia variables
$usuario = ""
$sesionid = 0
$total_cpu = 0
$mem = 0
foreach ( $sesion in $sesiones )
{
# si se trata de una sesión de citrix
if ( $sesion -match "wdica" )
{
$sesion = $sesion -replace “\s+”,” ”
$t = $sesion.split(" ")
# captura usuario e id de sesión
$usuario = $t[2]
$sesionid = $t[3]
# inicia total_cpu y mem para esta sesión/usuario
$total_cpu = 0
$mem = 0
# captura la memoria y el total de cpu de los procesos
# de cada sesión/usuario de citrix
$procesos = get-process | where {$_.sessionid -eq $sesionid}
foreach ( $proceso in $procesos )
{
$total_cpu += $proceso.cpu
$mem += $proceso.ws
}
$mem = [int]($mem / 1mb)
write-host $tiempo $nombre_host $usuario $total_cpu $mem
}
}
martes, 25 de diciembre de 2012
Punteros y Arrays en C
C es uno de los lenguajes de programación más utilizados por su portabilidad, potencia y rapidez, y con él se han escrito sistemas operativos, otros muchos lenguajes y aplicaciones críticas.
En general, el aprendizaje de C no difiere mucho de cualquier otro, pero hay un par de cosas que lo hacen característico: sólo tiene disponible tipos de datos básicos (entero, caracter, etc.) y es necesario tener un conocimiento profundo de punteros y arrays para desplegar toda su potencia.
Los punteros en C siempre han sido tema de discusión por su dificultad, pero eso depende de cómo se expliquen. Uno de los mejores tutoriales de punteros que existen por su simplicidad es el de Ted Jensen (disponible en este enlace), y he realizado la correspondiente traducción con su permiso (disponible en este enlace).
En general, el aprendizaje de C no difiere mucho de cualquier otro, pero hay un par de cosas que lo hacen característico: sólo tiene disponible tipos de datos básicos (entero, caracter, etc.) y es necesario tener un conocimiento profundo de punteros y arrays para desplegar toda su potencia.
Los punteros en C siempre han sido tema de discusión por su dificultad, pero eso depende de cómo se expliquen. Uno de los mejores tutoriales de punteros que existen por su simplicidad es el de Ted Jensen (disponible en este enlace), y he realizado la correspondiente traducción con su permiso (disponible en este enlace).
martes, 11 de diciembre de 2012
Información de un sistema Windows con WMI y C
Ya sabemos que WMI es la forma más sencilla de extraer información útil de un sistema Windows, ya sea para realizar diagnósticos, para registrar equipos o para realizar informes.
Buscando la forma más sencilla para conseguir esta información en cualquier máquina Windows, existe un comando de consola que extrae el dato directamente: wmic
Por ejemplo, si queremos ver el número de serie de la máquina local, podemos hacerlo así:
wmic csproduct get identifyingnumber
de igual forma, si queremos ver el nombre del microprocesador, utilizamos:
wmic cpu get name
Si con antelación sabemos la información que nos interesa de un sistema, podemos incluir todas
las sentencias que queramos en un archivo por lotes (.bat) y utilizarlo, pero si además nos interesa disponer de un archivo ejecutable que realice lo mismo, podemos hacerlo con un pequeño programa en C, llamado por ejemplo regsys.c de la siguiente forma:
Podemos modificar el programa anterior e incluir todas las sentencias WMI que necesitemos mostrar. Además, con los conocimientos necesarios podemos ampliarlo para darle más funcionalidad como aceptar argumentos y escribir informes en un archivo HTML, por ejemplo.
El programa anterior se puede escribir en cualquier Windows, y compilarlo y enlazarlo con MinGW de la siguiente forma:
cc regsys.c -o regsys.exe
y ya tendremos la herramienta regsys.exe lista para ejecutarlo.
Buscando la forma más sencilla para conseguir esta información en cualquier máquina Windows, existe un comando de consola que extrae el dato directamente: wmic
Por ejemplo, si queremos ver el número de serie de la máquina local, podemos hacerlo así:
wmic csproduct get identifyingnumber
de igual forma, si queremos ver el nombre del microprocesador, utilizamos:
wmic cpu get name
Si con antelación sabemos la información que nos interesa de un sistema, podemos incluir todas
las sentencias que queramos en un archivo por lotes (.bat) y utilizarlo, pero si además nos interesa disponer de un archivo ejecutable que realice lo mismo, podemos hacerlo con un pequeño programa en C, llamado por ejemplo regsys.c de la siguiente forma:
#include <stdio.h>
#include <stdlib.h>
char *wmi();
int main()
{
// número de serie
char *nserie = "wmic csproduct get IdentifyingNumber";
char *pNserie = wmi( nserie );
printf("Numero de serie: %s", pNserie);
// fabricante
char *fabricante = "wmic computersystem get Manufacturer";
char *pFabricante = wmi( fabricante );
printf("Fabricante: %s", pFabricante);
// modelo placa
char *modeloPlaca = "wmic computersystem get model";
char *pModeloPlaca = wmi( modeloPlaca );
printf("Modelo placa: %s", pModeloPlaca);
// arquitectura
char *arq = "wmic computersystem get SystemType";
char *pArq = wmi( arq );
printf("Arquitectura: %s", pArq);
// procesador
char *cpu = "wmic cpu get name";
char *pCpu = wmi( cpu );
printf("Procesador: %s", pCpu);
return 0;
}
char *wmi( char *in )
{
FILE *fp;
char line[130];
char *line2;
line2 = malloc(130 * sizeof(char *));
fp = popen( in, "r" );
int x = 0;
while ( fgets( line, sizeof line, fp))
{
if ( x == 1 )
{
int z;
for ( z = 0 ; z < sizeof line ; z++ )
{
line2[z] = line[z];
}
}
x++;
}
pclose(fp);
return line2;
}
#include <stdlib.h>
char *wmi();
int main()
{
// número de serie
char *nserie = "wmic csproduct get IdentifyingNumber";
char *pNserie = wmi( nserie );
printf("Numero de serie: %s", pNserie);
// fabricante
char *fabricante = "wmic computersystem get Manufacturer";
char *pFabricante = wmi( fabricante );
printf("Fabricante: %s", pFabricante);
// modelo placa
char *modeloPlaca = "wmic computersystem get model";
char *pModeloPlaca = wmi( modeloPlaca );
printf("Modelo placa: %s", pModeloPlaca);
// arquitectura
char *arq = "wmic computersystem get SystemType";
char *pArq = wmi( arq );
printf("Arquitectura: %s", pArq);
// procesador
char *cpu = "wmic cpu get name";
char *pCpu = wmi( cpu );
printf("Procesador: %s", pCpu);
return 0;
}
char *wmi( char *in )
{
FILE *fp;
char line[130];
char *line2;
line2 = malloc(130 * sizeof(char *));
fp = popen( in, "r" );
int x = 0;
while ( fgets( line, sizeof line, fp))
{
if ( x == 1 )
{
int z;
for ( z = 0 ; z < sizeof line ; z++ )
{
line2[z] = line[z];
}
}
x++;
}
pclose(fp);
return line2;
}
Podemos modificar el programa anterior e incluir todas las sentencias WMI que necesitemos mostrar. Además, con los conocimientos necesarios podemos ampliarlo para darle más funcionalidad como aceptar argumentos y escribir informes en un archivo HTML, por ejemplo.
El programa anterior se puede escribir en cualquier Windows, y compilarlo y enlazarlo con MinGW de la siguiente forma:
cc regsys.c -o regsys.exe
y ya tendremos la herramienta regsys.exe lista para ejecutarlo.
jueves, 22 de noviembre de 2012
Exchange 2010: listado de reenvíos de buzones
Es muy útil redirigir mensajes que llegan a un buzón y entregarlos en otro buzón. Además también se puede elegir si entregar el mensaje en ambos buzones o sólo en el de reenvío. Para ello puedes utilizar la consola de administración de Exchange y también puedes utilizar una pequeña herramienta para realizarlo directamente conociendo los nombres de las cuentas (propiedad samAccountName) de los buzones en cuestión.
Cuando existe un número elevado de buzones que están redirigidos a otros, es necesario tenerlo controlado y disponer de un listado de ellos con su correspondiente configuración en un momento dado.
Puedes realizar este listado con Powershell, en concreto con el cmd-let de Exchange Get-Mailbox, que muestra las propiedades de los buzones. En este caso las propiedades son ForwardingAddress y DeliverToMailboxAndForward.
Con el siguiente script de Powershell puedes conseguir este listado: todas las cuentas de todos los buzones que tengan activado el reenvío, la cuenta del buzón de reenvío y si el reenvío se entrega en ambos buzones o sólo en el buzón de reenvío:
Cuando existe un número elevado de buzones que están redirigidos a otros, es necesario tenerlo controlado y disponer de un listado de ellos con su correspondiente configuración en un momento dado.
Puedes realizar este listado con Powershell, en concreto con el cmd-let de Exchange Get-Mailbox, que muestra las propiedades de los buzones. En este caso las propiedades son ForwardingAddress y DeliverToMailboxAndForward.
Con el siguiente script de Powershell puedes conseguir este listado: todas las cuentas de todos los buzones que tengan activado el reenvío, la cuenta del buzón de reenvío y si el reenvío se entrega en ambos buzones o sólo en el buzón de reenvío:
# ignora errores
$ErrorActionPreference = "SilentlyContinue"
function bruto_a_sam($bruto)
{
$bruto2 = $bruto -replace "^.*/", ""
$root = [ADSI]''
$busca = new-object System.DirectoryServices.DirectorySearcher($root)
$busca.Filter = "(&(|(objectCategory=person)(objectCategory=group))(Name=$bruto2))"
$sam = $busca.findone()
return $sam.properties.samaccountname
}
$buzones = Get-Mailbox
$c = 0
foreach ($b in $buzones)
{
$buzon = [string]$b.samaccountname
$reenviar_a = [string]$b.ForwardingAddress
$dual = [string]$b.DeliverToMailboxAndForward
if ( $reenviar_a )
{
Write-Host Buzón: $buzon
$sam = bruto_a_sam($reenviar_a)
write-host Dirección de reenvío: $sam
if ( $dual -eq "True" )
{
write-host Entrega en buzón y en dirección de reenvío
}
else
{
Write-Host Entrega sólo en dirección de reenvío
}
Write-Host -----
$c++
}
}
Write-Host $c registros
$ErrorActionPreference = "SilentlyContinue"
function bruto_a_sam($bruto)
{
$bruto2 = $bruto -replace "^.*/", ""
$root = [ADSI]''
$busca = new-object System.DirectoryServices.DirectorySearcher($root)
$busca.Filter = "(&(|(objectCategory=person)(objectCategory=group))(Name=$bruto2))"
$sam = $busca.findone()
return $sam.properties.samaccountname
}
$buzones = Get-Mailbox
$c = 0
foreach ($b in $buzones)
{
$buzon = [string]$b.samaccountname
$reenviar_a = [string]$b.ForwardingAddress
$dual = [string]$b.DeliverToMailboxAndForward
if ( $reenviar_a )
{
Write-Host Buzón: $buzon
$sam = bruto_a_sam($reenviar_a)
write-host Dirección de reenvío: $sam
if ( $dual -eq "True" )
{
write-host Entrega en buzón y en dirección de reenvío
}
else
{
Write-Host Entrega sólo en dirección de reenvío
}
Write-Host -----
$c++
}
}
Write-Host $c registros
sábado, 16 de junio de 2012
¿Qué servidor hay detrás de una web?
Detrás de cualquier sitio web hay un servidor web, como Apache, IIS, etc. Una forma de saber esto es mirar el campo Server de la cabecera HTTP en la respuesta del sitio web en cuestión.
Por ejemplo, hagamos una lista de sitios web en un archivo de texto ( webs.txt ):
www.microsoft.com
www.google.com
www.apple.com
www.wikipedia.org
www.yahoo.com
www.facebook.com
www.twitter.com
Y ahora utilicemos el siguiente script de Powershell ( webserver.ps1 ) en la misma carpeta que el archivo webs.txt:
El resultado es el siguiente:
www.microsoft.com -> Microsoft-IIS/8.0
www.google.com -> gws
www.apple.com -> Apache/2.2.3 (Oracle)
www.wikipedia.org -> Apache
www.yahoo.com -> YTS/1.20.10
www.facebook.com -> no especificado
www.twitter.com -> tfe
Y las conclusiones son interesantes:
Por ejemplo, hagamos una lista de sitios web en un archivo de texto ( webs.txt ):
www.microsoft.com
www.google.com
www.apple.com
www.wikipedia.org
www.yahoo.com
www.facebook.com
www.twitter.com
Y ahora utilicemos el siguiente script de Powershell ( webserver.ps1 ) en la misma carpeta que el archivo webs.txt:
# webserver.ps1 - servidores web desde urls
function servidor_web($url)
{
if ( $url -ne "" )
{
$solicitud=[system.Net.HttpWebRequest]::Create("http://"+$url)
$cabecera = $solicitud.getresponse()
$cabecera.Close()
if ( $cabecera.Server ) { write-host $url "->" $cabecera.Server }
else { write-host $url "-> no especificado" }
}
}
$urls = get-content ./webs.txt
foreach ( $url in $urls) { servidor_web($url) }
function servidor_web($url)
{
if ( $url -ne "" )
{
$solicitud=[system.Net.HttpWebRequest]::Create("http://"+$url)
$cabecera = $solicitud.getresponse()
$cabecera.Close()
if ( $cabecera.Server ) { write-host $url "->" $cabecera.Server }
else { write-host $url "-> no especificado" }
}
}
$urls = get-content ./webs.txt
foreach ( $url in $urls) { servidor_web($url) }
El resultado es el siguiente:
www.microsoft.com -> Microsoft-IIS/8.0
www.google.com -> gws
www.apple.com -> Apache/2.2.3 (Oracle)
www.wikipedia.org -> Apache
www.yahoo.com -> YTS/1.20.10
www.facebook.com -> no especificado
www.twitter.com -> tfe
Y las conclusiones son interesantes:
- Los servidores web de Google, Yahoo y Twitter son de desarrollo propio ( gws es Google Web Server, YTS es Yahoo Traffic Server y tfe sólo lo sabrán los ingenieros de Twitter ).
- Facebook no da a conocer el campo Server en su cabecera (no especificado).
- Apple y Wikipedia apuestan por Apache.
jueves, 3 de mayo de 2012
Concesiones DHCP con Netsh y PowerShell
¿Cuales son los hosts cuyas direcciones ip son asignadas de forma dinámica por un servidor DHCP de Windows?
Para conocer esta información normalmente consultas las concesiones de direcciones del servicio DHCP mediante su consola de administración.
Si necesitas la información anterior en otro formato para utilizarla después, la consola de administración de DHCP te permite realizar una exportación a un fichero de texto, pero ¿existe alguna manera automática de conseguir esta información? El comando netsh también puede mostrar esa información, como en el siguiente ejemplo (la ip del servidor DHCP es 192.168.1.100 y el ámbito consultado es 192.168.0.0):
netsh dhcp server 192.168.1.100 v4 scope 192.168.0.0 show clientsvq
Si redireccionas la salida del comando anterior a un fichero de texto ya tendrías un listado que puede servir de informe, pero si quieres un informe personalizado o automatizar otras tareas con esta información, es necesario extraer cada ip, mac y nombre de cada host del listado.
Para ello, puedes utilizar la salida del comando anterior en un script de PowerShell de la siguiente forma:
$clientes = netsh dhcp server 192.168.1.100 v4 scope 192.168.0.0 show clientsvq
foreach ($cliente in $clientes)
{
if ($cliente -match "^\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}")
{
$cliente -match "^(\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3})\s{1,}-\s\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}\s{1,}-(\w\w-\w\w-\w\w-\w\w-\w\w-\w\w).*-[D|U|N]\s-(.*?)\s-"
$ip = $Matches[1]
$mac = $Matches[2] -replace "-",""
$nombre = $Matches[3]
write-host "$ip - $mac - $nombre"
}
}
foreach ($cliente in $clientes)
{
if ($cliente -match "^\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}")
{
$cliente -match "^(\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3})\s{1,}-\s\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}\s{1,}-(\w\w-\w\w-\w\w-\w\w-\w\w-\w\w).*-[D|U|N]\s-(.*?)\s-"
$ip = $Matches[1]
$mac = $Matches[2] -replace "-",""
$nombre = $Matches[3]
write-host "$ip - $mac - $nombre"
}
}
Y ya tendrías la ip, la mac y el nombre de cada host disponibles para lo que quieras.
miércoles, 28 de marzo de 2012
Reenvío de mensajes en Exchange 2010
Realizar esta tarea con la consola de Administración de Exchange o con Powershell implica varios pasos. Con objetivo de reducir estos pasos, he desarrollado una herramienta llamada:

que además tiene un aspecto similar a esta opción de la consola de Administración de Exchange:

El manejo es sencillo:
Primero introduce el nombre de la Cuenta del buzón (samaccountname) en la que gestionarás el reenvío y pulsa ENTER (si hay algún problema aquí, como por ej. no existe la cuenta, etc., se borrará lo introducido y empezarás de nuevo).
Si la Cuenta del buzón introducida no tiene el reenvío activado, el checkbox Reenvío quedará disponible y clicando en él activarás el reenvío. En este caso, en el campo Reenviar a: escribe la cuenta (samaccountname) de la cuenta que recibirá los emails en lugar de la cuenta del buzón, y opcionalmente clica en Entregar en el buzón y en la dirección de reenvío si quieres que los mensajes los reciban ambos buzones. Finalmente clica en Aceptar para aplicar los cambios.
Si la Cuenta del buzón introducida tiene el reenvío activado verás que Reenvío está marcado, en Reenviar a: aparece la cuenta donde llegan actualmente los mensajes, y si corresponde, la entrega en ambos buzones. En este caso puedes desactivar el reenvío clicando en Reenvío o también puedes cambiar la cuenta de reenvío en Reenviar a: o puedes activar o desactivar la entrega en ambos buzones. Finalmente clica en Aceptar para aplicar los cambios.
Notas adicionales:
- Después de introducir el nombre de una cuenta de un buzón y pulsar ENTER, es posible que tarde unos segundos en mostrar si tiene el reenvío o no activado.
- Después de clicar en Aceptar es posible que tarde unos segundos en aplicar los cambios. Para comprobarlo, con el buzón correspondiente en el campo Cuenta del buzón: pulsa ENTER hasta ver los cambios aplicados.
- El campo Reenviar a: también admite los nombres de las cuentas (samaccountname) de grupos de distribución.
lunes, 27 de febrero de 2012
Suscribirse a:
Entradas (Atom)
