Skip to content

PowerShell rules: expand diagnostic coverage (flags + Tier 1 cmdlets)#105

Open
jonchun wants to merge 4 commits into
mainfrom
feat/powershell-rules-coverage
Open

PowerShell rules: expand diagnostic coverage (flags + Tier 1 cmdlets)#105
jonchun wants to merge 4 commits into
mainfrom
feat/powershell-rules-coverage

Conversation

@jonchun

@jonchun jonchun commented Apr 21, 2026

Copy link
Copy Markdown
Collaborator

Summary

Follow-up to v0.7.0 (docs/plans/.../v2). Review of the current PowerShell rules against typical Windows diagnostic sessions surfaced coverage gaps — real agent patterns that get rejected with "unknown flag" or "command not available" despite being legitimate read-only operations.

Safety unchanged — no grammar relaxation, no new cmdlet that mutates state, no new types in the PSStaticCall whitelist. Every addition is a YAML-level allow expansion.

What's added

8 new cmdlets (Tier 1 from review):

  • Get-Member — pipeline introspection (Get-Process | Get-Member)
  • ConvertFrom-Json / ConvertFrom-Csv — parsing back (we had the -To direction)
  • Get-NetIPConfiguration — consolidated IP/gateway/DNS per interface
  • Get-DnsClientServerAddress — DNS server list
  • Get-Uptime — elapsed time since boot
  • Get-FileHash — hash verification
  • Get-TimeZone — current timezone / list available

Flag additions to 13 existing cmdlets. Biggest gaps closed:

  • Get-Content -Raw — read whole file as string (the most common read pattern)
  • Select-String -Context — grep-style pre/post lines (-A/-B equivalent)
  • Get-ChildItem -Force -File -Directory -Include -Exclude -Depth
  • Get-WinEvent -ProviderName -FilterXPath -ListLog -ListProvider
  • Get-Process -IncludeUserName -Module
  • Select-Object -Unique -Skip -Index, Sort-Object -Unique -Top -Bottom
  • Get-NetTCPConnection -RemoteAddress -RemotePort -OwningProcess
  • Measure-Object -Line -Word -Character (how you count lines without wc)
  • Full list in the commit message

Corpus harness

19 new entries under parser/testdata/corpus/baseline.yaml exercising the additions. One surfaces a known gap — Get-NetTCPConnection -RemoteAddress 10.0.0.1 still fails because IP literals don't lex (captured under the existing ip-address-literal reason tag for a future grammar workstream).

Test plan

  • go test ./... -count=1 — all packages green
  • go test ./... -race -count=1 — no races
  • go vet ./... — clean
  • go test ./parser/ -run FuzzParsePowerShell -fuzz=... -fuzztime=60s — 10.9M iters, no safety invariant breaks
  • Round-trip property test passes
  • Manual replay against a Windows target (fast-follow)

Small test-helper fix

quoteForTest in the corpus round-trip helper used to treat , as quote-free, which broke re-parse when a string arg was literally just , (e.g., ConvertFrom-Csv -Delimiter ','). Tightened to require the char be alphanumeric / path-style. Id,Name round-trip still works — it just gets wrapped as a single-quoted string on the reconstruction pass.

Release

No version bump needed — additive. Tag v0.7.1 after merge (patch bump from v0.7.0).

jonchun added 4 commits April 21, 2026 12:34
Follow-up to v0.7.0. Fills coverage gaps surfaced by reviewing the
PowerShell rules against typical Windows diagnostic sessions. Nothing
in this change relaxes safety — every addition is a read-only cmdlet
or a flag that doesn't mutate state.

8 new cmdlet manifests:
- Get-Member         — pipeline introspection
- ConvertFrom-Json   — parse JSON output (companion to ConvertTo-Json)
- ConvertFrom-Csv    — parse CSV output
- Get-NetIPConfiguration     — consolidated IP/gateway/DNS per iface
- Get-DnsClientServerAddress — DNS server list
- Get-Uptime         — elapsed time since boot
- Get-FileHash       — file hash verification
- Get-TimeZone       — current timezone / list available

High-value flag additions to 13 existing cmdlets:
- Get-Content:      -Raw, -Encoding, -Stream, -Delimiter, -Force
- Select-String:    -Context, -CaseSensitive, -AllMatches, -NotMatch,
                    -Quiet, -List, -LiteralPath, -Include, -Exclude,
                    -Encoding
- Get-ChildItem:    -Force, -File, -Directory, -Hidden, -ReadOnly,
                    -System, -Include, -Exclude, -Depth, -FollowSymlink
- Get-WinEvent:     -ProviderName, -FilterXPath, -FilterXml,
                    -ComputerName, -ListLog, -ListProvider, -Oldest,
                    -Path, -Force
- Get-EventLog:     -After, -Before, -Source, -Message, -Index,
                    -InstanceId, -List, -ComputerName, -UserName,
                    -AsBaseObject
- Select-Object:    -Unique, -Skip, -SkipLast, -Index, -ExcludeProperty
- Sort-Object:      -Unique, -Top, -Bottom, -CaseSensitive, -Stable,
                    -Culture
- Get-Process:      -IncludeUserName, -Module, -FileVersionInfo,
                    -ComputerName, -InputObject
- Get-Service:      -DependentServices, -RequiredServices, -Include,
                    -Exclude, -ComputerName
- Get-NetTCPConnection: -LocalAddress, -RemoteAddress, -RemotePort,
                    -OwningProcess, -AppliedSetting
- Get-NetAdapter:   -InterfaceIndex, -InterfaceAlias,
                    -InterfaceDescription, -Physical, -Virtual,
                    -IncludeHidden
- Measure-Object:   -Line, -Word, -Character, -StandardDeviation,
                    -AllStats, -IgnoreWhiteSpace
- Format-Table:     -Wrap, -GroupBy, -HideTableHeaders, -RepeatHeader,
                    -View, -ShowError
- Format-List:      -GroupBy, -View, -ShowError
- Test-Path:        -Filter, -Include, -Exclude, -IsValid, -OlderThan,
                    -NewerThan

Biggest single wins: Get-Content -Raw (read file as string) and
Select-String -Context (log triage with pre/post lines).

Manifest count bumps from 280 to 288. Corpus harness gains 19 new
entries exercising the additions (including one more ip-address-literal
case since Get-NetTCPConnection -RemoteAddress IP still won't lex —
tracked for a future workstream). FuzzParsePowerShell ran 10.9M
iterations clean; round-trip property test passes.

Fixed a corpus-test helper bug along the way: quoteForTest used to
treat `,` as a quote-free char, which meant a string arg of just "',"
round-tripped unquoted and failed re-parse. Comma-joined idents like
"Id,Name" still round-trip correctly — they just get wrapped in single
quotes instead of passing through as bare Ident+Comma+Ident tokens.
Review of PR #105 against Microsoft Learn docs surfaced three flags that
don't exist on the cmdlets we attached them to:

- Get-NetAdapter: -Virtual does not exist; only -Physical toggles the
  physical/virtual split. Removed.
- Get-Process: -ComputerName has never been a parameter on this cmdlet.
  Remote process queries go through Invoke-Command. Removed.
- Get-Service: -ComputerName was removed in PowerShell 6+; docs explicitly
  redirect callers to Invoke-Command. Removed to avoid encouraging a
  deprecated / PS 5.1-only pattern.

No corpus entries referenced these flags; tests remain green.
Reviewing the Dassault Systemes knowledge base (SIMULIA CST Studio Suite
+ 3DEXPERIENCE on-prem + DSLS + FlexNet) surfaced six PowerShell cmdlets
that recur in real diagnostic flows but weren't allowlisted yet. All six
are read-only and match specific troubleshooting patterns called out in
the R2024x installation/ops guides.

New cmdlets:
- Select-Xml: parse server.xml / web.xml / logback.xml / httpd.conf for
  config troubleshooting (TomEE, Apache, 3DSpace). Frequent pattern:
  Get-Content config.xml -Raw | Select-Xml -XPath //Connector
- Get-NetFirewallProfile: firewall profile state when diagnosing blocked
  3DEXPERIENCE ports (443, 8000-8100, 19000-19100, 4084-4086, etc.)
- Get-NetIPInterface: interface state / MTU / forwarding — paired with
  Get-NetIPConfiguration for connectivity debugging
- Get-NetConnectionProfile: Public/Private/Domain classification (drives
  which firewall profile applies)
- Get-NetAdapterStatistics: NIC RX/TX counters for MPI perf triage on
  compute clusters
- ConvertFrom-StringData: parse Java .properties (database.properties,
  cas.properties, enovia.ini-adjacent configs)

CIM-remoting flags (-CimSession / -AsJob / -ThrottleLimit) are
deliberately omitted, matching the pattern already established on
Get-NetIPConfiguration and other NetTCPIP cmdlets, to avoid encouraging
lateral pivoting from an already-compromised target.

Also fix a corpus round-trip helper gap: tokens with a leading `/`
(XPath literals like `/Directory`, `//Connector`) must be quoted on
reconstruction, since the Ident lexer won't accept `/` as a leading
char. Without this, the round-trip test over XPath corpus entries
failed even though the original parse succeeded via single-quoted
string literals.

Manifest count: 288 -> 294. 19 new corpus entries (split across six
reason tags). All existing tests green.
…checks

Flip both cmdlets from outright deny to restricted allow (mirroring curl's
GET-only policy):

  Allow: -Uri, -Method (GET/HEAD only), -UseBasicParsing, -TimeoutSec,
         -MaximumRedirection, -UserAgent, -DisableKeepAlive, -SslProtocol,
         -NoProxy, -HttpVersion
  Deny:  -Body, -InFile, -Form, -OutFile (write/upload)
         -Credential, -UseDefaultCredentials, -Certificate, -CertificateThumbprint
         -Proxy, -ProxyCredential, -ProxyUseDefaultCredentials
         -SkipCertificateCheck, -SkipHttpErrorCheck
         -AllowInsecureRedirect, -AllowUnencryptedAuthentication
         -SessionVariable, -WebSession, -CustomMethod, -Headers, -Resume

This unblocks the canonical Windows-admin healthcheck idiom on 3DEXPERIENCE
/ SIMULIA boxes (probing Tomcat endpoints like https://localhost:447/3dpassport/)
while keeping the read-only diagnostic policy.

Also:
- manifest_test: deny count 125 -> 123, spot-check new allow manifests,
  and add a cross-cutting test that every write-capable / credential /
  bypass flag is denied with a reason
- validator: add powershell_http_test.go covering parse+validate end-to-end
  for healthcheck forms, write-flag rejection, and -Method restriction
- parser/corpus_test: drop leading-slash special case and remove '/' from
  the quote-free char set entirely so URL tokens round-trip correctly
- baseline corpus: add three healthcheck round-trip fixtures
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant