Application Inventory: The Unsung Hero of macOS Security

In the ever-evolving threat landscape, keeping your organization’s macOS devices secure is paramount. While Mobile Device Management (MDM) solutions offer a valuable layer of control, a critical piece of the puzzle often gets overlooked: application inventory.

This blog post dives into the importance of a comprehensive application inventory for macOS devices, explores the limitations of MDM reporting, and highlights the security benefits gained from improved application visibility.


The Silent Threat: Unseen Applications

Imagine a blind spot in your home security system. That’s essentially what an incomplete application inventory creates for your macOS environment. MDM solutions often focus on device details and pre-approved applications.However, this leaves a gap for unauthorized applications, potentially exposing your network to vulnerabilities.

Malware can disguise itself as legitimate applications, making it crucial to have a complete picture of everything running on your Macs. Additionally, outdated or unmaintained software can pose security risks.

Beyond Pre-Approved Apps

While mostly all MDM excels at managing pre-approved applications, it often felt like a shortcoming when it comes to comprehensive application discovery. Here are some limitations to consider:

  • Limited Visibility: MDM might not report on all applications, especially those installed outside the designated channels (e.g., user downloads).
  • Version Control Challenges: Version tracking for discovered applications may be limited, making it difficult to identify outdated software with known vulnerabilities.
  • Static Reporting: MDM reports typically provide a snapshot in time, sometimes limiting to capture applications continuously installed, removed, or updated.

The Power of Application Inventory

A robust application inventory solution fills the gaps left by MDM, offering significant security benefits:

  • Enhanced Threat Detection: By identifying all applications, you can discover unauthorized software that might harbor malware.
  • Vulnerability Management: Identify outdated applications with known vulnerabilities and prioritize patching to minimize the attack surface.
  • Improved Compliance: Ensure adherence to software licensing agreements and internal security policies by monitoring application usage.
  • Streamlined Security Audits: A complete application inventory simplifies security audits by providing a centralized view of your software landscape.

Beyond Security: The Added Value of Application Inventory

The benefits of application inventory extend beyond just security. It empowers you to:

  • Optimize Software Licensing: Gain insights into software usage patterns, allowing for informed decisions about licensing costs.
  • Identify Shadow IT: Discover unsanctioned software deployments and improve overall IT governance.
  • Simplify Software Deployment: Plan and deploy software updates more effectively through a comprehensive understanding of your application ecosystem.

Taking Control: Building a Comprehensive Inventory with Intune and Azure Log Analytics

Traditionally, building a comprehensive application inventory required additional tools. However, by leveraging Microsoft Intune and Azure Log Analytics, you can achieve this with a custom script.

The Power of Automation:

The script utilizes a bash script running on macOS devices enrolled in Intune. This script gathers application data and sends it securely to your Azure Log Analytics workspace for centralized analysis.

Benefits of this Approach:

  • Centralized Visibility: Gain a holistic view of all applications installed across your macOS devices.
  • Continuous Updates: Schedule automatic script execution to ensure your inventory stays up-to-date.
  • Seamless Integration: Leverages existing tools within the Microsoft ecosystem for a streamlined solution.

Building the macOS Application Inventory Script

The following lines define variables for the CustomerId (your Azure Log Analytics workspace ID) and SharedKey (your workspace’s primary key). These are placeholders; you’ll need to replace them with your actual values before deployment.

#!/bin/bash# Replace these with your actual Workspace ID and Primary KeyCustomerId="your_workspace_id"SharedKey="your_primary_key"

The script retrieves the computer name using scutil --get ComputerName.

It then extracts the device serial number using system_profiler SPHardwareDataType and awk to filter the output for the line containing “Serial”

ComputerName=$(scutil --get ComputerName)DeviceSerialNumber=$(system_profiler SPHardwareDataType | awk '/Serial/ {print $4}')

This section is the heart of application data collection:

  • It defines a variable Applications as an opening bracket for a JSON array.
  • The script iterates through lines retrieved using system_profiler SPApplicationsDataType.
  • It uses conditional statements (if and elif) to identify lines containing “Location:” (indicating app location) and “Version:”.
  • For “Location:”, it extracts the application name using basename to remove the path and “.app” extension.
  • For “Version:”, it extracts the version number using awk.
  • It then constructs a JSON object for each application with details like AppNameAppVersionComputerName, and DeviceSerialNumber.
  • The loop keeps adding these application objects (separated by commas) to the Applications variable.
  • Finally, it removes the trailing comma from the JSON array using sed.
Applications="["

IFS=$'\n'
for line in $(system_profiler SPApplicationsDataType); do
  if [[ "$line" =~ "Location:" ]]; then
    appName=$(basename "$line" .app)  # Extracts only the app name, removing path and .app extension
  elif [[ "$line" =~ "Version:" ]]; then
    appVersion=$(echo "$line" | awk -F": " '{print $2}')
    Applications+="{\"AppName\": \"$appName\", \"AppVersion\": \"$appVersion\", \"ComputerName\": \"$ComputerName\", \"DeviceSerialNumber\": \"$DeviceSerialNumber\"},"
  fi
done
IFS=$' \t\n'

# JSON format
Applications=$(echo $Applications | sed 's/,\]/\]/')

It passes the CustomerId (workspace ID), SharedKey (primary key), the prepared Applications JSON data (containing application details), and a log type identifier (“Mac_app_inventory_CL”) for reference within Log Analytics.

# Send data
send_data "$CustomerId" "$SharedKey" "$Applications" "Mac_app_inventory_CL"

So, let’s put together all the blocks and build our complete script:

#!/bin/bash

# Replace these with your actual Workspace ID and Primary Key
CustomerId="your_workspace_id"
SharedKey="your_primary_key"

# Function to create the authorization signature
function generate_signature() {
    local customerId="$1"
    local sharedKey="$2"
    local date="$3"
    local contentLength="$4"
    local method="$5"
    local contentType="$6"
    local resource="$7"
    
    local stringToHash="$method\n$contentLength\n$contentType\nx-ms-date:$date\n$resource"
    local decodedKey=$(echo "$sharedKey" | base64 -d | xxd -p -u -c 256)
    local hash=$(echo -ne "$stringToHash" | xxd -p -u -c 256 | xxd -r -p | openssl dgst -sha256 -mac HMAC -macopt hexkey:$decodedKey -binary | base64)
    
    echo "SharedKey $customerId:$hash"
}

# Function to send data to Log Analytics
function send_data() {
    local customerId="$1"
    local sharedKey="$2"
    local data="$3"
    local logType="$4"
    
    local method="POST"
    local contentType="application/json"
    local resource="/api/logs"
    local date=$(date -u +%a,\ %d\ %b\ %Y\ %H:%M:%S\ GMT)
    local contentLength=$(echo -n "$data" | wc -c | tr -d ' ')
    local signature=$(generate_signature "$customerId" "$sharedKey" "$date" "$contentLength" "$method" "$contentType" "$resource")
    local uri="https://$customerId.ods.opinsights.azure.com$resource?api-version=2016-04-01"
    
    response=$(curl --silent --location "$uri" \
         --header "Authorization: $signature" \
         --header "Log-Type: $logType" \
         --header "x-ms-date: $date" \
         --header "Content-Type: $contentType" \
         --data "$data")
    echo "$response"
}

# Main data collection and processing
ComputerName=$(scutil --get ComputerName)
DeviceSerialNumber=$(system_profiler SPHardwareDataType | awk '/Serial/ {print $4}')

# Collecting dynamic application data
Applications="["

appCount=0  # Initialize application count
IFS=$'\n'
for line in $(system_profiler SPApplicationsDataType); do
    if [[ "$line" =~ "Location:" ]]; then
        appName=$(basename "$line" .app)  # Extracts only the app name, removing path and .app extension
    elif [[ "$line" =~ "Version:" ]]; then
        appVersion=$(echo "$line" | awk -F": " '{print $2}')
        Applications+="{\"AppName\": \"$appName\", \"AppVersion\": \"$appVersion\", \"ComputerName\": \"$ComputerName\", \"DeviceSerialNumber\": \"$DeviceSerialNumber\"},"
        ((appCount++))  # Increment application count
    fi
done
IFS=$' \t\n'

# Remove the last comma for JSON format correctness
Applications=$(echo $Applications | sed 's/,\]/\]/')

# Debug output to check everything is captured correctly
echo "Debug: Prepared JSON Data: $Applications"

# Send data
send_data "$CustomerId" "$SharedKey" "$Applications" "Mac_app_inventory_CL"

# Print completion message
echo "Application inventory collected and uploaded to Azure Log Analytics workspace. The total count of apps discovered and uploaded are $appCount."

Deployment:

It is advisable that you run the script locally on a test Mac to see the data before you push it to all production machines!

You need to deploy the script to all your Macs enrolled with Intune. Steps are as below: 

  • Sign in to the Microsoft Intune admin center.
  • Select Devices > macOS > Shell scripts > Add.
  • In Basics, enter the required properties, and select Next.
  • In Script settings, configure as below and select Next:
  • Select Assignments > Select groups to include

End Results

Once the script executes successfully, it transmits the collected data to your Azure Log Analytics workspace. This data will be stored in a new table named Mac_app_inventory_CL . Within this table, you’ll find all the application inventory details gathered by the script from the device.

  • Testing locally first on a test machine:
  • Data in Azure Log Analytics Workspace:

Conclusion

In conclusion, maintaining a comprehensive inventory of applications on Mac endpoints is crucial for several reasons. It enhances visibility into installed applications, aids in security compliance by ensuring all software is up-to-date, and helps IT departments manage resources more effectively. The limitations of standard MDM reporting functionalities often necessitate a more hands-on approach, as demonstrated through the use of our custom script.

The script not only automates the collection of application data but also seamlessly uploads this inventory to Azure Log Analytics. This integration provides a centralized and accessible location for monitoring and analysis, enabling organizations to make informed decisions based on accurate and up-to-date application usage data.

It empowers you to overcome the reporting limitations of MDM solutions by providing a deeper insight into the applications installed on your network’s endpoints.

Next Steps:

  • Experiment with the script to customize and extend its capabilities according to your organization’s specific needs.
  • Consider integrating this script into your regular IT audit processes to ensure continuous compliance and security.
  • Stay updated with the latest in script automation and endpoint management by subscribing to my blog and following on social media channels.

Categories: Automation, Intune, macOS, Security

Leave a Reply

Cookies Notice

Intune - In Real Life, uses cookies. If you continue to use this site it is assumed that you are happy with this.

Discover more from Intune - In Real Life

Subscribe now to keep reading and get access to the full archive.

Continue reading