Mostramos una aplicación de consola realizada en Visual Studio .Net C# (C Sharp) que lee la dirección IP de un fichero CSV (exportado de las reservas de un servidor de DHCP en Windows Server) y si el nombre de red del equipo coincide con el nombre de red de alguno de los registros del fichero, establecerá su IP estática y los datos de red contenidos en el fichero de configuración de la aplicación: máscara de subred, puerta de enlace y servidores DNS. También permite desactivar el protocolo IPv6 de todos los adaptadores de red donde se ejecuta.
- Requisitos para desarrollar aplicación Visual Studio .Net que cambia la IP del equipo.
- Realizar aplicación de consola en Visual Studio .Net C# que modifica la dirección IP de un equipo y desactiva el protocolo TCP IPv6.
- Funcionamiento de la aplicación Asignar IP estática en C#.
- Descarga del código fuente en C# de la aplicación completa.
Requisitos para desarrollar aplicación Visual Studio .Net que cambia la IP del equipo
Necesitaremos disponer del entorno de desarrollo Visual Studio .Net. Es válida la versión Community, que es gratuita. Para realizar la aplicación hemos usado Microsoft Visual Studio Community 2019.
En los siguientes enlaces explicamos como instalar Visual Studio .Net y realizar una aplicación simple de prueba:
- Instalar Visual Studio Community 2017 y primera aplicación.
- Instalar Microsoft Visual Studio .NET Community 2015 primera aplicación C#.
El usuario con el que trabajemos en el equipo Windows deberá tener permisos suficientes para acceder a las propiedades de red, a la configuración del adaptador de red y modificar sus valores: dirección IP, puerta de enlace, DNS, etc..
Realizar aplicación de consola en Visual Studio .Net C# que modifica la dirección IP de un equipo y desactiva el protocolo TCP IPv6
A continuación explicaremos paso a paso cómo crear una aplicación (proyecto) en Visual Studio .NET Community. Dicha aplicación leerá la IP y el nombre de red del equipo (hostname o nombre DNS) y establecerá estos valores en la configuración de red del propio equipo donde se ejecuta, siempre y cuando el nombre de red coincida con alguno de los nombres de red del fichero CSV.
Crearemos un nuevo proyecto pulsando en «Archivo» – «Nuevo» – «Proyecto…»:
Elegiremos un proyecto de tipo «Aplicación de consola (.NET Framework)»:
Introduciremos los datos para el nuevo proyecto:
- Nombre del proyecto: por ejemplo «AsignarIPEstatica».
- Ubicación: carpeta donde se crearán los ficheros del proyecto.
- Framework: elegiremos del desplegable la versión de .NET Framework que queramos usar. Los equipos donde ejecutemos la apliación deberán tener una versión de .NET Framework igual o superior a la elegida.
Necesitaremos dos referencias para que la aplicación funcione correctamente, que las agregaremos antes de agregar el código. Para ello pulsaremos en el menú «Proyecto» – «Agregar referencia…»:
Deberemos tener marcadas las siguientes referencias:
Por defecto suelen venir marcadas, en una aplicación de consola:
- System.Core
- System.Data
- Ssytem.Data.DataSetExtensions
- System.Net.Http
- System.Xml.Linq
- Microsoft.CSharp
- System
- System.Xml
Marcaremos las dos que faltan:
- System.Configuration
- System.Management
Una vez creado el proyecto y agregadas las referencias, en el fichero Program.cs que se crea por defecto, agregaremos el siguiente código C#:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 |
using System; using System.Configuration; using System.IO; using System.Management; using System.Management.Automation; using System.Net; using System.Net.Sockets; namespace AsignarIPEstatica { class CambiarIP { //Se le pasará como parámetro: //IP: la nueva IP que tendrá el equipo //Máscara de subred //Puerta de enlace (gateway) //Servidores DNS (si son varios, con formato "IP,IP". Por ejemplo: "8.8.8.8,1.1.1.1") //MAC del adaptador (tarjeta de red) del equipo al que se le aplicará la configuración //Si no se indica la MAC se aplicará a todos los adaptadores //Si el parámetro "desactivarIPv6" se pasa a false no se desactivará el protocolo IPv6 public void establecerConfiguracionRed(string direccionIP, string mascaraSubred, string puertaEnlace, string servidoresDNS, string macNIC, bool desactivarIPv6) { ManagementClass objWMIRed = new ManagementClass( "Win32_NetworkAdapterConfiguration"); ManagementObjectCollection objWMITodosLosNIC = objWMIRed.GetInstances(); foreach (ManagementObject objNICActual in objWMITodosLosNIC) { //Si la MAC está vacía no filtrar por MAC, aplicar a todos los adaptadores activos //Si la MAC no está vacía aplicar configuración red solo al adaptador con esa MAC (si está activo) bool filtrarMAC = false; if (macNIC == "") filtrarMAC = true; if (!filtrarMAC) filtrarMAC = (string)objNICActual["MACAddress"] == macNIC; if ((bool)objNICActual["IPEnabled"] & filtrarMAC) { try { ManagementBaseObject objNuevaIP = null; ManagementBaseObject objEstablecerIP = null; ManagementBaseObject objNuevaPuertaEnlace = null; ManagementBaseObject objNuevaDNS = null; objNuevaIP = objNICActual.GetMethodParameters("EnableStatic"); objNuevaPuertaEnlace = objNICActual.GetMethodParameters("SetGateways"); objNuevaDNS = objNICActual.GetMethodParameters("SetDNSServerSearchOrder"); //Establecemos los valores para la Puerta de Enlace (Gateway) objNuevaPuertaEnlace["DefaultIPGateway"] = new string[] { puertaEnlace }; objNuevaPuertaEnlace["GatewayCostMetric"] = new int[] { 1 }; //Establecemos los valores para la IP, la máscara de subred y los DNS objNuevaIP["IPAddress"] = new string[] { direccionIP }; objNuevaIP["SubnetMask"] = new string[] { mascaraSubred }; objNuevaDNS["DNSServerSearchOrder"] = servidoresDNS.Split(','); //Aplicamos los cambios a cada propiedad (EnableStatic, SetGateways, SetDNSServerSearchOrder) objEstablecerIP = objNICActual.InvokeMethod("EnableStatic", objNuevaIP, null); objEstablecerIP = objNICActual.InvokeMethod("SetGateways", objNuevaPuertaEnlace, null); objEstablecerIP = objNICActual.InvokeMethod("SetDNSServerSearchOrder", objNuevaDNS, null); new EscribirLog(" -> IP establecida a \"" + objNICActual["Caption"], true); if (desactivarIPv6) { //Desactivar IPv6 en el adaptador usando PowerShell PowerShell ps = PowerShell.Create(); ps.AddCommand("Disable-NetAdapterBinding"); ps.AddParameter("InterfaceDescription", "\"" + objNICActual["Description"] + "\""); ps.AddParameter("ComponentID", "ms_tcpip6"); ps.AddParameter("PassThru"); ps.Invoke(); new EscribirLog(" -> Desactivado IPv6 para \"" + objNICActual["Caption"], false); } } catch (Exception ex) { new EscribirLog("Error: " + ex.Message, false); } } } } } //Escribe en un fichero de log el texto indicado //Añadiendo al principio el día y la hora //Permite mostrar el mensaje por consola o guardarlo en fichero de log class EscribirLog { public string mensajeLog { get; set; } public Boolean mostrarConsola { get; set; } //Constructor si se pasa el mensaje por parámetro en la creación de la clase public EscribirLog(string mensajeEnviar, Boolean mostrarConsola) { mensajeLog = mensajeEnviar; if (mostrarConsola) monstrarMensajeConsola(); escribirLineaFichero(); } //Constructor si se pasa el mensaje por setter tras la creación de la clase public EscribirLog() { if (mostrarConsola) monstrarMensajeConsola(); escribirLineaFichero(); } public void monstrarMensajeConsola() { //Quitar posibles saltos de línea del mensaje mensajeLog = mensajeLog.Replace(Environment.NewLine, " | "); mensajeLog = mensajeLog.Replace("\r\n", " | ").Replace("\n", " | ").Replace("\r", " | "); Console.WriteLine(DateTime.Now.ToString("dd/MM/yyyy hh:mm:ss") + " " + mensajeLog); } //Escribe el mensaje de la propiedad mensajeLog en un fichero en la carpeta del ejecutable public void escribirLineaFichero() { try { FileStream fs = new FileStream(@AppDomain.CurrentDomain.BaseDirectory + "estado.log", FileMode.OpenOrCreate, FileAccess.Write); StreamWriter m_streamWriter = new StreamWriter(fs); m_streamWriter.BaseStream.Seek(0, SeekOrigin.End); //Quitar posibles saltos de línea del mensaje mensajeLog = mensajeLog.Replace(Environment.NewLine, " | "); mensajeLog = mensajeLog.Replace("\r\n", " | ").Replace("\n", " | ").Replace("\r", " | "); m_streamWriter.WriteLine(DateTime.Now.ToString("dd/MM/yyyy hh:mm:ss") + " " + mensajeLog); m_streamWriter.Flush(); m_streamWriter.Close(); } catch { //Silenciosa } } } //Obtiene el nombre de red completo (FQDN) del equipo actual class ObtenerNombreDeRed { //Obtener el nombre de red DNS del equipo actual (hostname) public static string obtenerNombreRedDNS() { try { //Obtener nombre de red sin dominio String nombreDeRedSinDominio = Dns.GetHostName(); //Obtener nombre de red con dominio (Fully qualified hostname) String nombreDeRed = Dns.GetHostEntry(nombreDeRedSinDominio).HostName; return nombreDeRed; } catch (SocketException ex) { new EscribirLog("Error al obtener nombre del equipo: " + ex.Source + " " + ex.Message, false); return ""; } catch (Exception ex) { new EscribirLog("Error al obtener nombre del equipo: " + ex.Source + " " + ex.Message, false); return ""; } } } //Guardar y leer valores en fichero XML de configuración class LeerGuardarDatosConfiguracion { public LeerGuardarDatosConfiguracion() { } //Constructor si se pasan los parámetros clave y valor //escribe en el fichero de configuración el valor de esa clave public LeerGuardarDatosConfiguracion(string clave, string valor) { guardarValorConfiguracion(clave, valor); } //Lee un valor de una clave en el fichero de configuración XML de la aplicación public string leerValorConfiguracion(string clave) { try { if (clave == "") return ""; else { string resultado = ConfigurationManager.AppSettings[clave].ToString(); return resultado; } } catch (NullReferenceException error) { new EscribirLog("Error al leer valor de configuración: " + error.GetType().ToString() + " " + error.Message, false); return ""; } catch (Exception error) { new EscribirLog("Error al leer valor de configuración: " + error.GetType().ToString() + " " + error.Message, false); return ""; } } //Guarda un valor en una clave en el fichero de configuración XML de la aplicación public void guardarValorConfiguracion(string clave, string valor) { try { Configuration ficheroConfXML = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None); //Configuration ficheroConfXML = // ConfigurationManager.OpenExeConfiguration(AppDomain.CurrentDomain.BaseDirectory); //Eliminamos la clave actual (si existe), de lo contrario los valores //se irán acumulando separados por coma ficheroConfXML.AppSettings.Settings.Remove(clave); //Asignamos el valor en la clave indicada ficheroConfXML.AppSettings.Settings.Add(clave, valor); //Guardamos los cambios definitivamente en el fichero de configuración ficheroConfXML.Save(ConfigurationSaveMode.Modified); } catch (Exception error) { new EscribirLog("Error al guardar valor de configuración: " + error.GetType().ToString() + " " + error.Message, false); } } } class Program { static void Main(string[] args) { //Leemos el fichero de configuración de la aplicación new EscribirLog("Leyendo fichero de configuración de la aplicación AsignarIPEstatica.exe.config", true); LeerGuardarDatosConfiguracion fConf = new LeerGuardarDatosConfiguracion(); string servidoresDNS = fConf.leerValorConfiguracion("DNS"); string mascaraSubred = fConf.leerValorConfiguracion("Máscara de subred"); string puertaDeEnlace = fConf.leerValorConfiguracion("Puerta de enlace"); bool desactivarIPv6 = false; try { desactivarIPv6 = Boolean.Parse(fConf.leerValorConfiguracion("Desactivar IPv6")); } catch (Exception error) { new EscribirLog("Error al leer fichero de configuración. Faltan parámetros como 'Desactivar IPv6'" + error.GetType().ToString() + " " + error.Message, true); } string ficheroReservasCSV = fConf.leerValorConfiguracion("Ruta y nombre fichero reservas CSV"); if (servidoresDNS == "" || mascaraSubred == "" || puertaDeEnlace == "" || ficheroReservasCSV == "") new EscribirLog("Debe indicar los DNS, máscara subred, puerta de enlace " + "y fichero de reservas en el fichero de configuración.", true); else { CambiarIP cIP = new CambiarIP(); //Leemos los valores de un fichero CSV, con formato: [IP] nombre_DNS string ficheroCSV = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ficheroReservasCSV); if (File.Exists(ficheroCSV)) { new EscribirLog("Leyendo fichero de reservas IP: " + ficheroReservasCSV, true); using (var reader = new StreamReader(@ficheroCSV)) { //List<string> listaIP = new List<string>(); //List<string> listaNombreDNS = new List<string>(); while (!reader.EndOfStream) { var lineaActual = reader.ReadLine(); var valoresSeparados = lineaActual.Split(' '); //Quitamos los corchetes que se exportan desde el DHCP de Windows //en la IP del equipo del fichero CSV string ipPCActualCSV = valoresSeparados[0].Replace("[", ""); ipPCActualCSV = ipPCActualCSV.Replace("]", ""); string nombrePCActualCSV = valoresSeparados[1]; //Comprobamos si el nombre coincide con el del equipo actual if (nombrePCActualCSV == ObtenerNombreDeRed.obtenerNombreRedDNS()) { new EscribirLog("PC [" + nombrePCActualCSV + "] con IP [" + ipPCActualCSV + "]", true); //Se establecerá la IP del fichero CSV al equipo según su nombre de red (DNS) cIP.establecerConfiguracionRed(ipPCActualCSV, mascaraSubred, puertaDeEnlace, servidoresDNS, "", desactivarIPv6); } else { new EscribirLog("El nombre de red del fichero CSV de la línea actual [" + nombrePCActualCSV + "] no coincide con el del equipo [" + ObtenerNombreDeRed.obtenerNombreRedDNS() + "], por lo que no se realizará ninguna acción", true); } } } new EscribirLog("Fin lectura fichero de reservas IP:" + ficheroReservasCSV, true); } else { new EscribirLog("No se ha encontrado el fichero: [" + ficheroReservasCSV + "]", true); } //Para que no se cierre la consola tras acabar, para depuración Console.WriteLine(""); Console.WriteLine("Pulse cualquier tecla para salir."); Console.ReadLine(); } } } } |
Funcionamiento de la aplicación Asignar IP estática en C#
Para entender mejor el código anterior, explicaremos el funcionamiento de la aplicación paso a paso a continuación.
- Lee los valores de DNS, máscara de subred, puerta de enlace, desactivar IPv6, ruta y nombre del fichero de reservas CSV, del fichero de configuración de la aplicación AsignarIPEstatica.exe.config, que debe existir junto con el ejecutable y tener el siguiente contenido (de ejemplo):
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<?xml version="1.0" encoding="utf-8" ?> <configuration> <appSettings> <add key="DNS" value="1.1.1.1,8.8.8.8" /> <add key="Máscara de subred" value="255.255.255.0" /> <add key="Puerta de enlace" value="192.168.1.1" /> <add key="Desactivar IPv6" value="True" /> <add key="Ruta y nombre fichero reservas CSV" value="reservas.csv" /> </appSettings> <startup> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" /> </startup> </configuration> |
En el ejemplo de fichero de configuración anterior, vemos que los parámetros que requiere la aplicación son:
- DNS: direcciones IP de los servidores DNS, si son varias las separaremos con una coma.
- Máscara de subred: máscara de subred que se aplicará al adaptador de red por defecto del equipo en el que se ejecute el programa, siempre que exista en el fichero CSV de reservas.
- Puerta de enlace: puerta de enlace (gateway) que se aplicará al adaptador de red por defecto del equipo en el que se ejecute el programa, siempre que exista en el fichero CSV de reservas.
- Desactivar IPv6: introcudiremos true o false para que se desactive el protocolo TCP IPv6 en el adaptador de red del equipo (si hemos indicado «true») o para que se active (si hemos indicado «false»).
- Ruta y nombre fichero reservas CSV: nombre del fichero CSV que contendrá los equipos y la IP que le corresponde.
Dicho fichero de configuración debe existir y tener los parámetros anteriores definidos, de lo contrario la aplicación finalizará con error.
Una vez leídos los valores de configuración anterior, la aplicación pasará a leer el contenido del fichero CSV, que debe tener este formato:
1 2 3 4 |
[192.168.1.100] pcalmacen [192.168.1.110] pcfacturacion [192.168.1.111] equipostock [192.168.1.112] servidor |
Como vemos, el fichero reservas.csv contendrá las direcciones IP de los equipos de la red entre corchetes, una espacio y el nombre de red del equipo al que le corresponde la dirección IP.
La aplicación irá leyendo cada línea del fichero. Obtendrá el nombre de red del equipo actual (hostname o nombre DNS) en el que se está ejecutando.
Si coincide el nombre del equipo actual con alguno de los nombres del fichero CSV:
modificará los datos de configuración de red del equipo por la IP del fichero CSV y el resto de valores del fichero de configuración (puerta de enlace, DNS, máscara de subred).
Esta aplicación es útil para casos en los que tengamos las asignaciones de direcciones IP por DHCP, de forma automática, como muestra la imagen siguiente:

Y queramos cambiar a asignación estática:
En este caso podremos generar un fichero CSV con el formato indicado, con todos los equipos y la IP que le correspondan y ejecutar la aplicación en todos los equipos, de forma que desactivará la asignación por DHCP (obtener una dirección IP automáticamente) y cambiará a su dirección estática fija.
En un dominio el programa puede ejecutarse por script de directiva, para que el proceso sea automático.
El programa en funcionamiento:
Vemos que va comprobando cada línea del fichero CSV, si coincide el nombre del equipo, realizará el cambio de IP.
Descarga del código fuente en C# de la aplicación completa
A continuación os mostramos enlace para la descarga gratuita del código fuente completo en C# de la aplicación de este tutorial. Realizada con Visual Studio .Net Community 2019: