From a790d5997d3b4cb9d3ffa8462c8b92af3be91ebd Mon Sep 17 00:00:00 2001 From: mwrock Date: Thu, 1 Oct 2020 14:58:59 -0700 Subject: add interpreter arg to powershell_out allowing it to call pwsh.exe Signed-off-by: mwrock --- lib/chef/mixin/powershell_out.rb | 17 ++++++++++++----- omnibus/omnibus-test.ps1 | 9 ++++++++- spec/functional/mixin/powershell_out_spec.rb | 10 +++++++++- spec/spec_helper.rb | 1 + spec/support/platform_helpers.rb | 5 +++++ spec/unit/mixin/powershell_out_spec.rb | 14 ++++++++++++++ 6 files changed, 49 insertions(+), 7 deletions(-) diff --git a/lib/chef/mixin/powershell_out.rb b/lib/chef/mixin/powershell_out.rb index 1ecc9bac98..e6519fe5a0 100644 --- a/lib/chef/mixin/powershell_out.rb +++ b/lib/chef/mixin/powershell_out.rb @@ -28,19 +28,24 @@ class Chef # can be set to :i386 or :x86_64 to force the windows architecture. # # @param script [String] script to run + # @param interpreter [Symbol] the interpreter type, `:powershell` or `:pwsh` # @param options [Hash] options hash # @return [Mixlib::Shellout] mixlib-shellout object def powershell_out(*command_args) script = command_args.first options = command_args.last.is_a?(Hash) ? command_args.last : nil + interpreter = command_args[1].is_a?(Symbol) ? command_args[1] : :powershell - run_command_with_os_architecture(script, options) + raise ArgumentError, "Expected interpreter of :powershell or :pwsh" unless [:powershell, :pwsh].include?(interpreter) + + run_command_with_os_architecture(script, interpreter, options) end # Run a command under powershell with the same API as shell_out! # (raises exceptions on errors) # # @param script [String] script to run + # @param interpreter [Symbol] the interpreter type, `:powershell` or `:pwsh` # @param options [Hash] options hash # @return [Mixlib::Shellout] mixlib-shellout object def powershell_out!(*command_args) @@ -56,16 +61,17 @@ class Chef # because chef-client runs as a 32-bit app on 64-bit windows). # # @param script [String] script to run + # @param interpreter [Symbol] the interpreter type, `:powershell` or `:pwsh` # @param options [Hash] options hash # @return [Mixlib::Shellout] mixlib-shellout object - def run_command_with_os_architecture(script, options) + def run_command_with_os_architecture(script, interpreter, options) options ||= {} options = options.dup arch = options.delete(:architecture) with_os_architecture(nil, architecture: arch) do shell_out( - build_powershell_command(script), + build_powershell_command(script, interpreter), **options ) end @@ -74,8 +80,9 @@ class Chef # Helper to build a powershell command around the script to run. # # @param script [String] script to run + # @param interpreter [Symbol] the interpreter type, `:powershell` or `:pwsh` # @return [String] powershell command to execute - def build_powershell_command(script) + def build_powershell_command(script, interpreter) flags = [ # Hides the copyright banner at startup. "-NoLogo", @@ -91,7 +98,7 @@ class Chef "-InputFormat None", ] - "powershell.exe #{flags.join(" ")} -Command \"#{script.gsub('"', '\"')}\"" + "#{interpreter}.exe #{flags.join(" ")} -Command \"#{script.gsub('"', '\"')}\"" end end end diff --git a/omnibus/omnibus-test.ps1 b/omnibus/omnibus-test.ps1 index 4384563296..b30409596a 100644 --- a/omnibus/omnibus-test.ps1 +++ b/omnibus/omnibus-test.ps1 @@ -2,7 +2,14 @@ $ErrorActionPreference = "Stop" # install chocolatey -Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1')) +Set-ExecutionPolicy Bypass -Scope Process -Force +[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072 +iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1')) + +# install powershell core +Invoke-WebRequest "https://github.com/PowerShell/PowerShell/releases/download/v7.0.3/PowerShell-7.0.3-win-x64.msi" -UseBasicParsing -OutFile powershell.msi +Start-Process msiexec.exe -Wait -ArgumentList "/package PowerShell.msi /quiet" +$env:path += ";C:\Program Files\PowerShell\7" $channel = "$Env:CHANNEL" If ([string]::IsNullOrEmpty($channel)) { $channel = "unstable" } diff --git a/spec/functional/mixin/powershell_out_spec.rb b/spec/functional/mixin/powershell_out_spec.rb index 1ef9776efc..d9b5c69cd6 100644 --- a/spec/functional/mixin/powershell_out_spec.rb +++ b/spec/functional/mixin/powershell_out_spec.rb @@ -18,7 +18,7 @@ require "spec_helper" require "chef/mixin/powershell_out" -describe Chef::Mixin::PowershellOut, windows_only: true do +describe Chef::Mixin::PowershellOut, :windows_only do include Chef::Mixin::PowershellOut describe "#powershell_out" do @@ -26,6 +26,14 @@ describe Chef::Mixin::PowershellOut, windows_only: true do expect(powershell_out("get-process").run_command.stdout).to match /Handles/ end + it "uses :powershell by default" do + expect(powershell_out("$PSVersionTable").run_command.stdout).to match /Desktop/ + end + + it ":pwsh interpreter uses core edition", :pwsh_installed do + expect(powershell_out("$PSVersionTable", :pwsh).run_command.stdout).to match /Core/ + end + it "does not raise exceptions when the command is invalid" do powershell_out("this-is-not-a-valid-command").run_command end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index b0a56f4b7f..4c925bace3 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -200,6 +200,7 @@ RSpec.configure do |config| # check for particular binaries we need config.filter_run_excluding choco_installed: true unless choco_installed? config.filter_run_excluding requires_ifconfig: true unless ifconfig? + config.filter_run_excluding pwsh_installed: true unless pwsh_installed? running_platform_arch = `uname -m`.strip unless windows? diff --git a/spec/support/platform_helpers.rb b/spec/support/platform_helpers.rb index 51a9299497..6e97230b11 100644 --- a/spec/support/platform_helpers.rb +++ b/spec/support/platform_helpers.rb @@ -245,3 +245,8 @@ def choco_installed? result = ShellHelpers.powershell_out("choco --version") result.stderr.empty? ? true : false end + +def pwsh_installed? + result = ShellHelpers.powershell_out("pwsh.exe --version") + result.stderr.empty? ? true : false +end diff --git a/spec/unit/mixin/powershell_out_spec.rb b/spec/unit/mixin/powershell_out_spec.rb index 7306332057..14a9483758 100644 --- a/spec/unit/mixin/powershell_out_spec.rb +++ b/spec/unit/mixin/powershell_out_spec.rb @@ -44,6 +44,20 @@ describe Chef::Mixin::PowershellOut, :windows_only do expect(object.powershell_out("Get-Process", timeout: 600)).to eql(ret) end + it "uses pwsh.exe when given :pwsh interpreter" do + ret = double("Mixlib::ShellOut") + expect(object).to receive(:shell_out).with( + "pwsh.exe #{flags} -Command \"Get-Process\"", + timeout: 600 + ).and_return(ret) + expect(object.powershell_out("Get-Process", :pwsh, timeout: 600)).to eql(ret) + end + + it "raises error if interpreter is invalid" do + ret = double("Mixlib::ShellOut") + expect { object.powershell_out("Get-Process", :blah, timeout: 600) }.to raise_error(ArgumentError) + end + context "when double quote is passed in the powershell command" do it "passes if double quote is appended with single escape" do result = object.powershell_out("Write-Verbose \"Some String\" -Verbose") -- cgit v1.2.1