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