159 lines
6.6 KiB
PowerShell
159 lines
6.6 KiB
PowerShell
param (
|
|
[switch]$zip,
|
|
[switch]$encrypt,
|
|
[switch]$verbose
|
|
)
|
|
|
|
# Verbose output
|
|
if ($verbose) {
|
|
$VerbosePreference = "continue"
|
|
}
|
|
|
|
# get the date/time for the back filename
|
|
$dateTime = Get-Date -format ("yyyyMMdd-HHmmss")
|
|
# set the binaries path, do not rely on the path variables as they are not hashed
|
|
$bw = "$PSScriptRoot\lib\bw.exe"
|
|
$gpg = "$PSScriptRoot\lib\gpg\bin\gpg.exe"
|
|
$sdelete = "$PSScriptRoot\lib\sdelete.exe"
|
|
|
|
# set bitwarden server to my self hosted instance
|
|
#& $bw config server https://bitwarden.johnhgaunt.com
|
|
|
|
# begin while loop to login, if login is incorrect, ask user again
|
|
while ($true) {
|
|
# ask for api client id/secret and password
|
|
$clientID = Read-Host "Please enter your Bitwarden API client_id"
|
|
$env:BW_CLIENTID = "$clientID"
|
|
$clientSecret = Read-Host -assecurestring "Please enter your bitwarden API client_secret"
|
|
$clientSecret = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($clientSecret))
|
|
$env:BW_CLIENTSECRET = "$clientSecret"
|
|
# test login
|
|
& $bw login --apikey --raw
|
|
$bwStatus = $(ConvertFrom-Json $(& $bw status))
|
|
if ($bwStatus."Status" -eq "locked") {
|
|
# Authentication was successful
|
|
# start new loop for password unlock
|
|
while ($true) {
|
|
$password = Read-Host -assecurestring "Please enter your Bitwarden password"
|
|
$password = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($password))
|
|
$sessionKey = $(& $bw unlock $password --raw --nointeraction)
|
|
# get the bw status to see if the login was successfull and inform user
|
|
$bwStatus = $(ConvertFrom-Json $(& $bw status --session $sessionKey))
|
|
if ($bwStatus."Status" -eq "unlocked") {
|
|
$username = $bwStatus."userEmail"
|
|
break
|
|
} else {
|
|
# just writing a new line
|
|
Write-Host " "
|
|
Write-Warning "Unable to unlock your vault, please try agian."
|
|
}
|
|
}
|
|
break
|
|
} else {
|
|
Write-Host " "
|
|
Write-Warning "Unable to authenticate, please try agian."
|
|
}
|
|
}
|
|
|
|
# Export the vault to both CSV and JSON files, this allows best compatibility to import again or switch managers.
|
|
Write-Host "Exporting vault to both CSV and JSON files."
|
|
Write-Verbose "Exporting vault to CSV."
|
|
& $bw export $password --output "$PSScriptRoot\Bitwarden User $username Export $dateTime.csv" --format csv --session $sessionKey
|
|
# just writing a new line
|
|
Write-Host " "
|
|
Write-Verbose "Exporting vault to JSON."
|
|
& $bw export $password --output "$PSScriptRoot\Bitwarden User $username Export $dateTime.json" --format json --session $sessionKey
|
|
# just writing a new line
|
|
Write-Host " "
|
|
|
|
# look for organizations
|
|
Write-Host "Looking for Organizations..."
|
|
$organizations = $(ConvertFrom-Json $(& $bw list organizations --session $sessionKey))
|
|
Write-Host "Found $(($organizations | Measure-Object).count) Organiztaions."
|
|
|
|
# loop through the found organizations and again export both as CSV and JSON for best compatibility
|
|
$organizations | ForEach-Object {
|
|
Write-Host "Exporting organization $($_.name) vault to both CSV and JSON files."
|
|
Write-Verbose "Exporting organization vault to CSV."
|
|
& $bw export $password --organizationid $_.id --output "$PSScriptRoot\Bitwarden Organization $($_.name) Export $dateTime.csv" --format csv --session $sessionKey
|
|
# just writing a new line
|
|
Write-Host " "
|
|
Write-Verbose "Exporting organization vault to JSON."
|
|
& $bw export $password --organizationid $_.id --output "$PSScriptRoot\Bitwarden Organization $($_.name) Export $dateTime.json" --format json --session $sessionKey
|
|
# just writing a new line
|
|
Write-Host " "
|
|
}
|
|
|
|
# find all items with attachments
|
|
Write-Host "Looking for items with attachments..."
|
|
$itemsWithAttachments = $((ConvertFrom-Json $(& $bw list items --session $sessionKey)) | Where-Object attachments)
|
|
Write-Host "Found $(($itemsWithAttachments | Measure-Object).count) items with attachments."
|
|
|
|
# loop through all the items with attachments and download them into a folder with the name of the item
|
|
Write-Host "Downloading attachments..."
|
|
$itemsWithAttachments | ForEach-Object {
|
|
Write-Verbose "Working on item $($_.name) ($($_.id))."
|
|
$folder="$PSScriptRoot\attachments\$($_.name)"
|
|
$itemID=$_.id
|
|
$_.attachments | ForEach-Object {
|
|
Write-Verbose "Downloading attachment ($($_.id)) with name $($_.fileName) to $folder."
|
|
& $bw get attachment $_.id --itemid $itemID --output "$folder\$($_.fileName)" --session $sessionKey
|
|
# just writing a new line
|
|
Write-Host " "
|
|
Start-Sleep -Milliseconds 500
|
|
}
|
|
}
|
|
|
|
# zip file name used below
|
|
$zipFilename = "Bitwarden Backup $dateTime.zip"
|
|
|
|
# if the user wants the export zipped or encrypted
|
|
if ($zip -or $encrypt) {
|
|
# zip the export
|
|
Write-Host "Zipping the backup together..."
|
|
Compress-Archive -Path $PSScriptRoot\*.csv, $PSScriptRoot\*.json, $PSScriptRoot\attachments -DestinationPath "$PSScriptRoot\$zipFilename"
|
|
# securely delete the export items with sdelete
|
|
Write-Host "Securely deleting the exports and attachments..."
|
|
& $sdelete -s -p 25 $PSScriptRoot\*.csv $PSScriptRoot\*.json $PSScriptRoot\attachments
|
|
|
|
# if encrypting the export
|
|
if ($encrypt) {
|
|
# encrypt the zip export with gpg
|
|
Write-Host "Encrypting the backup zip with your bitwarden password..."
|
|
& $gpg --no-options --batch --passphrase "$password" --symmetric --cipher-algo AES256 --digest-algo SHA512 --compression-algo Uncompressed --output "$PSScriptRoot\$zipFilename.gpg" "$PSScriptRoot\$zipFilename"
|
|
# securely delete the zip export with sdelete
|
|
Write-Host "Securely deleting the zip file..."
|
|
& $sdelete -p 25 "$PSScriptRoot\$zipFilename"
|
|
}
|
|
}
|
|
# logout of bitwaren to ensure the session is destroyed
|
|
& $bw logout
|
|
# remove all the variables
|
|
Remove-Variable -Name * -ErrorAction SilentlyContinue
|
|
|
|
|
|
|
|
<#
|
|
|
|
# Restore of attachements
|
|
|
|
cd C:\users\jgaunt\Git\bitwardenbackup\attachments
|
|
|
|
bw status
|
|
|
|
$folders = Get-childItem -Directory
|
|
$items = bw list items | convertfrom-json
|
|
$array = @()
|
|
foreach ($folder in $folders) {
|
|
foreach ($item in $items) {
|
|
if ($folder.name -eq $item.name -and $item.type -gt 1) {
|
|
#$array += bw get item $item.id | convertfrom-json
|
|
$attachements = Get-ChildItem $folder
|
|
foreach ($attachement in $attachements) {
|
|
bw create attachment --file "$($attachement.FullName)" --itemid $item.id
|
|
}
|
|
Remove-Item -Recurse $folder
|
|
}
|
|
}
|
|
}
|
|
#> |