Guide complet pour obtenir la liste des extensions de navigateur macOS

Les extensions de navigateur sont des outils puissants qui améliorent les fonctionnalités des navigateurs web, mais elles peuvent également présenter des risques pour la sécurité si elles ne sont pas correctement gérées. Pour les professionnels de l’informatique et les fournisseurs de services gérés (MSP) chargés de maintenir un environnement informatique sécurisé et efficace, il est essentiel de disposer d’une méthode permettant d’inventorier les extensions de navigateur dans les différents navigateurs sur les systèmes macOS.

Cet article présente un script complet qui crée une liste des extensions de navigateur installées sur Safari, Chrome, Firefox et Edge pour macOS. La compréhension et la gestion de ces extensions peuvent considérablement renforcer la posture de sécurité d’une entreprise.

Contexte

Dans le monde informatique actuel, il est fondamental de s’assurer que tous les logiciels, y compris les extensions de navigateur, sont à jour et sécurisés. Les extensions peuvent apporter de grands avantages, mais elles présentent également des vulnérabilités potentielles que des personnes malveillantes peuvent exploiter.

Ce script est conçu pour aider les professionnels de l’informatique à recueillir rapidement et efficacement des informations sur les extensions de navigateur installées dans plusieurs navigateurs sur les systèmes macOS. Cette capacité est essentielle pour maintenir la conformité en matière de sécurité et garantir que seules les extensions autorisées sont utilisées.

Le script

#!/usr/bin/env bash

#
# Description: Get the browser extensions for Safari, Chrome, Firefox, and Edge that are installed on a macOS system.
#
# Usage: [multilineCustomFieldName] [wysiwygCustomFieldName]
#
# Release Notes: Fixed 10% width bug.
# By using this script, you indicate your acceptance of the following legal terms as well as our Terms of Use at https://www.ninjaone.com/terms-of-use.
# Ownership Rights: NinjaOne owns and will continue to own all right, title, and interest in and to the script (including the copyright). NinjaOne is giving you a limited license to use the script in accordance with these legal terms. 
# Use Limitation: You may only use the script for your legitimate personal or internal business purposes, and you may not share the script with another party. 
# Republication Prohibition: Under no circumstances are you permitted to re-publish the script in any script library or website belonging to or under the control of any other software provider. 
# Warranty Disclaimer: The script is provided “as is” and “as available”, without warranty of any kind. NinjaOne makes no promise or guarantee that the script will be free from defects or that it will meet your specific needs or expectations. 
# Assumption of Risk: Your use of the script is at your own risk. You acknowledge that there are certain inherent risks in using the script, and you understand and assume each of those risks. 
# Waiver and Release: You will not hold NinjaOne responsible for any adverse or unintended consequences resulting from your use of the script, and you waive any legal or equitable rights or remedies you may have against NinjaOne relating to your use of the script. 
# EULA: If you are a NinjaOne customer, your use of the script is subject to the End User License Agreement applicable to you (EULA).
#
# Example Output:
#
# Safari Extensions:
# User: john, Name: com.betafish.adblock-mac.SafariMenu, Id: 3KKZV48AQD
# User: ken, Name: com.rockysandstudio.MKPlayer.MKPlayer-Extension, Id: 2N35YUC83U
#
# Chrome Extensions:
# User: john, Name: Chrome Web Store Payments, Id: nmmhkkegccagdldgiimedpiccmgmieda, Version: 1.0.0.6, Profile Name: test1
# User: john, Name: Turn Off the Lights, Id: bfbmjmiodbnnpllbbbfblcplfjjepjdn, Version: 4.2.6.0, Profile Name: test2
# User: ken, Name: Google Docs Offline, Id: ghbmnnjooekpmoecnnnilnnbdlolhkhi, Version: 1.76.1, Profile Name: Person 1
#
# Firefox Addons:
# User: john, Name: Return YouTube Dislike, Id: {762f9885-5a13-4abd-9c77-433dcd38b8fd}, Description: Returns ability to see dislike statistics on youtube, Profile Name: default-release
# User: john, Name: Stylebot, Id: {52bda3fd-dc48-4b3d-a7b9-58af57879f1e}, Description: Change the appearance of the web instantly, Profile Name: default-release
# User: ken, Name: Search by Image, Id: {2e5ff8c8-32fe-46d0-9fc8-6b8986621f3c}, Description: A powerful reverse image search tool, with support for various search engines, such as Google, Bing, Yandex, Baidu and TinEye., Profile Name: default-release
#
# Edge Extensions:
# User: john, Name: Google Docs Offline, Id: ghbmnnjooekpmoecnnnilnnbdlolhkhi, Version: 1.76.2, Profile Name: test 3
# User: john, Name: Edge relevant text changes, Id: jmjflgjpcpepeafmmgdpfkogkghcpiha, Version: 1.2.1, Profile Name: test 3
# User: ken, Name: Google Docs Offline, Id: ghbmnnjooekpmoecnnnilnnbdlolhkhi, Version: 1.76.2, Profile Name: Profile 1

_arg_multilineField=$1
_arg_wysiwygField=$2

# Determines whether or not help text is necessary and routes the output to stderr
die() {
    local _ret="${2:-1}"
    echo "$1" >&2
    test "${_PRINT_HELP:-no}" = yes && print_help >&2
    exit "${_ret}"
}

# Prints the help text
print_help() {
    echo "Get the browser extensions for Safari, Chrome, Firefox, and Edge that are installed on a macOS system."
    echo "Usage: [multilineCustomFieldName] [wysiwygCustomFieldName]"
}

# Check if --help or -h is passed as an argument
for _arg in "$@"; do
    case "$_arg" in
    --help | -h)
        print_help
        exit 0
        ;;
    esac
done

# Set the custom field value using ninjarmm-cli
GetCustomField() {
    customfieldName=$1
    dataPath=$(printenv | grep -i NINJA_DATA_PATH | awk -F = '{print $2}')
    value=""
    if [ -e "${dataPath}/ninjarmm-cli" ]; then
        value=$("${dataPath}"/ninjarmm-cli get "$customfieldName")
    else
        value=$(/Applications/NinjaRMMAgent/programdata/ninjarmm-cli get "$customfieldName")
    fi
    if [[ "${value}" == *"Unable to find the specified field"* ]]; then
        echo ""
        return 1
    else
        echo "$value"
    fi
}

# Check if the multilineCustomFieldName is set as environment variables
multiline=$(printenv | grep -i multilineCustomFieldName | awk -F = '{print $2}')
if [[ -n "$multiline" ]] && [[ "${multiline}" != "null" ]]; then
    _arg_multilineField=$(printenv | grep -i multilineCustomFieldName | awk -F = '{print $2}')
fi

# Check if the wysiwygCustomFieldName is set as environment variables
wysiwygField=$(printenv | grep -i wysiwygCustomFieldName | awk -F = '{print $2}')
if [[ -n "$wysiwygField" ]] && [[ "${wysiwygField}" != "null" ]]; then
    _arg_wysiwygField=$(printenv | grep -i wysiwygCustomFieldName | awk -F = '{print $2}')
fi

# Check if both _arg_multilineField and _arg_wysiwygField are set and not empty
if [[ -n "$_arg_multilineField" && -n "$_arg_wysiwygField" ]]; then
    # Convert both field names to uppercase to check for equality
    multiline=$(echo "$_arg_multilineField" | tr '[:lower:]' '[:upper:]')
    wysiwyg=$(echo "$_arg_wysiwygField" | tr '[:lower:]' '[:upper:]')

    # If the converted names are the same, it means both fields cannot be identical
    # If they are, terminate the script with an error
    if [[ "$multiline" == "$wysiwyg" ]]; then
        _PRINT_HELP=yes die '[Error] Multline Field and WYSIWYG Field cannot be the same name. https://ninjarmm.zendesk.com/hc/en-us/articles/360060920631-Custom-Fields-Configuration-Device-Role-Fields'
    fi
fi

# Warn that if not running as root, the script may not be able to access all user directories
if [[ $EUID -ne 0 ]]; then
    echo "[Warn] This script may not be able to access all user directories unless run as root."
fi

# Converts a string input into an HTML table format
convertToHTMLTable() {
    local _arg_delimiter=" "
    local _arg_inputObject

    # Process command-line arguments for the function
    while test $# -gt 0; do
        _key="$1"
        case "$_key" in
        --delimiter | -d)
            test $# -lt 2 && echo "[Error] Missing value for the optional argument" >&2 && return 1
            _arg_delimiter=$2
            shift
            ;;
        --*)
            echo "[Error] Got an unexpected argument" >&2
            return 1
            ;;
        *)
            _arg_inputObject=$1
            ;;
        esac
        shift
    done

    # Handles missing input by checking stdin or returning an error
    if [[ -z $_arg_inputObject ]]; then
        if [ -p /dev/stdin ]; then
            _arg_inputObject=$(cat)
        else
            echo "[Error] Missing input object to convert to table" >&2
            return 1
        fi
    fi

    local htmlTable="<table>\n"
    htmlTable+=$(printf '%b' "$_arg_inputObject" | head -n1 | awk -F "$_arg_delimiter" '{
    printf "<tr>"
    for (i=1; i<=NF; i+=1)
      { printf "<th>"$i"</th>" }
    printf "</tr>"
    }')
    htmlTable+="\n"
    htmlTable+=$(printf '%b' "$_arg_inputObject" | tail -n +2 | awk -F "$_arg_delimiter" '{
    printf "<tr>"
    for (i=1; i<=NF; i+=1)
      { printf "<td>"$i"</td>" }
    print "</tr>"
    }')
    htmlTable+="\n</table>"

    printf '%b' "$htmlTable" '\n'
}

createExtList() {
    userHome=$1
    browser=$2 # chrome or edge
    user_name=$(echo "$userHome" | cut -d "/" -f 3)
    if [[ "${browser}" == "chrome" ]]; then
        manifests=$(find "${userHome}/Library/Application Support/Google/Chrome" -type f -name 'manifest.json' 2>/dev/null | grep "Extensions")
        profileLocalState="${userHome}/Library/Application Support/Google/Chrome/Local State"
    elif [[ "${browser}" == "edge" ]]; then
        manifests=$(find "${userHome}/Library/Application Support/Microsoft Edge" -type f -name 'manifest.json' 2>/dev/null | grep "Extensions")
        profileLocalState="${userHome}/Library/Application Support/Microsoft Edge/Local State"
    fi

    en_messages="_locales/en/messages.json"
    enUS_messages="_locales/en_US/messages.json"

    while IFS= read -r manifest; do
        # Check if we can read the manifest file
        if [ ! -f "$manifest" ]; then
            continue
        fi

        profileName=$(
            # Get profile name from profileLocalState that contains json data
            # "profile.info_cache.Default" is the default profile
            osascript -l JavaScript -e "
                    var profileLocalState = JSON.parse(ObjC.unwrap($.NSString.alloc.initWithDataEncoding($.NSData.dataWithContentsOfFile('$profileLocalState'), $.NSUTF8StringEncoding)));
                    // Get each profile name based on the profile path
                    if ('$browser' === 'chrome') {
                        var profilePathName = '$manifest'.split('/')[7];
                    } else if ('$browser' === 'edge') {
                        var profilePathName = '$manifest'.split('/')[6];
                    }
                    for (var key in profileLocalState.profile.info_cache) {
                        if (key.toLowerCase() === profilePathName.toLowerCase()) {
                            var profileName = profileLocalState.profile.info_cache[key].name;
                            break;
                        }
                    }
                    profileName;
                "
        )

        # Get the id of the extension from the manifest path by splitting the path on '/' and getting the 9th element
        if [[ "${browser}" == "chrome" ]]; then
            extID=$(awk -F '/' '{print $10}' <<<"$manifest")
        elif [[ "${browser}" == "edge" ]]; then
            extID=$(awk -F '/' '{print $9}' <<<"$manifest")
        fi
        # Get name from manifest
        name=$(
            osascript -l JavaScript -e "
                var data = JSON.parse(ObjC.unwrap($.NSString.alloc.initWithDataEncoding($.NSData.dataWithContentsOfFile('$manifest'), $.NSUTF8StringEncoding)));
                var name = data.name;
                name;
            "
        )
        # Get version from manifest
        version=$(
            osascript -l JavaScript -e "
                var data = JSON.parse(ObjC.unwrap($.NSString.alloc.initWithDataEncoding($.NSData.dataWithContentsOfFile('$manifest'), $.NSUTF8StringEncoding)));
                var version = data.version;
                version;
            "
        )

        # Get the name of the extension from the messages.json file if the name contains "__MSG_"
        if [[ "${name}" =~ "__MSG_" ]]; then
            name=$(echo "$name" | sed 's/__MSG_//g' | sed 's/__$//g')
            if [ -f "$(dirname "$manifest")/$en_messages" ]; then
                # Check if message.json exists in en folder
                name=$(
                    osascript -l JavaScript -e "
                        var data = JSON.parse(ObjC.unwrap($.NSString.alloc.initWithDataEncoding($.NSData.dataWithContentsOfFile('$(dirname "$manifest")/$en_messages'), $.NSUTF8StringEncoding)));
                        var searchKey = '$name';
                        var asLowercase = searchKey.toLowerCase();
                        var name = data[Object.keys(data).find(key => key.toLowerCase() === asLowercase)].message;
                        name;
                    " 2>/dev/null
                )
            elif [ -f "$(dirname "$manifest")/$enUS_messages" ]; then
                # Check if message.json exists in enUS folder
                name=$(
                    osascript -l JavaScript -e "
                        var data = JSON.parse(ObjC.unwrap($.NSString.alloc.initWithDataEncoding($.NSData.dataWithContentsOfFile('$(dirname "$manifest")/$enUS_messages'), $.NSUTF8StringEncoding)));
                        var searchKey = '$name';
                        var asLowercase = searchKey.toLowerCase();
                        var name = data[Object.keys(data).find(key => key.toLowerCase() === asLowercase)].message;
                        name;
                    " 2>/dev/null
                )
            fi
        fi
        if [[ -n "$name" ]]; then
            printf "%s|%s|%s|%s|%s\n" "$user_name" "$profileName" "$name" "$extID" "$version"
        else
            printf "%s|%s|%s|%s|%s\n" "$user_name" "$profileName" "Name Not Found" "$extID" "$version"
        fi
    done <<<"$manifests"
}

# Get a list of all users in the /Users directory except Shared
users=()
for user in /Users/*; do
    if [[ -d "$user" && ! "$user" =~ /Users/Shared ]]; then
        users+=("${user##*/}")
    fi
done

# Error when no users are found
if [[ ${#users[@]} -eq 0 ]]; then
    _PRINT_HELP=no die "[Error] No user directories found in /Users"
fi

safari_title="Safari Extensions"
safari_extensions=""
chrome_title="Chrome Extensions"
chrome_extensions=""
firefox_title="Firefox Addons"
firefox_addons=""
edge_title="Edge Extensions"
edge_extensions=""

# Safari
for user in "${users[@]}"; do
    ext_plist="/Users/$user/Library/Containers/com.apple.Safari/Data/Library/Safari/AppExtensions/Extensions.plist"
    pattern='(com\..*)\s\((.*)\)'
    if [[ -f "$ext_plist" ]]; then
        safari_extensions+=$'\n'"$(
            grep -Eo "$pattern" "$ext_plist" | while read -r line; do
                ext_name=$(echo "$line" | awk -F ' ' '{print $1}')
                ext_id=$(echo "$line" | awk -F ' ' '{print $2}' | tr -d '()')
                printf "%s|%s|%s\n" "$user" "$ext_name" "$ext_id"
            done
        )"
    fi
done

# Chrome
for user in "${users[@]}"; do
    # Add a newline to the beginning of the string to separate the results from the previous user
    chrome_extensions+=$'\n'"$(createExtList "/Users/$user" "chrome")"
done

# Firefox Get installed Addons (not extensions)
firefox_addons=$(
    # Loop through each user profile
    for user in "${users[@]}"; do
        firefox_path="/Users/$user/Library/Application Support/Firefox"
        profile_dir="$firefox_path/Profiles"
        # Check if Profiles directory exists
        if [[ -d "$profile_dir" ]]; then
            profiles_ini_path="$firefox_path/profiles.ini"
            # Check if profiles.ini file exists
            if [[ -f "$profiles_ini_path" ]]; then
                profiles_ini=$(cat "$profiles_ini_path")
                # Parse the profiles.ini file and get the profile names and paths
                # Get each section
                awk -F '=' '/\[/{print $1}' <<<"$profiles_ini" | while read -r section; do
                    # Get the profile name
                    profile_name=$(
                        awk -F'=' -v section="$section" -v k="Name" '
                        $0==section{ f=1; next }
                        /\[/{ f=0; next }
                        f && $1==k{ print $0 }
                        ' <<<"$profiles_ini" | sed 's/^Name=//'
                    )
                    # Get the profile path
                    profile_path=$(
                        awk -F'=' -v section="$section" -v k="Path" '
                        $0==section{ f=1; next }
                        /\[/{ f=0; next }
                        f && $1==k{ print $0 }
                        ' <<<"$profiles_ini" | sed 's/^Path=//'
                    )
                    # Get the addons json file path
                    ext_dir="$firefox_path/$profile_path/addons.json"
                    if [[ -f "$ext_dir" ]]; then
                        # Get name, id, and description from the addons.json file
                        ff_results=$(
                            osascript -l JavaScript -e "
                                var data = JSON.parse(ObjC.unwrap($.NSString.alloc.initWithDataEncoding($.NSData.dataWithContentsOfFile('$ext_dir'), $.NSUTF8StringEncoding)));
                                var addons = data.addons;
                                var result = '';
                                for (var i = 0; i < addons.length; i++) {
                                    var addon = addons[i];
                                    result += addon.name + ',' + addon.id + ',' + addon.description + '\n';
                                }
                                result;
                            "
                        )
                        Old_IFS=$IFS
                        echo "$ff_results" | while IFS=, read -r name id description; do
                            printf "%s|%s|%s|%s|%s\n" "$user" "$profile_name" "$name" "$id" "$description"
                        done
                        IFS=$Old_IFS
                    fi
                done
            fi
        fi
    done
)

# Edge
for user in "${users[@]}"; do
    # Add a newline to the beginning of the string to separate the results from the previous user
    edge_extensions+=$'\n'"$(createExtList "/Users/$user" "edge")"
done

if [[ -n $_arg_multilineField ]] || [[ -n $_arg_wysiwygField ]]; then
    # Add headers if a custom field is set
    if [[ -n "${safari_extensions}" ]]; then
        safari_extensions=$(echo -e "User|Name|Id\n$safari_extensions")
    fi
    if [[ -n "${chrome_extensions}" ]]; then
        chrome_extensions=$(echo -e "User|Profile Name|Name|Id|Version\n$chrome_extensions")
    fi
    if [[ -n "${firefox_addons}" ]]; then
        firefox_addons=$(echo -e "User|Profile Name|Name|Id|Description\n$firefox_addons")
    fi
    if [[ -n "${edge_extensions}" ]]; then
        edge_extensions=$(echo -e "User|Profile Name|Name|Id|Version\n$edge_extensions")
    fi
fi

# Checks if there is a multiline custom field set
if [[ -n $_arg_multilineField ]]; then
    echo ""
    echo "Attempting to set Custom Field '$_arg_multilineField'..."

    # Formats the extension data for the multiline custom field
    multilineValue=""
    # Check if any browser extensions were found
    if [[ -n "$safari_title" ]] && [[ -n "${safari_extensions}" ]]; then
        multilineValue+=$'\n'
        multilineValue+="$safari_title:"
        multilineValue+=$'\n'
        multilineValue+=$(
            # Convert the safari_extensions string to a table format. Skip the first line as it is the header
            echo "$safari_extensions" | tail -n +2 | while IFS='|' read -r user name id; do
                printf "User: %s, Name: %s, Id: %s\n" "$user" "$name" "$id"
            done
        )
    fi
    if [[ -n "$chrome_title" ]] && [[ -n "${chrome_extensions}" ]]; then
        multilineValue+=$'\n'
        multilineValue+="$chrome_title:"
        multilineValue+=$'\n'
        multilineValue+=$(
            # Convert the chrome_extensions string to a table format. Skip the first line as it is the header
            echo "$chrome_extensions" | tail -n +2 | while IFS='|' read -r user_name profileName name id version; do
                if [[ -n "$name" ]]; then
                    printf "User: %s, Profile Name: %s, Name: %s, Id: %s, Version: %s\n" "$user_name" "$profileName" "$name" "$id" "$version"
                fi
            done
        )
    fi
    if [[ -n "$firefox_title" ]] && [[ -n "${firefox_addons}" ]]; then
        multilineValue+=$'\n'
        multilineValue+="$firefox_title:"
        multilineValue+=$'\n'
        multilineValue+=$(
            # Convert the firefox_addons string to a table format. Skip the first line as it is the header
            echo "$firefox_addons" | tail -n +2 | while IFS='|' read -r user profileName name id description; do
                if [[ -n "$name" ]]; then
                    printf "User: %s, Profile Name: %s, Name: %s, Id: %s, Description: %s\n" "$user" "$profileName" "$name" "$id" "$description"
                fi
            done
        )
    fi
    if [[ -n "$edge_title" ]] && [[ -n "${edge_extensions}" ]]; then
        multilineValue+=$'\n'
        multilineValue+="$edge_title:"
        multilineValue+=$'\n'
        multilineValue+=$(
            # Convert the edge_extensions string to a table format. Skip the first line as it is the header
            echo "$edge_extensions" | tail -n +2 | while IFS='|' read -r user_name profileName name id version; do
                if [[ -n "$name" ]]; then
                    printf "User: %s, Profile Name: %s, Name: %s, Id: %s, Version: %s\n" "$user_name" "$profileName" "$name" "$id" "$version"
                fi
            done
        )
    fi
    # if all multilineValue is empty, set it to "No browser extensions found"
    if [[ -z "$multilineValue" ]]; then
        multilineValue="No browser extensions found"
    fi

    # Tries to set the multiline custom field using ninjarmm-cli and captures the output
    if ! output=$(printf '%b' "$multilineValue" | /Applications/NinjaRMMAgent/programdata/ninjarmm-cli set --stdin "$_arg_multilineField" 2>&1); then
        echo "[Error] $output" >&2
        EXITCODE=1
    else
        echo "[Info] Successfully set Custom Field '$_arg_multilineField'!"
    fi
fi

# Checks if there is a WYSIWYG custom field set
if [[ -n $_arg_wysiwygField ]]; then
    echo ""
    echo "Attempting to set Custom Field '$_arg_wysiwygField'..."

    # Initializes an HTML formatted string with headers and extension details
    # Check if any browser extensions were found
    if [[ -n "$safari_title" ]] && [[ -n "${safari_extensions}" ]]; then
        htmlObject+="<h2>$safari_title</h2>"
        htmlObject+=$(echo "$safari_extensions" | convertToHTMLTable --delimiter '|')
    fi
    if [[ -n "$chrome_title" ]] && [[ -n "${chrome_extensions}" ]]; then
        htmlObject+="<h2>$chrome_title</h2>"
        htmlObject+=$(echo "$chrome_extensions" | convertToHTMLTable --delimiter '|')
    fi
    if [[ -n "$firefox_title" ]] && [[ -n "${firefox_addons}" ]]; then
        htmlObject+="<h2>$firefox_title</h2>"
        htmlObject+=$(echo "$firefox_addons" | convertToHTMLTable --delimiter '|')
    fi
    if [[ -n "$edge_title" ]] && [[ -n "${edge_extensions}" ]]; then
        htmlObject+="<h2>$edge_title</h2>"
        htmlObject+=$(echo "$edge_extensions" | convertToHTMLTable --delimiter '|')
    fi
    # if all htmlObject is empty, set it to "No browser extensions found"
    if [[ -z "$htmlObject" ]]; then
        htmlObject="<p>No browser extensions found</p>"
    fi
    # Replace <table> with <table style='white-space:nowrap;'>
    htmlObject=${htmlObject//<table>/<table style=\'white-space:nowrap;\'>}
    # Tries to set the WYSIWYG custom field using ninjarmm-cli and captures the output
    if ! output=$(printf '%b' "$htmlObject" | /Applications/NinjaRMMAgent/programdata/ninjarmm-cli set --stdin "$_arg_wysiwygField" 2>&1); then
        echo "[Error] $output" >&2
        EXITCODE=1
    else
        echo "[Info] Successfully set Custom Field '$_arg_wysiwygField'!"
    fi
fi

# If both _arg_multilineField and _arg_wysiwygField are not set, or if there is an error saving to the custom fields, print the results
if [[ -z $_arg_multilineField && -z $_arg_wysiwygField ]] || [[ $EXITCODE -ne 0 ]]; then
    echo ""
    echo "$safari_title:"
    echo "$safari_extensions" | while IFS='|' read -r user name id; do
        if [[ -n "$name" ]]; then
            printf "User: %s, Name: %s, Id: %s\n" "$user" "$name" "$id"
        fi
    done
    echo ""
    echo "$chrome_title:"
    echo "$chrome_extensions" | while IFS='|' read -r user profileName name id version; do
        if [[ -n "$name" ]]; then
            printf "User: %s, Profile Name: %s, Name: %s, Id: %s, Version: %s\n" "$user" "$profileName" "$name" "$id" "$version"
        fi
    done
    echo ""
    echo "$firefox_title:"
    echo "$firefox_addons" | while IFS='|' read -r user profileName name id description; do
        if [[ -n "$name" ]]; then
            printf "User: %s, Profile Name: %s, Name: %s, Id: %s, Description: %s\n" "$user" "$profileName" "$name" "$id" "$description"
        fi
    done
    echo ""
    echo "$edge_title:"
    echo "$edge_extensions" | while IFS='|' read -r user profileName name id version; do
        if [[ -n "$name" ]]; then
            printf "User: %s, Profile Name: %s, Name: %s, Id: %s, Version: %s\n" "$user" "$profileName" "$name" "$id" "$version"
        fi
    done
    # If no extensions are found, print a message
    if [[ -z "$safari_extensions" ]] && [[ -z "$chrome_extensions" ]] && [[ -z "$firefox_addons" ]] && [[ -z "$edge_extensions" ]]; then
        echo "[Info] No Browser Extensions Found"
    fi
fi

# Checks if an error code is set and exits the script with that code
if [[ -n $EXITCODE ]]; then
    echo "[Error] Failed to save browser extensions to custom field '$_arg_multilineField' or '$_arg_wysiwygField'."
    exit "$EXITCODE"
fi

 

Description détaillée

Le script commence par définir son objectif et son utilisation, en fournissant une description claire et des exemples de résultats. Il vérifie ensuite les arguments d’aide et définit les valeurs des champs personnalisés à l’aide de ninjarmm-cli, un outil de gestion des champs personnalisés dans NinjaOne.

1. Initialisation et traitement des arguments

  • Le script s’initialise en vérifiant si les arguments d’aide (–help ou -h) sont fournis. Si c’est le cas, il imprime les instructions d’utilisation et quitte.
  • Il définit une fonction GetCustomField pour récupérer les valeurs des champs personnalisés à l’aide de ninjarmm-cli.

2. Vérification des variables d’environnement

  • Le script vérifie si multilineCustomFieldName et wysiwygCustomFieldName sont définis en tant que variables d’environnement, et met à jour les arguments du script en conséquence.

3. Identification du répertoire des utilisateurs

  • Il identifie les répertoires d’utilisateurs dans /Users, à l’exclusion du répertoire Shared, et rassemble tous les comptes d’utilisateurs sur le système.

4. Extensions Safari

  • Pour chaque utilisateur, le script recherche les fichiers plist des extensions Safari et extrait les détails des extensions à l’aide d’expressions régulières.

5. Extensions Chrome et Edge

  • Le script utilise une fonction createExtList pour trouver et répertorier les extensions Chrome et Edge. Il analyse les fichiers manifest.json dans les répertoires d’extensions du navigateur, en extrayant les noms, les identifiants et les versions des extensions.

6. Modules d’extension de Firefox

  • Pour Firefox, le script analyse les fichiers profiles.ini et addons.json pour dresser la liste des modules complémentaires installés, y compris les noms, les identifiants et les descriptions.

7. Paramétrage des champs personnalisés et résultats

  • Si des champs personnalisés sont définis, le script formate les données recueillies dans des tableaux HTML ou du texte brut, puis tente de définir ces champs à l’aide de ninjarmm-cli. Si la définition des champs échoue, les données recueillies sont affichées sur la console.

Cette approche structurée garantit une couverture complète des principaux navigateurs et fournit un inventaire des extensions installées de façon claire et détaillée.

Cas d’utilisation potentiels

Prenons l’exemple d’une entreprise MSP chargée de veiller à ce que toutes les machines de ses clients soient sécurisées. À l’aide de ce script, l’entreprise MSP peut rapidement générer une liste de toutes les extensions de navigateur installées sur les systèmes macOS des clients. Par exemple, si une faille de sécurité est découverte dans une extension spécifique, l’entreprise MSP peut utiliser le script pour identifier les clients qui ont installé l’extension et prendre les mesures appropriées pour atténuer les risques.

Comparaisons

Les autres méthodes pour obtenir la liste les extensions de navigateur impliquent généralement des vérifications manuelles ou l’utilisation d’outils spécifiques au navigateur, ce qui peut prendre du temps et être source d’erreurs. Ce script fournit une solution unifiée et automatisée qui fonctionne sur plusieurs navigateurs, ce qui permet de gagner du temps et de réduire les risques d’oubli. De plus, l’intégration avec NinjaOne permet une gestion et un reporting centralisés, ce qui n’est pas possible avec des méthodes manuelles.

FAQ

  • Comment le script gère-t-il les différents profils d’utilisateurs ?
    Le script parcourt chaque répertoire d’utilisateurs dans /Users et traite chaque profil trouvé dans les répertoires de navigateurs respectifs.
  • Que se passe-t-il si le script ne peut pas accéder à un répertoire d’utilisateurs ?
    Le script prévient qu’il peut avoir besoin de l’accès root pour lire tous les répertoires des utilisateurs. L’exécution du script en tant que root garantit un accès complet.
  • Le script peut-il être utilisé sur des systèmes non-macOS ?
    Non, ce script est spécifiquement conçu pour macOS en raison des chemins et des outils qu’il utilise.

Implications

Les résultats de ce script fournissent des informations essentielles sur les extensions installées dans plusieurs navigateurs et mettent en évidence les risques potentiels pour la sécurité. En disposant d’un inventaire clair, les professionnels de l’informatique peuvent garantir le respect des politiques de sécurité, détecter les extensions non autorisées et remédier rapidement aux vulnérabilités.

Recommandations

  • Exécutez le script en tant que root pour garantir l’accès à tous les répertoires d’utilisateurs.
  • Examinez régulièrement les listes d’extensions afin d’identifier et de supprimer toute extension inutile ou potentiellement nuisible.
  • Intégrez le script à un outil de surveillance tel que NinjaOne pour une gestion et un reporting continus.

Conclusion

La gestion des extensions de navigateur est un aspect crucial du maintien d’un environnement informatique sécurisé. Ce script fournit une solution puissante et automatisée pour faire la liste de toutes les extensions des principaux navigateurs sur macOS, ce qui en fait un outil précieux pour les professionnels de l’informatique et les MSP. En l’intégrant avec NinjaOne, vous pouvez améliorer votre capacité à contrôler et à gérer les extensions de navigateur, garantissant ainsi un environnement informatique sécurisé et conforme.

Pour aller plus loin

Créer une équipe informatique efficace et performante nécessite une solution centralisée qui soit l’outil principal pour fournir vos services. NinjaOne permet aux équipes informatiques de surveiller, gérer, sécuriser et prendre en charge tous les appareils, où qu’ils soient, sans avoir besoin d’une infrastructure complexe sur site.

Pour en savoir plus sur NinjaOne Endpoint Management, participez à une visite guidée ou commencez votre essai gratuit de la plateforme NinjaOne.

Catégories :

Vous pourriez aussi aimer

Voir la démo×
×

Voir NinjaOne en action !

En soumettant ce formulaire, j'accepte la politique de confidentialité de NinjaOne.

Termes et conditions NinjaOne

En cliquant sur le bouton « J’accepte » ci-dessous, vous indiquez que vous acceptez les termes juridiques suivants ainsi que nos conditions d’utilisation:

  • Droits de propriété: NinjaOne possède et continuera de posséder tous les droits, titres et intérêts relatifs au script (y compris les droits d’auteur). NinjaOne vous accorde une licence limitée pour l’utilisation du script conformément à ces conditions légales.
  • Limitation de l’utilisation: Les scripts ne peuvent être utilisés qu’à des fins personnelles ou professionnelles internes légitimes et ne peuvent être partagés avec d’autres entités.
  • Interdiction de publication: Vous n’êtes en aucun cas autorisé à publier le script dans une bibliothèque de scripts appartenant à, ou sous le contrôle d’un autre fournisseur de logiciels.
  • Clause de non-responsabilité: Le texte est fourni « tel quel » et « tel que disponible », sans garantie d’aucune sorte. NinjaOne ne promet ni ne garantit que le script sera exempt de défauts ou qu’il répondra à vos besoins ou attentes particulières.
  • Acceptation des risques: L’utilisation du script est sous votre propre responsabilité. Vous reconnaissez qu’il existe certains risques inhérents à l’utilisation du script, et vous comprenez et assumez chacun de ces risques.
  • Renonciation et exonération de responsabilité: Vous ne tiendrez pas NinjaOne pour responsable des conséquences négatives ou involontaires résultant de votre utilisation du script, et vous renoncez à tout droit ou recours légal ou équitable que vous pourriez avoir contre NinjaOne en rapport avec votre utilisation du script.
  • EULA: Si vous êtes un client de NinjaOne, votre utilisation du script est soumise au contrat de licence d’utilisateur final qui vous est applicable (End User License Agreement (EULA)).