Active Directory: senha expira em ~40 dias apesar da GPO de 365 — diagnóstico com FGPP/PSO e correção passo a passo

Usuários vendo alerta de “senha expira em 4 dias” cerca de 5 semanas após a troca, mesmo com GPO de 365 dias? O culpado quase sempre é uma Fine‑Grained Password Policy (FGPP/PSO) a sobrepor a Default Domain Policy. Veja como diagnosticar e corrigir.

Índice

Visão geral do cenário

O administrador alterou a Default Domain Policy para definir MaxPasswordAge = 365 dias e forçou todos a mudarem a senha. Cinco semanas depois pipocaram avisos de expiração (“faltam 4 dias”), o que indica um ciclo efetivo próximo de 40–42 dias. As verificações mostram que a GPO chega às estações (gpresult /R), o atributo pwdLastSet está correto (por exemplo, 19/03/2024) e não há outros DCs causando latência de replicação. Ainda assim, o prazo não bate.

O ponto-chave: GPOs comuns não impõem política de senha de domínio. Quem manda é a política de senha do objeto Domain (atributo maxPwdAge) ou um Password Settings Object (PSO), também conhecido como FGPP, aplicável a usuários/grupos e com precedência sobre o domínio.

Por que a GPO não controla diretamente as senhas

Os ajustes de senha em Computer Configuration > Policies > Windows Settings > Security Settings > Account Policies na Default Domain Policy na verdade escrevem nos atributos do objeto de domínio (ex.: maxPwdAge). Eles não são processados como uma GPO tradicional pelo cliente. É por isso que gpresult ou “GPO aplicada” não garantem a efetividade sobre senhas: o que vale é o que está no diretório para o domínio ou o que um PSO determina.

Desde o Windows Server 2008, as Fine‑Grained Password Policies permitem ter regras diferentes por usuário ou por global security group. Quando um PSO se aplica ao usuário (diretamente ou via grupo), ele vence a política do domínio. Resultado típico: o domínio mostra 365 dias, mas um PSO de 42 dias encurta o ciclo e dispara avisos após ~38–41 dias.

Diagnóstico rápido com comandos certeiros

Execute no PowerShell (RSAT/ActiveDirectory instalado e credenciais adequadas):

Verifique a política do domínio

Get-ADDefaultDomainPasswordPolicy | Select-Object MaxPasswordAge, MinPasswordAge, PasswordHistoryCount, ComplexityEnabled

Alternativa em qualquer membro do domínio:

net accounts /domain

Confirme se o domínio realmente reporta ~365 dias de validade.

Liste todos os PSOs existentes

Get-ADFineGrainedPasswordPolicy | Format-Table Name, Precedence, MaxPasswordAge, MinPasswordLength, ComplexityEnabled

Procure por MaxPasswordAge entre 30 e 45 dias — muitas organizações têm PSOs históricos com 42 dias (o antigo padrão).

Descubra se um usuário está sob um PSO

# Resultado efetivo (se houver PSO, este objeto é retornado)
Get-ADAccountResultantPasswordPolicy -Identity <usuario>

Apenas a referência do PSO aplicado (DN), quando existir

Get-ADUser \<usuario> -Properties msDS-ResultantPSO | Select-Object Name, msDS-ResultantPSO </code></pre>

  <p>Se algum dos comandos retornar um PSO, é esse o responsável por sobrepor a Default Domain Policy.</p>
</section>

<section>
  <h2>Entendendo a precedência e o “~40 dias”</h2>
  <p>Quando múltiplos PSOs podem alcançar um usuário (por estar em vários grupos, por exemplo), o AD escolhe o <strong>PSO com menor valor de <code>msDS-PasswordSettingsPrecedence</code></strong> (número mais baixo = mais forte). Se houver empate, aplica-se o PSO diretamente ligado ao usuário; se persistir, a escolha é determinística pelo DN. Na prática, <strong>um único PSO “curto” ligado a um grupo amplo</strong> (até mesmo o “Domain Users”) já basta para toda a empresa ver avisos em ~40 dias.</p>
</section>

<section>
  <h2>Correção direta</h2>
  <h3>Ajustar o PSO para 365 dias</h3>
  <pre><code>Set-ADFineGrainedPasswordPolicy -Identity "&lt;NomeDoPSO&gt;" `
  -MaxPasswordAge (New-TimeSpan -Days 365)
</code></pre>

  <h3>Remover o vínculo do PSO a grupos/usuários</h3>
  <p>Primeiro identifique quem recebe o PSO:</p>
  <pre><code>Get-ADFineGrainedPasswordPolicySubject -Identity "&lt;NomeDoPSO&gt;"
</code></pre>
  <p>Depois remova as associações indevidas (propriedade <code>AppliesTo</code>):</p>
  <pre><code>Set-ADFineGrainedPasswordPolicy -Identity "&lt;NomeDoPSO&gt;" `
  -AppliesTo @{Remove='CN=Grupo,OU=Unidade,DC=exemplo,DC=local'}

Para remover múltiplos:

\$targets = @(
'CN=Admins,OU=TI,DC=exemplo,DC=local',
'CN=Domain Users,CN=Users,DC=exemplo,DC=local'
)
foreach (\$t in \$targets) {
Set-ADFineGrainedPasswordPolicy -Identity "\<NomeDoPSO>" -AppliesTo @{Remove=\$t}
} </code></pre>

  <h3>Sincronização e validação</h3>
  <ul>
    <li>Se houver vários DCs, aguarde a replicação normal ou force (<code>repadmin /syncall /APeD</code> em um DC).</li>
    <li>Peça a um usuário afetado para fazer logoff/logon e confira com:
      <pre><code>net user &lt;login&gt; /domain
</code></pre>
    </li>
  </ul>
  <p>O campo “Password expires” deve refletir o novo cálculo a partir do <code>pwdLastSet</code> e do <code>MaxPasswordAge</code> agora efetivo.</p>
</section>

<section>
  <h2>O que não influencia a senha de usuário</h2>
  <p>A chave de registro <code>HKLM\SYSTEM\CurrentControlSet\Services\Netlogon\Parameters\MaximumPasswordAge</code> controla a <strong>idade da senha da conta de computador</strong> (renovação automática das contas de máquina) e <strong>não tem relação com a expiração de senhas de usuários</strong>. Modificá-la para 365 dias não corrige o problema descrito.</p>
</section>

<section>
  <h2>Fluxo completo de diagnóstico com exemplos</h2>
  <ol>
    <li>
      <p><strong>Confirme o alvo do domínio</strong>:</p>
      <pre><code>$dom = Get-ADDomain
Get-ADDefaultDomainPasswordPolicy | fl *

Verifique se MaxPasswordAge é ~365. Se não for, ajuste pela GPMC no nível do domínio (Account Policies) ou diretamente:

Set-ADDefaultDomainPasswordPolicy -MaxPasswordAge (New-TimeSpan -Days 365)

Levante todos os PSOs e ordene por “força”:

Get-ADFineGrainedPasswordPolicy | Sort-Object Precedence |
  Select-Object Name, Precedence, MaxPasswordAge, MinPasswordLength, ComplexityEnabled |
  Format-Table -Auto

Descubra quem está coberto por um PSO “curto” (por exemplo, 42 dias):

$curtos = Get-ADFineGrainedPasswordPolicy | Where-Object {
  $.MaxPasswordAge.Days -ge 30 -and $.MaxPasswordAge.Days -le 45
}
foreach ($p in $curtos) {
  "`n--- $($p.Name) ($($p.MaxPasswordAge.Days) dias; precedência $($p.Precedence))"
  Get-ADFineGrainedPasswordPolicySubject -Identity $p | Select-Object Name,ObjectClass,DistinguishedName
}

Para um usuário que recebeu aviso, obtenha a política efetiva e a data de expiração calculada:

$u = 'fulano'
Get-ADAccountResultantPasswordPolicy -Identity $u | fl *
Get-ADUser $u -Properties PasswordLastSet,pwdLastSet,msDS-ResultantPSO | fl Name,PasswordLastSet,msDS-ResultantPSO
net user $u /domain

Ajuste os PSOs (elevar para 365 ou remover a associação) e valide novamente com net user e Get-ADAccountResultantPasswordPolicy.

Automatizando a auditoria de PSO em toda a organização

O script abaixo gera um relatório CSV com o resultado de política de senha para todos os usuários habilitados, destacando quem está sob FGPP e a idade máxima aplicada:

# Requer módulo ActiveDirectory
$saida = @()
$usuarios = Get-ADUser -Filter {Enabled -eq $true} -Properties msDS-ResultantPSO, PasswordLastSet
foreach ($usr in $usuarios) {
  $res = $null
  try { $res = Get-ADAccountResultantPasswordPolicy -Identity $usr.SamAccountName } catch {}
  $max = if ($res) { $res.MaxPasswordAge.Days } else { (Get-ADDefaultDomainPasswordPolicy).MaxPasswordAge.Days }
  $pso = if ($usr.'msDS-ResultantPSO') { $usr.'msDS-ResultantPSO' } else { 'Dominio' }
  $saida += [pscustomobject]@{
    Usuario         = $usr.SamAccountName
    Nome            = $usr.Name
    EmFGPP          = [bool]$usr.'msDS-ResultantPSO'
    PSOouDominio    = $pso
    MaxPasswordDias = $max
    PasswordLastSet = $usr.PasswordLastSet
  }
}
$saida | Sort-Object EmFGPP -Descending, MaxPasswordDias |
  Export-Csv -NoTypeInformation -Encoding UTF8 .\Relatorio-PSO-Usuarios.csv

"Gerado: \$(Get-Date)  -  Total: \$(\$saida.Count) usuários  -  Saída: Relatorio-PSO-Usuarios.csv" 

Com o CSV em mãos, fica simples identificar grupos/usuários sob PSOs com prazo curto e planejar o ajuste sem surpresas.

Boas práticas e armadilhas comuns

  • Não aplique PSO ao “Domain Users”. Use grupos globais dedicados (ex.: GG-FGPP-Admins, GG-FGPP-Terceiros).
  • Documente a precedência. Um número pequeno vale mais; padronize convenções (ex.: 10 para Administradores, 20 para TI, 100 para Exceções).
  • Evite conflito de requisitos. Historicamente, defaults de 42 dias vêm de ambientes antigos; alinhe com a política corporativa e compliance.
  • Teste contas de serviço. Algumas aplicações falham se a senha expira; considere PasswordNeverExpires ou PSO com expiração longa e complexidade elevada.
  • Use comandos corretos de leitura. net accounts /domain lê do domínio; net accounts sozinho mostra o local (num DC, coincide; em membro, pode confundir).
  • Confirme o nível funcional. FGPP exige Windows Server 2008 ou superior como nível funcional do domínio.
  • Audite periodicamente. PSOs esquecidos causam “surpresas” meses depois. Agende o script de auditoria.

Casos que produzem expiração em ~40 dias

OrigemComo ocorreComo detectarCorreção
PSO legado com 42 diasPSO aplicado a grupo amplo (até “Domain Users”)Get-ADFineGrainedPasswordPolicy e Get-ADFineGrainedPasswordPolicySubjectAjustar MaxPasswordAge ou remover AppliesTo
PSO com precedência menorDois PSOs competem; vence o de menor PrecedenceOrdene PSOs por PrecedencePadronize precedências e escopos
Leitura incorretaUso de net accounts sem /domainComandos retornam valores distintosUse Get-ADDefaultDomainPasswordPolicy
Confusão com registroChave Netlogon alterada achando que afeta usuárioVerifica-se valor alto em registry, mas nada mudaIgnorar; não governa senha de usuário

Quando e por que usar FGPP

SituaçãoVantagemRisco/Observação
Expiração mais curta para contas administrativasAumenta a segurançaExija MFA, rotacione com maior frequência e documente claramente para evitar confusão
Senhas mais longas ou sem expiração para serviços críticosReduz intervenções e janelas de indisponibilidadeValide se a aplicação suporta comprimento/complexidade; proteja segredos (Vault)
Políticas diferentes por unidade de negócioFlexibilidade alinhada ao riscoEleva a complexidade de gestão e troubleshooting

Em ambientes menores, uma única política de domínio costuma simplificar a operação e evitar incidentes como o do exemplo.

FAQ objetivo

“Eu mudei a Default Domain Policy para 365 e mesmo assim alertas aparecem em 40 dias. É bug?”

Não. Muito provavelmente há um PSO ativo com MaxPasswordAge ≈ 42 dias. O PSO vence a política do domínio para usuários/grupos aos quais está aplicado.

“Como garanto que todos respeitam 365 dias?”

Eleve ou remova PSOs “curtos”, verifique precedência e confirme com Get-ADAccountResultantPasswordPolicy para contas de amostra em diferentes departamentos.

“Preciso reiniciar ou rodar gpupdate nas estações?”

Não. A mudança é de diretório (atributos de políticas). Garanta a replicação entre DCs e faça logoff/logon para renovar o ticket e reavaliar expiração.

“Posso aplicar PSO a OUs?”

Não. PSO aplica-se a usuários ou grupos de segurança globais. Se precisa afetar uma OU, vincule o PSO a um grupo global e popule-o com os usuários da OU.

“Qual o valor padrão histórico de expiração?”

Ambientes clássicos costumavam usar 42 dias. Muitos PSOs legados permanecem com esse período e causam o sintoma aqui descrito.

Checklist rápido para produção

  • Confirmar MaxPasswordAge do domínio = 365.
  • Inventariar PSOs e localizar qualquer MaxPasswordAge ≤ 45 dias.
  • Mapear AppliesTo de cada PSO e remover grupos amplos indevidos.
  • Padronizar Precedence e nomeação dos PSOs.
  • Validar em contas piloto com Get-ADAccountResultantPasswordPolicy e net user /domain.
  • Documentar e comunicar aos usuários finais.

Resumo da causa provável

Existe um Password Settings Object com MaxPasswordAge ~42 dias aplicado — direta ou indiretamente via grupo — sobrepondo a Default Domain Policy. Ajustar ou remover esse FGPP faz com que as contas voltem ao ciclo de 365 dias definido para o domínio.

Modelo de comunicação para o Service Desk

“Identificámos uma política de senha avançada aplicada a um grupo de utilizadores, que reduzia o prazo de expiração para ~40 dias. Atualizámos a política para 365 dias conforme o padrão corporativo. Se receber aviso de expiração, reinicie a sessão e verifique a data em net user <seu_login> /domain. Em caso de dúvida, abra um ticket.”

Conclusão

Se a “senha expira” aparecer cedo demais após uma alteração para 365 dias, investigue FGPP/PSO antes de qualquer outra coisa. O diagnóstico leva minutos com os cmdlets corretos e evita mexidas irrelevantes em GPOs, estações ou registro. Aplique governança mínima de PSOs — precedência clara, grupos dedicados e auditoria recorrente — para manter previsibilidade e conformidade.

Índice