Wednesday, November 26, 2025

Bitwarden Password Vault Cleanup Guide


Bitwarden CLI Vault Cleanup Guide

A comprehensive guide for cleaning up your Bitwarden vault using the CLI, based on real troubleshooting sessions.


Prerequisites

  • Bitwarden CLI installed in C:\Tools\Bitwarden (or your chosen directory)
  • Windows PowerShell (works with PowerShell 5.x)
  • Navigate to the Bitwarden directory in a Windows Terminal: cd C:\Tools\Bitwarden


Initial Setup (Required for All Operations)


1. Login to Bitwarden

.\bw login

Enter your email, master password, and 2FA code when prompted.


2. Unlock the Vault and Store Your Session

You already logged in, but you still need to unlock and capture the session token.

Run this EXACT command:

$env:BW_SESSION = .\bw unlock --raw

You will be prompted for your master password again.

When it completes, your environment variable will be set.


3. Verify Session is Active

Check it:

$env:BW_SESSION

You should see a long base64-like token.

❗ If You See Nothing Printed

That means unlocking failed.

If unlocking failed, run:

.\bw unlock --raw

Copy the output token manually and set it:

$env:BW_SESSION = "PASTE_TOKEN_HERE"

Then verify again:

$env:BW_SESSION



Part 1: Remove Old Entries by Date


Step 1: Load All Items

$items = .\bw list items --session $env:BW_SESSION | ConvertFrom-Json


Step 2: Filter Items Older Than Specific Date

# Set your cutoff date (change as needed)
$cutoff = Get-Date '2023-01-01'

# Filter for login items (type 1) older than cutoff
$old = $items | Where-Object { 
    $_.type -eq 1 -and 
    ([datetime]$_.revisionDate) -lt $cutoff 
} | Select-Object name, username, revisionDate, id

One-line version (easier to paste):

$cutoff = Get-Date '2023-01-01'; $old = $items | Where-Object { $_.type -eq 1 -and ([datetime]$_.revisionDate) -lt $cutoff } | Select-Object name, username, revisionDate, id


Step 3: Review What Will Be Deleted

$old | Format-Table -AutoSize
$old.Count


Step 4: Delete Old Items (Moves to Trash)

⚠️ WARNING: Review the list carefully first!

$old.id | ForEach-Object { 
    .\bw delete item $_ --session $env:BW_SESSION 
}


Part 2: Remove Duplicate Entries


Step 1: Load Items (if not already loaded)

$items = .\bw list items --session $env:BW_SESSION | ConvertFrom-Json
$logins = $items | Where-Object { $_.type -eq 1 }


Step 2: Find Duplicate Groups

Groups by username + item name to identify duplicates:

$dupeGroups = $logins | Group-Object -Property {
    # username (lowercased, safe if null)
    $u = ''
    if ($_.login -and $null -ne $_.login.username) {
        $u = $_.login.username.ToLower()
    }

    # item name (lowercased, safe if null)
    $n = ''
    if ($_.name) {
        $n = $_.name.ToLower()
    }

    # key: username|name
    "$u|$n"
} | Where-Object { $_.Count -gt 1 }


Step 3: Extract Older Duplicates (Keep Newest)

$dupes = @()

foreach ($g in $dupeGroups) {
    # Sort newest → oldest by revisionDate
    $sorted = $g.Group | Sort-Object @{ Expression = { [datetime]$_.revisionDate }; Descending = $true }

    if ($sorted.Count -gt 1) {
        # Skip index 0 (newest), keep the rest
        $dupes += $sorted[1..($sorted.Count - 1)]
    }
}


Step 4: Review Duplicates

$dupes | Select-Object `
    name,
    @{Name='username'; Expression = { if ($_.login) { $_.login.username } }},
    revisionDate,
    id | Format-Table -AutoSize

$dupes.Count


Step 5: Delete Duplicates (Moves to Trash)

$dupes.id | ForEach-Object {
    .\bw delete item $_ --session $env:BW_SESSION
}



Part 3: Final Cleanup

Permanently Delete Items from Trash

⚠️ FINAL WARNING: This is permanent and cannot be undone!

Only after verifying in the Bitwarden UI that trash contains only items you want gone:

.\bw delete items --permanent --session $env:BW_SESSION

Sync Your Vault

.\bw sync --session $env:BW_SESSION



Critical Notes & Troubleshooting

Always Use .\bw

  • ❌ Wrong: bw login
  • ✅ Correct: .\bw login

PowerShell doesn't load commands from the current directory by default unless you use .\

Avoid Reserved Variable Names

  • Never use $host in scripts (it's a PowerShell automatic variable)
  • The duplicate script uses $u and $n to avoid this conflict

Item Types

  • $_.type -eq 1 = Login items
  • $_.type -eq 2 = Secure notes
  • $_.type -eq 3 = Card items
  • $_.type -eq 4 = Identity items

Adjusting Cutoff Dates

Change the date in these examples as needed:

$cutoff = Get-Date '2022-01-01'  # Older than 2022
$cutoff = Get-Date '2020-01-01'  # Older than 2020
$cutoff = Get-Date '2024-06-01'  # Older than mid-2024



Safety Best Practices

1. Export Before Bulk Deletion

.\bw export --format json --session $env:BW_SESSION > backup.json

2. Test with Small Batches First

# Test with first 5 items
$old = $old | Select-Object -First 5

3. Review Trash Before Permanent Delete

  • Open Bitwarden web vault or desktop app
  • Check the Trash folder
  • Verify nothing important is there
  • Then run the permanent delete command

4. Items Go to Trash First

Deleted items aren't gone immediately - they go to Trash where you can:

  • Review them
  • Restore if needed
  • Permanently delete when ready



Quick Reference


Complete Old Item Cleanup (One Session)

# 1. Setup
cd C:\Tools\Bitwarden
$env:BW_SESSION = .\bw unlock --raw

# 2. Filter & Review
$items = .\bw list items --session $env:BW_SESSION | ConvertFrom-Json
$cutoff = Get-Date '2023-01-01'
$old = $items | Where-Object { $_.type -eq 1 -and ([datetime]$_.revisionDate) -lt $cutoff } | Select-Object name, username, revisionDate, id
$old | Format-Table -AutoSize

# 3. Delete (after review)
$old.id | ForEach-Object { .\bw delete item $_ --session $env:BW_SESSION }


Session Management

If your session expires during work:

$env:BW_SESSION = .\bw unlock --raw

To check if session is active:

$env:BW_SESSION  # Should show a token



Common Issues & Solutions


"bw: The term 'bw' is not recognized"

Solution: Use .\bw instead of just bw

"error: option '--session <session>' argument missing"

Solution: Your session isn't set or has expired. Run:

$env:BW_SESSION = .\bw unlock --raw

"Cannot overwrite variable Host"

Solution: Script has been fixed to avoid using $host variable name

Session Expired

Solution: Run $env:BW_SESSION = .\bw unlock --raw again

Empty Results When Filtering

Solution: Check your date format and verify items exist in that date range:

$items | Select-Object name, revisionDate | Sort-Object revisionDate | Format-Table

Nothing Appears After $env:BW_SESSION

Solution: Unlock failed. Manually unlock and copy the token:

.\bw unlock --raw
# Copy the token output
$env:BW_SESSION = "PASTE_TOKEN_HERE"


Important Reminders


  • Login vs Unlock: Login authenticates you; unlock creates a session. You need both.
  • Session per PowerShell Window: Each new PowerShell window needs its own unlock.
  • Trash is Your Friend: All deletes go to trash first - nothing is permanent until you explicitly purge.
  • Test First: Always review with Format-Table before running delete commands.
  • Export for Safety: Create a backup export before any bulk cleanup operation.


Created & Maintained by Pacific Northwest Computers



📞 Pacific Northwest Computers offers Remote & Onsite Support Across: 

SW Washington including Vancouver WA, Battle Ground WA, Camas WA, Washougal WA, Longview WA, Kelso WA, and Portland OR 

No comments:

Post a Comment