@echo off
setlocal EnableExtensions
chcp 65001 >nul
title Inventario TI - Camiones Chinos Peru

:: Solicitar permisos de administrador para obtener el inventario completo.
fltmc >nul 2>&1
if not "%errorlevel%"=="0" (
    echo Solicitando permisos de administrador...
    powershell.exe -NoProfile -ExecutionPolicy Bypass -Command "Start-Process -FilePath '%~f0' -Verb RunAs"
    exit /b
)

cls
echo ============================================================
echo  SOPORTE TI - CAMIONES CHINOS PERU
echo  Inventario automatico de equipos v1.5.4
echo ============================================================
echo.

set "WORK=%TEMP%\HelpdeskCCP_Inventario"
set "PS1=%WORK%\InventarioTI.ps1"
set "HCCP_SELF=%~f0"
set "HCCP_PS1=%PS1%"
if not exist "%WORK%" mkdir "%WORK%" >nul 2>&1

echo [1/2] Preparando componente integrado...
powershell.exe -NoProfile -ExecutionPolicy Bypass -Command "$ErrorActionPreference='Stop'; try { $lines=[System.IO.File]::ReadAllLines($env:HCCP_SELF,[System.Text.Encoding]::UTF8); $b=[Array]::IndexOf($lines,'###__HCCP_PS1_BEGIN__###'); $e=[Array]::IndexOf($lines,'###__HCCP_PS1_END__###'); if($b -lt 0 -or $e -le $b){throw 'No se encontro el componente integrado.'}; $payload=$lines[($b+1)..($e-1)]; [System.IO.File]::WriteAllLines($env:HCCP_PS1,$payload,(New-Object System.Text.UTF8Encoding($true))); exit 0 } catch { Write-Host $_.Exception.Message -ForegroundColor Red; exit 1 }"
if errorlevel 1 (
    echo.
    echo ERROR: No se pudo preparar el componente integrado.
    pause
    exit /b 1
)

if not exist "%PS1%" (
    echo ERROR: El componente integrado no pudo ser creado.
    pause
    exit /b 1
)

echo [2/2] Iniciando inventario...
echo.
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "%PS1%"
set "RC=%errorlevel%"

if not "%RC%"=="0" (
    echo.
    echo ERROR: El inventario termino con codigo %RC%.
    pause
)

endlocal & exit /b %RC%

###__HCCP_PS1_BEGIN__###
[CmdletBinding()]
param(
    [string]$NombrePersonal = '',
    [string]$Area = '',
    [string]$Cargo = '',
    [string]$Sede = '',
    [string]$Correo = '',
    [string]$TieneCelularCorporativo = '',
    [string]$CelularCorporativo = '',
    [string]$MarcaCelular = '',
    [string]$ModeloCelular = '',
    [string]$Empresa = ''
)

$ErrorActionPreference = 'SilentlyContinue'
$ProgressPreference = 'SilentlyContinue'
$UploadUrl = 'https://www.helpdeskccp.com/api/inventario'

function Texto($Valor) {
    if ($null -eq $Valor) { return '' }
    return ([string]$Valor).Trim()
}

function Normalizar-SiNo([string]$Valor) {
    $v = (Texto $Valor).ToUpperInvariant()
    $v = $v.Replace('Í','I')
    if ($v -in @('SI','S')) { return 'SI' }
    if ($v -in @('NO','N')) { return 'NO' }
    return ''
}

function Preguntar-SiNo([string]$Pregunta) {
    while ($true) {
        $r = Normalizar-SiNo (Read-Host "$Pregunta (SI/NO)")
        if ($r -in @('SI','NO')) { return $r }
        Write-Host 'Respuesta no valida. Escriba SI o NO.' -ForegroundColor Yellow
    }
}

function GB($Bytes) {
    try {
        if ($null -eq $Bytes -or [double]$Bytes -lt 0) { return '' }
        return [math]::Round(([double]$Bytes / 1GB), 2)
    } catch { return '' }
}

function Porcentaje($Parte, $Total) {
    try {
        if ([double]$Total -le 0) { return '' }
        return [math]::Round((([double]$Parte / [double]$Total) * 100), 1)
    } catch { return '' }
}

function FechaTexto($Valor) {
    try {
        if ($null -eq $Valor) { return '' }
        return ([datetime]$Valor).ToString('yyyy-MM-dd')
    } catch { return '' }
}

function Limpiar-NombreArchivo([string]$TextoEntrada) {
    $s = Texto $TextoEntrada
    foreach ($c in [IO.Path]::GetInvalidFileNameChars()) { $s = $s.Replace([string]$c, '_') }
    $s = ($s -replace '\s+', '_')
    if ($s.Length -gt 70) { $s = $s.Substring(0,70) }
    if (-not $s) { $s = 'SIN_NOMBRE' }
    return $s
}


function Normalizar-ID([string]$Valor) {
    $s = (Texto $Valor).ToUpperInvariant()
    $s = $s -replace '[^A-Z0-9]', ''
    return $s
}

function Analizar-Identificador([string]$Valor, [string]$Tipo='SERIE') {
    $original = Texto $Valor
    if (-not $original) {
        return [pscustomobject]@{ Valido=$false; Estado='VACIO'; Motivo='Sin valor'; Normalizado='' }
    }
    $n = Normalizar-ID $original
    if (-not $n) {
        return [pscustomobject]@{ Valido=$false; Estado='VACIO'; Motivo='Sin caracteres utiles'; Normalizado='' }
    }

    if ($Tipo.ToUpperInvariant() -eq 'UUID') {
        try {
            $g = [guid]$original
            $ng = $g.ToString('N').ToUpperInvariant()
            if ($ng -eq ('0' * 32) -or $ng -eq ('F' * 32)) {
                return [pscustomobject]@{ Valido=$false; Estado='GENERICO'; Motivo='UUID vacio/generico'; Normalizado=$ng }
            }
            return [pscustomobject]@{ Valido=$true; Estado='OK'; Motivo=''; Normalizado=$g.ToString().ToUpperInvariant() }
        } catch {
            return [pscustomobject]@{ Valido=$false; Estado='INVALIDO'; Motivo='UUID no valido'; Normalizado=$n }
        }
    }

    $genericos = @(
        'TOBEFILLEDBYOEM','TOBEFILLEDBYOEM','DEFAULTSTRING','DEFAULT','SYSTEMSERIALNUMBER',
        'SERIALNUMBER','NONE','NA','NOTAPPLICABLE','NOTSPECIFIED','UNKNOWN','OEM','INVALID',
        'UNDEFINED','NOASSETTAG','ASSETTAG','CHASSISSERIALNUMBER','MOTHERBOARDSERIALNUMBER',
        'MANUFACTURER','PLACEHOLDER','123456789','0123456789','1234567890'
    )
    if ($genericos -contains $n) {
        return [pscustomobject]@{ Valido=$false; Estado='GENERICO'; Motivo='Valor generico del fabricante'; Normalizado=$n }
    }
    if ($n.Length -lt 4) {
        return [pscustomobject]@{ Valido=$false; Estado='SOSPECHOSO'; Motivo='Identificador demasiado corto'; Normalizado=$n }
    }
    if ($n -match '^0+$' -or $n -match '^F+$' -or $n -match '^X+$' -or $n -match '^1+$' -or $n -match '^([A-Z0-9])\1{5,}$') {
        return [pscustomobject]@{ Valido=$false; Estado='GENERICO'; Motivo='Patron repetitivo/generico'; Normalizado=$n }
    }
    return [pscustomobject]@{ Valido=$true; Estado='OK'; Motivo=''; Normalizado=$n }
}

function Obtener-SHA256Texto([string]$TextoEntrada) {
    try {
        $sha = [Security.Cryptography.SHA256]::Create()
        try {
            $bytes = [Text.Encoding]::UTF8.GetBytes($TextoEntrada)
            $hash = $sha.ComputeHash($bytes)
            return ([BitConverter]::ToString($hash)).Replace('-','').ToUpperInvariant()
        } finally { $sha.Dispose() }
    } catch { return '' }
}

function Obtener-TipoEquipo($Computer, $Enclosure) {
    $tiposLaptop = @(8,9,10,11,12,14,18,21,30,31,32)
    $chassis = @($Enclosure.ChassisTypes)
    if ($chassis | Where-Object { $_ -in $tiposLaptop }) { return 'Laptop' }
    if ($Computer.PCSystemType -eq 2) { return 'Laptop' }
    if ($Computer.PCSystemType -eq 1) { return 'Desktop' }
    if ($Computer.PCSystemType -eq 3) { return 'Workstation' }
    return 'Otro'
}

function Obtener-WindowsLicencia {
    $resultado = [ordered]@{ Activado='DESCONOCIDO'; Estado='No se pudo verificar' }
    try {
        $licencias = @(Get-CimInstance SoftwareLicensingProduct -Filter "ApplicationID='55c92734-d682-4d71-983e-d6ec3f16059f' AND PartialProductKey IS NOT NULL" -OperationTimeoutSec 8)
        if ($licencias | Where-Object { $_.LicenseStatus -eq 1 }) {
            $resultado.Activado = 'SI'; $resultado.Estado = 'Licenciado'
        } elseif ($licencias | Where-Object { $_.LicenseStatus -in @(2,6) }) {
            $resultado.Activado = 'EN GRACIA'; $resultado.Estado = 'Periodo de gracia'
        } elseif ($licencias.Count -gt 0) {
            $resultado.Activado = 'NO'; $resultado.Estado = 'No activado'
        }
    } catch { }
    return [pscustomobject]$resultado
}

function Obtener-Office {
    $r = [ordered]@{ Instalado='NO'; Activado='NO APLICA'; Estado='Office no instalado'; Producto='' }
    try {
        $appId = '0ff1ce15-a989-479d-af46-f275c6370663'
        $lics = @(Get-CimInstance SoftwareLicensingProduct -Filter "ApplicationID='$appId' AND PartialProductKey IS NOT NULL" -OperationTimeoutSec 8)
        $reg = Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Office\ClickToRun\Configuration' -ErrorAction SilentlyContinue
        if (-not $reg) { $reg = Get-ItemProperty 'HKLM:\SOFTWARE\WOW6432Node\Microsoft\Office\ClickToRun\Configuration' -ErrorAction SilentlyContinue }
        if ($lics.Count -gt 0 -or $reg) {
            $r.Instalado = 'SI'
            $r.Producto = Texto $(if ($reg.ProductReleaseIds) { $reg.ProductReleaseIds } elseif ($reg.ProductVersion) { $reg.ProductVersion } else { (($lics | Select-Object -ExpandProperty Name -Unique) -join ' | ') })
            if ($lics | Where-Object { $_.LicenseStatus -eq 1 }) {
                $r.Activado='SI'; $r.Estado='Licenciado'
            } elseif ($lics | Where-Object { $_.LicenseStatus -in @(2,6) }) {
                $r.Activado='EN GRACIA'; $r.Estado='Periodo de gracia / activacion pendiente'
            } elseif ($lics.Count -gt 0) {
                $r.Activado='NO'; $r.Estado='No activado'
            } else {
                $r.Activado='DESCONOCIDO'; $r.Estado='Instalado; licencia no determinada'
            }
        }
    } catch { }
    return [pscustomobject]$r
}

function Obtener-Antivirus {
    $nombres = @()
    try {
        $nombres = @(Get-CimInstance -Namespace 'root/SecurityCenter2' -ClassName AntivirusProduct | Select-Object -ExpandProperty displayName -Unique)
    } catch { }
    return (($nombres | Where-Object { $_ } | Sort-Object -Unique) -join ' | ')
}

function Obtener-AnyDesk {
    $instalado = 'NO'; $id = ''
    $rutas = @(
        "$env:ProgramFiles\AnyDesk\AnyDesk.exe",
        "${env:ProgramFiles(x86)}\AnyDesk\AnyDesk.exe",
        "$env:LOCALAPPDATA\Programs\AnyDesk\AnyDesk.exe"
    )
    if ($rutas | Where-Object { Test-Path -LiteralPath $_ }) { $instalado = 'SI' }
    if (Get-Service -Name 'AnyDesk*' -ErrorAction SilentlyContinue | Select-Object -First 1) { $instalado = 'SI' }
    foreach ($f in @("$env:ProgramData\AnyDesk\system.conf", "$env:ProgramData\AnyDesk\service.conf", "$env:APPDATA\AnyDesk\system.conf", "$env:APPDATA\AnyDesk\user.conf")) {
        if ((Test-Path -LiteralPath $f) -and -not $id) {
            $t = Get-Content -LiteralPath $f -Raw -ErrorAction SilentlyContinue
            foreach ($p in @('ad.anynet.id\s*=\s*(\d+)','ad\.client\.id\s*=\s*(\d+)','anynet\.id\s*=\s*(\d+)')) {
                $m = [regex]::Match($t,$p)
                if ($m.Success) { $id=$m.Groups[1].Value; $instalado='SI'; break }
            }
        }
    }
    return [pscustomobject]@{ Instalado=$instalado; ID=$id }
}

function Obtener-Monitores {
    $filas = @()
    try {
        $mons = @(Get-CimInstance -Namespace root\wmi -ClassName WmiMonitorID -ErrorAction SilentlyContinue)
        foreach ($m in $mons) {
            $fabricante = -join ($m.ManufacturerName | Where-Object { $_ -gt 0 } | ForEach-Object { [char]$_ })
            $modelo = -join ($m.UserFriendlyName | Where-Object { $_ -gt 0 } | ForEach-Object { [char]$_ })
            $serie = -join ($m.SerialNumberID | Where-Object { $_ -gt 0 } | ForEach-Object { [char]$_ })
            $texto = (@((Texto $fabricante),(Texto $modelo),(Texto $serie)) | Where-Object { $_ }) -join ' '
            if ($texto) { $filas += $texto }
        }
    } catch { }
    return @($filas | Sort-Object -Unique)
}

function Obtener-PerifericosPnP([string]$Clase) {
    try {
        return @(
            Get-CimInstance Win32_PnPEntity -ErrorAction SilentlyContinue |
            Where-Object { $_.PNPClass -eq $Clase -and $_.Name } |
            Select-Object -ExpandProperty Name -Unique |
            Where-Object { $_ -notmatch '(?i)virtual|remote|rdp' }
        )
    } catch { return @() }
}

function Obtener-RAMModulos {
    $filas = @()
    try {
        $mods = @(Get-CimInstance Win32_PhysicalMemory -ErrorAction SilentlyContinue)
        foreach ($m in $mods) {
            $size = GB $m.Capacity
            $speed = if ($m.ConfiguredClockSpeed) { $m.ConfiguredClockSpeed } else { $m.Speed }
            $part = Texto $m.PartNumber
            $fab = Texto $m.Manufacturer
            $bank = Texto $m.BankLabel
            $filas += [pscustomobject]@{
                Banco=$bank; CapacidadGB=$size; VelocidadMHz=$speed; Fabricante=$fab; Parte=$part
            }
        }
    } catch { }
    return $filas
}

function Es-DiscoInterno($d) {
    $bus = (Texto $d.BusType).ToUpperInvariant()
    $friendly = (Texto $d.FriendlyName).ToUpperInvariant()
    $location = (Texto $d.Location).ToUpperInvariant()
    if ($bus -in @('USB','SD','MMC','FILE BACKED VIRTUAL')) { return $false }
    if (($friendly + ' ' + $location) -match 'USB|REMOVABLE|EXTERNAL|PENDRIVE|FLASH|SD CARD|CARD READER|CARDREADER') { return $false }
    return $true
}

function Obtener-Discos {
    $filas = @()
    try {
        $fisicos = @{}
        try {
            foreach ($p in @(Get-PhysicalDisk -ErrorAction SilentlyContinue)) {
                $key = (Texto $p.FriendlyName).ToLowerInvariant()
                if ($key -and -not $fisicos.ContainsKey($key)) { $fisicos[$key] = $p }
            }
        } catch { }

        $discos = @(Get-Disk -ErrorAction Stop | Where-Object { $_.Size -gt 0 -and $_.IsOffline -eq $false } | Sort-Object Number)
        foreach ($d in $discos) {
            if (-not (Es-DiscoInterno $d)) { continue }
            $particiones = @(Get-Partition -DiskNumber $d.Number -ErrorAction SilentlyContinue | Where-Object { $_.DriveLetter })
            $letras = @(); $libre = 0
            foreach ($p in $particiones) {
                $v = Get-Volume -DriveLetter $p.DriveLetter -ErrorAction SilentlyContinue
                if ($v -and $v.DriveType -eq 'Fixed') {
                    $letras += ($p.DriveLetter + ':')
                    if ($null -ne $v.SizeRemaining) { $libre += [double]$v.SizeRemaining }
                }
            }
            if ($letras.Count -eq 0) { continue }
            $pf = $null
            $key = (Texto $d.FriendlyName).ToLowerInvariant()
            if ($key -and $fisicos.ContainsKey($key)) { $pf = $fisicos[$key] }
            $tipo = Texto $pf.MediaType
            if (-not $tipo -or $tipo -eq 'Unspecified') { $tipo = Texto $d.BusType }
            $tam = GB $d.Size
            $lib = GB $libre
            $pct = if ([double]$d.Size -gt 0) { Porcentaje $libre $d.Size } else { '' }
            $filas += [pscustomobject]@{
                Numero=$d.Number
                Modelo=Texto $d.FriendlyName
                Serial=Texto $d.SerialNumber
                Bus=Texto $d.BusType
                Tipo=$tipo
                Unidades=(($letras | Sort-Object -Unique) -join ', ')
                TotalGB=$tam
                LibreGB=$lib
                LibrePct=$pct
            }
        }
    } catch { }

    if ($filas.Count -eq 0) {
        try {
            $dds = @(Get-CimInstance Win32_DiskDrive -ErrorAction SilentlyContinue | Where-Object {
                $_.Size -gt 0 -and (Texto $_.InterfaceType) -notmatch '(?i)USB|1394' -and (Texto $_.Model) -notmatch '(?i)USB|REMOVABLE|EXTERNAL|FLASH|SD CARD|CARD READER'
            } | Sort-Object Index)
            foreach ($d in $dds) {
                $letras=@(); $libre=0
                foreach ($p in @(Get-CimAssociatedInstance -InputObject $d -Association Win32_DiskDriveToDiskPartition -ErrorAction SilentlyContinue)) {
                    foreach ($l in @(Get-CimAssociatedInstance -InputObject $p -Association Win32_LogicalDiskToPartition -ErrorAction SilentlyContinue | Where-Object { $_.DriveType -eq 3 })) {
                        if ($l.DeviceID) { $letras += $l.DeviceID }
                        if ($l.FreeSpace) { $libre += [double]$l.FreeSpace }
                    }
                }
                if ($letras.Count -eq 0) { continue }
                $filas += [pscustomobject]@{
                    Numero=$d.Index; Modelo=Texto $d.Model; Serial=Texto $d.SerialNumber; Bus=Texto $d.InterfaceType; Tipo=Texto $d.MediaType;
                    Unidades=(($letras | Sort-Object -Unique) -join ', '); TotalGB=(GB $d.Size); LibreGB=(GB $libre); LibrePct=(Porcentaje $libre $d.Size)
                }
            }
        } catch { }
    }
    return $filas
}

function Obtener-Bateria {
    $r = [ordered]@{ Presente='NO'; CargaPct=''; Estado=''; CapacidadDisenoMWh=''; CapacidadActualMWh=''; SaludPct='' }
    try {
        $b = Get-CimInstance Win32_Battery -ErrorAction SilentlyContinue | Select-Object -First 1
        if ($b) {
            $r.Presente='SI'; $r.CargaPct=$b.EstimatedChargeRemaining; $r.Estado=Texto $b.Status
            $design = (Get-CimInstance -Namespace root\wmi -ClassName BatteryStaticData -ErrorAction SilentlyContinue | Select-Object -First 1).DesignedCapacity
            $full = (Get-CimInstance -Namespace root\wmi -ClassName BatteryFullChargedCapacity -ErrorAction SilentlyContinue | Select-Object -First 1).FullChargedCapacity
            if ($design) { $r.CapacidadDisenoMWh=$design }
            if ($full) { $r.CapacidadActualMWh=$full }
            if ($design -and $full) { $r.SaludPct=[math]::Round(([double]$full/[double]$design)*100,1) }
        }
    } catch { }
    return [pscustomobject]$r
}

function Obtener-SoftwareInstalado {
    $items = @()
    $rutas = @(
        'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*',
        'HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*',
        'HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*'
    )
    foreach ($ruta in $rutas) {
        try {
            $items += Get-ItemProperty $ruta -ErrorAction SilentlyContinue | Where-Object { $_.DisplayName } | ForEach-Object {
                [pscustomobject]@{ Nombre=Texto $_.DisplayName; Version=Texto $_.DisplayVersion; Fabricante=Texto $_.Publisher }
            }
        } catch { }
    }
    return @($items | Sort-Object Nombre,Version -Unique)
}

function Obtener-SSID {
    try {
        $salida = netsh wlan show interfaces 2>$null
        foreach ($linea in $salida) {
            if ($linea -match '^\s*SSID\s*:\s*(.+)$' -and $linea -notmatch '^\s*BSSID') { return (Texto $matches[1]) }
        }
    } catch { }
    return ''
}

function Preparar-CarpetaSalida {
    $candidatos = @()
    if ($PSScriptRoot) { $candidatos += (Join-Path $PSScriptRoot 'RESULTADOS') }
    $desktop = [Environment]::GetFolderPath('Desktop')
    if ($desktop) { $candidatos += (Join-Path $desktop 'InventarioTI_Resultados') }
    $candidatos += (Join-Path $env:TEMP 'InventarioTI_Resultados')
    foreach ($ruta in $candidatos) {
        try {
            New-Item -ItemType Directory -Force -Path $ruta | Out-Null
            $prueba = Join-Path $ruta ('.write_test_' + [guid]::NewGuid().ToString('N'))
            'ok' | Set-Content -LiteralPath $prueba -Encoding ASCII
            Remove-Item -LiteralPath $prueba -Force
            return $ruta
        } catch { }
    }
    throw 'No se pudo crear una carpeta de resultados.'
}

Clear-Host
Write-Host '============================================================' -ForegroundColor Cyan
Write-Host ' INVENTARIO TI PORTABLE v1.5.4 - INVENTARIO 2026' -ForegroundColor Cyan
Write-Host ' Captura local de hardware y software' -ForegroundColor Cyan
Write-Host '============================================================' -ForegroundColor Cyan
Write-Host ''

while (-not (Texto $NombrePersonal)) {
    $NombrePersonal = Read-Host 'Nombre y apellido del personal'
}
if (-not (Texto $Area)) { $Area = Read-Host 'Area (opcional, Enter para omitir)' }
if (-not (Texto $Cargo)) { $Cargo = Read-Host 'Cargo (opcional, Enter para omitir)' }
if (-not (Texto $Sede)) { $Sede = Read-Host 'Sede (opcional, Enter para omitir)' }
if (-not (Texto $Correo)) { $Correo = Read-Host 'Correo corporativo (opcional, Enter para omitir)' }

# Celular corporativo:
# - SI: numero, marca y modelo son obligatorios.
# - NO: los tres campos quedan con el valor literal NO.
$estadoCelular = Normalizar-SiNo $TieneCelularCorporativo
if (-not $estadoCelular) {
    $numeroActual = (Texto $CelularCorporativo).ToUpperInvariant()
    if ($numeroActual -eq 'NO') {
        $estadoCelular = 'NO'
    } elseif ((Texto $CelularCorporativo) -or (Texto $MarcaCelular) -or (Texto $ModeloCelular)) {
        $estadoCelular = 'SI'
    }
}
if (-not $estadoCelular) {
    $estadoCelular = Preguntar-SiNo 'Tiene celular corporativo?'
}

if ($estadoCelular -eq 'SI') {
    while (-not (Texto $CelularCorporativo) -or (Texto $CelularCorporativo).ToUpperInvariant() -eq 'NO') {
        $CelularCorporativo = Read-Host 'Numero del celular corporativo'
    }
    while (-not (Texto $MarcaCelular) -or (Texto $MarcaCelular).ToUpperInvariant() -eq 'NO') {
        $MarcaCelular = Read-Host 'Marca del celular corporativo'
    }
    while (-not (Texto $ModeloCelular) -or (Texto $ModeloCelular).ToUpperInvariant() -eq 'NO') {
        $ModeloCelular = Read-Host 'Modelo del celular corporativo'
    }
} else {
    $CelularCorporativo = 'NO'
    $MarcaCelular = 'NO'
    $ModeloCelular = 'NO'
}

if (-not (Texto $Empresa)) {
    $empresaEntrada = Read-Host 'Empresa (Enter = Camiones Chinos Peru S.A.C.)'
    if (Texto $empresaEntrada) { $Empresa = Texto $empresaEntrada } else { $Empresa = 'Camiones Chinos Peru S.A.C.' }
}
Write-Host ''
Write-Host 'Recolectando informacion del equipo...' -ForegroundColor Yellow

$computer = Get-CimInstance Win32_ComputerSystem -ErrorAction SilentlyContinue
$enclosure = Get-CimInstance Win32_SystemEnclosure -ErrorAction SilentlyContinue | Select-Object -First 1
$bios = Get-CimInstance Win32_BIOS -ErrorAction SilentlyContinue
$product = Get-CimInstance Win32_ComputerSystemProduct -ErrorAction SilentlyContinue | Select-Object -First 1
$baseboard = Get-CimInstance Win32_BaseBoard -ErrorAction SilentlyContinue | Select-Object -First 1
$cpu = Get-CimInstance Win32_Processor -ErrorAction SilentlyContinue | Select-Object -First 1
$os = Get-CimInstance Win32_OperatingSystem -ErrorAction SilentlyContinue
$gpus = @(Get-CimInstance Win32_VideoController -ErrorAction SilentlyContinue | Where-Object { $_.Name } | Sort-Object AdapterRAM -Descending -Unique)

$ramTotal = if ($computer.TotalPhysicalMemory) { [double]$computer.TotalPhysicalMemory } elseif ($os.TotalVisibleMemorySize) { [double]$os.TotalVisibleMemorySize * 1KB } else { 0 }
$ramLibre = if ($os.FreePhysicalMemory) { [double]$os.FreePhysicalMemory * 1KB } else { 0 }
$ramUso = [math]::Max(0, $ramTotal - $ramLibre)
$ramModulos = @(Obtener-RAMModulos)
$discos = @(Obtener-Discos)

$totalAlmacenamientoGB = 0.0
$libreAlmacenamientoGB = 0.0
foreach ($d in $discos) {
    if ($d.TotalGB -ne '') { $totalAlmacenamientoGB += [double]$d.TotalGB }
    if ($d.LibreGB -ne '') { $libreAlmacenamientoGB += [double]$d.LibreGB }
}
$totalAlmacenamientoGB = [math]::Round($totalAlmacenamientoGB,2)
$libreAlmacenamientoGB = [math]::Round($libreAlmacenamientoGB,2)
$libreAlmacenamientoPct = if ($totalAlmacenamientoGB -gt 0) { [math]::Round(($libreAlmacenamientoGB / $totalAlmacenamientoGB) * 100,1) } else { '' }

$unidadSistema = $env:SystemDrive
$unidadSistemaTotalGB = ''
$unidadSistemaLibreGB = ''
$unidadSistemaLibrePct = ''
try {
    $letraSistema = $unidadSistema.TrimEnd(':')
    $volSistema = Get-Volume -DriveLetter $letraSistema -ErrorAction Stop
    $unidadSistemaTotalGB = GB $volSistema.Size
    $unidadSistemaLibreGB = GB $volSistema.SizeRemaining
    $unidadSistemaLibrePct = Porcentaje $volSistema.SizeRemaining $volSistema.Size
} catch { }

$ramSlotsTotal = ''
try {
    $ramArray = Get-CimInstance Win32_PhysicalMemoryArray -ErrorAction SilentlyContinue | Select-Object -First 1
    if ($ramArray -and $ramArray.MemoryDevices) { $ramSlotsTotal = $ramArray.MemoryDevices }
} catch { }
$ramSlotsUsados = $ramModulos.Count
$cpuCargaPct = ''
try {
    $cpuLoads = @(Get-CimInstance Win32_Processor -ErrorAction SilentlyContinue | Where-Object { $null -ne $_.LoadPercentage } | Select-Object -ExpandProperty LoadPercentage)
    if ($cpuLoads.Count -gt 0) { $cpuCargaPct = [math]::Round((($cpuLoads | Measure-Object -Average).Average),1) }
} catch { }
$windowsLic = Obtener-WindowsLicencia
$office = Obtener-Office
$antivirus = Obtener-Antivirus
$anydesk = Obtener-AnyDesk
$bateria = Obtener-Bateria
$monitores = @(Obtener-Monitores)
$teclados = @(Obtener-PerifericosPnP 'Keyboard')
$mouse = @(Obtener-PerifericosPnP 'Mouse')
$software = @(Obtener-SoftwareInstalado)

$net = @(Get-CimInstance Win32_NetworkAdapterConfiguration -ErrorAction SilentlyContinue | Where-Object { $_.IPEnabled -eq $true })
$netPreferida = $net | Sort-Object @{Expression={ if ($_.DefaultIPGateway) {0} else {1} }} | Select-Object -First 1
$ip = @($netPreferida.IPAddress | Where-Object { $_ -match '^\d+\.\d+\.\d+\.\d+$' -and $_ -notmatch '^169\.254\.' -and $_ -ne '127.0.0.1' }) | Select-Object -First 1
$mac = Texto $netPreferida.MACAddress
$ssid = Obtener-SSID

# IDENTIFICACION ROBUSTA DEL EQUIPO
# Algunos fabricantes devuelven seriales genericos o repetidos. Se conservan todas
# las fuentes y se genera un ID alternativo para no depender de un unico serial.
$serieBios = Texto $bios.SerialNumber
$serieProducto = Texto $product.IdentifyingNumber
$serieChasis = Texto $enclosure.SerialNumber
$serieElegida = ''
$serieFuente = 'NINGUNA'
$serieProblemas = New-Object System.Collections.Generic.List[string]
foreach ($cand in @(
    [pscustomobject]@{Fuente='BIOS'; Valor=$serieBios},
    [pscustomobject]@{Fuente='PRODUCTO'; Valor=$serieProducto},
    [pscustomobject]@{Fuente='CHASIS'; Valor=$serieChasis}
)) {
    $a = Analizar-Identificador $cand.Valor 'SERIE'
    if ($a.Valido -and -not $serieElegida) {
        $serieElegida = $cand.Valor
        $serieFuente = $cand.Fuente
    } elseif (-not $a.Valido) {
        $serieProblemas.Add("$($cand.Fuente): $($a.Estado)")
    }
}
$serieMostrar = $serieElegida
if (-not $serieMostrar) {
    foreach ($v in @($serieBios,$serieProducto,$serieChasis)) {
        if (Texto $v) { $serieMostrar = $v; break }
    }
}
$serieValida = if ($serieElegida) { 'SI' } else { 'NO' }
$serieProblema = if ($serieElegida) { '' } else { (($serieProblemas | Select-Object -Unique) -join ' | ') }
if (-not $serieProblema -and -not $serieElegida) { $serieProblema = 'No se encontro un numero de serie confiable' }

$uuidEquipo = Texto $product.UUID
$uuidAnalisis = Analizar-Identificador $uuidEquipo 'UUID'
$uuidValido = if ($uuidAnalisis.Valido) { 'SI' } else { 'NO' }

$placaAnalisis = Analizar-Identificador (Texto $baseboard.SerialNumber) 'SERIE'
$discosSerialValidos = @()
foreach ($d in $discos) {
    $da = Analizar-Identificador (Texto $d.Serial) 'SERIE'
    if ($da.Valido) { $discosSerialValidos += $da.Normalizado }
}
$huellaPartes = New-Object System.Collections.Generic.List[string]
$huellaPartes.Add('MARCA=' + (Texto $computer.Manufacturer))
$huellaPartes.Add('MODELO=' + (Texto $computer.Model))
if ($uuidAnalisis.Valido) { $huellaPartes.Add('UUID=' + $uuidAnalisis.Normalizado) }
if ($placaAnalisis.Valido) { $huellaPartes.Add('PLACA=' + $placaAnalisis.Normalizado) }
if ($discosSerialValidos.Count -gt 0) { $huellaPartes.Add('DISCOS=' + (($discosSerialValidos | Sort-Object -Unique) -join ',')) }
if ($mac) { $huellaPartes.Add('MAC=' + (Normalizar-ID $mac)) }
if ($huellaPartes.Count -le 2) {
    $huellaPartes.Add('PC=' + (Texto $(if ($env:COMPUTERNAME) { $env:COMPUTERNAME } else { $computer.Name })))
    $huellaPartes.Add('CPU=' + (Texto $cpu.Name))
}
$huellaHardware = Obtener-SHA256Texto (($huellaPartes | Sort-Object) -join '|')

$idEquipo = ''
$metodoId = ''
$confiabilidadId = ''
if ($serieElegida) {
    $idEquipo = 'SN-' + (Normalizar-ID $serieElegida)
    $metodoId = 'SERIE'
    $confiabilidadId = 'ALTA'
} elseif ($uuidAnalisis.Valido) {
    $idEquipo = 'UUID-' + (($uuidAnalisis.Normalizado) -replace '-','')
    $metodoId = 'UUID'
    $confiabilidadId = 'ALTA'
} elseif ($huellaHardware) {
    $idEquipo = 'HW-' + $huellaHardware.Substring(0,16)
    $metodoId = 'HUELLA HARDWARE'
    $confiabilidadId = 'MEDIA'
}

$displayVersion = '' 
try {
    $cv = Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion' -ErrorAction SilentlyContinue
    $displayVersion = Texto $(if ($cv.DisplayVersion) { $cv.DisplayVersion } else { $cv.ReleaseId })
} catch { }

$bitlocker = 'DESCONOCIDO'
try {
    $bl = Get-BitLockerVolume -MountPoint $env:SystemDrive -ErrorAction Stop
    $bitlocker = Texto $bl.ProtectionStatus
    if ($bitlocker -eq 'On') { $bitlocker = 'ACTIVO' } elseif ($bitlocker -eq 'Off') { $bitlocker = 'INACTIVO' }
} catch { }

$tpm = 'DESCONOCIDO'
try {
    $t = Get-Tpm -ErrorAction Stop
    if ($t.TpmPresent) { $tpm = if ($t.TpmReady) { 'PRESENTE / LISTO' } else { 'PRESENTE / NO LISTO' } } else { $tpm='NO PRESENTE' }
} catch { }

$secureBoot = 'DESCONOCIDO'
try { $secureBoot = if (Confirm-SecureBootUEFI -ErrorAction Stop) { 'ACTIVO' } else { 'INACTIVO' } } catch { }

$lastBoot = $null
try { $lastBoot = [datetime]$os.LastBootUpTime } catch { }
$uptimeDias = ''
if ($lastBoot) { $uptimeDias = [math]::Round(((Get-Date) - $lastBoot).TotalDays, 2) }

$ramDetalle = ($ramModulos | ForEach-Object {
    $x = "$($_.CapacidadGB)GB"
    if ($_.VelocidadMHz) { $x += " @ $($_.VelocidadMHz)MHz" }
    if ($_.Fabricante) { $x += " $($_.Fabricante)" }
    if ($_.Parte) { $x += " [$($_.Parte)]" }
    $x
}) -join ' | '

$gpuDetalle = ($gpus | ForEach-Object {
    $vram = if ($_.AdapterRAM) { GB $_.AdapterRAM } else { '' }
    if ($vram) { "$(Texto $_.Name) ($($vram)GB)" } else { Texto $_.Name }
}) -join ' | '
$gpuPrincipal = $gpus | Select-Object -First 1
$gpuPrincipalVram = if ($gpuPrincipal.AdapterRAM) { GB $gpuPrincipal.AdapterRAM } else { '' }

$row = [ordered]@{
    Fecha=(Get-Date).ToString('dd/MM/yyyy HH:mm')
    Fecha_Inventario=(Get-Date).ToString('yyyy-MM-dd HH:mm:ss')
    Empresa=Texto $Empresa
    Sede=Texto $Sede
    Area=Texto $Area
    Cargo=Texto $Cargo
    Nombre_Apellido=Texto $NombrePersonal
    Correo_Corporativo=Texto $Correo
    Celular_Corporativo=Texto $CelularCorporativo
    Marca_Celular=Texto $MarcaCelular
    Modelo_Celular=Texto $ModeloCelular
    Usuario_Windows=Texto $env:USERNAME
    Nombre_PC=Texto $(if ($env:COMPUTERNAME) { $env:COMPUTERNAME } else { $computer.Name })
    Tipo_Equipo=Obtener-TipoEquipo $computer $enclosure
    Serie=Texto $serieMostrar
    Serie_Valida=$serieValida
    Serie_Fuente=$serieFuente
    Serie_Problema=Texto $serieProblema
    Serie_BIOS=Texto $serieBios
    Serie_Producto=Texto $serieProducto
    Serie_Chasis=Texto $serieChasis
    UUID_Equipo=Texto $uuidEquipo
    UUID_Valido=$uuidValido
    ID_Equipo=Texto $idEquipo
    Metodo_ID=Texto $metodoId
    Confiabilidad_ID=Texto $confiabilidadId
    Huella_Hardware=Texto $huellaHardware
    Marca=Texto $computer.Manufacturer
    Modelo=Texto $computer.Model
    Etiqueta_Activo_Fabricante=Texto $enclosure.SMBIOSAssetTag
    Placa_Madre=Texto $baseboard.Product
    Placa_Madre_Serie=Texto $baseboard.SerialNumber
    BIOS_Version=Texto $bios.SMBIOSBIOSVersion
    Fecha_BIOS=FechaTexto $bios.ReleaseDate
    Procesador=Texto $cpu.Name
    CPU_Nucleos_Fisicos=$cpu.NumberOfCores
    CPU_Procesadores_Logicos=$cpu.NumberOfLogicalProcessors
    CPU_Max_MHz=$cpu.MaxClockSpeed
    CPU_Carga_Pct=$cpuCargaPct
    RAM_GB=GB $ramTotal
    RAM_En_Uso_GB=GB $ramUso
    RAM_Libre_GB=GB $ramLibre
    RAM_Uso_Pct=Porcentaje $ramUso $ramTotal
    RAM_Modulos_Cantidad=$ramModulos.Count
    RAM_Slots_Total=$ramSlotsTotal
    RAM_Slots_Usados=$ramSlotsUsados
    RAM_Modulos_Detalle=$ramDetalle
    GPU=Texto $gpuPrincipal.Name
    GPU_RAM_GB=$gpuPrincipalVram
    GPU_Tipo=''
    GPU_Todas=$gpuDetalle
    Discos_Cantidad=$discos.Count
    Almacenamiento_Total_GB=$totalAlmacenamientoGB
    Almacenamiento_Libre_GB=$libreAlmacenamientoGB
    Almacenamiento_Libre_Pct=$libreAlmacenamientoPct
    Unidad_Sistema=$unidadSistema
    Unidad_Sistema_Total_GB=$unidadSistemaTotalGB
    Unidad_Sistema_Libre_GB=$unidadSistemaLibreGB
    Unidad_Sistema_Libre_Pct=$unidadSistemaLibrePct
    Sistema_Operativo=Texto $os.Caption
    Windows_DisplayVersion=$displayVersion
    Version_Windows=Texto $os.Version
    Windows_Build=Texto $os.BuildNumber
    Arquitectura=Texto $os.OSArchitecture
    Windows_Activado=$windowsLic.Activado
    Windows_Estado_Licencia=$windowsLic.Estado
    Fecha_Instalacion_Windows=FechaTexto $os.InstallDate
    Ultimo_Arranque=$(if ($lastBoot) { $lastBoot.ToString('yyyy-MM-dd HH:mm:ss') } else { '' })
    Uptime_Dias=$uptimeDias
    Office_Instalado=$office.Instalado
    Office_Activado=$office.Activado
    Office_Estado_Licencia=$office.Estado
    Office_Producto=$office.Producto
    Antivirus=$antivirus
    BitLocker_Sistema=$bitlocker
    TPM=$tpm
    Secure_Boot=$secureBoot
    Dominio_o_Grupo=Texto $computer.Domain
    IP=Texto $ip
    MAC_Address=$mac
    Adaptador_Red=Texto $netPreferida.Description
    WiFi_SSID=$ssid
    AnyDesk_Instalado=$anydesk.Instalado
    AnyDesk_ID=$anydesk.ID
    Bateria_Presente=$bateria.Presente
    Bateria_Carga_Pct=$bateria.CargaPct
    Bateria_Estado=$bateria.Estado
    Bateria_Capacidad_Diseno_mWh=$bateria.CapacidadDisenoMWh
    Bateria_Capacidad_Actual_mWh=$bateria.CapacidadActualMWh
    Bateria_Salud_Pct=$bateria.SaludPct
    Monitores_Cantidad=$monitores.Count
    Monitores=(($monitores) -join ' | ')
    Teclados=(($teclados) -join ' | ')
    Mouse=(($mouse) -join ' | ')
    Programas_Instalados_Cantidad=$software.Count
}

for ($i=0; $i -lt 6; $i++) {
    $n=$i+1
    if ($i -lt $discos.Count) {
        $d=$discos[$i]
        $row["Disco_${n}_Modelo"]=$d.Modelo
        $row["Disco_${n}_Serial"]=$d.Serial
        $row["Disco_${n}_Bus"]=$d.Bus
        $row["Disco_${n}_Tipo"]=$d.Tipo
        $row["Disco_${n}_Unidades"]=$d.Unidades
        $row["Disco_${n}_Total_GB"]=$d.TotalGB
        $row["Disco_${n}_Libre_GB"]=$d.LibreGB
        $row["Disco_${n}_Libre_Pct"]=$d.LibrePct
    } else {
        $row["Disco_${n}_Modelo"]=''; $row["Disco_${n}_Serial"]=''; $row["Disco_${n}_Bus"]=''; $row["Disco_${n}_Tipo"]='';
        $row["Disco_${n}_Unidades"]=''; $row["Disco_${n}_Total_GB"]=''; $row["Disco_${n}_Libre_GB"]=''; $row["Disco_${n}_Libre_Pct"]=''
    }
}

$salida = Preparar-CarpetaSalida
$base = 'INV_' + (Limpiar-NombreArchivo $NombrePersonal) + '_' + (Limpiar-NombreArchivo $row.Nombre_PC) + '_' + (Get-Date -Format 'yyyyMMdd_HHmmss')
$csv = Join-Path $salida ($base + '.csv')
$txt = Join-Path $salida ($base + '.txt')

[pscustomobject]$row | Export-Csv -LiteralPath $csv -NoTypeInformation -Delimiter ';' -Encoding UTF8

$lineas = New-Object System.Collections.Generic.List[string]
$lineas.Add('============================================================')
$lineas.Add(' INVENTARIO TI - DETALLE DEL EQUIPO')
$lineas.Add('============================================================')
$lineas.Add("Fecha: $($row.Fecha_Inventario)")
$lineas.Add("Empresa: $($row.Empresa)")
$lineas.Add("Personal: $($row.Nombre_Apellido)")
$lineas.Add("Area: $($row.Area)")
$lineas.Add("Cargo: $($row.Cargo)")
$lineas.Add("Sede: $($row.Sede)")
$lineas.Add("Correo: $($row.Correo_Corporativo)")
$lineas.Add('')
$lineas.Add('--- CELULAR CORPORATIVO ---')
$lineas.Add("Tiene celular corporativo: $(if ((Texto $row.Celular_Corporativo).ToUpperInvariant() -eq 'NO') {'NO'} else {'SI'})")
$lineas.Add("Numero: $($row.Celular_Corporativo)")
$lineas.Add("Marca: $($row.Marca_Celular)")
$lineas.Add("Modelo: $($row.Modelo_Celular)")
$lineas.Add('')
$lineas.Add('--- IDENTIFICACION / CONTROL ---')
$lineas.Add("ID equipo: $($row.ID_Equipo) | Metodo: $($row.Metodo_ID) | Confiabilidad: $($row.Confiabilidad_ID)")
$lineas.Add("Serie usada: $($row.Serie) | Valida: $($row.Serie_Valida) | Fuente: $($row.Serie_Fuente)")
$lineas.Add("Serie BIOS: $($row.Serie_BIOS) | Producto: $($row.Serie_Producto) | Chasis: $($row.Serie_Chasis)")
$lineas.Add("UUID: $($row.UUID_Equipo) | Valido: $($row.UUID_Valido)")
if ($row.Serie_Problema) { $lineas.Add("Revision serial: $($row.Serie_Problema)") }
$lineas.Add('')
$lineas.Add('--- EQUIPO ---')
$lineas.Add("PC: $($row.Nombre_PC)")
$lineas.Add("Usuario Windows: $($row.Usuario_Windows)")
$lineas.Add("Tipo: $($row.Tipo_Equipo)")
$lineas.Add("Marca / Modelo: $($row.Marca) / $($row.Modelo)")
$lineas.Add("Serie: $($row.Serie)")
$lineas.Add("Placa madre: $($row.Placa_Madre) | Serie: $($row.Placa_Madre_Serie)")
$lineas.Add("BIOS: $($row.BIOS_Version) | Fecha: $($row.Fecha_BIOS)")
$lineas.Add('')
$lineas.Add('--- CPU / RAM / GPU ---')
$lineas.Add("CPU: $($row.Procesador)")
$lineas.Add("Nucleos fisicos: $($row.CPU_Nucleos_Fisicos) | Logicos: $($row.CPU_Procesadores_Logicos) | Max MHz: $($row.CPU_Max_MHz) | Carga actual: $($row.CPU_Carga_Pct)%")
$lineas.Add("RAM: $($row.RAM_GB) GB | En uso: $($row.RAM_En_Uso_GB) GB ($($row.RAM_Uso_Pct)%) | Libre: $($row.RAM_Libre_GB) GB")
$lineas.Add("Modulos RAM ($($row.RAM_Modulos_Cantidad)) / Slots: $($row.RAM_Slots_Usados) de $($row.RAM_Slots_Total): $($row.RAM_Modulos_Detalle)")
$lineas.Add("GPU principal: $($row.GPU) | VRAM: $($row.GPU_RAM_GB) GB")
$lineas.Add("GPU detectadas: $($row.GPU_Todas)")
$lineas.Add('')
$lineas.Add("--- DISCOS INTERNOS ($($row.Discos_Cantidad)) ---")
$lineas.Add("Almacenamiento total: $($row.Almacenamiento_Total_GB) GB | Libre: $($row.Almacenamiento_Libre_GB) GB ($($row.Almacenamiento_Libre_Pct)%)")
$lineas.Add("Unidad sistema $($row.Unidad_Sistema): Total $($row.Unidad_Sistema_Total_GB) GB | Libre $($row.Unidad_Sistema_Libre_GB) GB ($($row.Unidad_Sistema_Libre_Pct)%)")
if ($discos.Count -eq 0) { $lineas.Add('No se detectaron discos internos con unidad fija montada.') }
foreach ($d in $discos) {
    $lineas.Add("Disco $($d.Numero): $($d.Modelo) | Serie: $($d.Serial) | Bus: $($d.Bus) | Tipo: $($d.Tipo) | Unidades: $($d.Unidades) | Total: $($d.TotalGB) GB | Libre: $($d.LibreGB) GB ($($d.LibrePct)%)")
}
$lineas.Add('')
$lineas.Add('--- WINDOWS / SEGURIDAD ---')
$lineas.Add("SO: $($row.Sistema_Operativo) | Version: $($row.Windows_DisplayVersion) / $($row.Version_Windows) | Build: $($row.Windows_Build) | $($row.Arquitectura)")
$lineas.Add("Windows activado: $($row.Windows_Activado) | Estado: $($row.Windows_Estado_Licencia)")
$lineas.Add("Instalacion Windows: $($row.Fecha_Instalacion_Windows) | Ultimo arranque: $($row.Ultimo_Arranque) | Uptime: $($row.Uptime_Dias) dias")
$lineas.Add("Antivirus: $($row.Antivirus)")
$lineas.Add("BitLocker: $($row.BitLocker_Sistema) | TPM: $($row.TPM) | Secure Boot: $($row.Secure_Boot)")
$lineas.Add('')
$lineas.Add('--- OFFICE / ACCESO REMOTO ---')
$lineas.Add("Office instalado: $($row.Office_Instalado) | Activado: $($row.Office_Activado) | Producto: $($row.Office_Producto) | Estado: $($row.Office_Estado_Licencia)")
$lineas.Add("AnyDesk instalado: $($row.AnyDesk_Instalado) | ID: $($row.AnyDesk_ID)")
$lineas.Add('')
$lineas.Add('--- RED ---')
$lineas.Add("Dominio/Grupo: $($row.Dominio_o_Grupo)")
$lineas.Add("IP: $($row.IP) | MAC: $($row.MAC_Address)")
$lineas.Add("Adaptador: $($row.Adaptador_Red)")
$lineas.Add("WiFi SSID: $($row.WiFi_SSID)")
$lineas.Add('')
$lineas.Add('--- BATERIA ---')
$lineas.Add("Presente: $($row.Bateria_Presente) | Carga: $($row.Bateria_Carga_Pct)% | Estado: $($row.Bateria_Estado)")
$lineas.Add("Capacidad diseno: $($row.Bateria_Capacidad_Diseno_mWh) mWh | Capacidad actual: $($row.Bateria_Capacidad_Actual_mWh) mWh | Salud: $($row.Bateria_Salud_Pct)%")
$lineas.Add('')
$lineas.Add('--- PERIFERICOS DETECTADOS ---')
$lineas.Add("Monitores ($($row.Monitores_Cantidad)): $($row.Monitores)")
$lineas.Add("Teclados: $($row.Teclados)")
$lineas.Add("Mouse: $($row.Mouse)")
$lineas.Add('')
$lineas.Add("--- SOFTWARE INSTALADO ($($software.Count)) ---")
foreach ($app in $software) {
    $detalle = $app.Nombre
    if ($app.Version) { $detalle += " | v$($app.Version)" }
    if ($app.Fabricante) { $detalle += " | $($app.Fabricante)" }
    $lineas.Add($detalle)
}
$lineas | Set-Content -LiteralPath $txt -Encoding UTF8

# Envio automatico al VPS Helpdesk CCP.
# Si falla la red, los archivos locales se conservan y el inventario no se pierde.
$envioOk = $false
$envioId = ''
$envioError = ''
try {
    Write-Host ''
    Write-Host 'Enviando inventario a Soporte TI...' -ForegroundColor Yellow

    $payload = [ordered]@{
        client_version = '1.5.4'
        hostname       = Texto $row.Nombre_PC
        person         = Texto $row.Nombre_Apellido
        company        = Texto $row.Empresa
        area           = Texto $row.Area
        site           = Texto $row.Sede
        corporate_phone = Texto $row.Celular_Corporativo
        phone_brand     = Texto $row.Marca_Celular
        phone_model     = Texto $row.Modelo_Celular
        phone           = Texto $row.Celular_Corporativo
        collected_at   = Texto $row.Fecha_Inventario
        csv             = [IO.File]::ReadAllText($csv)
        txt             = [IO.File]::ReadAllText($txt)
    }

    $json = $payload | ConvertTo-Json -Depth 5 -Compress
    $body = [Text.Encoding]::UTF8.GetBytes($json)
    $resp = Invoke-RestMethod -Uri $UploadUrl -Method Post -ContentType 'application/json; charset=utf-8' -Body $body -TimeoutSec 45 -Headers @{ 'X-Inventory-Client'='HelpdeskCCP-Inventory/1.5.4' }

    if ($resp -and $resp.status -eq 'ok') {
        $envioOk = $true
        $envioId = Texto $resp.id
    } else {
        $envioError = 'El servidor respondio sin confirmacion de almacenamiento.'
    }
} catch {
    $envioError = Texto $_.Exception.Message
}

Write-Host ''
Write-Host 'CAPTURA COMPLETADA' -ForegroundColor Green
Write-Host "Empresa  : $Empresa" -ForegroundColor Green
Write-Host "Personal : $NombrePersonal" -ForegroundColor Green
Write-Host "Equipo   : $($row.Nombre_PC)" -ForegroundColor Green
Write-Host "CSV      : $csv" -ForegroundColor Cyan
Write-Host "TXT      : $txt" -ForegroundColor Cyan
if ($envioOk) {
    Write-Host "VPS      : ENVIADO CORRECTAMENTE" -ForegroundColor Green
    if ($envioId) { Write-Host "ID VPS   : $envioId" -ForegroundColor Green }
} else {
    Write-Host "VPS      : NO ENVIADO" -ForegroundColor Red
    if ($envioError) { Write-Host "Detalle  : $envioError" -ForegroundColor DarkYellow }
    Write-Host 'Los archivos locales quedaron guardados. Puedes volver a ejecutar el inventario cuando tengas Internet.' -ForegroundColor Yellow
}
Write-Host ''
Write-Host 'El CSV se conserva localmente como respaldo y para consolidacion en Excel.' -ForegroundColor Yellow
Write-Host 'El TXT conserva el detalle completo y la lista de programas instalados.' -ForegroundColor Yellow
Write-Host ''
Read-Host 'Presiona ENTER para cerrar' | Out-Null

###__HCCP_PS1_END__###
