Package Management with Homebrew on macOS
Streamline software deployment and package management across your MacFleet devices using Homebrew. This tutorial covers enterprise software installation, configuration management, compliance tracking, and automated deployment workflows for comprehensive fleet management.
Understanding Homebrew for Enterprise
Homebrew provides powerful package management for macOS:
- Formula packages - Command-line tools and libraries
- Cask applications - GUI applications and large binaries
- Tap repositories - Third-party package sources
- Bundle files - Declarative package manifests
- Services - Background daemon management
Basic Homebrew Installation
Install Homebrew
#!/bin/bash
# Install Homebrew package manager
install_homebrew() {
echo "=== Installing Homebrew Package Manager ==="
# Check if Homebrew is already installed
if command -v brew >/dev/null 2>&1; then
echo "✅ Homebrew already installed: $(brew --version | head -1)"
return 0
fi
echo "📦 Installing Homebrew..."
# Install Homebrew
if /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"; then
echo "✅ Homebrew installation completed"
# Add Homebrew to PATH for current session
if [[ -f "/opt/homebrew/bin/brew" ]]; then
eval "$(/opt/homebrew/bin/brew shellenv)"
elif [[ -f "/usr/local/bin/brew" ]]; then
eval "$(/usr/local/bin/brew shellenv)"
fi
# Verify installation
if command -v brew >/dev/null 2>&1; then
echo "🔍 Homebrew version: $(brew --version | head -1)"
return 0
else
echo "❌ Homebrew installation verification failed"
return 1
fi
else
echo "❌ Homebrew installation failed"
return 1
fi
}
# Execute installation
install_homebrew
Enhanced Package Installation Script
#!/bin/bash
# Enhanced package installation based on GitHub Gist
# Reference: https://gist.github.com/CliffordAnderson/817777b5dc0e67769e4b
enhanced_package_installation() {
echo "=== Enhanced Package Installation ==="
# Ensure Homebrew is installed
if ! command -v brew >/dev/null 2>&1; then
echo "❌ Homebrew not found. Installing..."
install_homebrew || return 1
fi
# Update Homebrew
echo "🔄 Updating Homebrew..."
brew update
# Programming Languages
echo "💻 Installing programming languages..."
brew install scala
brew install --cask r
brew install openjdk
# Development Tools
echo "🛠️ Installing development tools..."
brew install docker
brew install git
brew install --cask github
brew install --cask visual-studio-code
brew install --cask hyper
# Communication Apps
echo "💬 Installing communication apps..."
brew install --cask discord
brew install --cask microsoft-teams
brew install --cask slack
brew install --cask zoom
# Web Tools
echo "🌐 Installing web tools..."
brew install httpie
brew install node
brew install nvm
brew install --cask firefox
brew install --cask google-chrome
brew install --cask postman
# File Storage
echo "📁 Installing file storage tools..."
brew install --cask dropbox
brew install --cask onedrive
# Writing Apps
echo "✍️ Installing writing apps..."
brew install pandoc
brew install --cask zotero
brew install --cask microsoft-word
# Other Applications
echo "🎯 Installing additional applications..."
brew install --cask anki
echo "✅ Package installation completed"
}
# Execute enhanced installation
enhanced_package_installation
Enterprise Homebrew Management System
#!/bin/bash
# MacFleet Enterprise Homebrew Management System
# Comprehensive package deployment, compliance tracking, and fleet management
# Configuration
LOG_FILE="/var/log/macfleet_homebrew.log"
CONFIG_DIR="/etc/macfleet/packages"
PROFILES_DIR="$CONFIG_DIR/profiles"
CACHE_DIR="/var/cache/macfleet/homebrew"
REPORTS_DIR="$CONFIG_DIR/reports"
COMPLIANCE_DIR="$CONFIG_DIR/compliance"
# Package profiles for different roles
declare -A PACKAGE_PROFILES=(
["developer"]="git,node,python,docker,visual-studio-code,github,postman,hyper"
["designer"]="adobe-creative-cloud,figma,sketch,canva,affinity-designer,imageoptim"
["manager"]="microsoft-office,slack,zoom,teams,dropbox,onedrive,notion"
["analyst"]="r,python,tableau,microsoft-excel,jupyter-notebook,pandas"
["security"]="wireshark,nmap,burp-suite,malwarebytes,1password,gpg-suite"
["education"]="zoom,microsoft-office,rstudio,zotero,anki,mendeley"
["minimal"]="google-chrome,firefox,zoom,slack"
["corporate"]="microsoft-office,teams,onedrive,1password,chrome-enterprise"
)
# Compliance frameworks
declare -A COMPLIANCE_PACKAGES=(
["hipaa"]="1password,malwarebytes,gpg-suite,microsoft-office"
["sox"]="microsoft-office,1password,box-drive,tableau"
["gdpr"]="1password,gpg-suite,notion,signal"
["iso27001"]="1password,malwarebytes,gpg-suite,microsoft-defender"
)
# License tracking
declare -A LICENSE_REQUIRED=(
["microsoft-office"]="commercial"
["adobe-creative-cloud"]="commercial"
["tableau"]="commercial"
["sketch"]="commercial"
["1password"]="commercial"
["zoom"]="freemium"
["slack"]="freemium"
["notion"]="freemium"
)
# Logging function
log_action() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOG_FILE"
}
# Setup directories
setup_directories() {
for dir in "$CONFIG_DIR" "$PROFILES_DIR" "$CACHE_DIR" "$REPORTS_DIR" "$COMPLIANCE_DIR"; do
if [[ ! -d "$dir" ]]; then
mkdir -p "$dir"
log_action "Created directory: $dir"
fi
done
}
# Ensure Homebrew is installed and configured
ensure_homebrew() {
log_action "Ensuring Homebrew is properly configured"
# Check if Homebrew is installed
if ! command -v brew >/dev/null 2>&1; then
log_action "Installing Homebrew..."
if ! /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"; then
log_action "❌ Failed to install Homebrew"
return 1
fi
# Configure PATH
if [[ -f "/opt/homebrew/bin/brew" ]]; then
eval "$(/opt/homebrew/bin/brew shellenv)"
elif [[ -f "/usr/local/bin/brew" ]]; then
eval "$(/usr/local/bin/brew shellenv)"
fi
fi
# Update Homebrew
log_action "Updating Homebrew..."
brew update 2>/dev/null || log_action "⚠️ Homebrew update failed"
# Verify Homebrew health
if brew doctor >/dev/null 2>&1; then
log_action "✅ Homebrew health check passed"
else
log_action "⚠️ Homebrew health check issues detected"
fi
return 0
}
# Install packages from profile
install_package_profile() {
local profile_name="$1"
local dry_run="${2:-false}"
log_action "Installing package profile: $profile_name (dry_run: $dry_run)"
# Get profile packages
local profile_packages="${PACKAGE_PROFILES[$profile_name]}"
if [[ -z "$profile_packages" ]]; then
log_action "❌ Unknown profile: $profile_name"
return 1
fi
# Ensure Homebrew is ready
ensure_homebrew || return 1
# Parse packages
IFS=',' read -ra PACKAGES <<< "$profile_packages"
local success_count=0
local failure_count=0
local already_installed=0
for package in "${PACKAGES[@]}"; do
# Clean package name
package=$(echo "$package" | sed 's/^[ \t]*//;s/[ \t]*$//')
log_action "Processing package: $package"
if [[ "$dry_run" == "true" ]]; then
echo "Would install: $package"
continue
fi
# Check if already installed
if is_package_installed "$package"; then
log_action "✅ Package already installed: $package"
already_installed=$((already_installed + 1))
continue
fi
# Install package
if install_single_package "$package"; then
log_action "✅ Successfully installed: $package"
success_count=$((success_count + 1))
else
log_action "❌ Failed to install: $package"
failure_count=$((failure_count + 1))
fi
done
# Summary
log_action "Installation summary - Success: $success_count, Failed: $failure_count, Already installed: $already_installed"
# Generate installation report
generate_installation_report "$profile_name" "$success_count" "$failure_count" "$already_installed"
return 0
}
# Check if package is installed
is_package_installed() {
local package="$1"
# Check if it's a cask
if brew list --cask "$package" >/dev/null 2>&1; then
return 0
fi
# Check if it's a formula
if brew list "$package" >/dev/null 2>&1; then
return 0
fi
return 1
}
# Install single package
install_single_package() {
local package="$1"
# Try as cask first (for GUI applications)
if brew install --cask "$package" 2>/dev/null; then
return 0
fi
# Try as formula (for CLI tools)
if brew install "$package" 2>/dev/null; then
return 0
fi
return 1
}
# Generate comprehensive software inventory
generate_software_inventory() {
log_action "Generating comprehensive software inventory"
local inventory_file="$REPORTS_DIR/software_inventory_$(date '+%Y%m%d_%H%M%S').json"
cat > "$inventory_file" << EOF
{
"inventory_metadata": {
"timestamp": "$(date -Iseconds)",
"hostname": "$(hostname)",
"os_version": "$(sw_vers -productVersion)",
"homebrew_version": "$(brew --version | head -1)",
"generator": "MacFleet Homebrew Manager"
},
"installed_packages": {
"formulae": $(brew list --formula --json),
"casks": $(brew list --cask --json)
},
"package_summary": {
"total_formulae": $(brew list --formula | wc -l | tr -d ' '),
"total_casks": $(brew list --cask | wc -l | tr -d ' '),
"outdated_packages": $(brew outdated --json)
},
"system_info": {
"homebrew_prefix": "$(brew --prefix)",
"homebrew_cellar": "$(brew --cellar)",
"homebrew_cache": "$(brew --cache)"
}
}
EOF
log_action "✅ Software inventory generated: $inventory_file"
echo "$inventory_file"
}
# License compliance check
check_license_compliance() {
log_action "Checking license compliance for installed packages"
local compliance_report="$COMPLIANCE_DIR/license_compliance_$(date '+%Y%m%d_%H%M%S').json"
cat > "$compliance_report" << EOF
{
"compliance_metadata": {
"timestamp": "$(date -Iseconds)",
"hostname": "$(hostname)",
"check_type": "license_compliance"
},
"license_analysis": [
EOF
local first=true
local compliance_issues=0
# Check installed casks for license requirements
while IFS= read -r package; do
local license_type="${LICENSE_REQUIRED[$package]}"
if [[ -n "$license_type" ]]; then
if [[ "$first" == true ]]; then
first=false
else
echo "," >> "$compliance_report"
fi
local compliance_status="unknown"
local needs_attention=false
case "$license_type" in
"commercial")
compliance_status="requires_license"
needs_attention=true
compliance_issues=$((compliance_issues + 1))
;;
"freemium")
compliance_status="freemium_check_usage"
;;
esac
cat >> "$compliance_report" << EOF
{
"package": "$package",
"license_type": "$license_type",
"compliance_status": "$compliance_status",
"needs_attention": $needs_attention,
"installed_date": "$(brew list --cask --versions "$package" 2>/dev/null | awk '{print $2}' || echo 'unknown')"
}
EOF
fi
done < <(brew list --cask)
cat >> "$compliance_report" << EOF
],
"summary": {
"total_packages_checked": $(brew list --cask | wc -l | tr -d ' '),
"license_issues_found": $compliance_issues,
"compliance_status": "$([ $compliance_issues -eq 0 ] && echo 'compliant' || echo 'requires_attention')"
}
}
EOF
log_action "✅ License compliance check completed: $compliance_report"
echo "$compliance_report"
}
# Update all packages
update_all_packages() {
local update_mode="${1:-safe}" # safe, aggressive, or security-only
log_action "Starting package updates (mode: $update_mode)"
# Ensure Homebrew is ready
ensure_homebrew || return 1
# Update Homebrew itself
log_action "Updating Homebrew..."
if brew update; then
log_action "✅ Homebrew updated successfully"
else
log_action "❌ Homebrew update failed"
return 1
fi
# Get outdated packages
local outdated_formulae outdated_casks
outdated_formulae=$(brew outdated --formula --quiet)
outdated_casks=$(brew outdated --cask --quiet)
case "$update_mode" in
"safe")
# Update formulae only (CLI tools are generally safer to update)
if [[ -n "$outdated_formulae" ]]; then
log_action "Updating outdated formulae: $outdated_formulae"
brew upgrade
fi
;;
"aggressive")
# Update everything
if [[ -n "$outdated_formulae" ]]; then
log_action "Updating all outdated formulae"
brew upgrade
fi
if [[ -n "$outdated_casks" ]]; then
log_action "Updating all outdated casks"
brew upgrade --cask
fi
;;
"security-only")
# Only update packages with known security issues
# This would require integration with vulnerability databases
log_action "Security-only updates not yet implemented"
;;
esac
# Cleanup
log_action "Cleaning up old versions..."
brew cleanup
log_action "✅ Package updates completed"
# Generate post-update inventory
generate_software_inventory
}
# Generate Brewfile for current installation
generate_brewfile() {
local brewfile_path="${1:-$CONFIG_DIR/Brewfile}"
log_action "Generating Brewfile: $brewfile_path"
# Create Brewfile header
cat > "$brewfile_path" << EOF
# MacFleet Brewfile
# Generated on $(date)
# Hostname: $(hostname)
# Taps
EOF
# Add taps
brew tap | while read -r tap; do
echo "tap \"$tap\"" >> "$brewfile_path"
done
echo "" >> "$brewfile_path"
echo "# Formulae" >> "$brewfile_path"
# Add formulae
brew list --formula | while read -r formula; do
echo "brew \"$formula\"" >> "$brewfile_path"
done
echo "" >> "$brewfile_path"
echo "# Casks" >> "$brewfile_path"
# Add casks
brew list --cask | while read -r cask; do
echo "cask \"$cask\"" >> "$brewfile_path"
done
log_action "✅ Brewfile generated: $brewfile_path"
echo "$brewfile_path"
}
# Install from Brewfile
install_from_brewfile() {
local brewfile_path="$1"
local dry_run="${2:-false}"
if [[ ! -f "$brewfile_path" ]]; then
log_action "❌ Brewfile not found: $brewfile_path"
return 1
fi
log_action "Installing from Brewfile: $brewfile_path (dry_run: $dry_run)"
# Ensure Homebrew is ready
ensure_homebrew || return 1
if [[ "$dry_run" == "true" ]]; then
log_action "Dry run - would install packages from: $brewfile_path"
brew bundle --file="$brewfile_path" --verbose --no-install
else
# Install packages from Brewfile
if brew bundle --file="$brewfile_path"; then
log_action "✅ Brewfile installation completed"
return 0
else
log_action "❌ Brewfile installation failed"
return 1
fi
fi
}
# Security audit of installed packages
security_audit() {
log_action "Performing security audit of installed packages"
local audit_report="$REPORTS_DIR/security_audit_$(date '+%Y%m%d_%H%M%S').json"
cat > "$audit_report" << EOF
{
"audit_metadata": {
"timestamp": "$(date -Iseconds)",
"hostname": "$(hostname)",
"audit_type": "security"
},
"security_findings": [
EOF
local first=true
local security_issues=0
# Check for known vulnerable packages (simplified check)
# In production, this would integrate with CVE databases
local vulnerable_packages=("python@3.8" "node@14" "openssl@1.1")
for vuln_package in "${vulnerable_packages[@]}"; do
if is_package_installed "$vuln_package"; then
if [[ "$first" == true ]]; then
first=false
else
echo "," >> "$audit_report"
fi
cat >> "$audit_report" << EOF
{
"package": "$vuln_package",
"severity": "medium",
"issue": "potentially_outdated_version",
"recommendation": "update_to_latest_version",
"installed_version": "$(brew list --versions "$vuln_package" | awk '{print $2}')"
}
EOF
security_issues=$((security_issues + 1))
fi
done
cat >> "$audit_report" << EOF
],
"summary": {
"total_packages_audited": $(( $(brew list --formula | wc -l) + $(brew list --cask | wc -l) )),
"security_issues_found": $security_issues,
"security_status": "$([ $security_issues -eq 0 ] && echo 'secure' || echo 'requires_attention')"
}
}
EOF
log_action "✅ Security audit completed: $audit_report"
echo "$audit_report"
}
# Generate installation report
generate_installation_report() {
local profile_name="$1"
local success_count="$2"
local failure_count="$3"
local already_installed="$4"
local report_file="$REPORTS_DIR/installation_report_${profile_name}_$(date '+%Y%m%d_%H%M%S').json"
cat > "$report_file" << EOF
{
"installation_metadata": {
"timestamp": "$(date -Iseconds)",
"hostname": "$(hostname)",
"profile": "$profile_name",
"generator": "MacFleet Homebrew Manager"
},
"installation_results": {
"successful_installations": $success_count,
"failed_installations": $failure_count,
"already_installed": $already_installed,
"total_processed": $(( success_count + failure_count + already_installed ))
},
"post_installation_inventory": $(generate_software_inventory | tail -n +2 | head -n -1)
}
EOF
log_action "✅ Installation report generated: $report_file"
echo "$report_file"
}
# Main execution function
main() {
local action="${1:-inventory}"
local parameter="$2"
local additional_param="$3"
log_action "=== MacFleet Homebrew Management Started ==="
log_action "Action: $action"
log_action "Parameter: ${parameter:-N/A}"
setup_directories
case "$action" in
"install-profile")
if [[ -z "$parameter" ]]; then
echo "Available package profiles:"
for profile in "${!PACKAGE_PROFILES[@]}"; do
echo " - $profile: ${PACKAGE_PROFILES[$profile]}"
done
echo ""
echo "Usage: $0 install-profile <profile_name> [dry_run]"
exit 1
fi
install_package_profile "$parameter" "$additional_param"
;;
"inventory")
generate_software_inventory
;;
"update")
update_all_packages "$parameter"
;;
"compliance")
check_license_compliance
;;
"security")
security_audit
;;
"brewfile-generate")
generate_brewfile "$parameter"
;;
"brewfile-install")
if [[ -z "$parameter" ]]; then
echo "Usage: $0 brewfile-install <brewfile_path> [dry_run]"
exit 1
fi
install_from_brewfile "$parameter" "$additional_param"
;;
"ensure")
ensure_homebrew
;;
*)
echo "Usage: $0 {install-profile|inventory|update|compliance|security|brewfile-generate|brewfile-install|ensure}"
echo " install-profile - Install packages from predefined profile"
echo " inventory - Generate software inventory report"
echo " update - Update all packages (safe|aggressive|security-only)"
echo " compliance - Check license compliance"
echo " security - Perform security audit"
echo " brewfile-generate - Generate Brewfile from current installation"
echo " brewfile-install - Install packages from Brewfile"
echo " ensure - Ensure Homebrew is installed and configured"
exit 1
;;
esac
log_action "=== Homebrew management completed ==="
}
# Execute main function
main "$@"
Advanced Package Management Features
Custom Package Profile Creation
#!/bin/bash
# Create custom package profile
create_custom_profile() {
local profile_name="$1"
local packages="$2"
echo "=== Creating Custom Package Profile ==="
echo "Profile: $profile_name"
echo "Packages: $packages"
# Validate packages exist
IFS=',' read -ra PACKAGE_LIST <<< "$packages"
local valid_packages=()
for package in "${PACKAGE_LIST[@]}"; do
package=$(echo "$package" | sed 's/^[ \t]*//;s/[ \t]*$//')
# Check if package exists in Homebrew
if brew search --formula --cask "$package" | grep -q "^$package$"; then
valid_packages+=("$package")
echo "✅ Valid package: $package"
else
echo "⚠️ Package not found: $package"
fi
done
if [[ ${#valid_packages[@]} -eq 0 ]]; then
echo "❌ No valid packages found"
return 1
fi
# Create profile
local profile_packages
printf -v profile_packages '%s,' "${valid_packages[@]}"
profile_packages=${profile_packages%,} # Remove trailing comma
PACKAGE_PROFILES["$profile_name"]="$profile_packages"
echo "✅ Custom profile created: $profile_name"
echo "Packages: $profile_packages"
}
Automated License Management
#!/bin/bash
# Automated license management and tracking
manage_software_licenses() {
echo "=== Software License Management ==="
local license_db="$COMPLIANCE_DIR/license_database.json"
# Create license database if it doesn't exist
if [[ ! -f "$license_db" ]]; then
cat > "$license_db" << EOF
{
"license_metadata": {
"created": "$(date -Iseconds)",
"last_updated": "$(date -Iseconds)"
},
"licenses": {},
"compliance_rules": {}
}
EOF
fi
# Scan for commercial software
local commercial_software=()
while IFS= read -r package; do
if [[ -n "${LICENSE_REQUIRED[$package]}" ]]; then
commercial_software+=("$package")
fi
done < <(brew list --cask)
echo "Found ${#commercial_software[@]} packages requiring license management:"
printf '%s\n' "${commercial_software[@]}"
# Generate license report
local license_report="$REPORTS_DIR/license_report_$(date '+%Y%m%d_%H%M%S').json"
cat > "$license_report" << EOF
{
"license_report_metadata": {
"timestamp": "$(date -Iseconds)",
"hostname": "$(hostname)"
},
"commercial_software": [
EOF
local first=true
for package in "${commercial_software[@]}"; do
if [[ "$first" == true ]]; then
first=false
else
echo "," >> "$license_report"
fi
cat >> "$license_report" << EOF
{
"package": "$package",
"license_type": "${LICENSE_REQUIRED[$package]}",
"installed_version": "$(brew list --cask --versions "$package" 2>/dev/null | awk '{print $2}' || echo 'unknown')",
"license_status": "requires_verification"
}
EOF
done
cat >> "$license_report" << EOF
]
}
EOF
echo "📋 License report generated: $license_report"
}
Best Practices
🚀 Enterprise Deployment
- Profile-based installations for different user roles and departments
- Centralized package management with Brewfile deployment across fleets
- Automated software inventory tracking and reporting
- License compliance monitoring with automated auditing
🔐 Security Management
- Regular security audits of installed packages and dependencies
- Vulnerability scanning integration with CVE databases
- Package signature verification and trusted source validation
- Controlled update deployment with testing phases
📋 Compliance and Governance
- License tracking for commercial software compliance
- Policy enforcement based on organizational requirements
- Audit trails for all package installations and updates
- Cost management through license optimization
🔧 Maintenance and Optimization
- Automated updates with rollback capabilities
- Cleanup and optimization to manage disk space
- Performance monitoring of package management operations
- Custom profile creation for specialized use cases
Important Notes
- Test deployments in staging environments before production rollout
- Backup configurations before major package updates
- Monitor license compliance to avoid legal and financial risks
- Regular inventory audits to maintain accurate software tracking
- Network bandwidth considerations for large-scale deployments
- User communication for software changes and updates
Integration with Enterprise Systems
The Homebrew management system can be integrated with:
- MDM solutions for policy enforcement
- Asset management systems for inventory tracking
- License management platforms for compliance automation
- Security tools for vulnerability assessment
- Monitoring systems for deployment tracking