Powershell script works locally on windows machine but fails when attempted to run via playbook.

44 views
Skip to first unread message

Darshan Yamakanamardi

unread,
Jul 27, 2020, 12:29:32 AM7/27/20
to Ansible Project

Hello All,

I have a PowerShell script that actually takes an argument and stops/starts a service based on the argument passed. 

The script works well on the Windows machine when running locally. But fails when attempted to run via Ansible playbook. 

I am posting a stack overflow link in the email which has full details of the issue. 

Any support on this would be much appreciable. 

Sorry for not including all the details on the email. I believe it is more readable on stack-overflow. 

Regards,
Darshan

jbor...@gmail.com

unread,
Jul 27, 2020, 4:15:43 AM7/27/20
to Ansible Project
So breaking down your error message you get the following PowerShell error(s)

FINDSTR: Bad command line

Stop-Service : Cannot find any service with service name 'ColdFusion 9 - '.
At C:\Users\Administrator\Documents\servicerestart.ps1:7 char:1
    + Stop-Service -Name "ColdFusion 9 - $ServiceName"
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : ObjectNotFound: (ColdFusion 9 - :String) [Stop-Service], ServiceCommandException
    + FullyQualifiedErrorId : NoServiceFoundForGivenName,Microsoft.PowerShell.Commands.StopServiceCommand

Start-Service : Cannot find any service with service name 'ColdFusion 9 - '.
At C:\Users\Administrator\Documents\servicerestart.ps1:8 char:1
    + Start-Service -Name "ColdFusion 9 - $ServiceName"
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : ObjectNotFound: (ColdFusion 9 - :String) [Start-Service], ServiceCommandException
    + FullyQualifiedErrorId : NoServiceFoundForGivenName,Microsoft.PowerShell.Commands.StartServiceCommand

The first error 'FINDSTR: Bad command line' is saying that the call to findstr in your script didn't have a valid argument. My guess is that 'findstr $SITE' is the culprit and '$SITE' isn't actually set to anything hence it's just calling findstr with no arguments. The remaining 2 errors are due to it trying to restart the service 'ColdFusion 9 - ' with not service name at the end because the first command failed to find a value. My advice to you is to keep things simple and stop mixing files and technologies. You should
  • Stop using findstr and focus on pure PowerShell cmdlets
  • Get-Website produces an object so there's no reason to parse text as an output making findstr or other string matching tools unneeded at all
    • Matching strings can also be dangerous as sometimes strings don't match the output you expect, a new entry might shift things to places that you weren't checking before
    • By utilising PowerShell's object handling you shouldn't have to match strings unless the object value itself is a string
  • While it can be possible just embed the script contents in the win_shell task instead of relying on the file being present on the remote host
So what I would do is the following win_shell task

- name: restart website service
  win_shell: |
    $site = Get-Website -Name '*cdu*' | Where-Object { $_.Bindings.Collection.bindingInformation -like '*:80:*' }
    $serviceName = "ColdFusion 9 - {0}" -f $site.Name.Split(' ')[0]

    Stop-Service -Name $serviceName
    Start-Service -Name $serviceName

This will get any site that matches the name '*cdu*' and has a binding on port 80. I'm not sure where the findstr production aspect comes here so if you need any futher help filtering the object I would need to know more information about the environment. I also used the yaml multiline string format 'key: |' where the next indented lines are treated like a normal string value. This pretty much enables you to inline the PowerShell script in the task itself keeping the task closer to what it is actually doing.

Darshan Yamakanamardi

unread,
Jul 29, 2020, 7:44:14 PM7/29/20
to Ansible Project
Thank you very much for your response and for explaining the issue in detail.

 I have tried this and it worked as expected. In the playbook which you provided below, I  would like to define the "cdu" as a variable since I have to identify it dynamically. (Actually, this playbook will be called by a bash script which will pass an extra argument to the playbook) I tried to do that by modifying the playbook bit. 


 - hosts: CF-DEV-B

  gather_facts: no

  vars:

    SITE: cdu

  tasks:

    - name: restart website service

      win_shell: |

       $site = Get-Website -Name "*'{{ SITE }}'*" | Where-Object { $_.Bindings.Collection.bindingInformation -like '*:80:*' }

       $serviceName = "ColdFusion 9 - {0}" -f $site.Name.Split(' ')[0]


       Stop-Service -Name $serviceName

       #Start-Service -Name $serviceName



Also, tried to use the wildcard expression within the curly braces by escaping them but I ended up in the error. 

I am sending the error for your reference. 

 FAILED! => {"changed": true, "cmd": "$site = Get-Website -Name \"*'cdu'*\" | Where-Object { $_.Bindings.Collection.bindingInformation -like '*:80:*' }\n$serviceName = \"ColdFusion 9 - {0}\" -f $site.Name.Split(' ')[0]\n\nStop-Service -Name $serviceName\n#Start-Service -Name $serviceName", "delta": "0:00:00.763000", "end": "2020-07-29 11:31:36.584755", "msg": "non-zero return code", "rc": 1, "start": "2020-07-29 11:31:35.821755", "stderr": "You cannot call a method on a null-valued expression.\r\nAt line:2 char:1\r\n+ $serviceName = \"ColdFusion 9 - {0}\" -f $site.Name.Split(' ')[0]\r\n+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r\n    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException\r\n    + FullyQualifiedErrorId : InvokeMethodOnNull\r\n \r\nStop-Service : Cannot bind argument to parameter 'Name' because it is null.\r\nAt line:4 char:20\r\n+ Stop-Service -Name $serviceName\r\n+                    ~~~~~~~~~~~~\r\n    + CategoryInfo          : InvalidData: (:) [Stop-Service], ParameterBindin \r\n   gValidationException\r\n    + FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,M \r\n   icrosoft.PowerShell.Commands.StopServiceCommand", "stderr_lines": ["You cannot call a method on a null-valued expression.", "At line:2 char:1", "+ $serviceName = \"ColdFusion 9 - {0}\" -f $site.Name.Split(' ')[0]", "+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", "    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException", "    + FullyQualifiedErrorId : InvokeMethodOnNull", " ", "Stop-Service : Cannot bind argument to parameter 'Name' because it is null.", "At line:4 char:20", "+ Stop-Service -Name $serviceName", "+                    ~~~~~~~~~~~~", "    + CategoryInfo          : InvalidData: (:) [Stop-Service], ParameterBindin ", "   gValidationException", "    + FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,M ", "   icrosoft.PowerShell.Commands.StopServiceCommand"], "stdout": "", "stdout_lines": []}



Thank you again for your your help on this. 

Regards,
Darshan

jbor...@gmail.com

unread,
Jul 29, 2020, 11:38:03 PM7/29/20
to Ansible Project
This part '"*'{{ SITE }}'*"' means it will template the raw PowerSHell script as 'Get-WebSite -Name "*'cdu'*" (with the inner single quotes). My guess is you want this to be 'Get-Website -Name "*{{ SITE }}*"'. There's no need to quote a jinja2 block unless you are starting the YAML value with {.

I would test to see once you've fixed the Name part to see if it even found any websites. It's best to make sure that this has returned the site you need before trying to integrate it into the script.

Darshan Yamakanamardi

unread,
Jul 30, 2020, 2:12:26 AM7/30/20
to Ansible Project
Thanks a ton. It works as expected now. I appreciate your support. 
Have a great day ahead. Stay safe. 

Regards,
Darshan
Reply all
Reply to author
Forward
0 new messages