The password is right, the account is in the VPN group, and the connection is still refused with a message that mentions no policy at all. When that happens on a Windows remote-access server, the first place I look is not the NPS rule but one Active Directory attribute nobody opens: msNPAllowDialin, the value behind the Dial-in tab. It has three states, and the third one quietly hands the decision to somewhere else. Most of the time nobody changed it on purpose: the account was cloned from a template, or provisioned by a script that wrote an explicit deny years ago and was never revisited.

The refusal can happen before the policy is read

Windows checks the account's dial-in permission while it builds the authorization decision, so an explicit deny ends the conversation early. What you see on the client is a generic authentication failure, sometimes after the certificate exchange completed, which is why people spend an afternoon testing credentials that were never the problem.

The reverse case is just as confusing. An account that has never had the flag set may connect successfully because the policy allowed it, and then the same account stops connecting when someone edits the NPS rule for an unrelated reason. Neither event looks like a dial-in permission change from the outside.

Three states, and the third one is invisible

TRUE permits dial-in, FALSE refuses it, and a NULL value means the account inherits its answer from remote access policy or NPS authorization. The GUI renders that third state as "Control access through NPS Network Policy", and it reads like an unset checkbox rather than a decision.

That is why counting allowed users from the console tells you almost nothing. An inherited account may be allowed today and denied tomorrow without the account being touched, and a FALSE account may still connect on a server whose policy is configured to ignore user dial-in properties. Read the attribute and the policy together, or you are auditing half a decision.

Export the flags without dropping the inherited accounts

Run the export from a domain controller, or from a workstation with the Active Directory module, and keep the raw file as evidence rather than retyping a summary:

Get-ADUser -Filter * -Properties msNPAllowDialin, LastLogonDate |
  Select-Object SamAccountName, Enabled, msNPAllowDialin, LastLogonDate |
  Sort-Object SamAccountName |
  Export-Csv -NoTypeInformation .\dialin.csv

A single LDAP filter is easier to paste into a change record. This one returns only the explicit allows:

dsquery * -Filter "(&(objectCategory=person)(objectClass=user)(msNPAllowDialin=TRUE))" -Attr sAMAccountName

Then query again without the dial-in clause and look for accounts whose value is absent. Those are the inherited ones, usually the largest group in the domain, and skipping them turns an audit into a list of the few people somebody remembered to configure by hand.

Separate the flag from group access and account health

The attribute answers one question: may this account dial in. It says nothing about whether the person still works here, whether the account is enabled, or whether a shared password is sitting in a help-desk note. Pair the export with the enabled state, the last logon date and the group membership that grants access to the server.

The combinations are what you act on. A disabled account with TRUE is noise. An enabled account with TRUE that has not logged on in a year is a candidate for removal. An inherited account in the VPN group that nobody can explain is the finding that matters, because no single setting records why it was granted.

Read it from the domain controller the VPN server actually authenticates against. Replication lag can show a value that the server has already replaced, and an audit that cites a stale DC value will be challenged the moment someone checks again.

Change one account and prove the change landed

To remove access, set the attribute to FALSE instead of clearing it. Clearing returns the account to policy inheritance, which may allow it again on the next connection, and the change looks like a fix while it is actually a different decision:

dsmod user "CN=Jane Doe,OU=Staff,DC=corp,DC=example" -allowDialin no
Set-ADUser -Identity jdoe -Clear msNPAllowDialin

The second line is the inheritance reset, kept separate on purpose so nobody conflates the two operations. Then confirm from a second session, re-read the attribute, and check the NPS accounting events for the refusal rather than trusting the console refresh.

Finally, write down which mechanism owns the decision for each remote-access service. If the policy ignores user dial-in properties, the group condition is authoritative and the attribute is advisory for that service only. Two services on the same domain can legitimately answer differently, and the review record should say so in one line per service.

The output that survives an audit is short: who may connect, under which mechanism, reviewed when, by whom. The dial-in flag supplies the first two answers; only the policy review supplies the rest.

Mikanda mikatakata