Lo primero que debemos realizar es identificar los equipos con los que deseamos operar. En estos equipos debe estar activo WON (Wake On LAN) activado y es conveniente que posean una dirección IP fija (para evitar sustos por cambios de IP), Además necesitaremos un usuario administrador para poder lanzar las operaciones en remoto.
Se presenta Phoenix en modo aplicación consola aunque su mayor potencial es convirtiéndolo en servicio Microsoft Windows.
Empezamos por el archivo xml, este es un ejemplo del mismo:
<general> <!--Periodo de ejecucion de la aplicacion en segundos--> <frecuencia>5</frecuencia> <!--Ejecucion de la aplicacion los fines de semana 1 = Si, 0 = No--> <finsemana>0</finsemana> <!--Escritura de log 1 = Si, 0 = No--> <escrituralog>1</escrituralog> <rutalog>C:\Phoenix\Phoenix_Log.log</rutalog> </general> <equipos> <!--Apagar, Reiniciar, Encender Y = Si, N = No--> <equipo> <nombreequipo>nomEquipo1</nombreequipo> <direccionip>10.10.10.10</direccionip> <mac>SU:JA:D7:30:99:34</mac> <descripcion>Financieros_1</descripcion> <encender>Y</encender> <horaencender>11:08</horaencender> <apagar>N</apagar> <horaapagar>13:15</horaapagar> <reiniciar>N</reiniciar> <horareiniciar>10:25</horareiniciar> </equipo> <equipo> <nombreequipo>nomEquipo2</nombreequipo> <direccionip>10.10.10.11</direccionip> <mac>SU:JA:d7:30:33:2H</mac> <descripcion>Financieros_2</descripcion> <encender>Y</encender> <horaencender>11:08</horaencender> <apagar>N</apagar> <horaapagar>13:15</horaapagar> <reiniciar>Y</reiniciar> <horareiniciar>08:52</horareiniciar> </equipo> <equipo> <nombreequipo>nomEquipon</nombreequipo> <direccionip>10.10.10.11</direccionip> <mac>SU:JA:e7:30:77:2H</mac> <descripcion>Financieros_n</descripcion> <encender>Y</encender> <horaencender>11:08</horaencender> <apagar>N</apagar> <horaapagar>13:15</horaapagar> <reiniciar>Y</reiniciar> <horareiniciar>08:52</horareiniciar> </equipo> </equipos> </configuracion>
Como podemos el archivo tiene dos partes, la primera con unos parámetros generales -que se cargarán al inicio de la aplicación o servicio- donde se indica con qué frecuencia lanzamos la aplicación, después si queremos que se realice los fines de semana (no implementado en el código) y los dos últimos por si deseamos crear un log de actividad.
La segunda parte del archivo xml será dónde se identifiquen los equipos, la acción que deseamos que se realice y a qué hora la queremos efectuar. Esta configuración se leerá según el valor de frecuencia indicado en la parte general, se podrán crear tantos equipos como se deseen y cambiar los valores de ellos en caliente (si necesidad de parar y arrancar la aplicación).
En la aplicación de consola, realizada con Microsoft Visual Basic .NET (2013), tenemos las siguientes clases:
Clase ReadConfig, en esta clase realizamos la lectura de los valores del xml que es la configuración de la aplicación y el modo que actúa con los equipos.
Imports System.Xml
Imports Microsoft.VisualBasic.FileIO
Public Class ReadConfig
Private xmlDoc As XmlDocument
Private nodeList As XmlNodeList
Private node As XmlNode
Private pathConfig As String = "C:\Phoenix\Config_Phoenix.xml"
Private writeLog As New WriteLog
Public frecuencia As Integer
Public finSemana As Boolean
Public escrituraLog As Boolean
Public rutaLog As String
Public Sub ConfigGeneral()
Try
If FileSystem.FileExists(pathConfig) Then
xmlDoc = New XmlDocument()
xmlDoc.Load(pathConfig)
nodeList = xmlDoc.SelectNodes("configuracion/general/frecuencia")
For Each node In nodeList
frecuencia = (node.InnerXml)
Next
nodeList = xmlDoc.SelectNodes("configuracion/general/finSemana")
For Each node In nodeList
finSemana = (node.InnerXml)
Next
nodeList = xmlDoc.SelectNodes("configuracion/general/escrituraLog")
For Each node In nodeList
escrituraLog = (node.InnerXml)
Next
nodeList = xmlDoc.SelectNodes("configuracion/general/rutaLog")
For Each node In nodeList
rutaLog = (node.InnerXml)
Next
writeLog.EscribeLog(Now.ToString & " , In , Lectura de Configuracion General.")
Else
'controlar si no exite el xml de configuracion
End If
Catch ex As Exception
writeLog.EscribeLog(Now.ToString & " , Er , Se ha producido un error en la lectura de Configuracion General. " & ex.Message)
End Try
End Sub
Public Sub ConfigEquipos()
Dim nombreEquipo As String
Dim direccionIP As String
Dim direccionMac As String
Dim descripcion As String
Dim encender As String
Dim apagar As String
Dim reiniciar As String
Dim horaEncender As Date
Dim horaApagar As Date
Dim horaReiniciar As Date
Try
xmlDoc = New XmlDocument
xmlDoc.Load(pathConfig)
nodeList = xmlDoc.SelectNodes("configuracion/equipos/equipo")
For Each node In nodeList
nombreEquipo = node.ChildNodes.Item(0).InnerText
direccionIP = node.ChildNodes.Item(1).InnerText
direccionMac = node.ChildNodes.Item(2).InnerText
descripcion = node.ChildNodes.Item(3).InnerText
encender = node.ChildNodes.Item(4).InnerText
horaEncender = node.ChildNodes.Item(5).InnerText
apagar = node.ChildNodes.Item(6).InnerText
horaApagar = node.ChildNodes.Item(7).InnerText
reiniciar = node.ChildNodes.Item(8).InnerText
horaReiniciar = node.ChildNodes.Item(9).InnerText
Dim accion As New Decisiones
accion.decisionEquipo(nombreEquipo, direccionIP, direccionMac, descripcion, _
encender, horaEncender, apagar, horaApagar, reiniciar, horaReiniciar)
Next
Catch ex As Exception
writeLog.EscribeLog(Now.ToString & " , Er , Se ha producido un error en la lectura de Configuracion de Equipos. " & ex.Message)
End Try
End Sub
Clase OnOff, en esta clase definimos como operar dependiendo si es un inicio, apagado o reinicio.
Imports System.Diagnostics
Imports System.Net
Imports System.Net.NetworkInformation
Imports System.ServiceProcess
Public Class OnOff
Private servicio As ServiceController '= New ServiceController(nombreServicio)
Private pingSender As New Ping
Private pingReply As PingReply
Private writeLog As New WriteLog
Public Sub WakeOnLAN(ByVal direccionMac As String, ByVal direccionIP As String, ByVal nombreEquipo As String)
'http://www.planetsourcecode.com/vb/scripts/ShowCode.asp?txtCodeId=2367&lngWId=10
'// Name: A Wake-On-LAN sample from VB.NET
'// Description:Wake-On-LAN standard is based on a Magic Packet and is used to wake up PCs from remote. This VC#.NET sample shows how to power up PCs using Wake-On-LAN, also called WOL or wake-up-on-LAN
'// By: Roby Kott
'//This code is copyrighted and has// limited warranties.Please see http://www.Planet-Source-Code.com/vb/scripts/ShowCode.asp?txtCodeId=2367&lngWId=10//for details.//**************************************
' ********************************************************************
' Wake-On-LAN sample - power on a remote PC, based on its MAC address
'Requires freeware ASocket.dll to run the sample. Download it from http://www.vahland.com/asocket/asocket.dll
'and register it (REGSVR32 asocket.dll) on your machine.
' IMPORTANT: Online manual: http://www.vahland.com/asocket/manual.htm
Dim objWol As ASOCKETLib.WOLClass = New ASOCKETLib.WOL()
Try
' Se envia un paquete ICMP a la dirección IP para ejecutar si está apagado el equipo
pingReply = pingSender.Send(direccionIP)
If pingReply.Status <> 0 Then
'Console.WriteLine("WakeUp " & direccionMac & " ...")
objWol.WakeUp(direccionMac)
' Console.WriteLine("Resultado: " & objWol.GetErrorDescription(objWol.LastError))
System.Threading.Thread.Sleep(5000)
writeLog.EscribeLog(Now.ToString & " , In , Se ha Encendido el equipo " & nombreEquipo)
Else
writeLog.EscribeLog(Now.ToString & " , In , No se ha podido encender el equipo " & nombreEquipo & " porque no tiene conexion a la red o el soporte WOL está deshabilitado.")
Exit Sub
End If
Catch ex As Exception
writeLog.EscribeLog(Now.ToString & " , Er , Se ha producido un error en el Encendido del equipo " & nombreEquipo & " Mensaje de error: " & ex.Message)
End Try
End Sub
Public Sub RestartComputer(ByVal direccionIP As String, ByVal nombreEquipo As String)
Try
' Se envia un paquete ICMP a la dirección IP para ejecutar si está encendido el equipo
' pingReply.Status = 0 => succesful = equipo encendido
pingReply = pingSender.Send(direccionIP)
If pingReply.Status = 0 Then
Try
'System.Threading.Thread.Sleep(20000)
Dim process As New Process
process.Start("shutdown.exe", " -m \\" & direccionIP & " -r -t 1 -f")
System.Threading.Thread.Sleep(30000)
writeLog.EscribeLog(Now.ToString & " , In , Se ha Reinicio el equipo " & nombreEquipo)
Catch ex As Exception
writeLog.EscribeLog(Now.ToString & " , Er , No se ha podido reiniciar el equipo " & nombreEquipo)
End Try
Else
writeLog.EscribeLog(Now.ToString & " , In , No se ha podido reiniciar el equipo " & nombreEquipo & " porque está apagado o sin conexion")
Exit Sub
End If
Catch ex As Exception
writeLog.EscribeLog(Now.ToString & " , Er , Se ha producido un error en el Reinicio del equipo " & nombreEquipo & " Mensaje de error: " & ex.Message)
End Try
End Sub
Public Sub ShutdownComputer(ByVal direccionIP As String, ByVal nombreEquipo As String)
Try
' Se envia un paquete ICMP a la dirección IP para ejecutar si está encendido el equipo
pingReply = pingSender.Send(direccionIP)
If pingReply.Status = 0 Then
Try
Dim process As New Process
process.Start("shutdown.exe", " -m \\" & direccionIP & " -s -t 1 -f")
writeLog.EscribeLog(Now.ToString & " , In , Se ha Apagado el equipo " & nombreEquipo)
Catch ex As Exception
writeLog.EscribeLog(Now.ToString & " , Er , No se ha podido apagar el equipo " & nombreEquipo)
End Try
Else
writeLog.EscribeLog(Now.ToString & " , In , No se ha podido reiniciar el equipo " & nombreEquipo & " porque está apagado o sin conexion")
Exit Sub
End If
Catch ex As Exception
writeLog.EscribeLog(Now.ToString & " , Er , Se ha producido un error en el Apagado del equipo " & nombreEquipo & " Mensaje de error: " & ex.Message)
End Try
End Sub
Clase Decisiones, es quien activa lógica, según el archivo xml, de acciones.
Public Class Decisiones
Public Sub decisionEquipo(ByVal nombreEquipo As String, ByVal direccionIP As String, _
ByVal direccionMac As String, ByVal descripcion As String, _
ByVal encender As String, ByVal horaEncender As Date, ByVal apagar As String, _
ByVal horaApagar As Date, ByVal reiniciar As String, ByVal horaReiniciar As Date)
Dim onOff As New OnOff
Select Case encender
Case "Y"
If horaEncender.Hour = Now.Hour And ((horaEncender.Minute - 3) <= Now.Minute) _
And ((horaEncender.Minute + 5) > Now.Minute) Then
onOff.WakeOnLAN(direccionMac, direccionIP, nombreEquipo)
Console.WriteLine(Now & " Encender: => " & nombreEquipo)
End If
Case "N"
Exit Select
End Select
Select Case apagar
Case "Y"
If horaApagar.Hour = Now.Hour And ((horaApagar.Minute + 3) >= Now.Minute) Then
onOff.ShutdownComputer(direccionIP, nombreEquipo)
Console.WriteLine(Now & " Apagar: " & nombreEquipo)
End If
Case "N"
Exit Select
End Select
Select Case reiniciar
Case "Y"
If horaReiniciar.Hour = Now.Hour And ((horaReiniciar.Minute + 1) > Now.Minute) Then
onOff.RestartComputer(direccionIP, nombreEquipo)
Console.WriteLine(Now & "Reiniciar: " & nombreEquipo)
End If
Case "N"
Exit Select
End Select
End Sub
La clase Main es la inicial y la encargada de llamar a las clases anteriores cuando se indique.
Imports System.Timers
Module Main
Sub Main()
Dim writeLog As New WriteLog
Dim temporizador As New Timer()
writeLog.EscribeLog(Now.ToString & " , In , Iniciado Phoenix.")
Console.WriteLine("Phoenix iniciado .....................")
Console.WriteLine("Pulsa q + intro para salir")
Console.WriteLine(vbCrLf)
' Lectura de configuración general
Dim configGeneral As New ReadConfig
configGeneral.ConfigGeneral()
' Hook up the Elapsed event for the timer.
AddHandler temporizador.Elapsed, AddressOf OnTimedEvent
' Establecer el intervalo = frecuencia en segundos
temporizador.Interval = (configGeneral.frecuencia * 1000)
temporizador.Enabled = True
' Mantener activo el timer hasta el fin del Main
GC.KeepAlive(temporizador)
While Chr(Console.Read()) <> "q"c
End While
Console.WriteLine("Phoenix finalizado .....................")
End Sub
Private Sub OnTimedEvent(ByVal source As Object, ByVal e As ElapsedEventArgs)
Dim configuracion As New ReadConfig()
configuracion.ConfigEquipos()
End Sub
End Module
La clase que efectúa la escritura del log no está reflejada en esta entrada, tampoco la conversión a servicio ni una clase especial de impersonación.

No hay comentarios:
Publicar un comentario