0

I have a batch script which installs a service. I am using puppet to install this service on windows using Powershell.

C:\graylog-collector\bin\graylog-collector-service.bat install GrayLogCollector 

Using the above via PS would install the service as its simply launching the .bat file. This service requires JAVA_HOME which is already set as an env system variable, but Puppet does not know that. I am trying to pass the value of JAVA_HOME before running this batch file. I tried several different things, eg:

$JAVA_HOME = [Environment]::GetEnvironmentVariable("JAVA_HOME", "Machine"); C:\graylog-collector-0.5.0\bin\graylog-collector-service.bat install GrayLogCollector 

I do not want to edit the file and do not want to declare the variable again. I am trying to use what is already set in the system. Basically, trying to get the value of JAVA_HOME and feed it in the .bat file.

phuclv
  • 37,963
  • 15
  • 156
  • 475
user3421341
  • 101
  • 2
  • 6
  • 1
    `$env:JAVA_HOME`, but if it's already set what do you mean "puppet doesn't know it's set" and "feed it in the .bat file"? If it's set, it's set, Puppet or no Puppet, right? And if the .bat file isn't built to take input, you can't feed it input, right? – TessellatingHeckler Jun 17 '18 at 02:11
  • In PowerShell, use the command `& cmd.exe /C SET` to see what variables are available when you invoke you .bat script. – lit Jun 17 '18 at 03:23
  • You should be able to run the batch file directly via an `exec` resource. I fail to see where PowerShell would come into play here. – Ansgar Wiechers Jun 17 '18 at 13:50
  • @TessellatingHeckler I can't because Puppet doesn't know about it because Puppet doesn't have access to retrieve env system variables! From what I have read, I would need to define it as a FACT in puppet, that way it would work. But, I don't want to define this variable in multiple places because in future if the path changes then things might break! – user3421341 Jun 17 '18 at 14:24
  • @AnsgarWiechers True, I can do that! But, what different does it make? It still doesn't solve the issue I am having for puppet not knowing JAVA_HOME – user3421341 Jun 17 '18 at 14:26
  • @lit Sorry, I am not sure what you are referring to. I tried something like below, but didn't help: & cmd.exe /C SET JAVA_HOME; C:\graylog-collector-0.5.0\bin\graylog-collector-service.bat install GrayLogCollector I can get the value of my variable using[Environment]::GetEnvironmentVariable("JAVA_HOME", "Machine"), but how to feed it in the batch script? – user3421341 Jun 17 '18 at 14:31
  • @lit this did the job in Powershell: cmd /V /C "set JAVA_HOME=[Environment]::GetEnvironmentVariable("JAVA_HOME", "Machine") && C:\graylog-collector-0.5.0\bin\graylog-collector-service.bat install GrayLogCollector" But, puppet still threw an error. – user3421341 Jun 17 '18 at 14:49
  • @user3421341 - I was hoping that `cmd /C SET` would show if JAVA_HOME was set already or not. Glad you have something that works for you. I might not do it that way. – lit Jun 17 '18 at 15:23

2 Answers2

0

You can combine your batch and PowerShell scripts into single batch script to accomplish your work. For example:

<# :
@echo off
  setlocal
    set "JAVA_HOME=..." % rem : this will be established in PowerShell too
    powershell /nologo /executionpolicy bypass^
    "&{[ScriptBlock]::Create((Get-Content '%~f0') -join [Char]10).Invoke(@(&{$args}%*))}"
  endlocal
exit /b
#>
"PowerShell args...$($args.ForEach{$_})"
Get-ChildItem env:

Save this like a batch script (.bat or .cmd extension), then try launch mybatch.cmd a b c into cmd or PowerShell host. Hope this helps.

  • 1
    Do not use Frankenscripts like that one. They're a major pain in the rear to maintain and debug, and the person who inherits one of those from you will hate you for the rest of their life. – Ansgar Wiechers Jun 17 '18 at 14:02
  • @AnsgarWiechers, I'm not agree with this opinion because the person who inherits a code should understand what he chose work by himself (or herself) that's why there is possibility to face with any kind of code. –  Jun 17 '18 at 15:26
  • 1
    @KatePage You're free to disagree all you like. That doesn't make inheriting such an abomination anything less than a PITA. – Ansgar Wiechers Jun 17 '18 at 18:30
  • 1
    @KatePage - I have seen almost no options for people to choose what code they inherit. No, can't think of one at the moment. – lit Jun 17 '18 at 18:47
0

I would probably create a custom fact for resolving the JAVA_HOME environment variable:

Facter.add(:java_home) do
  setcode do
    ENV['JAVA_HOME']
  end
end

or (more complex with a fallback for locating the java binary should the environment variable not be set):

Facter.add(:java_home) do
  setcode do
    begin
      ENV['JAVA_HOME'] || File.dirname(File.dirname(`readlink -f $(which java) 2>/dev/null`.chomp))
    rescue
      nil
    end
  end
end

Facter.add(:java_home) do
  confine :osfamily => 'Windows'
  setcode do
    begin
      ENV['JAVA_HOME'] || File.dirname(File.dirname(`where java 2>nul`.lines[0].chomp))
    rescue
      nil
    end
  end
end

Name the file java_home.rb and place it in a proper directory. We usually place such facts in lib/facter of our application profiles module.

Then you can use that fact to modify the environment of an exec resource:

exec { 'Install GraylogCollector service':
  command     => 'graylog-collector-service.bat install GrayLogCollector',
  unless      => 'sc query GraylogCollector',
  path        => [ 'C:\Windows', 'C:\Windows\system32', 'C:\graylog-collector\bin' ],
  environment => [ "JAVA_HOME=${::java_home}" ],
  logoutput   => true,
}

NB: I can't test this right now, so I'm not entirely certain if the batch script can be run directly like that (I would expect it to, though). If it doesn't just change the line to

command => 'cmd.exe /c "graylog-collector-service.bat install GrayLogCollector"',
Ansgar Wiechers
  • 193,178
  • 25
  • 254
  • 328