Relevance Tip: Plural Strings to Singular "First" String

There are cases where you would typically have a singular result but you MIGHT have multiple results in some edge cases.

This came up recently when trying to uninstall an application. In the actionscript:

waithidden msiexec.exe /x { name of keys whose( (exists values "DisplayName" whose(it as string as lowercase starts with "NAME_OF_APP" as lowercase) of it) AND (exists values whose(it as string as lowercase starts with "msiexec") of it) ) of keys "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall" of ( x64 registries; x32 registries ) } /qn

The issue is that if this relevance returns multiple keys from the registry and thus multiple GUIDs, then the actionscript can’t handle that case. This can happen if there is more than one product with a similar name installed, especially if one copy is 32bit and another copy is 64bit.

One option is to just take the “first” result of the many results, uninstall the “first” one, then try again later to uninstall the rest, if desired.

See this example:

Q: tuple string item 0 of concatenations ", " of unique values of ("keyZ";"key1";"key2";"key1";"key3")
A: key1

This will collapse the many results into an alphabetized unique list, then turn that list of unknown number of items into a tuple string, ( example: "key1, key2" ) then take the first item from that tuple string. This works as long as the input strings do NOT contain commas.

One important thing though, is that this ALSO works if there is only 1 result:

Q: tuple string item 0 of concatenations ", " of unique values of ("keyA")
A: keyA

Break it apart to see what happens at each step:

First: Unique List

Q: unique values of ("keyZ";"key1";"key2";"key1";"key3")
A: key1
A: key2
A: key3
A: keyZ

Second: Create Tuple String

Q: concatenations ", " of unique values of ("keyZ";"key1";"key2";"key1";"key3")
A: key1, key2, key3, keyZ

Third: Get first item (0 index)

Q: tuple string items 0 of concatenations ", " of unique values of ("keyZ";"key1";"key2";"key1";"key3")
A: key1

Related:

4 Likes

And to throw in another approach that may be of use for some uninstall situations, grab the key names as a parameter then pipe them to a CMD line for loop

parameter "GUIDs" = "{concatenation " " of unique values of names of keys whose ((exists values "DisplayName" whose(it as string as lowercase starts with "NAME_OF_APP" as lowercase) of it) AND (exists values whose(it as string as lowercase starts with "msiexec") of it)) of keys "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall" of ( x64 registries; x32 registries )}"

waithidden cmd.exe /c "for %a in ({parameter "GUIDs"}) do msiexec /x %a /qn"
5 Likes

Very helpful! Thank you both! :sunglasses:

BigFix doesn’t directly support looping in actionscript (for good reasons) but this is one of the possible workarounds, is to do the looping within the shell itself. I will admit, I’m not as experienced using for in shell commands so I don’t think to use it, but it is a pretty good solution.

Another option is to build a script using relevance substitution that contains a line for each command you need to run to deal with each item individually. See this example: bigfix-content/fixlet/Cleanup old log archives - Windows.bes at main · jgstew/bigfix-content · GitHub

I was looking for a simpler form of this, and also wanted to avoid the sorting of ‘unique values of’, and handle the edge cases of commas embedded in the string values. I got some behavior for 'tuple string of ’ that I wasn’t expecting, that actually handles this much more easily than I thought:

  1. Automatically converts a plural to a tuple?
q: tuple string of ("keyZ";"key1";"key2";"key1";"key3")
A: keyZ, key1, key2, key1, key3
T: 14.949 ms
I: singular
  1. Automatically handles escaping embedded commas (by wrapping in parentheses):
    q: tuple string of ("key0, value0 ";"key1";"key2, value2";"key3")
    A: ( key0, value0  ), key1, ( key2, value2 ), key3
    T: 11.410 ms
    I: singular string
  1. easy to retrieve the “first” (not necessarily “lowest” or “greatest” per sort order) in both cases
q: tuple string item 0 of tuple string of ("keyZ";"key1";"key2";"key1";"key3")
A: keyZ
T: 12.068 ms
I: singular string

q: tuple string items 0 of tuple string of ("key0, value0 ";"key1";"key2, value2";"key3")
A: key0, value0 
T: 11.955 ms
I: plural string

I knew we could do some neat things with the ‘tuple string of’ inspector, but I had no idea it would convert a list into a tuple for us.

2 Likes

Of course, nothing’s perfect. While ‘tuple string of’ handles embedded commas gracefully, it’s not so happy with unmatched parentheses

q: tuple string items 0 of tuple string of ("key0, value0 )";"key1";"key2, value2";"key3")
E: The expression could not be evaluated: class MismatchedParentheses
1 Like

one reason I like using unique values in general for this sort of thing is the case where there are multiple results, but some of the results are identical, and i want to be sure to collapse those down.

It would be interesting if there was an inspector to sort without collapsing duplicates, or also a unique values inspector that removed the duplicates wherever they are found later in the series but without changing the overall order of the series.

1 Like

There was a challenge, I think, for that; I think @brolly33 had the use case for it. There were solutions, but it wasn’t trivial. I think I went with a solution based on substrings not being contained by their preceding texts.

1 Like

Yeah, I didn’t have a specific use case for it, but it would be ideal if there was a built in inspector that could provide it more efficiently than trying to brute force it.