mirror of
https://github.com/MLBZ521/MacAdmin.git
synced 2026-02-03 05:53:26 +00:00
1195 lines
49 KiB
Bash
1195 lines
49 KiB
Bash
#!/bin/sh
|
|
#set -x
|
|
|
|
###################################################################################################
|
|
# Script Name: uninstall_Office2011.sh
|
|
# By: Zack Thompson / Created: 2/12/2018
|
|
# Version: 1.0 / Updated: 2/12/2018 / By: ZT
|
|
#
|
|
# Description: This script combines the Remove2011 script by @pbowden (of Microsoft) and the dockutil utility by Kyle Crawford.
|
|
# This is done so I don't have to package this and have it provided by a distribution point. It'll run straight from the JSS.
|
|
#
|
|
# All credit to the authors:
|
|
# - https://github.com/pbowden-msft/Remove2011
|
|
###################################################################################################
|
|
|
|
TOOL_NAME="Microsoft Office 2011 for Mac Removal Tool"
|
|
TOOL_VERSION="1.5"
|
|
|
|
## Copyright (c) 2017 Microsoft Corp. All rights reserved.
|
|
## Scripts are not supported under any Microsoft standard support program or service. The scripts are provided AS IS without warranty of any kind.
|
|
## Microsoft disclaims all implied warranties including, without limitation, any implied warranties of merchantability or of fitness for a
|
|
## particular purpose. The entire risk arising out of the use or performance of the scripts and documentation remains with you. In no event shall
|
|
## Microsoft, its authors, or anyone else involved in the creation, production, or delivery of the scripts be liable for any damages whatsoever
|
|
## (including, without limitation, damages for loss of business profits, business interruption, loss of business information, or other pecuniary
|
|
## loss) arising out of the use of or inability to use the sample scripts or documentation, even if Microsoft has been advised of the possibility
|
|
## of such damages.
|
|
|
|
## Set up logging
|
|
# All stdout and sterr will go to the log file. Console alone can be accessed through >&3. For console and log use | tee /dev/fd/3
|
|
SCRIPT_NAME=$(basename "$0")
|
|
WORKING_FOLDER=$(dirname "$0")
|
|
LOG_FILE="$TMPDIR""$SCRIPT_NAME.log"
|
|
touch "$LOG_FILE"
|
|
exec 3>&1 1>>${LOG_FILE} 2>&1
|
|
|
|
## Formatting support
|
|
TEXT_RED='\033[0;31m'
|
|
TEXT_YELLOW='\033[0;33m'
|
|
TEXT_GREEN='\033[0;32m'
|
|
TEXT_BLUE='\033[0;34m'
|
|
TEXT_NORMAL='\033[0m'
|
|
|
|
## Initialize global variables
|
|
FORCE_PERM=false
|
|
PRESERVE_DATA=true
|
|
APP_RUNNING=false
|
|
KEEP_LYNC=false
|
|
SAVE_LICENSE=false
|
|
|
|
## Path constants
|
|
PATH_OFFICE2011="/Applications/Microsoft Office 2011"
|
|
PATH_WORD2011="/Applications/Microsoft Office 2011/Microsoft Word.app"
|
|
PATH_EXCEL2011="/Applications/Microsoft Office 2011/Microsoft Excel.app"
|
|
PATH_PPT2011="/Applications/Microsoft Office 2011/Microsoft PowerPoint.app"
|
|
PATH_OUTLOOK2011="/Applications/Microsoft Office 2011/Microsoft Outlook.app"
|
|
PATH_LYNC2011="/Applications/Microsoft Lync.app"
|
|
PATH_MAU="/Library/Application Support/Microsoft/MAU2.0/Microsoft AutoUpdate.app"
|
|
|
|
|
|
##### Creating the dockutil script from this script (so I don't have to package this process) #####
|
|
/bin/cat > "${WORKING_FOLDER}/dockutil" <<createdockutil
|
|
#!/usr/bin/python
|
|
|
|
##### This file was created by the MS Remove2011 script #####
|
|
|
|
# This file is based on or incorporates material from the projects listed below (Third Party IP). The original copyright notice and the license under
|
|
# which Microsoft received such Third Party IP, are set forth below. Such licenses and notices are provided for informational purposes only. Microsoft
|
|
# licenses the Third Party IP to you under the licensing terms for the Microsoft product. Microsoft reserves all other rights not expressly granted
|
|
# under this agreement, whether by implication, estoppel or otherwise.
|
|
|
|
# DOCKUTIL
|
|
# Copyright 2008 Kyle Crawford
|
|
|
|
# Provided for Informational Purposes Only
|
|
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
# THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY
|
|
# IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT.
|
|
|
|
# See the Apache Version 2.0 License for specific language governing permissions and limitations under the License.
|
|
|
|
# Send bug reports and comments to kcrwfrd at gmail
|
|
|
|
# Possible future enhancements
|
|
# tie in with application identifier codes for locating apps and replacing them in the dock with newer versions?
|
|
|
|
import sys, plistlib, subprocess, os, getopt, re, pipes, tempfile, pwd
|
|
import platform
|
|
|
|
|
|
# default verbose printing to off
|
|
verbose = False
|
|
version = '2.0.2'
|
|
|
|
def usage(e=None):
|
|
"""Displays usage information and error if one occurred"""
|
|
|
|
print """usage: %(progname)s -h
|
|
usage: %(progname)s --add <path to item> | <url> [--label <label>] [ folder_options ] [ position_options ] [ plist_location_specification ] [--no-restart]
|
|
usage: %(progname)s --remove <dock item label> | all [ plist_location_specification ] [--no-restart]
|
|
usage: %(progname)s --move <dock item label> position_options [ plist_location_specification ]
|
|
usage: %(progname)s --find <dock item label> [ plist_location_specification ]
|
|
usage: %(progname)s --list [ plist_location_specification ]
|
|
usage: %(progname)s --version
|
|
|
|
position_options:
|
|
--replacing <dock item label name> replaces the item with the given dock label or adds the item to the end if item to replace is not found
|
|
--position [ index_number | beginning | end | middle ] inserts the item at a fixed position: can be an position by index number or keyword
|
|
--after <dock item label name> inserts the item immediately after the given dock label or at the end if the item is not found
|
|
--before <dock item label name> inserts the item immediately before the given dock label or at the end if the item is not found
|
|
--section [ apps | others ] specifies whether the item should be added to the apps or others section
|
|
|
|
plist_location_specifications:
|
|
<path to a specific plist> default is the dock plist for current user
|
|
<path to a home directory>
|
|
--allhomes attempts to locate all home directories and perform the operation on each of them
|
|
--homeloc overrides the default /Users location for home directories
|
|
|
|
folder_options:
|
|
--view [grid|fan|list|automatic] stack view option
|
|
--display [folder|stack] how to display a folder's icon
|
|
--sort [name|dateadded|datemodified|datecreated|kind] sets sorting option for a folder view
|
|
|
|
Examples:
|
|
The following adds TextEdit.app to the end of the current user's dock:
|
|
%(progname)s --add /Applications/TextEdit.app
|
|
|
|
The following replaces Time Machine with TextEdit.app in the current user's dock:
|
|
%(progname)s --add /Applications/TextEdit.app --replacing 'Time Machine'
|
|
|
|
The following adds TextEdit.app after the item Time Machine in every user's dock on that machine:
|
|
%(progname)s --add /Applications/TextEdit.app --after 'Time Machine' --allhomes
|
|
|
|
The following adds ~/Downloads as a grid stack displayed as a folder for every user's dock on that machine:
|
|
%(progname)s --add '~/Downloads' --view grid --display folder --allhomes
|
|
|
|
The following adds a url dock item after the Downloads dock item for every user's dock on that machine:
|
|
%(progname)s --add vnc://miniserver.local --label 'Mini VNC' --after Downloads --allhomes
|
|
|
|
The following removes System Preferences from every user's dock on that machine:
|
|
%(progname)s --remove 'System Preferences' --allhomes
|
|
|
|
The following moves System Preferences to the second slot on every user's dock on that machine:
|
|
%(progname)s --move 'System Preferences' --position 2 --allhomes
|
|
|
|
The following finds any instance of iTunes in the specified home directory's dock:
|
|
%(progname)s --find iTunes /Users/jsmith
|
|
|
|
The following lists all dock items for all home directories at homeloc in the form: item<tab>path<tab><section>tab<plist>
|
|
%(progname)s --list --homeloc /Volumes/RAID/Homes --allhomes
|
|
|
|
The following adds Firefox after Safari in the Default User Template without restarting the Dock
|
|
%(progname)s --add /Applications/Firefox.app --after Safari --no-restart '/System/Library/User Template/English.lproj'
|
|
|
|
|
|
Notes:
|
|
When specifying a relative path like ~/Documents with the --allhomes option, ~/Documents must be quoted like '~/Documents' to get the item relative to each home
|
|
|
|
Bugs:
|
|
Names containing special characters like accent marks will fail
|
|
|
|
|
|
Contact:
|
|
Send bug reports and comments to kcrwfrd at gmail.
|
|
""" % dict(progname = os.path.basename(sys.argv[0]))
|
|
if e:
|
|
print ""
|
|
print 'Error processing options:', e
|
|
sys.exit(1)
|
|
sys.exit(0)
|
|
|
|
def verboseOutput(*args):
|
|
"""Used by verbose option (-v) to send more output to stdout"""
|
|
if verbose:
|
|
try:
|
|
print "verbose:", args
|
|
except:
|
|
pass
|
|
|
|
def main():
|
|
"""Parses options and arguments and performs fuctions"""
|
|
# setup our getoput opts and args
|
|
try:
|
|
(optargs, args) = getopt.getopt(sys.argv[1:], 'hv', ["help", "version",
|
|
"section=", "list", "find=", "add=", "move=", "replacing=",
|
|
"remove=", "after=", "before=", "position=", "display=", "view=",
|
|
"sort=", "label=", "type=", "allhomes", "homeloc=", "no-restart", "hupdock="])
|
|
except getopt.GetoptError, e: # if parsing of options fails, display usage and parse error
|
|
usage(e)
|
|
|
|
# setup default values
|
|
global verbose
|
|
add_path = None
|
|
remove_labels = []
|
|
find_label = None
|
|
move_label = None
|
|
after_item = None
|
|
before_item = None
|
|
position = None
|
|
add_path = None
|
|
plist_path = None
|
|
list = False
|
|
all_homes = False
|
|
replace_label = None
|
|
section = None
|
|
displayas = None
|
|
showas = None
|
|
arrangement = None
|
|
tile_type = None
|
|
label_name = None
|
|
home_directories_loc = '/Users'
|
|
restart_dock = True
|
|
|
|
for opt, arg in optargs:
|
|
if opt in ("-h", "--help"):
|
|
usage()
|
|
elif opt == "-v":
|
|
verbose = True
|
|
elif opt == "--version":
|
|
print version
|
|
sys.exit(0)
|
|
elif opt == "--add":
|
|
add_path = arg
|
|
elif opt == "--replacing":
|
|
replace_label = arg
|
|
elif opt == "--move":
|
|
move_label = arg
|
|
elif opt == "--find":
|
|
find_label = arg
|
|
elif opt == "--remove":
|
|
remove_labels.append(arg)
|
|
elif opt == "--after":
|
|
after_item = arg
|
|
elif opt == "--before":
|
|
before_item = arg
|
|
elif opt == "--position":
|
|
position = arg
|
|
elif opt == "--label":
|
|
label_name = arg
|
|
elif opt == '--sort':
|
|
if arg == 'name':
|
|
arrangement = 1
|
|
elif arg == 'dateadded':
|
|
arrangement = 2
|
|
elif arg == 'datemodified':
|
|
arrangement = 3
|
|
elif arg == 'datecreated':
|
|
arrangement = 4
|
|
elif arg == 'kind':
|
|
arrangement = 5
|
|
else:
|
|
usage('unsupported --sort argument')
|
|
elif opt == '--view':
|
|
if arg == 'fan':
|
|
showas = 1
|
|
elif arg == 'grid':
|
|
showas = 2
|
|
elif arg == 'list':
|
|
showas = 3
|
|
elif arg == 'auto':
|
|
showas = 0
|
|
else:
|
|
usage('unsupported --view argument')
|
|
elif opt == '--display':
|
|
if arg == 'stack':
|
|
displayas = 0
|
|
elif arg == 'folder':
|
|
displayas = 1
|
|
else:
|
|
usage('unsupported --display argument')
|
|
elif opt == '--type':
|
|
tile_type = arg+'-tile'
|
|
elif opt == '--section':
|
|
section = 'persistent-'+arg
|
|
elif opt == '--list':
|
|
list = True
|
|
elif opt == '--allhomes':
|
|
all_homes = True
|
|
elif opt == '--homeloc':
|
|
home_directories_loc = arg
|
|
elif opt == '--no-restart':
|
|
restart_dock = False
|
|
|
|
# for legacy compatibility only
|
|
elif opt == '--hupdock':
|
|
if arg.lower() in ("false", "no", "off", "0"):
|
|
restart_dock = False
|
|
|
|
# check for an action
|
|
if add_path == None and not remove_labels and move_label == None and find_label == None and list == False:
|
|
usage('no action was specified')
|
|
|
|
|
|
# get the list of plists to process
|
|
# if allhomes option was set, get a list of home directories in the homedirectory location
|
|
if all_homes:
|
|
possible_homes = os.listdir(home_directories_loc)
|
|
plist_paths = [ home_directories_loc+'/'+home+'/Library/Preferences/com.apple.dock.plist' for home in possible_homes if os.path.exists(home_directories_loc+'/'+home+'/Library/Preferences/com.apple.dock.plist') and os.path.exists(home_directories_loc+'/'+home+'/Desktop')]
|
|
else: # allhomes was not specified
|
|
# if no plist argument, then use the user's home directory dock plist, otherwise use the arguments provided
|
|
if args == []:
|
|
plist_paths = [ os.path.expanduser('~/Library/Preferences/com.apple.dock.plist') ]
|
|
else:
|
|
plist_paths = args
|
|
# exit if we couldn't find any plists to process
|
|
if len(plist_paths) < 1:
|
|
print 'no dock plists were found'
|
|
sys.exit(1)
|
|
|
|
# loop over plist paths
|
|
for plist_path in plist_paths:
|
|
|
|
verboseOutput('processing', plist_path)
|
|
# a home directory is allowed as an argument, so if the plist_path is a
|
|
# directory, we append the relative path to the plist
|
|
if os.path.isdir(plist_path):
|
|
plist_path = os.path.join(plist_path,'Library/Preferences/com.apple.dock.plist')
|
|
|
|
# verify that the plist exists at the given path
|
|
# and expand and quote it for use when shelling out
|
|
if os.path.exists(os.path.expanduser(plist_path)):
|
|
plist_path = os.path.expanduser(plist_path)
|
|
plist_path = os.path.abspath(plist_path)
|
|
plist_path = pipes.quote(plist_path)
|
|
else:
|
|
print plist_path, 'does not seem to be a home directory or a dock plist'
|
|
sys.exit(1)
|
|
|
|
|
|
# check for each action and process accordingly
|
|
if remove_labels: # --remove action(s)
|
|
pl = readPlist(plist_path)
|
|
changed = False
|
|
for remove_label in remove_labels:
|
|
if removeItem(pl, remove_label):
|
|
changed = True
|
|
else:
|
|
print 'item', remove_label, 'was not found in', plist_path
|
|
if changed:
|
|
commitPlist(pl, plist_path, restart_dock)
|
|
elif list: # --list action
|
|
pl = readPlist(plist_path)
|
|
# print a tab separated line for each item in the plist
|
|
# for each section
|
|
for section in ['persistent-apps', 'persistent-others']:
|
|
# for item in section
|
|
for item in pl[section]:
|
|
try:
|
|
# join and print relevant data into a string separated by tabs
|
|
print '\t'.join((item['tile-data']['file-label'], item['tile-data']['file-data']['_CFURLString'], section, plist_path))
|
|
except:
|
|
pass
|
|
|
|
elif find_label != None: # --find action
|
|
# since we are only reading the plist, make a copy before converting it to be read
|
|
pl = readPlist(plist_path)
|
|
# set found state
|
|
item_found = False
|
|
# loop through dock items looking for a match with provided find_label
|
|
for section in ['persistent-apps', 'persistent-others']:
|
|
for item_offset in range(len(pl[section])):
|
|
try:
|
|
if pl[section][item_offset]['tile-data']['file-label'] == find_label:
|
|
item_found = True
|
|
print find_label, "was found in", section, "at slot", item_offset+1, "in", plist_path
|
|
except:
|
|
pass
|
|
if not item_found:
|
|
print find_label, "was not found in", plist_path
|
|
if not all_homes: # only exit non-zero if we aren't processing all homes, because for allhomes, exit status for find would be irrelevant
|
|
sys.exit(1)
|
|
|
|
elif move_label != None: # --move action
|
|
pl = readPlist(plist_path)
|
|
# check for a position option before processing
|
|
if position is None and before_item is None and after_item is None:
|
|
usage('move action requires a position destination')
|
|
# perform the move and save the plist if it was successful
|
|
if moveItem(pl, move_label, position, before_item, after_item):
|
|
commitPlist(pl, plist_path, restart_dock)
|
|
else:
|
|
print 'move failed for', move_label, 'in', plist_path
|
|
|
|
elif add_path != None: # --add action
|
|
if add_path.startswith('~'): # we've got a relative path and relative paths need to be processed by using a path relative to this home directory
|
|
real_add_path = re.sub('^~', plist_path.replace('/Library/Preferences/com.apple.dock.plist',''), add_path) # swap out the full home path for the ~
|
|
else:
|
|
real_add_path = add_path
|
|
# determine smart default values where possible
|
|
if section == None:
|
|
if real_add_path.endswith('.app') or real_add_path.endswith('.app/'): # we've got an application
|
|
section = 'persistent-apps'
|
|
elif displayas != None or showas != None or arrangement != None: # we've got a folder
|
|
section = 'persistent-others'
|
|
|
|
if tile_type is None: # if type was not specified, we try to figure that out using the filesystem
|
|
if os.path.isdir(real_add_path) and section != 'persistent-apps': # app bundles are directories too
|
|
tile_type = 'directory-tile'
|
|
elif re.match('\w*://', real_add_path): # regex to determine a url in the form xyz://abcdef.adsf.com/adsf
|
|
tile_type = 'url-tile'
|
|
section = 'persistent-others'
|
|
else:
|
|
tile_type = 'file-tile'
|
|
|
|
if section == None:
|
|
section = 'persistent-others'
|
|
|
|
|
|
if tile_type != 'url-tile': # paths can't be relative in dock items
|
|
real_add_path = os.path.realpath(real_add_path)
|
|
|
|
|
|
pl = readPlist(plist_path)
|
|
verboseOutput('adding', real_add_path)
|
|
# perform the add save the plist if it was successful
|
|
if addItem(pl, real_add_path, replace_label, position, before_item, after_item, section, displayas, showas, arrangement, tile_type, label_name):
|
|
commitPlist(pl, plist_path, restart_dock)
|
|
else:
|
|
print 'item', add_path, 'was not added to Dock'
|
|
if not all_homes: # only exit non-zero if we aren't processing all homes, because for allhomes, exit status for add would be irrelevant
|
|
sys.exit(1)
|
|
|
|
# NOTE on use of defaults
|
|
# We use defaults because it knows how to handle cfpreferences caching even when given a path rather than a domain
|
|
# This allows us to keep using path-based plist specifications rather than domains
|
|
# Preserving path based plists are important for people needing to run this on a non boot volume
|
|
# However if Apple stops using plists or moves the plist path, all of this will break
|
|
# So at that point we will have to change the API so users pass in a defaults domain or user rather than a plist path
|
|
def writePlist(pl, plist_path):
|
|
"""writes a plist object down to a file"""
|
|
# get the unescaped path
|
|
plist_path = path_as_string(plist_path)
|
|
# get a tempfile path for writing our plist
|
|
plist_import_path = tempfile.mktemp()
|
|
# Write the plist to our temporary plist for importing because defaults can't import from a pipe (yet)
|
|
plistlib.writePlist(pl, plist_import_path)
|
|
# get original permissions
|
|
plist_stat = os.stat(plist_path)
|
|
# If we are running as root, ensure we run as the correct user to update cfprefsd
|
|
if os.geteuid() == 0:
|
|
# Running defaults as the user only works if the user exists
|
|
if valid_uid(plist_stat.st_uid):
|
|
subprocess.Popen(['sudo', '-u', '#%d' % plist_stat.st_uid, '-g', '#%d' % plist_stat.st_gid, 'defaults', 'import', plist_path, plist_import_path])
|
|
else:
|
|
subprocess.Popen(['defaults', 'import', plist_path, plist_import_path])
|
|
os.chown(plist_path, plist_stat.st_uid, plist_stat.st_gid)
|
|
os.chmod(plist_path, plist_stat.st_mode)
|
|
else:
|
|
subprocess.Popen(['defaults', 'import', plist_path, plist_import_path])
|
|
|
|
|
|
def valid_uid(uid):
|
|
"""returns bool of whether uid can be resolved to a user"""
|
|
try:
|
|
pwd.getpwuid(uid)
|
|
return True
|
|
except:
|
|
return False
|
|
|
|
def getOsxVersion():
|
|
"""returns a tuple with the (major,minor,revision) numbers"""
|
|
# OS X Yosemite return 10.10, so we will be happy with len(...) == 2, then add 0 for last number
|
|
try:
|
|
mac_ver = tuple(int(n) for n in platform.mac_ver()[0].split('.'))
|
|
assert 2 <= len(mac_ver) <= 3
|
|
except Exception as e:
|
|
raise e
|
|
if len(mac_ver) == 2:
|
|
mac_ver = mac_ver + (0, )
|
|
return mac_ver
|
|
|
|
def readPlist(plist_path):
|
|
"""returns a plist object read from a file path"""
|
|
# get the unescaped path
|
|
plist_path = path_as_string(plist_path)
|
|
# get a tempfile path for exporting our defaults data
|
|
export_fifo = tempfile.mktemp()
|
|
# make a fifo for defaults export in a temp file
|
|
os.mkfifo(export_fifo)
|
|
# export to the fifo
|
|
osx_version = getOsxVersion()
|
|
if osx_version[1] >= 9:
|
|
subprocess.Popen(['defaults', 'export', plist_path, export_fifo]).communicate()
|
|
# convert the export to xml
|
|
plist_string = subprocess.Popen(['plutil', '-convert', 'xml1', export_fifo, '-o', '-'], stdout=subprocess.PIPE).stdout.read()
|
|
else:
|
|
try:
|
|
cmd = ['/usr/libexec/PlistBuddy','-x','-c', 'print',plist_path]
|
|
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
(plist_string,err) = proc.communicate()
|
|
except Exception as e:
|
|
raise e
|
|
# parse the xml into a dictionary
|
|
pl = plistlib.readPlistFromString(plist_string)
|
|
return pl
|
|
|
|
def path_as_string(path):
|
|
"""returns an unescaped string of the path"""
|
|
return subprocess.Popen('ls -d '+path, shell=True, stdout=subprocess.PIPE).stdout.read().rstrip('\n')
|
|
|
|
def moveItem(pl, move_label=None, position=None, before_item=None, after_item=None):
|
|
"""locates an existing dock item and moves it to a new position"""
|
|
for section in ['persistent-apps', 'persistent-others']:
|
|
item_to_move = None
|
|
# loop over the items looking for the item label
|
|
for item_offset in range(len(pl[section])):
|
|
if pl[section][item_offset]['tile-data']['file-label'] == move_label:
|
|
item_found = True
|
|
verboseOutput('found', move_label)
|
|
# make a copy of the found dock entry
|
|
item_to_move = pl[section][item_offset]
|
|
found_offset = item_offset
|
|
break
|
|
else:
|
|
verboseOutput('no match for', pl[section][item_offset]['tile-data']['file-label'])
|
|
# if the item wasn't found, continue to next section loop iteration
|
|
if item_to_move == None:
|
|
continue
|
|
# we are still inside the section for loop
|
|
# remove the found item
|
|
pl[section].remove(pl[section][item_offset])
|
|
|
|
# figure out where to re-insert the original dock item back into the plist
|
|
if position != None:
|
|
if position in [ 'beginning', 'begin', 'first' ]:
|
|
pl[section].insert(0, item_to_move)
|
|
return True
|
|
elif position in [ 'end', 'last' ]:
|
|
pl[section].append(item_to_move)
|
|
return True
|
|
elif position in [ 'middle', 'center' ]:
|
|
midpoint = int(len(pl[section])/2)
|
|
pl[section].insert(midpoint, item_to_move)
|
|
return True
|
|
else:
|
|
# if the position integer starts with a + or - , then add or subtract from its current position respectively
|
|
if position.startswith('-') or position.startswith('+'):
|
|
new_position = int(position) + found_offset
|
|
if new_position > len(pl[section]):
|
|
pl[section].append(item_to_move)
|
|
elif new_position < 0:
|
|
pl[section].insert(0, item_to_move)
|
|
else:
|
|
pl[section].insert(int(position) + found_offset, item_to_move)
|
|
return True
|
|
|
|
try:
|
|
int(position)
|
|
except:
|
|
print 'Invalid position', position
|
|
return False
|
|
pl[section].insert(int(position)-1, item_to_move)
|
|
return True
|
|
elif after_item != None or before_item != None:
|
|
# if after or before is set, find the offset of that item and do the insert relative to that offset
|
|
for item_offset in range(len(pl[section])):
|
|
try:
|
|
if after_item != None:
|
|
if pl[section][item_offset]['tile-data']['file-label'] == after_item:
|
|
pl[section].insert(item_offset+1, item_to_move)
|
|
return True
|
|
if before_item != None:
|
|
if pl[section][item_offset]['tile-data']['file-label'] == before_item:
|
|
pl[section].insert(item_offset, item_to_move)
|
|
return True
|
|
except KeyError:
|
|
pass
|
|
|
|
return False
|
|
|
|
def generate_guid():
|
|
"""returns guid string"""
|
|
return subprocess.Popen(['/usr/bin/uuidgen'],stdout=subprocess.PIPE).communicate()[0].rstrip()
|
|
|
|
def addItem(pl, add_path, replace_label=None, position=None, before_item=None, after_item=None, section='persistent-apps', displayas=1, showas=1, arrangement=2, tile_type='file-tile',label_name=None):
|
|
"""adds an item to an existing dock plist object"""
|
|
if displayas == None: displayas = 1
|
|
if showas == None: showas = 0
|
|
if arrangement == None: arrangement = 2
|
|
|
|
#fix problems with unicode file names
|
|
enc = (sys.stdin.encoding if sys.stdin.encoding else 'UTF-8')
|
|
add_path = unicode(add_path, enc)
|
|
|
|
# set a dock label if one isn't provided
|
|
if label_name == None:
|
|
if tile_type == 'url-tile':
|
|
label_name = add_path
|
|
section = 'persistent-others'
|
|
else:
|
|
base_name = re.sub('/$', '', add_path).split('/')[-1]
|
|
label_name = re.sub('.app$', '', base_name)
|
|
|
|
|
|
# only add if item label isn't already there
|
|
|
|
if replace_label != label_name:
|
|
for existing_dock_item in (pl[section]):
|
|
for label_key in ['file-label','label']:
|
|
if existing_dock_item['tile-data'].has_key(label_key):
|
|
if existing_dock_item['tile-data'][label_key] == label_name:
|
|
print "%s already exists in dock. Use --replacing '%s' to update an existing item" % (label_name, label_name)
|
|
return False
|
|
|
|
|
|
|
|
if replace_label != None:
|
|
for item_offset in range(len(pl[section])):
|
|
tile_replace_candidate = pl[section][item_offset]['tile-data']
|
|
if tile_replace_candidate[label_key_for_tile(tile_replace_candidate)] == replace_label:
|
|
verboseOutput('found', replace_label)
|
|
del pl[section][item_offset]
|
|
position = item_offset + 1
|
|
break
|
|
|
|
new_guid = generate_guid()
|
|
if tile_type == 'file-tile':
|
|
new_item = {'GUID': new_guid, 'tile-data': {'file-data': {'_CFURLString': add_path, '_CFURLStringType': 0},'file-label': label_name, 'file-type': 32}, 'tile-type': tile_type}
|
|
elif tile_type == 'directory-tile':
|
|
if subprocess.Popen(['/usr/bin/sw_vers', '-productVersion'],
|
|
stdout=subprocess.PIPE).stdout.read().rstrip().split('.')[1] == '4': # gets the decimal after 10 in sw_vers; 10.4 does not use 10.5 options for stacks
|
|
new_item = {'GUID': new_guid, 'tile-data': {'directory': 1, 'file-data': {'_CFURLString': add_path, '_CFURLStringType': 0}, 'file-label': label_name, 'file-type': 2 }, 'tile-type': tile_type}
|
|
else:
|
|
new_item = {'GUID': new_guid, 'tile-data': {'arrangement': arrangement, 'directory': 1, 'displayas': displayas, 'file-data': {'_CFURLString': add_path, '_CFURLStringType': 0}, 'file-label': label_name, 'file-type': 2, 'showas': showas}, 'tile-type': tile_type}
|
|
|
|
elif tile_type == 'url-tile':
|
|
new_item = {'GUID': new_guid, 'tile-data': {'label': label_name, 'url': {'_CFURLString': add_path, '_CFURLStringType': 15}}, 'tile-type': tile_type}
|
|
else:
|
|
print 'unknown type:', tile_type
|
|
sys.exit(1)
|
|
|
|
verboseOutput('adding', new_item)
|
|
|
|
if position != None:
|
|
if position in [ 'beginning', 'begin', 'first' ]:
|
|
pl[section].insert(0, new_item)
|
|
return True
|
|
elif position in [ 'end', 'last' ]:
|
|
pl[section].append(new_item)
|
|
return True
|
|
elif position in [ 'middle', 'center' ]:
|
|
midpoint = int(len(pl[section])/2)
|
|
pl[section].insert(midpoint, new_item)
|
|
return True
|
|
else:
|
|
try:
|
|
int(position)
|
|
except:
|
|
print 'Invalid position', position
|
|
return False
|
|
if int(position) == 0:
|
|
pl[section].insert(int(position), new_item)
|
|
elif int(position) > 0:
|
|
pl[section].insert(int(position)-1, new_item)
|
|
else:
|
|
pl[section].insert(int(position)+len(pl[section])+1, new_item)
|
|
return True
|
|
elif after_item != None or before_item !=None:
|
|
for item_offset in range(len(pl[section])):
|
|
try:
|
|
if after_item != None:
|
|
if pl[section][item_offset]['tile-data']['file-label'] == after_item:
|
|
pl[section].insert(item_offset+1, new_item)
|
|
return True
|
|
if before_item != None:
|
|
if pl[section][item_offset]['tile-data']['file-label'] == before_item:
|
|
pl[section].insert(item_offset, new_item)
|
|
return True
|
|
except KeyError:
|
|
pass
|
|
pl[section].append(new_item)
|
|
verboseOutput('item added at end')
|
|
return True
|
|
|
|
def removeItem(pl, item_name):
|
|
removal_succeeded = False
|
|
if item_name == "all":
|
|
verboseOutput('Removing all items')
|
|
pl['persistent-apps'] = []
|
|
pl['persistent-others'] = []
|
|
return True
|
|
for dock_item in pl['persistent-apps']:
|
|
if dock_item['tile-data'].get('file-data').get('_CFURLString') == item_name:
|
|
verboseOutput('found', item_name)
|
|
pl['persistent-apps'].remove(dock_item)
|
|
removal_succeeded = True
|
|
for dock_item in pl['persistent-others']:
|
|
if dock_item['tile-type'] == "url-tile":
|
|
if dock_item['tile-data'].get('label') == item_name:
|
|
verboseOutput('found', item_name)
|
|
pl['persistent-others'].remove(dock_item)
|
|
removal_succeeded = True
|
|
else:
|
|
if dock_item['tile-data'].get('file-label') == item_name:
|
|
verboseOutput('found', item_name)
|
|
pl['persistent-others'].remove(dock_item)
|
|
removal_succeeded = True
|
|
return removal_succeeded
|
|
|
|
def commitPlist(pl, plist_path, restart_dock):
|
|
writePlist(pl, plist_path)
|
|
if restart_dock:
|
|
os.system('/usr/bin/killall -HUP Dock >/dev/null 2>&1')
|
|
|
|
#def commitPlistLegacy(pl, plist_path, restart_dock):
|
|
# plist_string_path = path_as_string(plist_path)
|
|
# pl = removeLongs(pl)
|
|
# plist_stat = os.stat(plist_string_path)
|
|
# writePlist(pl, plist_path)
|
|
# convertPlist(plist_path, 'binary1')
|
|
# os.chown(plist_string_path, plist_stat.st_uid, plist_stat.st_gid)
|
|
# os.chmod(plist_string_path, plist_stat.st_mode)
|
|
# if restart_dock:
|
|
# os.system('/usr/bin/killall -HUP cfprefsd >/dev/null 2>&1')
|
|
# os.system('/usr/bin/killall -HUP Dock >/dev/null 2>&1')
|
|
#
|
|
|
|
def label_key_for_tile(item):
|
|
for label_key in ['file-label','label']:
|
|
if item.has_key(label_key):
|
|
return label_key
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|
|
createdockutil
|
|
##### End of creating dockutil by this script #####
|
|
|
|
# Set the permissions
|
|
/bin/chmod 700 "${WORKING_FOLDER}/dockutil"
|
|
|
|
## Functions
|
|
function LogMessage {
|
|
echo $(date) "$*"
|
|
}
|
|
|
|
function ConsoleMessage {
|
|
echo "$*" >&3
|
|
}
|
|
|
|
function FormattedConsoleMessage {
|
|
FUNCDENT="$1"
|
|
FUNCTEXT="$2"
|
|
printf "$FUNCDENT" "$FUNCTEXT" >&3
|
|
}
|
|
|
|
function AllMessage {
|
|
echo $(date) "$*"
|
|
echo "$*" >&3
|
|
}
|
|
|
|
function LogDevice {
|
|
LogMessage "In function 'LogDevice'"
|
|
system_profiler SPSoftwareDataType -detailLevel mini
|
|
system_profiler SPHardwareDataType -detailLevel mini
|
|
}
|
|
|
|
function ShowUsage {
|
|
LogMessage "In function 'ShowUsage'"
|
|
ConsoleMessage "Usage: $SCRIPT_NAME [--Force] [--Help] [--KeepLync] [--SaveLicense]"
|
|
ConsoleMessage "Use --Force to bypass warnings and forcibly remove Office 2011 applications and data"
|
|
ConsoleMessage ""
|
|
}
|
|
|
|
function GetDestructivePerm {
|
|
LogMessage "In function 'GetDestructivePerm'"
|
|
if [ $FORCE_PERM = false ]; then
|
|
LogMessage "Script is not running with force - asking user for permission to continue"
|
|
ConsoleMessage "${TEXT_RED}WARNING: This procedure will remove application and data files.${TEXT_NORMAL}"
|
|
ConsoleMessage "${TEXT_RED}Be sure to have a backup before continuing.${TEXT_NORMAL}"
|
|
ConsoleMessage "Do you wish to continue? (y/n)"
|
|
read -p "" "GOAHEAD"
|
|
if [ "$GOAHEAD" == "y" ] || [ "$GOAHEAD" == "Y" ]; then
|
|
LogMessage "Destructive permissions granted by user"
|
|
return
|
|
else
|
|
LogMessage "Destructive permissions DENIED by user"
|
|
ConsoleMessage ""
|
|
exit 0
|
|
fi
|
|
fi
|
|
}
|
|
|
|
function GetDestructiveDataPerm {
|
|
LogMessage "In function 'GetDestructiveDataPerm'"
|
|
if [ $FORCE_PERM = false ]; then
|
|
LogMessage "Script is not running with force - asking user for permission to remove data files"
|
|
ConsoleMessage "${TEXT_RED}This tool can either preserve or remove Outlook data files.${TEXT_NORMAL}"
|
|
ConsoleMessage "Do you wish to preserve Outlook data? (y/n)"
|
|
read -p "" "GOAHEAD"
|
|
if [ "$GOAHEAD" == "y" ] || [ "$GOAHEAD" == "Y" ]; then
|
|
LogMessage "User chose to preserve Outlook data"
|
|
PRESERVE_DATA=true
|
|
else
|
|
LogMessage "User chose to remove Outlook data"
|
|
PRESERVE_DATA=false
|
|
fi
|
|
fi
|
|
}
|
|
|
|
function GetDestructiveLicensePerm {
|
|
LogMessage "In function 'GetDestructiveLicensePerm'"
|
|
if [ $FORCE_PERM = false ]; then
|
|
LogMessage "Script is not running with force - asking user for permission to remove license file"
|
|
if [ $SAVE_LICENSE = false ]; then
|
|
LogMessage "SAVE_LICENSE is false - asking user if they want to remove it"
|
|
ConsoleMessage "${TEXT_RED}This tool can either preserve or remove your product activation license.${TEXT_NORMAL}"
|
|
ConsoleMessage "Do you wish to preserve the license? (y/n)"
|
|
read -p "" "GOAHEAD"
|
|
if [ "$GOAHEAD" == "y" ] || [ "$GOAHEAD" == "Y" ]; then
|
|
LogMessage "User chose to preserve the license"
|
|
SAVE_LICENSE=true
|
|
else
|
|
LogMessage "User chose to remove the license"
|
|
SAVE_LICENSE=false
|
|
fi
|
|
fi
|
|
fi
|
|
}
|
|
function GetSudo {
|
|
LogMessage "In function 'GetSudo'"
|
|
if [ "$EUID" != "0" ]; then
|
|
LogMessage "Script is not running as root - asking user for admin password"
|
|
sudo -p "Enter administrator password: " echo
|
|
if [ $? -eq 0 ] ; then
|
|
LogMessage "Admin password entered successfully"
|
|
ConsoleMessage ""
|
|
return
|
|
else
|
|
LogMessage "Admin password is INCORRECT"
|
|
exit 1
|
|
fi
|
|
fi
|
|
}
|
|
|
|
function CheckRunning {
|
|
FUNCPROC="$1"
|
|
LogMessage "In function 'CheckRunning' with argument $FUNCPROC"
|
|
local RUNNING_RESULT=$(ps ax | grep -v grep | grep "$FUNCPROC")
|
|
if [ "${#RUNNING_RESULT}" -gt 0 ]; then
|
|
LogMessage "$FUNCPROC is currently running"
|
|
APP_RUNNING=true
|
|
fi
|
|
}
|
|
|
|
function CheckRunning2011 {
|
|
LogMessage "In function 'CheckRunning2011'"
|
|
CheckRunning "$PATH_WORD2011" "Word 2011"
|
|
CheckRunning "$PATH_EXCEL2011" "Excel 2011"
|
|
CheckRunning "$PATH_PPT2011" "PowerPoint 2011"
|
|
CheckRunning "$PATH_OUTLOOK2011" "Outlook 2011"
|
|
if [ $KEEP_LYNC = false ]; then
|
|
CheckRunning "$PATH_LYNC2011" "Lync 2011"
|
|
fi
|
|
}
|
|
|
|
function Close2011 {
|
|
LogMessage "In function 'Close2011'"
|
|
if [ $FORCE_PERM = false ]; then
|
|
LogMessage "Script is not running with force - asking user for permission to continue"
|
|
GetForcePerms
|
|
fi
|
|
ForceQuit2011
|
|
}
|
|
|
|
function GetForcePerms {
|
|
LogMessage "In function 'GetForcePerms'"
|
|
ConsoleMessage "${TEXT_YELLOW}WARNING: Office applications are currently open and need to be closed.${TEXT_NORMAL}"
|
|
ConsoleMessage "Do you want this program to forcibly close open applications? (y/n)"
|
|
read -p "" "GOAHEAD"
|
|
if [ "$GOAHEAD" == "y" ] || [ "$GOAHEAD" == "Y" ]; then
|
|
LogMessage "User gave permission for the script to close running apps"
|
|
FORCE_PERM=true
|
|
ConsoleMessage ""
|
|
else
|
|
LogMessage "User DENIED permissions for the script to close running apps"
|
|
ConsoleMessage ""
|
|
exit 0
|
|
fi
|
|
}
|
|
|
|
function ForceTerminate {
|
|
FUNCPROC="$1"
|
|
LogMessage "In function 'ForceTerminate' with argument $FUNCPROC"
|
|
$(ps ax | grep -v grep | grep "$FUNCPROC" | cut -d' ' -f1 | xargs kill -9 2> /dev/null)
|
|
}
|
|
|
|
function ForceQuit2011 {
|
|
LogMessage "In function 'ForceQuit2011'"
|
|
FormattedConsoleMessage "%-55s" "Shutting down all Office 2011 applications"
|
|
ForceTerminate "$PATH_WORD2011" "Word 2011"
|
|
ForceTerminate "$PATH_EXCEL2011" "Excel 2011"
|
|
ForceTerminate "$PATH_PPT2011" "PowerPoint 2011"
|
|
ForceTerminate "$PATH_OUTLOOK2011" "Outlook 2011"
|
|
if [ $KEEP_LYNC = false ]; then
|
|
ForceTerminate "$PATH_LYNC2011" "Lync 2011"
|
|
fi
|
|
ConsoleMessage "${TEXT_GREEN}Success${TEXT_NORMAL}"
|
|
}
|
|
|
|
function RemoveComponent {
|
|
FUNCPATH="$1"
|
|
FUNCTEXT="$2"
|
|
LogMessage "In function 'RemoveComponent with arguments $FUNCPATH and $FUNCTEXT'"
|
|
FormattedConsoleMessage "%-55s" "Removing $FUNCTEXT"
|
|
if [ -d "$FUNCPATH" ] || [ -e "$FUNCPATH" ] ; then
|
|
LogMessage "Removing path $FUNCPATH"
|
|
$(sudo rm -r -f "$FUNCPATH")
|
|
else
|
|
LogMessage "$FUNCPATH was not detected"
|
|
ConsoleMessage "${TEXT_YELLOW}Not detected${TEXT_NORMAL}"
|
|
return
|
|
fi
|
|
if [ -d "$FUNCPATH" ] || [ -e "$FUNCPATH" ] ; then
|
|
LogMessage "Path $FUNCPATH still exists after deletion"
|
|
ConsoleMessage "${TEXT_RED}Failed${TEXT_NORMAL}"
|
|
else
|
|
LogMessage "Path $FUNCPATH was successfully removed"
|
|
ConsoleMessage "${TEXT_GREEN}Success${TEXT_NORMAL}"
|
|
fi
|
|
}
|
|
|
|
function RemoveUserComponent {
|
|
FUNCPATH="$1"
|
|
FUNCTEXT="$2"
|
|
LogMessage "In function 'RemoveUserComponent with arguments $FUNCPATH and $FUNCTEXT'"
|
|
for u in `ls /Users`; do
|
|
FULLPATH="/Users/$u/$FUNCPATH"
|
|
$(sudo rm -r -f $FULLPATH)
|
|
done
|
|
}
|
|
|
|
function PreserveUserComponent {
|
|
FUNCPATH="$1"
|
|
FUNCTEXT="$2"
|
|
LogMessage "In function 'remove_PreserveComponent with arguments $FUNCPATH and $FUNCTEXT'"
|
|
FormattedConsoleMessage "%-55s" "Preserving $FUNCTEXT"
|
|
for u in `ls /Users`; do
|
|
FULLPATH="/Users/$u/$FUNCPATH"
|
|
if [ -d "$FULLPATH" ] || [ -e "$FULLPATH" ] ; then
|
|
LogMessage "Renaming path $FULLPATH"
|
|
$(sudo mv -fv "$FULLPATH" "$FULLPATH-Preserved")
|
|
fi
|
|
done
|
|
ConsoleMessage "${TEXT_GREEN}Success${TEXT_NORMAL}"
|
|
}
|
|
|
|
function Remove2011Receipts {
|
|
LogMessage "In function 'Remove2011Receipts'"
|
|
FormattedConsoleMessage "%-55s" "Removing Package Receipts"
|
|
RECEIPTCOUNT=0
|
|
RemoveReceipt "com.microsoft.office.all.*"
|
|
RemoveReceipt "com.microsoft.office.en.*"
|
|
RemoveReceipt "com.microsoft.merp.*"
|
|
RemoveReceipt "com.microsoft.mau.*"
|
|
if (( $RECEIPTCOUNT > 0 )) ; then
|
|
ConsoleMessage "${TEXT_GREEN}Success${TEXT_NORMAL}"
|
|
else
|
|
ConsoleMessage "${TEXT_YELLOW}Not detected${TEXT_NORMAL}"
|
|
fi
|
|
}
|
|
|
|
function RemoveReceipt {
|
|
FUNCPATH="$1"
|
|
LogMessage "In function 'RemoveReceipt' with argument $FUNCPATH"
|
|
PKGARRAY=($(pkgutil --pkgs=$FUNCPATH))
|
|
for p in "${PKGARRAY[@]}"
|
|
do
|
|
LogMessage "Forgetting package $p"
|
|
sudo pkgutil --forget $p
|
|
if [ $? -eq 0 ] ; then
|
|
((RECEIPTCOUNT++))
|
|
fi
|
|
done
|
|
}
|
|
|
|
function Remove2011Preferences {
|
|
LogMessage "In function 'Remove2011Preferences'"
|
|
FormattedConsoleMessage "%-55s" "Removing Preferences"
|
|
PREFCOUNT=0
|
|
RemovePref "/Library/Preferences/com.microsoft.Word.plist"
|
|
RemovePref "/Library/Preferences/com.microsoft.Excel.plist"
|
|
RemovePref "/Library/Preferences/com.microsoft.Powerpoint.plist"
|
|
RemovePref "/Library/Preferences/com.microsoft.Outlook.plist"
|
|
RemovePref "/Library/Preferences/com.microsoft.outlook.databasedaemon.plist"
|
|
RemovePref "/Library/Preferences/com.microsoft.DocumentConnection.plist"
|
|
RemovePref "/Library/Preferences/com.microsoft.office.setupassistant.plist"
|
|
RemoveUserPref "Library/Preferences/com.microsoft.Word.plist"
|
|
RemoveUserPref "Library/Preferences/com.microsoft.Excel.plist"
|
|
RemoveUserPref "Library/Preferences/com.microsoft.Powerpoint.plist"
|
|
if [ $KEEP_LYNC = false ]; then
|
|
RemoveUserPref "Library/Preferences/com.microsoft.Lync.plist"
|
|
fi
|
|
RemoveUserPref "Library/Preferences/com.microsoft.Outlook.plist"
|
|
RemoveUserPref "Library/Preferences/com.microsoft.outlook.databasedaemon.plist"
|
|
RemoveUserPref "Library/Preferences/com.microsoft.outlook.office_reminders.plist"
|
|
RemoveUserPref "Library/Preferences/com.microsoft.DocumentConnection.plist"
|
|
RemoveUserPref "Library/Preferences/com.microsoft.office.setupassistant.plist"
|
|
RemoveUserPref "Library/Preferences/com.microsoft.office.plist"
|
|
RemoveUserPref "Library/Preferences/com.microsoft.error_reporting.plist"
|
|
RemoveUserPref "Library/Preferences/ByHost/com.microsoft.Word.*.plist"
|
|
RemoveUserPref "Library/Preferences/ByHost/com.microsoft.Excel.*.plist"
|
|
RemoveUserPref "Library/Preferences/ByHost/com.microsoft.Powerpoint.*.plist"
|
|
RemoveUserPref "Library/Preferences/ByHost/com.microsoft.Outlook.*.plist"
|
|
RemoveUserPref "Library/Preferences/ByHost/com.microsoft.outlook.databasedaemon.*.plist"
|
|
RemoveUserPref "Library/Preferences/ByHost/com.microsoft.DocumentConnection.*.plist"
|
|
RemoveUserPref "Library/Preferences/ByHost/com.microsoft.office.setupassistant.*.plist"
|
|
RemoveUserPref "Library/Preferences/ByHost/com.microsoft.registrationDB.*.plist"
|
|
RemoveUserPref "Library/Preferences/ByHost/com.microsoft.e0Q*.*.plist"
|
|
RemoveUserPref "Library/Preferences/ByHost/com.microsoft.Office365.*.plist"
|
|
if [ $KEEP_LYNC = false ]; then
|
|
RemoveUserPref "Library/Preferences/ByHost/MicrosoftLyncRegistrationDB.*.plist"
|
|
fi
|
|
if (( $PREFCOUNT > 0 )); then
|
|
ConsoleMessage "${TEXT_GREEN}Success${TEXT_NORMAL}"
|
|
else
|
|
ConsoleMessage "${TEXT_YELLOW}Not detected${TEXT_NORMAL}"
|
|
fi
|
|
}
|
|
|
|
function RemovePref {
|
|
FUNCPATH="$1"
|
|
LogMessage "In function 'RemovePref' with argument $FUNCPATH"
|
|
ls $FUNCPATH
|
|
if [ $? -eq 0 ] ; then
|
|
LogMessage "Found preference $FUNCPATH"
|
|
$(sudo rm -f $FUNCPATH)
|
|
if [ $? -eq 0 ] ; then
|
|
LogMessage "Preference $FUNCPATH removed"
|
|
((PREFCOUNT++))
|
|
else
|
|
LogMessage "Preference $FUNCPATH could NOT be removed"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
function RemoveUserPref {
|
|
FUNCPATH="$1"
|
|
LogMessage "In function 'RemoveUserPref' with argument $FUNCPATH"
|
|
for u in `ls /Users`; do
|
|
FULLPATH="/Users/$u/$FUNCPATH"
|
|
$(sudo rm -f $FULLPATH)
|
|
((PREFCOUNT++))
|
|
done
|
|
}
|
|
|
|
function CleanDock {
|
|
LogMessage "In function 'CleanDock'"
|
|
FormattedConsoleMessage "%-55s" "Cleaning icons in dock"
|
|
if [ -e "$WORKING_FOLDER/dockutil" ]; then
|
|
LogMessage "Found DockUtil tool"
|
|
sudo "$WORKING_FOLDER"/dockutil --remove "file:///Applications/Microsoft%20Office%202011/Microsoft%20Document%20Connection.app/" --no-restart
|
|
sudo "$WORKING_FOLDER"/dockutil --remove "file:///Applications/Microsoft%20Office%202011/Microsoft%20Word.app/" --no-restart
|
|
sudo "$WORKING_FOLDER"/dockutil --remove "file:///Applications/Microsoft%20Office%202011/Microsoft%20Excel.app/" --no-restart
|
|
sudo "$WORKING_FOLDER"/dockutil --remove "file:///Applications/Microsoft%20Office%202011/Microsoft%20PowerPoint.app/" --no-restart
|
|
if [ $KEEP_LYNC = false ]; then
|
|
sudo "$WORKING_FOLDER"/dockutil --remove "file:///Applications/Microsoft%20Office%202011/Microsoft%20Lync.app/" --no-restart
|
|
fi
|
|
sudo "$WORKING_FOLDER"/dockutil --remove "file:///Applications/Microsoft%20Office%202011/Microsoft%20Outlook.app/"
|
|
LogMessage "Completed dock clean-up"
|
|
ConsoleMessage "${TEXT_GREEN}Success${TEXT_NORMAL}"
|
|
rm -f "${WORKING_FOLDER}/dockutil"
|
|
else
|
|
ConsoleMessage "${TEXT_YELLOW}Not detected${TEXT_NORMAL}"
|
|
fi
|
|
}
|
|
|
|
function RelaunchCFPrefs {
|
|
LogMessage "In function 'RelaunchCFPrefs'"
|
|
FormattedConsoleMessage "%-55s" "Restarting Preferences Daemon"
|
|
sudo ps ax | grep -v grep | grep "cfprefsd" | cut -d' ' -f1 | xargs sudo kill -9
|
|
if [ $? -eq 0 ] ; then
|
|
LogMessage "Successfully terminated all preferences daemons"
|
|
ConsoleMessage "${TEXT_GREEN}Success${TEXT_NORMAL}"
|
|
else
|
|
LogMessage "FAILED to terminate all preferences daemons"
|
|
ConsoleMessage "${TEXT_RED}Failed${TEXT_NORMAL}"
|
|
fi
|
|
}
|
|
|
|
function MainLoop {
|
|
LogMessage "In function 'MainLoop'"
|
|
# Show warning about destructive behavior of the script and ask for permission to continue
|
|
GetDestructivePerm
|
|
GetDestructiveDataPerm
|
|
GetDestructiveLicensePerm
|
|
# If appropriate, elevate permissions so the script can perform all actions
|
|
GetSudo
|
|
# Check to see if any of the 2011 apps are currently open
|
|
CheckRunning2011
|
|
if [ $APP_RUNNING = true ]; then
|
|
LogMessage "One of more 2011 apps are running"
|
|
Close2011
|
|
fi
|
|
# Remove Office 2011 apps
|
|
RemoveComponent "$PATH_OFFICE2011" "Office 2011 Applications"
|
|
if [ $KEEP_LYNC = false ]; then
|
|
RemoveComponent "$PATH_LYNC2011" "Lync"
|
|
fi
|
|
|
|
# Remove Office 2011 helpers
|
|
RemoveComponent "/Library/LaunchDaemons/com.microsoft.office.licensing.helper.plist" "Launch Daemon: Licensing Helper"
|
|
RemoveComponent "/Library/PrivilegedHelperTools/com.microsoft.office.licensing.helper" "Helper Tools: Licensing Helper"
|
|
# Remove Office 2011 fonts
|
|
RemoveComponent "/Library/Fonts/Microsoft" "Office Fonts"
|
|
# Remove Office 2011 license
|
|
if [ $SAVE_LICENSE = false ]; then
|
|
LogMessage "SAVE_LICENSE is false - removing license file"
|
|
RemoveComponent "/Library/Preferences/com.microsoft.office.licensing.plist" "Product License"
|
|
fi
|
|
# Remove Office 2011 application support
|
|
RemoveComponent "/Library/Application Support/Microsoft/MERP2.0" "Error Reporting"
|
|
RemoveUserComponent "Library/Application Support/Microsoft/Office" "Application Support"
|
|
# Remove Office 2011 caches
|
|
RemoveUserComponent "Library/Caches/com.microsoft.browserfont.cache" "Browser Font Cache"
|
|
RemoveUserComponent "Library/Caches/com.microsoft.office.setupassistant" "Setup Assistant Cache"
|
|
RemoveUserComponent "Library/Caches/Microsoft/Office" "Office Cache"
|
|
RemoveUserComponent "Library/Caches/Outlook" "Outlook Identity Cache"
|
|
RemoveUserComponent "Library/Caches/com.microsoft.Outlook" "Outlook Cache"
|
|
# Remove Office 2011 preferences
|
|
Remove2011Preferences
|
|
# Remove or rename Outlook 2011 identities and databases
|
|
if [ $PRESERVE_DATA = false ]; then
|
|
RemoveUserComponent "Documents/Microsoft User Data/Office 2011 Identities" "Outlook Identities and Databases"
|
|
RemoveUserComponent "Documents/Microsoft User Data/Saved Attachments" "Outlook Saved Attachments"
|
|
RemoveUserComponent "Documents/Microsoft User Data/Outlook Sound Sets" "Outlook Sound Sets"
|
|
else
|
|
PreserveUserComponent "Documents/Microsoft User Data/Office 2011 Identities" "Outlook Identities and Databases"
|
|
PreserveUserComponent "Documents/Microsoft User Data/Saved Attachments" "Outlook Saved Attachments"
|
|
PreserveUserComponent "Documents/Microsoft User Data/Outlook Sound Sets" "Outlook Sound Sets"
|
|
fi
|
|
# Remove Office 2011 package receipts
|
|
Remove2011Receipts
|
|
# Clean up icons on the dock
|
|
CleanDock
|
|
# Restart cfprefs
|
|
RelaunchCFPrefs
|
|
}
|
|
|
|
## Main
|
|
LogMessage "Starting $SCRIPT_NAME"
|
|
AllMessage "${TEXT_BLUE}=== $TOOL_NAME $TOOL_VERSION ===${TEXT_NORMAL}"
|
|
LogDevice
|
|
|
|
# Evaluate command-line arguments
|
|
if [[ $# = 0 ]]; then
|
|
LogMessage "No command-line arguments passed, going into interactive mode"
|
|
MainLoop
|
|
else
|
|
LogMessage "Command-line arguments passed, attempting to parse"
|
|
while [[ $# > 0 ]]
|
|
do
|
|
key="$1"
|
|
LogMessage "Argument: $key"
|
|
case "$key" in
|
|
--Help|-h|--help)
|
|
ShowUsage
|
|
exit 0
|
|
shift # past argument
|
|
;;
|
|
--Force|-f|--force)
|
|
LogMessage "Force mode set to TRUE"
|
|
FORCE_PERM=true
|
|
shift # past argument
|
|
;;
|
|
--KeepLync|-k|--keeplync)
|
|
LogMessage "Keep Lync set to TRUE"
|
|
KEEP_LYNC=true
|
|
shift # past argument
|
|
;;
|
|
--SaveLicense|-s|--savelicense)
|
|
LogMessage "SaveLicense set to TRUE"
|
|
SAVE_LICENSE=true
|
|
shift # past argument
|
|
;;
|
|
*)
|
|
ShowUsage
|
|
echo "Ignoring unrecognized argument: $key"
|
|
;;
|
|
esac
|
|
shift # past argument or value
|
|
done
|
|
MainLoop
|
|
fi
|
|
|
|
ConsoleMessage ""
|
|
ConsoleMessage "All events and errors were logged to $LOG_FILE"
|
|
ConsoleMessage ""
|
|
LogMessage "Exiting script"
|
|
exit 0 |