Tutorial

Nuevas actualizaciones y mejoras para Roundfleet.

Aviso importante

Los ejemplos de código y scripts proporcionados en estos tutoriales son solo para propósitos educativos. Roundfleet no es responsable de ningún problema, daño o vulnerabilidad de seguridad que pueda surgir del uso, modificación o implementación de estos ejemplos. Siempre revisa y prueba el código en un entorno seguro antes de usarlo en sistemas de producción.

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.