Manage FileVault Encryption on macOS
FileVault provides full-disk encryption for macOS devices, protecting sensitive data even if the device is lost or stolen. This tutorial shows how to automate FileVault management across your MacFleet using command-line scripts.
Understanding FileVault
FileVault encrypts the entire startup disk using XTS-AES-128 encryption with a 256-bit key. Key benefits include:
- Data Protection - Encrypts all data on the startup disk
- Compliance - Meets enterprise security requirements
- Performance - Hardware-accelerated encryption on modern Macs
- Recovery - Multiple recovery options available
Basic FileVault Commands
Check FileVault Status
#!/bin/bash
# Check current FileVault status
fdesetup status
# Get detailed encryption information
diskutil apfs listCryptoUsers /
Enable FileVault
#!/bin/bash
# Basic FileVault enable command
sudo fdesetup enable --user "username" --password "password"
# Enable with specific keychain
sudo fdesetup enable --user "username" --password "password" --keychain /Library/Keychains/System.keychain
Disable FileVault
#!/bin/bash
# Basic FileVault disable command
sudo fdesetup disable --user "username" --password "password"
Enterprise FileVault Management Script
Complete script for managing FileVault across your MacFleet:
#!/bin/bash
# FileVault Management Script for MacFleet
# Compatible with macOS 10.14+
# Configuration
LOG_FILE="/var/log/filevault_management.log"
KEYCHAIN_PATH="/Library/Keychains/System.keychain"
# Function to log messages
log_message() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOG_FILE"
}
# Function to get current user
get_current_user() {
stat -f "%Su" /dev/console
}
# Function to check if user has secure token
check_secure_token() {
local username="$1"
if sysadminctl -secureTokenStatus "$username" 2>/dev/null | grep -q "ENABLED"; then
return 0
else
return 1
fi
}
# Function to check FileVault status
check_filevault_status() {
local status
status=$(fdesetup status)
if echo "$status" | grep -q "FileVault is On"; then
echo "enabled"
elif echo "$status" | grep -q "FileVault is Off"; then
echo "disabled"
elif echo "$status" | grep -q "Encryption in progress"; then
echo "encrypting"
elif echo "$status" | grep -q "Decryption in progress"; then
echo "decrypting"
else
echo "unknown"
fi
}
# Function to get encryption progress
get_encryption_progress() {
fdesetup status | grep -o '[0-9]\+%' | head -1
}
# Function to validate user credentials
validate_user_credentials() {
local username="$1"
local password="$2"
# Check if user exists
if ! id "$username" &>/dev/null; then
log_message "✗ User does not exist: $username"
return 1
fi
# Check if user has admin privileges
if ! dsmemberutil checkmembership -U "$username" -G admin &>/dev/null; then
log_message "✗ User is not an administrator: $username"
return 1
fi
# Check if user has secure token
if ! check_secure_token "$username"; then
log_message "✗ User does not have secure token: $username"
return 1
fi
# Verify password (basic check)
if [[ -z "$password" ]]; then
log_message "✗ Password cannot be empty for user: $username"
return 1
fi
log_message "✓ User credentials validated: $username"
return 0
}
# Function to enable FileVault
enable_filevault() {
local username="$1"
local password="$2"
local force_enable="$3"
log_message "Starting FileVault enablement for user: $username"
# Check current status
local current_status
current_status=$(check_filevault_status)
case "$current_status" in
"enabled")
log_message "! FileVault is already enabled"
if [[ "$force_enable" != "true" ]]; then
return 0
fi
;;
"encrypting")
log_message "! FileVault encryption is already in progress"
local progress
progress=$(get_encryption_progress)
log_message " Encryption progress: ${progress:-Unknown}"
return 0
;;
"decrypting")
log_message "✗ Cannot enable FileVault while decryption is in progress"
return 1
;;
esac
# Validate user credentials
if ! validate_user_credentials "$username" "$password"; then
return 1
fi
# Enable FileVault
log_message "Enabling FileVault..."
if fdesetup enable -user "$username" -password "$password" -keychain "$KEYCHAIN_PATH" 2>/dev/null; then
log_message "✓ FileVault enable command executed successfully"
# Wait a moment and check status
sleep 5
local new_status
new_status=$(check_filevault_status)
case "$new_status" in
"enabled")
log_message "✓ FileVault is now enabled"
;;
"encrypting")
local progress
progress=$(get_encryption_progress)
log_message "✓ FileVault encryption started (${progress:-0%})"
;;
*)
log_message "! FileVault status unclear: $new_status"
;;
esac
return 0
else
log_message "✗ Failed to enable FileVault"
return 1
fi
}
# Function to disable FileVault
disable_filevault() {
local username="$1"
local password="$2"
local force_disable="$3"
log_message "Starting FileVault disablement for user: $username"
# Check current status
local current_status
current_status=$(check_filevault_status)
case "$current_status" in
"disabled")
log_message "! FileVault is already disabled"
if [[ "$force_disable" != "true" ]]; then
return 0
fi
;;
"decrypting")
log_message "! FileVault decryption is already in progress"
local progress
progress=$(get_encryption_progress)
log_message " Decryption progress: ${progress:-Unknown}"
return 0
;;
"encrypting")
log_message "✗ Cannot disable FileVault while encryption is in progress"
return 1
;;
esac
# Validate user credentials
if ! validate_user_credentials "$username" "$password"; then
return 1
fi
# Disable FileVault
log_message "Disabling FileVault..."
if fdesetup disable -user "$username" -password "$password" 2>/dev/null; then
log_message "✓ FileVault disable command executed successfully"
# Wait a moment and check status
sleep 5
local new_status
new_status=$(check_filevault_status)
case "$new_status" in
"disabled")
log_message "✓ FileVault is now disabled"
;;
"decrypting")
local progress
progress=$(get_encryption_progress)
log_message "✓ FileVault decryption started (${progress:-0%})"
;;
*)
log_message "! FileVault status unclear: $new_status"
;;
esac
return 0
else
log_message "✗ Failed to disable FileVault"
return 1
fi
}
# Function to get system information
get_system_info() {
log_message "=== System Information ==="
log_message "Hostname: $(hostname)"
log_message "macOS Version: $(sw_vers -productVersion)"
log_message "Current User: $(get_current_user)"
log_message "FileVault Status: $(check_filevault_status)"
# Get FileVault users
local fv_users
fv_users=$(fdesetup list 2>/dev/null)
if [[ -n "$fv_users" ]]; then
log_message "FileVault Enabled Users:"
echo "$fv_users" | while read -r line; do
log_message " $line"
done
fi
}
# Function to display usage
usage() {
echo "Usage: $0 {enable|disable|status} [options]"
echo ""
echo "Commands:"
echo " enable Enable FileVault"
echo " disable Disable FileVault"
echo " status Check FileVault status"
echo ""
echo "Options:"
echo " -u, --user USERNAME Specify username"
echo " -p, --password PASSWORD Specify password"
echo " -f, --force Force operation even if already in desired state"
echo " -h, --help Show this help message"
echo ""
echo "Examples:"
echo " $0 enable -u admin -p password123"
echo " $0 disable -u admin -p password123 -f"
echo " $0 status"
}
# Main function
main() {
local command="$1"
local username=""
local password=""
local force="false"
# Parse arguments
shift
while [[ $# -gt 0 ]]; do
case $1 in
-u|--user)
username="$2"
shift 2
;;
-p|--password)
password="$2"
shift 2
;;
-f|--force)
force="true"
shift
;;
-h|--help)
usage
exit 0
;;
*)
echo "Unknown option: $1"
usage
exit 1
;;
esac
done
# Execute command
case "$command" in
"enable")
if [[ -z "$username" ]] || [[ -z "$password" ]]; then
echo "Error: Username and password required for enable command"
usage
exit 1
fi
log_message "=== Starting FileVault Enable Operation ==="
get_system_info
if enable_filevault "$username" "$password" "$force"; then
log_message "=== FileVault Enable Operation Completed Successfully ==="
exit 0
else
log_message "=== FileVault Enable Operation Failed ==="
exit 1
fi
;;
"disable")
if [[ -z "$username" ]] || [[ -z "$password" ]]; then
echo "Error: Username and password required for disable command"
usage
exit 1
fi
log_message "=== Starting FileVault Disable Operation ==="
get_system_info
if disable_filevault "$username" "$password" "$force"; then
log_message "=== FileVault Disable Operation Completed Successfully ==="
exit 0
else
log_message "=== FileVault Disable Operation Failed ==="
exit 1
fi
;;
"status")
get_system_info
exit 0
;;
*)
echo "Error: Invalid command: $command"
usage
exit 1
;;
esac
}
# Execute main function
main "$@"
Quick FileVault Scripts
Simple Enable Script
#!/bin/bash
USERNAME="admin"
PASSWORD="your_password_here"
if fdesetup enable -user "$USERNAME" -password "$PASSWORD"; then
echo "FileVault enabled successfully"
else
echo "Failed to enable FileVault"
exit 1
fi
Simple Status Check
#!/bin/bash
STATUS=$(fdesetup status)
echo "FileVault Status: $STATUS"
if echo "$STATUS" | grep -q "FileVault is On"; then
echo "✓ FileVault is enabled"
exit 0
elif echo "$STATUS" | grep -q "FileVault is Off"; then
echo "✗ FileVault is disabled"
exit 1
else
echo "! FileVault status unclear"
exit 2
fi
Recovery Key Management
Generate Personal Recovery Key
#!/bin/bash
# Enable FileVault with personal recovery key
sudo fdesetup enable -user "$USERNAME" -password "$PASSWORD" -outputplist > /tmp/filevault_key.plist
# Extract recovery key
RECOVERY_KEY=$(grep -A1 "RecoveryKey" /tmp/filevault_key.plist | tail -1 | sed 's/.*<string>\(.*\)<\/string>.*/\1/')
echo "Recovery Key: $RECOVERY_KEY"
# Securely store recovery key
echo "$RECOVERY_KEY" | sudo tee /var/root/filevault_recovery_key.txt
sudo chmod 600 /var/root/filevault_recovery_key.txt
# Clean up
rm -f /tmp/filevault_key.plist
Enable Institutional Recovery Key
#!/bin/bash
# Create institutional recovery key
CERT_PATH="/path/to/institutional_certificate.cer"
if [[ -f "$CERT_PATH" ]]; then
sudo fdesetup enable -user "$USERNAME" -password "$PASSWORD" -certificate "$CERT_PATH"
echo "FileVault enabled with institutional recovery key"
else
echo "Institutional certificate not found: $CERT_PATH"
exit 1
fi
Troubleshooting Common Issues
Fix Secure Token Issues
#!/bin/bash
USERNAME="admin"
# Grant secure token to user
sudo sysadminctl -secureTokenOn "$USERNAME" -password -
# Verify secure token
if sysadminctl -secureTokenStatus "$USERNAME" | grep -q "ENABLED"; then
echo "✓ Secure token enabled for $USERNAME"
else
echo "✗ Failed to enable secure token for $USERNAME"
fi
Handle Blank Password Error
#!/bin/bash
USERNAME="admin"
# Check if user has a password set
if dscl . -read "/Users/$USERNAME" AuthenticationAuthority | grep -q "No such key"; then
echo "User $USERNAME has no password set"
echo "Setting password..."
sudo dscl . -passwd "/Users/$USERNAME" "" "new_password_here"
fi
Monitoring and Reporting
FileVault Status Report
#!/bin/bash
# Generate FileVault status report
REPORT_FILE="/tmp/filevault_report.txt"
{
echo "=== FileVault Status Report ==="
echo "Generated: $(date)"
echo "Hostname: $(hostname)"
echo ""
echo "=== FileVault Status ==="
fdesetup status
echo ""
echo "=== Enabled Users ==="
fdesetup list
echo ""
echo "=== Secure Token Status ==="
for user in $(dscl . -list /Users | grep -v '^_'); do
if [[ "$user" != "daemon" ]] && [[ "$user" != "nobody" ]]; then
token_status=$(sysadminctl -secureTokenStatus "$user" 2>/dev/null | grep -o "ENABLED\|DISABLED")
echo "User: $user - Token: ${token_status:-UNKNOWN}"
fi
done
} > "$REPORT_FILE"
echo "Report generated: $REPORT_FILE"
Common Error Solutions
Error | Cause | Solution |
---|---|---|
"Blank password" | User has no password | Set password with dscl . -passwd |
"Master keychain found" | Keychain ambiguity | Add -keychain parameter |
"Secure token required" | User lacks secure token | Grant token with sysadminctl |
"Already encrypted" | FileVault already on | Use -force or check status first |
"Encryption in progress" | Concurrent operation | Wait for completion |
Security Best Practices
- Use strong passwords for FileVault-enabled accounts
- Store recovery keys securely in enterprise key management
- Test scripts on isolated devices before fleet deployment
- Monitor encryption progress to ensure completion
- Backup recovery keys before making changes
- Validate user permissions before attempting operations
Performance Considerations
- Initial encryption can take several hours
- System performance may be impacted during encryption
- Schedule operations during maintenance windows
- Monitor disk space (encryption requires free space)
- Consider SSD vs HDD performance differences
Important Notes
- FileVault requires admin privileges and secure tokens
- Recovery keys are essential for data recovery
- Encryption/decryption cannot be interrupted safely
- Test all scripts thoroughly before production use
- Always have a backup recovery plan