Gsuite: Auto-deprovisioning with GAM

A GAM script to automate Gsuite account deprovisioning with logging.

GAM is a command line tool for Google Workspace admins to manage domain and user settings quickly and easily.

The goal of the sampling is to automate the deprovisioning process using a PowerShell script and a corresponding CSV, consisting of the following steps:

  • Suspend the account.
  • Remove 2FA information (both phone and email).
  • Update the account's OU.
  • Remove all data from user information fields.
  • Turn off directory discovery.
  • Disassociate all Google group memberships.
  • Set a random, strong password.
  • Re-enable the account in order for third-party tools to perform data backup.
  • Save the output to a local log file.

Requirements

  • GAM installed locally. API authorization is required for setting up a new project in Google Cloud Console for this.
  • deprov.csv - this is a header-less CSV listing email addresses in column A, placed in the same folder as the PowerShell script.
  • If an OU update is required, replace the OU with yours.
  • Important: Do not run this script against active accounts!

Script

# Get today's date to include in the log file name
$logDate = Get-Date -Format "yyyy-MM-dd"
$logFileName = "deprov_log_$logDate.txt"
$logPath = Join-Path -Path $PSScriptRoot -ChildPath $logFileName

# Create or append to the log file
if (-not (Test-Path $logPath)) {
    New-Item -Path $logPath -ItemType File | Out-Null
}

# Function to write log entries
function Write-Log {
    param (
        [string]$Message
    )
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $logEntry = "$timestamp - $Message"
    Add-Content -Path $logPath -Value $logEntry
}

try {
    # Read the CSV file and handle errors if the file doesn't exist or is inaccessible
    $csvData = Import-Csv -Path $csvPath -ErrorAction Stop
} catch {
    $errorMessage = "Error: $($_.Exception.Message)"
    Write-Host $errorMessage
    Write-Log $errorMessage
    exit 1
}

foreach ($email in $csvData) {
    # Trim whitespace and process each email address
    $email = $email.Trim()

    # Check if the $email variable contains a valid email address.
    if ($email -match "^\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$") {
        try {
            # Perform the GAM actions for each email address.
            # Move the account to /Deprovisioned
            gam update user $email ou /Deprovisioned
            sleep 1
            # Suspend the account for the cleanup
            gam update user $email suspended on
            sleep 1
            # Remove 2FA email
            gam update user $email recoveryemail `"`" 
            sleep 1
            # Remove 2FA phone
            gam update user $email recoveryphone `"`"
            sleep 1
            # Remove account data
            gam update user $email organization clear
            sleep 1
            # Turn off directory discovery
            gam update user $email gal false
            sleep 1
            # Remove the account's location
            gam update user $email location type buildingid:terminated endlocation
            sleep 1
            # Remove the account's group memberships
            gam user $email delete groups 2>$null
            sleep 1
            # Set a strong password, don't require password change
            gam update user $email password random changepassword false
            sleep 1
            # Reactivate account
            gam update user $email suspended off
            sleep 1
            $successMessage = "$email is prepared for backup!"
            Write-Host $successMessage
            Write-Log $successMessage
        } catch {
            $errorMessage = "Error processing $email: $($_.Exception.Message)"
            Write-Host $errorMessage
            Write-Log $errorMessage
        }
    } else {
        # If the email address is not valid, throw a message
        $invalidEmailMessage = "Invalid email address: $email"
        Write-Host $invalidEmailMessage
        Write-Log $invalidEmailMessage
    }
}

$completionMessage = "All accounts have been processed."
Write-Host $completionMessage
Write-Log $completionMessage