Windows module development question: msiexec acts up when ran through WinRM

Hi, Ansible devel folks,

This week I put together a module that sets the Splunk Universal Forwarder up on Windows machines. One of the nice things Splunk’s done with the forwarder is make some useful flags that you can pass to msiexec.exe that do things like configure the forwarder as a service, but leave it stopped for now and configured to start on next boot - this is perfect for what I want, which is to set the forwarder set up on a base machine image that I can spin up lots of new instances from and see them automagically start feeding their logs to the indexer.

The whole module in its current state is here - https://gist.github.com/kwerey/e20649d24d8dff63bf39db5ecb569fe1. The goal is to let users do their decision-making in the inventory, in ways that are pretty easy to compare & contrast. So you give it a dictionary of key/value pairs to pass as flags, and the module collapses them into the string you see here called $installParameters. Other than that, it’s not doing anything too complex, just downloading and installing:

`

$cmd = “msiexec.exe /i ${installer_path} RECEIVING_INDEXER=‘${indexer_uri}:${indexer_port}’ ${installParameters} AGREETOLICENSE=yes /quiet”
Invoke-Expression $cmd

`

But… Windows seems to be thwarting my plans. If I stick that variable containing the complete command - $cmd - into the module’s return values, I get this:

`
“cmd”: “msiexec.exe /i C:\Users\vagrant\AppData\Local\Temp\SplunkForwarder.msi RECEIVING_INDEXER=‘192.168.2.10:9997’ LAUNCH_SPLUNK=0 AGREETOLICENSE=yes /quiet”

`

If run that command verbatim in an RDP session, I get exactly the intended behaviour: the forwarder installs, shows up in the results of get-service as stopped:

`

PS C:\Users\Administrator> msiexec.exe /i C:\Users\vagrant\AppData\Local\Temp\SplunkForwarder.msi RECEIVING_INDEXER='192.168.2.10:9997' LAUNCH_SPLUNK=0 AGREETOLICENSE=yes /quiet
PS C:\Users\Administrator>
PS C:\Users\Administrator> get-service -name Spl*

Status   Name               DisplayName
------   ----               -----------
Stopped  SplunkForwarder    SplunkForwarder Service

PS C:\Users\Administrator>

`

But when I run through Ansible, splunkd starts up running. Very mysterious. It’s like it’s not reading the flags, even though it pays attention to /quiet and installs successfully.

I’ve had a google around for how the rules might change when logged in to an RDP session versus running remotely over WinRM, but nothing jumped out at me as suspicious. I thought I was on to something when I realised I’d been running my playbook as the Vagrant user, but RDP’d in as Administrator, but running the Ansible as Administrator doesn’t change anything.

Anyone wise in the ways of Powershell got any tips about where I’m going wrong here?

Thanks,
Nikki

Hi Nikki,

Building up command line arguments for powershell to execute can be a trial. On occasion I have had to resort to building an array of the args I want to pass and then running the exe using Start-Process. There’s a page here which describes the many ways you can and some times have to code powershell in order to start external programs: http://social.technet.microsoft.com/wiki/contents/articles/7703.powershell-running-executables.aspx

I would probably set /qn as one of the options, just to make sure msiexec.exe doesn’t try and start a gui.

Sounds like you are a way into getting your module working, but I’d consider making a role to do this. Well worth trying the win_package module to fetch and install the forwarder. I am pretty sure I have used it to install the splunk forwarder successfully in the past, although perhaps without as many extra args. You can also use win_template to modify the splunk config, depending on your needs and win_service to take control of when the forwarder comes up etc.

Hope this helps,

Jon

Thanks, Jon, that’s some really good info.

And, yeah, agreed that a role would be a better format for this. I’d started out trying to make one, hit weird bugs, and gone ‘eh, if I try to do it as a module it’ll probably make it easier to find what’s going wrong’.

And it… kind of has. Getting msiexec to log everything shows me it’s actually getting the right flag, applying it, and then running a bunch of extra stuff later that overrides to switches the ‘now start the service’ option back on. Mysterious, and maybe more a problem with Splunk than with my Ansible skills or the skills of whoever wrote the win_msi module I’d tried and rejected.

Oh well. I learned a lot of extra Powershell skills from trying!

Thanks,
Nikki

I had similar issues when automating the install of the splunk forwarder. I used the win_msi module to install splunk however I couldn’t get around the forwarder starting automatically (behavior was inconsistent). I am a very amateur powershell coder and personally despise the language (if you can even call it that). I ended up pulling the win_msi modules directrly from the devel branch of the extras repo and saw more consistent behavior but still had issues with the server starting. There was a large change in this module WRT to the RunAs parameter and wait logic. Maybe give it a try.

To get around the service starting before i could deploy my config file I didL

`

  • name: splunk | install forwarder
    win_msi:
    path: “{{splunk_installer_loc}}”
    state: present
    wait: yes
    extra_args: "{{ splunk_arg_list | join(’ ')}} "
    creates: “{{splunk_install_dir}}”
    register: splunk_install_status

  • name: splunk | set reboot required flag
    set_fact: win_reboot_required=true
    when: splunk_install_status.reboot_required | default(False)

  • name: splunk | deploy conf files
    win_template: src=“{{ item.file }}”
    dest=“{{ splunk_install_dir}}\{{item.loc}}”
    with_items:

  • { file: ‘server_outputs.conf.j2’, loc: ‘etc\system\local\outputs.conf’ }

  • { file: ‘windows_inputs.conf.j2’, loc: ‘etc\apps\Splunk_TA_windows\local\inputs.conf’ }
    register: splunk_conf_files

  • name: splunk | restart service
    win_service: name=“{{splunk_service_name}}” state=“{{item}}”
    with_items:

  • stopped

  • started
    ignore_errors: yes ##stopping an already stopped service causes errors
    when: splunk_conf_files | changed

`

I’m glad it’s not just me hitting this!

Thanks for the info, Marc. Can I check - in that example, you’re seeing it start automatically, then you’re restarting it so it reads the conf files?

(My original plan to stick it on a base machine image, so it’d be ideal to get it installed without ever starting the service)

It starts automatically…most of the time. I can’t figure exactly what the conditions are when it doesn’t start. if you notice I added a “ignore_errors: yes” to the restart service task. This was to work around the fact that it didn’t always start. As an FYI in ansible 1.9.x, when you call win_service: name=svc state=stopped when svc is already running, the module throws an error

Ah, okay. I wonder if things have changed - using the newest build of the universal forwarder, it seemed to be misbehaving, but misbehaving in pretty consistent ways.

Thanks! & glad you’ve got to some working automation. If I figure out a fix for my extra-specific use case, I’ll report back here with it.

Thanks for this.

One other thing that might be worth mentioning. My understanding is that msiexec communicates with a windows installer service, which actually does the job of doing whatever the msi is supposed to do.
You can wait for msiexec to complete but its perfectly possible for the installer service to be doing things after msiexec has returned.

Might be worth using Resource Monitor or similar to observe what processes are running and see if that might explain any inconsistencies.

Jon

I didn’t know that - nice.

BTW, the other thing I wrote a Powershell module for since starting to work with Windows was one to manage the certificate store. I couldn’t see an existing Ansible way to do this - but I suspect that’s because there’s nice native ways to do this with group policy for machines on a domain, and that most people don’t needs to. If a module for adding certificates to a store would be useful, though, I’d be happy to put together a PR for that.

Cheers,
Nikki

I would say put it out there. My team has written quite a few ad hoc powershell scripts to deal with certs on Windows and it can be a bit daunting. I was able to get a good start on some of these scripts by looking at how certs are handled in http://docs.ansible.com/ansible/intro_windows.html#windows-system-prep

Sorry for the delay following up on this one.

There is actually an as-yet-unmerged windows module for managing certificates here: https://github.com/ansible/ansible-modules-extras/pull/1374

It would be great to get your input on the module and perhaps enhancements (if yours does other things the above doesn’t). If you could test it out and comment on it to say you’ve tested it then that would get it a step closer to getting it merged into Ansible, or if you can enhance it that would be fab too. I agree there’s a place for a module to manage certs since not everyone is on a domain or wants to use group policy.

I know it can be a bit disappointing when someone else has got there first, but if you could take a look and share the wisdom of your experience, we will all get the best code we can.

By the way if you are thinking of creating a PR, its a big help if you can create integration tests. Since this is ansible we talking about integration tests are dead easy to create, since they are just playbooks. Happy to help anyone get started with integration testing, especially for windows stuff.

Hope this helps,

Jon

Nah, it being the weekend is an great reason not to reply to emails! And - no, that’s, cool, I’d much rather there be one good certificates module that’s passed several pairs of eyes than a whole bunch of different ones with different features. I’ve left some thoughts on that PR.

Happy to have a look through integration tests some time - is there anything particularly needed for Windows at the moment?

Best,
Nikki