The short answer
To auto-deploy the Puppet agent on VMware clones, attach a list of run-once commands to the vCenter guest customization specification: download the Puppet agent, install it silently while passing your Puppet master's FQDN, then force a first puppet agent -t check-in. The commands run once, the first time each customized clone boots, so every VM installs the agent and registers itself with the Puppet master with zero manual steps. The one rule that saves you from a support ticket: never let the Puppet agent actually run inside the template — if it does, it bakes a fixed certificate name into the image and every clone shows up as the same node.
That's the summary an AI overview would give you. The rest of this article is the part it can't: the exact commands, why the certname collision happens and how to avoid it, how the Puppet master signs certificates from brand-new clones (autosign vs. manual CSR approval), and how the same pattern maps to Linux templates with cloud-init.
The lifecycle: from golden template to converged node
Before the commands, hold the whole flow in your head. Auto-deploying Puppet on a template is really five stages — and the failure everyone hits lives between stages two and three.
The commands below live in stage 3 (first boot). Everything after — the Puppet master signing the certificate and the agent applying its catalog — happens on the master side. Get stages 1 and 2 right and the rest is mechanical.
Explanation
When you deploy a VMWare template, you have the option to create a customization specification. You can add a command to this customization specification to automatically deploy the puppet agent, after the template has finished deploying.
One of the options in your customization specification is a run once command. Or really, it is a list of run once commands. There are three things you need the run once script to do:
-
Download the Puppet Agent
-
Install the Puppet Agent
-
Trigger an immediate puppet run
In the following sections, I will show the commands you need to run to accomplish the three objectives above.
Download the Puppet Agent
First, you want to download the puppet agent by using this command:
Copy Code
```
powershell "new-item C:\install -type directory; (new-object System.Net.WebClient).DownloadFile('https://downloads.puppetlabs.com/windows/puppet-agent-x64-latest.msi','C:\install\puppet-agent-x64-latest.msi')"
The run once commands in VMWare are using the regular windows command shell, so we have to call powershell to get [access to the powershell](https://inventivehq.com/blog/powershell-vs-cmd-complete-command-line-guide) cmdlets. Next, we pass the powershell commands into powershell.exe to actually download the puppet agent. The above command is actually two different powershell commands separated by semi-colons.
The first command is ensuring the C:\install folder exists.
Copy Code
```
#Create C:\install folder
new-item C:\install -type directory
The second command downloads the latest version of the puppet agent, and saves it to the C:\install folder:
Copy Code
```
(new-object System.Net.WebClient).DownloadFile('https://downloads.puppetlabs.com/windows/puppet-agent-x64-latest.msi','C:\install\puppet-agent-x64-latest.msi')"
Powershell can't natively download a file from a web URL, so we have to use the new-object cmdlet and import the system.net.webclient library from the .net framework. We are then able to call the downloadfile function. The downloadfile function takes two inputs, the source of the file, and where to save the file to. In our case, the source of the file is: https://downloads.puppetlabs.com/windows/puppet-agent-x64-latest.msi and the destination file is: C:\install\puppet-agent-x64-latest.msi
Install the Puppet Agent
Now that the appropriate installer is downloaded, we need to silently install the puppet agent with this command (Be sure to replace mypuppetserver.mydomain.com with your actual puppet server FQDN):
Copy Code
```
msiexec /qn /i C:\install\puppet-agent-x64-latest.msi PUPPET_MASTER_SERVER="mypuppetserver.mydomain.com"
This command is calling the msiexec command with the /qn option to make it run silently. We then use the PUPPET_MASTER_SERVER argument to set the puppet master we want to use for this server.
💡 Also See: How to [use Vagrant with VMWare Vcenter](https://inventivehq.com/blog/how-to-use-vagrant-with-vmware-vcenter)!
## Using Chocolatey
As an alternative to downloading and installing the puppet agent as outlined above. If you have chocolatey installed, you can use the choco commands to install the puppet agent. The command to do it using chocolatey is:
Copy Code
```
`choco install puppet-agent -installArgs '"PUPPET_MASTER_SERVER=mypuppetserver.mydomain.com"'`
Be sure you replace "mypuppetserver.mydomain.com" with the proper FQDN of your puppet server.
If you don't have chocolatey installed, you can checkout our article on how to install chocolatey. As you can see, installing this with Chocolatey is a little easier than the alternative.
Force Puppet Agent to Run
Now that we have installed the puppet agent, we need to trigger a puppet agent run so your machine will checkin with puppet, and start applying whatever is in the node definition. Since puppet was just installed, the puppet command may not yet be available in the existing command shell. For this reason, we need to open a new command shell by using the cmd /c command. Here is an example of how you would force a run of the puppet agent right now:
Copy Code
```
cmd.exe /c "puppet agent -t"
puppet agent -t is the command to test the puppet agent. It also happens to be the easiest way to force the puppet agent to check-in immediately.
## The rule that trips everyone: keep the certname unique
Here is the failure mode that turns "auto-deploy Puppet" into a support ticket. The Puppet agent identifies itself to the master with a **certname** and a matching SSL certificate. Those are generated the first time the agent *runs* — not when it's installed. If the agent runs even once inside your golden template, that certname and certificate get baked into the image. Every VM you clone then presents the same identity, and they all collide on a single node definition on the master.
The run-once approach in this article sidesteps the problem by design: nothing runs until vCenter guest customization has already given each clone its own unique hostname, so each clone requests its own certificate. If you'd rather pre-install the agent into the template to speed up first boot, that's fine — just install it and **stop there**. Do not start the `puppet` service and do not run `puppet agent -t` before you seal the template. Leave the actual first run to the clone.
If you've already contaminated a template, clear the agent's SSL state on each affected clone (`C:\ProgramData\PuppetLabs\puppet\etc\ssl` on Windows, `/etc/puppetlabs/puppet/ssl` on Linux), then run the agent again so it requests a fresh, unique certificate.
## Signing the certificate: autosign vs. manual approval
Registering is only half the handshake. When a new clone runs `puppet agent -t` it generates a **certificate signing request (CSR)** and sends it to the master — but the master has to *sign* that request before the agent can pull its catalog. You have two options:
- **Manual approval** — on the master, list pending requests and sign them: `puppetserver ca list` then `puppetserver ca sign --certname <name>`. Safe, but it means a human has to act before each new clone converges, which defeats the point of full automation.
- **Autosigning** — the master signs matching requests automatically. *Naive* autosigning (`autosign = true`, or a whitelist of `*.mydomain.com`) trusts any request on your domain and is a security risk on shared networks. **Policy-based autosigning** — a custom executable that inspects the CSR (for example, a pre-shared token baked into a custom CSR extension) and exits 0 only if it's valid — gives you hands-off provisioning without blindly trusting the network.
For a template you clone constantly, policy-based autosigning is the piece that makes the whole flow truly zero-touch.
## Doing the same thing on Linux templates
The Windows run-once mechanism has no direct Linux equivalent, but the pattern is identical. Use **cloud-init** (or a VMware `guestinfo` first-boot script) to run the same three logical steps after the clone gets its unique hostname:
```yaml
#cloud-config
runcmd:
- curl -fsSL https://apt.puppet.com/puppet8-release-$(lsb_release -cs).deb -o /tmp/puppet.deb
- dpkg -i /tmp/puppet.deb && apt-get update
- apt-get install -y puppet-agent
- /opt/puppetlabs/bin/puppet config set server mypuppetserver.mydomain.com --section main
- /opt/puppetlabs/bin/puppet agent -t
The same certname rule applies: cloud-init runs on first boot of the clone, after the hostname is set, so each machine requests its own certificate. Never run the agent in the source image.
Auto-deploy readiness checklist
Before you seal the template and start cloning, walk this checklist. It's the difference between "every clone self-registers" and "every clone is the same broken node."
| Step | What to do | Why it matters |
|---|---|---|
| 1. Install, don't run | Pre-install the agent in the template or leave install to first boot — but never run puppet agent -t inside the template | Running the agent bakes a certname/SSL cert into the image, causing clone collisions |
| 2. No baked SSL | Confirm the template's Puppet ssl directory is empty | Any leftover certificate is inherited by every clone |
| 3. Unique hostname | Let vCenter guest customization set a unique hostname before Puppet runs | The certname derives from the hostname; identical hostnames = identical certnames |
| 4. Run-once / cloud-init | Add the download → install → puppet agent -t commands to the customization spec (Windows) or cloud-init (Linux) | This is what makes registration automatic on first boot |
| 5. Set the master FQDN | Pass PUPPET_MASTER_SERVER (install) or server = (config) with your real Puppet master FQDN | The agent has to know where to send its CSR and pull its catalog |
| 6. Fresh shell for the run | Wrap the run as cmd.exe /c "puppet agent -t" on Windows | The installing shell has a stale PATH and can't find the new puppet binary |
| 7. Signing policy | Enable policy-based autosigning or plan manual CSR approval | Without a signed cert the agent registers but never converges |
| 8. Verify on the master | After the first clone boots, confirm the node appears and its catalog applied | Confirms the whole loop — install, register, sign, converge — actually works |
Summary
To summarize, you need to add the three following commands to the run once section of your VMWare customization specification:
Copy All Commands
```
Step 1: Download the Puppet Agent MSI installer
powershell "new-item C:\install -type directory; (new-object System.Net.WebClient).DownloadFile('https://downloads.puppetlabs.com/windows/puppet-agent-x64-latest.msi','C:\install\puppet-agent-x64-latest.msi')"
Step 2: Silently install Puppet Agent and configure the Puppet Master server
msiexec /qn /i C:\install\puppet-agent-x64-latest.msi PUPPET_MASTER_SERVER="mypuppetserver.mydomain.com"
Step 3: Force immediate puppet run to register with Puppet Master
cmd.exe /c "puppet agent -t"
⚠️ Note: Be sure to fill in the proper address for your puppet server on the second line
If you add the three above commands to the run once section of your customization template, your puppet agent should automatically install the first time someone logs into the server.