In a previous post, we have shown how Velociraptor and CrowdStrike can work together to speed up the deep‑dive phase of an investigation. One topic left open was containment. When an EDR flags genuinely high‑risk behaviour, isolating the host is often the safest move, and—if your rules are well tuned—doing it automatically is even better. What follows is how we do it: we tag every endpoint, then let Fusion SOAR decide, in real time, whether a particular machine may be quarantined, whether a human must approve, or whether that system is off‑limits altogether. At the end, the user sees a custom pop‑up explaining why the network cable vanished.
Requirements
You need permission to upload custom response scripts and create Fusion SOAR workflows to reproduce the workflow. The most straightforward approach is to give yourself the Real‑Time Responder Administrator
and Workflow Author
roles.
Tagging Systems
Starting off, we define three Falcon grouping tags by hand on which we will decide if containment is allowed or not. SOARGreen
is applied to endpoints that may be isolated automatically when critical detection fires. SOAROrange
marks assets whose isolation must be approved manually: application servers, terminal servers, and any host with a maintenance window. SOARRed
is reserved for systems that are never isolated, such as domain controllers. Tag assignment lives in Host Setup and Management > Host Management
and can be applied by OU, operating system build, or explicit hostname list. Automating this phase is possible for example via the Falcon API or by using a dedicated workflow, but in practice, a spreadsheet, a change‑control ticket, and a two‑person review catch far more classification errors.

Building the Fusion SOAR Workflow
Once tagging is complete, a Fusion SOAR workflow can query those tags and contain a device only when the SOARGreen
tag is present. Create a new workflow under Next‑Gen SIEM > Workflows
.
- Trigger: Alert >
EPP Detection
so that endpoint detections activate the workflow. - First action:
Get device details
; this exposes the host’s tag to subsequent conditions. - Condition: the workflow proceeds only if the tag list contains
FalconGroupingTags/SOARGreen
and the detection severity is Critical or higher. During onboarding, we often lower the threshold once rules have been tuned and false positives have been reduced. - Final actions:
Contain device
, followed byAdd comment to alert
. The containment note is stored in the log repository; the comment becomes part of the detection record.

YAML Export of the Workflow
Below is an exported workflow that you can import directly.
# This is an exported workflow. Editing this file is not recommended.
name: Triggered - Remediation - Network Containment
trigger:
next:
- get_device_details_6647fac2
event: Investigatable/EPP
type: Signal
actions:
add_comment_to_alert_e6158820:
id: 7b77cb5d5ff2651cc51c7c4c610d54d1
properties:
comment: System ${get_device_details_6647fac2.Device.GetDetails.Hostname} isolated by workflow ${Workflow.Definition.Name}, ${Workflow.Execution.ID}.
investigatable_id: ${Trigger.Category.Investigatable.InvestigatableID}
contain_device_33fb3581:
next:
- add_comment_to_alert_e6158820
id: bec9fbeb4999d207937854fd56088107
properties:
device_id: ${Trigger.Category.Investigatable.Product.EPP.Sensor.SensorID}
get_device_details_6647fac2:
next:
- host_tags_includes_falcongroupingtagssoargreen_severity_is_greater_than_or_equal_to_critical_a1fcd203
id: 6265dc947cc2252f74a5f25261ac36a9
properties:
device_id: ${Trigger.Category.Investigatable.Product.EPP.Sensor.SensorID}
conditions:
host_tags_includes_falcongroupingtagssoargreen_severity_is_greater_than_or_equal_to_critical_a1fcd203:
next:
- contain_device_33fb3581
expression: get_device_details_6647fac2.Device.GetDetails.Tags:['FalconGroupingTags/SOARGreen']+Trigger.Category.Investigatable.Severity:>=5
display:
- Host tags includes FalconGroupingTags/SOARGreen
- Severity is greater than or equal to Critical
Adding a Network Containment Notification
Adding a note to the containment action stores the information in the detection record, but the text never reaches the people sitting in front of the keyboard. Hiding detections from the local console is generally desirable—an intruder learns less about the security stack, although he could do so fairly simply—but isolation is different.

When a workstation loses network access, the user needs to know why. A straightforward way to deliver that explanation on Windows is the msg cmdlet, which shows a pop‑up in every active session. Navigate to Host Setup and Management > Response Scripts and Files
, create a new script, and insert a single line such as msg * "CrowdStrike has quarantined this system. Stop work. Keep it on and online. SOC or CERT will message you via Teams when it’s safe. Need help? Call +49 (0) 123 123 12"
.

Saving the script makes it available to the workflow. When the isolation step executes, the script broadcasts the message so that each logged‑in user immediately sees why the endpoint has been taken off the network.

Improving the User Notifications
The workflow now isolates Windows hosts on critical detections, appends a note to the alert, and delivers a transient console message. The next step is to ensure the notice should is visually appealing and remains on‑screen until acknowledged.
The following screenshot shows what we’ve had so far.

Designing a Permanent Pop‑Up with HTA
A quick approach for richer Windows messages is relying for example on BurntToast, but that library requires installation, is Windows‑only, and disappears after a short while, just like msg. Instead, we will create a simple HTML Application (HTA) and launch it through mshta.exe
. The file remains visible until the user closes it, provided a policy does not block the executable.
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>System Isolated by CrowdStrike Falcon</title>
<!-- HTA settings -->
<hta:application
id="CSIsolationNotice"
applicationname="CrowdStrikeIsolationNotice"
border="thin"
caption="yes"
sysmenu="yes"
scroll="no"
singleinstance="yes"
windowstate="maximize" />
<style>
html, body {
height: 100%; /* make flex centering work */
margin: 0;
}
body {
font-family: "Segoe UI", Arial, sans-serif;
background-color: #2d2d30;
color: #ffffff;
display: -ms-flexbox; /* IE10/11 */
display: flex; /* modern */
-ms-flex-pack: center; /* IE */
justify-content: center; /* modern */
-ms-flex-align: center; /* IE */
align-items: center; /* modern */
text-align: center;
}
#wrapper {
max-width: 100%; /* keeps text from stretching too wide */
padding: 1.5em;
}
h1 {
font-size: 2.6em;
text-transform: uppercase;
margin: 0 0 .5em 0;
color: #ff4141;
}
p {
font-size: 1.15em;
margin: .4em 0;
}
button {
margin-top: 1.8em;
font-size: 1em;
padding: .6em 2.4em;
border-radius: 9px;
border: none;
cursor: pointer;
}
</style>
</head>
<body>
<div id="wrapper">
<h1>System Isolated</h1>
<p>Your endpoint has been isolated by <b>CrowdStrike Falcon</b> for security reasons.</p>
<p>Network access is temporarily disabled. Stop work. Keep it on and online.</p>
<p>You will be notified when the isolation has been lifted.</p>
</div>
</body>
</html>
Save the file and test locally with mshta.exe
; a full‑screen dialogue should appear.

Staging the HTA for Delivery
The HTA can reside on a read‑only share that remains reachable even during containment, or it can be uploaded to Host Setup and Management > Response Scripts and Files
so that the workflow deploys it on demand. The second option keeps everything inside Falcon.
The tricky part is creating an interactive process that displays the pop-up for all users. Although it would be possible to create an interactive scheduled task for every interactive user session on the system or create a new service, both are far beyond the scope of this post as, for example, creating a new service that runs interactively in another user session requires some token creation and juggling that we won’t cover in this post. Alternatively, we could run interactive applications with COM, which is beyond this post’s scope too.
The biggest problem is that while it is possible to run MSHTA and deploy the HTA file with a PowerShell script that we can deploy with Falcon, the CrowdStrike agent is running as SYSTEM
, and we need to make sure that every potentially logged-in user sees the isolation pop-up. Therefore, our first idea was to run PsExec for each session:
# Config
$psexec = 'C:\Program Files\CrowdStrike\Rtr\PutRun\PsExec.exe'
$hta = 'C:\Program Files\CrowdStrike\Rtr\PutRun\ cs_containment_notification.hta'
# Ensure PsExec EULA is silently accepted (idempotent)
& $psexec -accepteula | Out-Null
# Collect interactive session IDs (exclude session 0)
$sessionIds = (quser) | ForEach-Object {
if ($_ -match '^\s*>\s*(\S+)\s+(\S+)\s+(\d+)\s') { $matches[3] } # current session gets a leading >
elseif ($_ -match '^\s*(\S+)\s+(\S+)\s+(\d+)\s') { $matches[3] }
} | Where-Object { $_ -ne 0 } | Sort-Object -Unique
# Inject the HTA into every session
foreach ($sid in $sessionIds) {
Start-Process -FilePath $psexec `
-ArgumentList "-i $sid mshta.exe `"$hta`"" `
-NoNewWindow -Wait
}
Deploying ServiceUI.exe in Place of PsExec
Because the ADMIN$
share is disabled in our environment, PsExec cannot run; it relies on that share to copy psexesvc.exe
and create the transient PSEXESVC
service. We therefore switch to the Microsoft Deployment Toolkit utility ServiceUI.exe
. A typical command looks like "C:\Program Files\Microsoft Deployment Toolkit\Templates\Distribution\Tools\x64\ServiceUI.exe" -process:explorer.exe "C:\Windows\System32\mshta.exe" "\"C:\Program Files\CrowdStrike\Rtr\PutRun\cs_containment_notification.hta\""
.
In this case, ServiceUI.exe
enumerates every session that owns explorer.exe
and launches mshta.exe within each one, passing the HTA notification file as an argument so that the isolation banner appears for every logged‑in user. To make this work inside Falcon, upload ServiceUI.exe
under Host Setup and Management > Response Scripts and Files > Put Files
and extend the workflow so that it writes both ServiceUI.exe
and the HTA to the target system.

Handling Repeated Executions Without File‑Name Collisions
A second obstacle appears once the workflow triggers more than once. Falcon refuses to overwrite files already in C:\Program Files\CrowdStrike\Rtr\PutRun
, so a subsequent run fails when it tries to write the HTA or ServiceUI.exe
again. The fix is placing the payloads in a unique sub‑folder created dynamically for each execution.
A short PowerShell helper script solves the problem. It receives the workflow‑execution ID as an input parameter, verifies that the base PutRun directory exists, and then creates a child folder whose name is the execution ID, which guarantees uniqueness across runs.
$basePath = 'C:\Program Files\CrowdStrike\Rtr\PutRun'
# Ensure the CrowdStrike put and run directory exists
if (-not (Test-Path $basePath)) {
New-Item -Path $basePath -ItemType Directory -Force | Out-Null
}
# Pull workflow execution ID
try {
$workflowID = $args[0] | ConvertFrom-Json | Select-Object -ExpandProperty workflow_id
}
catch {
exit 1
}
if (-not $workflowID) {
exit 1
}
# Create alert specific directory
$workflowPath = Join-Path $basePath $workflowID
if (-not (Test-Path $workflowPath)) {
New-Item -Path $workflowPath -ItemType Directory -Force | Out-Null
}
The script expects its parameter in JSON form. A minimal input schema passes the value from Fusion SOAR:
{
"$schema": "https://json-schema.org/draft-07/schema",
"properties": {
"workflow_id": {
"type": "string"
}
},
"required": [
"workflow_id"
],
"type": "object",
"description": "This generated schema may need tweaking. In particular format fields are attempts at matching workflow field types but may not be correct."
}
Include this setup step immediately before the Put File actions. The HTA and ServiceUI.exe
are then written to C:\Program Files\CrowdStrike\Rtr\PutRun\<workflow_exec_id>
instead of the parent folder, so the workflow can run any number of times without encountering write errors.

After the helper script has created C:\Program Files\CrowdStrike\Rtr\PutRun\
, edit each Put File action so that its Target directory field is the variable ${Workflow.Execution.ID}
appended to the base path. Both the HTA and ServiceUI.exe
are now copied into the fresh sub‑folder, guaranteeing that no overwrite error arises when the workflow fires again.
Launching mshta.exe in Every Active Session
Passing complex strings through the Put and Run action proved brittle because ServiceUI.exe
needs quoted arguments, so a short PowerShell wrapper becomes the last workflow step. The wrapper receives the execution ID via the same JSON schema used earlier, builds the absolute paths for ServiceUI.exe
, mshta.exe
, and the HTA, verifies that each file exists, enumerates all interactive sessions, and finally starts ServiceUI.exe
in every one.
# Pull workflow execution ID
try {
$workflowID = $args[0] | ConvertFrom-Json | Select-Object -ExpandProperty workflow_id
}
catch {
exit 1
}
$basePath = 'C:\Program Files\CrowdStrike\Rtr\PutRun'
$alertPath = Join-Path -Path $basePath -ChildPath $workflowID
$serviceUI = 'ServiceUI.exe'
$htaFile = 'cs_containment_notification.hta'
# Build paths safely
$serviceUIPath = Join-Path -Path $alertPath -ChildPath $serviceUI
$htaFilePath = Join-Path -Path $alertPath -ChildPath $htaFile
$mshtaPath = "$env:WINDIR\System32\mshta.exe"
# Sanity checks
foreach ($item in $serviceUIPath, $mshtaPath, $htaFilePath) {
if (-not (Test-Path $item)) {
Write-Error "Required file not found: $item"
exit 1
}
}
# Get all active sessions
$sessionIds = @(quser 2>$null) |
Select-String '\bActive\b' |
ForEach-Object { ($_ -replace '\s{2,}', ',').Trim(',') } |
ConvertFrom-Csv -Header 'User','Session','ID','State','Idle','Logon' |
Select-Object -ExpandProperty ID -Unique
# Launch
foreach ($sid in $sessionIds) {
# Build ServiceUI's argument list
$svcArgs = @(
"-session:$($sid)"
"`"$mshtaPath`""
"`\`"$htaFilePath`\`""
) -join ' '
Start-Process -FilePath $serviceUIPath -ArgumentList $svcArgs -WindowStyle Hidden
}
Once this script runs, every user logged on and sees the full‑screen HTA that explains the containment action will stay open until closed manually. Our final workflow:

Final Thoughts
Should a hardening rule prevent the execution of mshta.exe, convert the notification to plain HTML, and start a browser that remains functional during isolation, for example, "C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe" "file:///C:/Program%20Files/CrowdStrike/Rtr/PutRun//cs_containment_notification.html"
.
The overall workflow now isolates the host, copies the notification assets into a collision‑free directory, and launches an unmistakable, persistent banner for every active session, without relying on the ADMIN$ share, PsExec, or mshta.exe.