From d458628529cdb9906da0e562ed40f50ad3c0c083 Mon Sep 17 00:00:00 2001 From: Megan Marsh Date: Thu, 14 Sep 2017 10:46:40 -0700 Subject: [PATCH 1/6] exclude elevated_executed_command from config interpolation so it can be used correctly later --- provisioner/powershell/provisioner.go | 1 + 1 file changed, 1 insertion(+) diff --git a/provisioner/powershell/provisioner.go b/provisioner/powershell/provisioner.go index 548579b0a..e46bc8a03 100644 --- a/provisioner/powershell/provisioner.go +++ b/provisioner/powershell/provisioner.go @@ -102,6 +102,7 @@ func (p *Provisioner) Prepare(raws ...interface{}) error { InterpolateFilter: &interpolate.RenderFilter{ Exclude: []string{ "execute_command", + "elevated_execute_command", }, }, }, raws...) From f86d45eaf68588803d04cca543b542a80fce7a7f Mon Sep 17 00:00:00 2001 From: Megan Marsh Date: Thu, 14 Sep 2017 10:48:56 -0700 Subject: [PATCH 2/6] fix docs for execute_command and elevated_execute_command --- website/source/docs/provisioners/powershell.html.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/website/source/docs/provisioners/powershell.html.md b/website/source/docs/provisioners/powershell.html.md index 87a9a76f6..0b916c413 100644 --- a/website/source/docs/provisioners/powershell.html.md +++ b/website/source/docs/provisioners/powershell.html.md @@ -55,13 +55,20 @@ Optional parameters: and Packer should therefore not convert Windows line endings to Unix line 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`. + 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 + `Vars`, which is the list of `environment_vars`, if configured. + - `environment_vars` (array of strings) - An array of key/value pairs to inject prior to the execute\_command. The format should be `key=value`. Packer injects some environmental variables by default into the environment, 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 "& { {{.Vars}}{{.Path}}; exit $LastExitCode}"`. + default this is `powershell 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 From 92e70757bb185a4119fa3adb8d3ee11837d4ede8 Mon Sep 17 00:00:00 2001 From: Megan Marsh Date: Thu, 14 Sep 2017 16:39:35 -0700 Subject: [PATCH 3/6] Move env vars into a file that we dot-source instead of trying to write them all to the command line --- provisioner/powershell/provisioner.go | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/provisioner/powershell/provisioner.go b/provisioner/powershell/provisioner.go index e46bc8a03..2ccb0eafa 100644 --- a/provisioner/powershell/provisioner.go +++ b/provisioner/powershell/provisioner.go @@ -124,7 +124,7 @@ func (p *Provisioner) Prepare(raws ...interface{}) error { } if p.config.ElevatedExecuteCommand == "" { - p.config.ElevatedExecuteCommand = `if (Test-Path variable:global:ProgressPreference){$ProgressPreference='SilentlyContinue'};{{.Vars}}&'{{.Path}}';exit $LastExitCode` + p.config.ElevatedExecuteCommand = `if (Test-Path variable:global:ProgressPreference){$ProgressPreference='SilentlyContinue'}; . {{.Vars}}; &'{{.Path}}'; exit $LastExitCode` } if p.config.Inline != nil && len(p.config.Inline) == 0 { @@ -413,10 +413,20 @@ func (p *Provisioner) generateCommandLineRunner(command string) (commandText str func (p *Provisioner) createCommandTextPrivileged() (command string, err error) { // Can't double escape the env vars, lets create shiny new ones flattenedEnvVars := p.createFlattenedEnvVars(true) + // Need to create a mini ps1 script containing all of the environment variables we want; + // we'll be dot-sourcing this later + envVarReader := strings.NewReader(flattenedEnvVars) + uuid := uuid.TimeOrderedUUID() + envVarPath := fmt.Sprintf(`${env:TEMP}\packer-env-vars-%s.ps1`, uuid) + log.Printf("Uploading env vars to %s", envVarPath) + err = p.communicator.Upload(envVarPath, envVarReader, nil) + if err != nil { + return "", fmt.Errorf("Error preparing elevated powershell script: %s", err) + } p.config.ctx.Data = &ExecuteCommandTemplate{ - Vars: flattenedEnvVars, Path: p.config.RemotePath, + Vars: envVarPath, } command, err = interpolate.Render(p.config.ElevatedExecuteCommand, &p.config.ctx) if err != nil { From cbe1d7d854214a8dbf9e34fa9942da28fb906b7c Mon Sep 17 00:00:00 2001 From: Megan Marsh Date: Thu, 14 Sep 2017 17:00:31 -0700 Subject: [PATCH 4/6] simplify file upload for elevated powershell wrapper --- provisioner/powershell/provisioner.go | 23 ++++------------------- 1 file changed, 4 insertions(+), 19 deletions(-) diff --git a/provisioner/powershell/provisioner.go b/provisioner/powershell/provisioner.go index 2ccb0eafa..d11136f3d 100644 --- a/provisioner/powershell/provisioner.go +++ b/provisioner/powershell/provisioner.go @@ -469,27 +469,12 @@ func (p *Provisioner) generateElevatedRunner(command string) (uploadedPath strin fmt.Printf("Error creating elevated template: %s", err) return "", err } - - tmpFile, err := ioutil.TempFile(os.TempDir(), "packer-elevated-shell.ps1") - writer := bufio.NewWriter(tmpFile) - if _, err := writer.WriteString(string(buffer.Bytes())); err != nil { - return "", fmt.Errorf("Error preparing elevated powershell script: %s", err) - } - - if err := writer.Flush(); err != nil { - return "", fmt.Errorf("Error preparing elevated powershell script: %s", err) - } - tmpFile.Close() - f, err := os.Open(tmpFile.Name()) - if err != nil { - return "", fmt.Errorf("Error opening temporary elevated powershell script: %s", err) - } - defer f.Close() - + wrapperBytes := buffer.Bytes() + wrapperReader := bytes.NewReader(wrapperBytes) uuid := uuid.TimeOrderedUUID() path := fmt.Sprintf(`${env:TEMP}\packer-elevated-shell-%s.ps1`, uuid) - log.Printf("Uploading elevated shell wrapper for command [%s] to [%s] from [%s]", command, path, tmpFile.Name()) - err = p.communicator.Upload(path, f, nil) + log.Printf("Uploading elevated shell wrapper for command [%s] to [%s]", command, path) + err = p.communicator.Upload(path, wrapperReader, nil) if err != nil { return "", fmt.Errorf("Error preparing elevated powershell script: %s", err) } From 5d63f01fed99d482b5117742ba9102490161d12d Mon Sep 17 00:00:00 2001 From: Megan Marsh Date: Fri, 15 Sep 2017 08:14:12 -0700 Subject: [PATCH 5/6] Update docs for elevated_execute_command with new default command --- website/source/docs/provisioners/powershell.html.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/website/source/docs/provisioners/powershell.html.md b/website/source/docs/provisioners/powershell.html.md index 0b916c413..765760ad9 100644 --- a/website/source/docs/provisioners/powershell.html.md +++ b/website/source/docs/provisioners/powershell.html.md @@ -56,11 +56,11 @@ 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 `powershell 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 - `Vars`, which is the list of `environment_vars`, if configured. + `Vars`, which is the location of a temp file containing the list of `environment_vars`, if configured. - `environment_vars` (array of strings) - An array of key/value pairs to inject prior to the execute\_command. The format should be `key=value`. From b05c673a14f112287c543badc732e51ea8fa5daf Mon Sep 17 00:00:00 2001 From: Megan Marsh Date: Fri, 15 Sep 2017 08:17:17 -0700 Subject: [PATCH 6/6] Update powershell provisioner test with new default --- provisioner/powershell/provisioner_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/provisioner/powershell/provisioner_test.go b/provisioner/powershell/provisioner_test.go index 73e85671d..3b3d8fa46 100644 --- a/provisioner/powershell/provisioner_test.go +++ b/provisioner/powershell/provisioner_test.go @@ -83,8 +83,8 @@ func TestProvisionerPrepare_Defaults(t *testing.T) { 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.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 != `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.ValidExitCodes == nil {