Leveraging ansible and powershell together for remote management.
Install
sudo yum install -y python3 python3-pip
sudo alternatives --set python /usr/bin/python3
pip3 install ansible --user
Test PS-Remoting
$pwd = ConvertTo-SecureString -String 'P@@@ssword54321' -AsPlainText -Force
$psCredential = New-Object System.Management.Automation.PSCredential('jmpesp\administrator',$pwd)
Test-WSMan -ComputerName "file4.jmpesp.xyz" -Credential $psCredential -Authentication Negotiate
Configure Ansible Client on the Remote Host
$winHostSession = New-PSSession "file4.jmpesp.xyz" -Credential $psCredential
$scriptBlock = {
$url = "https://raw.githubusercontent.com/ansible/ansible/devel/examples/scripts/ConfigureRemotingForAnsible.ps1"
$file = "$env:temp\ConfigureRemotingForAnsible.ps1"
(New-Object -TypeName System.Net.WebClient).DownloadFile($url, $file)
& $file
winrm set winrm/config/service '@{AllowUnencrypted="true"}'
}
Invoke-Command -Session $winHostSession -ScriptBlock $scriptBlock
Configure Ansible Server
Configure the hosts file:
sudo mkdir /etc/ansible && cd /etc/ansible
sudo touch hosts
Add hosts in this format:
[windows]
file4.jmpesp.xyz
Add configuration for windows connections to hosts in this format (windows is the group name shown in the previous example)
[windows:vars]
ansible_user=administrator@JMPESP.XYZ
ansible_password=P@ssw0rd123
ansible_connection=winrm
ansible_winrm_transport=kerberos
ansible_port=5985
You might need the kerberos client
yum -y install python-devel krb5-devel krb5-libs krb5-workstation
And if you do, you’ll also need to add the python-kerberos wrapper for ansible
pip install pywinrm[kerberos]
Some things you might need if the above errors out:
sudo yum install gcc
sudo yum install python3-devel
sudo yum install krb5-devel
Test with
ansible windows -m win_ping
where “windows” is the group name from above and win_ping is an ansible module that does what you’d expect.
If it fails with:
file4=10.0.0.150 | FAILED! => {
"msg": "winrm or requests is not installed: No module named 'winrm'"
}
You probably need to install the winrm module using: sudo pip install pywinrm
Then you should see:
file4.jmpesp.xyz | SUCCESS => {
"changed": false,
"ping": "pong"
}
Execute PowerShell on hosts via Ansible
Example:
ansible windows -m win_shell -a "get-Service"
Where “windows” is the group name i specified above.
Or, create a scripts folder
sudo mkdir scripts
sudo chown scripts/
Create a simple script for testing on windows admin machine:
Set-Content script1.ps1 -Value 'Get-Service -Name wuauserv | Start-Service'
Copy it to the ansible host:
scp script1.ps1 chad@centos`:/etc/ansible/scripts
On the ansible host, use win_copy module to deploy the script:
[chad@localhost ~]$ ansible windows -m win_copy -a "src=/etc/ansible/scripts/script1.ps1 dest=c:\script.ps1"
file4.jmpesp.xyz | CHANGED => {
"changed": true,
"checksum": "e7117f64e52ee17063f9339c4aab9d7ef4ad77f8",
"dest": "c:\\script.ps1",
"operation": "file_copy",
"original_basename": "script1.ps1",
"size": 44,
"src": "/etc/ansible/scripts/script1.ps1"
}
Run it:
[chad@localhost ~]$ ansible windows -m win_command -a "powershell.exe -ExecutionPolicy bypass -file c:\script.ps1"
file4.jmpesp.xyz | CHANGED | rc=0 >>
Runbook
The real power of ansible.
We create a playbooks folder in the ansible directory on the ansible host to store the playbooks, then use SCP to copy it from our administrative machine to the ansible host.
Sample:
- name: IIS
hosts: windows
tasks:
- name: create folder
win_file:
path: C:\iis
state: directory
- name: create html page
win_copy:
content: |
<html>
<head><title>Ansible Test</title></head>
<body>Some Things</body>
</html>
dest: C:\iis\index.html
- name: install IIS features
win_feature:
name: Web-Server
state: present
include_sub_features: yes
include_management_tools: no
- name: remove default website
win_iis_website:
name: Default Web Site
state: absent
- name: create new IIS website
win_iis_website:
name: IIS Demo
state: started
port: 8080
physical_path: C:\iis
- name: Copy PowerShell scripts
win_copy:
src: /etc/ansible/scripts/iissetup.ps1
dest: 'C:\'
remote_src: no
- name: Execute PowerShell script
win_command: powershell.exe -ExecutionPolicy Bypass -File C:\iissetup.ps1
We execute the playbook with:
ansible-playbook iissetup.yml -vv
On the client side:
You see processes created as children of a winrshost.exe (winrm) parent.
They’ll be sent over as encoded strings
The full command was:
"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -NoProfile -NonInteractive -ExecutionPolicy Unrestricted -EncodedCommand JgBjAGgAYwBwAC4AYwBvAG0AIAA2ADUAMAAwADEAIAA+ACAAJABuAHUAbABsAAoAJABlAHgAZQBjAF8AdwByAGEAcABwAGUAcgBfAHMAdAByACAAPQAgACQAaQBuAHAAdQB0ACAAfAAgAE8AdQB0AC0AUwB0AHIAaQBuAGcACgAkAHMAcABsAGkAdABfAHAAYQByAHQAcwAgAD0AIAAkAGUAeABlAGMAXwB3AHIAYQBwAHAAZQByAF8AcwB0AHIALgBTAHAAbABpAHQAKABAACgAIgBgADAAYAAwAGAAMABgADAAIgApACwAIAAyACwAIABbAFMAdAByAGkAbgBnAFMAcABsAGkAdABPAHAAdABpAG8AbgBzAF0AOgA6AFIAZQBtAG8AdgBlAEUAbQBwAHQAeQBFAG4AdAByAGkAZQBzACkACgBJAGYAIAAoAC0AbgBvAHQAIAAkAHMAcABsAGkAdABfAHAAYQByAHQAcwAuAEwAZQBuAGcAdABoACAALQBlAHEAIAAyACkAIAB7ACAAdABoAHIAbwB3ACAAIgBpAG4AdgBhAGwAaQBkACAAcABhAHkAbABvAGEAZAAiACAAfQAKAFMAZQB0AC0AVgBhAHIAaQBhAGIAbABlACAALQBOAGEAbQBlACAAagBzAG8AbgBfAHIAYQB3ACAALQBWAGEAbAB1AGUAIAAkAHMAcABsAGkAdABfAHAAYQByAHQAcwBbADEAXQAKACQAZQB4AGUAYwBfAHcAcgBhAHAAcABlAHIAIAA9ACAAWwBTAGMAcgBpAHAAdABCAGwAbwBjAGsAXQA6ADoAQwByAGUAYQB0AGUAKAAkAHMAcABsAGkAdABfAHAAYQByAHQAcwBbADAAXQApAAoAJgAkAGUAeABlAGMAXwB3AHIAYQBwAHAAZQByAA==
The encoded part comes to:
&chcp.com 65001 > $null
$exec_wrapper_str = $input | Out-String
$split_parts = $exec_wrapper_str.Split(@("`0`0`0`0"), 2, [StringSplitOptions]::RemoveEmptyEntries)
If (-not $split_parts.Length -eq 2) { throw "invalid payload" }
Set-Variable -Name json_raw -Value $split_parts[1]
$exec_wrapper = [ScriptBlock]::Create($split_parts[0])
&$exec_wrapper
Add custom Powershell to the Ansible Runbook
The example runbook above demonstrated this at the bottom, but its important so here we go again. We copy the script to the target machine, then we execute the script:
- name: Copy PowerShell scripts
win_copy:
src: /etc/ansible/scripts/iissetup.ps1
dest: 'C:\'
remote_src: no
- name: Execute PowerShell script
win_command: powershell.exe -ExecutionPolicy Bypass -File C:\iissetup.ps1