Using PowerShell to Remove Former Vendor Access

Using PowerShell to Remove Former Vendor Access

Use powershell remove former vendor access workflows to disable accounts, revoke sessions, remove group access, and retain audit evidence.

LakeRidge Team
July 19, 2026
7 min read

Share:

Schedule Your Free Compliance Consultation

Feeling overwhelmed by compliance requirements? Not sure where to start? Get expert guidance tailored to your specific needs in just 15 minutes.

Personalized Compliance Roadmap
Expert Answers to Your Questions
No Obligation, 100% Free

CMMC Phase 2 begins November 10, 2026.

You can use a powershell remove former vendor access workflow to disable a former supplier’s Microsoft 365 account, revoke active sign-in sessions, remove approved group memberships, and produce an audit record of every action. Automation handles repeatable identity changes quickly, but a person must still verify that the vendor engagement has ended, approve the request, and identify any business records or services that must remain available.

This approach supports ISO 27001 Annex A control 5.19, Information Security in Supplier Relationships, which requires defined and implemented processes for managing security risks associated with supplier products and services. For a small business owner, the practical goal is simple: no former vendor should retain a working account, an active session, or hidden access through a shared group after the engagement ends.

What can be automated and what still needs a human decision?

A PowerShell removal workflow is best for actions that are consistent, reversible where necessary, and recorded in Microsoft 365 or another identity platform. It is not a replacement for confirming the contract end date, settling retained records, or deciding whether a vendor-owned application can be safely removed.

Task Automate? Reason
Disable a Microsoft Entra guest account Yes This immediately prevents new sign-ins while preserving the account for evidence and review.
Revoke refresh tokens and active sessions Yes This reduces the window in which an already authenticated vendor can continue working.
Remove access to named security groups Yes Groups such as Client-Documents-Read and Practice-Management-Users are predictable access paths.
Delete the vendor account permanently Usually no Keep it disabled until billing, document ownership, and audit questions are resolved.
Remove a vendor-managed application or API integration Not without review The application may run payroll, file transfers, backups, or a client portal.
Confirm all supplier obligations are complete No A contract owner must verify the offboarding date, retained data, and handover requirements.

For example, a 32-person accounting firm may use an outside IT provider for Microsoft 365 administration and a separate document-scanning contractor during tax season. The office manager should approve each departure in a simple vendor register before the automated job runs. The script can disable the contractor’s guest account, but it cannot determine whether that contractor still needs to upload the final batch of scanned client records.

How does powershell remove former vendor access safely?

The safest pattern is an approved CSV queue. Each row represents one vendor identity, one change ticket, and a defined set of groups to remove. The script below refuses unapproved rows, checks that the account is a guest account, disables sign-in first, revokes sessions, then removes only the group IDs listed in the approved request.

Install the Microsoft Graph PowerShell SDK on the machine or automation worker that will run the script. Use an Entra application with certificate-based authentication rather than storing an administrator password in the script. The application needs delegated administrative approval for the equivalent application permissions: User.ReadWrite.All, GroupMember.ReadWrite.All, and Directory.ReadWrite.All.

Import-Module Microsoft.Graph.Users
Import-Module Microsoft.Graph.Groups

param(
    [string]$InputCsv = "C:\VendorOffboarding\approved-vendors.csv",
    [string]$TenantId = "contoso.onmicrosoft.com",
    [string]$ClientId = "6b5f0f7b-91a3-4a6f-8b26-95b087fc2032",
    [string]$CertificateThumbprint = "A12B34C56D78E90F12A34B56C78D90E12F34A567",
    [switch]$Execute
)

$ErrorActionPreference = "Stop"
$results = @()

Connect-MgGraph -TenantId $TenantId `
    -ClientId $ClientId `
    -CertificateThumbprint $CertificateThumbprint `
    -NoWelcome

foreach ($record in Import-Csv $InputCsv) {
    $timestamp = Get-Date -Format "s"

    try {
        if ($record.Approved -ne "YES") {
            throw "Row is not approved."
        }

        if ([datetime]$record.EndDate -gt (Get-Date)) {
            throw "End date has not yet passed."
        }

        $user = Get-MgUser -UserId $record.UserPrincipalName `
            -Property "id,displayName,userType,accountEnabled"

        if ($user.UserType -ne "Guest") {
            throw "Account is not a guest account; require manual review."
        }

        if (-not $Execute) {
            $results += [pscustomobject]@{
                Time = $timestamp; Ticket = $record.Ticket
                User = $record.UserPrincipalName; Status = "PLAN ONLY"
                Detail = "Would disable account, revoke sessions, and remove listed groups."
            }
            continue
        }

        Update-MgUser -UserId $user.Id -AccountEnabled:$false
        Revoke-MgUserSignInSession -UserId $user.Id

        foreach ($groupId in ($record.GroupIds -split ";")) {
            if ($groupId.Trim()) {
                try {
                    Remove-MgGroupMemberByRef `
                        -GroupId $groupId.Trim() `
                        -DirectoryObjectId $user.Id

                    $results += [pscustomobject]@{
                        Time = $timestamp; Ticket = $record.Ticket
                        User = $record.UserPrincipalName; Status = "REMOVED"
                        Detail = "Removed from group $($groupId.Trim())"
                    }
                }
                catch {
                    $results += [pscustomobject]@{
                        Time = $timestamp; Ticket = $record.Ticket
                        User = $record.UserPrincipalName; Status = "GROUP REVIEW"
                        Detail = "Could not remove group $($groupId.Trim()): $($_.Exception.Message)"
                    }
                }
            }
        }

        $results += [pscustomobject]@{
            Time = $timestamp; Ticket = $record.Ticket
            User = $record.UserPrincipalName; Status = "DISABLED"
            Detail = "Account disabled and sign-in sessions revoked."
        }
    }
    catch {
        $results += [pscustomobject]@{
            Time = $timestamp; Ticket = $record.Ticket
            User = $record.UserPrincipalName; Status = "FAILED"
            Detail = $_.Exception.Message
        }
    }
}

$results | Export-Csv "C:\VendorOffboarding\logs\vendor-offboarding-$((Get-Date).ToString('yyyyMMdd-HHmmss')).csv" -NoTypeInformation
Disconnect-MgGraph

Use a CSV like this, with real Entra group object IDs rather than group names. Group IDs prevent accidental removal from the wrong group when names are similar.

Ticket,Approved,EndDate,UserPrincipalName,GroupIds
CHG-2026-041,YES,2026-07-18,alex@vendor-example.com,"2df4d9b8-1234-45ab-9999-1b7b2dd34aa1;9a7ce284-5678-40cd-8888-3d2f11cae902"

Run the script once without -Execute to create a plan-only log. Review that log against the approval ticket, then run it with -Execute. This two-step PowerShell vendor offboarding process is easier to control than allowing an automated task to act on every row immediately.

How should the job run on a schedule or through CI/CD?

For most SMBs, an Azure Automation runbook or a locked-down Windows automation server is more practical than running the job from an owner’s laptop. Store the script in a private Git repository, require a second person to approve changes, and schedule the job daily after normal business hours. Use a certificate stored in the automation account or service account profile; never place a Global Administrator password in a CSV file, script, or shared drive.

$trigger = New-ScheduledTaskTrigger -Daily -At 6:00pm
$action = New-ScheduledTaskAction `
    -Execute "pwsh.exe" `
    -Argument "-NoProfile -File C:\VendorOffboarding\Remove-VendorAccess.ps1 -Execute"

Register-ScheduledTask `
    -TaskName "Vendor Access Offboarding" `
    -Action $action `
    -Trigger $trigger `
    -Description "Runs approved Microsoft 365 vendor offboarding requests."

A 24-person legal practice, for instance, can have its operations manager place approved vendor departures into the queue before 5:00 p.m. The scheduled task runs at 6:00 p.m., after staff have finished client work, and writes an immutable copy of the result log to a restricted SharePoint library or Azure storage account.

What monitoring and alerting hooks should be added?

The automation should create evidence, not merely make changes. Send a daily summary to the business owner and ensure failures become visible before the former supplier has another opportunity to sign in.

  • Send an email or Teams alert whenever a row has a FAILED or GROUP REVIEW status.
  • Retain the CSV result log with the ticket number, date, account name, actions taken, and error details.
  • Review Entra sign-in logs for the disabled account for seven days after offboarding.
  • Create an alert for attempts to sign in to a disabled guest account, especially from a new country or unfamiliar IP address.
  • Review the vendor register monthly for accounts with an end date but no completed offboarding log.

This monitoring layer turns a vendor-access removal script into evidence that your ISO 27001 supplier relationship process is working, rather than an undocumented technical action.

What happens when the automated vendor offboarding process fails?

Failure handling matters because partial removal can create false confidence. The script disables the account before attempting group removal, so a group error does not leave the vendor able to sign in. However, the owner still needs a clear response for each failure type.

Failure mode Immediate response Follow-up
Vendor account cannot be found Mark the ticket for review; do not assume access is gone. Search for alternate email addresses, personal accounts, and shared credentials.
Account is a Member rather than Guest Stop automation and require management approval. Confirm whether the vendor was incorrectly created as an internal user.
Group removal fails Keep the account disabled and alert the owner. Check nested groups, Teams membership, SharePoint direct permissions, and application roles.
Certificate authentication fails Do not switch to a shared administrator password. Renew the certificate, verify app permissions, and rerun the approved row.
Critical vendor service stops working Do not re-enable the account automatically. Use a time-limited, documented exception approved by the service owner.

Your next step is to create a one-page vendor offboarding register, add your current suppliers and their end dates, and test the script in plan-only mode with one inactive guest account.

 

Quick & Simple

Discover Our Cybersecurity Compliance Solutions:

Whether you need to meet and maintain your compliance requirements, help your clients meet them, or verify supplier compliance we have the expertise and solution for you

 CMMC Level 1 Compliance App

CMMC Level 1 Compliance

Become compliant, provide compliance services, or verify partner compliance with CMMC Level 1 Basic Safeguarding of Covered Contractor Information Systems requirements.
 NIST SP 800-171 & CMMC Level 2 Compliance App

NIST SP 800-171 & CMMC Level 2 Compliance

Become compliant, provide compliance services, or verify partner compliance with NIST SP 800-171 and CMMC Level 2 requirements.
 HIPAA Compliance App

HIPAA Compliance

Become compliant, provide compliance services, or verify partner compliance with HIPAA security rule requirements.
 ISO 27001 Compliance App

ISO 27001 Compliance

Become compliant, provide compliance services, or verify partner compliance with ISO 27001 requirements.
 FAR 52.204-21 Compliance App

FAR 52.204-21 Compliance

Become compliant, provide compliance services, or verify partner compliance with FAR 52.204-21 Basic Safeguarding of Covered Contractor Information Systems requirements.
 ECC Compliance App

ECC Compliance

Become compliant, provide compliance services, or verify partner compliance with Essential Cybersecurity Controls (ECC – 2 : 2024) requirements.