Exec Onlyif Registry Value Is Not Present

Telling Puppet to only run an install if registry key is not present

The user manbart found the answer 7 months ago with this question

Exec onlyif registry value is not present

calling reg.exe to query the registry in an exec resource.

Puppet: Conditional exec using unless-option

Make sure you are not subject to registry redirection or file system redirection. This is usually the case - if you are on a 64-bit Windows OS, it is preferred that you use a 64-bit version of Puppet.

We've noted file system redirector and workarounds in troubleshooting. We've also touched on registry redirection for custom facts. In your case, it could be you are subject to file system redirection as you are attempting to call c:\windows\system32\cmd.exe.

The short of it is, you should ensure that you are using the 64 bit version of cmd.exe, which is either in c:\windows\sysnative or c:\windows\system32. This is addressed by the $system32 fact starting with Puppet 3.7.3:

exec { 'example':
path => "$system32',
command => 'something',
unless => 'reg query "HKEY_LOCAL_MACHINE\Software\My key" /f 5.1',
}

c# Setting new registry value only if registry value name already exists

Use the Registry.GetValue() method:

Retrieves the value associated with the specified name, in the specified registry key. If the name is not found in the specified key, returns a default value that you provide, or null if the specified key does not exist.

If you want to test whether the keyName exists, test for null:

var myValue
= Registry.GetValue(@"HKEY_CURRENT_USER\missing_key", "missing_value", "hi");

// myValue = null (because that's just what GetValue returns)

If you want to test whether the valueName exists, test for your default value:

var myValue
= Registry.GetValue(@"HKEY_CURRENT_USER\valid_key", "missing_value", null);

// myValue = null (because that's what you specified as the defaultValue)

If the path could be invalid, you could try surrounding it with a try/catch block:

try
{
var myValue = Registry.GetValue( ... ); // throws exception on invalid keyName

if (myValue != null)
Registry.SetValue( ... );
}
catch (ArgumentException ex)
{
// do something like tell user that path is invalid
}

How to execute logic on Optional if not present?

With Java 9 or higher, ifPresentOrElse is most likely what you want:

Optional<> opt = dao.find();

opt.ifPresentOrElse(obj -> obj.setAvailable(true),
() -> logger.error("…"));

Currying using vavr or alike might get even neater code, but I haven't tried yet.

Execute create_resource after everything has finished or after exec has finished

Like all Puppet functions, create_resources() runs during catalog building. Each catalog is completely built before any resource declared in it is applied, and often on a different machine than the one for which it is intended. What you appear to be after is not modulating the behavior of create_resources(), but rather managing the relative order of application of the resources it adds to the catalog.

And that you can readily do with a chain operator and a resource collector. For example, add

Exec['I need to run first'] -> Do::Something<||>

to the body of class do::foo. There are a lot of possible variations on that, and also a few alternative approaches, but I would need details of the specific use case to make stronger or more specific recommendations.

Triggering dependent resources in a interation loop

I believe I need to add some dependencies using subscribe and refreshonly.

I'm not so sure that you need to add dependencies, because without explicit dependencies, resources should be applied in the relative order in which they appear in the manifest. Additionally, refreshonly does not declare a dependency, and subscribe is probably not appropriate for this particular task. Furthermore, although refreshonly works in conjunction with dependencies, it's probably not appropriate for this task, either, because notify / subscribe is not right for it.

In a general sense, the key issues are these:

  • the hive must be loaded before you can attempt to sync any registry entries, so you cannot know whether any given registry resource is out of sync without loading the hive first;

  • if the hive is loaded then it must also be unloaded;

  • but the hive must not be unloaded before all the registry entries are synced.

You cannot make Exec['load_registry_hive'] refreshonly because there is no resource that would signal it. You can, however, check whether $base_windows::registry has any elements as a precondition for doing any of the work. If it does, then you definitely need to load the hive.

You can set up explicit dependencies, and I'm generally inclined to do that, as it protects against surprises when a resource is affected by dependency edges that are not apparent at the point of its declaration. So I would suggest this:

$temp_hive_name = $base_windows::temp_hive_name

if ! $base_windows::registry.empty() {
# LOAD REGISTRY HIVE
exec { 'load_registry_hive' :
command => template('base_windows/Load-RegHive.ps1.erb'),
unless => template('base_windows/Test-HiveLoadState.ps1.erb'),
provider => powershell,
logoutput => true,
}

# MODIFY REGISTRY, ITERATING OVER HIERA DATA
$base_windows::registry.each | $key, $value | {
registry::value { "registry_${key}" :
key => "${value['key']}\\${temp_hive_name}\\${value['subkey']}",
type => $value['type'],
data => $value['data'],
value => $value['value'],
require => Exec['load_registry_hive'],
before => Exec['unload_registry_hive'],
}
}

# UNLOAD REGISTRY HIVE
exec { 'unload_registry_hive' :
command => template('base_windows/Unload-RegHive.ps1.erb'),
onlyif => template('base_windows/Test-HiveLoadState.ps1.erb'),
provider => powershell,
logoutput => true,
}
}

Note that you will necessarily both load and unload the hive on each Puppet run, because you cannot determine whether any entries need to be updated without doing so.

How to allow user to install only if a given registry key doesn't have a certain value?

You'll need a post build JScript for your MSI file. Or you can do it manually in Orca.

var installer = WScript.CreateObject("WindowsInstaller.Installer");
var filespec = WScript.Arguments(0);
var msiOpenDatabaseModeTransact = 1;
var database = installer.OpenDatabase(filespec, msiOpenDatabaseModeTransact);

Execute("INSERT INTO `AppSearch` (`Property`, `Signature_`) VALUES ('SOMESOFTWAREVERSION', 'SomeSoftwareVersion')");
Execute("INSERT INTO `RegLocator` (`Signature_`, `Root`, `Key`, `Name`, `Type`) VALUES ('SomeSoftwareVersion', 2, 'SOFTWARE\\Some Manufacturer\\SomeSoftware', 'SomeSoftwareVersion', 2)");
Execute("INSERT INTO `LaunchCondition` (`Condition`, `Description`) VALUES ('SOMESOFTWAREVERSION <> \"#1\"', 'This application cannot be installed with SOMESOFTWARE v1. Setup now will exit.')");

function Execute(sql) {
view = database.OpenView(sql);
view.Execute();
view.Close();
}

It will check Wow6432Node on 64-bit Windows just as WiX does



Related Topics



Leave a reply



Submit