Editing Salesforce permission set licenses with VSCode
19 Aug 2022
Carl Bussema wrote of Salesforce permission sets:
“Some permissions need to be in permission sets with a specific license, which is an obnoxiously hidden requirement that you won’t figure out until you need to add a permission, go ‘WHERE THE ** IS THIS?’, and then discover it needs a license. And you can’t change the license on an existing permission set. (XML hacking is the best bet here.)”
If you’re a frustrated admin, you might be wondering: what’s XML hacking?
Let’s try using a Windows computer, VSCode, the SFDX command-line tool, and the CumulusCI command-line tool to XML-hack an existing permission set and edit its license!
Install and run VSCode
I won’t walk all the way through it again: you can download the VSCode installer file from Microsoft and double-click it to run it. They make it very easy.
Install SFDX
Open up a Terminal panel in VSCode or open up the Command Prompt program in Windows (you hit the start menu icon in the lower left, start typing “cmd
,” and press Enter).
Check whether you have SFDX
At the command-prompt (it’s the name of a directory on your hard drive followed by a greater-than sign, like “C:\example>
“), execute the following command by typing it and pressing Enter:
sfdx --version
If you’ve never installed the SFDX command-line tool, you’ll see the computer’s command line interface reply:
'sfdx' is not recognized as an internal or external command, operable program or batch file.
That said, if you have installed it and just forgot you’d installed it, you’ll see something more like this, showing what version-number of the SFDX command-line tool you’re on and what version of the Node.js command-line tool SFDX’s installer put onto your computer when you installed SFDX:
sfdx-cli/1.2.3 win32-x64 node-v1.2.3
You should get the same result when you run this command (note the missing “dx” at the end of the first word):
sf --version
You can skip forward to “Install CCI” if you’ve already installed the SFDX command-line tool.
Install SFDX if not
Salesforce has really improved the process of installing the SFDX CLI since I first wrote about it in April 2019. (I should go back and edit that article.)
Nowadays, just download the SFDX CLI installer file from Salesforce and double-click it to run it. They make it pretty easy too, with one caveat:
So, no matter what Windows user you’re logged into your computer as, the SFDX CLI installer wants you to type in a Windows administrative user’s username and password after you double-click the .exe
file.
If you see that and “cleverly” think…
“Aha! Well, then, I, who am currently logged into Windows as a non-administrative Windows user (which I should be, for security), shall right-click the
.exe
file and click ‘Run as administrator’ and then type my Windows administrative username and password, and I’ll bet everything will work really nicely. That’s how Windows.exe
file installers that want me to type in an administrative username & password usually work really nicely.”
…then think again.
The installer has a bug in it where when the .exe
file is run under “Run as administrator” settings, instead of adding “C:\Program Files\sfdx\bin
” into the system-wide Windows environment variable called PATH
, it adds it into the user-specific Windows environment variable called PATH
… of the administrative user you just escalated your system to.
So if you tried to be “clever” when running the .exe
, then as a follow-up, you’ll have to fix PATH
yourself:
- click the Windows Start icon
- start typing “system env”
- click “Edit the system environment variables”
- type in a Windows administrative username & password again
- click the “Environment Variables” button in the lower-right corner of the System Properties popup
- double-click the variable named
Path
in the upper half of the Environment Variables popup - double-click the line reading “
C:\Program Files\sfdx\bin
” in the Edit environment variable popup - copy it to your clipboard
- click somewhere else
- single-click the line that says “
C:\Program Files\sfdx\bin
” - click the “Delete” button once
- double-click the variable named
Path
in the lower half of the Environment Variables popup - click the New button
- paste “
C:\Program Files\sfdx\bin
” off your clipboard - click OK 3 times to exit all 3 popups
On the other hand, if you just double-clicked the .exe
installer, I suspect everything should work right. That said, you might not be able to get anything out of sfdx --version
when logged into the computer as a different Windows user if you do it that way, without some clever PATH
manipulation as seen above.
You might have to close VSCode or the Windows Command Prompt and open it again before sfdx --version
works. If VSCode still doesn’t work but the Windows Command Prompt does, try rebooting your computer to give VSCode a kick in the pants.
Log SFDX into a Developer Hub Org
From a PowerShell session that’s in any old unrelated-to-Salesforce folder on my computer, I did sfdx auth:list
and saw that I haven’t logged into anything with the SFDX CLI yet. Of course not, I just installed it! So I ran this (substituting for my-clever-alias
and the instanceurl
appropriately):
sfdx force:auth:web:login --setalias my-clever-alias --instanceurl https://customdomain.my.salesforce.com/
And got this:
Successfully authorized [email protected] with org ID 00D123456789876543
Windows PowerShell
Copyright (C) Microsoft Corporation. All rights reserved.
Try the new cross-platform PowerShell https://aka.ms/pscore6
PS C:\example> sfdx retrieve metadata --metadata PermissionSet:Permission_Set_Name_Oops_Wrong_Org
» Warning: retrieve is not a sfdx command.
Did you mean force? [y/n]: n
PS C:\example> sf --version
@salesforce/cli/1.39.0 win32-x64 node-v16.16.0
PS C:\example> sf retrieve metadata --metadata PermissionSet:Permission_Set_Name_Oops_Wrong_Org
You acknowledge and agree that the CLI tool may collect usage information, user environment, and crash reports for the purposes of providing services or functions that are relevant to use of the CLI tool and product improvements.
RequiresProjectError: This command is required to run from within a Salesforce project directory.
Code: RequiresProjectError
Warning: This command is currently in beta. Any aspect of this command can change without advanced notice. Don't use beta commands in your scripts.
Error (1): No default environment found. Use -o or --target-org to specify an environment.
=== authenticated orgs
ALIAS USERNAME ORG ID INSTANCE URL AUTH METHOD
───────────────────────────────── ───────────────────────────── ────────────────── ──────────────────────────────────────────────────────────── ───────────
my-clever-alias [email protected] 00D123456789876543 https://customdomain.my.salesforce.com web
Copied-pasted in a C:\example\sfdx-project.json
from another project.
PS C:\example> sf retrieve metadata --metadata PermissionSet:Permission_Set_Name_Oops_Wrong_Org --target-org my-clever-alias
Warning: This command is currently in beta. Any aspect of this command can change without advanced notice. Don't use beta commands in your scripts.
Error (1): The path "force-app", specified in sfdx-project.json, does not exist. Be sure this directory is included in your project root.
Preparing retrieve request... done
PS C:\example> mkdir force-app
Directory: C:\example\noway
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 8/19/2022 2:53 PM force-app
PS C:\example> sf retrieve metadata --metadata PermissionSet:Permission_Set_Name_Oops_Wrong_Org --target-org my-clever-alias
Warning: This command is currently in beta. Any aspect of this command can change without advanced notice. Don't use beta commands in your scripts.
Preparing retrieve request... Succeeded
PS C:\example> sf retrieve metadata --metadata PermissionSet:Permission_Set_Without_A_License --target-org my-clever-alias
Warning: This command is currently in beta. Any aspect of this command can change without advanced notice. Don't use beta commands in your scripts.
Preparing retrieve request... Succeeded
Retrieved Source
========================================================================================================================================
| State Name Type Path
| ─────── ───────────────────────── ───────────── ──────────────────────────────────────────────────────────────────────────────────────
| Created Permission_Set_Without_A_License PermissionSet force-app\main\default\permissionsets\Permission_Set_Without_A_License.permissionset-meta.xml
PS C:\example> sf retrieve metadata --metadata PermissionSet:SalesUserPsl --target-org my-clever-alias
Warning: This command is currently in beta. Any aspect of this command can change without advanced notice. Don't use beta commands in your scripts.
Preparing retrieve request... Succeeded
PS C:\example> sf retrieve metadata --metadata PermissionSet:Permission_Set_With_Licensing --target-org my-clever-alias
Warning: This command is currently in beta. Any aspect of this command can change without advanced notice. Don't use beta commands in your scripts.
Preparing retrieve request... Succeeded
Retrieved Source
============================================================================================================================
| State Name Type Path
| ─────── ─────────────────── ───────────── ────────────────────────────────────────────────────────────────────────────────
| Created Permission_Set_With_Licensing PermissionSet force-app\main\default\permissionsets\Permission_Set_With_Licensing.permissionset-meta.xml
<?xml version="1.0" encoding="UTF-8"?>
<PermissionSet xmlns="http://soap.sforce.com/2006/04/metadata">
...
<license>LicenseDetailsHere</license>
...
</PermissionSet>
I mean, I was avoiding CCI for years, but then I found it had what I needed for little surgery things when SFDX didn’t provide a user experience I liked, but as far as I can tell, XML-hacking a single permission set is down to this now with SFDX alone:
- Install SFDX on your computer and make sure it works,
sfdx --version
andsf --version
- Create blank folder
C:\example
and open a command-line prompt using your favorite command-line tool so that you’re in the context of that folder when running commands. - Create a file
C:\example\sfdx-project.json
like this:{ "packageDirectories": [ { "path": "force-app", "default": true } ], "namespace": null, "sourceApiVersion": "55.0" }
- Create a blank folder
C:\example\force-app
since you said you would in the above JSON - Run
sfdx force:auth:list
to make sure you’ve got SFDX authenticated into the orgs you’d like to work with and aliased properly, and that you remember what aliases you chose. - If not, run
sfdx force:auth:web:login --setalias my-clever-alias --instanceurl https://customdomain.my.salesforce.com/
and log in. - Run
sf retrieve metadata --metadata PermissionSet:Permission_Set_Of_Interest --target-org my-clever-alias
- Open
C:\example\noway\force-app\main\default\permissionsets
in something like Notepad++ and take out the<license>...</license>
line (or add one) - Run
sf deploy metadata --metadata PermissionSet:Permission_Set_Of_Interest --target-org **my-clever-alias
- Delete
C:\example\
- :partying_face:
infocynic:
7: sfdx force:source:retrieve -m PermissionSet:Permission_Set_Of_Interest -u my-clever-alias
9: sfdx force:source:deploy -m PermissionSet:Permission_Set_Of_Interest -u my-clever-alias
should work fine
oh and it’s important to note you have to change the api name here – you can’t update a permission set this way so you’ll have to rename the file too
KatieKodes — Today at 3:25 PM Oh, I see, so you’re saying that in this case, “XML hacking” means “convenient clone” not “update”? infocynic — Today at 3:25 PM you can’t change the license when cloning in the gui either which is for some various legit technical reasons I choose to mostly accept. 🙂 KatieKodes — Today at 3:26 PM OK, so what one is doing here is just giving themselves a UI that does allow tweaking while cloning. infocynic — Today at 3:26 PM right, notably to change something you cannot otherwise do it doesn’t come up often but if you have a p-set that say you made with a Salesforce license because “obviously everyone has a salesforce license” thinks the junior admin, and then you get platform users and want to give them that p-set, well, RIP so the steps are basically the same up to “Edit the file….” “Save the file with a new name that reflects the API name you want to give the new set, e.g. My_Cool_New_Rules.permissionset-meta.xml “Deploy the file (using the new name)”
jlantz — Today at 3:29 PM FWIW, CumulusCI has a Metadata ETL task that does the exact operation you’re talking about fully automated and repeatable way for adding licenses to permission sets but it doesn’t currently support removing them. That would be a pretty trivial feature to add to those tasks.
The added benefit of the Metadata ETL approach is that it handles retrieving the metadata from the org for you at the time you want to transform it so you don’t run the risk of metadata changing in the org but not being synced to version control. State differences between orgs and version control are dangerous.
infocynic — Today at 3:32 PM two counter arguments:
- if you’re not using VCS (rip) it’s moot and you should always fetch the latest version from your org
- If you are using VCS and you do a pull and the source doesn’t match the org, you have a bigger problem than can be addressed here because I posit that 2 is not actually using version control . version control that doesn’t match what’s in your org is useless at best and dangerous at worst. if you forget to pull, well, that’s a different story. you’ll figure that one out when you go to commit / push / merge 😄
infocynic — Today at 3:46 PM yeah i don’t work in ISV spaces so all my comments apply to end users or implementation partners.
got source? use it & pull from repo. don’t got source? pull from org.
simple, easy, done. 🙂 alt: Don’t got source? GET SOURCE. See step 1. 😄 getting proper version control is left as an exercise to the reader.