I am having trouble automating backup of vault attachments.
My script is below. It is split into two as I backup for multiple family members. The parent script passes credentials for each user to the common backup script.
For each attachment it displays: “Attachment vault was not found.”
The same general logic works when exporting each organization.
It also works when executed manually.
I would like to automate this. What am I missing here?
Until I resolve this I am running the script with the attachment section disabled.
Thanks and best regards.
export.sh
#!/bin/bash
# Bitwarden CLI vault export
BW_CLIENTID='<retracted>'
BW_CLIENTSECRET='<retracted>'
BW_PASSWORD='<retracted>'
BW_ENC_PW='<retracted>'
USER='<retracted>'
./_export.sh "$BW_CLIENTID" "$BW_CLIENTSECRET" "$BW_PASSWORD" "$BW_ENC_PW" "$USER"
<other users retracted>
````Preformatted text`
_export.sh
==========
#!/bin/bash
# Bitwarden CLI vault export
export BW_CLIENTID="$1"
export BW_CLIENTSECRET="$2"
export BW_PASSWORD="$3"
export BW_ENC_PW="$4"
USER="$5"
TIMESTAMP=$(date +%Y%m%d%S)
export EXPORT_PATH=backups/$USER/$TIMESTAMP
EXPORT_ATTACHMENT=backups/$USER/attachments
EXPORT_FILE=vault_enc.json
save_folder_attachments=backups/$USER/attachments
LOG=$EXPORT_PATH/export.log
mkdir -p $EXPORT_PATH
# Check whether jq is installed.
if [ ! -x "$(command -v jq)" ]; then
echo 'Error: jq is not installed.' >> $LOG
exit 1
fi
# Check whether bw CLI is available.
if [ ! -f ./bw ]; then
echo 'bw does not exist. Downloading...' >> $LOG
curl -JLs "https://vault.bitwarden.com/download/?app=cli&platform=linux" -o bw.zip
unzip -oq bw.zip
rm bw.zip
chmod +x ./bw
fi
# Check whether already logged in.
if ./bw login --check > /dev/null 2>&1; then
echo "Already logged in. Logging out..." >> $LOG
./bw logout > /dev/null >> $LOG
fi
# Login
echo "Login..." >> $LOG
./bw login --apikey >> $LOG
echo >> $LOG
# Unlock
echo "Unlock vault..." >> $LOG
export BW_SESSION=$(./bw unlock --passwordenv BW_PASSWORD)
# Export vault
echo "Export vault..." >> $LOG
./bw export --session $BW_SESSION --format encrypted_json --password $BW_ENC_PW --output $EXPORT_PATH/$EXPORT_FILE >> $LOG
echo >> $LOG
# Check for attachments
if [[ $(./bw list items --session $BW_SESSION | jq -r '.[] | select(.attachments != null)') != "" ]] then
echo "Export attachments"
# FAILING HERE
bash <(./bw list items --session $BW_SESSION | jq -r '.[]
| select(.attachments != null)
| "./bw get attachment --session $BW_SESSION \"\(.attachments[].fileName)\" --itemid \"\(.id)\" --output \"'$EXPORT_PATH'/attachments/\(.name)\""')
fi
# Check for organizations
if [[ $(./bw list organizations --session $BW_SESSION | jq -r '.[]') != "" ]] then
echo "Export organizations..." >> $LOG
bash <(./bw list organizations --session $BW_SESSION | jq -r '.[]
| "./bw export --session $BW_SESSION --organizationid \"\(.id)\" --format encrypted_json --password $BW_ENC_PW --output \"$EXPORT_PATH/org/\(.name)/org_enc.json\""') >> $LOG
echo >> $LOG
else
echo "There are no organizations." >> $LOG
fi
./bw logout >> $LOG
echo >> $LOG
# Remove exported variables
unset BW_CLIENTID
unset BW_CLIENTSECRET
unset BW_PASSWORD
unset BW_SESSION
$ ./test.sh
Attachment `vault` was not found.
Attachment `vault` was not found.
Attachment `vault` was not found.
Attachment `vault` was not found.
Attachment `vault` was not found.
Attachment `vault` was not found.
Attachment `vault` was not found.
Attachment `vault` was not found.
Attachment `vault` was not found.
Attachment `vault` was not found.
Attachment `vault` was not found.
Attachment `vault` was not found.
Attachment `vault` was not found.
Attachment `vault` was not found.
Attachment `vault` was not found.
What version of BW CLI are you using? My version shows 2025.1.3.
And if I run it in bash, the 3 attachments in my test vault get downloaded (with the item name as the downloaded filename; which in my case, it results, in the third attachment overwritting the second one; as I have an item that has two attachments).
I’m using the same version of bw cli than you (the latest available).
I don’t understand you: doest it work or does it not???
As I do not manually login or have BW_SESSION previously set it prompts from my master password for each and every attachment. In that sense it does work, though it is not the desired behavior.
The objective is to automate and schedule backups (for multiple accounts), so manually logging in and configuring BW_SESSION is not practical.
Are you able to export attachments without previously logging in or having BW_SESSION set?
Meaning 1) login, 2) set / export BW_SESSION, and 3) export attached from within the same script.
What is the output of the bw list items command that you feed to bash??
$ export EXPORT_PATH=/tmp/test2delete/
$ ./bw list items --session $BW_SESSION | jq -r '.[] | select(.attachments != null) | "/.bw get attachment --session $BW_SESSION \"\(.attachments[].fileName)\" --itemid \"\(.id)\"
--output \"'$EXPORT_PATH'/attachments/\(.name)\""'
You are not logged in.
After manually logging in, setting BW_SESSION, and retrying…
It does not matter at all, as long as the vault is unlocked and BW_SESSION is set correctly. And yours, as mine, is correctly set, or else the list items command would fail.
I don’t know what else to tell you, I have no idea why it does work for me but not for you. I’m guessing the problem must be in the parts that you redacted.
As far as I can see, the only significant difference is whether BW_SESSION is externally being set in advance or set within the script. I would expect that export is making the variable visible in the jq-bw dynamic scope, but that may be failing. Strangely though this same logic works fine for exporting organizations though. So it may be something specific to attachments.
I found the problem. The unlock command was missing the --raw argument resulting in BW_SESSION being set to junk. It should be: export BW_SESSION=$(./bw unlock --passwordenv BW_PASSWORD --raw)