Dovetail is a robust PowerShell-based tool for remote script execution and management over WinRM. Originally developed for the Collegiate Cyber Defense Competition (CCDC), it allows for asynchronous deployment of PowerShell scripts across multiple Windows hosts and centralized collection of execution results.
- Parallel Execution: Deploy scripts across a range of Windows hosts simultaneously
- WinRM Protocol: Utilization of Microsoft's stable remoting protocol over HTTP (5985) or HTTPS (5986)
- Domain & Non-Domain Support: Client system can be a domain-joined system or disjoint
- Session Management: Create and repair WinRM sessions
- Flexible Targeting: Include or exclude hosts for on-demand targeting
- Organized and Thorough Output: Asynchronous output collection and organization regardless of blocked execution
- Windows PowerShell 5.1 or later
- WinRM enabled on target hosts (port 5985/5986) and client (winrm qc)
Setup WinRM if it has never been done before and allow the client to trust all remote hosts:
winrm qc
Set-Item WSMan:\localhost\Client\TrustedHosts -Value '*'ksetup /addkdc DOMAIN.COM dc.domain.comAdd entries to your C:\Windows\System32\etc\drivers\hosts.txt file or set your DNS server to the DC:
Hostname.domain.com #.#.#.#
Domain.com #.#.#.#
Finally, use the "non-domain" commands below with a target file of hostnames/FQDNs
Create a targets file with newline separated hostnames or IPs.
172.16.175.101
172.16.175.60
172.16.175.61
172.16.175.104
myhost.domain.com
# Connect
.\Dovetail.ps1 -Connect -NonDomain -Hosts targets.txt
# Repair broken sessions
.\Dovetail.ps1 -Connect -NonDomain -Hosts targets.txt -Repair
# Execute
.\Dovetail.ps1 -Script .\whoami.ps1
# Execute with custom function call (untested)
.\Dovetail.ps1 -Script .\utils.ps1 -FunctionCall "Get-SystemInventory"
# Target specific hosts
.\Dovetail.ps1 -Script .\whoami.ps1 -Include 172.16.175.101, 172.16.175.104# Connect to all Windows hosts in the domain
.\Dovetail.ps1 -Connect
# Repair broken sessions
.\Dovetail.ps1 -Connect -Repair
# Execute
.\Dovetail.ps1 -Script .\whoami.ps1
# Execute with custom function call (untested)
.\Dovetail.ps1 -Script .\utils.ps1 -FunctionCall "Get-SystemInventory"
# Target specific hosts
.\Dovetail.ps1 -Script .\whoami.ps1 -Include 172.16.175.101, 172.16.175.104PowerShell is simultaneously the best and worst language to implement this type of tool. Native WinRM session capabilities are a huge plus. However, you can't force/override certain operations such as the quick cleanup of broken/decomissioned sessions. If you are frequently reconnecting/creating sessions you may notice the line Get-PSSession | Remove-PSSession can take a long time to complete.
Async jobs are managed two different ways.
- Port scanning jobs are managed using
Wait-Job, which is the normal and recommended way to collect jobs. - Script execution jobs are collected manually (hoepfully race condition free) by polling their status every few milliseconds.
The reason for this is that Wait-Job requries all jobs to finish to then proceed onto the next instruction such as Receive-Job. The time delta between script job completion may be rather significant when executing long or complex scripts across a variety of hosts, meaning one host may severely delay/block script output for all other finished hosts. Hence, a "receive as finished" approach was implemented.