App Uninstallation Script (Universal)

MPL
Contributor II

Hello Jamf Community,

 

I previously posted this a couple weeks ago but still am struggling to figure out exactly how to get it working.

 

I am trying to create a script that will prompt a user with a popup box on which application they'd like to uninstall (only apps we deem approved). For example, a popup would come up and ask someone "Select an app you'd like to uninstall" with a list of apps such as, Google Chrome, Firefox, Adobe, etc.

 

Currently I have script that I feel is about 90% of the way there but still can't figure out how to get it completely working. I'll post it below.

 

Also, if there's any easier way to do this, please do let me know as well!

 

Any help is greatly appreciated! There may be some unnecessary lines in the script just FYI. Here's the script:

 

#!/bin/bash

# Parameters
app1="$4"
app2="$5"
app3="$6"
app4="$7"
app5="$8"

appList="$4
$5
$6
$7
$8"

uninstallApp="choose from list every paragraph of \"$appList\" with title \"Application Uninstaller\" with prompt \"Select which application you'd like to uninstall: \" multiple selections allowed false empty selection allowed false"

chosenApp=$( /usr/bin/osascript -e "$uninstallApp" )

exit

# Jamf helper information
jamfHelper="/Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper"

description1="Select one of the following approved applications to uninstall:"
description2="The software you selected has been uninstalled."
invalidEntry="Invalid Entry"

########Functions###########
uninstallSuccessful(){
	
	buttonClicked=$("$jamfHelper" -windowType hud -lockHUD -windowPosition "center" -title "Software Uninstalled" -description "${description2}" -alignDescription "Left" -button1 "OK")
}
invalidEntry(){
	
	buttonClicked=$("$jamfHelper" -windowType hud -lockHUD -windowPosition "center" -title "Invalid Entry" -description "$invalidEntry" -alignDescription "Left" -button1 "OK")
}
initializeUninstaller1(){
		# Force Quit the app
		ps aux | grep "$4.app" | grep -v "grep" | awk '{print $2}' | xargs kill -15
        
        # Remove the App
        /bin/rm -Rf "/Applications/$4.app"
}

initializeUninstaller2(){
		# Force Quit the app
		ps aux | grep "$5.app" | grep -v "grep" | awk '{print $2}' | xargs kill -15
        
        # Remove the App
        /bin/rm -Rf "/Applications/$5.app"
}

initializeUninstaller3(){
		# Force Quit the app
		ps aux | grep "$6.app" | grep -v "grep" | awk '{print $2}' | xargs kill -15
        
        # Remove the App
        /bin/rm -Rf "/Applications/$6.app"
}

appCheck(){
	if [[ $chosenApp == $4 ]]; then
		echo "User selected $4"
		echo "Initializing Software Uninstaller"
        initializeUninstaller1
        uninstallSuccessful
        
	elif [[ $chosenApp == $5  ]]; then
		echo "User selected $5"
		echo "Initializing Software Uninstaller"
        initializeUninstaller2
        uninstallSuccessful
        
   	elif [[ $chosenApp == $6  ]]; then
		echo "User selected $6"
		echo "Initializing Software Uninstaller"
        initializeUninstaller3
        uninstallSuccessful
   
    elif [[ $chosenApp != "2745wnfeljf23490" ]]; then
    	echo "Invalid Entry"
        invalidEntry
    
		exit 0
	fi
}

appCheck

exit 0		## Success
exit 1		## Failure

 

 

1 ACCEPTED SOLUTION

stevewood
Honored Contributor II
Honored Contributor II

I updated the script. The `pgrep` call was looking for the full app name and not the process name.

`pgrep $1` is getting the variable that was passed to the function. Inside a shell script when you send a variable to a function, you can access that variable as `$1`. Make sense?

 

#!/bin/bash

appList="$4
$5
$6
$7
$8"

uninstallApp="choose from list every paragraph of \"$appList\" with title \"Application Uninstaller\" with prompt \"Select which application you'd like to uninstall: \" multiple selections allowed false empty selection allowed false"

chosenApp=$( /usr/bin/osascript -e "$uninstallApp" )

# Jamf helper information
jamfHelper="/Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper"

description1="Select one of the following approved applications to uninstall:"
description2="The software you selected has been uninstalled."
invalidEntry="Invalid Entry"

########Functions###########
uninstallSuccessful(){
	
	buttonClicked=$("$jamfHelper" -windowType hud -lockHUD -windowPosition "center" -title "Software Uninstalled" -description "${description2}" -alignDescription "Left" -button1 "OK")
}

invalidEntry(){
	
	buttonClicked=$("$jamfHelper" -windowType hud -lockHUD -windowPosition "center" -title "Invalid Entry" -description "$invalidEntry" -alignDescription "Left" -button1 "OK")
}

initializeUninstaller(){
    # Force Quit the app
    pgrep $1 | xargs kill -15
    
    # Remove the App
    /bin/rm -Rf "/Applications/$1.app"
}

if [[ -d "/Applications/$chosenApp.app" ]]; then
    
    echo "User selected $chosenApp"
    echo "Initializing Software Uninstaller"
    initializeUninstaller "$chosenApp" # pass the app name to the function
    uninstallSuccessful
    exit 0
    
else
    
    invalidEntry
    exit 1
    
fi

View solution in original post

30 REPLIES 30

Fluffy
Contributor III

Where exactly is it failing?

I would recommend adding echo commands to confirm your variables as your script runs to see if something isn't coming out as it should.

And I may be missing something, but what is the purpose of the grep -v "grep" command in your initializeUninstaller functions?

MPL
Contributor II

Hey Fluffy,

 

Thanks for the reply! I actually grabbed that from another script someone provided me a couple weeks ago in a previous post. I'm not too familiar with writing scripts so I just left it there. Do you think it should be removed?

 

So running the policy currently provides a prompt (screenshot below) on which app to uninstall. The issue is after the apple script policy, it doesn't actually process the uninstallation. The policy fails because of "done" in the apple script. Not sure how to get it to feed to the next part of the script where it runs (post user selection) "appcheck".

 

Screenshot: 

Screen Shot 2022-06-10 at 9.34.01 AM.png

 

Policy Results:

 

[STEP 1 of 4]
Executing Policy Universal App Uninstaller - Testing
[STEP 2 of 4]
Running script Universal Applications Uninstaller...
Script exit code: 2
Script result: /Library/Application Support/JAMF/tmp/Universal Applications Uninstaller: line 20: syntax error near unexpected token `done'
/Library/Application Support/JAMF/tmp/Universal Applications Uninstaller: line 20: `done'
Error running script: return code was 2.
[STEP 3 of 4]
[STEP 4 of 4]

 

 

stevewood
Honored Contributor II
Honored Contributor II

You have an `exit` command on line 22, right after you call the `osascript` on line 20. That will stop your script from moving forward. Not sure why you're receiving that error on line 20 though. I ran this without issue on my machine.

You can, however, cleanup your script a bit and make it more compact. There's no need for the parameter list at the top. You never use it, unless you have plans for it in the future. And if you do, why not use those variables when creating your `appList` array?

You can generalize your `initializeUninstaller` function so that you just pass the `$chosenApp` variable to the function. No need for an individual uninstall function for each app.

The `grep -v "grep"` command is to ignore the output of your `grep` command prior. Confusing, I know, but if you were to issue `ps aux | grep "Safari.app"` you'd see that one of the items returned would be that `grep "Safari.app"` command. Instead you can use `pgrep` which looks for the process ID of any running process with the name passed. So the above becomes `pgrep Safari`.

I've cleaned up the code a little and tested on my Monterey device and this seems to work. Granted I am running this from Code Runner and not via a policy, so you may need to test in Jamf Pro.

 

#!/bin/bash

appList="$4
$5
$6
$7
$8"

uninstallApp="choose from list every paragraph of \"$appList\" with title \"Application Uninstaller\" with prompt \"Select which application you'd like to uninstall: \" multiple selections allowed false empty selection allowed false"

chosenApp=$( /usr/bin/osascript -e "$uninstallApp" )
chosenApp=$chosenApp.app

# Jamf helper information
jamfHelper="/Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper"

description1="Select one of the following approved applications to uninstall:"
description2="The software you selected has been uninstalled."
invalidEntry="Invalid Entry"

########Functions###########
uninstallSuccessful(){
	
	buttonClicked=$("$jamfHelper" -windowType hud -lockHUD -windowPosition "center" -title "Software Uninstalled" -description "${description2}" -alignDescription "Left" -button1 "OK")
}

invalidEntry(){
	
	buttonClicked=$("$jamfHelper" -windowType hud -lockHUD -windowPosition "center" -title "Invalid Entry" -description "$invalidEntry" -alignDescription "Left" -button1 "OK")
}

initializeUninstaller(){
    # Force Quit the app
    pgrep $1 | xargs kill -15
    
    # Remove the App
    /bin/rm -Rf "/Applications/$1"
}

if [[ -d "/Applications/$chosenApp" ]]; then
    
    echo "User selected $chosenApp"
    echo "Initializing Software Uninstaller"
    initializeUninstaller "$chosenApp" # pass the app name to the function
    uninstallSuccessful
    exit 0
    
else
    
    invalidEntry
    exit 1
    
fi

MPL
Contributor II

@stevewood This is almost perfect!!! Thank you so much!

 

The one issue I still see happening is it's not quitting the app prior to uninstallation. Is there a reason for that?

 

In the script, just out of curiosity, I see the "pgrep $1"...what is that grabbing? The mount point? Or should that be changed to $chosenApp or $4, $5 etc?

 

Also if you can, how would you add an "invalid entry" or "app not found" popup, let's say if a user selects to uninstall Firefox but they didn't have Firefox on their system? 

stevewood
Honored Contributor II
Honored Contributor II

I updated the script. The `pgrep` call was looking for the full app name and not the process name.

`pgrep $1` is getting the variable that was passed to the function. Inside a shell script when you send a variable to a function, you can access that variable as `$1`. Make sense?

 

#!/bin/bash

appList="$4
$5
$6
$7
$8"

uninstallApp="choose from list every paragraph of \"$appList\" with title \"Application Uninstaller\" with prompt \"Select which application you'd like to uninstall: \" multiple selections allowed false empty selection allowed false"

chosenApp=$( /usr/bin/osascript -e "$uninstallApp" )

# Jamf helper information
jamfHelper="/Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper"

description1="Select one of the following approved applications to uninstall:"
description2="The software you selected has been uninstalled."
invalidEntry="Invalid Entry"

########Functions###########
uninstallSuccessful(){
	
	buttonClicked=$("$jamfHelper" -windowType hud -lockHUD -windowPosition "center" -title "Software Uninstalled" -description "${description2}" -alignDescription "Left" -button1 "OK")
}

invalidEntry(){
	
	buttonClicked=$("$jamfHelper" -windowType hud -lockHUD -windowPosition "center" -title "Invalid Entry" -description "$invalidEntry" -alignDescription "Left" -button1 "OK")
}

initializeUninstaller(){
    # Force Quit the app
    pgrep $1 | xargs kill -15
    
    # Remove the App
    /bin/rm -Rf "/Applications/$1.app"
}

if [[ -d "/Applications/$chosenApp.app" ]]; then
    
    echo "User selected $chosenApp"
    echo "Initializing Software Uninstaller"
    initializeUninstaller "$chosenApp" # pass the app name to the function
    uninstallSuccessful
    exit 0
    
else
    
    invalidEntry
    exit 1
    
fi

MPL
Contributor II

Awesome thank you so much. I really appreciate it! Finally got it fully working :D.

 

Yep that makes complete sense!

 

Thanks again!!

SMR1
Contributor III

I added this script to a self-service policy to test, but when I run it, it doesn't do anything. I think I'm missing something.

stevewood
Honored Contributor II
Honored Contributor II

Did you provide the application name(s) to remove as Parameter 4, 5, 6, 7, and 8 in Jamf Pro? Or you can hardcode the applications by putting that in the 'appList' variable.

For example, if you wanted to remove Google Chrome and Microsoft Edge, you could set 'appList' like this:

 

appList="Google Chrome
Microsoft Edge"

SMR1
Contributor III

Whoops! Works great.

SMR1
Contributor III

Is it possible to configure the script to uninstall the app when running it in self-service instead of selecting the app and then uninstall?

stevewood
Honored Contributor II
Honored Contributor II

If you want to place a policy to uninstall a specific app, like Google Chrome, in Self Service, you can hard code that app and remove the 'appList' and remove the notifications that ask the user to choose.

This is a very simple (and untested) script that could accomplish that. Use Parameter 4 in Jamf Pro to pass the application that you want to uninstall.

#!/bin/bash

appToUninstall="$4"

########Functions###########
initializeUninstaller(){
    # Force Quit the app
    pgrep $1 | xargs kill -15
    
    # Remove the App
    /bin/rm -Rf "/Applications/$1.app"
}

if [[ -d "/Applications/$appToUninstall.app" ]]; then
    
    initializeUninstaller "$appToUninstall" # pass the app name to the function
    exit 0
    
else
    
    echo "Application is not installed on system."
    exit 1
    
fi

This has no messaging at all, so you would want to add something via the policy or add to the script.

Matexusa
New Contributor II

@stevewood This works perfectly for what I need! Amazing approach - short, sweet, and simple!

Matexusa
New Contributor II

Hello @stevewood - Please I need a little more assistance on this as I'm very new to Jamf. Your approach worked perfectly but I realized that I still have a left-over app and folder that I would like to remove when I run the policy.

Avast has an Uninstaller app called "Avast One Uninstaller" or "Avast Uninstaller" for some of our old machines in --> \Applications\Avast

There is also an Avast folder that I would like to remove in --> \Library\Application Support\Avast

Please any help here is appreciated!

#!/bin/bash

appToUninstall="$4"

########Functions###########
initializeUninstaller(){
    # Force Quit the app
    pgrep $1 | xargs kill -15
    
    # Remove the App
    /bin/rm -Rf "/Applications/$1.app"
rm -R /Applications/*Avast*
rm -R /Library/Application\ Support/*Avast*

}

if [[ -d "/Applications/$appToUninstall.app" ]]; then
    
    initializeUninstaller "$appToUninstall" # pass the app name to the function
    exit 0
    
else
    
    echo "Application is not installed on system."
    exit 1
    
fi

stevewood
Honored Contributor II
Honored Contributor II

Have you checked the Avast app bundle for an uninstall script? I found this old Jamf Nation post that references an uninstall.sh in "/Applications/Avast.app/Contents/Backend/utils/com.avast.uninstall.app/Contents/Resources/uninstall.sh". If that script is available I would try using that instead of the script I posted. Using the one provided by Avast should get all of the bits removed.

You can also check in the app bundles for those Uninstaller apps. There may be an uninstall script in there. You can use an if/then to test for the presence of the different versions of Uninstaller apps.

Matexusa
New Contributor II

Thanks so much for your response. Since your respond, I have been looking for the Uninstall script all over and I have not been successful in locating any script -- Seems that Avast have made some changes there - Avast and Avast one, both have an uninstallation app, is there a way to add a script line to call that Uninstallation file instead? If Jamf can run that uninstallation app, it will solve my issue. I'm just a month into Jamf, so I'm a newbie with scripting :) Thanks! 

Matexusa
New Contributor II

Hi @stevewood So, started reading every document if in the Avast app and I ran into this segment of Uninstaller paths that caught my eyes (eyes were wide open!)

-------------------------------------------

see attached.

------------------------------------------

so based on the above area of interest, I focused on these two paths to play with:

(1) /Applications/Avast.app/Contents/Backend/hub/uninstalluser.sh

(2) /Applications/Avast.app/Contents/Backend/hub/uninstall_wrapper.sh

None worked from my Mac Terminal, so I stared manipulating few things and I discovered that running this command on terminal did clean out Avast from my system -->

sudo /Applications/Avast.app/Contents/Backend/hub/uninstall.sh

How do I set this up as a policy in Jamf to run silently in the background. Someone wrote to configure it in Files and Process.

Thanks again.

 

 

Matexusa
New Contributor II
-------------------------------------------
com.avast.one.uninstaller.xpc/Library/LaunchDaemons/com.avast.one.uninstaller.xpc.plist/ Applications/Avast.app/Contents/Backend/hub/uninstall_wrapper.sh
/Applications/Avast.app/Contents/Backend/hub/uninstalluser.sh/Library/Application Support/Avast/config/license.avastlicdata/Applications/Avast.app/Contents/Backend/version.tag
/Applications/Avast.app/Contents/Backend/variant.tagContents/Resources/com.avast.one.uninstaller.xpc.cleanup.sh/Library/PrivilegedHelperTools/%@/bin/launchctlremove//
------------------------------------------

Matexusa
New Contributor II

Thanks again for creating the path! All looks good on my end, using the simple File and Process policy did the job! I'm all set now. 

MPL
Contributor II

@SMR1 The script I use currently uninstalls the app during the self service policy run. I've made some changes to the original script above but I'll post my fully working script that we have in production below in case you want to take a look. Added a JAMF inventory update post uninstall, added some icons, added parameters 10/11, and changed the window type, etc.

 

 

 

 

#!/bin/bash

appList="$4
$5
$6
$7
$8
$9
${10}
${11}"

uninstallApp="choose from list every paragraph of \"$appList\" with title \"Application Uninstaller\" with prompt \"Select which approved application you'd like to uninstall: \" multiple selections allowed false empty selection allowed false"

chosenApp=$( /usr/bin/osascript -e "$uninstallApp" )

# Jamf helper information
jamfHelper="/Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper"

description1="The $chosenApp application has been uninstalled."
invalidEntry="You either cancelled or the selection you made was invalid. 

If the application you'd like to remove is not listed, reach out to the IT Support Team for further assistance."

########Functions###########
uninstallSuccessful(){
	
	buttonClicked=$("$jamfHelper" -windowType utility -windowPosition "center" -title "Software Uninstalled" -description "${description1}" -alignDescription "Left" -icon "/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/ErasingIcon.icns" -button1 "OK")
}

invalidEntry(){
	
	buttonClicked=$("$jamfHelper" -windowType utility -windowPosition "center" -title "Invalid Entry" -description "$invalidEntry" -alignDescription "Left" -icon "/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/ToolbarDeleteIcon.icns" -button1 "OK")
}

initializeUninstaller(){
    # Force Quit the app
    pgrep $1 | xargs kill -15
    
    # Remove the App
    /bin/rm -Rf "/Applications/$1.app"
    
    # Force Quit the app again (for redundancy)
    pgrep $1 | xargs kill -15
    
    # Update JAMF Inventory
    sudo jamf recon
}

########End of Functions###########

if [[ -d "/Applications/$chosenApp.app" ]]; then
    
    echo "User selected $chosenApp"
    echo "Initializing Software Uninstaller..."
    initializeUninstaller "$chosenApp" # pass the app name to the function
    uninstallSuccessful
    echo "$chosenApp uninstalled"
    exit 0
    
else
    
    echo "Invalid Entry"
    invalidEntry
    echo "User cancelled or made an invalid selection"
    exit 0
    
fi

 

 

 

 

Jay_007
Contributor

Great script! Has anyone found a way to change it so it will return all apps, but exclude apps in the app list instead?

I got this this to return all apps, but it seems to be ignoring my exclusion list.

excludeAppList="Google Chrome.app
Microsoft Edge.app
"

appList=$(mdfind -onlyin /Applications "kMDItemCFBundleIdentifier != com.apple.* && kMDItemFSName != "$excludeAppList" && kMDItemKind = Application" | awk -F'/' '{print $NF}' | sort -f)

 

Fluffy
Contributor III

I don't think mdfind likes having multiple lines fed to it. Instead you can pipe it into grep -v to take out what you have in your variable.

excludeAppList="Google Chrome.app
Microsoft Edge.app"

appList=$(mdfind -onlyin /Applications "kMDItemCFBundleIdentifier != com.apple.* && kMDItemKind = Application" | grep -v "$excludeAppList" | awk -F'/' '{print $NF}' | sort -f)

Make sure to take out the new line in your excludeAppList variable as I did above or grep -v will remove everything piped from mdfind instead.

That worked perfectly, thanks!

I did have to also remove the file extension, otherwise I ended up with "Application.app.app".

 

So for anyone else that comes across this, this is the final working solution to show the user all apps in "/Applications", except apps listed in your "excludeAppList":

 

excludeAppList="Google Chrome.app
Microsoft Edge.app"

appList=$(mdfind -onlyin /Applications "kMDItemCFBundleIdentifier != com.apple.* && kMDItemKind = Application" | grep -v "$excludeAppList" | awk -F'/' '{print $NF}' | cut -f 1 -d '.' | sort -f)

 

 

Edit:

 

I've tidied things up a bit and added a function to handle if the returned list is empty.

This will show all apps in "/Applications" with the file extension ".app", but without the "com.apple.*" bundle identifier and it will also exclude any apps in your exclusion list. 

 

 

#!/bin/bash

# List of apps to exculde from being able to uninstall
excludeAppList=".Trash
Google Chrome.app
Citrix Workspace.app
OneDrive.app
Self Service.app
Jamf*
Microsoft*"


# Build App list
appList=$(mdfind -onlyin /Applications "kMDItemCFBundleIdentifier != com.apple.* && kMDItemFSName == *.app" | grep -v "$excludeAppList" | awk -F'/' '{print $NF}' | cut -f 1 -d '.' | sort -f)

# Jamf helper
jamfHelper="/Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper"

########Functions###########
uninstallSuccessful(){
	description1="The $chosenApp application has been successfully uninstalled."
	buttonClicked=$("$jamfHelper" -windowType utility -windowPosition "center" -title "Application Uninstalled" -description "${description1}" -alignDescription "Left" -icon "/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/ErasingIcon.icns" -button1 "OK")
}

invalidEntry(){
	invalidEntry="You either cancelled or the selection you made was invalid. 

If the application you'd like to remove is not listed, please reach out to your IT Support Team for further assistance."
	buttonClicked=$("$jamfHelper" -windowType utility -windowPosition "center" -title "Invalid Entry" -description "$invalidEntry" -alignDescription "Left" -icon "/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/ToolbarDeleteIcon.icns" -button1 "OK")
}

listEmpty(){
	listEmpty="No applications were found or all installed applications are required on your computer." 
	buttonClicked=$("$jamfHelper" -windowType utility -windowPosition "center" -title "No Applications Found" -description "$listEmpty" -alignDescription "Left" -icon "/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/ToolbarInfo.icns" -button1 "OK")
}

initializeUninstaller(){
    # Force Quit the app
    pgrep $1 | xargs kill -15
    
    # Remove the App
    /bin/rm -Rf "/Applications/$1.app"
    
    # Force Quit the app again (for redundancy)
    pgrep $1 | xargs kill -15
    
    # Update JAMF Inventory
    sudo jamf recon
}

########End of Functions###########

#######Begin Main Routine##########

# If list is emtpy, prompt user and exit
if [ -z "${appList}" ]; then
    
   echo "No apps available for removal"
   listEmpty
   echo "App list returned as empty. Exiting..."
   exit 0

# If list is not empty, show list for user selection.
else
	echo "Apps are available for removal. Prompting user with app list..."
    uninstallApp="choose from list every paragraph of \"$appList\" with title \"Application Remover\" with prompt \"Select which application you'd like to uninstall: 
    
Please note: Applications that are required to be on your computer will not be listed. \" multiple selections allowed false empty selection allowed false"

chosenApp=$( /usr/bin/osascript -e "$uninstallApp" )

    # If selected app exists, uninstall, prompt user and exit.
    if [[ -d "/Applications/$chosenApp.app" ]]; then

        echo "User selected $chosenApp"
        echo "Initializing Software Uninstaller..."
        initializeUninstaller "$chosenApp" # pass the app name to the function
        uninstallSuccessful
        echo "$chosenApp uninstalled"
        exit 0
	
    # If user cancelled or selection was invalid, prompt user and exit.
    else

       echo "Invalid Entry"
       invalidEntry
       echo "User cancelled or made an invalid selection"
       exit 0

    fi

fi

 

 

 

 

 

MALmen
New Contributor III

Hello! Tried this script and it works great except one thing :) Its seems to not understans app name with a "." in the name. For example zoom.us

Is there a way to fix this? :)

Hi, My script is specifically looking for apps with the extension ".app". It's not that can't find anything with "." in the name. The ".us" extension will be the issue for you.

 

I've modified it so it should now find everything in the "/Applications/" directory except apps with the "com.apple.*" bundle identifier. You may have to update your exclude list depending on what it returns. 

 

#!/bin/bash

# List of apps to exculde from being able to uninstall
excludeAppList=".Trash
Google Chrome.app
Citrix Workspace.app
OneDrive.app
Self Service.app
Jamf*
Microsoft*"


# Build App list
appList=$(mdfind -onlyin /Applications "kMDItemCFBundleIdentifier != com.apple.* | grep -v "$excludeAppList" | awk -F'/' '{print $NF}' | cut -f 1 -d '.' | sort -f)

# Jamf helper
jamfHelper="/Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper"

########Functions###########
uninstallSuccessful(){
	description1="The $chosenApp application has been successfully uninstalled."
	buttonClicked=$("$jamfHelper" -windowType utility -windowPosition "center" -title "Application Uninstalled" -description "${description1}" -alignDescription "Left" -icon "/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/ErasingIcon.icns" -button1 "OK")
}

invalidEntry(){
	invalidEntry="You either cancelled or the selection you made was invalid. 

If the application you'd like to remove is not listed, please reach out to your IT Support Team for further assistance."
	buttonClicked=$("$jamfHelper" -windowType utility -windowPosition "center" -title "Invalid Entry" -description "$invalidEntry" -alignDescription "Left" -icon "/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/ToolbarDeleteIcon.icns" -button1 "OK")
}

listEmpty(){
	listEmpty="No applications were found or all installed applications are required on your computer." 
	buttonClicked=$("$jamfHelper" -windowType utility -windowPosition "center" -title "No Applications Found" -description "$listEmpty" -alignDescription "Left" -icon "/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/ToolbarInfo.icns" -button1 "OK")
}

initializeUninstaller(){
    # Force Quit the app
    pgrep $1 | xargs kill -15
    
    # Remove the App
    /bin/rm -Rf "/Applications/$1.*"
    
    # Force Quit the app again (for redundancy)
    pgrep $1 | xargs kill -15
    
    # Update JAMF Inventory
    sudo jamf recon
}

########End of Functions###########

#######Begin Main Routine##########

# If list is emtpy, prompt user and exit
if [ -z "${appList}" ]; then
    
   echo "No apps available for removal"
   listEmpty
   echo "App list returned as empty. Exiting..."
   exit 0

# If list is not empty, show list for user selection.
else
	echo "Apps are available for removal. Prompting user with app list..."
    uninstallApp="choose from list every paragraph of \"$appList\" with title \"Application Remover\" with prompt \"Select which application you'd like to uninstall: 
    
Please note: Applications that are required to be on your computer will not be listed. \" multiple selections allowed false empty selection allowed false"

chosenApp=$( /usr/bin/osascript -e "$uninstallApp" )

    # If selected app exists, uninstall, prompt user and exit.
    if [[ -d "/Applications/$chosenApp.*" ]]; then

        echo "User selected $chosenApp"
        echo "Initializing Software Uninstaller..."
        initializeUninstaller "$chosenApp" # pass the app name to the function
        uninstallSuccessful
        echo "$chosenApp uninstalled"
        exit 0
	
    # If user cancelled or selection was invalid, prompt user and exit.
    else

       echo "Invalid Entry"
       invalidEntry
       echo "User cancelled or made an invalid selection"
       exit 0

    fi

fi

 

 

MALmen
New Contributor III

Thanks, I will try it out! :) 😃

MALmen
New Contributor III

The problem was the Zoom app was called zoom.us.app and it did not show up :( I tried the new script but it throws an error lite this. Any ideas? :)

 

Script result: /Library/Application Support/JAMF/tmp/RV Universal uninstaller: line 87: unexpected EOF while looking for matching `"'
/Library/Application Support/JAMF/tmp/RV Universal uninstaller: line 93: syntax error: unexpected end of file

MALmen
New Contributor III

Did it work for you? I get an error with the new script :S

Sorry for the late response. You might have figured it out already, but I left out a quotation that was producing a syntax error and yes, "zoom.us.app" was messing it up as it contains two dots. It should now extract everything before the last dot. Give it a try. 

 

#!/bin/bash

# List of apps to exclude from being able to uninstall
excludeAppList=".Trash
Google Chrome.app
Citrix Workspace.app
OneDrive.app
Self Service.app
Jamf*
Microsoft*"

# Build App list
appList=$(mdfind -onlyin /Applications "kMDItemCFBundleIdentifier != com.apple.*" | grep -v "$excludeAppList" | awk -F'/' '{print $NF}' | rev | cut -d '.' -f 2- | rev | sort -f)

# Jamf helper
jamfHelper="/Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper"

######## Functions ###########
uninstallSuccessful() {
    description1="The $chosenApp application has been successfully uninstalled."
    buttonClicked=$("$jamfHelper" -windowType utility -windowPosition "center" -title "Application Uninstalled" -description "${description1}" -alignDescription "Left" -icon "/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/ErasingIcon.icns" -button1 "OK")
}

invalidEntry() {
    invalidEntry="You either cancelled or the selection you made was invalid. 

If the application you'd like to remove is not listed, please reach out to your IT Support Team for further assistance."
    buttonClicked=$("$jamfHelper" -windowType utility -windowPosition "center" -title "Invalid Entry" -description "$invalidEntry" -alignDescription "Left" -icon "/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/ToolbarDeleteIcon.icns" -button1 "OK")
}

listEmpty() {
    listEmpty="No applications were found or all installed applications are required on your computer." 
    buttonClicked=$("$jamfHelper" -windowType utility -windowPosition "center" -title "No Applications Found" -description "$listEmpty" -alignDescription "Left" -icon "/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/ToolbarInfo.icns" -button1 "OK")
}

initializeUninstaller() {
    # Force Quit the app
    pgrep "$1" | xargs kill -15
    
    # Remove the App
    /bin/rm -Rf "/Applications/$1.app"
    
    # Force Quit the app again (for redundancy)
    pgrep "$1" | xargs kill -15
    
    # Update JAMF Inventory
    sudo jamf recon
}

######## End of Functions ###########

####### Begin Main Routine ##########

# If list is empty, prompt user and exit
if [ -z "${appList}" ]; then
    echo "No apps available for removal"
    listEmpty
    echo "App list returned as empty. Exiting..."
    exit 0
else
    echo "Apps are available for removal. Prompting user with app list..."
    uninstallApp="choose from list every paragraph of \"$appList\" with title \"Application Remover\" with prompt \"Select which application you'd like to uninstall: 
    
Please note: Applications that are required to be on your computer will not be listed. \" multiple selections allowed false empty selection allowed false"

    chosenApp=$( /usr/bin/osascript -e "$uninstallApp" )

    # If selected app exists, uninstall, prompt user and exit.
    if [[ -d "/Applications/$chosenApp.app" ]]; then
        echo "User selected $chosenApp"
        echo "Initializing Software Uninstaller..."
        initializeUninstaller "$chosenApp" # pass the app name to the function
        uninstallSuccessful
        echo "$chosenApp uninstalled"
        exit 0
    else
        echo "Invalid Entry"
        invalidEntry
        echo "User cancelled or made an invalid selection"
        exit 0
    fi
fi

 

Matexusa
New Contributor II

Hello Jamf Community!

Please I need a little more assistance on this as I'm very new to Jamf. I had used this approach by @stevewood  that worked perfectly but I realized that I still have a left-over app and folder that I would like to remove when I run the Jamf policy.

Avast has an Uninstaller app called "Avast One Uninstaller" or "Avast Uninstaller" for some of our old machines in --> \Applications\Avast

There is also an Avast folder that I would like to remove in --> \Library\Application Support\Avast

Please any help is appreciated!

Here is the script -- the two "rm -R" are where I'm having some issues :(

#!/bin/bash

appToUninstall="$4"

########Functions###########
initializeUninstaller(){
    # Force Quit the app
    pgrep $1 | xargs kill -15
    
    # Remove the App
    /bin/rm -Rf "/Applications/$1.app"
rm -R /Applications/*Avast*
rm -R /Library/Application\ Support/Avast

}

if [[ -d "/Applications/$appToUninstall.app" ]]; then
    
    initializeUninstaller "$appToUninstall" # pass the app name to the function
    exit 0
    
else
    
    echo "Application is not installed on system."
    exit 1
    
fi