• Passa al contenuto principale
  • Skip to header right navigation
  • Skip to site footer
Fabbri Enrico

Fabbri Enrico

Appunti, idee, qualsiasi cosa possa servire

  • IT
    • MacOS
    • Windows
    • Synology
    • Networking
    • Ubiquiti
    • Storage
    • Web
    • VMWare
  • Le mie passioni
    • Tesla
    • Apple
    • DJI
    • BMW GS
    • Bambu Lab
    • Xbox
  • Contatti
Finestra di PowerShell con privilegi di amministratore su sfondo blu che mostra l'elenco dei servizi di Windows ottenuto con il comando get-service

Upgrade a Windows 11 che torna indietro: la causa con SetupDiag

Un problema che incontro sempre più spesso con la fine del supporto di Windows 10: l’upgrade a Windows 11 parte, lavora per una quarantina di minuti, si riavvia un paio di volte e poi torna a Windows 10 con il messaggio “Impossibile aggiornare a Windows 11”. Nessun codice, nessuna spiegazione.

I requisiti hardware in questi casi c’entrano poco, perché i controlli iniziali li ha già superati. L’errore arriva nelle fasi successive, e per capirlo serve leggere i log. Qui vi spiego come farlo con SetupDiag e vi racconto un caso reale, risolto su un Dell Vostro in dominio.

Cos’è SetupDiag e come si lancia

SetupDiag è lo strumento ufficiale Microsoft che analizza i log di setup dopo un upgrade fallito e indica la causa e il codice errore. È un’applicazione a riga di comando: se la avviate con doppio clic si apre una finestra che si chiude subito, e sembra che non faccia nulla. Va lanciata da un prompt aperto come amministratore:

cd /d C:\Strumenti\SetupDiag
SetupDiag.exe /Output:C:\SetupDiagResults.log
type C:\SetupDiagResults.log

In PowerShell ricordate il .\ davanti al nome. Serve .NET Framework 4.6 o successivo, che su un Windows 10 aggiornato c’è già.

Se SetupDiag non trova nulla

Lo strumento legge i log in C:\$WINDOWS.~BT e in C:\Windows\Panther. Attenzione: se dopo il rollback avete lanciato Pulizia disco o Storage Sense, la cartella $WINDOWS.~BT potrebbe essere sparita. In quel caso rilanciate l’upgrade, lasciatelo fallire e fate girare SetupDiag prima di ripulire qualsiasi cosa. Potete anche puntarlo a una cartella di log copiata altrove con /LogsPath.

Se vi serve guardare i log a mano, i file utili sono setuperr.log e setupact.log nelle due cartelle sopra, e C:\Windows\Logs\MoSetup\BlueBox.log, che contiene il codice finale anche dopo la pulizia.

Il caso: DuplicateUserProfileFailure (0x4E5)

Su un PC Dell Vostro con UEFI e BIOS aggiornato l’upgrade si fermava sempre allo stesso punto. SetupDiag ha risposto con un errore molto chiaro: DuplicateUserProfileFailure, codice 0x000004E5, in fase Finalize. Il messaggio diceva che due SID diversi risultavano associati allo stesso profilo C:\Users\mario.rossi.

Perché succede

Succede tipicamente sui PC in dominio quando un utente viene eliminato e ricreato in Active Directory con lo stesso nome. Il nuovo account ha un SID diverso, ma sul PC il profilo locale è rimasto agganciato al vecchio. Nel registro ci sono quindi due chiavi, una per ogni SID, che puntano alla stessa cartella. Windows lavora senza problemi, ma il setup di Windows 11 non sa quale scegliere e si ferma, con rollback.

Il suggerimento di SetupDiag è di salvare i dati, eliminare l’account e ricrearlo. Funziona, ma è invasivo: di solito basta ripulire il registro.

Prima di iniziare

  • copiate la cartella del profilo su un disco esterno;
  • l’utente non deve essere connesso;
  • il PC deve raggiungere il domain controller, perché il SID valido si ricava risolvendo il nome utente;
  • il backup del ramo di registro lo fa lo script, ma esportarlo a mano non costa nulla.

Procedura

Le chiavi si trovano in HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList. Cercate le due chiavi il cui ProfileImagePath punta allo stesso profilo. Potete verificarlo anche da PowerShell:

Get-CimInstance Win32_UserProfile | Where-Object LocalPath -like '*mario.rossi*' | Select SID, LocalPath, Loaded

Il SID valido è quello attuale dell’utente in AD: lo vedete con whoami /user dalla sessione dell’utente, oppure con Get-ADUser mario.rossi | Select SID. L’altro è l’orfano e la sua chiave va rimossa, insieme all’eventuale chiave con suffisso .bak.

Per non farlo a mano ho preparato uno script. Di default non modifica nulla e mostra solo cosa farebbe. Con -Apply esporta prima un backup .reg in C:\ProfileFix-Backup, poi elimina solo le chiavi dei SID orfani. La cartella in C:\Users non viene toccata. Se non riesce a stabilire il SID valido, si ferma e chiede -KeepSid.

<#
.SYNOPSIS
  Risolve l'errore di upgrade Windows 11 "DuplicateUserProfileFailure" (0x4E5):
  piu' SID associati allo stesso profilo C:\Users\<utente>.

.DESCRIPTION
  1. Cerca in HKLM\...\ProfileList i profili con lo stesso ProfileImagePath ma SID diversi.
  2. Determina il SID valido risolvendo il nome utente (dominio/locale) oppure da -KeepSid.
  3. Esporta un backup .reg di ProfileList.
  4. Con -Apply rimuove le chiavi dei SID orfani (la cartella C:\Users NON viene toccata).

  Senza -Apply fa solo analisi (dry-run).

.EXAMPLE
  .\Fix-DuplicateProfile.ps1                       # solo analisi
  .\Fix-DuplicateProfile.ps1 -Apply                # applica la correzione
  .\Fix-DuplicateProfile.ps1 -Apply -KeepSid S-1-5-21-...-1105   # forza il SID da tenere
#>
[CmdletBinding()]
param(
    [switch]$Apply,
    [string]$KeepSid,
    [string]$BackupDir = 'C:\ProfileFix-Backup'
)

$ErrorActionPreference = 'Stop'

# --- Verifica privilegi amministratore ---
$id = [Security.Principal.WindowsIdentity]::GetCurrent()
if (-not (New-Object Security.Principal.WindowsPrincipal($id)).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
    Write-Error "Eseguire da PowerShell come Amministratore."
}

$plPath = 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList'
$plReg  = 'HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList'

# --- Leggi tutti i profili ---
$profiles = foreach ($k in Get-ChildItem $plPath) {
    $p = Get-ItemProperty $k.PSPath
    if (-not $p.ProfileImagePath) { continue }
    $sidClean = $k.PSChildName -replace '\.bak$', ''
    [pscustomobject]@{
        KeyName = $k.PSChildName
        Sid     = $sidClean
        IsBak   = ($k.PSChildName -like '*.bak')
        Path    = $p.ProfileImagePath
        Loaded  = (Test-Path "Registry::HKEY_USERS\$sidClean")
    }
}

# Considera solo SID di dominio/utente (S-1-5-21-...), ignora account di sistema
$profiles = $profiles | Where-Object { $_.Sid -like 'S-1-5-21-*' }

$dups = $profiles | Group-Object { $_.Path.ToLower() } | Where-Object {
    ($_.Group | Select-Object -ExpandProperty Sid -Unique).Count -gt 1
}

if (-not $dups) {
    Write-Host "Nessun profilo duplicato trovato in ProfileList." -ForegroundColor Green
    Write-Host "Se l'upgrade fallisce ancora, controlla anche cartelle tipo C:\Users\<utente>.<DOMINIO> o .000"
    return
}

# --- Backup del ramo ProfileList ---
if (-not (Test-Path $BackupDir)) { New-Item -ItemType Directory -Path $BackupDir | Out-Null }
$stamp   = Get-Date -Format 'yyyyMMdd-HHmmss'
$regFile = Join-Path $BackupDir "ProfileList-$stamp.reg"
& reg.exe export $plReg $regFile /y | Out-Null
Write-Host "Backup registro: $regFile" -ForegroundColor Cyan

# --- Analisi ---
$toRemove = @()
foreach ($g in $dups) {
    $path = $g.Group[0].Path
    $user = Split-Path $path -Leaf
    Write-Host "`nProfilo duplicato: $path" -ForegroundColor Yellow
    $g.Group | Format-Table KeyName, Sid, Loaded -AutoSize | Out-String | Write-Host

    # Determina il SID valido
    $valid = $null
    if ($KeepSid) {
        $valid = $KeepSid
    } else {
        $candidates = @($user, "$env:USERDOMAIN\$user")
        # Se il nome cartella ha suffisso .DOMINIO (es. user.AD) prova anche senza
        if ($user -match '^(.+)\.[^.]+$') { $candidates += $Matches[1] }
        foreach ($c in $candidates) {
            try {
                $sid = (New-Object Security.Principal.NTAccount($c)).Translate([Security.Principal.SecurityIdentifier]).Value
                if ($g.Group.Sid -contains $sid) { $valid = $sid; Write-Host "SID valido risolto da '$c': $sid" -ForegroundColor Green; break }
            } catch { }
        }
    }

    if (-not $valid) {
        Write-Warning "Impossibile determinare il SID valido per $user (DC raggiungibile? utente esistente?)."
        Write-Warning "Rilancia con -KeepSid <SID> dopo aver verificato con 'whoami /user' o Get-ADUser."
        continue
    }
    if ($g.Group.Sid -notcontains $valid) {
        Write-Warning "Il SID $valid non e' tra quelli del profilo: salto per sicurezza."
        continue
    }

    foreach ($e in $g.Group | Where-Object { $_.Sid -ne $valid }) {
        if ($e.Loaded) {
            Write-Warning "Il profilo $($e.Sid) risulta caricato (utente connesso?): salto. Disconnetti/riavvia e riprova."
            continue
        }
        Write-Host "Da rimuovere (orfano): $($e.KeyName)" -ForegroundColor Red
        $toRemove += $e
    }
}

# --- Applicazione ---
if (-not $toRemove) {
    Write-Host "`nNiente da rimuovere." -ForegroundColor Green
    return
}

if (-not $Apply) {
    Write-Host "`nDRY-RUN: nessuna modifica effettuata. Rilancia con -Apply per rimuovere le chiavi elencate." -ForegroundColor Cyan
    return
}

foreach ($e in $toRemove) {
    Remove-Item -Path (Join-Path $plPath $e.KeyName) -Recurse -Force
    Write-Host "Rimossa chiave: $($e.KeyName)" -ForegroundColor Green
}

Write-Host "`nFatto. Ripristino possibile con: reg import `"$regFile`"" -ForegroundColor Cyan
Write-Host "Prossimi passi: riavvia, fai login con l'utente per verificare il profilo, disinstalla l'antivirus di terze parti e rilancia l'upgrade."

Lanciatelo da PowerShell come amministratore. Prima l’analisi, e solo se propone di rimuovere un solo SID, dopo, con -Apply. Per tornare indietro basta un reg import del file di backup.

Prima di rilanciare l’upgrade

Riavviate e fate un login con l’utente, per verificare che il profilo si carichi correttamente. Poi disinstallate l’antivirus di terze parti: non basta disattivarlo. Nel mio caso era Kaspersky, e con gli ultimi aggiornamenti di Windows 11 è una causa frequente di errori; si reinstalla a upgrade finito. Se la versione di partenza non è l’ultima, vale la pena leggere anche come passare a 25H2.

Nel caso descritto, dopo la pulizia del registro l’upgrade a Windows 11 è andato a buon fine.

Se invece il problema è un profilo che Windows carica come temporaneo, la storia è diversa e la trovate in questo articolo.

Se l’errore è un altro

SetupDiag copre molti casi, ma i codici più frequenti sono questi:

  • 0xC1900101 con suffissi come 0x20017, 0x30018, 0x4000D: quasi sempre driver (storage, rete, grafica) o antivirus;
  • 0x800707E7-0x3000D: file o driver corrotti nella fase di migrazione; provate DISM /Online /Cleanup-Image /RestoreHealth e sfc /scannow;
  • 0x80070070 o 0xC190020E: spazio insufficiente, anche sulla partizione EFI;
  • 0xC1900208: applicazione incompatibile rilevata.

Vi è capitato un upgrade che torna indietro senza spiegazioni? Raccontate nei commenti codice errore e causa: possono essere utili ad altri.

Enrico Fabbri

Enrico Fabbri, classe 1989, appassionato da sempre da tutto ciò che circonda il mondo della tecnologia.
Se una cosa funziona, sento la necessità di scoprire come e perché.

Post precedente:Illustrazione ufficiale di GTA 6 con Jason e Lucia sotto le palme di Vice City, un elicottero e una moto da corsa ai latiGTA 6 esce il 19 novembre: data, prezzi e come prepararsi

Interazioni del lettore

Lascia un commento Annulla risposta

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *

Questo sito utilizza Akismet per ridurre lo spam. Scopri come vengono elaborati i dati derivati dai commenti.