Salesforce, Python, SQL, & other ways to put your data where you need it

Need event music? 🎸

Live and recorded jazz, pop, and meditative music for your virtual conference / Zoom wedding / yoga class / private party with quality sound and a smooth technical experience

Editing Salesforce permission set licenses with VSCode

19 Aug 2022 🔖 salesforce pardot
💬 EN

Table of Contents

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:

  1. click the Windows Start icon
  2. start typing “system env”
  3. click “Edit the system environment variables
  4. type in a Windows administrative username & password again
  5. click the “Environment Variables” button in the lower-right corner of the System Properties popup
  6. double-click the variable named Path in the upper half of the Environment Variables popup
  7. double-click the line reading “C:\Program Files\sfdx\bin” in the Edit environment variable popup
  8. copy it to your clipboard
  9. click somewhere else
  10. single-click the line that says “C:\Program Files\sfdx\bin
  11. click the “Delete” button once
  12. double-click the variable named Path in the lower half of the Environment Variables popup
  13. click the New button
  14. paste “C:\Program Files\sfdx\bin” off your clipboard
  15. 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:

  1. Install SFDX on your computer and make sure it works, sfdx --version and sf --version
  2. 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.
  3. Create a file C:\example\sfdx-project.json like this:
    {
      "packageDirectories": [
     {
       "path": "force-app",
       "default": true
     }
      ],
      "namespace": null,
      "sourceApiVersion": "55.0"
    }
    
  4. Create a blank folder C:\example\force-app since you said you would in the above JSON
  5. 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.
  6. If not, run sfdx force:auth:web:login --setalias my-clever-alias --instanceurl https://customdomain.my.salesforce.com/ and log in.
  7. Run sf retrieve metadata --metadata PermissionSet:Permission_Set_Of_Interest --target-org my-clever-alias
  8. Open C:\example\noway\force-app\main\default\permissionsets in something like Notepad++ and take out the <license>...</license> line (or add one)
  9. Run sf deploy metadata --metadata PermissionSet:Permission_Set_Of_Interest --target-org **my-clever-alias
  10. Delete C:\example\
  11. :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:

  1. if you’re not using VCS (rip) it’s moot and you should always fetch the latest version from your org
  2. 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.

--- ---