Detect Encoded PowerShell in Wazuh
Build and validate a PCRE2 rule for encoded PowerShell in Wazuh.
Introduction
30 Second Summary
A detection that fires once can still be dangerously misleading. Normal administrative work can look suspicious unless the rule isolates the behavior that matters.
In this project, you will engineer a high-fidelity encoded PowerShell detection in Wazuh. Controlled Sysmon process telemetry proves whether the final rule separates encoded execution from ordinary administration.
What You'll Build
Your final demo shows a high-importance alert for the encoded PowerShell child process while the ordinary harness process stays quiet.
By the end of this project, you'll have:
- A repeatable test harness that prints WAZUH-PLAIN-TEST for the baseline process. It also prints WAZUH-ENCODED-TEST from a harmless encoded child process.
- A high-importance custom alert powered by a two-stage PCRE2 rule. It appears for encoded-command syntax with a Base64-like payload. The plain harness process stays out of the custom alert results.
- A validation record showing the expected hit and miss. It also captures decoded evidence plus MITRE ATT&CK mappings.
- Secret Mission: Add parent-process context so encoded PowerShell launched through cmd.exe receives higher severity.
Are there any prerequisites?
This project uses your existing local lab. You need an operational Wazuh deployment with an enrolled Windows agent.
You also need Sysmon running on Windows plus access to Wazuh custom-rule management. No installation is required.
Before We Start
This checkpoint fixes the detector's success criteria before any telemetry checks begin. Success means rejecting the ordinary PowerShell harness process as a false positive while retaining a child powershell.exe process that uses -EncodedCommand with a valid UTF-16LE Base64 payload.
Verify the Telemetry Pipeline
Your detection goal is clear. A rule can only be trusted after its evidence reaches the manager in the expected shape.
First, you will confirm that Sysmon records process creation on the Windows endpoint.
Next, you will check ingestion in Wazuh. You will finish by confirming custom-rule access.
In this step, get ready to:
- Confirm recent process-creation records in Event Viewer.
- Verify that the Windows Wazuh agent is active.
- Confirm that Wazuh exposes the decoded fields needed by your custom rules.
Confirm Sysmon process creation events
Sysmon Event ID 1 records process creation with the full command line. This gives your future rule the process evidence it needs.
The Sysmon channel sits several folders deep, so it can feel hidden on a first pass.
- Press the Windows key to open Windows search.
- Type Event Viewer into the search box.
- Press Enter to open Event Viewer.
- Expand Applications and Services Logs in the left pane.
- Expand Microsoft.
- Expand Windows.
- Expand Sysmon.
- Select Operational.
You are now viewing the Sysmon event channel where Windows stores its process telemetry.
- Locate a recent row whose Event ID is 1.
- Select the matching event.
- Confirm that its provider is Microsoft-Windows-Sysmon.
You'll see a recent process-creation event produced by Microsoft-Windows-Sysmon.
That first link is solid: the endpoint is producing the process telemetry your detector needs.
No recent process events?
- Confirm that Operational is selected beneath Sysmon.
- Refresh the channel to retrieve the latest records.
- Ask for help with missing Sysmon Event ID 1 records.
Check the Wazuh agent and rule access
The Wazuh agent carries endpoint events into your deployment. Its active status confirms that the endpoint still has a working connection.
- Return to the Wazuh Dashboard for your existing deployment.
- Locate your enrolled Windows agent in the dashboard's agent list.
- Confirm that its status reads Active.
- Select Server management in the left navigation.
- Select Rules.
- Confirm that the page displays the custom-rule management area.
An Active status confirms that the agent is connected. The Rules page confirms that your account can reach the custom-rule workflow.
Your existing Wazuh deployment is ready for custom rule work.
Agent inactive or Rules unavailable?
- Confirm that the Windows endpoint is powered on.
- Confirm that the Wazuh agent service is running on the endpoint.
- Ask your Wazuh administrator to confirm your custom-rule permissions.
- Get help with checking my Wazuh agent and rule access.
Verify the decoded Wazuh fields
A decoder turns a collected Windows event into fields that rules can evaluate. Checking those fields now keeps your detection aligned with your installed environment.
Before you inspect the event, do you think the decoded record contains enough detail for both stages of the future rule?
- Select Threat Hunting from the Threat intelligence section.
- Set the time range to include the recent Event ID 1 record.
- Filter the events to your enrolled Windows agent.
- Filter the results to Sysmon Event ID 1.
- Expand one matching event.
- Expand the data object.
- Confirm that win.eventdata.image is present.
- Confirm that win.eventdata.commandLine is present.
Beneath data, you'll see win.eventdata.image.
You'll also see win.eventdata.commandLine.
That is the pipeline proven: your endpoint telemetry now reaches Wazuh in a rule-ready shape.
Why verify field names?
Custom Wazuh rules match decoder-extracted fields by exact name. Confirming these names in your deployment prevents a valid rule from testing the wrong data.
Fields missing beneath data?
- Confirm that the expanded event belongs to your enrolled Windows agent.
- Confirm that the event is Sysmon Event ID 1.
- Widen the time range to include more recent process events.
- Get help with finding the decoded Sysmon fields in Wazuh.
Your telemetry path is confirmed. Next, you'll create a safe test harness that produces controlled plain and encoded PowerShell cases.
Generate the Test Matrix
You have confirmed that Sysmon process-creation telemetry reaches Wazuh. The decoded event exposes win.eventdata.image plus win.eventdata.commandLine.
A trustworthy detection needs controlled positive and negative cases. This matrix shows whether a rule catches encoded execution while leaving an ordinary PowerShell process alone.
In this step, get ready to:
- Create a harness with one plain baseline plus one harmless encoded child process.
- Run the harness from Windows PowerShell.
- Trace both cases from Event Viewer into Wazuh.
Build the two-case harness
The harness process acts as your negative baseline. It launches a harmless encoded child process as the positive case.
- In your text editor, create Invoke-EncodedPowerShellTest.ps1 inside the folder shown in your Windows PowerShell prompt.
- Copy the code below into Invoke-EncodedPowerShellTest.ps1.
Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
Write-Host "Test start: $(Get-Date -Format o)"
Write-Host 'WAZUH-PLAIN-TEST: this harness process is the negative baseline.'
$command = 'Write-Output "WAZUH-ENCODED-TEST"'
$bytes = [System.Text.Encoding]::Unicode.GetBytes($command)
$encodedCommand = [Convert]::ToBase64String($bytes)
Write-Host "Encoded payload: $encodedCommand"
powershell.exe -EncodedCommand $encodedCommand
What does this harness do?
- The Set-StrictMode command catches mistakes such as references to variables that do not exist.
- The $ErrorActionPreference setting stops the harness when PowerShell encounters an error.
- The first two messages provide an ISO 8601 test time plus a marker for the negative baseline.
- The $command value holds the harmless output instruction.
- The $bytes value holds the command encoded as UTF-16LE bytes.
- The $encodedCommand value holds the Base64 representation accepted by the child process.
- The final line launches a child powershell.exe process with the encoded payload.
- Save Invoke-EncodedPowerShellTest.ps1.
- Check that your editor shows the exact filename with the .ps1 extension.
Does the filename look wrong?
- Confirm that the filename ends with .ps1 instead of .ps1.txt.
- Compare every variable name plus quotation mark with the full-code reference below.
If the file still looks different, help me compare my PowerShell harness with the target file.
✔️ Awesome, I've got everything!
Your saved harness now contains both controlled test cases.
ⓧ I'd like to double check the full code
Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
Write-Host "Test start: $(Get-Date -Format o)"
Write-Host 'WAZUH-PLAIN-TEST: this harness process is the negative baseline.'
$command = 'Write-Output "WAZUH-ENCODED-TEST"'
$bytes = [System.Text.Encoding]::Unicode.GetBytes($command)
$encodedCommand = [Convert]::ToBase64String($bytes)
Write-Host "Encoded payload: $encodedCommand"
powershell.exe -EncodedCommand $encodedCommand
Run the test harness
Windows PowerShell converts the harmless command to UTF-16LE before producing its Base64 representation. The child process decodes that value before printing the positive marker.
Before you run the harness, do you expect the plain marker plus the encoded marker to come from one process or two processes?
- Switch back to the Windows PowerShell prompt for the folder containing your script.
- Run the two-case harness by entering this command:
powershell.exe -NoProfile -File .\Invoke-EncodedPowerShellTest.ps1
What should I see?
The first line begins with Test start: followed by an ISO 8601 timestamp.
The next line includes WAZUH-PLAIN-TEST to identify the harness process as the negative baseline.
A later line begins with Encoded payload: followed by the generated Base64 value.
The child process prints WAZUH-ENCODED-TEST after decoding the harmless command.
That is your controlled matrix working. One run now generates a plain process plus a distinct encoded child process.
- Record the value printed after Test start: here: your ISO 8601 test start time.
Did the harness stop early?
- Confirm that the PowerShell prompt points to the folder containing Invoke-EncodedPowerShellTest.ps1.
- Replace your file with the full-code reference if the output stops before the encoded marker.
For help with another failure, help me diagnose why this PowerShell harness stopped.
Trace both cases through the pipeline
The console proves that the harness ran. The process events prove that your telemetry pipeline captured each case as separate evidence.
Before you refresh the Sysmon log, do you expect the harness plus its child to have identical command lines?
- Return to the Sysmon Operational log in Event Viewer from the previous step.
- Refresh the Operational log.
- Filter the event list for Event ID 1.
- Use your ISO 8601 test start time to locate the new process events.
- Open the event for the plain harness process.
- Confirm that its command line contains powershell.exe -NoProfile -File .\Invoke-EncodedPowerShellTest.ps1.
- Open the child powershell.exe process event.
- Confirm that the child command line contains -EncodedCommand followed by the generated payload.
You will see two recent Event ID 1 records with different command lines. This is the endpoint evidence for your negative plus positive cases.
- Return to the Wazuh event view where you inspected the earlier Sysmon event.
- Search around your ISO 8601 test start time.
- Open the event for the plain harness process.
- Inspect its win.eventdata.image value beneath data.
- Inspect its win.eventdata.commandLine value beneath data.
- Open the event for the encoded child process.
- Inspect its win.eventdata.image value beneath data.
- Inspect its win.eventdata.commandLine value beneath data.
What proves the matrix works?
The plain event shows the harness invocation in win.eventdata.commandLine.
The child event shows powershell.exe in win.eventdata.image.
The child event also shows -EncodedCommand plus the payload in win.eventdata.commandLine.
Both cases now exist as decoded Wazuh evidence that you can test against the same way after every rule change.
You now have a repeatable telemetry generator plus proof that both cases reach Wazuh. Next, you will apply a broad rule and watch the plain baseline expose its false-positive problem.
Observe Broad Rule Noise
Your safe harness now gives Wazuh two Sysmon process events to compare. The ordinary harness remains your negative baseline.
A useful detector must separate ordinary administration from encoded PowerShell execution. This step tests whether the executable image alone provides enough context.
In this step, get ready to:
- Create a temporary custom rule that selects PowerShell process creation events.
- Load the temporary rule into Wazuh.
- Compare its alerts with your expected negative baseline.
Define the broad match
The temporary rule uses PCRE2 to evaluate the decoded process image. Its expression selects any path that ends in powershell.exe.
- Return to Server management in Wazuh Dashboard.
- Select Rules.
- Select the control for adding a custom rule file.
- Enter encoded_powershell_rules.xml as the file name.
- Populate /var/ossec/etc/rules/encoded_powershell_rules.xml by pasting this XML:
<group name="windows,sysmon,powershell,custom_detection,">
<rule id="110100" level="3">
<if_group>sysmon_event1</if_group>
<field name="win.eventdata.image" type="pcre2">(?i)\\powershell\.exe$</field>
<description>PowerShell process creation baseline.</description>
</rule>
</group>
What Does This Rule Match?
- The sysmon_event1 group limits evaluation to process creation events.
- The win.eventdata.image field provides the decoded executable path.
- The (?i) option makes the expression case insensitive.
- The expression requires the image path to end in powershell.exe.
- Level 3 makes every match visible during this temporary test.
- Save /var/ossec/etc/rules/encoded_powershell_rules.xml.
- Confirm the saved file shows rule 110100 at level 3.
Rule File Not Saving?
- Confirm the file name is encoded_powershell_rules.xml.
- Check that every opening XML tag has a matching closing tag.
- Confirm rule 110100 appears only once in the file.
Help me check this custom rule file.
✔️ Awesome, I've got everything!
The temporary XML file is ready for a live test. It contains rule 110100 at level 3.
ⓧ I'd like to double check the full code
<group name="windows,sysmon,powershell,custom_detection,">
<rule id="110100" level="3">
<if_group>sysmon_event1</if_group>
<field name="win.eventdata.image" type="pcre2">(?i)\\powershell\.exe$</field>
<description>PowerShell process creation baseline.</description>
</rule>
</group>
Activate the temporary detector
Saving stores the XML in the custom-rule directory. The Wazuh manager must load that change before new events can match rule 110100.
- Use the Rules page reload control to load the saved change.
- Confirm encoded_powershell_rules.xml remains listed after the reload.
- Switch back to the Windows PowerShell window from earlier.
Before you rerun the harness, do you think an image-only rule can distinguish the ordinary process from the encoded child? Hold that prediction.
- Generate fresh process telemetry by running this command:
powershell.exe -NoProfile -File .\Invoke-EncodedPowerShellTest.ps1
What Does This Command Produce?
- The -NoProfile option keeps the run independent of local profile startup code.
- The harness prints WAZUH-PLAIN-TEST for the negative baseline.
- The child process prints WAZUH-ENCODED-TEST after executing the harmless encoded command.
- Confirm the console displays WAZUH-PLAIN-TEST.
- Confirm the console displays WAZUH-ENCODED-TEST.
Your harness has completed another controlled run. Fresh telemetry is now available for the temporary detector.
Missing a Test Marker?
- Check that the PowerShell prompt points to the folder containing Invoke-EncodedPowerShellTest.ps1.
- Confirm the script still contains both marker strings.
- Confirm the final line still launches powershell.exe -EncodedCommand $encodedCommand.
Help me troubleshoot the harness output.
Find the baseline alert
The console proves both test cases executed. The custom alerts now reveal whether the broad condition preserved the difference between them.
Before you inspect the results, do you think the ordinary harness stayed out of the alert set? Hold that prediction.
- Return to the Wazuh event view from earlier.
- Limit the displayed events to your latest harness run.
- Filter the displayed custom alerts for rule 110100.
- Open the alert whose win.eventdata.commandLine contains Invoke-EncodedPowerShellTest.ps1.
- Check that win.eventdata.image ends in powershell.exe.
- Check that win.eventdata.commandLine identifies the plain harness invocation.
- Compare the harness alert with the encoded-child alert from the same run.
Your temporary detector is working exactly as written. Rule 110100 appears on the ordinary harness process.
The harness is your intended negative baseline. Its alert is a false positive caused by executable-only matching.
Why Did the Baseline Match?
Both test cases use an image path ending in powershell.exe. Rule 110100 never evaluates the command line evidence that separates them.
Can't Find the Plain Harness Alert?
- Use the Rules page reload control again.
- Rerun the harness with the command from the previous substep.
- Confirm the alert's decoded image field ends in powershell.exe.
Help me locate the missing custom alert.
- Record the plain harness alert as a false positive in the checkpoint below.
You have proved that executable-only matching creates noisy alerts. Next, you will make the broad baseline silent before requiring encoded-command evidence.
Build the High-Fidelity Rule
The broad Wazuh rule exposed the exact problem a detection engineer needs to solve. It treated every Windows PowerShell process as equally suspicious.
A silent parent now keeps the Sysmon process selection. A PCRE2 child requires encoded-command evidence before Wazuh creates the alert.
In this step, get ready to:
- Deploy the two-stage custom rule set.
- Trace how each condition narrows Sysmon process events.
- Prove the encoded child alerts without flagging the plain harness.
Turn the baseline into a rule chain
Rule 110100 becomes an invisible selector for PowerShell process creation. Rule 110101 inherits those matched events before testing the command line.
- Return to the Rules page in Wazuh Dashboard.
- Select /var/ossec/etc/rules/encoded_powershell_rules.xml from the custom rules list.
- Replace every line in the file by pasting the complete rule set below:
<group name="windows,sysmon,powershell,custom_detection,">
<rule id="110100" level="0">
<if_group>sysmon_event1</if_group>
<field name="win.eventdata.image" type="pcre2">(?i)\\powershell\.exe$</field>
<description>PowerShell process creation baseline.</description>
</rule>
<rule id="110101" level="12">
<if_sid>110100</if_sid>
<field name="win.eventdata.commandLine" type="pcre2">(?i)\-(?:encodedcommand|e|ea|ec|encodeda|encode|en|enco)\s+[A-Za-z0-9+/]{20,}={0,2}(?:\s|$)</field>
<description>Encoded PowerShell command with a Base64-like payload on $(win.system.computer) by $(win.eventdata.user).</description>
<mitre>
<id>T1059.001</id>
<id>T1027.010</id>
</mitre>
<group>attack,execution,command_obfuscation,</group>
</rule>
</group>
How does the rule chain work?
- Rule 110100 selects events in the sysmon_event1 group.
- The win.eventdata.image condition limits the parent to processes whose image ends in powershell.exe.
- Level 0 keeps that broad selector out of the security event dashboard.
- The if_sid condition makes rule 110101 evaluate the same event after rule 110100 matches.
- The win.eventdata.commandLine condition requires encoded-command syntax with a Base64-like payload.
- Level 12 classifies the child match as a high-importance event.
- Save /var/ossec/etc/rules/encoded_powershell_rules.xml.
- Confirm the saved file includes rule 110101 beneath rule 110100.
The rule file now contains both detection layers. The reload later in this step activates them together.
Having trouble saving the rule file?
- Confirm the final </group> tag remains at the bottom of the file.
- Check that each <rule> element has a matching </rule> tag.
- Compare the backslashes in both PCRE2 expressions with the reference below.
Ask for help with the XML structure.
✔️ Awesome, I've got everything!
Your custom rule file now has the silent parent and high-importance child needed for the regression test.
ⓧ I'd like to double check the full code
<group name="windows,sysmon,powershell,custom_detection,">
<rule id="110100" level="0">
<if_group>sysmon_event1</if_group>
<field name="win.eventdata.image" type="pcre2">(?i)\\powershell\.exe$</field>
<description>PowerShell process creation baseline.</description>
</rule>
<rule id="110101" level="12">
<if_sid>110100</if_sid>
<field name="win.eventdata.commandLine" type="pcre2">(?i)\-(?:encodedcommand|e|ea|ec|encodeda|encode|en|enco)\s+[A-Za-z0-9+/]{20,}={0,2}(?:\s|$)</field>
<description>Encoded PowerShell command with a Base64-like payload on $(win.system.computer) by $(win.eventdata.user).</description>
<mitre>
<id>T1059.001</id>
<id>T1027.010</id>
</mitre>
<group>attack,execution,command_obfuscation,</group>
</rule>
</group>
Trace how the rule narrows events
Each condition removes a source of noise from the event stream. The MITRE ATT&CK mapping records the behaviors represented by the final match.
- Read rule 110100 from its if_group selector through its image condition.
- Follow the if_sid reference from rule 110101 back to rule 110100.
- Inspect the PCRE2 expression attached to win.eventdata.commandLine.
- Check the mitre block for T1059.001.
- Check the same block for T1027.010.
What does the command-line pattern require?
- The (?i) prefix makes the match case-insensitive.
- The switch group accepts the encoded-command forms listed in the expression.
- The \s+ section requires whitespace after the switch.
- The [A-Za-z0-9+/]{20,} section requires at least 20 Base64-like characters.
- The ={0,2} section allows up to two Base64 padding characters.
- The final (?:\s|$) section requires whitespace or the end of the command line.
Reload and test the detection
The saved XML only becomes active after the Wazuh manager loads the change. The same harness now tests whether the tuned chain preserves the positive case without repeating the false positive.
- Return to the Rules page from earlier.
- Use the reload control to load the saved rule changes.
- Wait for the page to confirm that the reload has completed.
- Return to Windows PowerShell from the earlier test run.
Before you rerun the harness, do you expect the two processes to produce the same custom rule result?
- Rerun the detection harness by entering this command:
powershell.exe -NoProfile -File .\Invoke-EncodedPowerShellTest.ps1
What does this command do?
The command starts Windows PowerShell without loading a profile. It runs Invoke-EncodedPowerShellTest.ps1 as a script file.
The harness creates the plain baseline process first. It then launches the harmless encoded child process for the positive case.
You will first see WAZUH-PLAIN-TEST in the console. You will then see WAZUH-ENCODED-TEST from the encoded child.
Harness not running?
- Confirm your current folder contains Invoke-EncodedPowerShellTest.ps1.
- Check that the script still ends with powershell.exe -EncodedCommand $encodedCommand.
- Compare the harness with the file that worked in the previous step.
Ask for help diagnosing the harness run.
- Return to the Sysmon Event ID 1 evidence view from earlier.
- Review the newest records from this harness run.
- Open the encoded child record containing -EncodedCommand.
- Confirm the custom rule ID is 110101.
- Confirm the custom rule level is 12.
Expected regression matrix
- The encoded child process matches custom rule 110101 at level 12.
- The plain harness process does not match custom rule 110101.
Your installed Wazuh version may also generate a stock alert for the encoded process. Judge this regression check by the custom rule ID.
- Inspect win.eventdata.image in the encoded child record.
- Inspect win.eventdata.commandLine in the same record.
- Inspect win.eventdata.user in the same record.
- Inspect win.eventdata.parentImage in the same record.
- Review the plain harness process from the same run.
- Verify that rule 110101 is absent from the plain harness process.
That is the false-positive gap closed. Your custom chain now retains the encoded behavior while suppressing the executable-only baseline.
Your high-fidelity rule now survives a live positive and negative test. Next up, you will package that evidence into a repeatable validation record.
Validate and Package the Detection
Your two-stage Wazuh rule now catches the encoded PowerShell child. It leaves the ordinary harness process out of custom rule 110101.
A detection becomes reusable when its evidence can be checked after every change. A single successful alert cannot provide that history.
You will capture the Sysmon process evidence plus its severity. You will preserve the MITRE ATT&CK rationale for future regression tests.
In this step, get ready to:
- Create a reusable detection-validation record.
- Capture live evidence for both test cases.
- Package the validated detection for future regression tests.
Create the validation record
A validation record defines success before you inspect the next result. That protects each regression test from confirmation bias.
- Create validation-results.md beside Invoke-EncodedPowerShellTest.ps1 by pasting the following template into a new file in your text editor:
# Encoded PowerShell Detection Validation
Rule file: encoded_powershell_rules.xml
Telemetry source: Sysmon Event ID 1
Custom alert rule: 110101
| Test case | Expected 110101 alert | Observed | Evidence checked |
| --- | --- | --- | --- |
| Plain harness process | No | [ ] | Image and command line |
| Valid encoded harmless child command | Yes | [ ] | Rule ID, level, endpoint, user, parent image, command line |
ATT&CK mapping:
- T1059.001: PowerShell
- T1027.010: Command Obfuscation
Final result: [ ] Pass [ ] Fail
What does this record capture?
- The expected-alert column fixes the correct result before each run.
- The observed checkboxes track whether the live result matches the matrix.
- The evidence column names the fields needed to support each conclusion.
- The final result provides one outcome for the complete regression test.
- Save validation-results.md.
- Confirm validation-results.md appears beside Invoke-EncodedPowerShellTest.ps1 in the same folder.
Does the validation file look different?
- Check that the filename ends with .md.
- Compare every table separator with the reference below.
- Ask for help comparing your file with the template.
Good progress. Your positive case plus your negative case now have a durable test contract.
✔️ Awesome, I've got everything!
Your saved validation template is ready for live evidence.
ⓧ I'd like to double check the full code
Compare your complete validation-results.md file with this reference.
# Encoded PowerShell Detection Validation
Rule file: encoded_powershell_rules.xml
Telemetry source: Sysmon Event ID 1
Custom alert rule: 110101
| Test case | Expected 110101 alert | Observed | Evidence checked |
| --- | --- | --- | --- |
| Plain harness process | No | [ ] | Image and command line |
| Valid encoded harmless child command | Yes | [ ] | Rule ID, level, endpoint, user, parent image, command line |
ATT&CK mapping:
- T1059.001: PowerShell
- T1027.010: Command Obfuscation
Final result: [ ] Pass [ ] Fail
What should match?
The headings, matrix, mappings, and blank checkboxes should match this reference exactly.
Capture live Wazuh evidence
A rule ID alone cannot explain why an alert is trustworthy. The expanded event ties the alert to one endpoint plus one process execution.
What makes this evidence reproducible?
- The endpoint identifies the system that generated the event.
- The timestamp identifies the exact process execution.
- The win.eventdata.image field identifies the executable.
- The win.eventdata.commandLine field preserves the encoded-command evidence.
- The win.eventdata.user field identifies the process owner.
- The win.eventdata.parentImage field provides the parent-process context.
- Rule level 12 records the alert severity.
- The T1059.001 plus T1027.010 mappings record the detection rationale.
- Switch back to Wazuh Threat Hunting.
- Focus the time range on your most recent harness run.
- Locate the encoded child event with custom rule 110101.
- Expand the positive alert.
- Read the endpoint value.
- Read the event timestamp.
- Inspect the four decoded process fields listed above beneath the data object.
- Confirm the alert shows rule level 12 plus both ATT&CK mappings.
You now have the full evidence chain behind the positive result. The alert can be traced from endpoint telemetry to detection rationale.
- Search the same time range for the event whose command line contains Invoke-EncodedPowerShellTest.ps1.
- Open the ordinary harness process event.
- Inspect its command line plus its custom-rule details.
You should see the plain harness command line without custom rule 110101. That miss proves the executable-only noise remains suppressed.
What if another alert appears?
Your installed ruleset may also produce a stock PowerShell alert for the encoded process. Judge this package by whether custom rule 110101 follows the expected matrix.
Package a repeatable detection
Repeatability means a fresh execution produces the same hit plus the same miss. This final run tests the package as one complete unit.
- Return to the Windows PowerShell session from earlier.
Before you run the harness again, which process do you expect custom rule 110101 to identify?
- Generate a fresh positive case plus a fresh negative case by running this command:
powershell.exe -NoProfile -File .\Invoke-EncodedPowerShellTest.ps1
What does this run prove?
- The test-start line gives you an ISO 8601 timestamp for the new run.
- The WAZUH-PLAIN-TEST marker identifies the ordinary harness process.
- The WAZUH-ENCODED-TEST output confirms the harmless encoded child executed.
- Record the latest test start time here: your latest ISO 8601 start time.
- Switch back to Wazuh Threat Hunting.
- Restrict the time range around your latest ISO 8601 start time.
- Locate the newest custom rule 110101 alert.
- Search the same run for the plain harness command line.
You should find one custom rule 110101 alert for the encoded child. You should find no custom rule 110101 alert for the plain harness process.
Can't find the fresh custom alert?
- Widen the time range around the recorded test start time.
- Confirm encoded_powershell_rules.xml remains enabled in the Wazuh rules manager.
- Use the Rules page reload control if the manager has not loaded the latest file.
- Ask for help tracing the missing alert.
- Retain Invoke-EncodedPowerShellTest.ps1 as the package's telemetry generator.
- Retain validation-results.md beside the harness as the package's test matrix.
- Leave /var/ossec/etc/rules/encoded_powershell_rules.xml enabled as the package's deployed detector.
That closes the detection-engineering loop. Your rule, test harness, and validation evidence now form a reusable regression package.
Secret mission
Add Parent-Process Context
Your detector already identifies encoded PowerShell execution. Extend it with parent-process context so an encoded command launched through cmd.exe receives a higher-severity alert.
Clean Up Your Resources
Clean Up Your Resources
Your detection package runs inside your existing local Wazuh lab at no additional cost. Choose whether to keep the detection active, pause its alerts, or remove the package.
Resources you used:
- The persistent Wazuh custom rule file at /var/ossec/etc/rules/encoded_powershell_rules.xml.
- The local Invoke-EncodedPowerShellTest.ps1 telemetry generator.
- The local validation-results.md evidence record.
Keep everything running
No action needed. Choose this if you plan to keep testing the detection after Wazuh or Sysmon changes.
- Leave /var/ossec/etc/rules/encoded_powershell_rules.xml enabled for future regression tests.
- Retain Invoke-EncodedPowerShellTest.ps1 as your controlled telemetry generator.
- Keep validation-results.md with the rule file as reproducible evidence.
Pause - I'll come back to this later
Pausing stops the custom alerts while preserving the rule logic and test evidence.
- Return to Server management in Wazuh Dashboard.
- Select Rules.
- Open /var/ossec/etc/rules/encoded_powershell_rules.xml.
- Set rule 110101's level value to 0.
- Set rule 110102's level value to 0.
- Save the custom rule file.
- Use the Rules page reload control to load the paused configuration.
All three custom rules now have level 0. The package remains available for reactivation.
Delete - I don't want to use this again
Deleting this package is permanent. Your existing local lab remains untouched.
- Copy any evidence you want to keep into a separate folder.
- Return to Server management in Wazuh Dashboard.
- Select Rules.
- Locate /var/ossec/etc/rules/encoded_powershell_rules.xml.
- Use the file action for /var/ossec/etc/rules/encoded_powershell_rules.xml to delete it from the manager.
- Use the Rules page reload control to load the change.
The custom rule file should no longer appear in the Rules list. The manager no longer loads rules 110100, 110101, or 110102.
Only the two local package files remain.
- Return to the local detection package folder in your file manager.
- Select Invoke-EncodedPowerShellTest.ps1.
- Delete the selected PowerShell file.
- Select validation-results.md.
- Delete the selected validation record.
- Confirm that neither filename remains in the folder.
Nice Work!
Nice Work!
You made it! Your Wazuh detection package now separates encoded PowerShell execution from ordinary administrative activity using live Sysmon telemetry.
What you learned:
- Built a safe regression harness that produces a plain baseline plus a harmless encoded PowerShell child process.
- Experienced the executable-only false positive before tuning the broad match into a silent parent with a PCRE2 child rule.
- Packaged live validation evidence that proves the expected hit plus miss while documenting the MITRE ATT&CK mappings for T1059.001 plus T1027.010.
- Secret Mission: Added parent-process context so cmd.exe launches reach rule 110102 at level 13 while direct encoded execution remains covered by rule 110101.
Ready to quiz yourself?