powershell detect then install nonexistent or replace existing custom service

72 views
Skip to first unread message

Aaron

unread,
Oct 30, 2015, 9:50:15 AM10/30/15
to Puppet Users
I have a question and hopefully someone can help me resolve it - 

In windows, I have custom services that I need to manage.  I've been running this code for a while, and it works well for several custom Windows services, but the problem is I cannot run it on a bare server without manual intervention (i.e. manually running the installer powershell script to create the Service before puppet will complete successfully after that).  It will fail because the Detect does not see the service, so the Uninstall cannot succeed.  I am trying to figure out how to use an ELSE off of the Detect Exec block, but am not sure how to make that work.  And I am unsure if there is anything clever I can do with the NOTIFY in the detect block.

Can anyone offer some assistance?

FYI I do not have installers, I have the bare files that are moved into place in the first File block, and then the Detect runs if any changes are made to any files in the service.  Hopefully that remains clear in my attempt to make this generic.

class FooService::install {

  if $::osfamily == 'windows' {
    File { source_permissions => ignore }
  }

  file { 'C:\\Services\\Win\\FooServiceConsumerSvc\\':
    ensure  => present,
    source  => 'puppet:///modules/FooService/FooService',
    recurse => true,
    purge   => true,
    force   => true,
  }

  exec { 'Detect FooService Service':
    command     => 'if ((Get-Service -name "FooService") -ne $null)',
    provider    => powershell,
    subscribe   => File['C:\\Services\\Win\\FooServiceConsumerSvc\\'],
    refreshonly => true,
    notify      => Exec['Uninstall Old FooService Service'],
    returns     => 0,
  }

  exec { 'Uninstall Old FooService Service':
    command     => 'C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\InstallUtil.exe /Logfile= /InstallStateDir="C:\Services\Logs\Win" /uninstall "C:\Services\Win\FooServiceConsumerSvc\FooService.exe"',
    provider    => powershell,
    refreshonly => true,
    notify      => Exec['Install New FooService Service'],
  }

  exec { 'Install New FooService Service':
    command     => 'C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\InstallUtil.exe /username=AD\user /password=password /Logfile= /InstallStateDir="C:\Services\Logs\Win"  "C:\Services\Win\FooServiceConsumerSvc\FooService.exe"',
    provider    => powershell,
    refreshonly => true,
  }

}


Rob Reynolds

unread,
Nov 3, 2015, 10:44:03 AM11/3/15
to puppet...@googlegroups.com
On Fri, Oct 30, 2015 at 8:50 AM, Aaron <aaron...@gmail.com> wrote:
I have a question and hopefully someone can help me resolve it - 

In windows, I have custom services that I need to manage.  I've been running this code for a while, and it works well for several custom Windows services, but the problem is I cannot run it on a bare server without manual intervention (i.e. manually running the installer powershell script to create the Service before puppet will complete successfully after that).  It will fail because the Detect does not see the service, so the Uninstall cannot succeed.  I am trying to figure out how to use an ELSE off of the Detect Exec block, but am not sure how to make that work.  And I am unsure if there is anything clever I can do with the NOTIFY in the detect block.

Can anyone offer some assistance?

FYI I do not have installers, I have the bare files that are moved into place in the first File block, and then the Detect runs if any changes are made to any files in the service.  Hopefully that remains clear in my attempt to make this generic.

class FooService::install {

  if $::osfamily == 'windows' {
    File { source_permissions => ignore }
  }

  file { 'C:\\Services\\Win\\FooServiceConsumerSvc\\':
    ensure  => present,
    source  => 'puppet:///modules/FooService/FooService',
    recurse => true,
    purge   => true,
    force   => true,
  }

  exec { 'Detect FooService Service':
    command     => 'if ((Get-Service -name "FooService") -ne $null)',

You could add more to the command to run here.

 
    provider    => powershell,
    subscribe   => File['C:\\Services\\Win\\FooServiceConsumerSvc\\'],
    refreshonly => true,
    notify      => Exec['Uninstall Old FooService Service'],
    returns     => 0,
  }

  exec { 'Uninstall Old FooService Service':
    command     => 'C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\InstallUtil.exe /Logfile= /InstallStateDir="C:\Services\Logs\Win" /uninstall "C:\Services\Win\FooServiceConsumerSvc\FooService.exe"',
    provider    => powershell,
    refreshonly => true,
    notify      => Exec['Install New FooService Service'],
  }

  exec { 'Install New FooService Service':
    command     => 'C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\InstallUtil.exe /username=AD\user /password=password /Logfile= /InstallStateDir="C:\Services\Logs\Win"  "C:\Services\Win\FooServiceConsumerSvc\FooService.exe"',
    provider    => powershell,
    refreshonly => true,
  }

I would move this from a refresh only and introduce onlyif or unless where you check to see if the service is installed. And if it is not, then install it. For an example of unless see 


 

}


--
You received this message because you are subscribed to the Google Groups "Puppet Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to puppet-users...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/puppet-users/7aba5a95-c27b-4bf3-a568-9f5e785ab9ce%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--
Rob Reynolds
Developer, Puppet Labs

Aaron

unread,
Nov 4, 2015, 2:58:46 PM11/4/15
to Puppet Users
Thanks Rob!

This appears to work well after looking into your suggestions...I tried to include an "unless" statement at the end of the Install New FooService Service" block for a little extra security, but it didn't seem to like that so I removed it - I'm not sure of the reason for that, however.
The refreshonly is there to make sure this doesn't just randomly uninstall and install the service but only does it when new code has been dropped into place or a file has been altered against policy and the service may be corrupted.

class FooService::install {


 
if $::osfamily == 'windows' {
   
File { source_permissions => ignore }
 
}


  file
{ 'C:\\Services\\Win\\FooServiceConsumerSvc\\':
   
ensure  => present,
    source  
=> 'puppet:///modules/FooService/FooService',
    recurse
=> true,
    purge  
=> true,
    force  
=> true,
 
}



 
exec { 'Uninstall Old FooService Service':

    command    
=> 'C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\InstallUtil.exe /Logfile= /InstallStateDir="C:\Services\Logs\Win" /uninstall "C:\Services\Win\FooServiceConsumerSvc\FooService.exe"',
    provider    
=> powershell,

    subscribe  
=> File['C:\\Services\\Win\\FooServiceConsumerSvc\\'],

    onlyif      
=> 'if ((Get-Service -name "FooService") -ne $null)',

Aaron

unread,
Nov 4, 2015, 3:11:10 PM11/4/15
to Puppet Users
blech - nevermind.  still throws horrible errors when the service has not been installed yet and puppet runs (such as on a new VM).  

Is there any way to have it see that there is an error during the uninstall and then run an ELSE and move onto the Install portion without getting hung up on not being able to uninstall first?  this is the step I can't seem to figure out.


Aaron

Rob Reynolds

unread,
Nov 30, 2015, 4:44:23 PM11/30/15
to puppet...@googlegroups.com
On Wed, Nov 4, 2015 at 2:11 PM, Aaron <aaron...@gmail.com> wrote:
blech - nevermind.  still throws horrible errors when the service has not been installed yet and puppet runs (such as on a new VM).  

Is there any way to have it see that there is an error during the uninstall and then run an ELSE and move onto the Install portion without getting hung up on not being able to uninstall first?  this is the step I can't seem to figure out.

Shift that install command to a file or script that can do error handling and have it ignore specific errors.

 


Aaron


On Wednesday, November 4, 2015 at 2:58:46 PM UTC-5, Aaron wrote:
Thanks Rob!

This appears to work well after looking into your suggestions...I tried to include an "unless" statement at the end of the Install New FooService Service" block for a little extra security, but it didn't seem to like that so I removed it - I'm not sure of the reason for that, however.
The refreshonly is there to make sure this doesn't just randomly uninstall and install the service but only does it when new code has been dropped into place or a file has been altered against policy and the service may be corrupted.

class FooService::install {


 
if $::osfamily == 'windows' {
   
File { source_permissions => ignore }
 
}


  file
{ 'C:\\Services\\Win\\FooServiceConsumerSvc\\':
   
ensure  => present,
    source  
=> 'puppet:///modules/FooService/FooService',
    recurse
=> true,
    purge  
=> true,
    force  
=> true,
 
}


 
exec { 'Uninstall Old FooService Service':
    command    
=> 'C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\InstallUtil.exe /Logfile= /InstallStateDir="C:\Services\Logs\Win" /uninstall "C:\Services\Win\FooServiceConsumerSvc\FooService.exe"',
    provider    
=> powershell,
    subscribe  
=> File['C:\\Services\\Win\\FooServiceConsumerSvc\\'],
    onlyif      
=> 'if ((Get-Service -name "FooService") -ne $null)',


You could probably convert this to simply onlyif='Get-Service -name "FooService"' - it's going to throw an error if there is no service by the name you are asking for.
 

For more options, visit https://groups.google.com/d/optout.
Reply all
Reply to author
Forward
0 new messages