add execution policy type and use it to default the powershell cmd

This commit is contained in:
Adrien Delorme 2019-05-23 14:10:41 +02:00
parent 2da36b7374
commit e96409954a
5 changed files with 142 additions and 7 deletions

View File

@ -23,6 +23,14 @@ type DecodeOpts struct {
Interpolate bool Interpolate bool
InterpolateContext *interpolate.Context InterpolateContext *interpolate.Context
InterpolateFilter *interpolate.RenderFilter InterpolateFilter *interpolate.RenderFilter
DecodeHooks []mapstructure.DecodeHookFunc
}
var DefaultDecodeHookFuncs = []mapstructure.DecodeHookFunc{
uint8ToStringHook,
mapstructure.StringToSliceHookFunc(","),
mapstructure.StringToTimeDurationHookFunc(),
} }
// Decode decodes the configuration into the target and optionally // Decode decodes the configuration into the target and optionally
@ -60,17 +68,18 @@ func Decode(target interface{}, config *DecodeOpts, raws ...interface{}) error {
} }
} }
decodeHookFuncs := DefaultDecodeHookFuncs
if len(config.DecodeHooks) != 0 {
decodeHookFuncs = config.DecodeHooks
}
// Build our decoder // Build our decoder
var md mapstructure.Metadata var md mapstructure.Metadata
decoder, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{ decoder, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
Result: target, Result: target,
Metadata: &md, Metadata: &md,
WeaklyTypedInput: true, WeaklyTypedInput: true,
DecodeHook: mapstructure.ComposeDecodeHookFunc( DecodeHook: mapstructure.ComposeDecodeHookFunc(decodeHookFuncs...),
uint8ToStringHook,
mapstructure.StringToSliceHookFunc(","),
mapstructure.StringToTimeDurationHookFunc(),
),
}) })
if err != nil { if err != nil {
return err return err

View File

@ -0,0 +1,38 @@
package powershell
import (
"fmt"
"reflect"
)
// ExecutionPolicy setting to run the command(s).
// For the powershell provider the default has historically been to bypass.
type ExecutionPolicy int
const (
Bypass ExecutionPolicy = 0
AllSigned ExecutionPolicy = 1
Default ExecutionPolicy = 2
RemoteSigned ExecutionPolicy = 3
Restricted ExecutionPolicy = 4
Undefined ExecutionPolicy = 5
Unrestricted ExecutionPolicy = 6
)
func (ep *ExecutionPolicy) Decode(v interface{}) (err error) {
str, ok := v.(string)
if !ok {
return fmt.Errorf("%#v is not a string", v)
}
*ep, err = ExecutionPolicyString(str)
return err
}
func StringToExecutionPolicyHook(f reflect.Kind, t reflect.Kind, data interface{}) (interface{}, error) {
if f != reflect.String || t != reflect.Int {
return data, nil
}
raw := data.(string)
return ExecutionPolicyString(raw)
}

View File

@ -0,0 +1,21 @@
package powershell
import (
"testing"
)
func TestExecutionPolicy_Decode(t *testing.T) {
config := map[string]interface{}{
"inline": []interface{}{"foo", "bar"},
"execution_policy": "AllSigned",
}
p := new(Provisioner)
err := p.Prepare(config)
if err != nil {
t.Fatal(err)
}
if p.config.ExecutionPolicy != AllSigned {
t.Fatalf("Expected AllSigned execution policy; got: %s", p.config.ExecutionPolicy)
}
}

View File

@ -0,0 +1,55 @@
// Code generated by "enumer -type ExecutionPolicy provisioner/powershell/execution_policy.go"; DO NOT EDIT.
//
package powershell
import (
"fmt"
)
const _ExecutionPolicyName = "BypassAllSignedDefaultRemoteSignedRestrictedUndefinedUnrestricted"
var _ExecutionPolicyIndex = [...]uint8{0, 6, 15, 22, 34, 44, 53, 65}
func (i ExecutionPolicy) String() string {
if i < 0 || i >= ExecutionPolicy(len(_ExecutionPolicyIndex)-1) {
return fmt.Sprintf("ExecutionPolicy(%d)", i)
}
return _ExecutionPolicyName[_ExecutionPolicyIndex[i]:_ExecutionPolicyIndex[i+1]]
}
var _ExecutionPolicyValues = []ExecutionPolicy{0, 1, 2, 3, 4, 5, 6}
var _ExecutionPolicyNameToValueMap = map[string]ExecutionPolicy{
_ExecutionPolicyName[0:6]: 0,
_ExecutionPolicyName[6:15]: 1,
_ExecutionPolicyName[15:22]: 2,
_ExecutionPolicyName[22:34]: 3,
_ExecutionPolicyName[34:44]: 4,
_ExecutionPolicyName[44:53]: 5,
_ExecutionPolicyName[53:65]: 6,
}
// ExecutionPolicyString retrieves an enum value from the enum constants string name.
// Throws an error if the param is not part of the enum.
func ExecutionPolicyString(s string) (ExecutionPolicy, error) {
if val, ok := _ExecutionPolicyNameToValueMap[s]; ok {
return val, nil
}
return 0, fmt.Errorf("%s does not belong to ExecutionPolicy values", s)
}
// ExecutionPolicyValues returns all values of the enum
func ExecutionPolicyValues() []ExecutionPolicy {
return _ExecutionPolicyValues
}
// IsAExecutionPolicy returns "true" if the value is listed in the enum definition. "false" otherwise
func (i ExecutionPolicy) IsAExecutionPolicy() bool {
for _, v := range _ExecutionPolicyValues {
if i == v {
return true
}
}
return false
}

View File

@ -66,6 +66,8 @@ type Config struct {
ElevatedUser string `mapstructure:"elevated_user"` ElevatedUser string `mapstructure:"elevated_user"`
ElevatedPassword string `mapstructure:"elevated_password"` ElevatedPassword string `mapstructure:"elevated_password"`
ExecutionPolicy ExecutionPolicy `mapstructure:"execution_policy"`
ctx interpolate.Context ctx interpolate.Context
} }
@ -84,6 +86,13 @@ type EnvVarsTemplate struct {
WinRMPassword string WinRMPassword string
} }
func (p *Provisioner) defaultExecuteCommand() string {
return `powershell -executionpolicy ` + p.config.ExecutionPolicy.String() +
` "& { if (Test-Path variable:global:ProgressPreference)` +
`{set-variable -name variable:global:ProgressPreference -value 'SilentlyContinue'};` +
`. {{.Vars}}; &'{{.Path}}'; exit $LastExitCode }"`
}
func (p *Provisioner) Prepare(raws ...interface{}) error { func (p *Provisioner) Prepare(raws ...interface{}) error {
// Create passthrough for winrm password so we can fill it in once we know // Create passthrough for winrm password so we can fill it in once we know
// it // it
@ -100,6 +109,7 @@ func (p *Provisioner) Prepare(raws ...interface{}) error {
"elevated_execute_command", "elevated_execute_command",
}, },
}, },
DecodeHooks: append(config.DefaultDecodeHookFuncs, StringToExecutionPolicyHook),
}, raws...) }, raws...)
if err != nil { if err != nil {
@ -115,11 +125,11 @@ func (p *Provisioner) Prepare(raws ...interface{}) error {
} }
if p.config.ExecuteCommand == "" { if p.config.ExecuteCommand == "" {
p.config.ExecuteCommand = `powershell -executionpolicy bypass "& { if (Test-Path variable:global:ProgressPreference){set-variable -name variable:global:ProgressPreference -value 'SilentlyContinue'};. {{.Vars}}; &'{{.Path}}'; exit $LastExitCode }"` p.config.ExecuteCommand = p.defaultExecuteCommand()
} }
if p.config.ElevatedExecuteCommand == "" { if p.config.ElevatedExecuteCommand == "" {
p.config.ElevatedExecuteCommand = `powershell -executionpolicy bypass "& { if (Test-Path variable:global:ProgressPreference){set-variable -name variable:global:ProgressPreference -value 'SilentlyContinue'};. {{.Vars}}; &'{{.Path}}'; exit $LastExitCode }"` p.config.ElevatedExecuteCommand = p.defaultExecuteCommand()
} }
if p.config.Inline != nil && len(p.config.Inline) == 0 { if p.config.Inline != nil && len(p.config.Inline) == 0 {
@ -272,6 +282,8 @@ func (p *Provisioner) Provision(ctx context.Context, ui packer.Ui, comm packer.C
// Close the original file since we copied it // Close the original file since we copied it
f.Close() f.Close()
log.Printf("%s returned with exit code %d", p.config.RemotePath, cmd.ExitStatus())
if err := p.config.ValidExitCode(cmd.ExitStatus()); err != nil { if err := p.config.ValidExitCode(cmd.ExitStatus()); err != nil {
return err return err
} }