Class: ChefPowerShell::Pwsh

Inherits:
PowerShell show all
Defined in:
lib/chef-powershell/pwsh.rb

Instance Attribute Summary

Attributes inherited from PowerShell

#errors, #result, #verbose

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from PowerShell

#error!, #error?, resolve_wrapper_dll

Constructor Details

#initialize(script, timeout: -1)) ⇒ Object

Run a command under pwsh (powershell core) via FFI This implementation requires the managed dll, native wrapper and a published, self contained dotnet core directory tree to exist in the bindir directory.

Parameters:

  • script (String)

    script to run

  • timeout (Integer, nil) (defaults to: -1))

    timeout in seconds.



47
48
49
50
# File 'lib/chef-powershell/pwsh.rb', line 47

def initialize(script, timeout: -1)
  @dll = Pwsh.dll
  super
end

Class Method Details

.dllObject



82
83
84
85
86
87
88
89
90
91
# File 'lib/chef-powershell/pwsh.rb', line 82

def self.dll
  # This Powershell DLL source lives here: https://github.com/chef/chef-powershell-shim

  # Every merge into that repo triggers a Habitat build and promotion. Running

  # the rake :update_chef_exec_dll task in this (chef/chef) repo will pull down

  # the built packages and copy the binaries to distro/ruby_bin_folder. Bundle install

  # ensures that the correct architecture binaries are installed into the path.

  # Also note that the version of pwsh is determined by which assemblies the dll was

  # built with. To update powershell, those dependencies must be bumped.

  @dll ||= resolve_core_wrapper_dll
end

.resolve_core_wrapper_dllObject

Raises:

  • (LoadError)


21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/chef-powershell/pwsh.rb', line 21

def self.resolve_core_wrapper_dll
  gem_spec = Gem.loaded_specs["chef-powershell"]
  arch = ENV["PROCESSOR_ARCHITECTURE"] || "AMD64"

  if gem_spec
    base = gem_spec.full_gem_path
    dll_path = File.join(base, "bin", "ruby_bin_folder", arch, "shared", "Microsoft.NETCore.App", "8.0.0", "Chef.PowerShell.Wrapper.Core.dll")
    return dll_path if File.exist?(dll_path)
  end

  override = ENV["CHEF_POWERSHELL_BIN"]
  candidate = override && File.join(override, "shared", "Microsoft.NETCore.App", "8.0.0", "Chef.PowerShell.Wrapper.Core.dll")
  return candidate if candidate && File.exist?(candidate)

  dll_path = gem_spec ? File.join(gem_spec.full_gem_path, "bin", "ruby_bin_folder", arch, "shared", "Microsoft.NETCore.App", "8.0.0", "Chef.PowerShell.Wrapper.Core.dll") : File.join("bin", "ruby_bin_folder", arch, "shared", "Microsoft.NETCore.App", "8.0.0", "Chef.PowerShell.Wrapper.Core.dll")
  raise LoadError, "Pwsh Core wrapper DLL not found at #{dll_path}. Populate binaries via rake update_chef_powershell_dlls"
end

Instance Method Details

#exec(script, timeout: -1)) ⇒ Object



52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/chef-powershell/pwsh.rb', line 52

def exec(script, timeout: -1)
  # Note that we need to override the location of the shared dotnet core library

  # location. With most .net core applications, you can simply publish them as a

  # "self-contained" application allowing consumers of the application to run them

  # and use its own stand alone version of the .net core runtime. However because

  # this is simply a dll and not an exe, it will look for the runtime in the shared

  # .net core installation folder. By setting DOTNET_MULTILEVEL_LOOKUP to 0 we can

  # override that folder's location with DOTNET_ROOT. To avoid the possibility of

  # interfering with other .net core processes that might rely on the common shared

  # location, we revert these variables after the script completes.

  original_dml = ENV["DOTNET_MULTILEVEL_LOOKUP"]
  original_dotnet_root = ENV["DOTNET_ROOT"]
  original_dotnet_root_x86 = ENV["DOTNET_ROOT(x86)"]

  ENV["DOTNET_MULTILEVEL_LOOKUP"] = "0"
  gem_spec = Gem.loaded_specs["chef-powershell"]
  if gem_spec
    arch = ENV["PROCESSOR_ARCHITECTURE"] || "AMD64"
    arch_root = File.join(gem_spec.full_gem_path, "bin", "ruby_bin_folder", arch)
    ENV["DOTNET_ROOT"] = arch_root
  end

  @powershell_dll = self.class.resolve_core_wrapper_dll
  super
ensure
  ENV["DOTNET_MULTILEVEL_LOOKUP"] = original_dml
  ENV["DOTNET_ROOT"] = original_dotnet_root
  ENV["DOTNET_ROOT(x86)"] = original_dotnet_root_x86
end