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.
lunes, 20 de octubre de 2014
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.
Suscribirse a:
Entradas (Atom)