Tutorial

New updates and improvements to Roundfleet.

Important notice

The code examples and scripts provided in these tutorials are for educational purposes only. Roundfleet is not responsible for any issues, damages, or security vulnerabilities that may arise from the use, modification, or implementation of these examples. Always review and test code in a secure environment before using it in production systems.

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 "Roundfleet 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-roundfleet-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/roundfleet_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 "Roundfleet 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 "Roundfleet App Version Alerts - $(hostname)" [email protected] < "$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.

Related Tutorials

Safari Browser Management on macOS

Learn how to configure Safari homepage, browser settings, security policies, and deploy enterprise browser management across your Roundfleet devices with comprehensive user management and compliance features.

Jul 7, 2025

Rosetta 2 and Apple Silicon Compatibility Management on macOS

Learn how to install, manage, and monitor Rosetta 2 translation layer on Apple Silicon Macs with enterprise-grade compatibility management, application monitoring, and fleet-wide deployment capabilities.

Jul 7, 2025

Package Management with Homebrew on macOS

Deploy, manage, and maintain software packages across macOS devices using Homebrew with enterprise-grade configuration management, compliance tracking, and automated deployment workflows.

Jul 7, 2025

Manage Kernel Extensions on macOS

Learn how to display, load, unload, and monitor kernel extensions (kexts) on macOS devices using command-line scripts for enhanced system management and security.

Jul 7, 2025

Install Unsigned Packages on macOS

Deploy and install unsigned PKG packages on Mac devices using scripts for specialized development tools and open-source software.

Jul 7, 2025

Install Latest Firefox Version on macOS Devices

Learn how to install and manage the latest Firefox version on macOS devices for enterprise deployment, updates, and configuration management.

Jul 7, 2025

Wi-Fi Network Management on macOS

Manage Wi-Fi networks, configure proxy settings, DNS servers, and implement enterprise network policies on macOS devices using advanced networksetup commands and centralized fleet management.

Jul 7, 2025

Wi-Fi Control on macOS

Comprehensive guide to controlling Wi-Fi settings on macOS devices using networksetup commands for enterprise wireless management, security policies, and power optimization across fleet deployments.

Jul 7, 2025