Ask Your Question

How can I modify how msutter DSC logs Powershell exceptions?

asked 2015-04-09 15:39:52 -0500

Paul Chernoch gravatar image

updated 2015-04-09 15:42:14 -0500

Using the xRemoteFile DSC resource wrapper provided in the msutter DSC module, I have this difficulty. If the source URL points to a file that does not exist (404 error) then I get no error or warning reported. No file created, no error reported. Not what I desire.

What I tried to do is modify set_dsc_configuration.erb in the following way:

$err = ''
$set_return = Start-DscConfiguration -Path $LCMConfigFolder -Wait -Verbose -ErrorVariable err
if ($err -ne '') { $set_return = $False; }

I added the "-ErrorVariable" switch and logic concerning $err. The variable "err" ends up holding the exception text (the 404 error). However, this return value of false (and I also tried using the word "Error" instead) has no effect on the puppet enterprise log. If I look in file dsc_configuration_provider.rb, I find this code:

  def exists?
    Puppet.debug "\n" + ps_script_content('test')
    output = powershell(ps_script_content('test'))
    if ['true','false'].include?(output.to_s.strip.downcase)
      check = (output.to_s.strip.downcase == 'true')
      Puppet.debug "Dsc Resource Exists?: #{check}"
      Puppet.debug "dsc_ensure: #{resource[:dsc_ensure]}"
      Puppet.debug "ensure: #{resource[:ensure]}"

  def create
    Puppet.debug "\n" + ps_script_content('set')
    output = powershell(ps_script_content('set'))
    Puppet.debug output

  def destroy
    Puppet.debug "\n" + ps_script_content('set')
    output = powershell(ps_script_content('set'))
    Puppet.debug output

Where is the function "powershell" defined? How does it work? Does it combine stderr and stout into a single stream and return it? Does it just return the error code? Or just return $True or $False? I would want to rewrite this function to test the powershell invocation to see if an exception was thrown and call Puppet.warning or something like that. All I want to do is make sure that I can log the fact that there was a 404 error.

edit retag flag offensive close merge delete


The naive approach: cd into the directory, where all the module's files are located (metadata.json and so on). Then grep -Ris -m1 powershell ./* will give you all files where powershell is used and one of them should be where it is defined.

Kai Burghardt gravatar imageKai Burghardt ( 2015-04-09 19:51:10 -0500 )edit

I used Notepad++ to search all files in the msutter dsc source directory (and the puppet source as well) and turned up nothing.

Paul Chernoch gravatar imagePaul Chernoch ( 2015-04-10 07:28:14 -0500 )edit

2 Answers

Sort by ยป oldest newest most voted

answered 2016-02-03 08:37:55 -0500

Puppet (with the permission of msutter) took over development of the DSC module and have added some features and improvements that might help your situation here. Specifically Invoke-DscResource is used instead of Start-DscConfiguration which means any error that occurs during a DSC Resource execution is bubbled up to Puppet and logged in the execution run. This will address your problem seeing the errors in the execution log.

edit flag offensive delete link more

answered 2015-04-10 15:45:09 -0500

Paul Chernoch gravatar image

updated 2015-04-10 15:48:18 -0500

I found where "powershell" is defined. In file dscproviderhelpers.rb, this line does the magic:

    provider.commands :powershell =>
    if File.exists?("#{ENV['SYSTEMROOT']}\\sysnative\\WindowsPowershell\\v1.0\\powershell.exe")
    elsif File.exists?("#{ENV['SYSTEMROOT']}\\system32\\WindowsPowershell\\v1.0\\powershell.exe")

This calls the method "commands" which is defined in provider.rb (puppet framework code):

  def self.commands(command_specs)
    command_specs.each do |name, path|
      has_command(name, path)

That code checks if the executable file passed in as a parameter exists. The type is considered "confined" to systems that have the program present. If the program exists, a command is generated for it and magically added as a method to the type. This method will execute the program and pass it all necessary parameters. The CommandDefiner does all that work.

  def self.has_command(name, path, &block)
    name = name.intern
    command = CommandDefiner.define(name, path, self, &block)

    @commands[name] = command.executable

    # Now define the class and instance methods.
    create_class_and_instance_method(name) do |*args|
      return command.execute(*args)
edit flag offensive delete link more

Your Answer

Please start posting anonymously - your entry will be published after you log in or create a new account.

Add Answer

Question Tools

1 follower


Asked: 2015-04-09 15:39:52 -0500

Seen: 276 times

Last updated: Apr 10 '15