Get Versions of Installed Apps on macOS
Managing a Mac fleet requires keeping track of application versions across all devices. This tutorial shows you how to create and deploy scripts to retrieve application versions on macOS devices remotely.
Why Application Version Tracking Matters
Application version tracking is crucial for:
- Security compliance: Ensuring all devices run supported software versions
- License management: Tracking software deployments and compliance
- Update planning: Identifying devices that need application updates
- Support efficiency: Quickly identifying software versions during troubleshooting
- Inventory management: Maintaining accurate software asset records
Basic Application Version Retrieval
Using mdls Command
The mdls
command reads metadata attributes from files, including application version information stored in the kMDItemVersion
attribute.
#!/bin/bash
# Basic script to get application versions
applications=("Safari" "Mail" "Calendar" "Notes" "Contacts")
heading_printed=false
for app in "${applications[@]}"; do
version=$(mdls -name kMDItemVersion "/Applications/${app}.app" 2>/dev/null | grep -o '".*"' | sed 's/"//g')
if [ -z "$version" ]; then
echo "Unable to retrieve version for ${app}"
else
if [ "$heading_printed" = false ]; then
echo "Application Versions:"
heading_printed=true
fi
echo "${app}: ${version}"
fi
done
Enhanced Version Script with User Context
For applications installed in user-specific locations, you may need to run the script with user context:
#!/bin/bash
# Enhanced script with user context support
applications=("Safari" "Mail" "Calendar" "Notes" "Contacts" "Xcode" "Final Cut Pro")
current_user=$(whoami)
heading_printed=false
echo "Checking application versions for user: $current_user"
echo "Date: $(date)"
echo "----------------------------------------"
for app in "${applications[@]}"; do
# Try system Applications folder first
version=$(mdls -name kMDItemVersion "/Applications/${app}.app" 2>/dev/null | grep -o '".*"' | sed 's/"//g')
# If not found, try user Applications folder
if [ -z "$version" ]; then
version=$(mdls -name kMDItemVersion "/Users/$current_user/Applications/${app}.app" 2>/dev/null | grep -o '".*"' | sed 's/"//g')
fi
if [ -z "$version" ]; then
echo "❌ Unable to retrieve version for ${app}"
else
if [ "$heading_printed" = false ]; then
echo "Application Versions:"
heading_printed=true
fi
echo "✅ ${app}: ${version}"
fi
done
Advanced Application Inventory Scripts
Comprehensive Application Scanner
#!/bin/bash
# Comprehensive application version scanner
OUTPUT_FILE="/tmp/app_versions_$(date +%Y%m%d_%H%M%S).txt"
DEVICE_NAME=$(scutil --get ComputerName)
DEVICE_USER=$(whoami)
echo "MacFleet Application Version Report" > "$OUTPUT_FILE"
echo "=====================================" >> "$OUTPUT_FILE"
echo "Device: $DEVICE_NAME" >> "$OUTPUT_FILE"
echo "User: $DEVICE_USER" >> "$OUTPUT_FILE"
echo "Date: $(date)" >> "$OUTPUT_FILE"
echo "macOS Version: $(sw_vers -productVersion)" >> "$OUTPUT_FILE"
echo "" >> "$OUTPUT_FILE"
# Function to get app version and additional info
get_app_info() {
local app_path="$1"
local app_name=$(basename "$app_path" .app)
if [ -d "$app_path" ]; then
local version=$(mdls -name kMDItemVersion "$app_path" 2>/dev/null | grep -o '".*"' | sed 's/"//g')
local bundle_id=$(mdls -name kMDItemCFBundleIdentifier "$app_path" 2>/dev/null | grep -o '".*"' | sed 's/"//g')
local size=$(du -sh "$app_path" 2>/dev/null | cut -f1)
local modified=$(stat -f "%Sm" -t "%Y-%m-%d %H:%M:%S" "$app_path" 2>/dev/null)
if [ -n "$version" ]; then
echo "Application: $app_name" >> "$OUTPUT_FILE"
echo " Version: $version" >> "$OUTPUT_FILE"
echo " Bundle ID: $bundle_id" >> "$OUTPUT_FILE"
echo " Size: $size" >> "$OUTPUT_FILE"
echo " Modified: $modified" >> "$OUTPUT_FILE"
echo " Path: $app_path" >> "$OUTPUT_FILE"
echo "" >> "$OUTPUT_FILE"
fi
fi
}
# Scan system Applications folder
echo "System Applications:" >> "$OUTPUT_FILE"
echo "-------------------" >> "$OUTPUT_FILE"
if [ -d "/Applications" ]; then
for app in /Applications/*.app; do
get_app_info "$app"
done
fi
# Scan user Applications folder
echo "User Applications:" >> "$OUTPUT_FILE"
echo "-----------------" >> "$OUTPUT_FILE"
if [ -d "/Users/$DEVICE_USER/Applications" ]; then
for app in "/Users/$DEVICE_USER/Applications"/*.app; do
get_app_info "$app"
done
fi
# Scan Utilities folder
echo "Utilities:" >> "$OUTPUT_FILE"
echo "---------" >> "$OUTPUT_FILE"
if [ -d "/Applications/Utilities" ]; then
for app in "/Applications/Utilities"/*.app; do
get_app_info "$app"
done
fi
echo "Report generated: $OUTPUT_FILE"
echo "Total applications found: $(grep -c "Application:" "$OUTPUT_FILE")"
# Optional: Display the report
cat "$OUTPUT_FILE"
Specific Application Version Checker
#!/bin/bash
# Check specific applications commonly used in enterprise environments
declare -A enterprise_apps=(
["Microsoft Word"]="/Applications/Microsoft Word.app"
["Microsoft Excel"]="/Applications/Microsoft Excel.app"
["Microsoft PowerPoint"]="/Applications/Microsoft PowerPoint.app"
["Microsoft Outlook"]="/Applications/Microsoft Outlook.app"
["Adobe Photoshop 2024"]="/Applications/Adobe Photoshop 2024/Adobe Photoshop 2024.app"
["Adobe Illustrator 2024"]="/Applications/Adobe Illustrator 2024/Adobe Illustrator 2024.app"
["Slack"]="/Applications/Slack.app"
["Zoom"]="/Applications/zoom.us.app"
["Google Chrome"]="/Applications/Google Chrome.app"
["Firefox"]="/Applications/Firefox.app"
["Visual Studio Code"]="/Applications/Visual Studio Code.app"
["Docker Desktop"]="/Applications/Docker.app"
["Xcode"]="/Applications/Xcode.app"
)
echo "Application Version Check"
echo "==================================="
echo "Device: $(scutil --get ComputerName)"
echo "Date: $(date)"
echo ""
for app_name in "${!enterprise_apps[@]}"; do
app_path="${enterprise_apps[$app_name]}"
if [ -d "$app_path" ]; then
version=$(mdls -name kMDItemVersion "$app_path" 2>/dev/null | grep -o '".*"' | sed 's/"//g')
bundle_id=$(mdls -name kMDItemCFBundleIdentifier "$app_path" 2>/dev/null | grep -o '".*"' | sed 's/"//g')
if [ -n "$version" ]; then
echo "✅ $app_name: $version"
echo " Bundle ID: $bundle_id"
else
echo "⚠️ $app_name: Installed but version unavailable"
fi
else
echo "❌ $app_name: Not installed"
fi
done
# Check for critical security applications
echo ""
echo "Security Applications:"
echo "--------------------"
security_apps=("Antivirus One" "Malwarebytes" "CleanMyMac" "Little Snitch")
for app in "${security_apps[@]}"; do
if [ -d "/Applications/${app}.app" ]; then
version=$(mdls -name kMDItemVersion "/Applications/${app}.app" 2>/dev/null | grep -o '".*"' | sed 's/"//g')
echo "✅ $app: ${version:-Version unavailable}"
else
echo "❌ $app: Not installed"
fi
done
Remote Deployment Scripts
Multi-Device Version Collection
#!/bin/bash
# Script for collecting application versions from multiple Mac devices
# This script should be deployed to each device and results collected centrally
CENTRAL_SERVER="your-macfleet-server.com"
DEVICE_ID=$(system_profiler SPHardwareDataType | grep "Serial Number" | awk '{print $4}')
REPORT_FILE="/tmp/device_app_report_${DEVICE_ID}.json"
# Create JSON report
create_json_report() {
local device_name=$(scutil --get ComputerName)
local device_user=$(whoami)
local os_version=$(sw_vers -productVersion)
local timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
cat > "$REPORT_FILE" << EOF
{
"device_info": {
"device_id": "$DEVICE_ID",
"device_name": "$device_name",
"user": "$device_user",
"os_version": "$os_version",
"timestamp": "$timestamp"
},
"applications": [
EOF
local first_app=true
for app in /Applications/*.app; do
if [ -d "$app" ]; then
local app_name=$(basename "$app" .app)
local version=$(mdls -name kMDItemVersion "$app" 2>/dev/null | grep -o '".*"' | sed 's/"//g')
local bundle_id=$(mdls -name kMDItemCFBundleIdentifier "$app" 2>/dev/null | grep -o '".*"' | sed 's/"//g')
if [ -n "$version" ]; then
if [ "$first_app" = false ]; then
echo "," >> "$REPORT_FILE"
fi
cat >> "$REPORT_FILE" << EOF
{
"name": "$app_name",
"version": "$version",
"bundle_id": "$bundle_id",
"path": "$app"
}EOF
first_app=false
fi
fi
done
echo "" >> "$REPORT_FILE"
echo " ]" >> "$REPORT_FILE"
echo "}" >> "$REPORT_FILE"
}
# Create the report
create_json_report
# Display local results
echo "Application version report created: $REPORT_FILE"
echo "Device ID: $DEVICE_ID"
echo "Total applications: $(grep -c '"name":' "$REPORT_FILE")"
# Optional: Send to central server (uncomment if needed)
# curl -X POST -H "Content-Type: application/json" -d @"$REPORT_FILE" "https://$CENTRAL_SERVER/api/device-reports"
Automated Version Monitoring
#!/bin/bash
# Automated application version monitoring with alerting
ALERT_THRESHOLD_DAYS=30
LOG_FILE="/var/log/macfleet_app_monitor.log"
ALERT_FILE="/tmp/app_version_alerts.txt"
# Function to log messages
log_message() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOG_FILE"
}
# Function to check if app needs update
check_app_age() {
local app_path="$1"
local app_name=$(basename "$app_path" .app)
local modified_date=$(stat -f "%Sm" -t "%Y-%m-%d" "$app_path" 2>/dev/null)
if [ -n "$modified_date" ]; then
local days_old=$(( ($(date +%s) - $(date -j -f "%Y-%m-%d" "$modified_date" +%s)) / 86400 ))
if [ $days_old -gt $ALERT_THRESHOLD_DAYS ]; then
echo "⚠️ $app_name: Last modified $days_old days ago ($modified_date)" >> "$ALERT_FILE"
log_message "ALERT: $app_name is $days_old days old"
fi
fi
}
# Initialize alert file
echo "MacFleet Application Age Alerts" > "$ALERT_FILE"
echo "================================" >> "$ALERT_FILE"
echo "Generated: $(date)" >> "$ALERT_FILE"
echo "Threshold: $ALERT_THRESHOLD_DAYS days" >> "$ALERT_FILE"
echo "" >> "$ALERT_FILE"
log_message "Starting application version monitoring"
# Check critical applications
critical_apps=("Safari" "Mail" "Calendar" "Microsoft Word" "Microsoft Excel" "Google Chrome" "Slack" "Zoom")
for app in "${critical_apps[@]}"; do
if [ -d "/Applications/${app}.app" ]; then
check_app_age "/Applications/${app}.app"
version=$(mdls -name kMDItemVersion "/Applications/${app}.app" 2>/dev/null | grep -o '".*"' | sed 's/"//g')
log_message "Checked $app: Version $version"
else
log_message "WARNING: $app not found"
fi
done
# Display alerts if any
if [ -s "$ALERT_FILE" ] && [ $(wc -l < "$ALERT_FILE") -gt 4 ]; then
echo "⚠️ Application age alerts found:"
cat "$ALERT_FILE"
# Optional: Send alerts via email or notification service
# mail -s "MacFleet App Version Alerts - $(hostname)" admin@yourcompany.com < "$ALERT_FILE"
fi
log_message "Application version monitoring completed"
Best Practices for Mac Fleet Management
1. Regular Monitoring
- Schedule version checks weekly or bi-weekly
- Monitor critical business applications more frequently
- Track both system and user-installed applications
2. Version Standardization
- Maintain approved application version lists
- Create policies for automatic updates
- Document version compatibility requirements
3. Security Considerations
- Prioritize security updates for all applications
- Monitor for applications with known vulnerabilities
- Implement approval workflows for major version updates
4. Reporting and Analytics
- Generate regular compliance reports
- Track update deployment success rates
- Monitor application usage patterns
5. Automation Integration
- Integrate with configuration management tools
- Automate routine version checks
- Set up alerts for version discrepancies
Troubleshooting Common Issues
Issue: mdls Command Not Found
# Verify command availability
which mdls
# If not found, check system integrity
sudo /usr/bin/mdutil -i on /
Issue: Permission Denied
# Run with appropriate permissions
sudo -u [username] mdls -name kMDItemVersion "/Applications/AppName.app"
Issue: Version Information Unavailable
# Try alternative methods
defaults read "/Applications/AppName.app/Contents/Info.plist" CFBundleShortVersionString
plutil -p "/Applications/AppName.app/Contents/Info.plist" | grep -i version
Issue: Applications in Non-Standard Locations
# Search for applications system-wide
find /Applications /Users/*/Applications -name "*.app" -type d 2>/dev/null
Conclusion
Application version tracking is essential for maintaining a secure and compliant Mac fleet. These scripts provide a foundation for:
- Automated version discovery and reporting
- Compliance monitoring and alerting
- Security vulnerability assessment
- Software asset management
Regular implementation of these monitoring practices will help ensure your Mac fleet remains secure, compliant, and properly managed.
For more advanced Mac fleet management capabilities, consider integrating these scripts with your existing configuration management and monitoring tools.