I recently had a problem – I needed to
- retrieve profiles and permission sets from Salesforce dev org
- 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) files.append(dir) files.sort() 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 removePrev = wordLine removeNext = wordLine if word in line: removingFrom = index - removePrev removingTo = index + removeNext + 1 del items[removingFrom:removingTo] index -= 1 for item in items: f.write(item)
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:
<userPermissions> <enabled>true</enabled> <name>SendExternalEmailAvailable</name> </userPermissions>
profileWordsToRemove.append(['Contact.SampleField__c', 2, 2])
will remove those 5
<fieldPermissions> <editable>true</editable> <field>Contact.SampleField__c</field> <readable>true</readable> </fieldPermissions>
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 https://github.com/gskaruz/profile-permission-set-cleaner