Powershell: Running from Ruby (Puppet) fails - OSX

Created on 13 Aug 2016  路  12Comments  路  Source: PowerShell/PowerShell

I at first attributed this to an issue with #1629, but that appears not to be the case here. I plan to dig in a bit but wanted to make you aware of it.

Steps to reproduce

  1. Ensure Puppet is installed.
  2. Clone https://github.com/puppetlabs/puppetlabs-powershell and apply the patch shown below. https://github.com/puppetlabs/puppetlabs-powershell
  3. Create the following manifest and save it as powershell_osx.pp:

    exec {'osx':
     command     => 'Write-Output "Hello from OSX"',
     logoutput  => true,
     provider    => 'powershell',
    }
    
  4. Run puppet apply path/to/powershell_osx.pp.

    PowerShell Module patch

diff --git a/lib/puppet/provider/exec/powershell.rb b/lib/puppet/provider/exec/powershell.rb
index b59d03a..5faa381 100644
--- a/lib/puppet/provider/exec/powershell.rb
+++ b/lib/puppet/provider/exec/powershell.rb
@@ -2,13 +2,14 @@ require 'puppet/provider/exec'
 require File.join(File.dirname(__FILE__), '../../../puppet_x/puppetlabs/powershell/powershell_manager')

 Puppet::Type.type(:exec).provide :powershell, :parent => Puppet::Provider::Exec do
-  confine :operatingsystem => :windows

   commands :powershell =>
     if File.exists?("#{ENV['SYSTEMROOT']}\\sysnative\\WindowsPowershell\\v1.0\\powershell.exe")
       "#{ENV['SYSTEMROOT']}\\sysnative\\WindowsPowershell\\v1.0\\powershell.exe"
     elsif File.exists?("#{ENV['SYSTEMROOT']}\\system32\\WindowsPowershell\\v1.0\\powershell.exe")
       "#{ENV['SYSTEMROOT']}\\system32\\WindowsPowershell\\v1.0\\powershell.exe"
+    elsif File.exists?('/usr/local/bin/powershell')
+      '/usr/local/bin/powershell'
     else
       'powershell.exe'
     end
@@ -55,7 +56,7 @@ Puppet::Type.type(:exec).provide :powershell, :parent => Puppet::Provider::Exec

   def run(command, check = false)
     if !PuppetX::PowerShell::PowerShellManager.supported?
-      self.class.upgrade_message
+      self.class.upgrade_message if Puppet::Util::Platform.windows?
       write_script(command) do |native_path|
         # Ideally, we could keep a handle open on the temp file in this
         # process (to prevent TOCTOU attacks), and execute powershell
@@ -65,7 +66,11 @@ Puppet::Type.type(:exec).provide :powershell, :parent => Puppet::Provider::Exec
         # we redirect powershell's stdin to read from the file. Current
         # versions of Windows use per-user temp directories with strong
         # permissions, but I'd rather not make (poor) assumptions.
-        return super("cmd.exe /c \"\"#{native_path(command(:powershell))}\" #{legacy_args} -Command - < \"#{native_path}\"\"", check)
+        if Puppet::Util::Platform.windows?
+          return super("cmd.exe /c \"\"#{native_path(command(:powershell))}\" #{legacy_args} -Command - < \"#{native_path}\"\"", check)
+        else
+          return super("sh -c \"#{native_path(command(:powershell))} #{posix_args} -Command - < #{native_path}\"", check)
+        end
       end
     else
       result = ps_manager.execute(command)
@@ -116,4 +122,10 @@ Puppet::Type.type(:exec).provide :powershell, :parent => Puppet::Provider::Exec
   def legacy_args
     '-NoProfile -NonInteractive -NoLogo -ExecutionPolicy Bypass'
   end
+
+  def posix_args
+    # ExecutionPolicy is a known issue right now
+    # https://github.com/PowerShell/PowerShell/blob/a6e10e4d3a863f21b01712fe57e00916a9cc06b9/docs/KNOWNISSUES.md#executionpolicy-unavailable-on-non-windows-platforms
+    '-NoProfile -NonInteractive -NoLogo'
+  end
 end

Expected behavior

It works properly.

rob@skylight $ sh -c "/usr/local/bin/powershell -NoProfile -NonInteractive -NoLogo -Command - < /var/folders/pg/45bzltkn4wg8kqpllxgzcjcr0000gp/T/puppet-powershell20160813-36623-2801se.ps1"
Hello from OSX

Actual behavior

Debug: Exec[osx](provider=powershell): Executing 'sh -c "/usr/local/bin/powershell -NoProfile -NonInteractive -NoLogo -Command - < /var/folders/pg/45bzltkn4wg8kqpllxgzcjcr0000gp/T/puppet-powershell20160813-36623-2801se.ps1"'
Debug: Executing: 'sh -c "/usr/local/bin/powershell -NoProfile -NonInteractive -NoLogo -Command - < /var/folders/pg/45bzltkn4wg8kqpllxgzcjcr0000gp/T/puppet-powershell20160813-36623-2801se.ps1"'
Notice: /Stage[main]/Main/Exec[osx]/returns:
Notice: /Stage[main]/Main/Exec[osx]/returns: Unhandled Exception: System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.TypeInitializationException: The type initializer for 'System.Management.Automation.Utils' threw an exception. ---> System.ArgumentNullException: Value cannot be null.
Notice: /Stage[main]/Main/Exec[osx]/returns: Parameter name: path1
Notice: /Stage[main]/Main/Exec[osx]/returns:    at System.IO.Path.Combine(String path1, String path2, String path3)
Notice: /Stage[main]/Main/Exec[osx]/returns:    at System.Management.Automation.Platform.SelectProductNameForDirectory(XDG_Type dirpath)
Notice: /Stage[main]/Main/Exec[osx]/returns:    at System.Management.Automation.Utils..cctor()
Notice: /Stage[main]/Main/Exec[osx]/returns:    --- End of inner exception stack trace ---
Notice: /Stage[main]/Main/Exec[osx]/returns:    at System.Management.Automation.Runspaces.EarlyStartup.<>c.<Init>b__0_0()
Notice: /Stage[main]/Main/Exec[osx]/returns:    at System.Management.Automation.Runspaces.InitialSessionState.CreateDefault2()
Notice: /Stage[main]/Main/Exec[osx]/returns:    at System.Threading.Tasks.Task.Execute()
Notice: /Stage[main]/Main/Exec[osx]/returns:    at Microsoft.PowerShell.UnmanagedPSEntry.Start(String consoleFilePath, String[] args, Int32 argc)
Notice: /Stage[main]/Main/Exec[osx]/returns:    --- End of inner exception stack trace ---
Notice: /Stage[main]/Main/Exec[osx]/returns:    at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
Notice: /Stage[main]/Main/Exec[osx]/returns:    at System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments)
Notice: /Stage[main]/Main/Exec[osx]/returns:    at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
Notice: /Stage[main]/Main/Exec[osx]/returns:    at System.Management.Automation.PowerShellAssemblyLoadContextInitializer.InitializeAndCallEntryMethod(String basePaths, AssemblyName entryAssemblyName, String entryTypeName, String entryMethodName, Object[] args)
Notice: /Stage[main]/Main/Exec[osx]/returns:    at Microsoft.PowerShell.ManagedPSEntry.Main(String[] args)
Notice: /Stage[main]/Main/Exec[osx]/returns: sh: line 1: 36962 Abort trap: 6           /usr/local/bin/powershell -NoProfile -NonInteractive -NoLogo -Command - < /var/folders/pg/45bzltkn4wg8kqpllxgzcjcr0000gp/T/puppet-powershell20160813-36623-2801se.ps1
Error: Write-Output "Hello from OSX" returned 134 instead of one of [0]
/opt/boxen/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/puppet-4.3.2/lib/puppet/util/errors.rb:106:in `fail'
/opt/boxen/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/puppet-4.3.2/lib/puppet/type/exec.rb:160:in `sync'
/opt/boxen/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/puppet-4.3.2/lib/puppet/transaction/resource_harness.rb:214:in `sync'
/opt/boxen/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/puppet-4.3.2/lib/puppet/transaction/resource_harness.rb:139:in `sync_if_needed'
/opt/boxen/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/puppet-4.3.2/lib/puppet/transaction/resource_harness.rb:89:in `block in perform_changes'
/opt/boxen/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/puppet-4.3.2/lib/puppet/transaction/resource_harness.rb:88:in `each'
/opt/boxen/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/puppet-4.3.2/lib/puppet/transaction/resource_harness.rb:88:in `perform_changes'
/opt/boxen/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/puppet-4.3.2/lib/puppet/transaction/resource_harness.rb:20:in `evaluate'
/opt/boxen/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/puppet-4.3.2/lib/puppet/transaction.rb:207:in `apply'
/opt/boxen/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/puppet-4.3.2/lib/puppet/transaction.rb:223:in `eval_resource'
/opt/boxen/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/puppet-4.3.2/lib/puppet/transaction.rb:150:in `call'
/opt/boxen/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/puppet-4.3.2/lib/puppet/transaction.rb:150:in `block (2 levels) in evaluate'
/opt/boxen/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/puppet-4.3.2/lib/puppet/util.rb:292:in `block in thinmark'
/opt/boxen/rbenv/versions/2.1.5/lib/ruby/2.1.0/benchmark.rb:294:in `realtime'
/opt/boxen/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/puppet-4.3.2/lib/puppet/util.rb:291:in `thinmark'
/opt/boxen/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/puppet-4.3.2/lib/puppet/transaction.rb:150:in `block in evaluate'
/opt/boxen/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/puppet-4.3.2/lib/puppet/graph/relationship_graph.rb:118:in `traverse'
/opt/boxen/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/puppet-4.3.2/lib/puppet/transaction.rb:141:in `evaluate'
/opt/boxen/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/puppet-4.3.2/lib/puppet/resource/catalog.rb:202:in `block in apply'
/opt/boxen/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/puppet-4.3.2/lib/puppet/util/log.rb:153:in `with_destination'
/opt/boxen/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/puppet-4.3.2/lib/puppet/transaction/report.rb:107:in `as_logging_destination'
/opt/boxen/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/puppet-4.3.2/lib/puppet/resource/catalog.rb:201:in `apply'
/opt/boxen/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/puppet-4.3.2/lib/puppet/configurer.rb:119:in `block in apply_catalog'
/opt/boxen/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/puppet-4.3.2/lib/puppet/util.rb:129:in `block in benchmark'
/opt/boxen/rbenv/versions/2.1.5/lib/ruby/2.1.0/benchmark.rb:294:in `realtime'
/opt/boxen/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/puppet-4.3.2/lib/puppet/util.rb:128:in `benchmark'
/opt/boxen/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/puppet-4.3.2/lib/puppet/configurer.rb:118:in `apply_catalog'
/opt/boxen/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/puppet-4.3.2/lib/puppet/configurer.rb:232:in `run_internal'
/opt/boxen/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/puppet-4.3.2/lib/puppet/configurer.rb:134:in `block in run'
/opt/boxen/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/puppet-4.3.2/lib/puppet/context.rb:65:in `override'
/opt/boxen/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/puppet-4.3.2/lib/puppet.rb:240:in `override'
/opt/boxen/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/puppet-4.3.2/lib/puppet/configurer.rb:133:in `run'
/opt/boxen/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/puppet-4.3.2/lib/puppet/application/apply.rb:347:in `apply_catalog'
/opt/boxen/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/puppet-4.3.2/lib/puppet/application/apply.rb:274:in `block in main'
/opt/boxen/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/puppet-4.3.2/lib/puppet/context.rb:65:in `override'
/opt/boxen/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/puppet-4.3.2/lib/puppet.rb:240:in `override'
/opt/boxen/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/puppet-4.3.2/lib/puppet/application/apply.rb:225:in `main'
/opt/boxen/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/puppet-4.3.2/lib/puppet/application/apply.rb:170:in `run_command'
/opt/boxen/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/puppet-4.3.2/lib/puppet/application.rb:344:in `block in run'
/opt/boxen/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/puppet-4.3.2/lib/puppet/util.rb:446:in `exit_on_fail'
/opt/boxen/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/puppet-4.3.2/lib/puppet/application.rb:344:in `run'
/opt/boxen/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/puppet-4.3.2/lib/puppet/util/command_line.rb:128:in `run'
/opt/boxen/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/puppet-4.3.2/lib/puppet/util/command_line.rb:72:in `execute'
/opt/boxen/rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/puppet-4.3.2/bin/puppet:5:in `<top (required)>'
/opt/boxen/rbenv/versions/2.1.5/bin/puppet:23:in `load'
/opt/boxen/rbenv/versions/2.1.5/bin/puppet:23:in `<main>'
Error: /Stage[main]/Main/Exec[osx]/returns: change from notrun to 0 failed: Write-Output "Hello from OSX" returned 134 instead of one of [0]
Debug: Class[Main]: Resource is being skipped, unscheduling all events
Debug: Stage[main]: Resource is being skipped, unscheduling all events
Debug: Finishing transaction 70161951724820
Debug: Storing state
Debug: Stored state in 0.00 seconds
Notice: Applied catalog in 1.04 seconds
Debug: Applying settings catalog for sections reporting, metrics
Debug: Finishing transaction 70162003194900
Debug: Received report to process from skylight.local
Debug: Evicting cache entry for environment 'production'
Debug: Caching environment 'production' (ttl = 0 sec)
Debug: Processing report from skylight.local with processor Puppet::Reports::Store

Running it outside of Ruby works fine:

rob@skylight $ sh -c "/usr/local/bin/powershell -NoProfile -NonInteractive -NoLogo -Command - < /var/folders/pg/45bzltkn4wg8kqpllxgzcjcr0000gp/T/puppet-powershell20160813-36623-2801se.ps1"
Hello from OSX

Environment data

> $PSVersionTable
Name                           Value
----                           -----
PSVersion                      6.0.0-alpha
PSEdition                      Core
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}
BuildVersion                   3.0.0.0
GitCommitId                    v6.0.0-alpha.8
CLRVersion
WSManStackVersion              3.0
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
OS-macOS Resolution-Fixed WG-Engine

Most helpful comment

@ferventcoder It makes my ridiculously happy that you tried this. I used to be a Puppet master myself :smile:

All 12 comments

@vors added more to the description.

Also, it's possible that it has something to do with Puppet redirecting output to a file.

Good catch!

Looks like the problem is in this code
https://github.com/PowerShell/PowerShell/blob/9ab60d66213b6f8da3c7543414740d9946f5780b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs#L236

string xdgConfigHomeDefault = Path.Combine(System.Environment.GetEnvironmentVariable("HOME"), ".config", "powershell");
string xdgDataHomeDefault = Path.Combine(System.Environment.GetEnvironmentVariable("HOME"), ".local", "share", "powershell");
string xdgModuleDefault = Path.Combine(xdgDataHomeDefault, "Modules");
string xdgCacheDefault = Path.Combine(System.Environment.GetEnvironmentVariable("HOME"), ".cache", "powershell");

It's possible that env variable HOME is not defined, when PS executed from some non-standard environment. We should add logic to handle it gracefully.

cc @ealexjordan

It's likely this is Linux as well, I just haven't tested it on another platform yet.

@ferventcoder It makes my ridiculously happy that you tried this. I used to be a Puppet master myself :smile:

The same happens when running from .NET Core on Windows.

Might be related to #3011 that @SteveL-MSFT is looking into.

This is still an issue on 6.0.0-alpha17

Confirmed. Puppet is running the PowerShell script without the HOME env var (not sure why yet, will look into it)

Oh...The Exec type strips all user related environment variables prior to invocation i.e. HOME

This is similar to that issue, but that change didn't fix this particular issue. I can repro this easily by unset HOME and trying to start powershell. I'll investigate this.

Was this page helpful?
0 / 5 - 0 ratings