Primera Version
This commit is contained in:
commit
4ee8015953
|
@ -0,0 +1,174 @@
|
|||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
share/python-wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
MANIFEST
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.nox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
*.py,cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
cover/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
local_settings.py
|
||||
db.sqlite3
|
||||
db.sqlite3-journal
|
||||
|
||||
# Flask stuff:
|
||||
instance/
|
||||
.webassets-cache
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
.pybuilder/
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# IPython
|
||||
profile_default/
|
||||
ipython_config.py
|
||||
|
||||
# pyenv
|
||||
# For a library or package, you might want to ignore these files since the code is
|
||||
# intended to run in multiple environments; otherwise, check them in:
|
||||
# .python-version
|
||||
|
||||
# pipenv
|
||||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||
# install all needed dependencies.
|
||||
#Pipfile.lock
|
||||
|
||||
# UV
|
||||
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
|
||||
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||
# commonly ignored for libraries.
|
||||
#uv.lock
|
||||
|
||||
# poetry
|
||||
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
||||
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||
# commonly ignored for libraries.
|
||||
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
||||
#poetry.lock
|
||||
|
||||
# pdm
|
||||
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
||||
#pdm.lock
|
||||
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
||||
# in version control.
|
||||
# https://pdm.fming.dev/latest/usage/project/#working-with-version-control
|
||||
.pdm.toml
|
||||
.pdm-python
|
||||
.pdm-build/
|
||||
|
||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
||||
__pypackages__/
|
||||
|
||||
# Celery stuff
|
||||
celerybeat-schedule
|
||||
celerybeat.pid
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# Environments
|
||||
.env
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
.spyproject
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# mkdocs documentation
|
||||
/site
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
.dmypy.json
|
||||
dmypy.json
|
||||
|
||||
# Pyre type checker
|
||||
.pyre/
|
||||
|
||||
# pytype static type analyzer
|
||||
.pytype/
|
||||
|
||||
# Cython debug symbols
|
||||
cython_debug/
|
||||
|
||||
# PyCharm
|
||||
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
||||
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
||||
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||
#.idea/
|
||||
|
||||
# Ruff stuff:
|
||||
.ruff_cache/
|
||||
|
||||
# PyPI configuration file
|
||||
.pypirc
|
|
@ -0,0 +1,22 @@
|
|||
import json
|
||||
|
||||
IP_HISTORY_FILE = "tu_ruta_a_ip_history.json" # Asegúrate de definir la ruta correcta
|
||||
|
||||
def remove_duplicates_preserve_order(history):
|
||||
"""Elimina duplicados de la lista manteniendo el orden."""
|
||||
seen = set()
|
||||
new_history = []
|
||||
for item in history:
|
||||
if item not in seen:
|
||||
seen.add(item)
|
||||
new_history.append(item)
|
||||
return new_history
|
||||
|
||||
if os.path.exists(IP_HISTORY_FILE):
|
||||
with open(IP_HISTORY_FILE, "r") as file:
|
||||
ip_history = json.load(file)
|
||||
ip_history = remove_duplicates_preserve_order(ip_history)
|
||||
|
||||
# Guardar la lista actualizada en el archivo JSON
|
||||
with open(IP_HISTORY_FILE, "w") as file:
|
||||
json.dump(ip_history, file)
|
|
@ -0,0 +1,106 @@
|
|||
import sys
|
||||
import subprocess
|
||||
import ctypes
|
||||
import time
|
||||
import logging
|
||||
import os
|
||||
from datetime import datetime
|
||||
|
||||
def setup_logging():
|
||||
"""Configura el logging para el script"""
|
||||
log_dir = os.path.join(os.path.dirname(__file__), 'logs')
|
||||
if not os.path.exists(log_dir):
|
||||
os.makedirs(log_dir)
|
||||
|
||||
log_file = os.path.join(log_dir, 'ip_changer_admin.log')
|
||||
|
||||
logging.basicConfig(
|
||||
level=logging.DEBUG,
|
||||
format='%(asctime)s - %(levelname)s - %(message)s',
|
||||
handlers=[
|
||||
logging.FileHandler(log_file),
|
||||
logging.StreamHandler(sys.stdout)
|
||||
]
|
||||
)
|
||||
return logging.getLogger(__name__)
|
||||
|
||||
def is_admin():
|
||||
"""Verifica si el script se está ejecutando con privilegios de administrador"""
|
||||
try:
|
||||
return ctypes.windll.shell32.IsUserAnAdmin()
|
||||
except:
|
||||
return False
|
||||
|
||||
def run_command(logger, cmd: str) -> bool:
|
||||
"""Ejecuta un comando y retorna True si fue exitoso"""
|
||||
logger.info(f"Executing command: {cmd}")
|
||||
try:
|
||||
result = subprocess.run(
|
||||
cmd,
|
||||
shell=True,
|
||||
capture_output=True,
|
||||
text=True
|
||||
)
|
||||
|
||||
if result.stdout:
|
||||
logger.info(f"Command output: {result.stdout}")
|
||||
if result.stderr:
|
||||
logger.error(f"Command error: {result.stderr}")
|
||||
|
||||
return result.returncode == 0
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error executing command: {str(e)}")
|
||||
return False
|
||||
|
||||
def main():
|
||||
logger = setup_logging()
|
||||
|
||||
# Log startup information
|
||||
logger.info("=" * 50)
|
||||
logger.info(f"Script started at {datetime.now()}")
|
||||
logger.info(f"Arguments received: {sys.argv}")
|
||||
logger.info(f"Running with admin privileges: {is_admin()}")
|
||||
|
||||
if not is_admin():
|
||||
logger.error("This script requires administrator privileges")
|
||||
return 1
|
||||
|
||||
if len(sys.argv) < 3:
|
||||
logger.error("Insufficient arguments")
|
||||
logger.info("Usage: ip_changer_admin.py <interface> <ip|dhcp>")
|
||||
logger.info("Example for static IP: ip_changer_admin.py Ethernet 192.168.1.100")
|
||||
logger.info("Example for DHCP: ip_changer_admin.py Ethernet dhcp")
|
||||
return 1
|
||||
|
||||
interface = sys.argv[1]
|
||||
ip_mode = sys.argv[2]
|
||||
|
||||
logger.info(f"Processing request for interface: {interface}")
|
||||
logger.info(f"IP mode: {ip_mode}")
|
||||
|
||||
if ip_mode.lower() == "dhcp":
|
||||
cmd = f'netsh interface ip set address "{interface}" dhcp'
|
||||
else:
|
||||
# Asumimos que es una IP estática
|
||||
ip = ip_mode
|
||||
gateway = '.'.join(ip.split('.')[:3] + ['1'])
|
||||
cmd = f'netsh interface ip set address "{interface}" static {ip} 255.255.255.0 {gateway}'
|
||||
|
||||
success = run_command(logger, cmd)
|
||||
|
||||
if success:
|
||||
logger.info("Command executed successfully")
|
||||
return 0
|
||||
else:
|
||||
logger.error("Command failed")
|
||||
return 1
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
exit_code = main()
|
||||
sys.exit(exit_code)
|
||||
except Exception as e:
|
||||
logger = setup_logging()
|
||||
logger.exception("Unhandled exception occurred")
|
||||
sys.exit(1)
|
|
@ -0,0 +1 @@
|
|||
{"last_interface": "Ethernet", "last_ip_prefix": "10.1.33"}
|
|
@ -0,0 +1 @@
|
|||
["10.1.22", "169.254.38", "10.1.20", "10.146.76", "192.168.0", "10.101.8", "10.1.33", "10.1.92", "192.168.121", "192.168.1", "169.254.3", "10.202.4", "192.168.2", "10.1.30", "192.168.88"]
|
|
@ -0,0 +1,192 @@
|
|||
import ctypes
|
||||
import subprocess
|
||||
import sys
|
||||
import re
|
||||
import os
|
||||
import json
|
||||
import time
|
||||
from win10toast import ToastNotifier
|
||||
|
||||
# Definir una constante para la ruta del directorio
|
||||
DIR = "D:\\Proyectos\\Scripts\\IPChanger"
|
||||
IP_HISTORY_FILE = os.path.join(DIR, "ip_history.json")
|
||||
|
||||
|
||||
def is_admin():
|
||||
"""Verifica si el script se está ejecutando con privilegios de administrador."""
|
||||
try:
|
||||
return ctypes.windll.shell32.IsUserAnAdmin()
|
||||
except:
|
||||
return False
|
||||
|
||||
|
||||
def run_as_admin(argv=None, debug=False):
|
||||
"""Ejecuta el script como administrador."""
|
||||
shell32 = ctypes.windll.shell32
|
||||
if argv is None and shell32.IsUserAnAdmin():
|
||||
# Ya estamos ejecutando como administrador, no es necesario hacer nada
|
||||
return True
|
||||
if argv is None:
|
||||
argv = sys.argv
|
||||
if hasattr(sys, "_MEIPASS"):
|
||||
# Soporte para PyInstaller
|
||||
arguments = map(str, argv[1:])
|
||||
else:
|
||||
arguments = map(str, argv)
|
||||
argument_line = " ".join(arguments)
|
||||
executable = str(sys.executable)
|
||||
if debug:
|
||||
print(f"Command line: {executable} {argument_line}")
|
||||
ret = shell32.ShellExecuteW(None, "runas", executable, argument_line, None, 1)
|
||||
if int(ret) <= 32:
|
||||
return False
|
||||
return None
|
||||
|
||||
|
||||
def set_static_ip(ip_address, gateway):
|
||||
"""Establece una dirección IP estática para el adaptador Ethernet."""
|
||||
try:
|
||||
subprocess.run(
|
||||
f'netsh interface ip set address "Ethernet" static {ip_address} 255.255.255.0 {gateway}',
|
||||
shell=True,
|
||||
)
|
||||
return f"Dirección IP establecida en {ip_address}"
|
||||
except Exception as e:
|
||||
return f"Error al establecer la dirección IP: {e}"
|
||||
|
||||
|
||||
def set_dhcp():
|
||||
"""Configura el adaptador Ethernet para obtener la dirección IP automáticamente a través de DHCP."""
|
||||
try:
|
||||
subprocess.run('netsh interface ip set address "Ethernet" dhcp', shell=True)
|
||||
return "Adaptador Ethernet configurado para DHCP"
|
||||
except Exception as e:
|
||||
return f"Error al configurar DHCP: {e}"
|
||||
|
||||
|
||||
def save_current_ip():
|
||||
"""Guarda la dirección IP actual del adaptador Ethernet en un archivo."""
|
||||
try:
|
||||
ip_config_output = subprocess.check_output("ipconfig", shell=True).decode(
|
||||
"cp850"
|
||||
)
|
||||
current_ip = re.search(
|
||||
"Adaptador de Ethernet Ethernet:[\s\S]*?Dirección IPv4. . . . . . . . . . . . . . : (\d+\.\d+\.\d+\.\d+)",
|
||||
ip_config_output,
|
||||
)
|
||||
if current_ip:
|
||||
update_ip_history(current_ip.group(1))
|
||||
return f"Dirección IP actual guardada: {current_ip.group(1)}"
|
||||
else:
|
||||
return "No se encontró la dirección IP actual."
|
||||
except Exception as e:
|
||||
return f"Error al guardar la dirección IP actual: {e}"
|
||||
|
||||
|
||||
def update_ip_history(current_ip):
|
||||
"""Actualiza el historial de las últimas 10 IPs usadas, excluyendo 'auto'."""
|
||||
if current_ip.lower() == "auto":
|
||||
return
|
||||
|
||||
if os.path.exists(IP_HISTORY_FILE):
|
||||
with open(IP_HISTORY_FILE, "r") as file:
|
||||
ip_history = json.load(file)
|
||||
else:
|
||||
ip_history = []
|
||||
|
||||
ip_history.insert(0, current_ip)
|
||||
ip_history = ip_history[:10]
|
||||
|
||||
with open("ip_history.json", "w") as file:
|
||||
json.dump(ip_history, file)
|
||||
|
||||
|
||||
def restore_last_ip():
|
||||
"""Restaura la última dirección IP guardada para el adaptador Ethernet."""
|
||||
if os.path.exists(IP_HISTORY_FILE):
|
||||
with open(IP_HISTORY_FILE, "r") as file:
|
||||
ip_history = json.load(file)
|
||||
if ip_history:
|
||||
last_ip = ip_history[0] # Obtener la última IP del historial
|
||||
gateway = last_ip.rsplit(".", 1)[0] + ".1"
|
||||
return set_static_ip(last_ip, gateway)
|
||||
else:
|
||||
return "No hay direcciones IP guardadas en el historial."
|
||||
else:
|
||||
return "No se encontró el archivo de historial de IPs."
|
||||
|
||||
|
||||
def get_input_parameter():
|
||||
"""Solicita al usuario un parámetro por línea de comandos."""
|
||||
return input(
|
||||
"Ingrese la dirección IP, 'auto' para DHCP, o 'last' para la última IP: "
|
||||
)
|
||||
|
||||
|
||||
def display_ip_history(ip_history):
|
||||
"""Muestra el historial de las últimas 10 IPs y permite al usuario seleccionar una."""
|
||||
if ip_history:
|
||||
for i, ip in enumerate(ip_history):
|
||||
print(f"{i}: {ip}")
|
||||
choice = input(
|
||||
"Seleccione una IP del historial (0-9), o presione Enter para continuar: "
|
||||
)
|
||||
if choice.isdigit() and 0 <= int(choice) < len(ip_history):
|
||||
return ip_history[int(choice)]
|
||||
return None
|
||||
|
||||
|
||||
def main():
|
||||
if not is_admin():
|
||||
# Si no se está ejecutando como administrador, solicitar elevación
|
||||
result = run_as_admin()
|
||||
if result is True:
|
||||
print("Ejecutando como administrador.")
|
||||
elif result is False:
|
||||
print("No se pudo obtener privilegios de administrador.")
|
||||
return
|
||||
else:
|
||||
# El script se reinició con privilegios de administrador
|
||||
return
|
||||
|
||||
if os.path.exists(IP_HISTORY_FILE):
|
||||
with open(IP_HISTORY_FILE, "r") as file:
|
||||
ip_history = json.load(file)
|
||||
|
||||
argument = sys.argv[1] if len(sys.argv) > 1 else None
|
||||
|
||||
if not argument:
|
||||
chosen_ip = display_ip_history()
|
||||
if chosen_ip:
|
||||
argument = chosen_ip
|
||||
else:
|
||||
argument = get_input_parameter()
|
||||
|
||||
# Guardar la dirección IP actual solo si no es 'auto'
|
||||
if argument.lower() != "auto":
|
||||
message = save_current_ip()
|
||||
|
||||
if argument == "auto":
|
||||
message = set_dhcp()
|
||||
elif argument == "last":
|
||||
message = restore_last_ip()
|
||||
else:
|
||||
ip_parts = argument.split(".")
|
||||
if len(ip_parts) == 3:
|
||||
argument += ".249"
|
||||
gateway = ".".join(ip_parts[:3]) + ".1"
|
||||
message = set_static_ip(argument, gateway)
|
||||
update_ip_history(argument) # Actualizar el historial solo con IPs estáticas
|
||||
|
||||
# Aquí asumimos que 'message' contiene el mensaje que quieres mostrar
|
||||
try:
|
||||
toaster = ToastNotifier()
|
||||
toaster.show_toast("Cambio de IP", message, duration=10)
|
||||
except Exception as e:
|
||||
print(
|
||||
f"Se produjo un error al mostrar la notificación, pero la operación se completó con éxito: {e}"
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
|
@ -0,0 +1,203 @@
|
|||
import ctypes
|
||||
import subprocess
|
||||
import sys
|
||||
import re
|
||||
import os
|
||||
import json
|
||||
import time
|
||||
from win10toast import ToastNotifier
|
||||
import threading
|
||||
|
||||
# Definir una constante para la ruta del directorio
|
||||
DIR = "D:\\Proyectos\\Scripts\\IPChanger"
|
||||
IP_HISTORY_FILE = os.path.join(DIR, "ip_history.json")
|
||||
|
||||
|
||||
def is_admin():
|
||||
"""Verifica si el script se está ejecutando con privilegios de administrador."""
|
||||
try:
|
||||
return ctypes.windll.shell32.IsUserAnAdmin()
|
||||
except:
|
||||
return False
|
||||
|
||||
|
||||
def run_as_admin(argv=None, debug=False):
|
||||
"""Ejecuta el script como administrador."""
|
||||
shell32 = ctypes.windll.shell32
|
||||
if argv is None and shell32.IsUserAnAdmin():
|
||||
# Ya estamos ejecutando como administrador, no es necesario hacer nada
|
||||
return True
|
||||
if argv is None:
|
||||
argv = sys.argv
|
||||
if hasattr(sys, "_MEIPASS"):
|
||||
# Soporte para PyInstaller
|
||||
arguments = map(str, argv[1:])
|
||||
else:
|
||||
arguments = map(str, argv)
|
||||
argument_line = " ".join(arguments)
|
||||
executable = str(sys.executable)
|
||||
if debug:
|
||||
print(f"Command line: {executable} {argument_line}")
|
||||
ret = shell32.ShellExecuteW(None, "runas", executable, argument_line, None, 1)
|
||||
if int(ret) <= 32:
|
||||
return False
|
||||
return None
|
||||
|
||||
|
||||
def set_static_ip(ip_address, gateway):
|
||||
"""Establece una dirección IP estática para el adaptador Ethernet."""
|
||||
try:
|
||||
subprocess.run(
|
||||
f'netsh interface ip set address "Ethernet" static {ip_address} 255.255.255.0 {gateway}',
|
||||
shell=True,
|
||||
)
|
||||
return f"Dirección IP establecida en {ip_address}"
|
||||
except Exception as e:
|
||||
return f"Error al establecer la dirección IP: {e}"
|
||||
|
||||
|
||||
def set_dhcp():
|
||||
"""Configura el adaptador Ethernet para obtener la dirección IP automáticamente a través de DHCP."""
|
||||
try:
|
||||
subprocess.run('netsh interface ip set address "Ethernet" dhcp', shell=True)
|
||||
return "Adaptador Ethernet configurado para DHCP"
|
||||
except Exception as e:
|
||||
return f"Error al configurar DHCP: {e}"
|
||||
|
||||
|
||||
def save_current_ip(ip_history):
|
||||
"""Guarda la dirección IP actual del adaptador Ethernet en un archivo y detecta si es de DHCP."""
|
||||
try:
|
||||
ip_config_output = subprocess.check_output("ipconfig /all", shell=True).decode(
|
||||
"cp850"
|
||||
)
|
||||
|
||||
# Buscar la sección del adaptador de Ethernet y DHCP
|
||||
ethernet_config = re.search(
|
||||
"Adaptador de Ethernet Ethernet:[\s\S]*?(DHCP habilitado[\s\S]*?)\r\n\r\n",
|
||||
ip_config_output,
|
||||
)
|
||||
current_ip = re.search(
|
||||
"Dirección IPv4. . . . . . . . . . . . . . : (\d+\.\d+\.\d+\.\d+)",
|
||||
ethernet_config.group(1) if ethernet_config else "",
|
||||
)
|
||||
dhcp_enabled = re.search(
|
||||
"DHCP habilitado . . . . . . . . . . . . . : sí",
|
||||
ethernet_config.group(1) if ethernet_config else "",
|
||||
)
|
||||
|
||||
if current_ip and not dhcp_enabled:
|
||||
ip_history.insert(0, current_ip.group(1))
|
||||
ip_history = ip_history[:10]
|
||||
return f"Dirección IP actual guardada: {current_ip.group(1)}"
|
||||
elif dhcp_enabled:
|
||||
return "La dirección IP actual es obtenida por DHCP."
|
||||
else:
|
||||
return "No se encontró la dirección IP actual."
|
||||
except Exception as e:
|
||||
return f"Error al obtener la configuración IP: {e}"
|
||||
|
||||
|
||||
def restore_last_ip(ip_history):
|
||||
"""Restaura la última dirección IP guardada para el adaptador Ethernet."""
|
||||
if ip_history:
|
||||
last_ip = ip_history[0] # Obtener la última IP del historial
|
||||
gateway = last_ip.rsplit(".", 1)[0] + ".1"
|
||||
return set_static_ip(last_ip, gateway)
|
||||
else:
|
||||
return "No hay direcciones IP guardadas en el historial."
|
||||
|
||||
|
||||
def get_input_parameter():
|
||||
"""Solicita al usuario un parámetro por línea de comandos."""
|
||||
return input(
|
||||
"Ingrese la dirección IP, 0-9 para los ultimas IP, 'a' o 'auto' para DHCP, o 'l' o 'last' para la última IP: "
|
||||
)
|
||||
|
||||
|
||||
def display_ip_history(ip_history):
|
||||
"""Muestra el historial de las últimas 10 IPs en orden inverso (de la más antigua a la más reciente) y permite al usuario seleccionar una."""
|
||||
if ip_history:
|
||||
for i, ip in enumerate(reversed(ip_history)):
|
||||
print(f"{len(ip_history) - 1 - i}: {ip}")
|
||||
return None
|
||||
|
||||
|
||||
def remove_duplicates_preserve_order(ip_history):
|
||||
"""Elimina duplicados de la lista manteniendo el orden."""
|
||||
seen = set()
|
||||
new_history = []
|
||||
for item in ip_history:
|
||||
if item not in seen:
|
||||
seen.add(item)
|
||||
new_history.append(item)
|
||||
return new_history
|
||||
|
||||
|
||||
def show_notification(message, duration):
|
||||
toaster = ToastNotifier()
|
||||
toaster.show_toast("Cambio de IP", message, duration=duration)
|
||||
|
||||
|
||||
def main():
|
||||
if not is_admin():
|
||||
# Si no se está ejecutando como administrador, solicitar elevación
|
||||
result = run_as_admin()
|
||||
if result is True:
|
||||
print("Ejecutando como administrador.")
|
||||
elif result is False:
|
||||
print("No se pudo obtener privilegios de administrador.")
|
||||
return
|
||||
else:
|
||||
# El script se reinició con privilegios de administrador
|
||||
return
|
||||
|
||||
if os.path.exists(IP_HISTORY_FILE):
|
||||
with open(IP_HISTORY_FILE, "r") as file:
|
||||
ip_history = json.load(file)
|
||||
ip_history = remove_duplicates_preserve_order(ip_history)
|
||||
else:
|
||||
ip_history = []
|
||||
|
||||
argument = sys.argv[1] if len(sys.argv) > 1 else None
|
||||
|
||||
if not argument:
|
||||
chosen_ip = display_ip_history(ip_history)
|
||||
argument = get_input_parameter()
|
||||
|
||||
if len(argument) == 0:
|
||||
return
|
||||
|
||||
if ip_history:
|
||||
if len(argument) == 1:
|
||||
if argument.isdigit() and 0 <= int(argument) < len(ip_history):
|
||||
argument = ip_history[int(argument)]
|
||||
|
||||
# Guardar la dirección IP actual solo si no es 'auto'
|
||||
message = save_current_ip(ip_history)
|
||||
print(message)
|
||||
|
||||
if argument == "auto" or argument == "a":
|
||||
message = set_dhcp()
|
||||
elif argument == "last" or argument == "l":
|
||||
if ip_history:
|
||||
message = restore_last_ip(ip_history)
|
||||
print(message)
|
||||
|
||||
else:
|
||||
ip_parts = argument.split(".")
|
||||
if len(ip_parts) == 3:
|
||||
argument += ".249"
|
||||
gateway = ".".join(ip_parts[:3]) + ".1"
|
||||
message = set_static_ip(argument, gateway)
|
||||
print(message)
|
||||
|
||||
with open(IP_HISTORY_FILE, "w") as file:
|
||||
json.dump(ip_history, file)
|
||||
|
||||
notification_thread = threading.Thread(target=show_notification, args=(message, 3))
|
||||
notification_thread.start()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
|
@ -0,0 +1 @@
|
|||
python ipchange.py
|
|
@ -0,0 +1 @@
|
|||
10.1.30.249
|
|
@ -0,0 +1,551 @@
|
|||
import tkinter as tk
|
||||
from tkinter import ttk, messagebox
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import re
|
||||
import ctypes
|
||||
import sys
|
||||
import ipaddress
|
||||
from typing import List, Optional
|
||||
from dataclasses import dataclass
|
||||
import threading
|
||||
import time
|
||||
|
||||
try:
|
||||
import wmi
|
||||
WMI_AVAILABLE = True
|
||||
except ImportError:
|
||||
WMI_AVAILABLE = False
|
||||
print("WMI module not found. Using alternative method for network interface detection.")
|
||||
|
||||
@dataclass
|
||||
class NetworkInterface:
|
||||
name: str
|
||||
description: str
|
||||
ip_address: str = ""
|
||||
subnet_mask: str = ""
|
||||
gateway: str = ""
|
||||
dhcp_enabled: bool = True
|
||||
active: bool = True
|
||||
adapter_id: str = ""
|
||||
|
||||
class IPChangeConfig:
|
||||
def __init__(self):
|
||||
self.config_file = "ip_config.json"
|
||||
self.history_file = "ip_history.json"
|
||||
self.load_config()
|
||||
|
||||
def load_config(self):
|
||||
try:
|
||||
if os.path.exists(self.config_file):
|
||||
with open(self.config_file, 'r') as f:
|
||||
config = json.load(f)
|
||||
self.last_interface = config.get('last_interface', '')
|
||||
self.last_ip_prefix = config.get('last_ip_prefix', '')
|
||||
else:
|
||||
self.last_interface = ''
|
||||
self.last_ip_prefix = ''
|
||||
except Exception as e:
|
||||
print(f"Error loading config: {e}")
|
||||
self.last_interface = ''
|
||||
self.last_ip_prefix = ''
|
||||
|
||||
def save_config(self):
|
||||
try:
|
||||
config = {
|
||||
'last_interface': self.last_interface,
|
||||
'last_ip_prefix': self.last_ip_prefix
|
||||
}
|
||||
with open(self.config_file, 'w') as f:
|
||||
json.dump(config, f)
|
||||
except Exception as e:
|
||||
print(f"Error saving config: {e}")
|
||||
|
||||
class IPChangerApp:
|
||||
def __init__(self, master):
|
||||
self.master = master
|
||||
self.master.title("Network Interface IP Configuration")
|
||||
self.master.geometry("900x700")
|
||||
|
||||
# Inicializar configuración antes que nada
|
||||
self.config = IPChangeConfig()
|
||||
|
||||
# Inicializar estructuras de datos
|
||||
self.interfaces: List[NetworkInterface] = []
|
||||
self.ip_history: List[str] = []
|
||||
|
||||
# Inicializar WMI si está disponible
|
||||
if WMI_AVAILABLE:
|
||||
self.wmi_client = wmi.WMI()
|
||||
|
||||
# Cargar datos guardados antes de crear widgets
|
||||
self.load_ip_history()
|
||||
|
||||
# Crear la interfaz
|
||||
self.create_widgets()
|
||||
|
||||
# Actualizar la lista de IPs en el combo
|
||||
self.update_history_display()
|
||||
|
||||
# Refrescar interfaces
|
||||
self.refresh_interfaces()
|
||||
|
||||
# Configurar pesos de la cuadrícula
|
||||
self.master.grid_columnconfigure(0, weight=1)
|
||||
self.master.grid_rowconfigure(1, weight=1) # El log expandible
|
||||
|
||||
def get_ip_prefix(self, ip: str) -> str:
|
||||
"""Extrae los primeros 3 octetos de una dirección IP"""
|
||||
parts = ip.split('.')
|
||||
if len(parts) >= 3:
|
||||
return '.'.join(parts[:3])
|
||||
return ip
|
||||
|
||||
def create_widgets(self):
|
||||
# Panel superior para controles
|
||||
self.control_frame = ttk.Frame(self.master, padding="10")
|
||||
self.control_frame.grid(row=0, column=0, sticky='new')
|
||||
|
||||
# Sección de interfaces
|
||||
self.interfaces_frame = ttk.LabelFrame(self.control_frame, text="Network Interfaces", padding="5")
|
||||
self.interfaces_frame.grid(row=0, column=0, sticky='ew', pady=(0,10))
|
||||
|
||||
ttk.Label(self.interfaces_frame, text="Select Interface:").grid(row=0, column=0, sticky='w', padx=5)
|
||||
self.if_var = tk.StringVar()
|
||||
self.if_combo = ttk.Combobox(self.interfaces_frame, textvariable=self.if_var, state='readonly', width=50)
|
||||
self.if_combo.grid(row=0, column=1, sticky='ew', padx=5)
|
||||
self.if_combo.bind('<<ComboboxSelected>>', self.on_interface_selected)
|
||||
|
||||
# Info de configuración actual
|
||||
self.current_frame = ttk.LabelFrame(self.control_frame, text="Current Configuration", padding="5")
|
||||
self.current_frame.grid(row=1, column=0, sticky='ew', pady=(0,10))
|
||||
|
||||
self.current_ip_var = tk.StringVar()
|
||||
self.current_mask_var = tk.StringVar()
|
||||
self.current_gateway_var = tk.StringVar()
|
||||
self.dhcp_status_var = tk.StringVar()
|
||||
|
||||
ttk.Label(self.current_frame, text="Current IP:").grid(row=0, column=0, sticky='w', padx=5)
|
||||
ttk.Label(self.current_frame, textvariable=self.current_ip_var).grid(row=0, column=1, sticky='w')
|
||||
ttk.Label(self.current_frame, text="Subnet Mask:").grid(row=1, column=0, sticky='w', padx=5)
|
||||
ttk.Label(self.current_frame, textvariable=self.current_mask_var).grid(row=1, column=1, sticky='w')
|
||||
ttk.Label(self.current_frame, text="Gateway:").grid(row=2, column=0, sticky='w', padx=5)
|
||||
ttk.Label(self.current_frame, textvariable=self.current_gateway_var).grid(row=2, column=1, sticky='w')
|
||||
ttk.Label(self.current_frame, text="DHCP Status:").grid(row=3, column=0, sticky='w', padx=5)
|
||||
ttk.Label(self.current_frame, textvariable=self.dhcp_status_var).grid(row=3, column=1, sticky='w')
|
||||
|
||||
# Sección de configuración IP
|
||||
self.ip_frame = ttk.LabelFrame(self.control_frame, text="IP Configuration", padding="5")
|
||||
self.ip_frame.grid(row=2, column=0, sticky='ew', pady=(0,10))
|
||||
|
||||
ttk.Label(self.ip_frame, text="IP Prefix (first 3 octets):").grid(row=0, column=0, sticky='w', padx=5)
|
||||
self.ip_prefix = tk.StringVar(value=self.config.last_ip_prefix)
|
||||
self.ip_entry = ttk.Entry(self.ip_frame, textvariable=self.ip_prefix, width=30)
|
||||
self.ip_entry.grid(row=0, column=1, sticky='w', padx=5)
|
||||
|
||||
ttk.Label(self.ip_frame, text="Last Octet:").grid(row=0, column=2, sticky='w', padx=5)
|
||||
self.last_octet = tk.StringVar(value="249")
|
||||
self.last_octet_entry = ttk.Entry(self.ip_frame, textvariable=self.last_octet, width=5)
|
||||
self.last_octet_entry.grid(row=0, column=3, sticky='w', padx=5)
|
||||
|
||||
# Sección de historial
|
||||
self.history_frame = ttk.LabelFrame(self.control_frame, text="IP History", padding="5")
|
||||
self.history_frame.grid(row=3, column=0, sticky='ew', pady=(0,10))
|
||||
|
||||
ttk.Label(self.history_frame, text="Previous IPs:").grid(row=0, column=0, sticky='w', padx=5)
|
||||
self.history_var = tk.StringVar()
|
||||
self.history_combo = ttk.Combobox(
|
||||
self.history_frame,
|
||||
textvariable=self.history_var,
|
||||
state='readonly',
|
||||
width=50
|
||||
)
|
||||
self.history_combo.grid(row=0, column=1, sticky='ew', padx=5)
|
||||
self.history_combo.bind('<<ComboboxSelected>>', self.on_history_selected)
|
||||
|
||||
# Botones de acción
|
||||
self.button_frame = ttk.Frame(self.control_frame)
|
||||
self.button_frame.grid(row=4, column=0, sticky='ew', pady=(0,10))
|
||||
|
||||
ttk.Button(self.button_frame, text="Set Static IP", command=self.set_static_ip).grid(row=0, column=0, padx=5)
|
||||
ttk.Button(self.button_frame, text="Enable DHCP", command=self.set_dhcp).grid(row=0, column=1, padx=5)
|
||||
ttk.Button(self.button_frame, text="Refresh Interfaces", command=self.refresh_interfaces).grid(row=0, column=2, padx=5)
|
||||
|
||||
# Log en la parte inferior
|
||||
self.log_frame = ttk.LabelFrame(self.master, text="Operation Log", padding="5")
|
||||
self.log_frame.grid(row=1, column=0, sticky='nsew', padx=10, pady=(0,10))
|
||||
|
||||
self.log_text = tk.Text(self.log_frame, wrap="none", height=10)
|
||||
self.log_scrollbar_y = ttk.Scrollbar(self.log_frame, orient="vertical", command=self.log_text.yview)
|
||||
self.log_scrollbar_x = ttk.Scrollbar(self.log_frame, orient="horizontal", command=self.log_text.xview)
|
||||
|
||||
self.log_text.configure(
|
||||
yscrollcommand=self.log_scrollbar_y.set,
|
||||
xscrollcommand=self.log_scrollbar_x.set
|
||||
)
|
||||
|
||||
self.log_text.grid(row=0, column=0, sticky='nsew')
|
||||
self.log_scrollbar_y.grid(row=0, column=1, sticky='ns')
|
||||
self.log_scrollbar_x.grid(row=1, column=0, sticky='ew')
|
||||
|
||||
ttk.Button(self.log_frame, text="Clear Log", command=self.clear_log).grid(row=2, column=0, columnspan=2, pady=5)
|
||||
|
||||
self.log_frame.grid_columnconfigure(0, weight=1)
|
||||
self.log_frame.grid_rowconfigure(0, weight=1)
|
||||
|
||||
def clear_log(self):
|
||||
self.log_text.delete('1.0', tk.END)
|
||||
|
||||
def log_message(self, message: str):
|
||||
self.log_text.insert(tk.END, f"{message}\n")
|
||||
self.log_text.see(tk.END)
|
||||
self.log_text.update_idletasks()
|
||||
|
||||
def load_ip_history(self):
|
||||
try:
|
||||
if os.path.exists(self.config.history_file):
|
||||
with open(self.config.history_file, 'r') as f:
|
||||
self.ip_history = json.load(f)
|
||||
else:
|
||||
self.ip_history = []
|
||||
except Exception as e:
|
||||
self.log_message(f"Error loading IP history: {e}")
|
||||
self.ip_history = []
|
||||
|
||||
def save_ip_history(self):
|
||||
try:
|
||||
with open(self.config.history_file, 'w') as f:
|
||||
json.dump(self.ip_history, f)
|
||||
except Exception as e:
|
||||
self.log_message(f"Error saving IP history: {e}")
|
||||
|
||||
def add_to_history(self, ip_prefix: str):
|
||||
if ip_prefix and ip_prefix not in self.ip_history:
|
||||
self.ip_history.insert(0, ip_prefix)
|
||||
self.ip_history = self.ip_history[:15] # Mantener solo las últimas 15 IPs
|
||||
self.save_ip_history()
|
||||
self.update_history_display()
|
||||
|
||||
def update_history_display(self):
|
||||
self.history_combo['values'] = self.ip_history
|
||||
if self.ip_history:
|
||||
self.history_combo.set(self.ip_history[0])
|
||||
|
||||
def on_history_selected(self, event):
|
||||
selected_ip = self.history_var.get()
|
||||
if selected_ip:
|
||||
# Ensure we only get the first three octets
|
||||
ip_parts = selected_ip.split('.')
|
||||
if len(ip_parts) >= 3:
|
||||
ip_prefix = '.'.join(ip_parts[:3])
|
||||
self.ip_prefix.set(ip_prefix)
|
||||
self.config.last_ip_prefix = ip_prefix
|
||||
self.config.save_config()
|
||||
self.log_message(f"Selected IP prefix from history: {ip_prefix}")
|
||||
|
||||
def refresh_interfaces(self):
|
||||
self.interfaces.clear()
|
||||
try:
|
||||
if WMI_AVAILABLE:
|
||||
self._refresh_interfaces_wmi()
|
||||
else:
|
||||
self._refresh_interfaces_netsh()
|
||||
|
||||
# Actualizar combobox
|
||||
self.if_combo['values'] = [inf.name for inf in self.interfaces if inf.active]
|
||||
|
||||
# Seleccionar última interfaz usada si está disponible
|
||||
if self.config.last_interface in self.if_combo['values']:
|
||||
self.if_combo.set(self.config.last_interface)
|
||||
self.on_interface_selected()
|
||||
|
||||
self.log_message("Interfaces refreshed successfully")
|
||||
|
||||
except Exception as e:
|
||||
self.log_message(f"Error refreshing interfaces: {str(e)}")
|
||||
self.show_error(f"Error refreshing interfaces: {str(e)}")
|
||||
|
||||
def _refresh_interfaces_wmi(self):
|
||||
try:
|
||||
adapters = self.wmi_client.Win32_NetworkAdapter(PhysicalAdapter=True)
|
||||
configs = self.wmi_client.Win32_NetworkAdapterConfiguration()
|
||||
|
||||
for adapter in adapters:
|
||||
config = next((cfg for cfg in configs if cfg.InterfaceIndex == adapter.InterfaceIndex), None)
|
||||
|
||||
if config and config.IPEnabled:
|
||||
interface = NetworkInterface(
|
||||
name=adapter.NetConnectionID,
|
||||
description=adapter.Description,
|
||||
ip_address=config.IPAddress[0] if config.IPAddress else "",
|
||||
subnet_mask=config.IPSubnet[0] if config.IPSubnet else "",
|
||||
gateway=config.DefaultIPGateway[0] if config.DefaultIPGateway else "",
|
||||
dhcp_enabled=config.DHCPEnabled,
|
||||
active=adapter.NetEnabled,
|
||||
adapter_id=adapter.GUID
|
||||
)
|
||||
self.interfaces.append(interface)
|
||||
except Exception as e:
|
||||
raise Exception(f"WMI refresh error: {str(e)}")
|
||||
|
||||
def _refresh_interfaces_netsh(self):
|
||||
try:
|
||||
output = subprocess.check_output("netsh interface ipv4 show config", shell=True, text=True)
|
||||
configs = output.split("\n\n")
|
||||
|
||||
for config in configs:
|
||||
if not config.strip():
|
||||
continue
|
||||
|
||||
name_match = re.search(r"Configuración de\s+\"(.+?)\"", config)
|
||||
if not name_match:
|
||||
continue
|
||||
|
||||
name = name_match.group(1)
|
||||
|
||||
ip_match = re.search(r"Dirección IP:\s+(\d+\.\d+\.\d+\.\d+)", config)
|
||||
mask_match = re.search(r"Máscara de subred:\s+(\d+\.\d+\.\d+\.\d+)", config)
|
||||
gateway_match = re.search(r"Puerta de enlace predeterminada:\s+(\d+\.\d+\.\d+\.\d+)", config)
|
||||
dhcp_match = re.search(r"DHCP habilitado:\s+(\w+)", config)
|
||||
|
||||
interface = NetworkInterface(
|
||||
name=name,
|
||||
description=name,
|
||||
ip_address=ip_match.group(1) if ip_match else "",
|
||||
subnet_mask=mask_match.group(1) if mask_match else "",
|
||||
gateway=gateway_match.group(1) if gateway_match else "",
|
||||
dhcp_enabled=dhcp_match.group(1).lower() == "sí" if dhcp_match else True,
|
||||
active=True
|
||||
)
|
||||
self.interfaces.append(interface)
|
||||
|
||||
except subprocess.CalledProcessError as e:
|
||||
raise Exception(f"Error executing netsh: {str(e)}")
|
||||
except Exception as e:
|
||||
raise Exception(f"Error parsing netsh output: {str(e)}")
|
||||
|
||||
def on_interface_selected(self, event=None):
|
||||
selected = self.if_var.get()
|
||||
interface = next((inf for inf in self.interfaces if inf.name == selected), None)
|
||||
|
||||
if interface:
|
||||
self.current_ip_var.set(interface.ip_address)
|
||||
self.current_mask_var.set(interface.subnet_mask)
|
||||
self.current_gateway_var.set(interface.gateway)
|
||||
self.dhcp_status_var.set("Enabled" if interface.dhcp_enabled else "Disabled")
|
||||
|
||||
# Actualizar IP prefix si hay una IP válida
|
||||
if interface.ip_address:
|
||||
prefix = '.'.join(interface.ip_address.split('.')[:3])
|
||||
self.ip_prefix.set(prefix)
|
||||
|
||||
# Guardar interfaz seleccionada
|
||||
self.config.last_interface = selected
|
||||
self.config.save_config()
|
||||
|
||||
self.log_message(f"Selected interface: {selected}")
|
||||
|
||||
def validate_ip_input(self) -> tuple[bool, str]:
|
||||
try:
|
||||
prefix = self.ip_prefix.get().strip()
|
||||
last_octet = self.last_octet.get().strip()
|
||||
|
||||
# Validar formato del prefijo
|
||||
if not re.match(r'^\d{1,3}\.\d{1,3}\.\d{1,3}', prefix):
|
||||
return False, "IP prefix must be in format: xxx.xxx.xxx"
|
||||
|
||||
# Validar último octeto
|
||||
if not last_octet.isdigit() or not 0 <= int(last_octet) <= 255:
|
||||
return False, "Last octet must be between 0 and 255"
|
||||
|
||||
# Construir y validar IP completa
|
||||
ip = f"{prefix}.{last_octet}"
|
||||
ipaddress.IPv4Address(ip)
|
||||
|
||||
return True, ip
|
||||
|
||||
except ValueError as e:
|
||||
return False, f"Invalid IP address: {str(e)}"
|
||||
|
||||
def execute_admin_script(self, interface: str, mode: str, debug: bool = True) -> bool:
|
||||
"""
|
||||
Ejecuta el script administrativo con los argumentos proporcionados
|
||||
mode puede ser una IP o 'dhcp'
|
||||
"""
|
||||
# Obtener rutas absolutas
|
||||
current_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
script_path = os.path.join(current_dir, "ip-changer-admin.py")
|
||||
python_exe = sys.executable
|
||||
|
||||
# Verificar que el script existe
|
||||
if not os.path.exists(script_path):
|
||||
error_msg = f"Admin script not found at: {script_path}"
|
||||
self.log_message(error_msg)
|
||||
return False
|
||||
|
||||
# Construir la línea de argumentos
|
||||
args = f'"{script_path}" "{interface}" "{mode}"'
|
||||
|
||||
if debug:
|
||||
self.log_message("Debug Information:")
|
||||
self.log_message(f"Current Directory: {current_dir}")
|
||||
self.log_message(f"Script Path: {script_path}")
|
||||
self.log_message(f"Python Executable: {python_exe}")
|
||||
self.log_message(f"Full Command: {python_exe} {args}")
|
||||
|
||||
try:
|
||||
self.log_message(f"Attempting to execute admin script with elevated privileges")
|
||||
|
||||
ret = ctypes.windll.shell32.ShellExecuteW(
|
||||
None, # hwnd
|
||||
"runas", # operation
|
||||
python_exe, # file
|
||||
args, # parameters
|
||||
current_dir, # directory
|
||||
1 # show command
|
||||
)
|
||||
|
||||
result_code = int(ret)
|
||||
if result_code > 32:
|
||||
self.log_message(f"ShellExecuteW successful (return code: {result_code})")
|
||||
return True
|
||||
else:
|
||||
error_codes = {
|
||||
0: "The operating system is out of memory or resources",
|
||||
2: "The specified file was not found",
|
||||
3: "The specified path was not found",
|
||||
5: "Access denied",
|
||||
8: "Insufficient memory to complete the operation",
|
||||
11: "Bad format",
|
||||
26: "A sharing violation occurred",
|
||||
27: "The file name association is incomplete or invalid",
|
||||
28: "The DDE operation timed out",
|
||||
29: "The DDE operation failed",
|
||||
30: "The DDE operation is busy",
|
||||
31: "The file name association is unavailable",
|
||||
32: "No application is associated with the file"
|
||||
}
|
||||
|
||||
self.log_message(f"Failed to execute admin script. Error code {result_code}: {error_msg}")
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
self.log_message(f"Exception while executing admin script: {str(e)}")
|
||||
return False
|
||||
|
||||
def set_static_ip(self):
|
||||
interface = self.if_var.get()
|
||||
if not interface:
|
||||
self.show_error("Please select a network interface")
|
||||
return
|
||||
|
||||
# Validar IP
|
||||
is_valid, result = self.validate_ip_input()
|
||||
if not is_valid:
|
||||
self.show_error(result)
|
||||
return
|
||||
|
||||
ip = result
|
||||
|
||||
# Guardar IP actual en el historial
|
||||
self.add_to_history(self.ip_prefix.get())
|
||||
|
||||
# Ejecutar script con privilegios
|
||||
if self.execute_admin_script(interface, ip, debug=True):
|
||||
time.sleep(2) # Esperar a que se apliquen los cambios
|
||||
self.refresh_interfaces()
|
||||
self.log_message(f"Successfully set static IP {ip} on {interface}")
|
||||
else:
|
||||
self.show_error("Failed to set static IP. Check the log for details.")
|
||||
|
||||
def set_dhcp(self):
|
||||
interface = self.if_var.get()
|
||||
if not interface:
|
||||
self.show_error("Please select a network interface")
|
||||
return
|
||||
|
||||
# Ejecutar script con privilegios
|
||||
if self.execute_admin_script(interface, "dhcp", debug=True):
|
||||
time.sleep(2) # Esperar a que se apliquen los cambios
|
||||
self.refresh_interfaces()
|
||||
self.log_message(f"Successfully enabled DHCP on {interface}")
|
||||
else:
|
||||
self.show_error("Failed to enable DHCP. Check the log for details.")
|
||||
|
||||
def run_command(self, cmd: str) -> bool:
|
||||
self.log_message(f"Executing command: {cmd}")
|
||||
try:
|
||||
process = subprocess.Popen(
|
||||
cmd,
|
||||
shell=True,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
universal_newlines=True
|
||||
)
|
||||
|
||||
while True:
|
||||
output = process.stdout.readline()
|
||||
if output == '' and process.poll() is not None:
|
||||
break
|
||||
if output:
|
||||
self.log_message(output.strip())
|
||||
|
||||
retcode = process.poll()
|
||||
|
||||
error_output = process.stderr.read()
|
||||
if error_output:
|
||||
self.log_message(f"Error output:\n{error_output}")
|
||||
|
||||
if retcode == 0:
|
||||
self.log_message("Command executed successfully")
|
||||
return True
|
||||
else:
|
||||
self.log_message(f"Command failed with return code: {retcode}")
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
self.log_message(f"Error executing command: {str(e)}")
|
||||
return False
|
||||
|
||||
def is_admin(self):
|
||||
try:
|
||||
return ctypes.windll.shell32.IsUserAnAdmin()
|
||||
except Exception as e:
|
||||
self.log_message(f"Error checking admin privileges: {str(e)}")
|
||||
return False
|
||||
|
||||
def elevate_privileges(self):
|
||||
if sys.platform == 'win32':
|
||||
self.show_info("The application needs administrator privileges to change network settings. "
|
||||
"Please confirm the UAC prompt.")
|
||||
script_path = os.path.abspath(sys.argv[0])
|
||||
try:
|
||||
ctypes.windll.shell32.ShellExecuteW(
|
||||
None,
|
||||
"runas",
|
||||
sys.executable,
|
||||
f'"{script_path}"',
|
||||
None,
|
||||
1
|
||||
)
|
||||
self.master.quit()
|
||||
except Exception as e:
|
||||
self.log_message(f"Error elevating privileges: {str(e)}")
|
||||
self.show_error("Failed to elevate privileges")
|
||||
|
||||
def show_error(self, message: str):
|
||||
self.log_message(f"ERROR: {message}")
|
||||
messagebox.showerror("Error", message)
|
||||
|
||||
def show_info(self, message: str):
|
||||
self.log_message(f"INFO: {message}")
|
||||
messagebox.showinfo("Information", message)
|
||||
|
||||
def main():
|
||||
root = tk.Tk()
|
||||
app = IPChangerApp(root)
|
||||
root.mainloop()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
|
@ -0,0 +1,55 @@
|
|||
import ctypes
|
||||
import sys
|
||||
import os
|
||||
import subprocess
|
||||
import re
|
||||
|
||||
def is_admin():
|
||||
"""Verifica si el script se está ejecutando con privilegios de administrador."""
|
||||
try:
|
||||
return ctypes.windll.shell32.IsUserAnAdmin()
|
||||
except:
|
||||
return False
|
||||
|
||||
def run_as_admin(argv=None, debug=False):
|
||||
"""Ejecuta el script como administrador."""
|
||||
shell32 = ctypes.windll.shell32
|
||||
if argv is None and shell32.IsUserAnAdmin():
|
||||
# Ya estamos ejecutando como administrador, no es necesario hacer nada
|
||||
return True
|
||||
if argv is None:
|
||||
argv = sys.argv
|
||||
if hasattr(sys, '_MEIPASS'):
|
||||
# Soporte para PyInstaller
|
||||
arguments = map(str, argv[1:])
|
||||
else:
|
||||
arguments = map(str, argv)
|
||||
argument_line = u' '.join(arguments)
|
||||
executable = str(sys.executable)
|
||||
if debug:
|
||||
print(f'Command line: {executable} {argument_line}')
|
||||
ret = shell32.ShellExecuteW(None, "runas", executable, argument_line, None, 1)
|
||||
if int(ret) <= 32:
|
||||
return False
|
||||
return None
|
||||
|
||||
def main():
|
||||
if not is_admin():
|
||||
# Si no se está ejecutando como administrador, solicitar elevación
|
||||
result = run_as_admin()
|
||||
if result is True:
|
||||
print("Ejecutando como administrador.")
|
||||
elif result is False:
|
||||
print("No se pudo obtener privilegios de administrador.")
|
||||
return
|
||||
else:
|
||||
# El script se reinició con privilegios de administrador
|
||||
return
|
||||
|
||||
# Aquí va el resto del código de tu script...
|
||||
# Por ejemplo:
|
||||
# save_current_ip()
|
||||
# ...
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
Loading…
Reference in New Issue