diff --git a/CHANGELOG.md b/CHANGELOG.md index 482e8a9ec15..258465a15e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -274,6 +274,7 @@ Ansible Changes By Release * win_reg_stat * win_region * win_say + * win_service_stat * win_shortcut * win_tempfile - xbps diff --git a/lib/ansible/modules/windows/win_service_stat.ps1 b/lib/ansible/modules/windows/win_service_stat.ps1 new file mode 100644 index 00000000000..57a010ed982 --- /dev/null +++ b/lib/ansible/modules/windows/win_service_stat.ps1 @@ -0,0 +1,80 @@ +#!powershell +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see . + +# WANT_JSON +# POWERSHELL_COMMON + +$ErrorActionPreference = "Stop" + +$params = Parse-Args $args -supports_check_mode $true +$check_mode = Get-AnsibleParam -obj $params "_ansible_check_mode" -type "bool" -default $false + +$name = Get-AnsibleParam -obj $params -name 'name' -type 'str' -failifempty $true + +$result = @{ + changed = $false +} + +$svc = Get-Service -Name $name -ErrorAction SilentlyContinue +if ($svc) { + $wmi_svc = Get-WmiObject Win32_Service | Where-Object { $_.Name -eq $svc.Name } + + # Delayed start_mode is in reality Automatic (Delayed), need to check reg key for type + $delayed_key = "HKLM:\System\CurrentControlSet\Services\$name" + try { + $delayed = ConvertTo-Bool ((Get-ItemProperty -Path $delayed_key).DelayedAutostart) + } catch { + $delayed = $false + } + $actual_start_mode = $wmi_svc.StartMode.ToString().ToLower() + if ($delayed -and $actual_start_mode -eq 'auto') { + $actual_start_mode = 'delayed' + } + + $existing_depenencies = @() + $existing_depended_by = @() + if ($svc.ServicesDependedOn.Count -gt 0) { + foreach ($dependency in $svc.ServicesDependedOn.Name) { + $existing_depenencies += $dependency + } + } + if ($svc.DependentServices.Count -gt 0) { + foreach ($dependency in $svc.DependentServices.Name) { + $existing_depended_by += $dependency + } + } + + $description = $wmi_svc.Description + if ($description -eq $null) { + $description = "" + } + + $result.exists = $true + $result.name = $svc.Name + $result.display_name = $svc.DisplayName + $result.state = $svc.Status.ToString().ToLower() + $result.start_mode = $actual_start_mode + $result.path = $wmi_svc.PathName + $result.description = $description + $result.username = $wmi_svc.startname + $result.desktop_interact = (ConvertTo-Bool $wmi_svc.DesktopInteract) + $result.dependencies = $existing_depenencies + $result.depended_by = $existing_depended_by +} else { + $result.exists = $false +} + +Exit-Json $result diff --git a/lib/ansible/modules/windows/win_service_stat.py b/lib/ansible/modules/windows/win_service_stat.py new file mode 100644 index 00000000000..34c3b7c25d3 --- /dev/null +++ b/lib/ansible/modules/windows/win_service_stat.py @@ -0,0 +1,104 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see . + +# this is a windows documentation stub. actual code lives in the .ps1 +# file of the same name + +ANSIBLE_METADATA = {'status': ['preview'], + 'supported_by': 'community', + 'version': '1.0'} + +DOCUMENTATION = r''' +--- +module: win_service_stat +version_added: "2.3" +short_description: returns information about a Windows service +description: +- This module will return information about a service such as whether it + exist or not as well as things like the state, startup type and more. +options: + name: + description: The name of the Windows service to get info for. + required: True +author: Jordan Borean (@jborean93) +''' + +EXAMPLES = r''' +- name: get details on a service + win_service_stat: + name: spooler + register: spooler_info +''' + +RETURN = r''' +exists: + description: whether the service exists or not + returned: success + type: boolean + sample: true +name: + description: the service name or id of the service + returned: success and service exists + type: string + sample: CoreMessagingRegistrar +display_name: + description: the display name of the installed service + returned: success and service exists + type: string + sample: CoreMessaging +status: + description: the current running status of the service + returned: success and service exists + type: string + sample: stopped +start_mode: + description: the startup type of the service + returned: success and service exists + type: string + sample: manual +path: + description: + returned: success and service exists + type: string + sample: C:\Windows\system32\svchost.exe -k LocalServiceNoNetwork +description: + description: the path to the executable of the service + returned: success and service exists + type: string + sample: Manages communication between system components. +username: + description: the username that runs the service + returned: success and service exists + type: string + sample: LocalSystem +desktop_interact: + description: Whether the current user is allowed to interact with the desktop + returned: success and service exists + type: boolean + sample: False +dependencies: + description: A list of dependencies the service relies on + returned: success and service exists + type: List + sample: False +depended_by: + description: A list of dependencies this service relies on + returned: success and service exists + type: List + sample: False +''' diff --git a/test/integration/targets/win_service_stat/aliases b/test/integration/targets/win_service_stat/aliases new file mode 100644 index 00000000000..ee0ed5974e9 --- /dev/null +++ b/test/integration/targets/win_service_stat/aliases @@ -0,0 +1 @@ +windows/ci/group2 diff --git a/test/integration/targets/win_service_stat/tasks/main.yml b/test/integration/targets/win_service_stat/tasks/main.yml new file mode 100644 index 00000000000..daf7d501e0d --- /dev/null +++ b/test/integration/targets/win_service_stat/tasks/main.yml @@ -0,0 +1,86 @@ +--- +# Until changes are merged into win_service to create a new module we will need +# to do it ourselves +- name: stop test services before test + win_command: sc stop TestService + ignore_errors: True + +- name: make sure we clean up any test services + win_command: sc delete TestService + ignore_errors: True + +- name: get stats on service that doesn't exist + win_service_stat: + name: TestService + register: missing_service + +- name: assert missing service doesn't exist + assert: + that: + - not missing_service|changed + - missing_service.exists == False + +- name: create a new test service + win_command: powershell.exe "New-Service -Name TestService -BinaryPathname C:\Windows\System32\snmptrap.exe" + +- name: get stats on newly created service + win_service_stat: + name: TestService + register: new_service + +- name: assert new service results are what we expect + assert: + that: + - not new_service|changed + - new_service.exists == True + - new_service.depended_by == [] + - new_service.dependencies == [] + - new_service.description == "" + - new_service.desktop_interact == False + - new_service.display_name == 'TestService' + - new_service.name == 'TestService' + - new_service.path == 'C:\Windows\System32\snmptrap.exe' + - new_service.start_mode == 'auto' + - new_service.state == 'stopped' + - new_service.username == 'LocalSystem' + +- name: change details about the service + win_command: powershell.exe "Set-Service -Name TestService -DisplayName NewDisplayName -Description description -StartupType Manual" + +- name: get stats on changed service + win_service_stat: + name: TestService + register: changed_service + +- name: assert changed service details have changed + assert: + that: + - not changed_service|changed + - changed_service.exists == True + - changed_service.description == 'description' + - changed_service.display_name == 'NewDisplayName' + - changed_service.start_mode == 'manual' + +- name: start the service + win_service: + name: TestService + state: started + register: started_service + +- name: get stats on started service + win_service_stat: + name: TestService + register: started_service + +- name: assert service stats is started + assert: + that: + - started_service.state == 'running' + +# TODO: Change other service info through win_service once we can do it with a module + +- name: stop test services before deleting + win_command: sc stop TestService + +- name: clean up test service at the end + win_command: sc delete TestService diff --git a/test/integration/test_win_group2.yml b/test/integration/test_win_group2.yml index 5eae464ec35..73ecbf8d9b8 100644 --- a/test/integration/test_win_group2.yml +++ b/test/integration/test_win_group2.yml @@ -13,3 +13,4 @@ - { role: win_package, tags: test_win_package } - { role: win_path, tags: test_win_path } - { role: win_shortcut, tags: test_win_shortcut } + - { role: win_service_stat, tags: test_win_service_stat }