lunes, 28 de noviembre de 2022

PowerShell - Script para verificar la conectividad de una lista de equipos

Verificar la conectividad entre equipos se puede convertir en una tarea bastante tediosa cuando la lista  y/o puertos a verificar es grande y tenemos que hacer las comprobaciones de forma manual. Para facilitarlo, a continuación se presenta un script PowerShell que nos permitirá automatizar la tarea de verificar la conectividad de N servidores a través de una lista de puertos.

Los servidores se listarán en un fichero de texto plano, para el ejemplo lo nombraremos como Targets.txt. separados por saltos de línea: 

servidor01
servidor02
servidor03
... 

Siguiendo el mismo formato los puertos se informarán en otro fichero de texto plano, que para el ejemplo nombraremos como Ports.txt, separados por saltos de línea:

port01
port02
port03
...
 
Creamos el siguiente PowerShell Script, que en mi caso he guardado con el nombre checkconnections.ps1, que tendrá como parámetros de entrada los ficheros con la lista de servidores y puertos:

param (
   
    [string]$targetsFile,
    [string]$portsFile
   
)

$targets = Get-Content -Path $targetsFile
$ports = Get-Content -Path $portsFile

ForEach ($target in $targets){

    foreach ($port in $ports){
        Test-NetConnection -ComputerName $target -Port $port
    }

}


Ejecutamos el script mediante el siguiente comando:

.\checkconnections.ps1 -targetsFile Targets.txt -portsFile Ports.txt 
 
Que nos devolverá el resultado de verificar la conectividad de los servidores listados en Targets.txt contra los puertos presentes en Ports.txt.

ComputerName           : servidor01
RemoteAddress          : 10.136.36.71
RemotePort             : port01
InterfaceAlias         : Ethernet
SourceAddress          : 10.136.36.94
PingSucceeded          : True
PingReplyDetails (RTT) : 1 ms
TcpTestSucceeded       : True

ComputerName           : servidor01
RemoteAddress          : 10.136.36.71
RemotePort             : Port02
InterfaceAlias         : Ethernet
SourceAddress          : 10.136.36.94
PingSucceeded          : True
PingReplyDetails (RTT) : 1 ms
TcpTestSucceeded       : False

ComputerName           : servidor01
RemoteAddress          : 10.136.36.71
RemotePort             : Port03
InterfaceAlias         : Ethernet
SourceAddress          : 10.136.36.94
PingSucceeded          : True
PingReplyDetails (RTT) : 1 ms
TcpTestSucceeded       : False

ComputerName           : servidor02
RemoteAddress          : 10.136.36.72
RemotePort             : Port01
InterfaceAlias         : Ethernet
SourceAddress          : 10.136.36.94
PingSucceeded          : True
PingReplyDetails (RTT) : 1 ms
TcpTestSucceeded       : True

... 

     

 








miércoles, 26 de agosto de 2015

Como configurar carpetas de red en Fillezilla Server


El objetivo de este artículo es describir como publicar a través de un servidor FileZilla  una carpeta de red (que no se encuentra en el servidor) para que sea accesible vía FTP.

Antes de proceder a configurar FileZilla hay que verificar que la carpeta compartida es accesible desde el servidor donde se está ejecutando.

Una vez verificado en acceso a la carpeta compartida, se sigue el siguiente procedimiento:
  • Arrancar el servicio FileZilla Server FTP server con un usuario con permisos de acceso a la carpeta compartida.


  • En la configuración de usuarios se añade la carpeta compartida mediante la cadena (no utilizar una unidad de red local mapeada ya que FileZilla no las resuelve correctamente): 
        \\[<host>]\[<remote folder>] 

         


REFERENCIA


martes, 12 de febrero de 2013

Compilación e instalación de servidor Apache en Redhat

Si pretendemos compilar he instalar un Servidor Web Apache (la versión que he instalado es la 2.4) en un sistema tipo Linux (en mi caso un Redhat 4 de 64 bits) recomiendo seguir las indicaciones de la Guía de Compilación e Instalación del Servidor HTTP Apache. Básicamente las indicaciones de la guía son correctas salvo en el apartado Requisitos donde falta indicar que son necesarios para compilar Apache: Apache Portable Runtime Project (APR), Apache Portable Runtime Project Utility y Perl Compatible Regular Expressions (PCRE).





sábado, 2 de febrero de 2013

Trabajando con Threads en Java. Caso 1

Bruce Eckel en su libro Thinking in Java en el capítulo sobre la concurrencia plantea un ejercio que resulta muy ilustrativo sobre sobre como funcionan los Threads en Java.

El enunciado del ejercicio es:


Implement a Runnable. Inside run( ), print a message, and then call yield( ). Repeat this three times, and then return from run( ). Put a startup message in the constructor and a shutdown message when the
task terminates. Create a number of these tasks and drive them using threads

La implementación es simple. En primer lugar definimos una clase Runnable que cumple con los requisitos pedidos.


package thinkinginjava.concurrency.exercise1;

public class RunnablePrinter implements Runnable {

private static int count = 0;

private final int id = count++;

public RunnablePrinter() {
System.out.println("Inicio RunnablePrinter. Id: " + id);
}

public void run() {

Thread t = Thread.currentThread();

System.out.println("#" + id + " Mensaje 1." + " Thread: " + t.getId());
Thread.yield();
System.out.println("#" + id + " Mensaje 2."  + " Thread: " + t.getId());
Thread.yield();
System.out.println("#" + id + " Mensaje 3. " + " Thread: " + t.getId());
Thread.yield();

System.out.println("Fin RunnablePrinter. Id: " + id);

return;
}

}

Y después creamos una clase de tipo main para lanzar los Threads.


package thinkinginjava.concurrency.exercise1;

public class RunnablePrinterMain {

public static void main(String[] args){

for(int i = 0; i < 10; i++)
new Thread(new RunnablePrinter()).start();


}

}


Hasta aquí nada especial. Ahora viene lo interesante, lancemos el main y veamos que sucede.

Una primera ejecución nos devuelve el siguiente resultado:


Inicio RunnablePrinter. Id: 0
Inicio RunnablePrinter. Id: 1
Inicio RunnablePrinter. Id: 2
#1 Mensaje 1. Thread: 8
#1 Mensaje 2. Thread: 8
#1 Mensaje 3.  Thread: 8
Fin RunnablePrinter. Id: 1
Inicio RunnablePrinter. Id: 3
#0 Mensaje 1. Thread: 7
#0 Mensaje 2. Thread: 7
#0 Mensaje 3.  Thread: 7
Fin RunnablePrinter. Id: 0
Inicio RunnablePrinter. Id: 4
#2 Mensaje 1. Thread: 9
#2 Mensaje 2. Thread: 9
#3 Mensaje 1. Thread: 10
#2 Mensaje 3.  Thread: 9
Inicio RunnablePrinter. Id: 5
#3 Mensaje 2. Thread: 10
#3 Mensaje 3.  Thread: 10
Fin RunnablePrinter. Id: 2
Inicio RunnablePrinter. Id: 6
#4 Mensaje 1. Thread: 11
Fin RunnablePrinter. Id: 3
#4 Mensaje 2. Thread: 11
#4 Mensaje 3.  Thread: 11
Fin RunnablePrinter. Id: 4
#5 Mensaje 1. Thread: 12
#5 Mensaje 2. Thread: 12
#5 Mensaje 3.  Thread: 12
Fin RunnablePrinter. Id: 5
Inicio RunnablePrinter. Id: 7
#6 Mensaje 1. Thread: 13
#6 Mensaje 2. Thread: 13
#6 Mensaje 3.  Thread: 13
Fin RunnablePrinter. Id: 6
Inicio RunnablePrinter. Id: 8
#7 Mensaje 1. Thread: 14
#7 Mensaje 2. Thread: 14
#7 Mensaje 3.  Thread: 14
Fin RunnablePrinter. Id: 7
Inicio RunnablePrinter. Id: 9
#8 Mensaje 1. Thread: 15
#8 Mensaje 2. Thread: 15
#8 Mensaje 3.  Thread: 15
Fin RunnablePrinter. Id: 8
#9 Mensaje 1. Thread: 16
#9 Mensaje 2. Thread: 16
#9 Mensaje 3.  Thread: 16
Fin RunnablePrinter. Id: 9

En este resultado se observa como se reparte el tiempo de CPU entre los distintos threads. La ejecución no es secuencial y esto se pone de manfiesto claramente en la primeras líneas del resultado anterior (marcadas en negrita), el thread 8 se ejecuta antes que el thread 8. Al cotrario de cono debería suceder en el caso de una ejecución secuencial.

Una segunda ejecución daría un resultado distinto al anterior.


Inicio RunnablePrinter. Id: 0
Inicio RunnablePrinter. Id: 1
#0 Mensaje 1. Thread: 7
#0 Mensaje 2. Thread: 7
#0 Mensaje 3.  Thread: 7
Fin RunnablePrinter. Id: 0
Inicio RunnablePrinter. Id: 2
#1 Mensaje 1. Thread: 8
#1 Mensaje 2. Thread: 8
#1 Mensaje 3.  Thread: 8
Fin RunnablePrinter. Id: 1
Inicio RunnablePrinter. Id: 3
#2 Mensaje 1. Thread: 9
#2 Mensaje 2. Thread: 9
#2 Mensaje 3.  Thread: 9
Fin RunnablePrinter. Id: 2
Inicio RunnablePrinter. Id: 4
#3 Mensaje 1. Thread: 10
#3 Mensaje 2. Thread: 10
#3 Mensaje 3.  Thread: 10
Fin RunnablePrinter. Id: 3
Inicio RunnablePrinter. Id: 5
#4 Mensaje 1. Thread: 11
#4 Mensaje 2. Thread: 11
#4 Mensaje 3.  Thread: 11
Fin RunnablePrinter. Id: 4
Inicio RunnablePrinter. Id: 6
#5 Mensaje 1. Thread: 12
#5 Mensaje 2. Thread: 12
#5 Mensaje 3.  Thread: 12
Fin RunnablePrinter. Id: 5
Inicio RunnablePrinter. Id: 7
#6 Mensaje 1. Thread: 13
#6 Mensaje 2. Thread: 13
#6 Mensaje 3.  Thread: 13
Fin RunnablePrinter. Id: 6
Inicio RunnablePrinter. Id: 8
#7 Mensaje 1. Thread: 14
#7 Mensaje 2. Thread: 14
#7 Mensaje 3.  Thread: 14
Fin RunnablePrinter. Id: 7
Inicio RunnablePrinter. Id: 9
#8 Mensaje 1. Thread: 15
#8 Mensaje 2. Thread: 15
#8 Mensaje 3.  Thread: 15
Fin RunnablePrinter. Id: 8
#9 Mensaje 1. Thread: 16
#9 Mensaje 2. Thread: 16
#9 Mensaje 3.  Thread: 16
Fin RunnablePrinter. Id: 9

Se observa que no podemos conocer apriori el reparto del tiempo de CPU entre los distintos thread.

miércoles, 25 de abril de 2012

Sobre variables estáticas en Java

La pasada semana leyendo el capítulo dedicado a la programación concurrente del expléndido libro de Bruce Ekell, Thinking in Java, me encontré con un ejemplo que me distrajo de mi lectura principal. En el ejemplo, Bruce pretendía ilustrar el uso de los Threads en Java usando una clase que implementaba una cuenta atrás.

package test.specifications;
    
public class LiftOff implements Runnable {
    
 protected int countDown = 10; // Default
 private static int taskCount = 0;
 private final int id = taskCount++;
    
 public LiftOff () {}
    
 public LiftOff(int countDown) {
  this.countDown = countDown;
 }
      
 public String status() {
  return "#" + id + "(" + (countDown > 0 ? countDown :
   "Liftoff!") + " ) , ";
 }
    
 public void run() {
  while (countDown-- > 0) {
   System.out.print( status() ) ;
   Thread.yield();
  }
 }
    
}
   

Bruce ilustraba el uso de la clase anterior con el código siguiente:

package test.specifications;

public class MoreBasicThreads {
   
    public static void main(String[] args){
        for(int i = 0; i < 5; i++)
            new Thread(new LiftOff()).start();
       
        System.out.println("Waiting for LiftOff");
    }

}
   

Atrajo mi atención el resultado obtenido al ejecutar el código anterior.


#0(9 ) , #4(9 ) , Waiting for LiftOff #3(9 ) , #2(9 ) , #1(9 ) , #4(8 ) , #1(8 ),
#4(7 ) , #3(8 ) , #4(6 ) , #0(8 ) , #4(5 ) , #3(7 ) , #1(7 ) , #2(8 ) , #1(6 ) , 
#3(6 ) , #4(4 ) , #0(7 ) , #4(3 ) , #3(5 ) , #1(5 ) , #2(7 ) , #1(4 ) , #3(4 ) , 
#4(2 ) , #0(6 ) , #4(1 ) , #3(3 ) , #1(3 ) , #2(6 ) , #1(2 ) , #3(2 ) , #3(1 ) ,
#4(Liftoff! ) , #0(5 ) , #0(4 ) , #0(3 ) , #0(2 ) , #0(1 ) , #0(Liftoff! ) ,
#3(Liftoff! ) , #1(1 ) , #2(5 ) , #1(Liftoff! ) , #2(4 ) , #2(3 ) , #2(2 ) , 
#2(1 ) , #2(Liftoff! ) , 
   

Lo que llamó mi atención de este resultado fue como el valor de la variable id, asignado a partir de la variable estática taskCount, cambiaba para las distintas instancias de la clase LiftOff. En un principio, confundido por la inicialización de la variable id (mediante asignación de la variable estática taskCount), esperaba que todos los valores de id fuesen iguales.

La evidencia del resultado y una mirada más en detalle me hicieron salir de mi error.

Para explicar este resultado, partimos de la definición de variables estáticas de la especificación de Java ( http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.3.1.1

If a field is declared  static , there exists exactly one incarnation of the field, no matter how many instances (possibly zero) of the class may eventually be created. A static field, sometimes called a class variable, is incarnated when the class is initialized

Efectivamente el valor de la variable taskCount es compartido por todas la instancias de la clase LiftOff, pero este valor se asigna a la variable final id y posteriormente se incrementa mediante el operador ++.
private final int id = taskCount++;

De esta forma la siguiente vez que se que se instancia la clase LiftOff, el valor de taskCount ha cambiado, con lo que a la variable id se le asigna el nuevo valor de la variable taskCount, valor distinto que al que se asigno a la variable id de la instancia anterior (de echo es el valor anterior incrementado en una unidad). Y así sucesivamente para las siguientes instancias.

Así que, aunque el resultado aparentemente parece contradecir la definición de variable estática mostrando valores distintos de taskCount para las distintas instancias de LiftOff, la realidad, descrita en los párrafos anteriores, es muy distinta y concordante con la especificación.


viernes, 2 de marzo de 2012

Como buscar una cadena de caracteres en un blob de Oracle

El requisito para realizar el procedimiento es que el campo blob donde queremos buscar contenga caracteres. Si este es nuestro caso y queremos localizar una determinada cadena de caracteres dentro de este campo, se sigue el procedimiento que paso a describir.

Oracle dispone de un paquete de utilidades para trabajar con objetos de tipo RAW denominado UTL_RAW, y este paquete contiene una función que permiter convertir un objeto tipo BLOB en otro tipo VARCAHR2:  UTL_RAW.CAST_TO_VARCHAR2([<objeto Blob>])

Utilizamos esta función para buscar una cadena de caracteres en un Blob mediante la siguiente SELECT:

select [<lista de campos a mostrar>] from [<tabla>] where utl_raw.cast_to_varchar2([<objeto Blob>]) like '%[<cadena a buscar>]%'



martes, 25 de octubre de 2011

Cómo exportar la configuración los Alias y los Drivers de SQuirreL SQL

En el presente artículo se indica como exportar los alias y los drivers de una instalación de SquirreL QSL e importarlos en otra.

Las definiciones de alias se guardan en los ficheros SQLAliases23.xml y SQLAliases23_treeStructure.xml, y las de los drivers en SQLDrivers.xml. La ubicación de estos ficheros se puede consultar en las preferencias globales de SQuirreL: File -> GlobalPreferences -> General -> User Directory.


Para exportar las definiciones de alias y drivers a otra instalación de SQuirreL, se copian los dos ficheros anteriores en el User Directory de la nueva instalación (sobreescribiendo los ficheros originales).

Hay que tener en cuenta que el fichero de definición de drivers hacer referencia a la ubicación física de los ficheros que contienen los drivers jdbc por lo que, para un correcto funcionamiento, en la nueva instalación estos ficheros deben encontrarse en la ruta referenciada por el fichero SQLDrivers.xml.