Homelab - Ensure external network shares stay connected on macOS.
This script was originally mentioned in my post: Homelab Chronicles: Chapter 4 but I wanted to expound on it.
macOS is a wonderful platform but connecting external network shares and keeping them connected can be a pain. If you browse the web, they mention you can drag the mounted Volume into the Login Items in System Settings but what do you do when there is an interruption? For example, the share restarts or there is an interruption in the network.
I was looking for a way to ensure that the SMB would reconnect automatically if and when it was disconnected from macOS.
Through a Shell script shown below, you can have it scheduled to run periodically. The high-level steps are:
Adding the entry is quite simple. Open the Terminal and execute the following command:
security add-generic-password -a your_username -s your_server_name_or_ip -w your_password -U
Copy the Shell script below to a location on your computer:
#!/bin/bash
# SMB details
SERVER_NAME=""
USER_NAME=""
SHARE_NAME=""
MOUNT_POINT="$HOME/Mounts/$SHARE_NAME"
# Retrieve credentials from Keychain
PASSWORD=$(security find-generic-password -a $USER_NAME -s $SERVER_NAME -w 2>/dev/null)
# Check if credentials are retrieved
if [ -z "$PASSWORD" ]; then
echo "$(date): Failed to retrieve credentials from Keychain. Exiting." >> ~/smb_reconnect.log
exit 1
fi
# Check if the mount_point exists and is already connected
if [ ! -d "$MOUNT_POINT" ] || ! mount | grep -q "//$USER_NAME@$SERVER_NAME/$SHARE_NAME on $MOUNT_POINT"; then
echo "$(date): Share is not mounted. Attempting to reconnect..." >> ~/smb_reconnect.log
# Ensure the mount point directory exists
if [ ! -d "$MOUNT_POINT" ]; then
mkdir -p "$MOUNT_POINT"
fi
# Attempt to mount the SMB share
mount_smbfs "//${USER_NAME}:${PASSWORD//@/%40}@${SERVER_NAME}/${SHARE_NAME}" "$MOUNT_POINT" 2>> ~/smb_reconnect.log
if [ $? -eq 0 ]; then
echo "$(date): Successfully reconnected to SMB share." >> ~/smb_reconnect.log
else
echo "$(date): Failed to reconnect to SMB share. Check if the SMB server is online." >> ~/smb_reconnect.log
fi
else
echo "$(date): Share is already mounted." >> ~/smb_reconnect.log
fi
Set the details in the variables at the front of the script.
Each step is added to a log file. By default it will save to your $HOME directory (~) under smb_reconnect.log. Set this to where you’d like the log file.
The script works by first retrieving the password from the Key vault. It then checks if the SMB is already mounted. Please note that this will not mount the SMB into the /Volumes directory if you mount it through Finder with the Cmd + K shortcut. It will mount it to the MOUNT_POINT directory. You may need to mount the drive manually through mount_smbfs in the Terminal to get this to work appropriately.
If it’s not connected, it will attempt to connect. Please note on the PASSWORD variable, it will do a special encoding if the password contains a : character. I had to do a lot of troubleshooting.
Ensure the script is executable by calling chmod on it:
chmod +x checksmb.sh
You could choose to execute the script through a cron job, but I chose to use the Apple way with a LaunchAgent command.
Create a text file under ~/Library/LaunchAgents/com.user.checksmb.plist with the following:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.user.checksmb</string>
<key>ProgramArguments</key>
<array>
<string>/bin/bash</string>
<string>/full/path/to/shell/script.sh</string>
</array>
<key>StartInterval</key>
<integer>300</integer> <!-- Runs every 5 minutes -->
<key>StandardOutPath</key>
<string>/full/path/to/standard/out/path.log</string>
<key>StandardErrorPath</key>
<string>/full/path/to/standard/error/path.log</string>
</dict>
</plist>
Finally the PLIST needs to be enabled. In the Terminal execute the following command:
launchctl load ~/Library/LaunchAgents/com.user.checksmb.plist
After this monitor the log file.