To block sign-in for multiple users in Microsoft Entra ID, set accountEnabled to false on each account in your list. Blocking stops new sign-ins; it does not end sessions that are already open, which is a separate step. Check the list first: a blocked account locks out anything that signs in as it, including a service account or your own.
| Method | Best fit |
|---|---|
| PowerShell | A script that reads a CSV of sign-in names and backs up, blocks and records each account. |
| Admin centre | Blocking 1 or 2 accounts, one at a time. |
| Altivane | Recommended for bulk changes to items you choose from a list, with every result in a change log. |
Before you start
A User Administrator can block members who hold no administrator role or only some limited ones; blocking any other administrator needs Privileged Authentication Administrator or Global Administrator. The PowerShell example requests User. and User.; your organisation may require administrator consent.
These examples change the tenant. Try them on 1 or 2 test accounts first, and keep the CSV files the script writes as your record of what changed.
Option 1
Block sign-in for multiple users with PowerShell
Save the sign-in names in users. beside the script, under a header of UserPrincipalName.
UserPrincipalName
alex.morgan@example.com
sam.lee@example.comInstall the modules once, then run the script. It is a dry run until you set $DryRun to $false: Update-MgUser supports -WhatIf, and the script switches it with that variable.
# Install once, if the modules are not already installed.
Install-Module Microsoft.Graph.Authentication, Microsoft.Graph.Users -Scope CurrentUser# While $DryRun is $true, nothing is changed. Set it to $false to block the accounts.
$DryRun = $true
$ErrorActionPreference = 'Stop'
Connect-MgGraph -Scopes 'User.EnableDisableAccount.All', 'User.Read.All' -NoWelcome
try {
$stamp = Get-Date -Format 'yyyyMMdd-HHmmss'
$rows = @(Import-Csv -Path './users.csv' | Where-Object { $_.UserPrincipalName })
if ($rows.Count -eq 0) { throw 'users.csv needs a UserPrincipalName column and some rows.' }
# Step 1: read each account as it is now and save it as the backup.
$properties = 'userPrincipalName,accountEnabled,onPremisesSyncEnabled'
$backup = foreach ($row in $rows) {
$upn = $row.UserPrincipalName.Trim()
try {
$user = Get-MgUser -UserId $upn -Property $properties
[pscustomobject]@{
UserPrincipalName = $upn
AccountEnabled = $user.AccountEnabled
OnPremisesSyncEnabled = [bool]$user.OnPremisesSyncEnabled
Error = ''
}
} catch {
[pscustomobject]@{
UserPrincipalName = $upn
AccountEnabled = ''
OnPremisesSyncEnabled = ''
Error = $_.Exception.Message
}
}
}
$backup | Export-Csv -Path "./block-backup-$stamp.csv" -NoTypeInformation -Encoding utf8
# Step 2: block each account that is not blocked already, 1 at a time.
$results = foreach ($account in $backup) {
$upn = $account.UserPrincipalName
$status = 'Failed'
$detail = $account.Error
if ($account.Error -eq '') {
if ($account.AccountEnabled -eq $false) {
$status = 'No change'
$detail = 'Sign-in is already blocked.'
} else {
try {
Update-MgUser -UserId $upn -AccountEnabled:$false -WhatIf:$DryRun
$status = if ($DryRun) { 'Preview' } else { 'Blocked' }
$detail = ''
} catch {
$detail = $_.Exception.Message
}
}
}
[pscustomobject]@{ UserPrincipalName = $upn; Status = $status; Detail = $detail }
}
$results | Export-Csv -Path "./block-results-$stamp.csv" -NoTypeInformation -Encoding utf8
$results | Group-Object Status | Select-Object Name, Count | Format-Table
} finally {
Disconnect-MgGraph | Out-Null
}The first pass saves block-backup-*.csv before anything changes: whether each account is enabled, and whether it is synchronised from on-premises Active Directory. The second blocks each account still enabled and saves block-results-*.csv with Preview, Blocked, No change or Failed for each. A failure on 1 account, such as a role that cannot change it, goes in Detail and the rest carry on. An account synchronised from on-premises Active Directory may refuse the change, so check OnPremisesSyncEnabled in the backup.
End sessions that are already open
Revoking sessions is a separate step with its own permission. Revoke-MgUserSignInSession invalidates the account's refresh tokens and browser session cookies, so the person must sign in again. Run it on its own, after the block.
# While $DryRun is $true, nothing is changed. Set it to $false to end the sessions.
$DryRun = $true
$ErrorActionPreference = 'Stop'
Connect-MgGraph -Scopes 'User.RevokeSessions.All' -NoWelcome
try {
$done = 0
foreach ($row in Import-Csv -Path './users.csv') {
$upn = $row.UserPrincipalName.Trim()
try {
Revoke-MgUserSignInSession -UserId $upn -WhatIf:$DryRun | Out-Null
$done++
} catch {
Write-Warning "${upn}: $($_.Exception.Message)"
}
}
Write-Output "$done accounts handled. Dry run: $DryRun."
} finally {
Disconnect-MgGraph | Out-Null
}Option 2
Block sign-in in the admin centre
- Sign in to the Microsoft 365 admin centre for the correct tenant.
- Go to Users > Active users.
- Select the name of the person to block, then select Block sign-in.
- On the Block sign-in page, select Block this user from signing in, then Save changes.
- Repeat for each person on your list.
Microsoft says a block can take up to 24 hours to take effect. To cut access at once, also select Reset password, then open the person's Account tab and select Sign out of all sessions. These steps cover 1 account at a time; for a longer list, use PowerShell or Altivane.
Option 3 ยท Recommended for bulk changes with a record of each result
Block sign-in for multiple users with Altivane
- Open Altivane and choose the tenant.
- Choose the accounts in Altivane's list of users, then the Block sign-in change. Its window shows the change, the accounts it applies to and the tenant.
- Run it from that window. Altivane blocks each account and writes each result to the change log.
Altivane reads each account before it changes it, and refuses an account synchronised from on-premises Active Directory, saying to change it there. The change log records when, who signed in, the account, the status and the command sent. A separate Revoke sign-in sessions change ends sessions, and refuses guests and other external accounts.
Contact usCommon questions
Does blocking sign-in end sessions that are already open?
No. Blocking stops new sign-ins, and Microsoft says it can take up to 24 hours to take effect. End sessions separately: with the revoke script above, the admin centre's Sign out of all sessions, or Altivane's Revoke sign-in sessions change.
How do I undo a block?
Set accountEnabled back to true. In PowerShell, run Update-MgUser with -AccountEnabled:$true for each account, leaving alone any the backup CSV shows were already blocked. In Altivane, run the Allow sign-in change on the same accounts. Revoked sessions do not come back: people sign in again.
Where do I get the list of accounts to block?
From a review you have already made. For accounts with no recent sign-in, see how to find inactive users in Microsoft Entra ID, and check each name before it goes in users..
Microsoft references
Technical references checked on 20 October 2026. The example scripts have been reviewed and syntax checked; they have not been run against a live tenant.