Run PowerShell code in Puppet


Summary: Hi everyone, Dan Franciscus here. I’m a systems engineer and freelance technical writer based out of New Jersey. My expertise is in Windows Server, PowerShell, VMware, and Puppet. Puppet is an infrastructure platform that helps automate your environment. While Puppet has a large Linux user base, it also supports the configuration of Windows systems.

---------------

Normally, it’s preferable to use specific Puppet and DSC Windows modules to manage systems in Puppet, but an alternative is running PowerShell commands and scripts by using the exec resource. This can be helpful for transitioning existing PowerShell code into Puppet quickly.

The exec resource allows you to execute shell commands on your nodes. Fortunately, Puppet also allows users to change the provider used for the exec resource to PowerShell, so that Windows Puppet nodes will run PowerShell commands.

For instance, in this example manifest, I want to run a PowerShell command that adds the string “Hello” to the contents of a text file (“C:\test.txt”) for my Puppet node (“Test-1”).

node ‘Test-1' {

exec { 'SETHELLO':

      command   => 'Add-Content -Path c:\test.txt –Value “Hello”’,

      logoutput => true,

      provider  => powershell,

      }

}

The three parameters I use in this manifest are command, logoutput and provider. The command parameter is the PowerShell code you want to run on your node. The logoutput parameter just logs the output to the console. Finally, provider is necessary to declare that PowerShell is the shell to use in this resource, instead of BASH by default.

When I run puppet agent on my Test-1 node, I get this output:

PS C:\> puppet agent --test  

Info: Retrieving pluginfacts                                                                

Info: Retrieving plugin                                                                     

Info: Loading facts                                                                         

Info: Caching catalog for Test-1                                                     

Info: Applying configuration version '1524181853'                                            

Notice: /Stage[main]/Main/Node[Test-1 ]/Exec[SETHELLO]/returns: executed successfully

Notice: Finished catalog run in 1.91 seconds

If I run Get-Content on c:\test.txt, I see Puppet did its job by adding “Hello”:

PS C:\> Get-Content C:\test.txt                                                             

Hello

You can see from the output, Puppet ran the Add-Content command successfully. This is fine, but with configuration management we usually want to make our configurations idempotent. In other words, we want the same effect on a node each time we run it, regardless of how many times. In this case, I only want “Hello” to be added to c:\test.txt when it does not already exist in the file. To make this resource idempotent, I will use the unless parameter in my manifest. In the unless parameter, I will look into the file with Select-String to see if the “Hello” string is present. If it is not present, Puppet adds “Hello” to c:\test.txt with Add-Content.

node 'puppetagent-win' {

      exec { 'SETHELLO':

           command   => 'Add-Content -Path c:\test.txt -Value "Hello"',

           unless => 'if (!(Select-String -Path c:\test.txt -Pattern "Hello")){exit 1}',

           logoutput => true,

           provider  => powershell,

      }

}

There is an alternative to the unless parameter. You can use onlyif, which only runs what is in the command parameter if the command in onlyif returns an exit code of 0.

Now on my node, I first illustrate that there is nothing in the contents of c:\test.txt by setting the value to $Null:

PS C:\> Set-Content -Value $Null -Path C:\test.txt                                          

PS C:\> Get-Content -Path C:\test.txt                                                                     

PS C:\>             

Next, I run puppet agent, which adds the “Hello” string to c:\test.txt since Select-String does not find it:

PS C:\> puppet agent --test  

Info: Retrieving pluginfacts                                                                

Info: Retrieving plugin                                                                     

Info: Loading facts                                                                         

Info: Caching catalog for Test-1                                                     

Info: Applying configuration version '1524332621'                                           

Notice: /Stage[main]/Main/Node[Test-1 ]/Exec[SETHELLO]/returns: executed successfully

Notice: Finished catalog run in 2.97 seconds 

As you can see with Get-Content, Puppet added the “Hello” string to c:\test.txt:

PS C:\> Get-Content –Path C:\test.txt                                                             

Hello 

Finally, if I run puppet agent on the node again, nothing is done. This is because the unless parameter has an exit code of 0, meaning “Hello” was found in c:\test.txt:

PS C:\> puppet agent --test                                        

Info: Retrieving pluginfacts                                                                

Info: Retrieving plugin                                                                     

Info: Loading facts                                                                         

Info: Caching catalog for Test-1                                                     

Info: Applying configuration version '1524333018'                                           

Notice: Finished catalog run in 1.89 seconds                                                

PS C:\> Get-Content -Path C:\test.txt                                                              

Hello   

I hope this gives you some insight into how to use PowerShell with Puppet to manage and automate the configuration of your Windows systems. For more information on using Puppet with Windows, you can visit puppet.com and view their 9-part webinar series.

 

Dan Franciscus, guest blogger

You can follow him on Twitter or read his blog here.

 

 

Comments (0)

Skip to main content