Une nouvelle sonde Nagios – Centreon pour Mac : monitorer les comptes mobiles

7 Déc

Je continue ma petite série d’articles sur le monitoring d’infrastructures Mac avec Nagios ou Centreon. Après avoir évoqué le monitoring des certificats SSL et le monitoring de la taille de dossiers volumineux, je m’attaque aux comptes mobiles.

 

Les comptes mobiles sous Mac OS X Server, de quoi s’agit-il ?

Les comptes mobiles sont des comptes utilisateurs enregistrés sur un serveur d’annuaire (Active Directory sous Windows Server ou OpenDirectory sous Mac OS X Server), disposant d’un répertoire de départ situé sur un volume réseau (point de partage), pour lesquels une synchronisation périodique est réalisée. Les données du répertoire de départ sont donc répliquées sur le point de partage et en local. C’est une solution idéale pour les postes portables d’une entreprise par exemple. Et en plus c’est très bien intégré avec les outils de OS X Server.

D’ailleurs, une vidéo valant mieux que de longs discours, voici une petite démonstration du fonctionnement de ces comptes mobiles (portable home directory – PHD) :

Vous trouverez dans la doc officielle de Mac OS X Server les informations nécessaires à la mise en place de ces PHD.

 

Un problème récurent avec les comptes mobiles : la synchronisation

« Le principal problème en informatique est souvent l’interface entre la chaise et le clavier. »

C’est très clair, le principal problème avec les PHD, c’est que nombre d’utilisateurs ne font pas leur synchronisation de compte de manière régulière. On veut gagner du temps lors d’une fermeture de session pour ne pas louper le prochain film et zou, on annule la synchronisation. Et au fil du temps, il y a de plus en plus de fichiers à synchroniser, donc cela prend de plus en plus de temps et l’on est de moins en moins patient …

Evidemment, c’est au moment où l’on a besoin de récupérer ses données que l’on s’aperçoit que l’on a fait sa dernière synchronisation complète il y a un mois ! Trop tard !

Pour pallier ce problème, j’ai déjà évoqué sur ce blog deux solutions que j’ai mises en production :

  1. pour l’administrateur système : un script lancé chaque nuit qui vérifie l’état des synchronisations et envoie un mail avec l’état des comptes à jour et ceux qui ne le sont pas
  2. sur les postes clients, une combinaison entre un AppleScript sous Automator et du Shell pour alerter les utilisateurs et les inciter à faire leur synchronisation, avec l’apparition d’une fenêtre de notification le cas échéant.

 

Intégrer la surveillance des comptes mobiles (PHD) sur Nagios – Centreon

Comme je dispose maintenant d’un serveur de monitoring Centreon, j’ai cherché à supprimer tous les outils de surveillance maison de type script lancés via Launchd ou Cron sur Mac Serveur. Autant déployer des sondes (plugins) pour Centreon.

C’est donc chose fait avec quelques heures de boulot. J’ai transformé le script lancé chaque nuit qui vérifie l’état des synchronisations en une sonde Nagios – Centreon. J’ai profité de ce refactoring pour améliorer mon script.

Au menu :

  • ajout de personnalisation dans l’utilisation de la sonde, on peut maintenant personnaliser :
    • les fichiers tests utilisés pour vérifier la synchronisation (option -f),
    • le nombre de fichiers synchronisés parmi ces fichiers tests pour considérer que la synchronisation est réalisée (option -n)
    • les délais en jours utilisés pour considérer qu’un compte est dans un état WARNING ou CRITICAL sont personnalisables (options -w et -c)
    • le seuil (% de comptes en état WARNING ou CRITICAL) pour renvoyer une alerte WARNING ou CRITICAL sur Centreon (option -t). Par défaut, sans l’utilisation de cette option, l’état WARNING est renvoyé dés qu’un compte est en état WARNING et de même pour l’état CRITICAL,
    • possibilité de filtrer la recherche sur les utilisateurs membres d’un ou plusieurs groupes de l’OpenDirectory (option -g),
    • possibilité de personnaliser le ou les répertoires où sont stockés les données des comptes mobiles (option -p),
  • ajout d’une sortie avec des statistiques sur les comptes mobiles, qui vous permettra d’avoir de jolis graphiques sur Centreon,
  • ajout d’une aide pour le paramétrage de la sonde (il suffit de la lancer avec l’option -h : ./check_mobile_accounts.sh -h).

En jouant avec les option -w, -c, -n et -t vous pouvez régler cette sonde à peu près comme vous le voulez.

 

Et pour les plus curieux, voici le code dans son intégralité :

#!/bin/bash

# Check if Mobile Accounts on OS X are synchronized
# by Yvan GODARD
# http://www.yvangodard.me

# v1.0 - 30 November 2015
# Initial release.

## Set up our variables
version="check_mobile_accounts v1.0 - 2015, Yvan Godard [godardyvan@gmail.com] - http://www.yvangodard.me"
currentDate=$(date "+%s")
scriptDir=$(dirname "${0}")
scriptName=$(basename "${0}")
scriptNameWithoutExt=$(echo "${scriptName}" | cut -f1 -d '.')
usersList=$(mktemp /tmp/${scriptNameWithoutExt}_fileUsers.XXXXX)
usersListWithNetworkDirectory=$(mktemp /tmp/${scriptNameWithoutExt}_fileUsers.XXXXX)
messageContent=$(mktemp /tmp/${scriptNameWithoutExt}_messageContent.XXXXX)
filesToTestList=$(mktemp /tmp/${scriptNameWithoutExt}_filesToTestList.XXXXX)
groupsList=$(mktemp /tmp/${scriptNameWithoutExt}_groupsList.XXXXX)
homeDirsPathList=$(mktemp /tmp/${scriptNameWithoutExt}_homeDirsPathList.XXXXX)
ldapGroups=$(mktemp /tmp/${scriptNameWithoutExt}_ldapGroups.XXXXX)
openDirectoryServer="127.0.0.1"
warnDays=""
critDays=""
filterWithGroups=0
personalFilesToTest=0
personalHomeDirsPath=0
numberOfFilesToBeChanged=2
withPercentage=0
filesToTest="com.apple.finder.plist
com.apple.MCX.plist
com.apple.recentitems.plist
.DS_Store
Mail"
homeDirsPath="/users"
help="no"

function help () {
  echo ""
  echo "${version}"
  echo "This script warns or crits if mobile accounts aren't synchronized for a few days."
  echo ""
  echo "Disclamer:"
  echo "This tool is provide without any support and guarantee."
  echo ""
  echo "Synopsis:"
  echo "./${scriptName} [-h] | -w <warn days> -c <crit days>" 
  echo "                           [-g <user groups to process>] [-f <files to test>]"
  echo "                           [-u <opendirectory server>] [-p <homedirs path>]"
  echo "                           [-n <test files to be changed>] [-t <tolerance percentage>]"
  echo ""
  echo "To print this help:"
  echo "   -h:                        prints this help then exit"
  echo ""
  echo "Mandatory options:"
  echo "   -w <warn days>:            Number of days (without full synchronization of all accounts) from which warn."
  echo "   -c <crit days>:            Number of days (without full synchronization of all accounts) from which crit."
  echo ""
  echo "Optional options:"
  echo "   -g <user groups>:          User groups, in OpenDirectory server, the full path of the directory to check."
  echo "                              If you want to check more than one user group, separate groups with '%',"
  echo "                              like 'workgoup%students'."
  echo "                              If not used, all users registered in OpenDirectory server will be tested."
  echo "   -f <files to test>:        Files used to test synchronization in each mobile account,"
  echo "                              separated by '%' character, like 'com.apple.finder.plist%.DS_Store'"
  echo "                              (default: '$(echo ${filesToTest} | perl -p -e 's/ /%/g' | awk '!x[$0]++')')"
  echo "   -u <opendirectory server>: OpenDirectory server address (default: '${openDirectoryServer}')"
  echo "   -p <homedirs path>:        full path of home directories,"
  echo "                              separated by '%' character, like '/users%/PHD'"
  echo "                              (default: '$(echo ${homeDirsPath} | perl -p -e 's/ /%/g' | awk '!x[$0]++')')"
  echo "   -n <files to be changed>:  Number of changed test files necessary to consider that synchronization is OK,"
  echo "                              (default: '${numberOfFilesToBeChanged})."
  echo "   -t <tolerance percentage>: Percentage of non-synchronized accounts over which to warn or crit."
  echo "                              If not used, warns or crits from the first unsynchronized account."
  echo "                              You can use the same value for warn and crit (eg.: '-t 15'),"
  echo "                              or two values for warn and crit, separated by %, as '-t warn%crit'."
}

function alldone () {
  # Prints message
  [[ ! -z ${2} ]] && echo ${2}
  [[ ! -z $(cat ${messageContent}) ]] && echo "" && cat ${messageContent}
  # Remove temp files
  ls /tmp/${scriptNameWithoutExt}* > /dev/null 2>&1
  [[ $? -eq 0 ]] && rm -R /tmp/${scriptNameWithoutExt}*
  exit ${1}
}

function testInteger () {
  test ${1} -eq 0 2>/dev/null
  if [[ $? -eq 2 ]]; then
    echo 0
  else
    echo 1
  fi
}

function testMemberOfGroup () {
  [[ $# -ne 2 ]] && alldone 3 "FATAL ERROR - Function 'testMemberOfGroup' used without mandatory parameters!"
  dsmemberutil checkmembership -U "$1" -G "$2" | grep "is a member" > /dev/null 2>&1
  if [[ $? -eq 0 ]]; then
    echo 1
  else
    echo 0
  fi 
}

# Parameters tests
optsCount=0
while getopts "hw:c:g:f:u:p:n:t:" option
do
    case "$option" in
      h)  help="yes"
          ;;
      w)  warnDays=${OPTARG}
          let optsCount=${optsCount}+1
          ;;
      c)  critDays=${OPTARG}
          let optsCount=${optsCount}+1
          ;;
      g)  if [[ ! -z ${OPTARG} ]]; then
            filterWithGroups=1
            echo ${OPTARG} | perl -p -e 's/%/\n/g' | perl -p -e 's/ //g' | awk '!x[$0]++' >> ${groupsList}
          else
            echo "> You tried to use '-g' option without any groupname in argument." >> ${messageContent}
            echo "  So, we continue the process for all users registered in OpenDirectory server." >> ${messageContent}
            echo "" >> ${messageContent}
          fi
          ;;
      f)  if [[ ! -z ${OPTARG} ]]; then
            personalFilesToTest=1
            echo ${OPTARG} | perl -p -e 's/%/\n/g' | perl -p -e 's/ //g' | awk '!x[$0]++' >> ${filesToTestList}
          else
            echo "> You tried to use '-f' option without any file in argument." >> ${messageContent}
            echo "  So, we continue the process without default files:" >> ${messageContent}
            for file in ${filesToTest}; do
              echo "  - ${file}" >> ${messageContent}
            done
            echo "" >> ${messageContent}

          fi
          ;;
      u)  openDirectoryServer=${OPTARG}
          ;;
      p)  if [[ ! -z ${OPTARG} ]]; then
            personalHomeDirsPath=1
            echo ${OPTARG} | perl -p -e 's/%/\n/g' | perl -p -e 's/ //g' | awk '!x[$0]++' >> ${homeDirsPathList}
          else
            echo "> You tried to use '-p' option without any directory in argument." >> ${messageContent}
            echo "  So, we continue the process with the default path '${homeDirsPath}'." >> ${messageContent}
            echo "" >> ${messageContent}
          fi
          ;;
      n)  if [[ $(testInteger ${OPTARG}) -ne 1 ]]; then
            echo "> You tried to use '-n ${OPTARG}' option without an integer in argument." >> ${messageContent}
            echo "  So, we continue the process with the default value '${numberOfFilesToBeChanged}'." >> ${messageContent}
            echo "" >> ${messageContent}
          else
            numberOfFilesToBeChanged=${OPTARG}
          fi
          ;;
      t)  echo ${OPTARG} | grep % > /dev/null 2>&1
          if [[ $? -ne 0 ]]; then
            if [[ $(testInteger ${OPTARG}) -ne 1 ]]; then
              echo "> You tried to use '-t ${OPTARG}' option without an integer in argument." >> ${messageContent}
              echo "  So, we continue the process without option '-t'." >> ${messageContent}
              echo "" >> ${messageContent}
            else
              critPercentage=${OPTARG}
              warnPercentage=${OPTARG}
              withPercentage=1
            fi
          else
            warnPercentage=$(echo ${OPTARG} | cut -d ""%"" -f 1)
            critPercentage=$(echo ${OPTARG} | cut -d ""%"" -f 2)
            if [[ $(testInteger ${warnPercentage}) -ne 1 ]]; then
              echo "> You tried to use '-t ${OPTARG}' but ${warnPercentage} (warn value) is not an integer." >> ${messageContent}
              echo "  So, we continue the process without option '-t'." >> ${messageContent}
              echo "" >> ${messageContent}
            elif [[ $(testInteger ${critPercentage}) -ne 1 ]]; then
              echo "> You tried to use '-t ${OPTARG}' but ${critPercentage} (crit value) is not an integer." >> ${messageContent}
              echo "  So, we continue the process without option '-t'." >> ${messageContent}
              echo "" >> ${messageContent}
            else
              withPercentage=1
              if [[ ${critPercentage} -lt ${warnPercentage} ]]; then
                echo "> You tried to use '-t ${OPTARG}' but ${critPercentage} (crit %) is not greater (or equal) than ${warnPercentage} (warn %)." >> ${messageContent}
                echo "  So, we continue the process with option '-t ${critPercentage}%${critPercentage}'." >> ${messageContent}
                echo "" >> ${messageContent}
                warnPercentage=${critPercentage}
              fi
            fi
          fi
          ;;
    esac
done

# Prints help
[[ ${help} = "yes" ]] && help && alldone 0

# Test mandatory options
[[ "${warnDays}" == "" ]] && echo "> You must provide a delay (in days) with -w!" >> ${messageContent}
[[ "${critDays}" == "" ]] && echo "> You must provide a delay (in days) with -c!" >> ${messageContent}
[[ ${optsCount} != "2" ]] && alldone 3 "FATAL ERROR - All mandatory options are not filled."

#  Test root access
[[ `whoami` != 'root' ]] && alldone 3 "FATAL ERROR - This tool needs a root access. Use 'sudo'."

# Test if -w and -c are integers
[[ $(testInteger ${warnDays}) -ne 1 ]] && alldone 3 "ERROR - Option -w have to be an integer."
[[ $(testInteger ${critDays}) -ne 1 ]] && alldone 3 "ERROR - Option -c have to be an integer."

# Coherence tests
[[ ${critDays} -lt ${warnDays} ]] && alldone 2 "ERROR - Option -c have to be greater than (or equal) -w."

# Test groups
if [[ ${filterWithGroups} == "1" ]]; then
  for group in $(cat ${groupsList}); do
    dscl /LDAPv3/${openDirectoryServer} -list /Groups | grep ^${group}$ >> ${ldapGroups}
  done
  if [[ -z $(cat ${ldapGroups}) ]]; then
    echo "> You tried to use '-g' option without any groupname registered in OpenDirectory in argument." >> ${messageContent}
    echo "  So, we continue the process for all users registered in OpenDirectory server." >> ${messageContent}
    echo "" >> ${messageContent}
    filterWithGroups=0
  fi
fi

# Creating user list
if [[ ${filterWithGroups} == "0" ]]; then
  dscl /LDAPv3/${openDirectoryServer} -list /Users >> ${usersList}
elif [[ ${filterWithGroups} == "1" ]]; then
  for user in $(dscl /LDAPv3/${openDirectoryServer} -list /Users); do
    userIsMemberOfOneOrMoreGroups=0
    for group in $(cat ${ldapGroups}); do
      [[ $(testMemberOfGroup ${user} ${group}) -eq 1 ]] && userIsMemberOfOneOrMoreGroups=1
    done
    [[ ${userIsMemberOfOneOrMoreGroups} -eq 1 ]] && echo "${user}" >> ${usersList}
  done
fi

# Test if list of users is not empty
[[ -z $(cat ${usersList}) ]] && alldone 3 "FATAL ERROR - No user to process. Please verify your configuration."

# Test if user has a network home directory
for user in $(cat ${usersList} | sort -u); do
  dscl /LDAPv3/${openDirectoryServer} -read /Users/${user} HomeDirectory 2> /dev/null | grep -v "No such key" > /dev/null 2>&1
  [[ $? -eq 0 ]] && echo ${user} >> ${usersListWithNetworkDirectory}
done

# Test if list of users is not empty
[[ -z $(cat ${usersListWithNetworkDirectory}) ]] && alldone 3 "FATAL ERROR - No user with Network Home Directory. Please verify your configuration."

# List of files to test
if [[ ${personalFilesToTest} -eq 0 ]]; then
  for file in ${filesToTest}; do
    echo "${file}" >> ${filesToTestList}
  done
fi

# Directories
[[ ${personalHomeDirsPath} -eq 0 ]] && echo ${homeDirsPath} > ${homeDirsPathList}

## Processing each user
echo "************************************************************************************" >> ${messageContent}
echo "********************************* PROCESSING USERS *********************************" >> ${messageContent}
echo "************************************************************************************" >> ${messageContent}
echo "" >> ${messageContent}

numberOfUsers=0
numberOfUsersWithoutSyncCrit=0
numberOfUsersWithoutSyncWarn=0
for user in $(cat ${usersListWithNetworkDirectory}); do
  thisUserIsWarn=0
  thisUserIsCrit=0
  echo "> Processing user ${user}" >> ${messageContent}
  for actualHomeDir in $(cat ${homeDirsPathList}); do
    if [ -d ${actualHomeDir%/}/${user} ]; then
      echo "  Test in '${actualHomeDir%/}/${user}'" >> ${messageContent}
      warnFilesChanged=0
      critFilesChanged=0
      for fileToTest in $(cat ${filesToTestList}); do
        [[ ! -z $(find ${actualHomeDir%/}/${user} -maxdepth 3 -a -mtime -${critDays} -a -name ${fileToTest}) ]] && let critFilesChanged=${critFilesChanged}+1
        [[ ! -z $(find ${actualHomeDir%/}/${user} -maxdepth 3 -a -mtime -${warnDays} -a -name ${fileToTest}) ]] && let warnFilesChanged=${warnFilesChanged}+1
      done
      if [[ ${critFilesChanged} -lt ${numberOfFilesToBeChanged} ]]; then
        if [[ ${critFilesChanged} -le 1 ]]; then
          echo "  CRIT: ${critFilesChanged} file changed since ${critDays} days." >> ${messageContent}
          [[ ${critFilesChanged} -le 1 ]] && echo "  WARN: ${critFilesChanged} file changed since ${critDays} days." >> ${messageContent}
          [[ ${critFilesChanged} -ge 2 ]] && echo "  WARN: ${critFilesChanged} files changed since ${critDays} days." >> ${messageContent}
        elif [[ ${critFilesChanged} -ge 2 ]]; then
          echo "  CRIT: ${critFilesChanged} files changed since ${critDays} days." >> ${messageContent}
          [[ ${critFilesChanged} -le 1 ]] && echo "  WARN: ${critFilesChanged} file changed since ${critDays} days." >> ${messageContent}
          [[ ${critFilesChanged} -ge 2 ]] && echo "  WARN: ${critFilesChanged} files changed since ${critDays} days." >> ${messageContent}
        fi
        echo "  **** CRIT ****" >> ${messageContent}
        thisUserIsCrit=1
        thisUserIsWarn=1
      elif [[ ${warnFilesChanged} -lt ${numberOfFilesToBeChanged} ]]; then
        if [[ ${warnFilesChanged} -le 1 ]]; then
          echo "  WARN: ${warnFilesChanged} file changed since ${warnDays} days, but not CRIT, because:" >> ${messageContent}
          [[ ${critFilesChanged} -le 1 ]] && echo "  CRIT: ${critFilesChanged} file changed since ${critDays} days." >> ${messageContent}
          [[ ${critFilesChanged} -ge 2 ]] && echo "  CRIT: ${critFilesChanged} files changed since ${critDays} days." >> ${messageContent}
        elif [[ ${warnFilesChanged} -ge 2 ]]; then
          echo "  WARN: ${warnFilesChanged} files changed since ${warnDays} days, but not CRIT, because:" >> ${messageContent}
          [[ ${critFilesChanged} -le 1 ]] && echo "  CRIT: ${critFilesChanged} file changed since ${critDays} days." >> ${messageContent}
          [[ ${critFilesChanged} -ge 2 ]] && echo "  CRIT: ${critFilesChanged} files changed since ${critDays} days." >> ${messageContent}
        fi
        echo "  **** WARN ****" >> ${messageContent}
        thisUserIsWarn=1
      else
        if [[ ${critFilesChanged} -le 1 ]]; then
          echo "  CRIT: ${critFilesChanged} file changed since ${critDays} days." >> ${messageContent}
          [[ ${critFilesChanged} -le 1 ]] && echo "  WARN: ${critFilesChanged} file changed since ${critDays} days." >> ${messageContent}
          [[ ${critFilesChanged} -ge 2 ]] && echo "  WARN: ${critFilesChanged} files changed since ${critDays} days." >> ${messageContent}
        elif [[ ${critFilesChanged} -ge 2 ]]; then
          echo "  CRIT: ${critFilesChanged} files changed since ${critDays} days." >> ${messageContent}
          [[ ${critFilesChanged} -le 1 ]] && echo "  WARN: ${critFilesChanged} file changed since ${critDays} days." >> ${messageContent}
          [[ ${critFilesChanged} -ge 2 ]] && echo "  WARN: ${critFilesChanged} files changed since ${critDays} days." >> ${messageContent}
        fi
        echo "  ***** OK *****" >> ${messageContent}
      fi
    fi
  done
  echo "" >> ${messageContent}
  let numberOfUsers=${numberOfUsers}+1
  [[ ${thisUserIsCrit} -eq 1 ]] && let numberOfUsersWithoutSyncCrit=${numberOfUsersWithoutSyncCrit}+1
  [[ ${thisUserIsWarn} -eq 1 ]] && let numberOfUsersWithoutSyncWarn=${numberOfUsersWithoutSyncWarn}+1
done

## Overviews
echo "************************************************************************************" >> ${messageContent}
echo "************************************* OVERVIEW *************************************" >> ${messageContent}
echo "************************************************************************************" >> ${messageContent}
echo "" >> ${messageContent}

pctCrit=$((${numberOfUsersWithoutSyncCrit}*100/${numberOfUsers}))
pctWarn=$((${numberOfUsersWithoutSyncWarn}*100/${numberOfUsers}))
pctCritRd=$(printf "%.0f" $(echo "scale=2;$pctCrit" | bc))
pctWarnRd=$(printf "%.0f" $(echo "scale=2;$pctWarn" | bc))

echo "Number of accounts: ${numberOfUsers}" >> ${messageContent}
echo "Number of accounts without sync crit: ${numberOfUsersWithoutSyncCrit} - ${pctCritRd}%" >> ${messageContent}
echo "Number of accounts without sync warn: ${numberOfUsersWithoutSyncWarn} - ${pctWarnRd}%" >> ${messageContent}

if [[ ${withPercentage} -eq 0 ]]; then
  outputValues="CriticalPHD=${numberOfUsersWithoutSyncCrit} WarningPHD=${numberOfUsersWithoutSyncWarn}"
  if [[ ${numberOfUsersWithoutSyncCrit} -ge 1 ]]; then
    [[ ${numberOfUsersWithoutSyncCrit} -le 1 ]] && alldone 2 "CRITICAL - ${numberOfUsersWithoutSyncCrit}/${numberOfUsers} mobile accounts is not synced|${outputValues}"
    [[ ${numberOfUsersWithoutSyncCrit} -gt 1 ]] && alldone 2 "CRITICAL - ${numberOfUsersWithoutSyncCrit}/${numberOfUsers} mobile accounts aren't synced|${outputValues}"
  elif [[ ${numberOfUsersWithoutSyncWarn} -ge 1 ]]; then
    [[ ${numberOfUsersWithoutSyncWarn} -le 1 ]] && alldone 1 "WARNING - ${numberOfUsersWithoutSyncWarn}/${numberOfUsers} mobile accounts is not synced|${outputValues}"
    [[ ${numberOfUsersWithoutSyncWarn} -gt 1 ]] && alldone 1 "WARNING - ${numberOfUsersWithoutSyncWarn}/${numberOfUsers} mobile accounts aren't synced|${outputValues}"
  else
    alldone 0 "OK|${outputValues}"
  fi 
elif [[ ${withPercentage} -eq 1 ]]; then
  outputValues="CriticalPHD=${pctCritRd}%;${critPercentage};;0;100 WarningPHD=${pctWarnRd}%;${warnPercentage};;0;100"
  if [[ ${pctCritRd} -ge ${critPercentage} ]]; then
    alldone 2 "CRITICAL - ${numberOfUsersWithoutSyncCrit}/${numberOfUsers} mobile accounts aren't synced|${outputValues}"
  elif [[ ${pctWarnRd} -ge ${warnPercentage} ]]; then
    alldone 1 "WARNING - ${numberOfUsersWithoutSyncWarn}/${numberOfUsers} mobile accounts aren't synced|${outputValues}"
  else
    alldone 0 "OK|${outputValues}"
  fi
fi
alldone 0
check_mobile_accounts.shview rawview file on GitHub

 

#JeSuisCharlie