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

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.

https://stackoverflow.com/questions/63100158/powershell-script-runs-locally-fine-but-throws-error-when-executed-via-ansibble?noredirect=1#comment111595021_63100158

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

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.

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: (:slight_smile: , 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: (:slight_smile: [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: (:slight_smile: , 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: (:slight_smile: [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

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.

Thanks a ton. It works as expected now. I appreciate your support.
Have a great day ahead. Stay safe.

Regards,
Darshan