From 2a060adbf80ab454cb4c322ae5754228b56e67de Mon Sep 17 00:00:00 2001 From: DanHam Date: Fri, 27 Jan 2017 01:32:33 +0000 Subject: [PATCH 1/4] Don't use -EncodedCommand with PS as progress stream always leaks to stderr * Setting $ProgressPreference to SilentlyContinue makes no difference when -EncodedCommand is used - any output to the progress stream still appears on stderr. * Delete file containing encode/decode functions since we no longer need them. * Fixes leak of output on progress streams for both normal and elevated commands. * Since we no longer base64 encode, ensure any characters special to XML are correctly escaped in the elevated command. This ensures correct parsing once the command is wrapped within the elevatedTemplates XML based Task Scheduler definition. Fixes #4322 --- provisioner/powershell/elevated.go | 12 +++--- provisioner/powershell/powershell.go | 54 --------------------------- provisioner/powershell/provisioner.go | 50 ++++++++++--------------- 3 files changed, 26 insertions(+), 90 deletions(-) delete mode 100644 provisioner/powershell/powershell.go diff --git a/provisioner/powershell/elevated.go b/provisioner/powershell/elevated.go index d2c23f757..f8adb6cd1 100644 --- a/provisioner/powershell/elevated.go +++ b/provisioner/powershell/elevated.go @@ -5,11 +5,11 @@ import ( ) type elevatedOptions struct { - User string - Password string - TaskName string - TaskDescription string - EncodedCommand string + User string + Password string + TaskName string + TaskDescription string + XMLEscapedCommand string } var elevatedTemplate = template.Must(template.New("ElevatedCommand").Parse(` @@ -53,7 +53,7 @@ $t.XmlText = @' cmd - /c powershell.exe -EncodedCommand {{.EncodedCommand}} > %SYSTEMROOT%\Temp\{{.TaskName}}.out 2>&1 + /c {{.XMLEscapedCommand}} > %SYSTEMROOT%\Temp\{{.TaskName}}.out 2>&1 diff --git a/provisioner/powershell/powershell.go b/provisioner/powershell/powershell.go deleted file mode 100644 index 086e3e554..000000000 --- a/provisioner/powershell/powershell.go +++ /dev/null @@ -1,54 +0,0 @@ -package powershell - -import ( - "encoding/base64" - "encoding/binary" - "unicode/utf16" - "unicode/utf8" - - "golang.org/x/text/encoding/unicode" -) - -func convertUtf8ToUtf16LE(message string) (string, error) { - utf16le := unicode.UTF16(unicode.LittleEndian, unicode.IgnoreBOM) - utfEncoder := utf16le.NewEncoder() - ut16LeEncodedMessage, err := utfEncoder.String(message) - - return ut16LeEncodedMessage, err -} - -// UTF16BytesToString converts UTF-16 encoded bytes, in big or little endian byte order, -// to a UTF-8 encoded string. -func UTF16BytesToString(b []byte, o binary.ByteOrder) string { - utf := make([]uint16, (len(b)+(2-1))/2) - for i := 0; i+(2-1) < len(b); i += 2 { - utf[i/2] = o.Uint16(b[i:]) - } - if len(b)/2 < len(utf) { - utf[len(utf)-1] = utf8.RuneError - } - return string(utf16.Decode(utf)) -} - -func powershellEncode(message string) (string, error) { - utf16LEEncodedMessage, err := convertUtf8ToUtf16LE(message) - if err != nil { - return "", err - } - - // Base64 encode the command - input := []uint8(utf16LEEncodedMessage) - return base64.StdEncoding.EncodeToString(input), nil -} - -func powershellDecode(messageBase64 string) (retour string, err error) { - messageUtf16LeByteArray, err := base64.StdEncoding.DecodeString(messageBase64) - - if err != nil { - return "", err - } - - message := UTF16BytesToString(messageUtf16LeByteArray, binary.LittleEndian) - - return message, nil -} diff --git a/provisioner/powershell/provisioner.go b/provisioner/powershell/provisioner.go index fd967ce86..1481d6ddc 100644 --- a/provisioner/powershell/provisioner.go +++ b/provisioner/powershell/provisioner.go @@ -5,6 +5,7 @@ package powershell import ( "bufio" "bytes" + "encoding/xml" "errors" "fmt" "io/ioutil" @@ -112,7 +113,7 @@ func (p *Provisioner) Prepare(raws ...interface{}) error { } if p.config.EnvVarFormat == "" { - p.config.EnvVarFormat = `$env:%s="%s"; ` + p.config.EnvVarFormat = `$env:%s=\"%s\"; ` } if p.config.ElevatedEnvVarFormat == "" { @@ -120,11 +121,11 @@ func (p *Provisioner) Prepare(raws ...interface{}) error { } if p.config.ExecuteCommand == "" { - p.config.ExecuteCommand = `if (Test-Path variable:global:ProgressPreference){$ProgressPreference='SilentlyContinue'};{{.Vars}}&'{{.Path}}';exit $LastExitCode` + p.config.ExecuteCommand = `powershell -executionpolicy bypass "& { if (Test-Path variable:global:ProgressPreference){$ProgressPreference='SilentlyContinue'};{{.Vars}}&'{{.Path}}';exit $LastExitCode }"` } if p.config.ElevatedExecuteCommand == "" { - p.config.ElevatedExecuteCommand = `if (Test-Path variable:global:ProgressPreference){$ProgressPreference='SilentlyContinue'}; . {{.Vars}}; &'{{.Path}}'; exit $LastExitCode` + p.config.ElevatedExecuteCommand = `powershell -executionpolicy bypass "& { if (Test-Path variable:global:ProgressPreference){$ProgressPreference='SilentlyContinue'};. {{.Vars}}; &'{{.Path}}'; exit $LastExitCode }"` } if p.config.Inline != nil && len(p.config.Inline) == 0 { @@ -389,25 +390,8 @@ func (p *Provisioner) createCommandTextNonPrivileged() (command string, err erro return "", fmt.Errorf("Error processing command: %s", err) } - commandText, err := p.generateCommandLineRunner(command) - if err != nil { - return "", fmt.Errorf("Error generating command line runner: %s", err) - } - - return commandText, err -} - -func (p *Provisioner) generateCommandLineRunner(command string) (commandText string, err error) { - log.Printf("Building command line for: %s", command) - - base64EncodedCommand, err := powershellEncode(command) - if err != nil { - return "", fmt.Errorf("Error encoding command: %s", err) - } - - commandText = "powershell -executionpolicy bypass -encodedCommand " + base64EncodedCommand - - return commandText, nil + // Return the interpolated command + return command, nil } func (p *Provisioner) createCommandTextPrivileged() (command string, err error) { @@ -449,20 +433,26 @@ func (p *Provisioner) createCommandTextPrivileged() (command string, err error) func (p *Provisioner) generateElevatedRunner(command string) (uploadedPath string, err error) { log.Printf("Building elevated command wrapper for: %s", command) - // generate command var buffer bytes.Buffer - base64EncodedCommand, err := powershellEncode(command) + // elevatedTemplate wraps the command in a single quoted XML text + // string so we need to escape characters considered 'special' in XML. + err = xml.EscapeText(&buffer, []byte(command)) if err != nil { - return "", fmt.Errorf("Error encoding command: %s", err) + return "", fmt.Errorf("Error escaping characters special to XML in command %s: %s", command, err) } + escapedCommand := buffer.String() + log.Printf("Command [%s] converted to [%s] for use in XML string", command, escapedCommand) + + buffer.Reset() + // Generate command err = elevatedTemplate.Execute(&buffer, elevatedOptions{ - User: p.config.ElevatedUser, - Password: p.config.ElevatedPassword, - TaskDescription: "Packer elevated task", - TaskName: fmt.Sprintf("packer-%s", uuid.TimeOrderedUUID()), - EncodedCommand: base64EncodedCommand, + User: p.config.ElevatedUser, + Password: p.config.ElevatedPassword, + TaskDescription: "Packer elevated task", + TaskName: fmt.Sprintf("packer-%s", uuid.TimeOrderedUUID()), + XMLEscapedCommand: escapedCommand, }) if err != nil { From 8214a12a2a3b48a07d3448b75343741fe48d0369 Mon Sep 17 00:00:00 2001 From: DanHam Date: Sun, 9 Jul 2017 20:38:27 +0100 Subject: [PATCH 2/4] Move append of portion of command used to send elevated PS output to file --- provisioner/powershell/elevated.go | 5 +++-- provisioner/powershell/provisioner.go | 18 +++++++++++++++++- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/provisioner/powershell/elevated.go b/provisioner/powershell/elevated.go index f8adb6cd1..6e0faa3d6 100644 --- a/provisioner/powershell/elevated.go +++ b/provisioner/powershell/elevated.go @@ -9,12 +9,13 @@ type elevatedOptions struct { Password string TaskName string TaskDescription string + LogFile string XMLEscapedCommand string } var elevatedTemplate = template.Must(template.New("ElevatedCommand").Parse(` $name = "{{.TaskName}}" -$log = "$env:SystemRoot\Temp\$name.out" +$log = [System.Environment]::ExpandEnvironmentVariables("{{.LogFile}}") $s = New-Object -ComObject "Schedule.Service" $s.Connect() $t = $s.NewTask($null) @@ -53,7 +54,7 @@ $t.XmlText = @' cmd - /c {{.XMLEscapedCommand}} > %SYSTEMROOT%\Temp\{{.TaskName}}.out 2>&1 + /c {{.XMLEscapedCommand}} diff --git a/provisioner/powershell/provisioner.go b/provisioner/powershell/provisioner.go index 1481d6ddc..4297acf08 100644 --- a/provisioner/powershell/provisioner.go +++ b/provisioner/powershell/provisioner.go @@ -435,6 +435,21 @@ func (p *Provisioner) generateElevatedRunner(command string) (uploadedPath strin var buffer bytes.Buffer + // Output from the elevated command cannot be returned directly to + // the Packer console. In order to be able to view output from elevated + // commands and scripts an indirect approach is used by which the + // commands output is first redirected to file. The output file is then + // 'watched' by Packer while the elevated command is running and any + // content appearing in the file is written out to the console. + // Below the portion of command required to redirect output from the + // command to file is built and appended to the existing command string + taskName := fmt.Sprintf("packer-%s", uuid.TimeOrderedUUID()) + // Only use %ENVVAR% format for environment variables when setting + // the log file path; Do NOT use $env:ENVVAR format as it won't be + // expanded correctly in the elevatedTemplate + logFile := `%SYSTEMROOT%\Temp\` + taskName + ".out" + command += fmt.Sprintf(" > %s 2>&1", logFile) + // elevatedTemplate wraps the command in a single quoted XML text // string so we need to escape characters considered 'special' in XML. err = xml.EscapeText(&buffer, []byte(command)) @@ -450,8 +465,9 @@ func (p *Provisioner) generateElevatedRunner(command string) (uploadedPath strin err = elevatedTemplate.Execute(&buffer, elevatedOptions{ User: p.config.ElevatedUser, Password: p.config.ElevatedPassword, + TaskName: taskName, TaskDescription: "Packer elevated task", - TaskName: fmt.Sprintf("packer-%s", uuid.TimeOrderedUUID()), + LogFile: logFile, XMLEscapedCommand: escapedCommand, }) From fa5fd602aa8a2c8367b8b8b97cf6f29b8430a11e Mon Sep 17 00:00:00 2001 From: DanHam Date: Wed, 20 Sep 2017 15:41:27 +0100 Subject: [PATCH 3/4] Fix tests post changes --- provisioner/powershell/provisioner_test.go | 122 +++++---------------- 1 file changed, 28 insertions(+), 94 deletions(-) diff --git a/provisioner/powershell/provisioner_test.go b/provisioner/powershell/provisioner_test.go index 3b3d8fa46..e7e64d52e 100644 --- a/provisioner/powershell/provisioner_test.go +++ b/provisioner/powershell/provisioner_test.go @@ -79,12 +79,12 @@ func TestProvisionerPrepare_Defaults(t *testing.T) { t.Error("expected elevated_password to be empty") } - if p.config.ExecuteCommand != `if (Test-Path variable:global:ProgressPreference){$ProgressPreference='SilentlyContinue'};{{.Vars}}&'{{.Path}}';exit $LastExitCode` { - t.Fatalf(`Default command should be "if (Test-Path variable:global:ProgressPreference){$ProgressPreference='SilentlyContinue'};{{.Vars}}&'{{.Path}}';exit $LastExitCode", but got %s`, p.config.ExecuteCommand) + if p.config.ExecuteCommand != `powershell -executionpolicy bypass "& { if (Test-Path variable:global:ProgressPreference){$ProgressPreference='SilentlyContinue'};{{.Vars}}&'{{.Path}}';exit $LastExitCode }"` { + t.Fatalf(`Default command should be 'powershell -executionpolicy bypass "& { if (Test-Path variable:global:ProgressPreference){$ProgressPreference='SilentlyContinue'};{{.Vars}}&'{{.Path}}';exit $LastExitCode }"', but got '%s'`, p.config.ExecuteCommand) } - if p.config.ElevatedExecuteCommand != `if (Test-Path variable:global:ProgressPreference){$ProgressPreference='SilentlyContinue'}; . {{.Vars}}; &'{{.Path}}'; exit $LastExitCode` { - t.Fatalf(`Default command should be "if (Test-Path variable:global:ProgressPreference){$ProgressPreference='SilentlyContinue'}; . {{.Vars}}; &'{{.Path}}'; exit $LastExitCode", but got %s`, p.config.ElevatedExecuteCommand) + if p.config.ElevatedExecuteCommand != `powershell -executionpolicy bypass "& { if (Test-Path variable:global:ProgressPreference){$ProgressPreference='SilentlyContinue'};. {{.Vars}}; &'{{.Path}}'; exit $LastExitCode }"` { + t.Fatalf(`Default command should be 'powershell -executionpolicy bypass "& { if (Test-Path variable:global:ProgressPreference){$ProgressPreference='SilentlyContinue'};. {{.Vars}}; &'{{.Path}}'; exit $LastExitCode }"', but got '%s'`, p.config.ElevatedExecuteCommand) } if p.config.ValidExitCodes == nil { @@ -413,23 +413,9 @@ func TestProvisionerProvision_Inline(t *testing.T) { t.Fatal("should not have error") } - expectedCommand := `if (Test-Path variable:global:ProgressPreference){$ProgressPreference='SilentlyContinue'};$env:PACKER_BUILDER_TYPE="iso"; $env:PACKER_BUILD_NAME="vmware"; &'c:/Windows/Temp/inlineScript.ps1';exit $LastExitCode` - expectedCommandBase64Encoded := `aQBmACAAKABUAGUAcwB0AC0AUABhAHQAaAAgAHYAYQByAGkAYQBiAGwAZQA6AGcAbABvAGIAYQBsADoAUAByAG8AZwByAGUAcwBzAFAAcgBlAGYAZQByAGUAbgBjAGUAKQB7ACQAUAByAG8AZwByAGUAcwBzAFAAcgBlAGYAZQByAGUAbgBjAGUAPQAnAFMAaQBsAGUAbgB0AGwAeQBDAG8AbgB0AGkAbgB1AGUAJwB9ADsAJABlAG4AdgA6AFAAQQBDAEsARQBSAF8AQgBVAEkATABEAEUAUgBfAFQAWQBQAEUAPQAiAGkAcwBvACIAOwAgACQAZQBuAHYAOgBQAEEAQwBLAEUAUgBfAEIAVQBJAEwARABfAE4AQQBNAEUAPQAiAHYAbQB3AGEAcgBlACIAOwAgACYAJwBjADoALwBXAGkAbgBkAG8AdwBzAC8AVABlAG0AcAAvAGkAbgBsAGkAbgBlAFMAYwByAGkAcAB0AC4AcABzADEAJwA7AGUAeABpAHQAIAAkAEwAYQBzAHQARQB4AGkAdABDAG8AZABlAA==` - expectedCommandPrefix := `powershell -executionpolicy bypass -encodedCommand ` - expectedCommandEncoded := expectedCommandPrefix + expectedCommandBase64Encoded - - actualCommandWithoutPrefix := strings.Replace(comm.StartCmd.Command, expectedCommandPrefix, "", -1) - actualCommandDecoded, err := powershellDecode(actualCommandWithoutPrefix) - if err != nil { - t.Fatal("should not have error when base64 decoding") - } - - if actualCommandDecoded != expectedCommand { - t.Fatalf("Expected decoded: %s, got %s", expectedCommand, actualCommandDecoded) - } - - if comm.StartCmd.Command != expectedCommandEncoded { - t.Fatalf("Expect command to be: %s, got %s", expectedCommandEncoded, comm.StartCmd.Command) + expectedCommand := `powershell -executionpolicy bypass "& { if (Test-Path variable:global:ProgressPreference){$ProgressPreference='SilentlyContinue'};$env:PACKER_BUILDER_TYPE=\"iso\"; $env:PACKER_BUILD_NAME=\"vmware\"; &'c:/Windows/Temp/inlineScript.ps1';exit $LastExitCode }"` + if comm.StartCmd.Command != expectedCommand { + t.Fatalf("Expect command to be: %s, got %s", expectedCommand, comm.StartCmd.Command) } envVars := make([]string, 2) @@ -444,23 +430,9 @@ func TestProvisionerProvision_Inline(t *testing.T) { t.Fatal("should not have error") } - 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.ps1';exit $LastExitCode` - expectedCommandBase64Encoded = `aQBmACAAKABUAGUAcwB0AC0AUABhAHQAaAAgAHYAYQByAGkAYQBiAGwAZQA6AGcAbABvAGIAYQBsADoAUAByAG8AZwByAGUAcwBzAFAAcgBlAGYAZQByAGUAbgBjAGUAKQB7ACQAUAByAG8AZwByAGUAcwBzAFAAcgBlAGYAZQByAGUAbgBjAGUAPQAnAFMAaQBsAGUAbgB0AGwAeQBDAG8AbgB0AGkAbgB1AGUAJwB9ADsAJABlAG4AdgA6AEIAQQBSAD0AIgBCAEEAWgAiADsAIAAkAGUAbgB2ADoARgBPAE8APQAiAEIAQQBSACIAOwAgACQAZQBuAHYAOgBQAEEAQwBLAEUAUgBfAEIAVQBJAEwARABFAFIAXwBUAFkAUABFAD0AIgBpAHMAbwAiADsAIAAkAGUAbgB2ADoAUABBAEMASwBFAFIAXwBCAFUASQBMAEQAXwBOAEEATQBFAD0AIgB2AG0AdwBhAHIAZQAiADsAIAAmACcAYwA6AC8AVwBpAG4AZABvAHcAcwAvAFQAZQBtAHAALwBpAG4AbABpAG4AZQBTAGMAcgBpAHAAdAAuAHAAcwAxACcAOwBlAHgAaQB0ACAAJABMAGEAcwB0AEUAeABpAHQAQwBvAGQAZQA=` - expectedCommandPrefix = `powershell -executionpolicy bypass -encodedCommand ` - expectedCommandEncoded = expectedCommandPrefix + expectedCommandBase64Encoded - - actualCommandWithoutPrefix = strings.Replace(comm.StartCmd.Command, expectedCommandPrefix, "", -1) - actualCommandDecoded, err = powershellDecode(actualCommandWithoutPrefix) - if err != nil { - t.Fatal("should not have error when base64 decoding") - } - - if actualCommandDecoded != expectedCommand { - t.Fatalf("Expected decoded: %s, got %s", expectedCommand, actualCommandDecoded) - } - - if comm.StartCmd.Command != expectedCommandEncoded { - t.Fatalf("Expect command to be: %s, got %s", expectedCommandEncoded, comm.StartCmd.Command) + expectedCommand = `powershell -executionpolicy bypass "& { 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.ps1';exit $LastExitCode }"` + if comm.StartCmd.Command != expectedCommand { + t.Fatalf("Expect command to be: %s, got %s", expectedCommand, comm.StartCmd.Command) } } @@ -483,24 +455,11 @@ func TestProvisionerProvision_Scripts(t *testing.T) { t.Fatal("should not have error") } - 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` - expectedCommandBase64Encoded := `aQBmACAAKABUAGUAcwB0AC0AUABhAHQAaAAgAHYAYQByAGkAYQBiAGwAZQA6AGcAbABvAGIAYQBsADoAUAByAG8AZwByAGUAcwBzAFAAcgBlAGYAZQByAGUAbgBjAGUAKQB7ACQAUAByAG8AZwByAGUAcwBzAFAAcgBlAGYAZQByAGUAbgBjAGUAPQAnAFMAaQBsAGUAbgB0AGwAeQBDAG8AbgB0AGkAbgB1AGUAJwB9ADsAJABlAG4AdgA6AFAAQQBDAEsARQBSAF8AQgBVAEkATABEAEUAUgBfAFQAWQBQAEUAPQAiAGYAbwBvAHQAeQBwAGUAIgA7ACAAJABlAG4AdgA6AFAAQQBDAEsARQBSAF8AQgBVAEkATABEAF8ATgBBAE0ARQA9ACIAZgBvAG8AYgB1AGkAbABkACIAOwAgACYAJwBjADoALwBXAGkAbgBkAG8AdwBzAC8AVABlAG0AcAAvAHMAYwByAGkAcAB0AC4AcABzADEAJwA7AGUAeABpAHQAIAAkAEwAYQBzAHQARQB4AGkAdABDAG8AZABlAA==` - expectedCommandPrefix := `powershell -executionpolicy bypass -encodedCommand ` - expectedCommandEncoded := expectedCommandPrefix + expectedCommandBase64Encoded - - actualCommandWithoutPrefix := strings.Replace(comm.StartCmd.Command, expectedCommandPrefix, "", -1) - actualCommandDecoded, err := powershellDecode(actualCommandWithoutPrefix) - if err != nil { - t.Fatal("should not have error when base64 decoding") - } - - if actualCommandDecoded != expectedCommand { - t.Fatalf("Expected decoded: %s, got %s", expectedCommand, actualCommandDecoded) + expectedCommand := `powershell -executionpolicy bypass "& { 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 }"` + if comm.StartCmd.Command != expectedCommand { + t.Fatalf("Expect command to be: %s, got %s", expectedCommand, comm.StartCmd.Command) } - if comm.StartCmd.Command != expectedCommandEncoded { - t.Fatalf("Expect command to be: %s, got %s", expectedCommandEncoded, comm.StartCmd.Command) - } } func TestProvisionerProvision_ScriptsWithEnvVars(t *testing.T) { @@ -529,23 +488,9 @@ func TestProvisionerProvision_ScriptsWithEnvVars(t *testing.T) { t.Fatal("should not have error") } - 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` - expectedCommandBase64Encoded := `aQBmACAAKABUAGUAcwB0AC0AUABhAHQAaAAgAHYAYQByAGkAYQBiAGwAZQA6AGcAbABvAGIAYQBsADoAUAByAG8AZwByAGUAcwBzAFAAcgBlAGYAZQByAGUAbgBjAGUAKQB7ACQAUAByAG8AZwByAGUAcwBzAFAAcgBlAGYAZQByAGUAbgBjAGUAPQAnAFMAaQBsAGUAbgB0AGwAeQBDAG8AbgB0AGkAbgB1AGUAJwB9ADsAJABlAG4AdgA6AEIAQQBSAD0AIgBCAEEAWgAiADsAIAAkAGUAbgB2ADoARgBPAE8APQAiAEIAQQBSACIAOwAgACQAZQBuAHYAOgBQAEEAQwBLAEUAUgBfAEIAVQBJAEwARABFAFIAXwBUAFkAUABFAD0AIgBmAG8AbwB0AHkAcABlACIAOwAgACQAZQBuAHYAOgBQAEEAQwBLAEUAUgBfAEIAVQBJAEwARABfAE4AQQBNAEUAPQAiAGYAbwBvAGIAdQBpAGwAZAAiADsAIAAmACcAYwA6AC8AVwBpAG4AZABvAHcAcwAvAFQAZQBtAHAALwBzAGMAcgBpAHAAdAAuAHAAcwAxACcAOwBlAHgAaQB0ACAAJABMAGEAcwB0AEUAeABpAHQAQwBvAGQAZQA=` - expectedCommandPrefix := `powershell -executionpolicy bypass -encodedCommand ` - expectedCommandEncoded := expectedCommandPrefix + expectedCommandBase64Encoded - - actualCommandWithoutPrefix := strings.Replace(comm.StartCmd.Command, expectedCommandPrefix, "", -1) - actualCommandDecoded, err := powershellDecode(actualCommandWithoutPrefix) - if err != nil { - t.Fatal("should not have error when base64 decoding") - } - - if actualCommandDecoded != expectedCommand { - t.Fatalf("Expected decoded: %s, got %s", expectedCommand, actualCommandDecoded) - } - - if comm.StartCmd.Command != expectedCommandEncoded { - t.Fatalf("Expect command to be: %s, got %s", expectedCommandEncoded, comm.StartCmd.Command) + expectedCommand := `powershell -executionpolicy bypass "& { 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 }"` + if comm.StartCmd.Command != expectedCommand { + t.Fatalf("Expect command to be: %s, got %s", expectedCommand, comm.StartCmd.Command) } } @@ -588,7 +533,6 @@ func TestProvisioner_createFlattenedElevatedEnvVars_windows(t *testing.T) { t.Fatalf("expected flattened env vars to be: %s, got %s.", expectedValue, flattenedEnvVars) } } - } func TestProvisioner_createFlattenedEnvVars_windows(t *testing.T) { @@ -603,11 +547,11 @@ func TestProvisioner_createFlattenedEnvVars_windows(t *testing.T) { {"FOO==bar"}, // User env var with value starting with equals } expected := []string{ - `$env:PACKER_BUILDER_TYPE="iso"; $env:PACKER_BUILD_NAME="vmware"; `, - `$env:FOO="bar"; $env:PACKER_BUILDER_TYPE="iso"; $env:PACKER_BUILD_NAME="vmware"; `, - `$env:BAZ="qux"; $env:FOO="bar"; $env:PACKER_BUILDER_TYPE="iso"; $env:PACKER_BUILD_NAME="vmware"; `, - `$env:FOO="bar=baz"; $env:PACKER_BUILDER_TYPE="iso"; $env:PACKER_BUILD_NAME="vmware"; `, - `$env:FOO="=bar"; $env:PACKER_BUILDER_TYPE="iso"; $env:PACKER_BUILD_NAME="vmware"; `, + `$env:PACKER_BUILDER_TYPE=\"iso\"; $env:PACKER_BUILD_NAME=\"vmware\"; `, + `$env:FOO=\"bar\"; $env:PACKER_BUILDER_TYPE=\"iso\"; $env:PACKER_BUILD_NAME=\"vmware\"; `, + `$env:BAZ=\"qux\"; $env:FOO=\"bar\"; $env:PACKER_BUILDER_TYPE=\"iso\"; $env:PACKER_BUILD_NAME=\"vmware\"; `, + `$env:FOO=\"bar=baz\"; $env:PACKER_BUILDER_TYPE=\"iso\"; $env:PACKER_BUILD_NAME=\"vmware\"; `, + `$env:FOO=\"=bar\"; $env:PACKER_BUILDER_TYPE=\"iso\"; $env:PACKER_BUILD_NAME=\"vmware\"; `, } p := new(Provisioner) @@ -635,27 +579,17 @@ func TestProvision_createCommandText(t *testing.T) { p.communicator = comm _ = p.Prepare(config) + // Defaults provided by Packer + p.config.PackerBuildName = "vmware" + p.config.PackerBuilderType = "iso" + // Non-elevated cmd, _ := p.createCommandText() - expectedCommand := `if (Test-Path variable:global:ProgressPreference){$ProgressPreference='SilentlyContinue'};$env:PACKER_BUILDER_TYPE=""; $env:PACKER_BUILD_NAME=""; &'c:/Windows/Temp/script.ps1';exit $LastExitCode` - expectedCommandBase64Encoded := `aQBmACAAKABUAGUAcwB0AC0AUABhAHQAaAAgAHYAYQByAGkAYQBiAGwAZQA6AGcAbABvAGIAYQBsADoAUAByAG8AZwByAGUAcwBzAFAAcgBlAGYAZQByAGUAbgBjAGUAKQB7ACQAUAByAG8AZwByAGUAcwBzAFAAcgBlAGYAZQByAGUAbgBjAGUAPQAnAFMAaQBsAGUAbgB0AGwAeQBDAG8AbgB0AGkAbgB1AGUAJwB9ADsAJABlAG4AdgA6AFAAQQBDAEsARQBSAF8AQgBVAEkATABEAEUAUgBfAFQAWQBQAEUAPQAiACIAOwAgACQAZQBuAHYAOgBQAEEAQwBLAEUAUgBfAEIAVQBJAEwARABfAE4AQQBNAEUAPQAiACIAOwAgACYAJwBjADoALwBXAGkAbgBkAG8AdwBzAC8AVABlAG0AcAAvAHMAYwByAGkAcAB0AC4AcABzADEAJwA7AGUAeABpAHQAIAAkAEwAYQBzAHQARQB4AGkAdABDAG8AZABlAA==` - expectedCommandPrefix := `powershell -executionpolicy bypass -encodedCommand ` - expectedCommandEncoded := expectedCommandPrefix + expectedCommandBase64Encoded - - actualCommandWithoutPrefix := strings.Replace(cmd, expectedCommandPrefix, "", -1) - - actualCommandDecoded, err := powershellDecode(actualCommandWithoutPrefix) - if err != nil { - t.Fatal("should not have error when base64 decoding") - } - - if actualCommandDecoded != expectedCommand { - t.Fatalf("Expected decoded: %s, got %s", expectedCommand, actualCommandDecoded) - } + expectedCommand := `powershell -executionpolicy bypass "& { if (Test-Path variable:global:ProgressPreference){$ProgressPreference='SilentlyContinue'};$env:PACKER_BUILDER_TYPE=\"iso\"; $env:PACKER_BUILD_NAME=\"vmware\"; &'c:/Windows/Temp/script.ps1';exit $LastExitCode }"` - if cmd != expectedCommandEncoded { - t.Fatalf("Expect command to be: %s, got %s", expectedCommandEncoded, cmd) + if cmd != expectedCommand { + t.Fatalf("Expected Non-elevated command: %s, got %s", expectedCommand, cmd) } // Elevated From b7bb6b54b443bb613fc542affb796e3ec15b4b3c Mon Sep 17 00:00:00 2001 From: DanHam Date: Wed, 20 Sep 2017 16:13:27 +0100 Subject: [PATCH 4/4] Update docs with new defaults for Powershell commands --- .../source/docs/provisioners/powershell.html.md | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/website/source/docs/provisioners/powershell.html.md b/website/source/docs/provisioners/powershell.html.md index 765760ad9..f085a6e82 100644 --- a/website/source/docs/provisioners/powershell.html.md +++ b/website/source/docs/provisioners/powershell.html.md @@ -56,7 +56,12 @@ Optional parameters: endings (if there are any). By default this is false. - `elevated_execute_command` (string) - The command to use to execute the elevated - script. By default this is `powershell if (Test-Path variable:global:ProgressPreference){$ProgressPreference='SilentlyContinue'}; . {{.Vars}}; &'{{.Path}}'; exit $LastExitCode`. + script. By default this is as follows: + + ``` powershell + powershell -executionpolicy bypass "& { if (Test-Path variable:global:ProgressPreference){$ProgressPreference='SilentlyContinue'};. {{.Vars}}; &'{{.Path}}'; exit $LastExitCode }" + ``` + The value of this is treated as [configuration template](/docs/templates/engine.html). There are two available variables: `Path`, which is the path to the script to run, and @@ -68,7 +73,12 @@ Optional parameters: as well, which are covered in the section below. - `execute_command` (string) - The command to use to execute the script. By - default this is `powershell if (Test-Path variable:global:ProgressPreference){$ProgressPreference='SilentlyContinue'};{{.Vars}}&'{{.Path}}';exit $LastExitCode`. + default this is as follows: + + ``` powershell + powershell -executionpolicy bypass "& { if (Test-Path variable:global:ProgressPreference){$ProgressPreference='SilentlyContinue'};{{.Vars}}&'{{.Path}}';exit $LastExitCode }" + ``` + The value of this is treated as [configuration template](/docs/templates/engine.html). There are two available variables: `Path`, which is the path to the script to run, and