Base64 encode powershell to avoid any necessary escaping
This commit is contained in:
parent
52c6cd5fc1
commit
17597b48e1
|
@ -101,7 +101,7 @@ func IsPowershellAvailable() (bool, string, error) {
|
|||
if err != nil {
|
||||
return false, "", err
|
||||
} else {
|
||||
return false, path, err
|
||||
return true, path, err
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,3 +15,9 @@ func powershellEncode(buffer []byte) string {
|
|||
input := []uint8(wideCmd)
|
||||
return base64.StdEncoding.EncodeToString(input)
|
||||
}
|
||||
|
||||
func powershellDecode(message string) (retour string) {
|
||||
base64Text := make([]byte, base64.StdEncoding.DecodedLen(len(message)))
|
||||
base64.StdEncoding.Decode(base64Text, []byte(message))
|
||||
return string(base64Text)
|
||||
}
|
||||
|
|
|
@ -107,24 +107,25 @@ func (p *Provisioner) Prepare(raws ...interface{}) error {
|
|||
},
|
||||
},
|
||||
}, raws...)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if p.config.EnvVarFormat == "" {
|
||||
p.config.EnvVarFormat = `$env:%s=\"%s\"; `
|
||||
p.config.EnvVarFormat = `$env:%s="%s"; `
|
||||
}
|
||||
|
||||
if p.config.ElevatedEnvVarFormat == "" {
|
||||
p.config.ElevatedEnvVarFormat = `$env:%s=\"%s\"; `
|
||||
p.config.ElevatedEnvVarFormat = `$env:%s="%s"; `
|
||||
}
|
||||
|
||||
if p.config.ExecuteCommand == "" {
|
||||
p.config.ExecuteCommand = `powershell '& {if (Test-Path variable:global:ProgressPreference){$ProgressPreference=\"SilentlyContinue\"}; {{.Vars}}{{.Path}}; exit $LastExitCode}'`
|
||||
p.config.ExecuteCommand = `{{.Vars}}{{.Path}}`
|
||||
}
|
||||
|
||||
if p.config.ElevatedExecuteCommand == "" {
|
||||
p.config.ElevatedExecuteCommand = `powershell '& {if (Test-Path variable:global:ProgressPreference){$ProgressPreference=\"SilentlyContinue\"}; {{.Vars}}{{.Path}}; exit $LastExitCode}'`
|
||||
p.config.ElevatedExecuteCommand = `{{.Vars}}{{.Path}}'`
|
||||
}
|
||||
|
||||
if p.config.Inline != nil && len(p.config.Inline) == 0 {
|
||||
|
@ -374,28 +375,41 @@ func (p *Provisioner) createFlattenedEnvVars(elevated bool) (flattened string, e
|
|||
}
|
||||
|
||||
func (p *Provisioner) createCommandText() (command string, err error) {
|
||||
// Return the interpolated command
|
||||
if p.config.ElevatedUser == "" {
|
||||
return p.createCommandTextNonPrivileged()
|
||||
} else {
|
||||
return p.createCommandTextPrivileged()
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Provisioner) createCommandTextNonPrivileged() (command string, err error) {
|
||||
// Create environment variables to set before executing the command
|
||||
flattenedEnvVars, err := p.createFlattenedEnvVars(false)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
p.config.ctx.Data = &ExecuteCommandTemplate{
|
||||
Vars: flattenedEnvVars,
|
||||
Path: p.config.RemotePath,
|
||||
}
|
||||
command, err = interpolate.Render(p.config.ExecuteCommand, &p.config.ctx)
|
||||
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("Error processing command: %s", err)
|
||||
}
|
||||
|
||||
// Return the interpolated command
|
||||
if p.config.ElevatedUser == "" {
|
||||
return command, nil
|
||||
}
|
||||
encodedCommand := "powershell -executionpolicy bypass -encodedCommand " + powershellEncode([]byte("if (Test-Path variable:global:ProgressPreference){$ProgressPreference=\"SilentlyContinue\"}; "+command+"; exit $LastExitCode"))
|
||||
|
||||
return encodedCommand, err
|
||||
}
|
||||
|
||||
func (p *Provisioner) createCommandTextPrivileged() (command string, err error) {
|
||||
// Can't double escape the env vars, lets create shiny new ones
|
||||
flattenedEnvVars, err = p.createFlattenedEnvVars(true)
|
||||
flattenedEnvVars, err := p.createFlattenedEnvVars(true)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
p.config.ctx.Data = &ExecuteCommandTemplate{
|
||||
Vars: flattenedEnvVars,
|
||||
Path: p.config.RemotePath,
|
||||
|
@ -412,7 +426,7 @@ func (p *Provisioner) createCommandText() (command string, err error) {
|
|||
// Return the path to the elevated shell wrapper
|
||||
command = fmt.Sprintf("powershell -executionpolicy bypass -file \"%s\"", path)
|
||||
|
||||
return
|
||||
return command, err
|
||||
}
|
||||
|
||||
func (p *Provisioner) generateElevatedRunner(command string) (uploadedPath string, err error) {
|
||||
|
@ -425,7 +439,7 @@ func (p *Provisioner) generateElevatedRunner(command string) (uploadedPath strin
|
|||
Password: p.config.ElevatedPassword,
|
||||
TaskDescription: "Packer elevated task",
|
||||
TaskName: fmt.Sprintf("packer-%s", uuid.TimeOrderedUUID()),
|
||||
EncodedCommand: powershellEncode([]byte("if (Test-Path variable:global:ProgressPreference){$ProgressPreference=\"SilentlyContinue\"}; " + command + "; exit $LASTEXITCODE")),
|
||||
EncodedCommand: powershellEncode([]byte("if (Test-Path variable:global:ProgressPreference){$ProgressPreference=\"SilentlyContinue\"}; " + command + "; exit $LastExitCode")),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
|
|
|
@ -75,12 +75,12 @@ func TestProvisionerPrepare_Defaults(t *testing.T) {
|
|||
t.Error("expected elevated_password to be empty")
|
||||
}
|
||||
|
||||
if p.config.ExecuteCommand != `powershell '& {if (Test-Path variable:global:ProgressPreference){$ProgressPreference=\"SilentlyContinue\"}; {{.Vars}}{{.Path}}; exit $LastExitCode}'` {
|
||||
t.Fatalf("Default command should be powershell '& {if (Test-Path variable:global:ProgressPreference){$ProgressPreference=\"SilentlyContinue\"}; {{.Vars}}{{.Path}}; exit $LastExitCode}', but got %s", p.config.ExecuteCommand)
|
||||
if p.config.ExecuteCommand != `{{.Vars}}{{.Path}}` {
|
||||
t.Fatalf("Default command should be '{{.Vars}}{{.Path}}', but got %s", p.config.ExecuteCommand)
|
||||
}
|
||||
|
||||
if p.config.ElevatedExecuteCommand != `powershell '& {if (Test-Path variable:global:ProgressPreference){$ProgressPreference=\"SilentlyContinue\"}; {{.Vars}}{{.Path}}; exit $LastExitCode}'` {
|
||||
t.Fatalf("Default command should be powershell powershell '& {if (Test-Path variable:global:ProgressPreference){$ProgressPreference=\"SilentlyContinue\"}; {{.Vars}}{{.Path}}; exit $LastExitCode}', but got %s", p.config.ElevatedExecuteCommand)
|
||||
if p.config.ElevatedExecuteCommand != `{{.Vars}}{{.Path}}'` {
|
||||
t.Fatalf("Default command should be '{{.Vars}}{{.Path}}', but got %s", p.config.ElevatedExecuteCommand)
|
||||
}
|
||||
|
||||
if p.config.ValidExitCodes == nil {
|
||||
|
@ -95,8 +95,8 @@ func TestProvisionerPrepare_Defaults(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
if p.config.ElevatedEnvVarFormat != `$env:%s=\"%s\"; ` {
|
||||
t.Fatalf(`Default command should be powershell '$env:%%s=\"%%s\"; ', but got %s`, p.config.ElevatedEnvVarFormat)
|
||||
if p.config.ElevatedEnvVarFormat != `$env:%s="%s"; ` {
|
||||
t.Fatalf(`Default command should be powershell '$env:%%s="%%s"; ', but got %s`, p.config.ElevatedEnvVarFormat)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -389,11 +389,15 @@ func TestProvisionerProvision_Inline(t *testing.T) {
|
|||
t.Fatal("should not have error")
|
||||
}
|
||||
|
||||
expectedCommand := `powershell '& {if (Test-Path variable:global:ProgressPreference){$ProgressPreference=\"SilentlyContinue\"}; $env:PACKER_BUILDER_TYPE=\"iso\"; $env:PACKER_BUILD_NAME=\"vmware\"; c:/Windows/Temp/inlineScript.bat; exit $LastExitCode}'`
|
||||
expectedCommand := `if (Test-Path variable:global:ProgressPreference){$ProgressPreference="SilentlyContinue"}; $env:PACKER_BUILDER_TYPE="iso"; $env:PACKER_BUILD_NAME="vmware"; c:/Windows/Temp/inlineScript.bat; exit $LastExitCode`
|
||||
expectedCommandPrefix := `powershell -executionpolicy bypass -encodedCommand `
|
||||
expectedCommandEncoded := expectedCommandPrefix + powershellEncode([]byte(expectedCommand))
|
||||
|
||||
// Should run the command without alteration
|
||||
if comm.StartCmd.Command != expectedCommand {
|
||||
t.Fatalf("Expect command to be: %s, got %s", expectedCommand, comm.StartCmd.Command)
|
||||
if comm.StartCmd.Command != expectedCommandEncoded {
|
||||
actualCommandWithoutPrefix := strings.Replace(comm.StartCmd.Command, expectedCommandPrefix, "", -1)
|
||||
actualCommandDecoded := powershellDecode(actualCommandWithoutPrefix)
|
||||
t.Fatalf("Expect command to be: %s, got %s. Expected decoded: %s, got %s", expectedCommandEncoded, comm.StartCmd.Command, expectedCommand, actualCommandDecoded)
|
||||
}
|
||||
|
||||
envVars := make([]string, 2)
|
||||
|
@ -408,11 +412,15 @@ func TestProvisionerProvision_Inline(t *testing.T) {
|
|||
t.Fatal("should not have error")
|
||||
}
|
||||
|
||||
expectedCommand = `powershell '& {if (Test-Path variable:global:ProgressPreference){$ProgressPreference=\"SilentlyContinue\"}; $env:BAR=\"BAZ\"; $env:FOO=\"BAR\"; $env:PACKER_BUILDER_TYPE=\"iso\"; $env:PACKER_BUILD_NAME=\"vmware\"; c:/Windows/Temp/inlineScript.bat; exit $LastExitCode}'`
|
||||
expectedCommand = `if (Test-Path variable:global:ProgressPreference){$ProgressPreference="SilentlyContinue"}; $env:BAR="BAZ"; $env:FOO="BAR"; $env:PACKER_BUILDER_TYPE="iso"; $env:PACKER_BUILD_NAME="vmware"; c:/Windows/Temp/inlineScript.bat; exit $LastExitCode`
|
||||
expectedCommandPrefix = `powershell -executionpolicy bypass -encodedCommand `
|
||||
expectedCommandEncoded = expectedCommandPrefix + powershellEncode([]byte(expectedCommand))
|
||||
|
||||
// Should run the command without alteration
|
||||
if comm.StartCmd.Command != expectedCommand {
|
||||
t.Fatalf("Expect command to be: %s, got: %s", expectedCommand, comm.StartCmd.Command)
|
||||
if comm.StartCmd.Command != expectedCommandEncoded {
|
||||
actualCommandWithoutPrefix := strings.Replace(comm.StartCmd.Command, expectedCommandPrefix, "", -1)
|
||||
actualCommandDecoded := powershellDecode(actualCommandWithoutPrefix)
|
||||
t.Fatalf("Expect command to be: %s, got %s. Expected decoded: %s, got %s", expectedCommandEncoded, comm.StartCmd.Command, expectedCommand, actualCommandDecoded)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -434,12 +442,15 @@ func TestProvisionerProvision_Scripts(t *testing.T) {
|
|||
t.Fatal("should not have error")
|
||||
}
|
||||
|
||||
//powershell -Command "$env:PACKER_BUILDER_TYPE=''"; powershell -Command "$env:PACKER_BUILD_NAME='foobuild'"; powershell -Command c:/Windows/Temp/script.ps1
|
||||
expectedCommand := `powershell '& {if (Test-Path variable:global:ProgressPreference){$ProgressPreference=\"SilentlyContinue\"}; $env:PACKER_BUILDER_TYPE=\"footype\"; $env:PACKER_BUILD_NAME=\"foobuild\"; c:/Windows/Temp/script.ps1; exit $LastExitCode}'`
|
||||
expectedCommand := `if (Test-Path variable:global:ProgressPreference){$ProgressPreference="SilentlyContinue"}; $env:PACKER_BUILDER_TYPE="footype"; $env:PACKER_BUILD_NAME="foobuild"; c:/Windows/Temp/script.ps1; exit $LastExitCode`
|
||||
expectedCommandPrefix := `powershell -executionpolicy bypass -encodedCommand `
|
||||
expectedCommandEncoded := expectedCommandPrefix + powershellEncode([]byte(expectedCommand))
|
||||
|
||||
// Should run the command without alteration
|
||||
if comm.StartCmd.Command != expectedCommand {
|
||||
t.Fatalf("Expect command to be %s NOT %s", expectedCommand, comm.StartCmd.Command)
|
||||
if comm.StartCmd.Command != expectedCommandEncoded {
|
||||
actualCommandWithoutPrefix := strings.Replace(comm.StartCmd.Command, expectedCommandPrefix, "", -1)
|
||||
actualCommandDecoded := powershellDecode(actualCommandWithoutPrefix)
|
||||
t.Fatalf("Expect command to be: %s, got %s. Expected decoded: %s, got %s", expectedCommandEncoded, comm.StartCmd.Command, expectedCommand, actualCommandDecoded)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -468,11 +479,15 @@ func TestProvisionerProvision_ScriptsWithEnvVars(t *testing.T) {
|
|||
t.Fatal("should not have error")
|
||||
}
|
||||
|
||||
expectedCommand := `powershell '& {if (Test-Path variable:global:ProgressPreference){$ProgressPreference=\"SilentlyContinue\"}; $env:BAR=\"BAZ\"; $env:FOO=\"BAR\"; $env:PACKER_BUILDER_TYPE=\"footype\"; $env:PACKER_BUILD_NAME=\"foobuild\"; c:/Windows/Temp/script.ps1; exit $LastExitCode}'`
|
||||
expectedCommand := `if (Test-Path variable:global:ProgressPreference){$ProgressPreference="SilentlyContinue"}; $env:BAR="BAZ"; $env:FOO="BAR"; $env:PACKER_BUILDER_TYPE="footype"; $env:PACKER_BUILD_NAME="foobuild"; c:/Windows/Temp/script.ps1; exit $LastExitCode`
|
||||
expectedCommandPrefix := `powershell -executionpolicy bypass -encodedCommand `
|
||||
expectedCommandEncoded := expectedCommandPrefix + powershellEncode([]byte(expectedCommand))
|
||||
|
||||
// Should run the command without alteration
|
||||
if comm.StartCmd.Command != expectedCommand {
|
||||
t.Fatalf("Expect command to be %s NOT %s", expectedCommand, comm.StartCmd.Command)
|
||||
if comm.StartCmd.Command != expectedCommandEncoded {
|
||||
actualCommandWithoutPrefix := strings.Replace(comm.StartCmd.Command, expectedCommandPrefix, "", -1)
|
||||
actualCommandDecoded := powershellDecode(actualCommandWithoutPrefix)
|
||||
t.Fatalf("Expect command to be: %s, got %s. Expected decoded: %s, got %s", expectedCommandEncoded, comm.StartCmd.Command, expectedCommand, actualCommandDecoded)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -500,7 +515,7 @@ func TestProvisioner_createFlattenedElevatedEnvVars_windows(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("should not have error creating flattened env vars: %s", err)
|
||||
}
|
||||
if flattenedEnvVars != `$env:PACKER_BUILDER_TYPE=\"iso\"; $env:PACKER_BUILD_NAME=\"vmware\"; ` {
|
||||
if flattenedEnvVars != `$env:PACKER_BUILDER_TYPE="iso"; $env:PACKER_BUILD_NAME="vmware"; ` {
|
||||
t.Fatalf("unexpected flattened env vars: %s", flattenedEnvVars)
|
||||
}
|
||||
|
||||
|
@ -511,7 +526,7 @@ func TestProvisioner_createFlattenedElevatedEnvVars_windows(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("should not have error creating flattened env vars: %s", err)
|
||||
}
|
||||
if flattenedEnvVars != `$env:FOO=\"bar\"; $env:PACKER_BUILDER_TYPE=\"iso\"; $env:PACKER_BUILD_NAME=\"vmware\"; ` {
|
||||
if flattenedEnvVars != `$env:FOO="bar"; $env:PACKER_BUILDER_TYPE="iso"; $env:PACKER_BUILD_NAME="vmware"; ` {
|
||||
t.Fatalf("unexpected flattened env vars: %s", flattenedEnvVars)
|
||||
}
|
||||
|
||||
|
@ -522,7 +537,7 @@ func TestProvisioner_createFlattenedElevatedEnvVars_windows(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("should not have error creating flattened env vars: %s", err)
|
||||
}
|
||||
if flattenedEnvVars != `$env:BAZ=\"qux\"; $env:FOO=\"bar\"; $env:PACKER_BUILDER_TYPE=\"iso\"; $env:PACKER_BUILD_NAME=\"vmware\"; ` {
|
||||
if flattenedEnvVars != `$env:BAZ="qux"; $env:FOO="bar"; $env:PACKER_BUILDER_TYPE="iso"; $env:PACKER_BUILD_NAME="vmware"; ` {
|
||||
t.Fatalf("unexpected flattened env vars: %s", flattenedEnvVars)
|
||||
}
|
||||
}
|
||||
|
@ -545,7 +560,7 @@ func TestProvisioner_createFlattenedEnvVars_windows(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("should not have error creating flattened env vars: %s", err)
|
||||
}
|
||||
if flattenedEnvVars != `$env:PACKER_BUILDER_TYPE=\"iso\"; $env:PACKER_BUILD_NAME=\"vmware\"; ` {
|
||||
if flattenedEnvVars != `$env:PACKER_BUILDER_TYPE="iso"; $env:PACKER_BUILD_NAME="vmware"; ` {
|
||||
t.Fatalf("unexpected flattened env vars: %s", flattenedEnvVars)
|
||||
}
|
||||
|
||||
|
@ -556,7 +571,7 @@ func TestProvisioner_createFlattenedEnvVars_windows(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("should not have error creating flattened env vars: %s", err)
|
||||
}
|
||||
if flattenedEnvVars != `$env:FOO=\"bar\"; $env:PACKER_BUILDER_TYPE=\"iso\"; $env:PACKER_BUILD_NAME=\"vmware\"; ` {
|
||||
if flattenedEnvVars != `$env:FOO="bar"; $env:PACKER_BUILDER_TYPE="iso"; $env:PACKER_BUILD_NAME="vmware"; ` {
|
||||
t.Fatalf("unexpected flattened env vars: %s", flattenedEnvVars)
|
||||
}
|
||||
|
||||
|
@ -567,7 +582,7 @@ func TestProvisioner_createFlattenedEnvVars_windows(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("should not have error creating flattened env vars: %s", err)
|
||||
}
|
||||
if flattenedEnvVars != `$env:BAZ=\"qux\"; $env:FOO=\"bar\"; $env:PACKER_BUILDER_TYPE=\"iso\"; $env:PACKER_BUILD_NAME=\"vmware\"; ` {
|
||||
if flattenedEnvVars != `$env:BAZ="qux"; $env:FOO="bar"; $env:PACKER_BUILDER_TYPE="iso"; $env:PACKER_BUILD_NAME="vmware"; ` {
|
||||
t.Fatalf("unexpected flattened env vars: %s", flattenedEnvVars)
|
||||
}
|
||||
}
|
||||
|
@ -582,8 +597,16 @@ func TestProvision_createCommandText(t *testing.T) {
|
|||
|
||||
// Non-elevated
|
||||
cmd, _ := p.createCommandText()
|
||||
if cmd != `powershell '& {if (Test-Path variable:global:ProgressPreference){$ProgressPreference=\"SilentlyContinue\"}; $env:PACKER_BUILDER_TYPE=\"\"; $env:PACKER_BUILD_NAME=\"\"; c:/Windows/Temp/script.ps1; exit $LastExitCode}'` {
|
||||
t.Fatalf("Got unexpected non-elevated command: %s", cmd)
|
||||
|
||||
expectedCommand := `if (Test-Path variable:global:ProgressPreference){$ProgressPreference="SilentlyContinue"}; $env:PACKER_BUILDER_TYPE=""; $env:PACKER_BUILD_NAME=""; c:/Windows/Temp/script.ps1; exit $LastExitCode`
|
||||
expectedCommandPrefix := `powershell -executionpolicy bypass -encodedCommand `
|
||||
expectedCommandEncoded := expectedCommandPrefix + powershellEncode([]byte(expectedCommand))
|
||||
|
||||
// Should run the command without alteration
|
||||
if cmd != expectedCommandEncoded {
|
||||
actualCommandWithoutPrefix := strings.Replace(comm.StartCmd.Command, expectedCommandPrefix, "", -1)
|
||||
actualCommandDecoded := powershellDecode(actualCommandWithoutPrefix)
|
||||
t.Fatalf("Expect command to be: %s, got %s. Expected decoded: %s, got %s", expectedCommandEncoded, comm.StartCmd.Command, expectedCommand, actualCommandDecoded)
|
||||
}
|
||||
|
||||
// Elevated
|
||||
|
|
Loading…
Reference in New Issue