lunes, 18 de agosto de 2025

Copiar Extensiones y Marcadores de Chrome con PowerShell

PowerShell — Exportar solo nombres de programas a TXT

  
  
  # =====================================================================
# Chrome – Inventario completo de extensiones y copia de seguridad
# Perfila todos los usuarios de Windows y todos los canales de Chrome.
# Exporta: JSON + CSV de extensiones por perfil. Copia carpetas de
# extensiones y marcadores (Bookmarks/Bookmarks.bak) de cada perfil.
# =====================================================================

$ErrorActionPreference = 'SilentlyContinue'

# Carpeta de salida
$timestamp  = Get-Date -Format 'yyyyMMdd_HHmmss'
$BackupRoot = Join-Path $env:USERPROFILE "Desktop\Chrome_Backup_$timestamp"
New-Item -ItemType Directory -Path $BackupRoot -Force | Out-Null

# Raíces de perfiles de Windows (robusto: del Registro + usuario actual)
$profileRoots = @()
$profileRoots += (Get-ChildItem 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList' |
    ForEach-Object { (Get-ItemProperty $_.PSPath).ProfileImagePath } |
    Where-Object { $_ -and (Test-Path $_) } | Select-Object -Unique)
$profileRoots += (Split-Path $env:LOCALAPPDATA -Parent)  # usuario que ejecuta
$profileRoots = $profileRoots | Sort-Object -Unique

# Canales de Chrome
$chromeProducts = @('Chrome','Chrome Beta','Chrome Dev','Chrome SxS')

# Auxiliar: aplanar coincidencias de content_scripts
function Get-CSMatches {
    param([object]$Manifest)
    $matches = @()
    if ($Manifest.content_scripts) {
        foreach ($cs in $Manifest.content_scripts) {
            if ($cs.matches) { $matches += $cs.matches }
        }
    }
    return ($matches -join ', ')
}

# Exporta un perfil concreto
function Export-ChromeProfile {
    param(
        [string]$UserDataPath,   # ...\User Data
        [string]$ProfileName,    # Default | Profile 1 | ...
        [string]$UserName,       # nombre de carpeta de usuario Windows
        [string]$Channel         # Chrome | Chrome Beta | ...
    )

    $profilePath = Join-Path $UserDataPath $ProfileName
    if (!(Test-Path $profilePath)) { return }

    $safeTag   = ($UserName + '_' + $Channel + '_' + $ProfileName) -replace '[^\w\-\.]','_'
    $outDir    = Join-Path $BackupRoot $safeTag
    New-Item -ItemType Directory -Path $outDir -Force | Out-Null

    # ---- Inventario de extensiones (JSON + CSV) ----
    $extDir = Join-Path $profilePath 'Extensions'
    $extRows = @()

    if (Test-Path $extDir) {
        foreach ($ext in Get-ChildItem $extDir -Directory) {
            $extId = $ext.Name

            # última versión instalada (ordena por número de versión si es posible)
            $ver = Get-ChildItem $ext.FullName -Directory |
                   Sort-Object { try { [version]$_.Name } catch { $_.Name } } -Descending |
                   Select-Object -First 1

            if ($ver) {
                $manifestPath = Join-Path $ver.FullName 'manifest.json'
                $mf = $null
                if (Test-Path $manifestPath) {
                    try { $mf = Get-Content $manifestPath -Raw | ConvertFrom-Json } catch {}
                }

                $extRows += [PSCustomObject]@{
                    WindowsUser          = $UserName
                    ChromeChannel        = $Channel
                    Profile              = $ProfileName
                    ExtensionId          = $extId
                    Name                 = if ($mf) { $mf.name } else { $null }
                    Description          = if ($mf) { $mf.description } else { $null }
                    Version              = if ($mf) { $mf.version } else { $ver.Name }
                    ManifestVersion      = if ($mf) { $mf.manifest_version } else { $null }
                    Permissions          = if ($mf -and $mf.permissions) { ($mf.permissions -join ', ') } else { $null }
                    HostPermissions      = if ($mf -and $mf.host_permissions) { ($mf.host_permissions -join ', ') } else { $null }
                    ContentScriptsMatch  = if ($mf) { Get-CSMatches -Manifest $mf } else { $null }
                    BackgroundType       = if ($mf -and $mf.background) {
                                                if ($mf.background.service_worker) { 'service_worker' }
                                                elseif ($mf.background.scripts)   { 'scripts' }
                                                else { 'other' }
                                           } else { $null }
                    HomepageURL          = if ($mf) { $mf.homepage_url } else { $null }
                    UpdateURL            = if ($mf) { $mf.update_url } else { $null }
                    Path                 = $ver.FullName
                }
            }
        }

        if ($extRows.Count -gt 0) {
            $extRows | ConvertTo-Json -Depth 6 | Out-File (Join-Path $outDir 'Extensions.json') -Encoding UTF8
            $extRows | Export-Csv (Join-Path $outDir 'Extensions.csv') -NoTypeInformation -Encoding UTF8
        }

        # Copia completa de las carpetas de extensiones
        $destExt = Join-Path $outDir 'Extensions_Files'
        New-Item -ItemType Directory -Path $destExt -Force | Out-Null
        # Robocopy maneja rutas largas y bloqueos mejor que Copy-Item
        $null = robocopy $extDir $destExt /E /R:0 /W:0 /NFL /NDL /NP /NJH /NJS
    }

    # ---- Marcadores ----
    $bm = Join-Path $profilePath 'Bookmarks'
    if (Test-Path $bm)      { Copy-Item $bm (Join-Path $outDir 'Bookmarks.json') -Force }
    $bmBak = Join-Path $profilePath 'Bookmarks.bak'
    if (Test-Path $bmBak)   { Copy-Item $bmBak (Join-Path $outDir 'Bookmarks.bak') -Force }

    # Preferencias del perfil (útil para contexto de extensiones)
    $prefs = Join-Path $profilePath 'Preferences'
    if (Test-Path $prefs)   { Copy-Item $prefs (Join-Path $outDir 'Preferences.json') -Force }
}

# Perfila todos los usuarios y canales
$processed = 0
foreach ($root in $profileRoots) {
    $userName = Split-Path $root -Leaf
    foreach ($product in $chromeProducts) {
        $userData = Join-Path $root "AppData\Local\Google\$product\User Data"
        if (Test-Path $userData) {
            # Perfiles estándar
            $profiles = Get-ChildItem $userData -Directory |
                        Where-Object { $_.Name -match '^(Default|Profile \d+|Guest Profile|System Profile)$' }

            # Si no encuentra nada, intenta perfiles con patrón "Profile *" sin restricción
            if (!$profiles -or $profiles.Count -eq 0) {
                $profiles = Get-ChildItem $userData -Directory |
                            Where-Object { $_.Name -like 'Profile *' -or $_.Name -eq 'Default' }
            }

            foreach ($p in $profiles) {
                Export-ChromeProfile -UserDataPath $userData -ProfileName $p.Name -UserName $userName -Channel $product
                $processed++
            }
        }
    }
}

# Si nada se procesó, deja evidencia explícita
if ($processed -eq 0) {
    "No se encontraron perfiles de Chrome en los usuarios detectados:
$($profileRoots -join [Environment]::NewLine)" |
    Out-File (Join-Path $BackupRoot 'SIN_RESULTADOS.txt') -Encoding UTF8
}

Write-Host "Listo. Carpeta: $BackupRoot"

  
  
  
  

Explicación paso a paso

  1. Cópia el código
  2. Abre PowerShell como administrador.
  3. Pulsa Botón derecho para pegar exactamente el bloque de código de arriba.
  4. Presiona Enter.
  5. El sistema mira dos zonas del registro: programas de 64 bits y de 32 bits.
  6. Toma solo el campo DisplayName (el nombre visible del programa).
  7. Quita los vacíos, ordena alfabéticamente y deja un nombre por línea.
  8. Guarda el resultado en el Escritorio con el nombre Programas_Instalados.txt.
  9. Abre ese archivo para ver la lista.
```

No hay comentarios:

Publicar un comentario

Copiar Extensiones y Marcadores de Chrome con PowerShell

PowerShell — Exportar solo nombres de programas a TXT Copiar # ==========================================...