Skip to content

Instantly share code, notes, and snippets.

@Leask
Created September 5, 2016 08:27
Show Gist options
  • Save Leask/36ba4c97f8fa35fa2a17a71a3e114929 to your computer and use it in GitHub Desktop.
Save Leask/36ba4c97f8fa35fa2a17a71a3e114929 to your computer and use it in GitHub Desktop.
Find and remove existing installations of Parallels Access
#!/usr/bin/env bash
#
# Find and remove existing installations of Parallels Access
export PATH=/bin:/sbin:/usr/bin:/usr/sbin
RootCheck () {
if [ $(id -u) != "0" ]
then
sudo -p "This script requires administrative privileges. Please enter your password: " "$0" "$@"
exit $?
fi
}
function GetUsers() {
for usr in `ls -1 /Users/ | grep -ivw Shared | grep -ve '^\\.'`; do
[ -d "/Users/$usr" ] || continue
id "$usr" >/dev/null 2>&1 || continue
echo "$usr"
done
}
RemoveFile() {
local filename="${1}"
if [ -e "${filename}" ]; then
echo " - Removing ${filename}"
rm -rf "${filename}"
fi
}
RemoveStatFiles() {
for stat_file in /private/var/db/Parallels/Stats/Parallels\ Access*
do
RemoveFile "${stat_file}"
done
}
RunCommandForEachUser() {
local command="$@"
local parent_proc='/System/Library/CoreServices/loginwindow.app/Contents/MacOS/loginwindow'
ps -Awww -opid,user,command | \
awk "{if (\$3==\"${parent_proc}\") system(\"launchctl bsexec \"\$1\" sudo -u \"\$2\" ${command}\")}"
}
UnloadKernelExtension () {
local BundlePath="${1}"
local KextBundlePath="${BundlePath}/Contents/Library/Extensions/10.6"
local KextMod="$KextBundlePath/${2}"
local KextModName=`basename "${KextMod}"`
if [ -d "${BundlePath}" ]; then
kext_id=`defaults read "${KextMod}/Contents/Info.plist" CFBundleIdentifier 2>/dev/null`
else
kext_id=`defaults read "${KextBundlePath}/${KextModName}/Contents/Info.plist" CFBundleIdentifier 2>/dev/null`
fi
if [ "${kext_id}" == "" ]; then
return
fi
echo " - Unloading kernel extension: ${KextModName}"
res=1
COUNTER=3
while [ $COUNTER -gt 1 ]; do
# Return immediately if extension unloaded
kextstat | grep -qs "${kext_id}"
if [ $? -ne 0 ]; then
res=0
break
fi
# Else retry
kextunload "${KextMod}"
let COUNTER-=1
done
test $res -eq 0 || echo "Failed to unload kernel extension ${KextModName}"
}
UninstallLaunchdItem() {
local launchd_id="${1}"
local launchd_type="${2}"
case "${launchd_type}" in
agent) local launchd_path="/Library/LaunchAgents/${launchd_id}.plist"
;;
daemon) local launchd_path="/Library/LaunchDaemons/${launchd_id}.plist"
;;
*) return
;;
esac
if [ ! -e "${launchd_path}" ]; then
return
fi
echo " - Uninstalling Launchd item: $launchd_id"
case "${launchd_type}" in
agent) RunCommandForEachUser \
launchctl unload -S Aqua "${launchd_path}"
;;
daemon) launchctl stop "${launchd_id}"
launchctl unload -wF "${launchd_path}"
;;
*) return
;;
esac
rm -f "${launchd_path}"
}
UninstallInputMethod() {
local PrlImBundle="${1}"
local PrlIm="${PrlImBundle}/Contents/MacOS/ParallelsIM"
if [ ! -e "${PrlImBundle}" ]; then
return
fi
echo " - Uninstalling Input Method: ${PrlImBundle}"
"${PrlIm}" --disable
"${PrlIm}" --terminate
rm -rf "${PrlImBundle}"
}
TerminateRunningWizards () {
local pid_file
local pid_files=`find /var/run/parallels -name '*deskctl_wizard*.pid'`
# find out prl_deskctl_wizard PID from .pid file(s) and terminate them
for pid_file in ${pid_files}; do
echo " - Terminating ${pid_file}"
kill -TERM `cat ${pid_file}`
done
sleep 0.5
pid_files=`find /var/run/parallels -name '*deskctl_wizard*.pid'`
# find out prl_descktl_wizard processes which were not terminated and kill them
for pid_file in ${pid_files}; do
echo " - Failed to terminate ${pid_file}; forcing"
kill -KILL `cat ${pid_file}`
rm -f ${pid_file}
done
}
TerminateRunningWizardsUsingKill() {
local WizardName="${1}"
ps -Awwwc -opid,command | \
awk "{if (\$2 ~ /${WizardName}/) system(\"echo ' - Unloading Desktop Control Wizard:' ${WizardName} && kill -9 \"\$1\"\")}"
}
UninstallMainBundle() {
local BundlePath="${1}"
if [ ! -e "${BundlePath}" ]; then
return
fi
echo " - Uninstalling App bundle: ${BundlePath}"
rm -rf "${BundlePath}"
}
UninstallDispatcherConfigFiles() {
local XmlConfigName="${1}"
local PlistConfigName="${2}"
local XmlConfigBase="/Library/Preferences/Parallels"
local PlistConfigBase="/var/root/Library/Preferences/"
local XmlConfigPath="${XmlConfigBase}/${XmlConfigName}"
local PlistConfigPath="${PlistConfigBase}/${PlistConfigName}"
if [ ! -f "${XmlConfigPath}" -a ! -f "${PlistConfigPath}" -a ! -f "${PlistConfigPath}.lockfile" ]; then
return
fi
echo " - Uninstalling Dispatcher config files"
rm -f "${XmlConfigPath}"
rm -f "${PlistConfigPath}"
rm -f "${PlistConfigPath}.lockfile"
if [ -z "`find ${XmlConfigBase} -type f`" ]; then
rm -r "${XmlConfigBase}"
fi
}
RootCheck
echo "Purging Parallels Access"
UnloadKernelExtension "/Applications/Parallels Access.app" "prl_virtual_sound.kext"
UninstallLaunchdItem "com.parallels.mobile.kextloader.launchdaemon" daemon
UninstallLaunchdItem "com.parallels.mobile.dispatcher.launchdaemon" daemon
UninstallLaunchdItem "com.parallels.mobile.prl_deskctl_agent.launchagent" agent
UninstallLaunchdItem "com.parallels.mobile.startgui.launchagent" agent
UninstallLaunchdItem "com.parallels.mobile.agent.launchagent" agent
UninstallLaunchdItem "com.parallels.mobile.startgui.launchdaemon" agent
UninstallInputMethod "/Library/Input Methods/ParallelsIM.app"
TerminateRunningWizards
TerminateRunningWizardsUsingKill "prl_deskctl_wizard"
TerminateRunningWizardsUsingKill "prl_deskctl_agent"
TerminateRunningWizardsUsingKill "prl_pm_service"
UninstallDispatcherConfigFiles "dispatcher.pmobile.xml" "com.parallels.mobile.plist"
UninstallMainBundle "/Applications/Parallels Access.app"
UninstallMainBundle "/Applications/Parallels Mobile.app"
UninstallMainBundle "/Applications/Parallels Personal Cloud.app"
for user in $(GetUsers):
do
RemoveFile "/Users/$user/Library/Preferences/com.parallels.Parallels Access.plist"
RemoveFile "/Users/$user/Library/Preferences/com.parallels.Parallels Access.plist.sdb"
done
RemoveFile "/Library/Preferences/com.parallels.Parallels Access.plist.sdb"
RemoveFile "/Library/Preferences/Parallels/vmdirectorylist.pmobile.xml"
RemoveFile "/private/etc/com.parallels.mobile.prl_deskctl_agent.launchd"
RemoveStatFiles
echo "Done. Your system is pristine."
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment