Este script PowerShell realiza un análisis completo de la salud del sistema, recopilando métricas de rendimiento, logs de eventos, información de seguridad y generando informes detallados en múltiples formatos. Está diseñado para ejecutarse con privilegios de administrador y proporciona una visión integral del estado del servidor o estación de trabajo. Genera informes en HTML, JSON, CSV o Excel para facilitar el análisis y la documentación.
📋 Requerimientos
Componente | Requisito |
---|---|
Sistema Operativo | Windows 10/11, Windows Server 2016+ |
PowerShell | Versión 5.1 o superior (recomendado PowerShell 7+) |
Permisos | Ejecución como Administrador (requerido para acceder a logs y WMI) |
Módulos adicionales | Algunas funciones requieren: ImportExcel, Pester (para pruebas) |
Funciones Principales
- Get-InformacionSistema
- Get-MetricasRendimiento
- Get-LogsEventos
- Get-AnalisisConfiabilidad
- Get-VerificacionCumplimiento
- Get-AnalisisPermisos
- Get-AuditoriaSoftware
Parámetros del Script
Parámetro | Descripción | Valores Permitidos | Valor por Defecto |
---|---|---|---|
SalidaArchivo | Ruta donde se guardarán los informes generados | Cualquier ruta válida | "C:\InformesSalud" |
DiasLogs | Número de días hacia atrás para analizar logs | Número entero positivo | 15 |
FormatoExportar | Formato de exportación del informe | HTML, JSON, CSV, EXCEL | HTML |
ParchesFaltantes | Revisa parches faltantes | Switch (true/false) | $false |
RevisarServicioTerceros | Revisa servicios de terceros | Switch (true/false) | $false |
AnalisisSeguridad | Realiza análisis de seguridad | Switch (true/false) | $true |
VerificarCumplimiento | Verifica cumplimiento con estándares | Switch (true/false) | $true |
Get-InformacionSistema
Propósito: Recopila información básica del sistema.
Parámetros: Ninguno
Retorna: Hashtable con:
- Nombre del servidor
- Dirección IP
- Información del SO (nombre, versión, build)
- Información del hardware (procesador, memoria, fabricante)
- Tiempo de actividad desde el último reinicio
- Información de dominio/workgroup
Código relevante:
Cargando código...
Get-MetricasRendimiento
Propósito: Recopila métricas de rendimiento de los subsistemas principales (CPU, memoria, disco y red).
Parámetros: Ninguno
Retorna: Hashtable con métricas detalladas de:
- Uso de CPU y cola de procesos
- Uso de memoria física y virtual
- Espacio en disco y tiempos de respuesta
- Tráfico y errores de red
Código relevante:
Cargando código...
Get-LogsEventos
Propósito: Recopila logs de eventos del sistema, aplicación y seguridad.
Parámetros: Dias: Número de días hacia atrás para buscar logs
Retorna: Hashtable con:
- Logs del sistema (errores y advertencias)
- Logs de aplicación (errores y advertencias)
- Eventos de seguridad (logins fallidos, cambios de cuenta)
Código relevante:
Cargando código...
param([int]$Dias)
try {
Write-Progress -Activity "Recopilando logs de los 3 tipos principales" -PercentComplete 25
$fechaInicio = (Get-Date).AddDays(-$Dias)
Write-Host " Período de logs: desde $($fechaInicio) hasta $(Get-Date)" -ForegroundColor Yellow
Write-Host " Recopilando logs del Sistema..." -ForegroundColor Yellow
$logsSistema = Get-WinEvent -FilterHashtable @{
LogName = 'System'
Level = 1,2,3
StartTime = $fechaInicio
} -MaxEvents 200 -ErrorAction SilentlyContinue |
Select-Object TimeCreated, LevelDisplayName, ProviderName, Id,
@{Name="Message";Expression={$_.Message.Substring(0,[Math]::Min(300,$_.Message.Length))}}
Write-Host " Recopilando logs de Aplicación..." -ForegroundColor Yellow
$logsAplicacion = Get-WinEvent -FilterHashtable @{
LogName = 'Application'
Level = 1,2,3
StartTime = $fechaInicio
} -MaxEvents 200 -ErrorAction SilentlyContinue |
Select-Object TimeCreated, LevelDisplayName, ProviderName, Id,
@{Name="Message";Expression={$_.Message.Substring(0,[Math]::Min(300,$_.Message.Length))}}
Write-Host " Recopilando logs de Seguridad..." -ForegroundColor Yellow
try {
$eventosSeguridad = Get-WinEvent -FilterHashtable @{
LogName = 'Security'
ID = 4624, 4625, 4634, 4647, 4648, 4740, 4767, 4771, 4776, 4616, 4720, 4722, 4724, 4738
StartTime = $fechaInicio
} -MaxEvents 150 -ErrorAction Stop
Write-Host " Se encontraron $($eventosSeguridad.Count) eventos de seguridad" -ForegroundColor Yellow
$logsSeguridad = $eventosSeguridad | ForEach-Object {
$evento = $_
$cuenta = "N/A"
$ip = "N/A"
try { $cuenta = if ($evento.Properties.Count -gt 5) { $evento.Properties[5].Value } elseif ($evento.Properties.Count -gt 1) { $evento.Properties[1].Value }
if ([string]::IsNullOrEmpty($cuenta)) {
for ($i = 0; $i -lt [Math]::Min(10, $evento.Properties.Count); $i++) {
if (![string]::IsNullOrEmpty($evento.Properties[$i].Value)) { $cuenta = $evento.Properties[$i].Value; break }
}
}
} catch { $cuenta = "No disponible" }
$ip = if ($evento.Properties.Count -gt 19) { $evento.Properties[19].Value } elseif ($evento.Properties.Count -gt 9) { $evento.Properties[9].Value }
try { $rawMessage = $evento.Message; if ($rawMessage.Length -gt 150) { $rawMessage = $rawMessage.Substring(0, 150) + "..." }
} catch { $rawMessage = "[No disponible]" }
$tipoEvento = switch ($evento.Id) {
4625 { "Login Fallido" }
4648 { "Login Explícito" }
4771 { "Kerberos Fallido" }
4776 { "Validación" }
4740 { "Cuenta Bloqueada" }
4767 { "Desbloqueada" }
4624 { "Login" }
4634 { "Logout" }
4647 { "Logout Usuario" }
4616 { "Cambio hora" }
4720 { "Cuenta creada" }
4722 { "Cuenta habilitada" }
4724 { "Cambio pwd" }
4738 { "Cambio cuenta" }
default { "ID:$($evento.Id)" }
}
[PSCustomObject]@{TimeCreated=$evento.TimeCreated;Id=$evento.Id;Account=$cuenta;SourceIP=$ip;EventType=$tipoEvento;RawMessage=$rawMessage}
}
} catch {
Write-Host " Error al obtener logs de seguridad: $_" -ForegroundColor Red
$logsSeguridad = @()
}
Write-Host " Total eventos encontrados - Sistema: $($logsSistema.Count), Aplicación: $($logsAplicacion.Count), Seguridad: $($logsSeguridad.Count)" -ForegroundColor Yellow
return @{
LogsSistema = $logsSistema
LogsAplicacion = $logsAplicacion
LogsSeguridad = $logsSeguridad
}
} catch {
Write-Warning "Error al obtener logs de eventos: $_"
return @{ Error = $_.Exception.Message }
}
}
Get-AnalisisConfiabilidad
Propósito: Analiza la confiabilidad del sistema y eventos críticos.
Parámetros: Ninguno
Retorna: Estadísticas de estabilidad y eventos de confiabilidad.
Código relevante:
Cargando código...
try {
Write-Progress -Activity "Analizando confiabilidad del sistema" -PercentComplete 35
Write-Host " Analizando registros de confiabilidad..." -ForegroundColor Yellow
$datos = @{}
try {
$reliabilityRecords = Get-CimInstance -ClassName Win32_ReliabilityRecords -ErrorAction SilentlyContinue |
Where-Object { $_.TimeGenerated -gt (Get-Date).AddDays(-30) } |
Sort-Object TimeGenerated -Descending |
Select-Object -First 100
if ($reliabilityRecords) {
Write-Host " Se encontraron $($reliabilityRecords.Count) registros de confiabilidad" -ForegroundColor Yellow
$eventosConfiabilidad = $reliabilityRecords | ForEach-Object {
$tipoEvento = switch ($_.EventIdentifier) {
1001 { "Inicio de aplicación" }
1002 { "Fallo de aplicación" }
1003 { "Cuelgue de aplicación" }
1004 { "Instalación exitosa" }
1005 { "Fallo de instalación" }
1006 { "Inicio del sistema" }
1007 { "Apagado del sistema" }
1008 { "Fallo del sistema" }
default { "Evento ID: $($_.EventIdentifier)" }
}
[PSCustomObject]@{
Fecha = $_.TimeGenerated
TipoEvento = $tipoEvento
Fuente = $_.SourceName
Descripcion = if ($_.Message) { $_.Message.Substring(0, [Math]::Min(200, $_.Message.Length)) } else { "N/A" }
EventID = $_.EventIdentifier
Criticidad = switch ($_.EventIdentifier) {
{ $_ -in @(1002, 1003, 1005, 1008) } { "Alto" }
{ $_ -in @(1001, 1004, 1006, 1007) } { "Normal" }
default { "Medio" }
}
}
}
$datos.EventosConfiabilidad = $eventosConfiabilidad
$fallosAplicacion = ($eventosConfiabilidad | Where-Object { $_.EventID -in @(1002, 1003) }).Count
$fallosSistema = ($eventosConfiabilidad | Where-Object { $_.EventID -eq 1008 }).Count
$reinicios = ($eventosConfiabilidad | Where-Object { $_.EventID -in @(1006, 1007) }).Count
$datos.EstadisticasEstabilidad = @{
FallosAplicacion = $fallosAplicacion
FallosSistema = $fallosSistema
ReiniciosDetectados = $reinicios
TotalEventos = $eventosConfiabilidad.Count
PeriodoAnalisis = "Últimos 30 días"
IndiceEstabilidad = switch ($true) {
{ $fallosSistema -gt 5 -or $fallosAplicacion -gt 20 } { "Baja" }
{ $fallosSistema -gt 2 -or $fallosAplicacion -gt 10 } { "Media" }
default { "Alta" }
}
}
$tendenciasSemana = $eventosConfiabilidad |
Group-Object { (Get-Date $_.Fecha).ToString("yyyy-MM-dd") } |
Sort-Object Name -Descending |
Select-Object -First 7 |
ForEach-Object {
$fallosDia = ($_.Group | Where-Object { $_.Criticidad -eq "Alto" }).Count
[PSCustomObject]@{
Fecha = $_.Name
TotalEventos = $_.Count
EventosCriticos = $fallosDia
Estabilidad = if ($fallosDia -eq 0) { "Estable" } elseif ($fallosDia -lt 3) { "Moderada" } else { "Inestable" }
}
}
$datos.TendenciasSemanales = $tendenciasSemana
} else {
Write-Host " No se encontraron registros de confiabilidad o no están disponibles" -ForegroundColor Yellow
$datos.EventosConfiabilidad = @()
$datos.EstadisticasEstabilidad = @{ Error = "No hay datos de confiabilidad disponibles" }
$datos.TendenciasSemanales = @()
}
} catch {
Write-Host " Error al acceder a registros de confiabilidad: $_" -ForegroundColor Red
try {
Write-Host " Intentando método alternativo con Event Log..." -ForegroundColor Yellow
$eventosAlternativos = Get-WinEvent -FilterHashtable @{
LogName = 'System'
Level = 1,2
StartTime = (Get-Date).AddDays(-7)
} -MaxEvents 50 -ErrorAction SilentlyContinue |
Where-Object { $_.Id -in @(1001, 1074, 6005, 6006, 6008, 6009, 6013) } |
ForEach-Object {
[PSCustomObject]@{
Fecha = $_.TimeCreated
TipoEvento = switch ($_.Id) {
1074 { "Apagado del sistema" }
6005 { "Inicio del servicio Event Log" }
6006 { "Parada del servicio Event Log" }
6008 { "Apagado inesperado" }
6009 { "Información de versión del procesador" }
6013 { "Tiempo de actividad del sistema" }
default { "Evento del sistema" }
}
EventID = $_.Id
Fuente = $_.ProviderName
Criticidad = if ($_.Id -eq 6008) { "Alto" } else { "Normal" }
}
}
$datos.EventosConfiabilidad = $eventosAlternativos
$datos.EstadisticasEstabilidad = @{
Metodo = "Event Log alternativo"
ApagadosInesperados = ($eventosAlternativos | Where-Object { $_.EventID -eq 6008 }).Count
TotalEventos = $eventosAlternativos.Count
PeriodoAnalisis = "Últimos 7 días"
}
} catch {
$datos.EventosConfiabilidad = @()
$datos.EstadisticasEstabilidad = @{ Error = "No se pudo obtener información de confiabilidad: $_" }
}
}
return $datos
} catch {
Write-Warning "Error en análisis de confiabilidad: $_"
return @{ Error = $_.Exception.Message }
}
}
Get-DiagnosticoHardwareAvanzado
Propósito: Realiza diagnóstico avanzado del hardware.
Parámetros: Ninguno
Retorna: Estado SMART de discos, temperaturas, baterías y otros componentes.
Código relevante:
Cargando código...
try {
Write-Progress -Activity "Realizando diagnóstico avanzado de hardware" -PercentComplete 45
Write-Host " Analizando hardware avanzado..." -ForegroundColor Yellow
$datos = @{}
Write-Host " Verificando estado SMART de discos..." -ForegroundColor Yellow
try {
$discosSMART = Get-CimInstance -ClassName Win32_DiskDrive -ErrorAction SilentlyContinue | ForEach-Object {
$disco = $_
$smartData = $null
try {
$smartData = Get-CimInstance -ClassName MSStorageDriver_FailurePredictStatus -Namespace "root\wmi" -ErrorAction SilentlyContinue |
Where-Object { $_.InstanceName -like "*$($disco.PNPDeviceID)*" }
if (-not $smartData) {
$smartData = Get-CimInstance -ClassName Win32_DiskDrive -ErrorAction SilentlyContinue |
Where-Object { $_.DeviceID -eq $disco.DeviceID } |
ForEach-Object {
[PSCustomObject]@{
PredictFailure = $false
Reason = "Datos SMART no disponibles"
}
}
}
} catch {
$smartData = [PSCustomObject]@{
PredictFailure = $null
Reason = "Error al acceder a SMART: $_"
}
}
[PSCustomObject]@{
Modelo = $disco.Model
NumeroSerie = $disco.SerialNumber
TamanoGB = [math]::Round($disco.Size / 1GB, 2)
Interfaz = $disco.InterfaceType
EstadoSMART = if ($smartData.PredictFailure -eq $true) { "FALLO PREDICHO" }
elseif ($smartData.PredictFailure -eq $false) { "Saludable" }
else { "No disponible" }
DetallesSMART = $smartData.Reason
Particiones = (Get-CimInstance -ClassName Win32_DiskPartition -ErrorAction SilentlyContinue |
Where-Object { $_.DiskIndex -eq $disco.Index }).Count
Estado = switch ($smartData.PredictFailure) {
$true { "Crítico" }
$false { "Normal" }
default { "Desconocido" }
}
}
}
$datos.DiscosSMART = $discosSMART
} catch {
Write-Host " Error al obtener datos SMART: $_" -ForegroundColor Red
$datos.DiscosSMART = @{ Error = "No se pudo obtener información SMART: $_" }
}
Write-Host " Verificando temperaturas de componentes..." -ForegroundColor Yellow
try {
$temperaturas = @()
$tempCPU = Get-CimInstance -ClassName Win32_PerfRawData_Counters_ThermalZoneInformation -ErrorAction SilentlyContinue |
Where-Object { $_.Name -like "*CPU*" -or $_.Name -like "*Processor*" } |
ForEach-Object {
$tempKelvin = $_.Temperature
$tempCelsius = if ($tempKelvin -and $tempKelvin -gt 0) {
[math]::Round(($tempKelvin / 10) - 273.15, 1)
} else { $null }
[PSCustomObject]@{
Componente = "CPU - $($_.Name)"
TemperaturaC = $tempCelsius
Estado = if ($tempCelsius -gt 80) { "Crítico" }
elseif ($tempCelsius -gt 70) { "Alto" }
elseif ($tempCelsius -gt 0) { "Normal" }
else { "No disponible" }
}
}
if ($tempCPU) { $temperaturas += $tempCPU }
try {
$wmiTemp = Get-CimInstance -ClassName MSAcpi_ThermalZoneTemperature -Namespace "root\wmi" -ErrorAction SilentlyContinue |
ForEach-Object {
$tempKelvin = $_.CurrentTemperature
$tempCelsius = if ($tempKelvin -and $tempKelvin -gt 0) {
[math]::Round(($tempKelvin / 10) - 273.15, 1)
} else { $null }
[PSCustomObject]@{
Componente = "Zona Térmica - $($_.InstanceName)"
TemperaturaC = $tempCelsius
Estado = if ($tempCelsius -gt 80) { "Crítico" }
elseif ($tempCelsius -gt 70) { "Alto" }
elseif ($tempCelsius -gt 0) { "Normal" }
else { "No disponible" }
}
}
if ($wmiTemp) { $temperaturas += $wmiTemp }
} catch {
Write-Host " Método WMI para temperaturas no disponible" -ForegroundColor Yellow
}
if ($temperaturas.Count -eq 0) {
$temperaturas = @([PSCustomObject]@{
Componente = "Sistema"
TemperaturaC = $null
Estado = "Sensores de temperatura no disponibles"
})
}
$datos.Temperaturas = $temperaturas
} catch {
Write-Host " Error al obtener temperaturas: $_" -ForegroundColor Red
$datos.Temperaturas = @{ Error = "No se pudo obtener información de temperatura: $_" }
}
Write-Host " Verificando estado de la batería..." -ForegroundColor Yellow
try {
$baterias = Get-CimInstance -ClassName Win32_Battery -ErrorAction SilentlyContinue
if ($baterias) {
$estadoBaterias = $baterias | ForEach-Object {
$bateria = $_
$batteryStatus = Get-CimInstance -ClassName BatteryStatus -Namespace "root\wmi" -ErrorAction SilentlyContinue |
Where-Object { $_.InstanceName -like "*$($bateria.DeviceID)*" }
$estadoCarga = switch ($bateria.BatteryStatus) {
1 { "Desconocido" }
2 { "Cargando" }
3 { "Descargando" }
4 { "Crítico" }
5 { "Bajo" }
6 { "Cargando y Alto" }
7 { "Cargando y Bajo" }
8 { "Cargando y Crítico" }
9 { "Indefinido" }
10 { "Parcialmente Cargado" }
11 { "Completamente Cargado" }
default { "Estado $($bateria.BatteryStatus)" }
}
[PSCustomObject]@{
Nombre = $bateria.Name
Fabricante = $bateria.Manufacturer
EstadoCarga = $estadoCarga
PorcentajeCarga = $bateria.EstimatedChargeRemaining
TiempoRestante = if ($bateria.EstimatedRunTime -and $bateria.EstimatedRunTime -ne 71582788) {
"$([math]::Round($bateria.EstimatedRunTime / 60, 1)) horas"
} else { "Calculando..." }
CapacidadDiseño = if ($bateria.DesignCapacity) { "$($bateria.DesignCapacity) mWh" } else { "N/A" }
CapacidadCompleta = if ($bateria.FullChargeCapacity) { "$($bateria.FullChargeCapacity) mWh" } else { "N/A" }
SaludBateria = if ($bateria.DesignCapacity -and $bateria.FullChargeCapacity) {
$salud = [math]::Round(($bateria.FullChargeCapacity / $bateria.DesignCapacity) * 100, 1)
"$salud%"
} else { "No disponible" }
Estado = switch ($true) {
{ $bateria.BatteryStatus -in @(4, 8) } { "Crítico" }
{ $bateria.BatteryStatus -in @(5, 7) } { "Bajo" }
{ $bateria.EstimatedChargeRemaining -lt 20 } { "Advertencia" }
default { "Normal" }
}
}
}
$datos.Baterias = $estadoBaterias
} else {
$datos.Baterias = @([PSCustomObject]@{
Estado = "No se detectaron baterías (sistema de escritorio)"
})
}
} catch {
Write-Host " Error al obtener estado de batería: $_" -ForegroundColor Red
$datos.Baterias = @{ Error = "No se pudo obtener información de batería: $_" }
}
Write-Host " Recopilando información adicional de hardware..." -ForegroundColor Yellow
try {
$memoriaFisica = Get-CimInstance -ClassName Win32_PhysicalMemory -ErrorAction SilentlyContinue | ForEach-Object {
[PSCustomObject]@{
Ubicacion = $_.DeviceLocator
Capacidad = "$([math]::Round($_.Capacity / 1GB, 2)) GB"
Velocidad = "$($_.Speed) MHz"
Fabricante = $_.Manufacturer
NumeroSerie = $_.SerialNumber
TipoMemoria = switch ($_.MemoryType) {
20 { "DDR" }
21 { "DDR2" }
22 { "DDR2 FB-DIMM" }
24 { "DDR3" }
26 { "DDR4" }
default { "Tipo $($_.MemoryType)" }
}
}
}
$datos.MemoriaFisica = $memoriaFisica
$ventiladores = Get-CimInstance -ClassName Win32_Fan -ErrorAction SilentlyContinue | ForEach-Object {
[PSCustomObject]@{
Nombre = $_.Name
Descripcion = $_.Description
Estado = switch ($_.Status) {
"OK" { "Normal" }
"Error" { "Error" }
"Degraded" { "Degradado" }
default { $_.Status }
}
Activo = $_.ActiveCooling
}
}
if ($ventiladores.Count -eq 0) {
$ventiladores = @([PSCustomObject]@{
Estado = "No se detectaron ventiladores o información no disponible"
})
}
$datos.Ventiladores = $ventiladores
} catch {
Write-Host " Error al obtener información adicional de hardware: $_" -ForegroundColor Red
$datos.MemoriaFisica = @{ Error = "No disponible" }
$datos.Ventiladores = @{ Error = "No disponible" }
}
return $datos
} catch {
Write-Warning "Error en diagnóstico de hardware avanzado: $_"
return @{ Error = $_.Exception.Message }
}
}
Get-AnalisisRolesServidor
Propósito: Analiza roles y características del servidor (si es aplicable).
Parámetros: Ninguno
Retorna: Información sobre roles instalados y su estado.
Código relevante:
Cargando código...
try {
Write-Progress -Activity "Analizando roles y características del servidor" -PercentComplete 55
Write-Host " Analizando roles de Windows Server..." -ForegroundColor Yellow
$datos = @{}
$os = Get-CimInstance -ClassName Win32_OperatingSystem
$esServidor = $os.ProductType -eq 2 -or $os.ProductType -eq 3 -or $os.Caption -like "*Server*"
if (-not $esServidor) {
Write-Host " Sistema detectado como cliente Windows, no servidor" -ForegroundColor Yellow
return @{
TipoSistema = "Cliente Windows"
EsServidor = $false
Mensaje = "Este sistema no es Windows Server. Análisis de roles no aplicable."
}
}
Write-Host " Sistema Windows Server detectado, analizando roles..." -ForegroundColor Yellow
$datos.EsServidor = $true
$datos.TipoSistema = "Windows Server"
try {
Write-Host " Obteniendo características mediante DISM..." -ForegroundColor Yellow
$dismFeatures = dism /online /get-features /format:table | Out-String
$caracteristicasHabilitadas = @()
$lineas = $dismFeatures -split "`n" | Where-Object { $_ -match "Enabled" }
foreach ($linea in $lineas) {
if ($linea -match "^([^\|]+)\|.*Enabled") {
$nombreCaracteristica = $matches[1].Trim()
if ($nombreCaracteristica -and $nombreCaracteristica -ne "Feature Name") {
$caracteristicasHabilitadas += $nombreCaracteristica
}
}
}
$datos.CaracteristicasDISM = $caracteristicasHabilitadas
} catch {
Write-Host " Error al usar DISM: $_" -ForegroundColor Red
$datos.CaracteristicasDISM = @("Error al obtener características via DISM")
}
Write-Host " Analizando servicios de roles específicos..." -ForegroundColor Yellow
$rolesDetectados = @()
$addsService = Get-Service -Name "NTDS" -ErrorAction SilentlyContinue
if ($addsService) {
$rolesDetectados += [PSCustomObject]@{
Rol = "Active Directory Domain Services"
Servicio = "NTDS"
Estado = $addsService.Status
TipoInicio = $addsService.StartType
Descripcion = "Controlador de dominio Active Directory"
Critico = $true
}
}
$dnsService = Get-Service -Name "DNS" -ErrorAction SilentlyContinue
if ($dnsService) {
$rolesDetectados += [PSCustomObject]@{
Rol = "DNS Server"
Servicio = "DNS"
Estado = $dnsService.Status
TipoInicio = $dnsService.StartType
Descripcion = "Servidor DNS"
Critico = $true
}
}
$dhcpService = Get-Service -Name "DHCPServer" -ErrorAction SilentlyContinue
if ($dhcpService) {
$rolesDetectados += [PSCustomObject]@{
Rol = "DHCP Server"
Servicio = "DHCPServer"
Estado = $dhcpService.Status
TipoInicio = $dhcpService.StartType
Descripcion = "Servidor DHCP"
Critico = $false
}
}
$iisService = Get-Service -Name "W3SVC" -ErrorAction SilentlyContinue
if ($iisService) {
$rolesDetectados += [PSCustomObject]@{
Rol = "Web Server (IIS)"
Servicio = "W3SVC"
Estado = $iisService.Status
TipoInicio = $iisService.StartType
Descripcion = "Servidor web IIS"
Critico = $false
}
try {
$iisInfo = Get-CimInstance -ClassName Win32_Service -Filter "Name='W3SVC'" -ErrorAction SilentlyContinue
$sitiosIIS = @()
if (Get-Command "Get-IISSite" -ErrorAction SilentlyContinue) {
$sitiosIIS = Get-IISSite | ForEach-Object {
[PSCustomObject]@{
Nombre = $_.Name
Estado = $_.State
Puerto = ($_.Bindings | ForEach-Object { $_.EndPoint.Port }) -join ", "
RutaFisica = $_.PhysicalPath
}
}
} else {
try {
$appcmdPath = "$env:SystemRoot\System32\inetsrv\appcmd.exe"
if (Test-Path $appcmdPath) {
$sitiosOutput = & $appcmdPath list sites
$sitiosIIS = $sitiosOutput | ForEach-Object {
if ($_ -match 'SITE "([^"]+)" \$\$id:(\d+),bindings:([^,]+),state:(\w+)\$\$') {
[PSCustomObject]@{
Nombre = $matches[1]
ID = $matches[2]
Bindings = $matches[3]
Estado = $matches[4]
}
}
}
}
} catch {
$sitiosIIS = @([PSCustomObject]@{ Info = "No se pudo obtener información de sitios IIS" })
}
}
$datos.SitiosIIS = $sitiosIIS
} catch {
$datos.SitiosIIS = @{ Error = "Error al obtener información de IIS: $_" }
}
}
$lanmanService = Get-Service -Name "LanmanServer" -ErrorAction SilentlyContinue
if ($lanmanService -and $lanmanService.Status -eq "Running") {
$rolesDetectados += [PSCustomObject]@{
Rol = "File and Storage Services"
Servicio = "LanmanServer"
Estado = $lanmanService.Status
TipoInicio = $lanmanService.StartType
Descripcion = "Servicios de archivos y almacenamiento"
Critico = $false
}
}
$spoolerService = Get-Service -Name "Spooler" -ErrorAction SilentlyContinue
if ($spoolerService -and $spoolerService.Status -eq "Running") {
$impresorasCompartidas = Get-CimInstance -ClassName Win32_Printer -ErrorAction SilentlyContinue |
Where-Object { $_.Shared -eq $true }
if ($impresorasCompartidas) {
$rolesDetectados += [PSCustomObject]@{
Rol = "Print and Document Services"
Servicio = "Spooler"
Estado = $spoolerService.Status
TipoInicio = $spoolerService.StartType
Descripcion = "Servicios de impresión y documentos"
Critico = $false
}
}
}
$termService = Get-Service -Name "TermService" -ErrorAction SilentlyContinue
if ($termService) {
$rolesDetectados += [PSCustomObject]@{
Rol = "Remote Desktop Services"
Servicio = "TermService"
Estado = $termService.Status
TipoInicio = $termService.StartType
Descripcion = "Servicios de escritorio remoto"
Critico = $false
}
}
$wsusService = Get-Service -Name "WsusService" -ErrorAction SilentlyContinue
if ($wsusService) {
$rolesDetectados += [PSCustomObject]@{
Rol = "Windows Server Update Services"
Servicio = "WsusService"
Estado = $wsusService.Status
TipoInicio = $wsusService.StartType
Descripcion = "Servidor WSUS"
Critico = $false
}
}
$hypervService = Get-Service -Name "vmms" -ErrorAction SilentlyContinue
if ($hypervService) {
$rolesDetectados += [PSCustomObject]@{
Rol = "Hyper-V"
Servicio = "vmms"
Estado = $hypervService.Status
TipoInicio = $hypervService.StartType
Descripcion = "Plataforma de virtualización Hyper-V"
Critico = $false
}
try {
if (Get-Command "Get-VM" -ErrorAction SilentlyContinue) {
$vms = Get-VM -ErrorAction SilentlyContinue | ForEach-Object {
[PSCustomObject]@{
Nombre = $_.Name
Estado = $_.State
CPUs = $_.ProcessorCount
MemoriaGB = [math]::Round($_.MemoryAssigned / 1GB, 2)
TiempoActividad = if ($_.Uptime) { $_.Uptime.ToString() } else { "N/A" }
}
}
$datos.MaquinasVirtuales = $vms
} else {
$datos.MaquinasVirtuales = @{ Info = "Cmdlets de Hyper-V no disponibles" }
}
} catch {
$datos.MaquinasVirtuales = @{ Error = "Error al obtener VMs: $_" }
}
}
$datos.RolesDetectados = $rolesDetectados
Write-Host " Recopilando información adicional del servidor..." -ForegroundColor Yellow
try {
$dominioInfo = Get-CimInstance -ClassName Win32_ComputerSystem
$datos.InformacionDominio = @{
ParteDominio = $dominioInfo.PartOfDomain
Dominio = $dominioInfo.Domain
Workgroup = $dominioInfo.Workgroup
Rol = switch ($dominioInfo.DomainRole) {
0 { "Standalone Workstation" }
1 { "Member Workstation" }
2 { "Standalone Server" }
3 { "Member Server" }
4 { "Backup Domain Controller" }
5 { "Primary Domain Controller" }
default { "Desconocido ($($dominioInfo.DomainRole))" }
}
}
} catch {
$datos.InformacionDominio = @{ Error = "No se pudo obtener información de dominio" }
}
try {
$caracteristicasWindows = Get-WindowsFeature -ErrorAction SilentlyContinue |
Where-Object { $_.InstallState -eq "Installed" } |
Select-Object Name, DisplayName, InstallState |
Sort-Object DisplayName
if ($caracteristicasWindows) {
$datos.CaracteristicasWindows = $caracteristicasWindows
} else {
$datos.CaracteristicasWindows = @{ Info = "Get-WindowsFeature no disponible en esta versión" }
}
} catch {
$datos.CaracteristicasWindows = @{ Error = "Error al obtener características de Windows: $_" }
}
$rolesCriticos = $rolesDetectados | Where-Object { $_.Critico -eq $true }
$rolesDetenidos = $rolesDetectados | Where-Object { $_.Estado -ne "Running" }
$datos.ResumenRoles = @{
TotalRoles = $rolesDetectados.Count
RolesCriticos = $rolesCriticos.Count
RolesDetenidos = $rolesDetenidos.Count
EstadoGeneral = if ($rolesDetenidos.Count -eq 0) { "Todos los roles funcionando" }
elseif ($rolesDetenidos.Count -eq 1) { "1 rol detenido" }
else { "$($rolesDetenidos.Count) roles detenidos" }
}
return $datos
} catch {
Write-Warning "Error en análisis de roles del servidor: $_"
return @{ Error = $_.Exception.Message }
}
}
Get-AnalisisPoliticasGrupo
Propósito: Analiza políticas de grupo aplicadas.
Parámetros: Ninguno
Retorna: GPOs aplicadas y configuración de políticas locales.
Código relevante:
Cargando código...
try {
Write-Progress -Activity "Analizando políticas de grupo aplicadas" -PercentComplete 60
Write-Host " Analizando políticas de grupo (GPO)..." -ForegroundColor Yellow
$datos = @{}
try {
$computerSystem = Get-CimInstance -ClassName Win32_ComputerSystem
if (-not $computerSystem.PartOfDomain) {
Write-Host " Sistema no está en dominio, análisis GPO limitado" -ForegroundColor Yellow
return @{
EnDominio = $false
Mensaje = "El sistema no está unido a un dominio. Análisis de GPO no aplicable."
PoliticasLocales = Get-AnalisisPoliticasLocales
}
}
Write-Host " Sistema en dominio detectado, analizando GPOs..." -ForegroundColor Yellow
$datos.EnDominio = $true
$gpresultOutput = gpresult /r /scope:computer 2>$null
$gpresultUser = gpresult /r /scope:user 2>$null
$gpoComputer = @()
$gpoUser = @()
if ($gpresultOutput) {
$inGPOSection = $false
foreach ($line in $gpresultOutput) {
if ($line -match "Applied Group Policy Objects") {
$inGPOSection = $true
continue
}
if ($inGPOSection -and $line.Trim() -ne "" -and $line -notmatch "^-+$") {
if ($line -match "The following GPOs were not applied") {
break
}
$gpoName = $line.Trim()
if ($gpoName -and $gpoName -ne "None") {
$gpoComputer += [PSCustomObject]@{
Nombre = $gpoName
Tipo = "Equipo"
Estado = "Aplicada"
}
}
}
}
}
if ($gpresultUser) {
$inGPOSection = $false
foreach ($line in $gpresultUser) {
if ($line -match "Applied Group Policy Objects") {
$inGPOSection = $true
continue
}
if ($inGPOSection -and $line.Trim() -ne "" -and $line -notmatch "^-+$") {
if ($line -match "The following GPOs were not applied") {
break
}
$gpoName = $line.Trim()
if ($gpoName -and $gpoName -ne "None") {
$gpoUser += [PSCustomObject]@{
Nombre = $gpoName
Tipo = "Usuario"
Estado = "Aplicada"
}
}
}
}
}
$datos.GPOsEquipo = $gpoComputer
$datos.GPOsUsuario = $gpoUser
try {
Write-Host " Obteniendo detalles de configuración GPO..." -ForegroundColor Yellow
$gpresultDetailed = gpresult /v /scope:computer 2>$null
$configuracionesSeguridad = @()
$configuracionesRed = @()
$configuracionesAuditoria = @()
if ($gpresultDetailed) {
$currentSection = ""
foreach ($line in $gpresultDetailed) {
if ($line -match "Security Settings") {
$currentSection = "Security"
} elseif ($line -match "Network") {
$currentSection = "Network"
} elseif ($line -match "Audit") {
$currentSection = "Audit"
}
if ($line -match "^\s+(.+):\s+(.+)$") {
$setting = $matches[1].Trim()
$value = $matches[2].Trim()
$configObj = [PSCustomObject]@{
Configuracion = $setting
Valor = $value
Seccion = $currentSection
}
switch ($currentSection) {
"Security" { $configuracionesSeguridad += $configObj }
"Network" { $configuracionesRed += $configObj }
"Audit" { $configuracionesAuditoria += $configObj }
}
}
}
}
$datos.ConfiguracionesSeguridad = $configuracionesSeguridad
$datos.ConfiguracionesRed = $configuracionesRed
$datos.ConfiguracionesAuditoria = $configuracionesAuditoria
} catch {
Write-Host " Error al obtener detalles de GPO: $_" -ForegroundColor Red
$datos.ConfiguracionesSeguridad = @()
$datos.ConfiguracionesRed = @()
$datos.ConfiguracionesAuditoria = @()
}
try {
$gpoUpdateInfo = gpresult /r | Select-String "Last time Group Policy was applied"
if ($gpoUpdateInfo) {
$datos.UltimaActualizacionGPO = $gpoUpdateInfo.ToString().Split(":")[1].Trim()
} else {
$datos.UltimaActualizacionGPO = "No disponible"
}
} catch {
$datos.UltimaActualizacionGPO = "Error al obtener fecha"
}
} catch {
Write-Host " Error al analizar GPOs: $_" -ForegroundColor Red
$datos.Error = "Error al obtener información de GPO: $_"
}
$datos.PoliticasLocales = Get-AnalisisPoliticasLocales
return $datos
} catch {
Write-Warning "Error en análisis de políticas de grupo: $_"
return @{ Error = $_.Exception.Message }
}
}
Get-VerificacionCumplimiento
Propósito: Verifica cumplimiento con estándares CIS Benchmarks.
Parámetros: Ninguno
Retorna: Resultados de verificaciones de cumplimiento.
Código relevante:
Cargando código...
try {
Write-Progress -Activity "Verificando cumplimiento con estándares de seguridad" -PercentComplete 65
Write-Host " Verificando cumplimiento con CIS Benchmarks..." -ForegroundColor Yellow
$verificaciones = @()
Write-Host " Verificando políticas de contraseña..." -ForegroundColor Yellow
$passwordPolicy = net accounts 2>$null
$minPasswordLength = 0
$maxPasswordAge = 0
$minPasswordAge = 0
$passwordComplexity = $false
if ($passwordPolicy) {
foreach ($line in $passwordPolicy) {
if ($line -match "Minimum password length:\s*(\d+)") {
$minPasswordLength = [int]$matches[1]
} elseif ($line -match "Maximum password age \$\$days\$\$:\s*(\d+)") {
$maxPasswordAge = [int]$matches[1]
} elseif ($line -match "Minimum password age \$\$days\$\$:\s*(\d+)") {
$minPasswordAge = [int]$matches[1]
}
}
}
try {
$secpol = secedit /export /cfg "$env:TEMP\secpol_check.cfg" 2>$null
if (Test-Path "$env:TEMP\secpol_check.cfg") {
$secpolContent = Get-Content "$env:TEMP\secpol_check.cfg"
$complexityLine = $secpolContent | Where-Object { $_ -match "PasswordComplexity" }
if ($complexityLine -and $complexityLine -match "=\s*1") {
$passwordComplexity = $true
}
Remove-Item "$env:TEMP\secpol_check.cfg" -Force -ErrorAction SilentlyContinue
}
} catch {}
$verificaciones += [PSCustomObject]@{
ID = "CIS-1.1.1"
Descripcion = "Enforce password history: 24 or more passwords remembered"
Categoria = "Políticas de Contraseña"
EstadoActual = "Verificar manualmente"
Recomendacion = "24 o más contraseñas"
Cumple = "Pendiente"
Criticidad = "Media"
}
$verificaciones += [PSCustomObject]@{
ID = "CIS-1.1.2"
Descripcion = "Maximum password age: 365 or fewer days"
Categoria = "Políticas de Contraseña"
EstadoActual = "$maxPasswordAge días"
Recomendacion = "365 días o menos"
Cumple = if ($maxPasswordAge -le 365 -and $maxPasswordAge -gt 0) { "Sí" } else { "No" }
Criticidad = "Media"
}
$verificaciones += [PSCustomObject]@{
ID = "CIS-1.1.3"
Descripcion = "Minimum password age: 1 or more days"
Categoria = "Políticas de Contraseña"
EstadoActual = "$minPasswordAge días"
Recomendacion = "1 día o más"
Cumple = if ($minPasswordAge -ge 1) { "Sí" } else { "No" }
Criticidad = "Baja"
}
$verificaciones += [PSCustomObject]@{
ID = "CIS-1.1.4"
Descripcion = "Minimum password length: 14 or more characters"
Categoria = "Políticas de Contraseña"
EstadoActual = "$minPasswordLength caracteres"
Recomendacion = "14 caracteres o más"
Cumple = if ($minPasswordLength -ge 14) { "Sí" } else { "No" }
Criticidad = "Alta"
}
$verificaciones += [PSCustomObject]@{
ID = "CIS-1.1.5"
Descripcion = "Password must meet complexity requirements"
Categoria = "Políticas de Contraseña"
EstadoActual = if ($passwordComplexity) { "Habilitado" } else { "Deshabilitado" }
Recomendacion = "Habilitado"
Cumple = if ($passwordComplexity) { "Sí" } else { "No" }
Criticidad = "Alta"
}
Write-Host " Verificando políticas de bloqueo de cuenta..." -ForegroundColor Yellow
$lockoutThreshold = 0
$lockoutDuration = 0
if ($passwordPolicy) {
foreach ($line in $passwordPolicy) {
if ($line -match "Lockout threshold:\s*(\d+)") {
$lockoutThreshold = [int]$matches[1]
} elseif ($line -match "Lockout duration \$\$minutes\$\$:\s*(\d+)") {
$lockoutDuration = [int]$matches[1]
}
}
}
$verificaciones += [PSCustomObject]@{
ID = "CIS-1.2.1"
Descripcion = "Account lockout threshold: 5 or fewer invalid attempts"
Categoria = "Políticas de Bloqueo"
EstadoActual = if ($lockoutThreshold -eq 0) { "Sin bloqueo" } else { "$lockoutThreshold intentos" }
Recomendacion = "5 intentos o menos"
Cumple = if ($lockoutThreshold -gt 0 -and $lockoutThreshold -le 5) { "Sí" } else { "No" }
Criticidad = "Media"
}
$verificaciones += [PSCustomObject]@{
ID = "CIS-1.2.2"
Descripcion = "Account lockout duration: 15 or more minutes"
Categoria = "Políticas de Bloqueo"
EstadoActual = "$lockoutDuration minutos"
Recomendacion = "15 minutos o más"
Cumple = if ($lockoutDuration -ge 15) { "Sí" } else { "No" }
Criticidad = "Media"
}
Write-Host " Verificando servicios y características de seguridad..." -ForegroundColor Yellow
$defenderStatus = Get-MpComputerStatus -ErrorAction SilentlyContinue
$verificaciones += [PSCustomObject]@{
ID = "CIS-18.9.39.1"
Descripcion = "Windows Defender Antivirus: Real-time protection enabled"
Categoria = "Antivirus"
EstadoActual = if ($defenderStatus -and $defenderStatus.RealTimeProtectionEnabled) { "Habilitado" } else { "Deshabilitado" }
Recomendacion = "Habilitado"
Cumple = if ($defenderStatus -and $defenderStatus.RealTimeProtectionEnabled) { "Sí" } else { "No" }
Criticidad = "Alta"
}
$firewallProfiles = Get-NetFirewallProfile -ErrorAction SilentlyContinue
foreach ($profile in $firewallProfiles) {
$verificaciones += [PSCustomObject]@{
ID = "CIS-9.1.$($profile.Name)"
Descripcion = "Windows Firewall: $($profile.Name) profile enabled"
Categoria = "Firewall"
EstadoActual = if ($profile.Enabled) { "Habilitado" } else { "Deshabilitado" }
Recomendacion = "Habilitado"
Cumple = if ($profile.Enabled) { "Sí" } else { "No" }
Criticidad = "Alta"
}
}
$uacSettings = Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System" -ErrorAction SilentlyContinue
$uacEnabled = $uacSettings.EnableLUA -eq 1
$verificaciones += [PSCustomObject]@{
ID = "CIS-2.3.17.1"
Descripcion = "User Account Control: Admin Approval Mode for Built-in Administrator"
Categoria = "Control de Acceso"
EstadoActual = if ($uacEnabled) { "Habilitado" } else { "Deshabilitado" }
Recomendacion = "Habilitado"
Cumple = if ($uacEnabled) { "Sí" } else { "No" }
Criticidad = "Alta"
}
Write-Host " Verificando configuración de auditoría..." -ForegroundColor Yellow
$auditCategories = @(
@{ Name = "Logon/Logoff"; ID = "CIS-17.1" },
@{ Name = "Account Management"; ID = "CIS-17.2" },
@{ Name = "Privilege Use"; ID = "CIS-17.3" },
@{ Name = "System"; ID = "CIS-17.4" }
)
try {
$auditPol = auditpol /get /category:* 2>$null
foreach ($category in $auditCategories) {
$auditEnabled = $false
if ($auditPol) {
$categorySection = $auditPol | Select-String -Pattern $category.Name -Context 0,10
if ($categorySection -and $categorySection.ToString() -match "(Success and Failure|Success|Failure)") {
$auditEnabled = $true
}
}
$verificaciones += [PSCustomObject]@{
ID = $category.ID
Descripcion = "Audit $($category.Name) events"
Categoria = "Auditoría"
EstadoActual = if ($auditEnabled) { "Configurado" } else { "No configurado" }
Recomendacion = "Success and Failure"
Cumple = if ($auditEnabled) { "Sí" } else { "No" }
Criticidad = "Media"
}
}
} catch {
Write-Host " Error al verificar auditoría: $_" -ForegroundColor Red
}
Write-Host " Verificando configuraciones del registro..." -ForegroundColor Yellow
$smbv1Enabled = $false
try {
$smbv1Feature = Get-WindowsOptionalFeature -Online -FeatureName "SMB1Protocol" -ErrorAction SilentlyContinue
$smbv1Enabled = $smbv1Feature -and $smbv1Feature.State -eq "Enabled"
} catch {
$smbv1Reg = Get-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Services\mrxsmb10" -Name "Start" -ErrorAction SilentlyContinue
$smbv1Enabled = $smbv1Reg -and $smbv1Reg.Start -ne 4
}
$verificaciones += [PSCustomObject]@{
ID = "CIS-18.3.1"
Descripcion = "SMB v1 protocol disabled"
Categoria = "Protocolos de Red"
EstadoActual = if ($smbv1Enabled) { "Habilitado" } else { "Deshabilitado" }
Recomendacion = "Deshabilitado"
Cumple = if (-not $smbv1Enabled) { "Sí" } else { "No" }
Criticidad = "Alta"
}
$rdpEnabled = $false
try {
$rdpSetting = Get-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server" -Name "fDenyTSConnections" -ErrorAction SilentlyContinue
$rdpEnabled = $rdpSetting -and $rdpSetting.fDenyTSConnections -eq 0
} catch {}
$verificaciones += [PSCustomObject]@{
ID = "CIS-18.9.48.3.1"
Descripcion = "Remote Desktop connections security"
Categoria = "Acceso Remoto"
EstadoActual = if ($rdpEnabled) { "Habilitado" } else { "Deshabilitado" }
Recomendacion = "Configurado según necesidad"
Cumple = "Revisar"
Criticidad = "Media"
}
$totalVerificaciones = $verificaciones.Count
$cumpleCompleto = ($verificaciones | Where-Object { $_.Cumple -eq "Sí" }).Count
$noCumple = ($verificaciones | Where-Object { $_.Cumple -eq "No" }).Count
$pendienteRevision = ($verificaciones | Where-Object { $_.Cumple -in @("Pendiente", "Revisar") }).Count
$porcentajeCumplimiento = if ($totalVerificaciones -gt 0) {
[math]::Round(($cumpleCompleto / $totalVerificaciones) * 100, 1)
} else { 0 }
$resumenCumplimiento = @{
TotalVerificaciones = $totalVerificaciones
Cumple = $cumpleCompleto
NoCumple = $noCumple
PendienteRevision = $pendienteRevision
PorcentajeCumplimiento = $porcentajeCumplimiento
NivelCumplimiento = switch ($porcentajeCumplimiento) {
{ $_ -ge 90 } { "Excelente" }
{ $_ -ge 80 } { "Bueno" }
{ $_ -ge 70 } { "Aceptable" }
{ $_ -ge 60 } { "Mejorable" }
default { "Deficiente" }
}
}
return @{
Verificaciones = $verificaciones
ResumenCumplimiento = $resumenCumplimiento
}
} catch {
Write-Warning "Error en verificación de cumplimiento: $_"
return @{ Error = $_.Exception.Message }
}
}
Get-AnalisisPermisos
Propósito: Analiza permisos de carpetas sensibles.
Parámetros: Ninguno
Retorna: Análisis de permisos y carpetas con problemas.
Código relevante:
Cargando código...
try {
Write-Progress -Activity "Analizando permisos de carpetas sensibles" -PercentComplete 70
Write-Host " Analizando permisos de carpetas sensibles..." -ForegroundColor Yellow
$analisisPermisos = @()
$carpetasSensibles = @(
@{ Ruta = "C:\Windows\System32"; Descripcion = "Archivos del sistema Windows" },
@{ Ruta = "C:\Windows\SysWOW64"; Descripcion = "Archivos del sistema Windows (32-bit)" },
@{ Ruta = "C:\Program Files"; Descripcion = "Programas instalados" },
@{ Ruta = "C:\Program Files (x86)"; Descripcion = "Programas instalados (32-bit)" },
@{ Ruta = "C:\Windows\Temp"; Descripcion = "Archivos temporales del sistema" },
@{ Ruta = "C:\ProgramData"; Descripcion = "Datos de aplicaciones" },
@{ Ruta = "C:\Users\Public"; Descripcion = "Carpeta pública de usuarios" },
@{ Ruta = "C:\inetpub"; Descripcion = "Sitios web IIS" }
)
try {
$carpetasCompartidas = Get-SmbShare -ErrorAction SilentlyContinue | Where-Object { $_.Name -ne "IPC$" -and $_.Name -ne "ADMIN$" -and $_.Name -notlike "*$" }
foreach ($share in $carpetasCompartidas) {
$carpetasSensibles += @{ Ruta = $share.Path; Descripcion = "Carpeta compartida: $($share.Name)" }
}
} catch {
Write-Host " No se pudieron obtener carpetas compartidas" -ForegroundColor Yellow
}
foreach ($carpeta in $carpetasSensibles) {
try {
if (Test-Path $carpeta.Ruta) {
Write-Host " Analizando: $($carpeta.Ruta)" -ForegroundColor Yellow
$acl = Get-Acl $carpeta.Ruta -ErrorAction SilentlyContinue
if ($acl) {
$permisosProblematicos = @()
$permisosNormales = @()
foreach ($access in $acl.Access) {
$usuario = $access.IdentityReference.Value
$permisos = $access.FileSystemRights.ToString()
$tipo = $access.AccessControlType.ToString()
$herencia = $access.IsInherited
$esProblematico = $false
$razon = ""
if ($usuario -match "(Everyone|Users|Authenticated Users)" -and $tipo -eq "Allow") {
if ($permisos -match "(FullControl|Modify|Write)" -and $carpeta.Ruta -match "(System32|Program Files|Windows)") {
$esProblematico = $true
$razon = "Permisos excesivos para grupo amplio en carpeta del sistema"
}
}
if ($permisos -match "(Write|Modify|FullControl)" -and $tipo -eq "Allow" -and $carpeta.Ruta -match "(System32|SysWOW64)") {
if ($usuario -notmatch "(SYSTEM|Administrators|TrustedInstaller)") {
$esProblematico = $true
$razon = "Permisos de escritura en carpeta crítica del sistema"
}
}
if ($carpeta.Ruta -match "Temp" -and $permisos -match "FullControl" -and $usuario -match "Everyone") {
$esProblematico = $true
$razon = "Control total para Everyone en carpeta temporal"
}
$permisoObj = [PSCustomObject]@{
Usuario = $usuario
Permisos = $permisos
Tipo = $tipo
Heredado = $herencia
Problematico = $esProblematico
Razon = $razon
}
if ($esProblematico) {
$permisosProblematicos += $permisoObj
} else {
$permisosNormales += $permisoObj
}
}
$analisisPermisos += [PSCustomObject]@{
Ruta = $carpeta.Ruta
Descripcion = $carpeta.Descripcion
Propietario = $acl.Owner
PermisosProblematicos = $permisosProblematicos
PermisosNormales = $permisosNormales
TotalPermisos = $acl.Access.Count
PermisosProblematicosCount = $permisosProblematicos.Count
Estado = if ($permisosProblematicos.Count -eq 0) { "Normal" }
elseif ($permisosProblematicos.Count -le 2) { "Advertencia" }
else { "Crítico" }
}
}
} else {
Write-Host " Carpeta no existe: $($carpeta.Ruta)" -ForegroundColor Gray
}
} catch {
Write-Host " Error al analizar $($carpeta.Ruta): $_" -ForegroundColor Red
$analisisPermisos += [PSCustomObject]@{
Ruta = $carpeta.Ruta
Descripcion = $carpeta.Descripcion
Error = $_.Exception.Message
Estado = "Error"
}
}
}
$totalCarpetas = $analisisPermisos.Count
$carpetasConProblemas = ($analisisPermisos | Where-Object { $_.Estado -in @("Advertencia", "Crítico") }).Count
$carpetasCriticas = ($analisisPermisos | Where-Object { $_.Estado -eq "Crítico" }).Count
$resumenPermisos = @{
TotalCarpetasAnalizadas = $totalCarpetas
CarpetasConProblemas = $carpetasConProblemas
CarpetasCriticas = $carpetasCriticas
CarpetasNormales = $totalCarpetas - $carpetasConProblemas
PorcentajeSeguras = if ($totalCarpetas -gt 0) {
[math]::Round((($totalCarpetas - $carpetasConProblemas) / $totalCarpetas) * 100, 1)
} else { 0 }
NivelSeguridad = switch ($carpetasCriticas) {
0 { if ($carpetasConProblemas -eq 0) { "Excelente" } else { "Bueno" } }
{ $_ -le 2 } { "Aceptable" }
default { "Deficiente" }
}
}
return @{
AnalisisPermisos = $analisisPermisos
ResumenPermisos = $resumenPermisos
}
} catch {
Write-Warning "Error en análisis de permisos: $_"
return @{ Error = $_.Exception.Message }
}
}
Get-AuditoriaSoftware
Propósito: Realiza auditoría de software instalado.
Parámetros: Ninguno
Retorna: Lista de software instalado y problemas detectados.
Código relevante:
Cargando código...
try {
Write-Progress -Activity "Realizando auditoría de software instalado" -PercentComplete 75
Write-Host " Auditando software instalado..." -ForegroundColor Yellow
$softwareInstalado = @()
$softwareProblematico = @()
Write-Host " Obteniendo lista de software instalado..." -ForegroundColor Yellow
$registryPaths = @(
"HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*",
"HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*"
)
foreach ($path in $registryPaths) {
try {
$installedSoftware = Get-ItemProperty $path -ErrorAction SilentlyContinue |
Where-Object { $_.DisplayName -and $_.DisplayName -notmatch "^(KB|Update for)" }
foreach ($software in $installedSoftware) {
$nombre = $software.DisplayName
$version = $software.DisplayVersion
$fabricante = $software.Publisher
$fechaInstalacion = $software.InstallDate
$tamaño = $software.EstimatedSize
$fechaInstalacionFormateada = "No disponible"
if ($fechaInstalacion -and $fechaInstalacion -match "^\d{8}$") {
try {
$fechaInstalacionFormateada = [DateTime]::ParseExact($fechaInstalacion, "yyyyMMdd", $null).ToString("dd/MM/yyyy")
} catch {}
}
$tamañoMB = if ($tamaño) { [math]::Round($tamaño / 1024, 2) } else { 0 }
$softwareInstalado += [PSCustomObject]@{
Nombre = $nombre
Version = $version
Fabricante = $fabricante
FechaInstalacion = $fechaInstalacionFormateada
TamañoMB = $tamañoMB
RegistryPath = $software.PSPath
}
}
} catch {
Write-Host " Error al leer registro: $_" -ForegroundColor Red
}
}
$softwareInstalado = $softwareInstalado | Sort-Object Nombre, Version | Get-Unique -AsString
Write-Host " Se encontraron $($softwareInstalado.Count) programas instalados" -ForegroundColor Yellow
Write-Host " Identificando software problemático..." -ForegroundColor Yellow
$softwareProblemas = @(
@{ Nombre = "Adobe Flash Player"; Razon = "Software descontinuado y vulnerable"; Criticidad = "Alta" },
@{ Nombre = "Java"; VersionMinima = "8.0.300"; Razon = "Versiones antiguas de Java son vulnerables"; Criticidad = "Alta" },
@{ Nombre = "Adobe Reader"; VersionMinima = "2021.0"; Razon = "Versiones antiguas tienen vulnerabilidades"; Criticidad = "Media" },
@{ Nombre = "VLC media player"; VersionMinima = "3.0.16"; Razon = "Versiones antiguas pueden tener vulnerabilidades"; Criticidad = "Baja" },
@{ Nombre = "WinRAR"; VersionMinima = "6.0"; Razon = "Versiones antiguas tienen vulnerabilidades conocidas"; Criticidad = "Media" },
@{ Nombre = "7-Zip"; VersionMinima = "21.0"; Razon = "Versiones antiguas pueden ser vulnerables"; Criticidad = "Baja" },
@{ Nombre = "Google Chrome"; Razon = "Verificar que esté actualizado"; Criticidad = "Media" },
@{ Nombre = "Mozilla Firefox"; Razon = "Verificar que esté actualizado"; Criticidad = "Media" },
@{ Nombre = "Internet Explorer"; Razon = "Navegador descontinuado"; Criticidad = "Alta" }
)
$softwareSinSoporte = @(
"Windows XP", "Windows Vista", "Windows 7", "Office 2010", "Office 2013",
"Adobe Flash", "Internet Explorer", "Silverlight"
)
foreach ($software in $softwareInstalado) {
$problemas = @()
foreach ($problema in $softwareProblemas) {
if ($software.Nombre -like "*$($problema.Nombre)*") {
if ($problema.VersionMinima) {
$versionActual = $software.Version
if ($versionActual) {
try {
$versionActualNum = [Version]$versionActual.Split(' ')[0]
$versionMinimaNum = [Version]$problema.VersionMinima
if ($versionActualNum -lt $versionMinimaNum) {
$problemas += @{
Tipo = "Versión desactualizada"
Descripcion = $problema.Razon
Criticidad = $problema.Criticidad
Recomendacion = "Actualizar a versión $($problema.VersionMinima) o superior"
}
}
} catch {
$problemas += @{
Tipo = "Verificación de versión"
Descripcion = "No se pudo verificar la versión automáticamente"
Criticidad = "Baja"
Recomendacion = "Verificar manualmente la versión"
}
}
}
} else {
$problemas += @{
Tipo = "Software problemático"
Descripcion = $problema.Razon
Criticidad = $problema.Criticidad
Recomendacion = "Considerar desinstalar o reemplazar"
}
}
}
}
foreach ($sinSoporte in $softwareSinSoporte) {
if ($software.Nombre -like "*$sinSoporte*") {
$problemas += @{
Tipo = "Sin soporte"
Descripcion = "Software sin soporte del fabricante"
Criticidad = "Alta"
Recomendacion = "Migrar a versión soportada"
}
}
}
if ($software.FechaInstalacion -ne "No disponible") {
try {
$fechaInstalacion = [DateTime]::ParseExact($software.FechaInstalacion, "dd/MM/yyyy", $null)
$añosAntiguedad = ((Get-Date) - $fechaInstalacion).Days / 365
if ($añosAntiguedad -gt 5) {
$problemas += @{
Tipo = "Software muy antiguo"
Descripcion = "Instalado hace más de 5 años"
Criticidad = "Baja"
Recomendacion = "Verificar si hay actualizaciones disponibles"
}
}
} catch {}
}
if (-not $software.Fabricante -or $software.Fabricante -eq "") {
$problemas += @{
Tipo = "Fabricante desconocido"
Descripcion = "Software sin información del fabricante"
Criticidad = "Media"
Recomendacion = "Verificar la legitimidad del software"
}
}
if ($problemas.Count -gt 0) {
$softwareProblematico += [PSCustomObject]@{
Nombre = $software.Nombre
Version = $software.Version
Fabricante = $software.Fabricante
FechaInstalacion = $software.FechaInstalacion
Problemas = $problemas
CriticidadMaxima = ($problemas | ForEach-Object { $_.Criticidad } | Sort-Object {
switch ($_) { "Alta" { 3 } "Media" { 2 } "Baja" { 1 } default { 0 } }
} -Descending)[0]
}
}
}
Write-Host " Analizando navegadores y plugins..." -ForegroundColor Yellow
$navegadores = $softwareInstalado | Where-Object {
$_.Nombre -match "(Chrome|Firefox|Edge|Internet Explorer|Opera|Safari)"
}
$totalSoftware = $softwareInstalado.Count
$softwareConProblemas = $softwareProblematico.Count
$softwareCritico = ($softwareProblematico | Where-Object { $_.CriticidadMaxima -eq "Alta" }).Count
$softwareMedia = ($softwareProblematico | Where-Object { $_.CriticidadMaxima -eq "Media" }).Count
$softwareBaja = ($softwareProblematico | Where-Object { $_.CriticidadMaxima -eq "Baja" }).Count
$resumenAuditoria = @{
TotalSoftwareInstalado = $totalSoftware
SoftwareConProblemas = $softwareConProblemas
SoftwareCritico = $softwareCritico
SoftwareRiesgoMedio = $softwareMedia
SoftwareRiesgoBajo = $softwareBaja
SoftwareSeguro = $totalSoftware - $softwareConProblemas
PorcentajeSeguro = if ($totalSoftware -gt 0) {
[math]::Round((($totalSoftware - $softwareConProblemas) / $totalSoftware) * 100, 1)
} else { 0 }
NivelRiesgo = switch ($softwareCritico) {
0 { if ($softwareMedia -eq 0) { "Bajo" } else { "Medio" } }
{ $_ -le 2 } { "Medio" }
default { "Alto" }
}
}
return @{
SoftwareInstalado = $softwareInstalado
SoftwareProblematico = $softwareProblematico
Navegadores = $navegadores
ResumenAuditoria = $resumenAuditoria
}
} catch {
Write-Warning "Error en auditoría de software: $_"
return @{ Error = $_.Exception.Message }
}
}
Generate-CompleteHTML
Propósito: Genera informe HTML completo con todos los datos recopilados.
Parámetros: Todos los objetos de datos recopilados por las funciones anteriores.
Retorna: Contenido HTML del informe.
Script completo
Código:
Ejemplo de Uso
Ejecución
.\Health-Check.ps1 -SalidaArchivo "C:\Informes" -DiasLogs 7 -FormatoExportar HTML -AnalisisSeguridad $true
Este comando generará un informe completo que incluye:
- 7 días de logs de eventos
- Verificación de parches faltantes
- Análisis de servicios de terceros
- Auditoría de seguridad completa
- Verificación de cumplimiento con estándares
- Informe en formato HTML
Notas Adicionales
- El script requiere ejecución con privilegios de administrador para acceder a toda la información del sistema.
- Para sistemas con UAC habilitado, ejecutar PowerShell "Como administrador".
- El informe HTML generado incluye gráficos y secciones interactivas para mejor visualización.
- El tiempo de ejecución puede variar dependiendo del sistema y la cantidad de datos a analizar.
Casos de Uso
Monitoreo de Salud del Sistema Regular
- Ejecución programada para generar informes periódicos
- Identificación de problemas de rendimiento (CPU, memoria, disco)
- Detección temprana de fallos hardware
Investigación de Incidentes
- Análisis de logs de eventos para troubleshooting
- Revisión de intentos de acceso no autorizados
- Identificación de procesos maliciosos
Auditoría de Seguridad
- Verificación de cumplimiento con estándares CIS
- Análisis de permisos en carpetas sensibles
- Revisión de configuración de seguridad (firewall, UAC)
Planificación de Capacidad
- Análisis de tendencias de uso de recursos
- Identificación de necesidades de actualización
- Optimización de configuración del sistema
Documentación del Sistema
- Inventario de software instalado
- Configuración de red y servicios
- Especificaciones técnicas del hardware