Skip to main content
Question

NT-ware uniFLOW SmartClient Uninstaller for Jamf Pro

  • November 6, 2020
  • 2 replies
  • 248 views

cainehorr
Forum|alt.badge.img+18

Are you running the NT-ware uniFLOW SmartClient for macOS?

As you probably know, NT-ware's older versions (v1.1.0 and lower) were not as robust as their Windows versions.

In order to upgrade/update to newer versions, you need to uninstall the older versions first.

NT-ware places their default uninstall script here...

/etc/smartclient/uninstall-smartclient.bash

Unfortunately, this script is extremely rudimentary and lacks any support for running in an automated environment that uses an MDM/UDM solution such as Jamf Pro.

With that, I give you my highly augmented version of an NT-ware uniFLOW SmartClient uninstaller that works both locally and/or with Jamf Pro.

A brief HOWTO is posted down below... after the script.

THE SCRIPT

#!/bin/sh

##############################################################################
#
# SCRIPT FILENAME:
#   uninstall_nt-ware_uniflow_smartclient.sh
#
# DESCRIPTION:
#   The core functionality of this script was written by NT-ware to uninstall
#   the uniFLOW SmartClient for macOS. 
#
#   This version of the uniFLOW SmartClient "uninstall-smartclient.sh" is a
#   complete overhaul that provides additional error checking, better local
#   user identification, multi-shell compatibility, robust support for unique
#   user environments, better output/logging, and a local (terminal) mode 
#   and an automated UDM/MDM (Jamf Pro) mode. 
#
# DISCLAIMER:
#   Jamf Pro is not required to run this script. This script can be used as
#   a replacement for the default "uninstall-smartclient.sh" that comes 
#   bundled with the uniFLOW SmartClient.
#
# CHANGE LOG:
#   v1.0 - 2020-11-05
#     Written by Caine Hörr
#     https://github.com/cainehorr
#       * Initial Script Creation
#         * Replaced vendor assigned shebang for bash and zsh compatibility
#         * Replaced vendor code that checks for sudo/root permissions to 
#           properly identify the currently logged in user
#         * Replaced vendor code with an array to process sub-folder deletion
#           within home folders
#         * Replaced vendor code with AppleScript to gracefully quit the 
#           uniFLOW SmartClient
#         * Removed vendor code that unnecessarily utilizes ls commands in 
#           favor of echoing path data already held within variables
#         * Added functions for multi-use code blocks
#         * Added comments to properly "document/explain" the script
#         * Added absolute path statements to all called binaries (because 
#           you never know what users have done to their system environment)
#         * Added error checking for existence of files and directories
#         * Added echo statements for running script both locally and for 
#           logging to Jamf Pro policy logs
#         * Added JamfHelper pop-ups to guide the user appropriately when
#           being run from Jamf Pro
#
##############################################################################

##############################################################################
#
# MIT License
#
# Copyright (c) 2020 Caine Hörr
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to 
# deal in the Software without restriction, including without limitation the 
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
#
##############################################################################

# Set the name and location of the uniFLOW SmartClient application
appName="/Applications/uniFLOW SmartClient.app"

# Acquire the currently installed version of uniFLOW SmartClient.app
currentAppVersion="$(defaults read "${appName}/Contents/Info" CFBundleShortVersionString | awk '{ print $1 }')"

##############################################################################
#
# EDIT THESE VALUES AS MUCH AS YOU WANT!
# 
# These values configure the jamfHelper pop-up window look and feel
#
window_Type="utility"
text_Title="mac@Your_Company_Name"
text_Header="uniFLOW SmartClient Uninstall"
align_Header="left"
text_Message_One="IT is uninstalling version ${currentAppVersion} of the following application from your device in preparation for an updated version\\n \\n${appName}\\n \\nClicking "OK" will begin the process. \\n \\nOn the next pop-up window, please click the "Yes" button."
text_Message_Two="The removal of version ${currentAppVersion} of the following application from your device has failed\\n \\nn${appName}\\n \\nPlease contact IT for immediate remediation."
text_Message_Three="The removal of version ${currentAppVersion} of the following application from your device has completed\\n \\n${appName}\\n \\nIT will now proceed with installing an updated version."
align_Description="left"
icon_path="/path/to/your/corporate/logo.png"
button_Continue="OK"
button_Default=1
#
##############################################################################

##############################################################################
#
# THERE ARE NO USER SERVICABLE PARTS DOWN HERE...
# DO NOT EDIT BELOW THIS LINE!
#
##############################################################################

# Check for sudo/root permissions
# This is only need when running the script locally
# When running in an automated UDM/MDM environment, sudo/root is implied
if [[ "$(/usr/bin/id -u)" != "0" ]]; then
  echo "[ERROR] $0 requires sudo/root privileges"
  exit 1
fi

function_jamfHelperPopUpWindow(){
  # Call jamfHelper and display the pop-up window
  jamfHelper -windowType "${window_Type}" -lockHUD -title "${text_Title}" -heading "${text_Header}" -alignHeading "${align_Header}" -description "${text_Description}" -alignDescription "${align_Description}" -icon "${icon_path}" -button1 "${button_Continue}" -defaultButton "${button_Default}"

}

function_quit_uniFLOW_SmartClient(){
  if [[ ${jamfHelperInstalled} = "True" ]]; then
    # Set the jamfHelper Message
    text_Description=$( echo ${text_Message_One} )

    function_jamfHelperPopUpWindow
  fi

  # Attempt to quit the uniFLOW SmartClient gracefully
  /usr/bin/osascript <<'END'
tell application "SmartClient"
  quit
end tell
END
}

echo "Preparing to uninstall ${appName} v${currentAppVersion}"

# Set path to the jamfHelper.app
jamfHelperPath=/Library/Application Support/JAMF/bin/jamfHelper.app

if [[ -d "${jamfHelperPath}" ]]; then
  jamfHelperInstalled="True"
  echo "jamfHelper is installed - Running in Jamf Pro mode"
  # Set path to the jamfHelper.app/Contents/MacOS
  PATH=$PATH:/Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS
else
  jamfHelperInstalled="False"
  echo "jamfHelper is not installed - Running in terminal mode"
fi

# Identify if the uniFLOW SmartClient is running - First Pass
runningInstance=$(/bin/ps -a -x -o comm | /usr/bin/grep 'SmartClient$' )
# Validate that $runningInstance contains information
if [[ -n "$runningInstance" ]]; then
  echo "[WARNING] uniFLOW SmartClient is running on this device - Attempting to quit"
  function_quit_uniFLOW_SmartClient

  until function_quit_uniFLOW_SmartClient; do
    if [[ $? -eq 0 ]]; then
        echo "User agreed to the uniFLOW SmartClient uninstallation"
    fi
  done
else
  echo "[WARNING] uniFLOW SmartClient is not running on this device"
fi

# Identify if the uniFLOW SmartClient is running - Second Pass
runningInstance=$(/bin/ps -a -x -o comm | /usr/bin/grep 'SmartClient$' )
# Validate that $runningInstance does not contains information
if [[ ! -z "$runningInstance" ]]; then
  echo "[ERROR] uniFLOW SmartClient is running on this device - Attempting to quit has failed"

  if [[ ${jamfHelperInstalled} = "True" ]]; then
    # Set the jamfHelper Message
    text_Description=$( echo ${text_Message_Two} )

    function_jamfHelperPopUpWindow
  fi

  exit 1
fi

# Remove UniFlow SmartCient Domains and Services 
plistPath=/Library/LaunchAgents/com.ntware.SmartClient.plist
if [[ -f ${plistPath} ]]; then
  echo "Removing UniFlow SmartCient Domains and Services"
  /bin/launchctl bootout system /Library/LaunchAgents/com.ntware.SmartClient.plist
fi

# Delete existing uniFLOW SmartClient printer queues
if [[ -f /Users/shared/.smartclient/queue_created_at_installation ]]; then
   QUEUE_NAME_NO_SPACES=$(/bin/cat /Users/shared/.smartclient/queue_created_at_installation)
   # Validate that $QUEUE_NAME_NO_SPACES is not null
   if [[ -n "$QUEUE_NAME_NO_SPACES" ]]; then
      echo "Deleting printer queue $QUEUE_NAME_NO_SPACES"
      # Delete the printer or class destination
      /usr/sbin/lpadmin -x "$QUEUE_NAME_NO_SPACES"
   fi
fi

# Identify the uniFLOW SmartClient printers and what devices they are attached to
list=$(/usr/bin/lpstat -v | /usr/bin/grep 'mom:S*$')
# Determine the number of uniFLOW SmartClient printers present
count=$(echo "$list" | /usr/bin/wc -l)

for queueNumber in $(seq $count); do
   name=$(echo "$list" | /usr/bin/sed -n "$queueNumber p" | /usr/bin/awk '{print $(NF-1)}' 2>/dev/null | /usr/bin/sed 's?:$??')
   newPath=$(echo "$list" | /usr/bin/sed -n "$queueNumber p" | /usr/bin/awk '{print $(NF)}' 2>/dev/null | /usr/bin/sed 's?mom:??g')
   # If $name OR $newPath value is null then continue to the next queueNumber
   # in the loop without running any further commands below this if/then statement
   if [ -z "$name" -o -z "$newPath" ]; then
      continue
   fi
  # The following statements will not execute if $name OR $newPath are null
   echo "Changing path for $name to $newPath"
   /usr/sbin/lpadmin -p "$name" -E -v "$newPath"
done

# If the script can't uninstall all uniFLOW SmartClient printers, throw this error
remaining=$(/usr/bin/lpstat -v | /usr/bin/grep 'mom:S*$')
if [[ -n "$remaining" ]]; then
   echo "[ERROR] Unable to remove 'mom:' backend from all printers. \\n \\nPlease do so manually before attempting to uninstall again."
   exit 1
fi

# Set input field separator to a comma ","
IFS=','

files='/Library/LaunchAgents/com.ntware.SmartClient.plist,/private/etc/paths.d/momadmin-path,/private/etc/sudoers.d/momadmin-sudoers,/usr/libexec/cups/backend/mom,/usr/local/sbin/momadmin.sh'
directories='/Applications/uniFLOW SmartClient.app,/private/etc/smartclient,/Users/Shared/.smartclient'

# Check for the existence of files as declared in $files
for file in ${files}; do
  # If file is not found, break out of loop
  if [[ ! -f ${file} ]]; then
    # If content of $file is not found then continue to the next itteration of $file
    # in the loop without running any further commands below this if/then statement
    echo "[WARNING] File not found: ${file}"
    continue
  fi
  # The following statements will not execute if $file is not found
  # Delete ${file}
  /bin/rm -f ${file}
  echo "Deleting the following file: ${file}"
done

# Check for the existence of directories as declared in $directories
for directory in ${directories}; do
  if [[ ! -d ${directory} ]]; then
    # If content of $directories is not found then continue to the next itteration of $directories
    # in the loop without running any further commands below this if/then statement
    echo "[WARNING] Directory not found: ${directory}"
    continue
  fi
  # The following statements will not execute if $directories is not found
  # Delete ${directory} 
  /bin/rm -r ${directory}
  echo "Deleting the following directory: ${directory}"
done

# Delete all .smartclient sub-directories from all User home folders
array=(/Users/*)
for i in "${!array[@]}"; do
  userDirectory=${array[i]}
  smartClientUserConfig="${userDirectory}/.smartclient"
  if [[ -d "${smartClientUserConfig}" ]]; then
    echo "Deleting ${smartClientUserConfig}"
    /bin/rm -rf "${smartClientUserConfig}"
  else
    echo "[WARNING] Directory not found: ${smartClientUserConfig}"
  fi
done

if [[ ${jamfHelperInstalled} = "True" ]]; then
  # Set the jamfHelper Message
  text_Description=$( echo ${text_Message_Three} )

  function_jamfHelperPopUpWindow
fi

exit

HOWTO USE uninstall_nt-ware_uniflow_smartclient.sh

It's pretty straight forward really.

  1. Upload the script to Jamf Pro > Settings > Computer Management > Script
  2. Set the script priority to "Before"
  3. Create a Computer Policy and assign the script
  4. Set any additional policy parameters you require

ENJOY!

2 replies

Forum|alt.badge.img
  • New Contributor
  • December 10, 2021

We are having issues installing SmartClient. Do you have any ideas for how we might do that?


Forum|alt.badge.img+14

We just switched from PaperCut to uniFLOW and we discovered exactly what you described in terms of requiring an uninstall. Thanks for doing the work and making life easier. Cheers!