views:

72

answers:

1

I want to be able to set a system environment variable in Perl and I wrote the following script (inspired from this idea) to accomplish this:

use Win32;
use Win32::API;
use Win32::OLE qw( in );

my $machine = ".";
my $WMIServices = Win32::OLE->GetObject ( "winmgmts:{impersonationLevel=impersonate,(security)}//$machine/root/cimv2" ) || die;

my $objVariable = $WMIServices->Get("Win32_Environment")->SpawnInstance_;
$objVariable->{Name}="NewOSType";
$objVariable->{UserName} = "<System>";
$objVariable->{VariableValue} = "LAMBDA";
$objVariable->Put_;

However, I am not an expert in Perl and I would like to know what the experts think about this code. Is this the best way to accomplish this?

+2  A: 

Another possible approach:

use strict;
use warnings;
use Win32::TieRegistry qw[:KEY_];
use Win32::API;
use constant HWND_BROADCAST => -1;
use constant WM_SETTINGCHANGE => 0x1a;

my $hklm_env = Win32::TieRegistry->new(
    'HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Control/Session Manager/Environment', 
    { Access => KEY_READ() | KEY_WRITE(), Delimiter => '/' }
); # returns undef if SYSTEM ENV not writable

my $hkcu_env = Win32::TieRegistry->new(
    'HKEY_CURRENT_USER/Environment', 
    { Access => KEY_READ() | KEY_WRITE(), Delimiter => '/' }
);

# if SYSTEM ENV not writable try USER ENV
my $e = defined($hklm_env) ? $hklm_env : $hkcu_env;

if(defined $e) {
  $e->SetValue('Variable', 'Value');  
}
else {
  warn "Cannot open neither SYSTEM ENV nor USER ENV registry for Read+Write";
}

my $SendMessage = new Win32::API("user32", "SendMessage", 'NNNP', 'N') or die "Couldn't create SendMessage: $!\n";
my $RetVal = $SendMessage->Call(HWND_BROADCAST,WM_SETTINGCHANGE,0,'Environment');
kmx
I think Santhosh's code is better as WMI is the way recommended by Microsoft. Also, it is shorter. Anyway, +1 for the WM_SETTINGCHANGE that would be not known to those tempted by a direct manipulation of the registry.
dolmen