Automating Windows targets


Bolt lets you automate almost any task you can think of. These are some of the common scenarios we've come across.

If you'd like to share a real-world use case, reach out to us in the #bolt channel on Slack.

For more usage examples, check out the Puppet blog.

Run a PowerShell script that restarts a service

To show you how you can use Bolt to reuse your existing PowerShell scripts, this guide walks you through running a script with Bolt, and then converting the script to a Bolt task and running that.

Before you begin

The example script, called restart_service.ps1, performs common task of restarting a service on demand. The process involves these steps:

  1. Run your PowerShell script on a Windows target.

  2. Create an inventory file to store information about the target.

  3. Convert your script to a task.

  4. Execute your new task.

1. Run your PowerShell script on a Windows target

First, we’ll use Bolt to run the script as-is on a single target.

  1. Create a Bolt project directory to work in, called bolt-guide.

  2. Copy the restart_service.ps1 script into bolt-guide.

  3. In the bolt-guide directory, run the restart_service.ps1 script:

    bolt script run .\restart_service.ps1 W32Time --targets winrm://<HOSTNAME> -u Administrator -p 

    Note: The -p option prompts you to enter a password.

    By running this command, you’ve brought your script under Bolt control and have run it on a remote target. When you ran your script with Bolt, the script was transferred into a temporary directory on the remote target, it ran on that target, and then it was deleted from the target.

2. Create an inventory file to store information about your targets

To run Bolt commands against multiple targets at once, you need to provide information about the environment by creating an inventory file. The inventory file is a YAML file that contains a list of targets and target specific data.

  1. Inside the bolt-guide directory, use a text editor to create an inventory.yaml file.

  2. Inside the new inventory.yaml file, add the following content, listing the fully qualified domain names of the targets you want to run the script on, and replacing the credentials in the winrm section with those appropriate for your target:

      - name: windows
          - <>
          transport: winrm
            user: Administrator
            password: <ADD PASSWORD>

    Note: To have Bolt securely prompt for a password, use the --password-prompt flag without supplying any value. This prevents the password from appearing in a process listing or on the console. Alternatively you can use the ``prompt plugin to set configuration values via a prompt.

    You now have an inventory file where you can store information about your targets.

    You can also configure a variety of options for Bolt in bolt.yaml, including global and transport options. For more information, see Bolt configuration options.

3. Convert your script to a Bolt task

To convert the restart_service.ps1 script to a task, giving you the ability to reuse and share it, create a task metadata file. Task metadata files describe task parameters, validate input, and control how the task runner executes the task.

Note: This guide shows you how to convert the script to a task by manually creating the .ps1 file in a directory called tasks. Alternatively, you can use Puppet Development Kit (PDK), to create a new task by using the pdk new task command. If you’re going to be creating a lot of tasks, using PDK is worth getting to know. For more information, see the PDK documentation.

  1. In the bolt-guide directory, create the following subdirectories:

    └── modules
        └── gsg
            └── tasks
  2. Move the restart_service.ps1 script into the tasks directory.

  3. In the tasks directory, use your text editor to create a task metadata file — named after the script, but with a .json extension, in this example, restart_service.json.

  4. Add the following content to the new task metadata file:

      "puppet_task_version": 1,
      "supports_noop": false,
      "description": "Stop or restart a service or list of services on a target.",
      "parameters": {
        "service": {
          "description": "The name of the service, or a list of service names to stop.",
          "type": "Variant[Array[String],String]"
        "norestart": {
          "description": "Immediately restart the services after start.",
          "type": "Optional[Boolean]"
  5. Save the task metadata file and navigate back to the bolt-guide directory.

    You now have two files in the gsg module’s tasks directory: restart_service.ps1 and restart_service.json -- the script is officially converted to a Bolt task. Now that it’s converted, you no longer need to specify the file extension when you call it from a Bolt command.

  6. Validate that Bolt recognizes the script as a task:

    bolt task show gsg::restart_service

    Congratulations! You’ve successfully converted the restart_service.ps1 script to a Bolt task.

  7. Execute your new task:

    bolt task run gsg::restart_service service=W32Time --targets windows

    Note: --targets windows refers to the name of the group of targets that you specified in your inventory file. For more information, see Specify targets.

Deploy a package with Bolt and Chocolatey

You can use Bolt with Chocolatey to deploy a package on a Windows node by writing a Bolt plan that installs Chocolatey and uses Puppet's Chocolatey package provider to install a package. This is all done using content from the Puppet Forge.

Before you begin

In this example, you:

  • Build a project-specific configuration using a Bolt project directory and PDK.

  • Download module content from the Puppet Forge.

  • Write a Bolt plan to apply Puppet code and orchestrate the deployment of a package resource using the Chocolatey provider.

1. Build a project-specific configuration

Bolt runs in the context of a Bolt project directory. This directory contains all of the configuration, code, and data loaded by Bolt.

  1. Create a module called bolt_choco_example

mkdir bolt_choco_example
  1. Add a bolt.yaml file to the puppet_choco_tap directory:

New-Item -Type File -Path .\puppet_choco_tap\bolt.yaml

Adding a bolt.yaml file (even if it's empty), makes the containing directory a Bolt project directory when you run Bolt from it. This is where Bolt loads code and configuration from.

  1. Create an inventory file to store information about your targets. This is stored as inventory.yaml by default in the project directory. Add the following code:

  - name: windows
      transport: winrm
        user: Administrator
        password: <ADD PASSWORD>
  1. To make sure that your inventory is configured correctly and that you can connect to all the targets, run the following command from inside the project directory:

bolt command run 'echo hi' --targets windows

Note: The --targets windows argument refers to the target group defined in the inventory file.

You should get the following output:

Started on x.x.x.x...
Started on localhost...
Finished on localhost:
Finished on
Finished on
Successful on 3 targets:,localhost
Ran on 3 targets in 0.20 seconds

2. Download the Chocolatey module

Bolt uses a Puppetfile to install module content from the Forge. A Puppetfile is a formatted text file that specifies the modules and data you want in each environment.

  1. Create a file named Puppetfile in the project directory, with the modules needed for this example:

mod 'puppetlabs-chocolatey', '4.1.0'
mod 'puppetlabs-stdlib', '4.13.1'
mod 'puppetlabs-powershell', '2.3.0'
mod 'puppetlabs-registry', '2.1.0'

Note that you can install modules from a number of different sources. For more information, see the Puppetfile README.

  1. From inside the project directory, install the required modules:

bolt puppetfile install

After it runs, you can see a modules directory inside the project directory, containing the modules you specified in the Puppetfile.

3. Write a Bolt plan to apply Puppet code

Write a Bolt plan to orchestrate the deployment of a package resource using the Chocolatey provider. Plans allow you to run more than one task with a single command, compute values for the input to a task, process the results of tasks, or make decisions based on the result of running a task.

  1. Create a site-modules directory. This is where you will add local code and modules.

  2. Inside the site-modules directory, create a new module called puppet_choco_tap.

    pdk new module puppet_choco_tap
  3. Inside the puppet_choco_tap module, create a plans directory with a Bolt plan at /plans/installer.pp.

The folder tree should look like this:

└── site-modules
    └── puppet_choco_tap
        └── plans
            └── installer.pp 
  1. Create a plan called puppet_choco_tap::installer by copying the following code into the installer.pp file::

plan puppet_choco_tap::installer(
  TargetSpec $targets,
  String $package,
  Variant[Enum['absent', 'present'], String ] $ensure = 'present',

    include chocolatey

    package { $package :
      ensure    => $ensure,
      provider  => 'chocolatey',

Take note of the following features of the plan:

  • It has three parameters: the list of targets to install the package on, a package string for the package name, and the ensure state of the package which allows for version, absent or present.

  • It has the apply_prep function call, which is used to install modules needed by apply on targets as well as to gather facts about the targets.

  • include chocolatey installs the Chocolatey package manager. The Chocolatey provider is also deployed as a library with the Puppet agent in apply_prep.

  • The package resource ensures a package's state using the Chocolatey provider.

  1. To verify that the puppet_choco_tap::installer plan is available, run the following command inside the bolt_choco_example directory:

bolt plan show

The output should look like:

  1. Run the plan with the bolt plan run command:

bolt plan run puppet_choco_tap::installer package=frogsay --targets=windows

The output looks like this:

Starting: plan puppet_choco_tap::installer
Starting: install puppet and gather facts on,
Finished: install puppet and gather facts with 0 failures in 22.11 sec
Starting: apply catalog on,
Finished: apply catalog with 0 failures in 18.77 sec
Starting: apply catalog on,
Finished: apply catalog with 0 failures in 33.74 sec
Finished: plan puppet_choco_tap::installer in 74.63 sec
  1. To check that the installation worked, run the following frogsay command:

bolt command run 'frogsay ribbit' --targets=windows 

The result will vary on each server, and will look something like this:

Started on
Started on
Finished on
    ( >__< )
    ^^ ~~ ^^
Finished on
    ( >__< )
    ^^ ~~ ^^
Successful on 2 targets:,
Ran on 2 targets in 3.15 seconds

That’s it! In this one plan, you have both installed Chocolatey and deployed the package to two targets. You can do the same thing on any number of targets by editing the inventory file. Note that Chocolatey will remain installed on your machine.

After you have installed your package, with the help of Bolt, you can use Chocolatey to automate all of the package management tasks for upgrades or uninstalls. You can use Puppet Enterprise to guarantee state across all of your nodes and handle configuration drift — and make sure no one accidentally uninstalls the package that you just installed.

See an issue? Please file a JIRA ticket in our [DOCUMENTATION] project
Puppet sites use proprietary and third-party cookies. By using our sites, you agree to our cookie policy.