How to perform relevance substitution with multiple values

We ran into an issue with some devices failing to upgrade Microsoft Edge. I won’t get into the details unless necessary, but while we were able to resolve the issue, it resulted in multiple instances of Edge appearing in software inventory. The upgrades are now successful and there are no traces of the old versions remaining EXCEPT for the corresponding entries located here:

"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall" of 
(
	x64 registries; x32 registries
)

I want to be able to identify all of those keys except for the current revision, then delete them. I was able to create an expression that can parse all of the older versions with this:

keys whose
(
	(
		value "DisplayName" of it as string as trimmed string equals "Microsoft Edge"
      	)
	AND
	(
		value "DisplayVersion" of it as string as version < maximum of
			(
				values "DisplayVersion" of keys whose
				(
					value "DisplayName" of it as string as trimmed string equals "Microsoft Edge"
      				)
				of keys "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall" of 
      				(
         			 x64 registries; x32 registries
				)
				as string as version
			)
		)
	)
of keys "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall" of 
(
	x64 registries; x32 registries
)

The output gave me the expected regkey paths:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall{AB712F32-2F69-3125-8A0C-FB35D2825FF0}
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall{B7C37725-DB9C-3C53-9F90-908C92D0B55C}

However, I don’t know where to go from here. I’m not sure how I can take this expression and pipe it to a parameter or something with relevance substitution to delete these regkeys. If it were just 1 value it would be simple, but these multiple values make it difficult.

There is no construct for loops in native ActionScript, so instead you have to create a batch file with the multiple commands. We use the CR/LF character combination (%09%0a) to embed newline characters in the batch substitution.

Try

action uses wow64 redirection false

delete __appendfile
appendfile {concatenation "%0d%0a" of ("REG.EXE DELETE %22" & pathname of it & "%22 /F") of <your query> }

delete reg_delete.cmd
move __appendfile reg_delete.cmd
waithidden cmd.exe /c reg_delete.cmd

Note - the batch file may only delete the “native” (64-bit) paths the way you’re querying, so you may need to instead query for keys ("Microsoft\Windows\CurrentVersion\Uninstall") of (it; keys "Wow6432Node" of it) of keys "HKLM\Software" of native registry so you have the native pathnames (including Wow6432Node) to pass to the native version of reg.exe

2 Likes

Shame there is no native loop support but as long as there is a way I’ll take it. You were correct with my query only finding 64-bit paths and it did not remove them from under the WOW6432Node path, so I substituted my key path with yours:

action uses wow64 redirection false

delete __appendfile
appendfile {concatenation "%0d%0a" of ("REG.EXE DELETE %22" & pathname of it & "%22 /F") of keys whose ((value "DisplayName" of it as string as trimmed string equals "Microsoft Edge") AND (value "DisplayVersion" of it as string as version < maximum of ( values "DisplayVersion" of keys whose (value "DisplayName" of it as string as trimmed string equals "Microsoft Edge") of keys ("Microsoft\Windows\CurrentVersion\Uninstall") of (it; keys "Wow6432Node" of it) of keys "HKLM\Software" of native registry as string as version))) of keys ("Microsoft\Windows\CurrentVersion\Uninstall") of (it; keys "Wow6432Node" of it) of keys "HKLM\Software" of native registry}

delete reg_delete.cmd
move __appendfile reg_delete.cmd
waithidden cmd.exe /c reg_delete.cmd

It’s a bit harder to read without formatting, but I can’t complain with the results because it works! Only question I have is you used %09%0a for CR/LF in your description and %0d%0a in your example - I used the latter, but what’s the difference, or is there a resource you could reference?

1 Like

You’re right - %0d%0a is proper, just a tyop on my part

If it is always exactly those 2 entries, you could just do:

regdelete64 [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{{AB712F32-2F69-3125-8A0C-FB35D2825FF0}]

regdelete64 [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{{B7C37725-DB9C-3C53-9F90-908C92D0B55C}]

You could have relevance to check if either exists too. Ideally you could even have relevance to detect that the registry entries exist, but the install does not actually exist so that you detect the problem condition so that you only delete the entries if the problem condition exists.

You really only need to implement “looping” using the batch file method if the number of entries are arbitrary and are different on different systems, especially if it is fine to blindly delete any or either item and if the item doesn’t exist, then nothing bad happens, it just will attempt to delete something that doesn’t exist and it will move on.

That said, @JasonWalker 's recommendation is the correct one when you have an arbitrary large number of things that are not consistently “named” across many machines.

Yes I needed this approach because there are multiple application GUIDs for MS Edge. This particular device only had 2 stale entries, but we have hundreds of devices which we had to correct after repairing the corruption. There are dozens of versions (mostly v87-103), and each time they updated they left more entries, so some had 2 or 3 or 4 stale entries.

However I did account for the relevance which is only applicable to these affected devices. It’s the same as my query above, but with “exist” in front to check if any non-current Edge entries exist by comparing them using the “maximum of version” property. If only 1 version exists, there will be no entries below the maximum version, otherwise I want it to delete everything else that it finds:

exist keys 
whose
(
    (
        value "DisplayName" of it as string as trimmed string equals "Microsoft Edge"
    )
  AND
    (
        value "DisplayVersion" of it as string as version < maximum of 
        (
            values "DisplayVersion" of keys 
            whose
            (
                value "DisplayName" of it as string as trimmed string equals "Microsoft Edge"
            )
            of keys 
            (
                "Microsoft\Windows\CurrentVersion\Uninstall"
            )
            of 
            (
                it; keys "Wow6432Node" of it
            )
            of keys "HKLM\Software" of native registry as string as version
        )
    )
)
of keys 
(
    "Microsoft\Windows\CurrentVersion\Uninstall"
)
of 
(
    it; keys "Wow6432Node" of it
)
of keys "HKLM\Software" of native registry
2 Likes