Active Directory - PowerShell

PowerShell e Active Directory: Come estrarre la data di scadenza della password e di ultimo cambio

Sapere quando una password scade e quando è stata cambiata l’ultima volta è fondamentale per la gestione della sicurezza: consente di prevenire blocchi imprevisti degli utenti, verificare la conformità alle policy aziendali e produrre report per audit. La procedura varia a seconda dell’ambiente: dominio Active Directory on-premises, Microsoft Entra ID o account locali su un singolo PC Windows. In questo articolo vedremo i comandi PowerShell per un dominio Active Directory.

Sintassi dei comandi

In un dominio AD, la data di scadenza effettiva della password non è un attributo diretto dell’utente ma viene calcolata dal controller di dominio combinando la policy password applicata e la data dell’ultimo cambio. Il modo più affidabile per ottenerla è attraverso l’attributo calcolato msDS-UserPasswordExpiryTimeComputed.

Il valore è un timestamp in formato Windows FILETIME (numero di intervalli di 100 nanosecondi dal 1° gennaio 1601) e va convertito con [datetime]::FromFileTime(). Vediamo alcuni esempi.

Ottenere la scadenza della password per un singolo utente

Get-ADUser -Identity "NomeUtente" -Properties msDS-UserPasswordExpiryTimeComputed |
    Select-Object Name,
        @{Name="ScadenzaPassword"; Expression={
            [datetime]::FromFileTime($_."msDS-UserPasswordExpiryTimeComputed")
        }}

# Output atteso
Name          ScadenzaPassword
----          ----------------
Mario Rossi   14/10/2026 21:51:38

Ottenere la data dell’ultimo cambio della password per un singolo utente

Get-ADUser -Identity "NomeUtente" -Properties PasswordLastSet |
    Select-Object Name, PasswordLastSet

# Output atteso
Name          PasswordLastSet
----          ---------------
Mario Rossi   16/07/2026 21:51:38

Report combinato (ultimo cambio + scadenza) per un singolo utente

$utente = Get-ADUser -Identity "NomeUtente" `
    -Properties msDS-UserPasswordExpiryTimeComputed, PasswordLastSet

[PSCustomObject]@{
    Nome             = $utente.Name
    Ultimocambio     = $utente.PasswordLastSet
    ScadenzaPassword = [datetime]::FromFileTime($utente."msDS-UserPasswordExpiryTimeComputed")
    GiorniRimanenti  = ([datetime]::FromFileTime($utente."msDS-UserPasswordExpiryTimeComputed") - (Get-Date)).Days
}

# Output atteso
Nome          Ultimocambio        ScadenzaPassword    GiorniRimanenti
----          ------------        ----------------    ---------------
Mario Rossi   16/07/2026 21:51:38 14/10/2026 21:51:38              89

Report combinato (ultimo cambio + scadenza) per tutti gli utenti attivi escludendo quelli con l’opzione “Password Never Expired”

Get-ADUser -Filter "Enabled -eq 'True' -and PasswordNeverExpires -eq 'False'" `
    -Properties msDS-UserPasswordExpiryTimeComputed, PasswordLastSet |
    Select-Object Name, UserPrincipalName,
        PasswordLastSet,
        @{Name="ScadenzaPassword"; Expression={
            [datetime]::FromFileTime($_."msDS-UserPasswordExpiryTimeComputed")
        }} |
    Sort-Object ScadenzaPassword

# Output atteso
Name              UserPrincipalName             PasswordLastSet     ScadenzaPassword
----              -----------------             ---------------     ----------------
Mario Rossi       mario.rossi@domain.local      16/07/2026 15:15:15 14/10/2026 15:15:15
Giovanni Verdi    giovanni.verdi@domain.local   16/07/2026 16:51:38 14/10/2026 16:51:38
Laura Bianchi     laura.bianchi@domain.local    16/07/2026 16:53:50 14/10/2026 16:53:50

Report per identificare gli utenti la cui password scade entro un numero configurabile di giorni (nell’esempio 14)

$oggi   = Get-Date
$limite = $oggi.AddDays(14)

Get-ADUser -Filter "Enabled -eq 'True' -and PasswordNeverExpires -eq 'False'" `
    -Properties msDS-UserPasswordExpiryTimeComputed, PasswordLastSet |
    Select-Object Name, UserPrincipalName,
        PasswordLastSet,
        @{Name="ScadenzaPassword"; Expression={
            [datetime]::FromFileTime($_."msDS-UserPasswordExpiryTimeComputed")
        }} |
    Where-Object { $_.ScadenzaPassword -gt $oggi -and $_.ScadenzaPassword -le $limite } |
    Sort-Object ScadenzaPassword

# Output atteso
Name              UserPrincipalName             PasswordLastSet     ScadenzaPassword
----              -----------------             ---------------     ----------------
Mario Rossi       mario.rossi@domain.local      18/04/2026 08:31:46 17/07/2026 08:31:46
Giovanni Verdi    giovanni.verdi@domain.local   18/04/2026 17:40:46 17/07/2026 17:40:46
Laura Bianchi     laura.bianchi@domain.local    20/04/2026 07:45:57 19/07/2026 07:45:57

Esempio di utilizzo

Scenario: produrre un report completo di tutti gli utenti attivi del dominio con la data dell’ultimo cambio password e quella di scadenza, filtrando chi scade entro i prossimi 30 giorni, ed esportarlo in un file CSV

$oggi      = Get-Date
$preavviso = $oggi.AddDays(30)
$outputCsv = "C:\Report\scadenza_password_$(Get-Date -Format 'yyyyMMdd').csv"

Get-ADUser -Filter "Enabled -eq 'True' -and PasswordNeverExpires -eq 'False'" `
    -Properties msDS-UserPasswordExpiryTimeComputed, PasswordLastSet |
    Select-Object Name, UserPrincipalName,
        PasswordLastSet,
        @{Name="ScadenzaPassword"; Expression={
            [datetime]::FromFileTime($_."msDS-UserPasswordExpiryTimeComputed")
        }} |
    Where-Object { $_.ScadenzaPassword -gt $oggi -and $_.ScadenzaPassword -le $preavviso } |
    Sort-Object ScadenzaPassword |
    Export-Csv -Path $outputCsv -NoTypeInformation -Encoding UTF8

Write-Host "Report salvato in: $outputCsv"

# Output atteso nel file csv
"Name","UserPrincipalName","PasswordLastSet","ScadenzaPassword"
"Mario Rossi","mario.rossi@dominio.local","07/01/2026 09:14:22","07/31/2026 09:14:22"
"Laura Bianchi","laura.bianchi@dominio.local","07/05/2026 11:03:45","08/04/2026 11:03:45"
"Giovanni Verdi","giovanni.verdi@dominio.local","07/10/2026 08:55:10","08/09/2026 08:55:10"

L’elenco degli articoli di questa serie può essere consultato qui