Visualizzazione post con etichetta Powershell. Mostra tutti i post
Visualizzazione post con etichetta Powershell. Mostra tutti i post

giovedì 24 luglio 2025

MS Outlook: Eliminare le cartelle vuote tramite PowerShell

Le cartelle vuote in Outlook possono accumularsi nel tempo, rendendo più difficile la gestione della posta e occupando spazio inutilmente. Questo articolo illustra come utilizzare uno script PowerShell per identificare ed eliminare in modo efficiente le cartelle di posta vuote, inclusi i feed RSS, mantenendo al sicuro le cartelle predefinite di sistema.

Per scaricare lo script è possibile cliccare sul seguente link


Lo script PowerShell esegue:
  • Analisi Gerarchica
    Scansiona ricorsivamente l'intera struttura delle cartelle di una casella di posta o di un file di dati Outlook.
  • Identificazione delle Cartelle di Posta
    Si concentra solo sulle cartelle che contengono (o potrebbero contenere) messaggi di posta elettronica, ignorando elementi come calendari o contatti.
  • Rilevamento Cartelle Nascoste
    Identifica e ignora le cartelle di sistema nascoste, evitando operazioni indesiderate su componenti interni di Outlook.
  • Report Dettagliato
    Genera un file di testo con l'elenco completo delle cartelle visibili, mostrando il loro percorso completo e il numero di elementi contenuti.
  • Pulizia Intelligente
    Offre la funzionalità (opzionale e controllata) di eliminare automaticamente le cartelle che sono completamente vuote e non contengono sottocartelle.

Come Funziona lo Script

Lo script si basa sull'interazione con il modello a oggetti COM (Component Object Model) di Microsoft Outlook, una potente interfaccia che permette a script e applicazioni esterne di controllare Outlook.

1. Inizializzazione e Connessione a Outlook
try {
    $outlookApp = New-Object -ComObject Outlook.Application
}
catch {
    Write-Error "Errore durante l'avvio dell'applicazione Outlook. Assicurati che Outlook sia installato."
    exit 1 
}
$mapiNamespace = $outlookApp.GetNameSpace("MAPI")

Il primo passo è creare un'istanza dell'applicazione Outlook. Un blocco try-catch garantisce che lo script gestisca elegantemente l'assenza di Outlook o altri problemi di avvio. Successivamente, si ottiene il Namespace("MAPI"), che è la porta d'accesso a tutti gli archivi di dati di Outlook (caselle di posta, file PST/OST, archivi).


2. Selezione dell'Archivio Dati
try {
    Write-Host "Seleziona la cartella da cui desideri iniziare l'analisi (questa sarà la radice della scansione)..."
    $startFolder = $mapiNamespace.PickFolder() # Cattura l'oggetto Folder selezionato
    
    if ($startFolder -eq $null) {
        Write-Error "Nessuna cartella selezionata. Lo script verrà terminato."
                [System.Runtime.InteropServices.Marshal]::ReleaseComObject($mapiNamespace) | Out-Null
        [System.Runtime.InteropServices.Marshal]::ReleaseComObject($outlookApp) | Out-Null
        exit 1
    }
    Write-Host "La scansione inizierà dalla cartella: $($startFolder.FullFolderPath)"
}
catch {
    Write-Error "Errore durante la selezione della cartella. Lo script verrà terminato."
    # Rilascia l'oggetto Outlook prima di uscire per pulire le risorse.
    [System.Runtime.InteropServices.Marshal]::ReleaseComObject($mapiNamespace) | Out-Null
    [System.Runtime.InteropServices.Marshal]::ReleaseComObject($outlookApp) | Out-Null
    exit 1
}

Una caratteristica chiave è la flessibilità: lo script chiede all'utente di selezionare una cartella tramite l'interfaccia di Outlook ($mapiNamespace.PickFolder()). Questo permette di scegliere qualsiasi casella di posta configurata o file di dati (come un PST), rendendo lo script versatile per diversi scenari. Una volta selezionata la cartella questa viene impostata come punto di partenza per la scansione.
Selezione cartella
FIG 1 - Selezione cartella



3. Preparazione dell'Output
$timestamp = Get-Date -Format "yyyy-MM-dd.HH-mm-ss"
$outputDirectory = Join-Path -Path $env:USERPROFILE -ChildPath "Documents"
$outputFileName = "OutlookFolderNames_$timestamp.txt"
$outputPath = Join-Path -Path $outputDirectory -ChildPath $outputFileName

if (-not (Test-Path -Path $outputDirectory -PathType Container)) {
    New-Item -Path $outputDirectory -ItemType Directory | Out-Null
    Write-Host "Creata la directory: $outputDirectory"
}

Per un'analisi tracciabile, lo script genera un file di testo con un timestamp unico nel nome, salvandolo nella cartella "Documenti" dell'utente. Viene anche inclusa una verifica per creare la cartella "Documenti" se non esistente, garantendo che l'operazione di scrittura del file avvenga senza errori.


4. La Funzione Ricorsiva ListAndManageFolders
Il cuore dello script è una funzione ricorsiva che attraversa l'intera gerarchia delle cartelle:

Function ListAndManageFolders {
    param(
        [Parameter(Mandatory=$true)]
        [object]$Folders, # Collezione di oggetti Outlook.Folder
        [string]$Indent = "" # Stringa per l'indentazione gerarchica
    )

    foreach ($folder in $Folders) {
        $propertyAccessor = $null

        try {
            if ($folder -eq $null) {
                Write-Warning "Trovato un oggetto cartella nullo, saltato."
                continue
            }
            if ($folder.DefaultMessageClass -eq "IPM.Note") {
                if ($folder.Folders.Count -gt 0) {
                    ListAndManageFolders -Folders $folder.Folders -Indent ($Indent + "  ")
                }
                $propertyAccessor = $folder.PropertyAccessor
                $isHidden = $false
                try {
                    $isHidden = $propertyAccessor.GetProperty($hiddenFolderPropName)
                }
                catch {
                    Write-Verbose "Impossibile leggere la proprietà nascosta per la cartella $($folder.FullFolderPath). Assunta non nascosta."
                    $isHidden = $false
                }
                if ($isHidden -ne $true) {
                    $outputLine = "$Indent$($folder.FullFolderPath) ($($folder.Items.Count) elementi)"
                    $outputLine | Out-File -FilePath $outputPath -Append -Encoding UTF8
                    Write-Host $outputLine
                    if ($folder.Items.Count -eq 0 -and $folder.Folders.Count -eq 0) {
                        Write-Host "$Indent   [ELIMINAZIONE] Cartella vuota rilevata: $($folder.Name)" -ForegroundColor Yellow
                        try {
                            $folder.Delete()
                            Write-Host "$Indent   [SUCCESSO] Cartella eliminata: $($folder.Name)" -ForegroundColor Green
                        }
                        catch {
                            Write-Error "$Indent   [ERRORE] Impossibile eliminare la cartella $($folder.Name): $($_.Exception.Message)"
                        }
                    }
                }
            }
        }
        catch {
            Write-Error "Errore durante l'elaborazione della cartella '$($folder.FullFolderPath)': $($_.Exception.Message)"
        }
        finally {
            if ($propertyAccessor -ne $null) {
                [System.Runtime.InteropServices.Marshal]::ReleaseComObject($propertyAccessor) | Out-Null
            }
        }
    }
}

- Filtro per Tipo di Cartella: if ($folder.DefaultMessageClass -eq "IPM.Note") assicura che vengano elaborate solo le cartelle destinate ai messaggi di posta (incluse le cartelle RSS), escludendo calendari, contatti, ecc.

- Rilevamento Cartelle Nascoste: Viene utilizzata la proprietà MAPI http://schemas.microsoft.com/mapi/proptag/0x10F4000B (corrispondente a PR_ATTR_HIDDEN) per identificare le cartelle nascoste di sistema. Queste vengono ignorate per evitare modifiche indesiderate.

- Output e Visualizzazione: Per ogni cartella visibile, il suo percorso completo e il conteggio degli elementi vengono scritti sia nel file di output che nella console, con un'indentazione che riflette la gerarchia.

- Logica di Eliminazione:
if ($folder.Items.Count -eq 0 -and $folder.Folders.Count -eq 0) {
    Write-Host "$Indent   [ELIMINAZIONE] Cartella vuota rilevata: $($folder.Name)" -ForegroundColor Yellow
    try {
          $folder.Delete()
          Write-Host "$Indent   [SUCCESSO] Cartella eliminata: $($folder.Name)" -ForegroundColor Green
    }
    catch {
           Write-Error "$Indent   [ERRORE] Impossibile eliminare la cartella $($folder.Name): $($_.Exception.Message)"
    }
}

Questa sezione è cruciale e potenzialmente distruttiva. La cartella viene eliminata solo se è completamente vuota (zero elementi e zero sottocartelle). Viene fornito un feedback visivo e una robusta gestione degli errori per ogni tentativo di eliminazione.

Output
FIG 2 - Output



5. Gestione degli Oggetti COM e Pulizia
[System.Runtime.InteropServices.Marshal]::ReleaseComObject($startFolder) | Out-Null # Rilascia la cartella di partenza
[System.Runtime.InteropServices.Marshal]::ReleaseComObject($mapiNamespace) | Out-Null
[System.Runtime.InteropServices.Marshal]::ReleaseComObject($outlookApp) | Out-Null

Un aspetto critico della programmazione con oggetti COM è la gestione della memoria. A differenza degli oggetti .NET, gli oggetti COM non vengono automaticamente rilasciati dal garbage collector di PowerShell. Non rilasciare questi oggetti può portare a perdite di memoria, blocchi di Outlook o processi "fantasma" in background. Lo script include chiamate esplicite a [System.Runtime.InteropServices.Marshal]::ReleaseComObject() per ogni oggetto COM creato, garantendo una pulizia efficiente delle risorse.


Considerazioni Importanti:

Backup: Prima di eseguire qualsiasi script che comporti l'eliminazione di dati, è fondamentale eseguire un backup completo della casella di posta o del file PST.

Autorizzazioni: Lo script deve essere eseguito con un utente che abbia le autorizzazioni necessarie per interagire con Outlook e per eliminare le cartelle.

Parametro -WhatIf: Per future evoluzioni, si potrebbe considerare di aggiungere un parametro -WhatIf alla funzione di eliminazione, permettendo agli amministratori di simulare l'eliminazione senza effettivamente apportare modifiche.





lunedì 21 luglio 2025

Windows: Individuare quale utente ha installato o rimosso un programma

In ambienti IT complessi e distribuiti, dove molteplici amministratori operano su un'infrastruttura condivisa, la necessità di mantenere una tracciabilità dettagliata delle modifiche al software è cruciale. Ogni modifica al parco software di un'azienda, sia essa un'installazione o una disinstallazione, può avere implicazioni significative. L'introduzione di nuove applicazioni può portare a vulnerabilità di sicurezza se non gestite correttamente, mentre la rimozione non autorizzata di software essenziale può causare interruzioni operative. Identificare rapidamente l'autore di tali azioni non solo facilita l'audit e la conformità normativa, ma permette anche una risposta tempestiva a eventuali problemi di configurazione o di sicurezza.

MsiInstaller e Registo Eventi di Windows

Il sistema operativo Windows, attraverso il suo meccanismo di logging degli eventi, registra in dettaglio le attività svolte. In particolare, quando si installano o disinstallano applicazioni "classiche" basate sul programma di installazione MSI (Microsoft Installer), eventi specifici vengono scritti nel log di sistema. Il provider `MsiInstaller` è il principale responsabile della registrazione di queste operazioni.

Due eventi chiave nel log "Applicazione" sono di particolare interesse:
  • ID Evento 11707: Indica il completamento con successo dell'installazione di un'applicazione MSI.
  • ID Evento 11724: Indica la disinstallazione di un'applicazione MSI.

Analisi Manuale tramite il Visualizzatore Eventi

Per iniziare l'indagine, è possibile utilizzare la console del Visualizzatore eventi di Windows (eventvwr.msc). Una volta aperta, seguire questi passaggi:
  1. Navigare su Registri di Windows->Applicazione.
  2. Nel pannello di destra, selezionare Filtra registro corrente....
  3. Nel campo "ID evento:", inserire '11707, 11724'.
  4. Nel campo "Origini evento:", selezionare 'MsiInstaller'.
  5. Cliccare su OK.
Filtro registro corrente
FIG 1 - Filtro registro corrente


Verrà visualizzato un elenco filtrato di eventi relativi all'installazione e alla rimozione di programmi. Ogni evento contiene una descrizione dettagliata dell'operazione, inclusi il nome del prodotto coinvolto e l'esito. Ad esempio:
Product: Python 3.13.5 Add to Path (64-bit) -- Installation completed successfully.
Prodotto: Adobe Acrobat Reader - Italiano -- Removal completed successfully.

La proprietà "Utente" di ogni evento rivela l'account che ha eseguito l'azione, fornendo immediatamente la necessaria attribuzione.
Registro Eventi Applicazione, Origine MsiInstaller
FIG 2 - Registro Eventi Applicazione, Origine MsiInstaller

Automazione con PowerShell per una Ricerca Rapida

Per ambienti con un elevato volume di eventi o per necessità di automazione, PowerShell offre un metodo più efficiente per interrogare i log degli eventi. Il seguente script PowerShell permette di filtrare rapidamente gli eventi di installazione e disinstallazione per un'applicazione specifica, fornendo il nome utente associato:

Get-WinEvent -FilterHashtable @{LogName="Application"; ID=11707,11724; ProviderName='MsiInstaller'} | Where-Object { $_.Message -like '*NomeApplicazione*' } | Select TimeCreated, @{Name='Username'; Expression={(New-Object System.Security.Principal.SecurityIdentifier($_.userid)).Translate([System.Security.Principal.NTAccount]).Value}}, Message

Sostituire `'*NomeApplicazione*'` con una parte del nome del programma che si desidera tracciare (ad esempio, `'*Python*'`).


Get-WinEvent -FilterHashtable @{...}
Questo cmdlet è utilizzato per recuperare eventi dai log di Windows.

LogName="Application"
Specifica il log degli eventi "Applicazione".

ID=11707,11724
Filtra per gli ID evento di installazione e disinstallazione.

ProviderName='MsiInstaller'
Limita la ricerca agli eventi generati dal provider MsiInstaller.

Where-Object { $_.Message -like '*NomeApplicazione*' }
Filtra ulteriormente gli eventi in base al contenuto del messaggio, cercando il nome dell'applicazione di interesse.

Select TimeCreated, @{Name='Username'; Expression={(New-Object System.Security.Principal.SecurityIdentifier($_.userid)).Translate([System.Security.Principal.NTAccount]).Value}}, Message
Seleziona le proprietà desiderate:
  • TimeCreated: L'ora in cui l'evento è stato generato.
  • Username: Questa è una proprietà calcolata. Il campo 'userid' nell'evento contiene il Security Identifier (SID) dell'utente. Questa espressione PowerShell converte il SID in un nome di account utente leggibile ('NTAccount'), rendendo l'informazione immediatamente utile.
  • Message: Il messaggio completo dell'evento, contenente i dettagli dell'operazione.
PowerShell, Get-WinEvent
FIG 3 - PowerShell, Get-WinEvent


Considerazioni Aggiuntive e Best Practices

  • Log Retention Policy: Assicurarsi che la policy di conservazione dei log degli eventi sia adeguatamente configurata per mantenere i dati per un periodo sufficiente. Una policy troppo restrittiva potrebbe causare la sovrascrittura di informazioni preziose.
  • Gestione Centralizzata dei Log: In ambienti di grandi dimensioni, è consigliabile implementare un sistema centralizzato di gestione dei log (SIEM o un log collector dedicato). Questo non solo facilita la ricerca e l'analisi su più sistemi, ma migliora anche la sicurezza dei log, proteggendoli da manipolazioni locali.
  • Alternative di Installazione: È importante notare che questo metodo è primariamente efficace per installazioni e disinstallazioni che utilizzano l'installer MSI. Software installati tramite altri metodi (ad esempio, XCOPY deployment, Windows Store Apps, o script personalizzati) potrebbero non generare eventi MsiInstaller e richiedere metodi di monitoraggio alternativi.
  • Least Privilege: Implementare sempre il principio del privilegio minimo per gli account utente e di servizio. Questo riduce la superficie di attacco e limita le possibilità di modifiche non autorizzate al software.




venerdì 18 luglio 2025

Windows: Scrivere i log nel Visualizzatore eventi di Windows con PowerShell e CMD

Il Registro Eventi di Windows è uno strumento integrato nel sistema operativo che registra eventi, errori e avvisi relativi a diverse componenti del sistema e alle applicazioni installate. Questi registri sono fondamentali per il monitoraggio del sistema, la diagnostica dei problemi e la sicurezza e sono accessibili attraverso il Visualizzatore Eventi (Event Viewer) anch'esso incluso nel sistema operativo .

Per le nostre applicazioni/script, anziché affidarci esclusivamente a file di log testuali, possiamo sfruttare le potenzialità del registro eventi di Windows.

In questo articolo vedremo come scrivere informazioni nel Registro Eventi utilizzando PowerShell e il Prompt dei Comandi (CMD), due strumenti indispensabili per ogni amministratore di sistema.

1. Scrivere Eventi con PowerShell

Il cmdlet principale per scrivere eventi nel Visualizzatore Eventi è 
Write-EventLog

Per scrivere un evento informativo nel  registro eventi Applicazione si può utilizzare il comando:
Write-EventLog -LogName Application -Source "Application" -EntryType Information -EventID 1 -Message "Messaggio personalizzato"

-LogName:
Specifica il nome del registro eventi di destinazione (es. "Application", "System", "Security").
-Source:
Definisce l'origine dell'evento. Se l'origine non esiste, PowerShell tenterà di crearla, ma è buona pratica crearla esplicitamente prima.
-EntryType:
Indica il tipo di evento. I valori accettati sono: Error, Information, FailureAudit, SuccessAudit, Warning.
-EventID:
Specifica un identificatore numerico per l'evento, utile per la categorizzazione e il filtraggio.
-Message:
Il testo descrittivo dell'evento.
PowerShell, Creare un evento nel Registro Eventi
FIG 1 - PowerShell, Creare un evento nel Registro Eventi

Visualizzatore Eventi
FIG 2 - Visualizzatore Eventi

Creazione e Utilizzo di una Origine Evento Personalizzata
Per una migliore organizzazione e identificazione, è consigliabile creare un'origine evento personalizzata per i propri script. Questo permette di filtrare facilmente gli eventi generati dalle proprie applicazioni.

Per creare una nuova origine evento:
New-EventLog -LogName Application -Source "MioScript"

Questo comando registra "MioScript" come nuova origine nel registro eventi "Applicazione".

Per scrivere un evento con l'origine personalizzata:
Write-EventLog -LogName Application -Source "MioScript" -EntryType Warning –EventID 1 –Message "Messaggio personalizzato"
Creazione e utilizzo di una origine evento personalizzata
FIG 3 - Creazione e utilizzo di una origine evento personalizzata

Dopo aver eseguito questi comandi, aprire il Visualizzatore Eventi (digitando eventvwr.msc nella finestra Esegui o nel Prompt dei Comandi), espandere "Registri di Windows" quindi selezionare il registro "Applicazione" e verificare la presenza del nuovo evento con la descrizione personalizzata.
Visualizzatore eventi, Evento con origine personalizzata
FIG 4 - Visualizzatore eventi, Evento con origine personalizzata


Gestione dei Registri Eventi Personalizzati
Oltre ai Registri Eventi predefiniti, è possibile crearne di personalizzati per raggruppare eventi specifici. Questo è particolarmente utile per applicazioni complesse o per la segregazione dei log.

Il cmdlet New-EventLog consente anche di creare un intero log eventi personalizzato, specificando più origini associate:
New-EventLog -LogName MioRegistroEventi -source 'Origine1','Origine2','Origine3'


Importante: Affinché un nuovo log eventi personalizzato appaia nel Visualizzatore Eventi, è necessario inviargli almeno un evento.

Quando si scrivono eventi in un registro eventi personalizzato, è una buona pratica verificare se il registro esiste già per evitare errori:

If ([System.Diagnostics.EventLog]::SourceExists('MioRegistroEventi') -eq $False) {
 New-EventLog -LogName MioRegistroEventi -source 'Origine1','Origine2','Origine3'
}
Write-EventLog -LogName MioRegistroEventi -Source Origine1 -EntryType Information -EventID 1 -Message "Test"

Un nuovo file .evtx verrà creato nella cartella %SystemRoot%\System32\Winevt\Logs per ogni registro personalizzato.

All'interno del Visualizzatore Eventi il nuovo registro eventi sarà visibile all'interno di "Registri applicazioni e servizi".
Nuovo Registro Eventi
FIG 5 - Nuovo Registro Eventi



2. Scrivere Eventi con CMD

Per gli script batch (.bat/.cmd), lo strumento da utilizzare è eventcreate.exe.

Per aggiungere un evento informativo al registro eventi "Applicazione":
eventcreate /t information /l application /id 1 /d "Messaggio personalizzato"

/t
Specifica il tipo di evento (es. ErrorInformationSuccessWarning).
/l:
Indica il nome del registro eventi di destinazione (es. "Application", "System", "Security").
/id:
L'ID numerico dell'evento.
/d:
La descrizione dell'evento.

EventCreate, Creazione Evento da Prompt dei Comandi
FIG 6 - EventCreate, Creazione Evento da Prompt dei Comandi



3. Query e Filtraggio dei Registri Eventi

Una volta che gli eventi sono stati registrati, il cmdlet Get-WinEvent è lo strumento più potente per cercarli e filtrarli in PowerShell. Questo cmdlet è più moderno e versatile rispetto a Get-EventLog (che opera solo sui log classici).
Get-WinEvent -FilterHashtable @{logname='MioRegistroEventi';id=1}|ft TimeCreated,Id,Message | Select-Object -First 15

Questa query filtra gli eventi nel log "MioRegistroEventi" con EventID pari a 1 e visualizza le prime 15 occorrenze, mostrando la data di creazione, l'ID e il messaggio.
PowerShell, Query registro eventi
FIG 7 - PowerShell, Query registro eventi



4. Considerazioni

Considerazioni su PowerShell Core
Nelle versioni più recenti di PowerShell Core (7.x e successive), il cmdlet Write-EventLog non è supportato nativamente per impostazione predefinita. Tentare di usarlo genererà un errore.

Per usare Write-EventLog in PowerShell Core, è necessario importare il modulo Microsoft.PowerShell.Management con l'opzione -UseWindowsPowerShell:

Import-Module Microsoft.PowerShell.Management -UseWindowsPowerShell

Questo consente a PowerShell Core di accedere ai cmdlet di gestione specifici di Windows PowerShell.


Permessi di Accesso
Per scrivere eventi nel Visualizzatore Eventi utilizzando Write-EventLog o eventcreate.exe, l'account utente che esegue lo script deve essere membro del gruppo Administrators locale. Un utente non amministratore può solo inviare eventi a log eventi personalizzati che sono stati creati da un amministratore.




mercoledì 9 luglio 2025

Windows 11: Errore "L’account Microsoft è già presente"

In ambiente Windows (in particolare Windows 10 e 11), gli utenti del sistema operativo possono essere creati in due distinte modalità: come account locale e come account Microsoft. Entrambe le configurazioni consentono l'accesso al sistema operativo, ma presentano differenze sostanziali in termini di funzionalità disponibili, sincronizzazione dei dati e implicazioni sulla privacy. Prima di affrontare il problema del messaggio "L'account Microsoft è già presente" è opportuno capire la differenza tra i due tipi di account.

Account Locale:
L'account locale rappresenta la modalità classica di un profilo utente in Windows. Questo tipo di account è intrinsecamente legato al singolo dispositivo e non richiede una connessione Internet persistente né una registrazione online. I suoi principali vantaggi risiedono nella sua semplicità d'uso, nella maggiore riservatezza e in un controllo più granulare sui dati dell'utente, che non vengono sincronizzati con i server remoti di Microsoft.
Tuttavia, l'adozione di un account locale comporta delle limitazioni significative nell'accesso alle funzionalità moderne dell'ecosistema Windows. Non è possibile, ad esempio, usufruire della sincronizzazione automatica delle impostazioni tra più dispositivi, accedere ai servizi cloud come OneDrive, utilizzare app dal Microsoft Store o integrare fluidamente il profilo con servizi online quali Outlook e Office. Questo lo rende meno adatto per gli utenti che operano in un ambiente multipiattaforma o che necessitano di un accesso costante ai servizi online di Microsoft.

Account Microsoft: 
Al contrario, l'account Microsoft è un profilo online associato a un indirizzo email, spesso parte del dominio Microsoft (ad esempio, @outlook.com, @hotmail.com, @live.com). L'accesso a Windows tramite un account Microsoft sblocca una vasta gamma di servizi integrati e funzionalità avanzate. Le impostazioni personalizzate, i file, le applicazioni installate, le preferenze del desktop e persino le password possono essere sincronizzate senza soluzione di continuità su più dispositivi. Inoltre, si ottiene accesso diretto ai servizi cloud di Microsoft, al backup automatico, al Microsoft Store e a una migliore integrazione con strumenti di produttività come Teams, OneDrive e la suite Office 365.
D'altro canto, l'utilizzo di un account Microsoft implica una maggiore trasmissione di dati e preferenze a Microsoft, sollevando legittime preoccupazioni in termini di privacy per alcuni utenti che preferiscono mantenere i propri dati il più possibile offline.



Con il rilascio di Windows 11, Microsoft ha introdotto un cambiamento sostanziale nel processo di installazione del sistema operativo. A partire dalla versione 22H2, è stata resa obbligatoria l'associazione a un account Microsoft per completare la configurazione iniziale sia per l'edizione Home che per la Pro, le varianti più diffuse tra utenti privati e professionisti. Durante l'installazione, viene richiesta una connessione Internet e l'autenticazione con un account Microsoft esistente o la creazione di uno nuovo, prima di poter procedere con la configurazione del sistema e l'accesso al desktop.
Questa mossa strategica da parte di Microsoft mira a consolidare ulteriormente l'integrazione dell'ecosistema cloud, ma ha generato critiche da parte di coloro che prediligono la flessibilità e la privacy offerte da un account locale. In precedenza, l'edizione Pro consentiva ancora la creazione di un account locale durante l'installazione, un'opzione ora rimossa se il dispositivo è connesso a Internet. Sebbene esistano metodi non ufficiali per aggirare questo vincolo – come la disconnessione dalla rete durante l'installazione – si tratta di pratiche non garantite e soggette a modifiche in futuri aggiornamenti. Le edizioni Enterprise ed Education, progettate per ambienti aziendali e scolastici, mantengono una maggiore flessibilità nella fase di installazione, inclusa la possibilità di configurare account locali.


Risolvere l'errore "L'Account Microsoft è già presente"
Tra le problematiche più frequenti nella gestione degli account Windows, l'errore "L'account Microsoft è già presente" si distingue per la sua frustrante opacità. Questo messaggio compare tipicamente quando si tenta di associare un account Microsoft a un profilo utente che risulta già in uso sul dispositivo, anche se non appare tra gli account attivi nelle impostazioni. La situazione è spesso paradossale, in quanto può manifestarsi anche dopo operazioni legittime, come il ritorno a un account Microsoft precedentemente disconnesso o la conversione temporanea di un profilo in account locale.

Account già presente
FIG 1 - Account già presente



La causa più probabile di questo comportamento anomalo è la persistenza dell'account Microsoft nel database utenti del sistema operativo, anche dopo che è stato apparentemente rimosso o convertito. In altre parole, l'account continua a esistere nell'archivio del sistema, impedendone una nuova associazione.
Per diagnosticare questa persistenza, è possibile utilizzare la console avanzata per la gestione di utenti e gruppi locali. Accedendo al menu Start e digitando lusrmgr.msc, si aprirà lo strumento dove, nella sezione Utenti, è possibile visualizzare l'elenco completo dei profili riconosciuti dal sistema. Spesso, il vecchio account Microsoft è ancora presente, identificato non tramite indirizzo email ma con un nome utente generico, facilmente confondibile con altri profili locali.
lusrmgr, utenti e gruppi locali
FIG 2 - lusrmgr, utenti e gruppi locali


Per confermare l'identità dell'account "fantasma", è consigliabile utilizzare PowerShell. Aprendo PowerShell dal menu Start e digitando il comando:
Get-LocalUser -Name 'NomeUtente' | Select PrincipalSource

sostituendo 'NomeUtente' con il nome visualizzato in lusrmgr.msc, si otterrà l'origine del profilo. Se il risultato include la dicitura MicrosoftAccount (FIG 3), è confermata la presenza residua dell'account Microsoft nel sistema.
MicrosoftAccount
FIG 3 - MicrosoftAccount

La soluzione a questo problema consiste nella rimozione manuale dell'account residuo dal sistema. Prima di procedere, è fondamentale eseguire un backup completo del sistema per prevenire qualsiasi perdita di dati o configurazioni. Una volta completato il backup, si può tornare alla console Utenti e gruppi locali (lusrmgr.msc), selezionare il profilo corrispondente all'account Microsoft persistente e rimuoverlo tramite il menu contestuale (clic destro sull'elemento e selezionare "Elimina"). È cruciale assicurarsi di cancellare l'account corretto per evitare di compromettere l'accesso al sistema.
lusrmgr, Elimina account
FIG 4 - lusrmgr, Elimina account







mercoledì 25 giugno 2025

Windows: Elencare i programmi installati

Spesso ci si trova nella necessità di sapere con precisione quali software siano installati sul proprio sistema Windows: che sia per manutenzione, migrazione dati o semplice curiosità, avere un elenco completo può rivelarsi estremamente utile. Fortunatamente, Windows mette a disposizione un comando potente e poco conosciuto: WMIC (Windows Management Instrumentation Command-line).

Con un semplice comando da terminale, è possibile ottenere l’elenco di tutti i programmi installati. Per visualizzarli direttamente a schermo, è sufficiente aprire il Prompt dei comandi (cmd) e digitare:
wmic product get name

Il sistema restituirà una lista completa dei software presenti sul computer.

Se invece si desidera esportare l'elenco in un file CSV, utile per archiviarlo, condividerlo o elaborarlo successivamente con Excel o un editor di testo, si può utilizzare il comando:
wmic /output:C:\SWInstallati.csv product get name,version /format:csv

WMIC, Elenco dei software installati
FIG 1 - WMIC, Elenco dei software installati


Per ottenere maggiori informazioni su ciacun software installato utilizzare il comando
wmic /output:C:\SWInstallati.csv product get /format:csv

Questo comando creerà un file chiamato SWInstallati.csv nella directory radice del disco C:, contenente il nome e la versione di ciascun programma installato. Importando il file CSV in un foglio di calcolo come Excel, verranno visualizzati i dettagli di ciascun software installato come mostrato in FIG 2.
File CSV
FIG 2 - File CSV



Visualizzare l'elenco dei programmi installati tramite PowerShell

Va detto che WMIC è uno strumento ormai deprecato nelle versioni più recenti di Windows. In alternativa, è possibile utilizzare PowerShell con questo comando:

Get-ItemProperty HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* | Select-Object DisplayName, DisplayVersion | Format-Table -AutoSize
PowerShell, Elenco dei software installati.png
FIG 3 - PowerShell, Elenco dei software installati.png


Oppure, per esportare l’elenco in un file:

Get-ItemProperty HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* | Select-Object DisplayName, DisplayVersion | Export-Csv C:\SWInstallati.csv -NoTypeInformation

Come visto per WMIC per visualizzare più informazioni per ciascun software è possibile utilizzare il comando
Get-ItemProperty HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* | Export-Csv C:\SWInstallati.csv -NoTypeInformation






mercoledì 10 aprile 2024

Windows Server 2022: Impostare la complessità della password tramite Password Settings Object

All'interno di un dominio è sempre consigliabile stabilire una policy aziendale per forzare l'utilizzo di password complesse al fine di prevenire (o quantomeno rendere difficili) accessi non autorizzati.
Già a partire da Windows Server 2012 è possibile controllare la complessità delle password attraverso l'utilizzo dei criteri granulari per le password (FINE-GRAINED password policy) e la creazione di Password Settings Object (PSO). I requisiti minimi per procedere sono i seguenti:
  • Sia presente almeno un Domain Controller con Windows Server 2012 o superiore;
  • Il livello di funzionalità della foresta sia impostata almeno su Windows Server 2008.
In questi articoli stiamo utilizzando Windows Server 2022 con il livello di funzionalità della foresta di Windows Server 2016 pertanto i requisiti sono ampiamente rispettati. Solo i membri del gruppo Domain Admin possono creare PSO.


Creazione di Password Settings Object (PSO) tramite il Centro di amministrazione di Active Directory

Da Server Manager cliccare sul menu Strumenti e selezionare Centro di amministrazione di Active Directory. In alternativa premere la combinazione di tasti WIN+R, digitare dsac.exe e premere invio.
Server Manager
FIG 1 - Server Manager

Selezionare il proprio dominio (nel nostro caso mycompany.local) quindi aprire il container System con un doppio click.
Centro di amministrazione di Active Directory, container System
FIG 2 - Centro di amministrazione di Active Directory, container System

Cliccare due volte su Password Settings container.
Centro di amministrazione di Active Directory, Password Settings Container
FIG 3 - Centro di amministrazione di Active Directory, Password Settings Container

Sul pannello Attività (sul lato destro della finestra) cliccare su Nuovo quindi Impostazioni password.
Impostazioni password
FIG 4 - Impostazioni password

Nella finestra Crea Impostazioni password ci sono diverse opzioni da settare per la creazione del PSO.
  • All'interno della casella Nome specificare il nome da assegnare all'oggetto. E' consigliabile utilizzare un nome significativo che consenta di capire il suo scopo. Ad es. dovendo creare un PSO per gli amministratori di dominio un nome significativo potrebbe essere PSO_Domain_Admin.
  • All'interno del campo Precedenza inserire il valore 1. Il valore di tale campo ci permette di specificare la precedenza dell'oggetto: nel caso in cui su un account utente o su un gruppo siano definite più PSO, quello con il valore più basso avrà la precedenza.
  • Il campo Lunghezza minima password consente di specificare il numero minimo di caratteri da utilizzare per la password. Impostare tale campo a 12 caratteri.
  • Imponi cronologia delle password. Tale campo, se selezionato, permette di impedire che l'utente riutilizzi una password già utilizzata in precedenza. Il valore di default di tale campo è 24 il che comporta che l'utente può reinserire una password già utilizzata in passato solo dopo 24 cambi password. Lasciare l'opzione attiva con il valore di default.
  • Imponi validità minima password. Permette di specificare dopo quanto tempo dal cambio password l'utente potrà nuovamente modificarla. Il valore di default è 1 quindi quando l'utente cambia la password dovrà aspettare il giorno successivo (24h) per poterla cambiare nuovamente.
  • Imponi validità massima password. Il valore di default è 42. Modificare tale valore in 30. Il campo permette di specificare dopo quanti giorni l'utente è obbligato a cambiare password.
  • Attivare l'opzione Applica criteri di blocco account. Nel campo Numero di tentativi di accesso non riusciti consentiti inserire 5. Nel campo Ripristina conteggio tentativi di accesso non riusciti lasciare il valore 30. Lasciare attiva l'opzione Per un periodo di tempo pari a (minuti) valorizzata a 30. Con tali opzioni, dopo 5 tentativi di accesso non riusciti, l'account verrà bloccato per 30 minuti. Il contatore degli accessi non riusciti verrà resettato dopo 30 accessi riusciti consecutivi.
Cliccare su OK per completare la creazione del PSO con le impostazioni settate.
Creazione PSO
FIG 5 - Creazione PSO


Creazione di Password Settings Object (PSO) tramite PowerShell

Per eseguire la stessa operazione tramite PowerShell è necessario utilizzare il cmdlet New-ADFineGrainedPasswordPolicy.

Sintassi
New-ADFineGrainedPasswordPolicy
   [-WhatIf]
   [-Confirm]
   [-AuthType <ADAuthType>]
   [-ComplexityEnabled <Boolean>]
   [-Credential <PSCredential>]
   [-Description <String>]
   [-DisplayName <String>]
   [-Instance <ADFineGrainedPasswordPolicy>]
   [-LockoutDuration <TimeSpan>]
   [-LockoutObservationWindow <TimeSpan>]
   [-LockoutThreshold <Int32>]
   [-MaxPasswordAge <TimeSpan>]
   [-MinPasswordAge <TimeSpan>]
   [-MinPasswordLength <Int32>]
   [-Name] <String>
   [-OtherAttributes <Hashtable>]
   [-PassThru]
   [-PasswordHistoryCount <Int32>]
   [-Precedence] <Int32>
   [-ProtectedFromAccidentalDeletion <Boolean>]
   [-ReversibleEncryptionEnabled <Boolean>]
   [-Server <String>]
   [<CommonParameters>]
   
Parametri
-AuthType 
Specifica il metodo di autenticazione. I valori accettati dal parametro sono:
  • Negotiate oppure 0 (default)
  • Basic oppure 1

-ComplexityEnabled
Specifica se la complessità della password è abilitata per il criterio della password. Se abilitata, la password deve contenere tre dei seguenti quattro tipi di caratteri:
  • Caratteri maiuscoli (A, B, C, D, E, ...)
  • Caratteri minuscoli (a, b, c, d, e, ...)
  • Numeri (0, 1, 2, 3, ...)
  • Caratteri speciali (#, $, *, %, ...)
I valori accettati per questo parametro sono:
  • $False o 0. Disabilita la complessità della password.
  • $True o 1. Abilita la complessità della password.


-Confirm
Se specificato, tale parametro mostra la richiesta di conferma prima di eseguire il cmdlet.


-Credential
Specifica un'account utente che ha i permessi necessari per eseguire l'operazione. Se omesso viene considerato l'utente corrente che sta eseguendo il comando. Al parametro può essere passato il nome dell'account, come ad es. "utente01" o "Dominio\utente01" oppure può essere passato un'oggetto PSCredential generato dal cmdlet Get-Credential. Se viene specificato un'account utente verrà richiesto di inserire la password all'esecuzione del comando.


-Description
Specifica una descrizione dell'oggetto. Tale parametro imposta il valore della proprietà Description dell'oggetto.


-DisplayName
Specifica il display name dell'oggetto: imposta la proprietà DisplayName dell'oggetto.


-Instance
Specifica un'istanza di un oggetto fine-grained password policy da usare come modello per un nuovo oggetto fine-grained password policy.

È possibile utilizzare un'istanza di un oggetto fine-grained password policy esistente come modello o costruire un nuovo oggetto fine-grained password policy utilizzando la riga di comando di Windows PowerShell o uno script.

Metodo 1: utilizzare un oggetto fine-grained password policy esistente come modello per un nuovo oggetto. Per recuperare un'istanza di un oggetto fine-grained password policy esistente, utilizzare un cmdlet come Get-ADFineGrainedPasswordPolicy. Quindi fornire questo oggetto al parametro Instance del cmdlet New-ADFineGrainedPasswordPolicy. È possibile sovrascrivere i valori delle proprietà del nuovo oggetto impostando i parametri appropriati.

Metodo 2: creare un nuovo oggetto ADFineGrainedPasswordPolicy e impostare i valori delle proprietà utilizzando l'interfaccia della riga di comando di Windows PowerShell. Passare quindi questo oggetto al parametro Instance del cmdlet New-ADFineGrainedPasswordPolicy per creare il nuovo oggetto Active Directory fine-grained password policy.


-LockoutDuration
Specifica il periodo di tempo in cui un account viene bloccato dopo che il numero di tentativi di accesso falliti supera la soglia di blocco. Non è possibile accedere a un account bloccato finché il periodo di tempo di durata del blocco non è scaduto. Se si imposta il valore a 0, l'account deve essere sbloccato manualmente dall'amministratore. Questo parametro imposta la proprietà lockoutDuration di un oggetto criterio password. Il nome di visualizzazione LDAP (ldapDisplayName) di questa proprietà è msDS-LockoutDuration.

La durata del blocco deve essere maggiore o uguale al tempo di osservazione del blocco per un criterio di password. Utilizzare il parametro LockOutObservationWindow per impostare il tempo di osservazione del blocco.

Specificare l'intervallo di tempo della durata del blocco nel formato seguente:
D.H:M:S.F

dove:
D = Giorni (da 0 a 10675199)
H = Ore (da 0 a 23)
M = Minuti  (da 0 a 59)
S = Secondi (da 0 a 59)
F = Frazioni di secondo (da 0 a 9999999)


-LockoutObservationWindow
Specifica l'intervallo di tempo massimo tra due tentativi di accesso non riusciti prima che il numero di tentativi di accesso non riusciti venga riportato a 0. Un account viene bloccato quando il numero di tentativi di accesso non riusciti supera la soglia di blocco del criterio della password. Questo parametro imposta la proprietà lockoutObservationWindow di un oggetto criterio password. Il nome di visualizzazione LDAP (ldapDisplayName) di questa proprietà è msDS-lockoutObservationWindow.

La finestra di osservazione del blocco deve essere minore o uguale alla durata del blocco di un criterio di password. Utilizzare il parametro LockoutDuration per impostare la durata del blocco.

Specificare l'intervallo di tempo nel formato seguente:
D:H:M:S.F

dove:
D = Giorni (da 0 a 10675199)
H = Ore (da 0 a 23)
M = Minuti (da 0 a 59)
S = Secondi (da 0 a 59)
F = Frazioni di secondo (da 0 a 9999999)

Nota: I valori possono essere compresi tra 0:0:0:0.0 e 10675199:02:48:05.4775807.


-LockoutThreshold
Specifica il numero di tentativi di accesso non riusciti consentiti prima che un account venga bloccato. Questo numero aumenta quando l'intervallo tra i tentativi di accesso non riusciti è inferiore al tempo specificato da LockoutObservationWindow. Questo parametro imposta la proprietà LockoutThreshold di un criterio di password.

-MaxPasswordAge
Specifica il periodo di tempo massimo in cui è possibile mantenere la stessa password. Dopo questo periodo di tempo, la password scade e bisogna crearne una nuova.
Questo parametro imposta la proprietà maxPasswordAge di un criterio di password. Il nome di visualizzazione LDAP (ldapDisplayName) per questa proprietà è maxPwdAge.

Specificare l'intervallo di tempo nel formato seguente:
D.H:M:S.F

dove:
D = Giorni (da 0 a 10675199)
H = Ore (da 0 a 23)
M = Minuti (da 0 a 59)
S = Secondi (da 0 a 59)
F = Frazioni di secondo  (da 0 a 9999999)

Nota: I valori di tempo devono essere compresi tra  0 e 10675199:02:48:05.4775807.


-MinPasswordAge
Specifica il periodo di tempo minimo prima di poter modificare una password.
Questo parametro imposta la proprietà minPasswordAge di un criterio di password. Il nome di visualizzazione LDAP (ldapDisplayName) per questa proprietà è minPwdAge.
Specificare l'intervallo di tempo nel seguente formato:
D.H:M:S.F

dove:
D = Giorni (da 0 a 10675199)
H = Ore (da 0 a 23)
M = Minuti (da 0 a 59)
S = Secondi (da 0 a 59)
F = Frazioni di secondo (da 0 a 9999999)

Nota: I valori dell'ora devono essere compresi tra i seguenti 0 e 10675199:02:48:05.


-MinPasswordLength
Specifica il numero minimo di caratteri che una password deve contenere. Questo parametro imposta la proprietà MinPasswordLength del criterio della password.


-Name
Specifica il nome dell'oggetto. Questo parametro imposta la proprietà Name dell'oggetto Active Directory. Il nome di visualizzazione LDAP (ldapDisplayName) di questa proprietà è name.


-OtherAttributes
Specifica i valori degli attributi dell'oggetto per gli attributi non rappresentati dai parametri del cmdlet. Con questo parametro è possibile impostare uno o più parametri contemporaneamente. Se un attributo ha più di un valore, è possibile assegnare più valori. Per identificare un attributo, specificare il nome LDAPDisplayName (ldapDisplayName) definito per esso nello schema di Active Directory.
Sintassi:
Per specificare un singolo valore per un attributo:
OtherAttributes @{'AttributeLDAPDisplayName'=value}
Per specificare più valori per un attributo
OtherAttributes @{'AttributeLDAPDisplayName'=value1,value2,...}
È possibile specificare i valori per più di un attributo usando il punto e virgola per separare gli attributi. La sintassi seguente mostra come impostare i valori di più attributi:
OtherAttributes @{'Attribute1LDAPDisplayName'=value; 'Attribute2LDAPDisplayName'=value1,value2;...}


-PassThru
Restituisce un oggetto che rappresenta l'elemento con cui si sta lavorando. Per impostazione predefinita, questo cmdlet non genera alcun output.


-PasswordHistoryCount
Specifica il numero di password precedenti da salvare. Un utente non può riutilizzare una password nell'elenco delle password salvate. Questo parametro imposta la proprietà PasswordHistoryCount per un criterio di password.


-Precedence
Specifica un valore che definisce la precedenza di un criterio fine-grained password rispetto agli altri criteri. Questo parametro imposta la proprietà Precedence per una fine-grained password policy.Il nome di visualizzazione LDAP (ldapDisplayName) per questa proprietà è msDS-PasswordSettingsPrecedence.

Questo valore determina quale criterio di password utilizzare quando a un utente o a un gruppo si applicano più criteri di password. In caso di conflitto, il criterio di password che ha il valore più basso della proprietà Precedence ha la priorità più alta. Ad esempio, se PasswordPolicy1 ha un valore di Precedenza pari a 200 e PasswordPolicy2 ha un valore di Precedenza pari a 100, viene utilizzato PasswordPolicy2.

In genere, i valori di precedenza dei criteri di password sono assegnati in multipli di 10 o 100, per facilitare l'aggiunta di criteri in un secondo momento. Ad esempio, se si impostano i valori di precedenza iniziali per i criteri a 100 e 200, è possibile aggiungere un altro criterio con valore di precedenza pari a 150.

Se il parametro Precedence specificato è già assegnato a un altro oggetto criterio password, il cmdlet restituisce un errore di terminazione.


-ProtectedFromAccidentalDeletion
Specifica se impedire l'eliminazione dell'oggetto. Quando questa proprietà è impostata su true, non è possibile eliminare l'oggetto corrispondente senza modificare il valore della proprietà. I valori accettabili per questo parametro sono:
  • $False o 0
  • $True o 1


-ReversibleEncryptionEnabled
Specifica se la directory deve memorizzare le password utilizzando la crittografia reversibile. Questo parametro imposta la proprietà ReversibleEncryption per un criterio di password. I valori possibili sono:
  • $False o 0
  • $True o 1


-Server
Specifica l'istanza di Active Directory Domain Services a cui connettersi, fornendo uno dei seguenti valori per un nome di dominio o un server di directory corrispondente. Il servizio può essere uno dei seguenti: Active Directory Lightweight Domain Services, Active Directory Domain Services o Active Directory snapshot instance.


-WhatIf
Mostra cosa accadrebbe se il cmdlet venisse eseguito. Il cmdlet non viene eseguito.


Avviare Windows PowerShell (amministratore) ed eseguire il seguente comando per creare e impostare il Password Settings Object (PSO) allo stesso modo di come fatto tramite GUI
New-ADFineGrainedPasswordPolicy -ComplexityEnabled:$true -LockoutDuration:"00:30:00" -LockoutObservationWindow:"00:30:00" -LockoutThreshold:"5" -MaxPasswordAge:"30.00:00:00" -MinPasswordAge:"1.00:00:00" -MinPasswordLength:"12" -Name:"PSO_Domain_Admin" -PasswordHistoryCount:"24" -Precedence:"1" -ReversibleEncryptionEnabled:$false -Server:"Server1DC.mycompany.local"