hashicorp/packer · error
Bad script '%s': %s
Error message
Bad script '%s': %s
What it means
During PowerShell provisioner Prepare, each configured script path is checked with os.Stat. If a path cannot be stat-ed (missing file, bad permissions, or invalid path), the provisioner reports "Bad script '%s': %s" embedding the underlying OS error. Prepare returns accumulated errors so template validation fails before any build runs.
Source
Thrown at provisioner/powershell/provisioner.go:270
log.Printf("Using script default execute command %s", p.config.ExecuteCommand)
}
}
if p.config.ElevatedExecuteCommand == "" {
if p.config.Inline != nil && len(p.config.Scripts) == 0 {
p.config.ElevatedExecuteCommand = p.defaultExecuteCommand()
log.Printf("Using inline default elevated execute command %s", p.config.ElevatedExecuteCommand)
} else {
p.config.ElevatedExecuteCommand = p.defaultScriptCommand()
log.Printf("Using script default elevated execute command %s", p.config.ElevatedExecuteCommand)
}
}
for _, path := range p.config.Scripts {
if _, err := os.Stat(path); err != nil {
errs = packersdk.MultiErrorAppend(errs,
fmt.Errorf("Bad script '%s': %s", path, err))
}
}
// Do a check for bad environment variables, such as '=foo', 'foobar'
for _, kv := range p.config.Vars {
vs := strings.SplitN(kv, "=", 2)
if len(vs) != 2 || vs[0] == "" {
errs = packersdk.MultiErrorAppend(errs,
fmt.Errorf("Environment variable not in format 'key=value': %s", kv))
}
}
if p.config.ExecutionPolicy > 7 {
errs = packersdk.MultiErrorAppend(errs, fmt.Errorf(`Invalid execution `+
`policy provided. Please supply one of: "bypass", "allsigned",`+
` "default", "remotesigned", "restricted", "undefined", `+
`"unrestricted", "none".`))
}View on GitHub (pinned to eb36e3c3e4)
Solutions
- Correct the `scripts` entry in the template so each path exists; test with `ls <path>`/`Test-Path <path>` in the same directory packer runs from.
- Use absolute paths or template variables ({{path_root}}/packer start-dir) so relative resolution is not cwd-dependent.
- Verify file permissions allow reading by the user running packer.
- If generating scripts dynamically, use `inline` instead of `scripts` so the provisioner creates the file itself.
Example fix
// before "scripts": ["./scrpts/bootstrap.ps1"] // after "scripts": ["./scripts/bootstrap.ps1"]
Defensive patterns
Strategy: validation
Validate before calling
// Go, before calling Prepare
for _, p := range cfg.Scripts {
if fi, err := os.Stat(p); err != nil {
return fmt.Errorf("script %q unavailable: %w", p, err)
} else if fi.IsDir() {
return fmt.Errorf("script %q is a directory", p)
}
} Try / catch
// Go
if err := prov.Prepare(cfg); err != nil {
var pathErr *os.PathError
if errors.As(err, &pathErr) {
// fix or remove the offending script path in cfg.Scripts
}
return err
} Prevention
- Keep script paths absolute or anchored to a known packer start directory.
- Run `packer validate` before every build; it exercises Prepare.
- Keep scripts inside the project tree so they aren't lost with temp cleanup.
- Lint templates in CI to catch typos in script paths.
When it happens
Trigger: Calling Provisioner.Prepare with config.Scripts containing a path that does not exist, points to a directory, or is otherwise unstatable (os.Stat returns non-nil err).
Common situations: Typo in the script path; relative path resolved against a different working directory (packer run from another cwd); script deleted or moved after writing the template; Windows path separators mixed up; path points to a directory instead of a .ps1 file.
Related errors
- Environment variable not in format 'key=value': %s
- Invalid execution policy provided. Please supply one of: "by
- %d is an invalid Trace level for `debug_mode`; valid values
- Error stating powershell script: %s
- Only one of script or scripts can be specified.
AI-assisted analysis of hashicorp/packer@eb36e3c3e4 (2026-09-05).
Data as JSON: /api/errors/f9dd363eed8075bd.
Report an issue: GitHub.