Salesforce – How to automatically clean up profiles and permission sets?

I recently had a problem – I needed to

  1. retrieve profiles and permission sets from Salesforce dev org
  2. clean them up to prepare for deployment

Although retrieving is easy, manual cleaning takes some time. Especially when you have to do the same from time to time.

This might happen if we have different API version between orgs, or a managed package installed in source org and not in destination org.

Why not automating this?

As I began to learn Python last year, I though I’ll use it to automate process of cleaning up.

I started with importing os and time libraries, tracking execution time and setting a variable responsible for making backup files (if needed):

import os
import time

start_time = time.time()
makeBackup = False

Then I defined listDir to get files from a given path

def listDir(path):
	files = []
	for dirname, dirnames, filenames in os.walk(path):        
		for filename in filenames:
			dir = os.path.join(dirname, filename)
	return files

After that I defined method to process files and remove lines with texts passed as “words” variable

def processFile(fileName, words):
	with open(fileName, "r") as f:
		items = f.readlines()
	if makeBackup:
		fileName = fileName + '-after'
	with open(fileName, "w") as f:
		index = len(items)-1
		while index > 1 :
			line = items[index].strip("\n")
			for wordLine in words:
				word = wordLine[0]
				removePrev = wordLine[1]
				removeNext = wordLine[2]
				if word in line:
					removingFrom = index - removePrev
					removingTo = index + removeNext + 1	
					del items[removingFrom:removingTo]
			index -= 1
		for item in items:

Having that, it all comes down to getting a list of profiles (double backslashes as I use Windows)

profileList = listDir("c:\\Data\\profiles\\")

and defining lines I wanted to remove

profileWordsToRemove = []
profileWordsToRemove.append(['<name>SendExternalEmailAvailable</name>', 2, 1])
profileWordsToRemove.append(['<name>CreateReductionOrder</name>', 2, 1])
profileWordsToRemove.append(['<recordType>Case.SampleRecordType1</recordType>', 2, 2])
profileWordsToRemove.append(['<field>Contact.SampleField__c</field>', 2, 2])
profileWordsToRemove.append(['<apexClass>SampleApexClass</apexClass>', 1, 2])
  • First param is text we want to remove
  • Second param defines how many lines we want to remove BEFORE the line with text
  • Third param to define number of lines to remove AFTER text is found


profileWordsToRemove.append(['SendExternalEmailAvailable', 2, 1])

will remove those 4 lines:



profileWordsToRemove.append(['Contact.SampleField__c', 2, 2])

will remove those 5


Execute it all

At the end, it all comes down to a previously defined processFile method

for fileName in profileList:
	processFile(fileName, profileWordsToRemove)

The same happens for permission sets:

permSetList = listDir('c:\\Data\\permissionsets\\')
permSetWordsToRemove = []
permSetWordsToRemove.append(['<field>Account.CustomTextField__c</field>', 2, 2])
permSetWordsToRemove.append(['<field>Lead.CustomField__1c</field>', 2, 2])
for fileName in permSetList:
	processFile(fileName, permSetWordsToRemove)

At the very end, I just print execution time

print('--- %s seconds ---' % (round(time.time() - start_time, 2)))

To be fair – this script may not be perfectly optimized, as I’m very much a beginner in Python, but execution time for processing 45 files is about 5-10 seconds (depending on number of lines to process). It’s still fast comparing to manual removal.

You can download full code from

Leave a Reply

Your email address will not be published. Required fields are marked *