Updating Uninstall Cisco AnyConnect Secure Mobility Client Fixlet

I am new to BigFix and have been trying to create a fixlet to uninstall Cisco AnyConnect Secure Mobility client from our production workstations. I found a standard uninstall fixlet here: Source Wizard: http://bigfix.me/uninstall - the issue is we have multiple versions of the app installed across the environment with multiple GUIDs. What would be the best way to get this fixlet working? Can I add multiple GUIDs to the fixlet so it sees all the different versions? Is there a better way to set this up? I apologize as I don’t want to waste anyone’s time, just trying to learn and become a better BF operator.

Thanks!

I think the best approach is to dynamically build the uninstall command based on whichever guid is actually found on the machine.

There are several examples of this in the forum, but I really would like to make a concise blog about the approaches.

One method I like that you could reference is at Relevance Tip: Plural Strings to Singular "First" String
All you need to do is replace the Display name search on it

2 Likes

Thanks @JasonWalker - I will take a look at this and see what I can do

Thanks again @JasonWalker,
I think I need to figure out a few steps first. I’m trying to create an analysis to find all available GUIDs for Cisco AnyConnect. My thought is once I have those, I can build the uninstall fixlet around them. If you have any tips for setting something up, would be appreciated.

Cheers,

I think the post I linked has everything you need for the action, if you just replace the sample display name with “Cisco Anyconnect” or whatever the actual display name is for that product

1 Like

I ran this through debugger and I think it worked, although it rebooted my machine instantly. I’m guessing if I add some switches like quiet and no restart it may be the solution. Can I add those switches in

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

?

We use this template for Windows uninstalls based on MSIs:

  1. windows of operating system
  2. exist keys whose( (exists values "DisplayName" whose(it as string as lowercase starts with "REPLACE" 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 ( x32 registries; x64 registries )

Action:

parameter "theDisplayName" = "REPLACE" 

waithidden msiexec.exe /X { name of keys whose( (exists values "DisplayName" whose(it as string as lowercase starts with (parameter "theDisplayName") 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 ( x32 registries; x64 registries ) } /qn 

parameter "theExit" = "{exit code of action}" 
if {parameter "theExit" = "1603"} 
    action requires restart 
endif

Where you see the text “REPLACE”, swap in the display name of the product you’re trying to match.

4 Likes

Thanks @atlauren

I ran this in debugger and added one “{” as it was throwing error there.

waithidden msiexec.exe /X {{ name of keys whose( (exists values "DisplayName" whose(it as string as lowercase starts with (parameter "cisco anyconnect") 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 ( x32 registries; x64 registries ) } /qn 

parameter “theExit” = "{exit code of action}"
if {parameter “theExit” = “1603”}
action requires restart
endif

Seems as though it’s stuck running, any chance you’ve seen this behavior?

In your quoted example, you have parameter "cisco anyconnect". There is likely no such thing.

Instead, use the parameter and enter “Cisco AnyConnect Secure Mobility Client” where you see the word “REPLACE”

Agreed, and adding a second { isn’t the solution there. That escapes the whole thing so the relevance isn’t evaluated at all, so it’s sending the literal string { name of keys... as part of the MSIEXEC command line

I think @atlauren’s suggestion is correct, and that 'Cisco AnyConnect Secure Mobility Client" probably really is the string you want to find. If you didn’t have the full string, use the Fixlet Debugger or the WebUI’s ‘Query’ app to run relevance on the clients to find the correct DisplayName values:

q: values "DisplayName" of keys of keys "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall" of ( x32 registries; x64 registries)
A: Visual Studio Build Tools 2019
A: Cisco WebEx Meetings
A: AnyDesk
A: Audacity 2.3.3
A: Visual Studio Build Tools 2017
A: KDiff3 (remove only)
A: Microsoft Edge
A: Microsoft Edge Update
A: Microsoft Edge WebView2 Runtime
... and many more

Then, knowing the DisplayName you want to remove, you could do it a couple of ways. Using a ‘Parameter’ just makes it easier to reuse the fixlet later, since you can just change the Parameter line and not worry too much about finding & replacing in the longer relevance statement, or you could make it just a bit simpler by not using a parameter at all if you expect this is a one-time issue…

Either of these should work

parameter "theDisplayName" = "Cisco AnyConnect Secure Mobility Client" 

waithidden msiexec.exe /X { name of keys whose( (exists values "DisplayName" whose(it as string as lowercase starts with (parameter "theDisplayName") 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 ( x32 registries; x64 registries ) } /qn 

parameter "theExit" = "{exit code of action}" 
if {parameter "theExit" = "1603"} 
    action requires restart 
endif

or

waithidden msiexec.exe /X { name of keys whose( (exists values "DisplayName" whose(it as string as lowercase starts with "Cisco AnyConnect Secure Mobility Client" 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 ( x32 registries; x64 registries ) } /qn 

parameter "theExit" = "{exit code of action}" 
if {parameter "theExit" = "1603"} 
    action requires restart 
endif

(although… @atlauren … I’m not sure about checking for exit code 1603 - I think that’s an error condition, isn’t it? 3010 is the usual ‘success - restart required’ exit code with which I’m familiar)

1 Like

The check for 1603 is there because sometimes it shows up, and 1603 is an msiexec general catch-all. In practice, 1603 often means “Dunno. Restart and try again.”

My thinking is that if you see 1603, you definitely need to restart. The action will report “Fail” but the pending restart puts you in a better position for success on the next try.

2 Likes

Thank you both, I think I got it working and learned a few things too! Have a great weekend

3 Likes