PoshTorch is a PowerShell helper module for generating, formatting, and exporting Prometheus data.
Whether you are dropping .prom files for the node_exporter textfile collector, pushing to a Pushgateway, or exposing a live /metrics endpoint via Pode, PoshTorch handles the strict Prometheus formatting, label validation, and character escaping for you.
You can use it to format and export metrics from any source you can reach using Powershell, and therefore can seamlessly integrate it to any monitoring script you already use.
- Native PowerShell Objects: Build metrics dynamically via the pipeline.
- Spec-Compliant: Strict validation of metric names and labels against the Prometheus regex (
[a-zA-Z_][a-zA-Z0-9_]*). - Built-in Exporters: Export to
.promfiles atomically, push to a Pushgateway, or output raw text for your own custom scenarios.
This module is not available (yet?) from Powershell gallery. Clone the repo and copy PoshTorch folder to C:\Program Files\WindowsPowerShell\Modules for system-wide availability. May require Unblock-Files.
Here is the documentation for the module's functions, written in English and formatted in the standard Markdown style you would typically find in the README.md or docs/ folder of a community-supported PowerShell GitHub repository.
The module is built around two main categories of functions: Metrics (for creating and populating metrics) and Exporters (for outputting the data). All functions are designed to be highly pipeline-friendly.
Initializes a new metric object in memory with its metadata (name, help text, and type). The function automatically validates the metric name against Prometheus naming conventions (alphanumeric characters and underscores only).
| Parameter | Type | Required | Pipeline | Description |
|---|---|---|---|---|
-Name |
[string] |
Yes | No | The technical name of the metric (e.g., cpu_usage_percent). |
-Help |
[string] |
Yes | No | A human-readable description of what the metric represents. |
-Type |
[MetricType] |
Yes | No | The Prometheus metric type. Accepted values: counter, gauge, histogram, summary. |
Example:
$metric = New-PrometheusMetric -Name 'backup_duration_seconds' -Help 'Time taken for the backup' -Type gaugeAppends a numeric sample to an existing metric. It modifies the object and outputs it back to the pipeline, allowing for seamless chaining. You can call this function multiple times in a loop on the same metric to generate multiple time series (using different labels).
| Parameter | Type | Required | Pipeline | Description |
|---|---|---|---|---|
-Metric |
[Metric] |
Yes | Yes | The target metric object to add the value to. |
-Value |
[double] |
Yes | No | The numeric value of the metric sample. |
-Labels |
[hashtable] |
No | No | Optional key-value pairs representing the metric's dimensions (e.g., @{ status = "success" }). |
Example:
$metric | Add-PrometheusMetricValue -Value 42.5 -Labels @{ db_name = "Finance" }Converts the PowerShell metric object(s) into a raw string formatted according to the Prometheus Text Exposition Format (v0.0.4). This is primarily used for debugging in the console or for piping the raw payload to a custom HTTP server (like Pode).
| Parameter | Type | Required | Pipeline | Description |
|---|---|---|---|---|
-Metric |
[Metric[]] |
Yes | Yes | The metric object(s) to convert to text. |
Example:
$metric | Out-PrometheusMetricExports the metrics to a local text file (usually with a .prom extension). This function is designed to work natively with the Node Exporter's Textfile Collector. To prevent Prometheus from scraping a partially written file, it writes to a temporary file first and performs an atomic replace.
| Parameter | Type | Required | Pipeline | Description |
|---|---|---|---|---|
-Metric |
[Metric[]] |
Yes | Yes | The metric object(s) to write to disk. |
-Path |
[string] |
Yes | No | The absolute path where the .prom file will be saved. |
Example:
$metric | Export-PrometheusFile -Path 'C:\Metrics\custom_scripts.prom'Pushes the metrics directly to a Prometheus Pushgateway instance via an HTTP request. This is the recommended approach for ephemeral scripts (like scheduled tasks, CI/CD pipelines, or backup scripts) that finish execution before Prometheus has a chance to actively scrape them.
| Parameter | Type | Required | Pipeline | Description |
|---|---|---|---|---|
-Metric |
[Metric[]] |
Yes | Yes | The metric object(s) to push. |
-GatewayUrl |
[string] |
Yes | No | The base URL of your Pushgateway (e.g., http://pushgateway.local:9091). |
-Job |
[string] |
Yes | No | The job name associated with these metrics (used in the grouping key). |
-Instance |
[string] |
No | No | An optional instance name for finer-grained grouping. |
-Method |
[string] |
No | No | The HTTP method to use. Defaults to PUT (replace). POST (add) is also supported. |
Example:
$metric | Export-PrometheusPushgateway -GatewayUrl 'http://localhost:9091' -Job 'nightly_backup'Creating metrics in PoshTorch is designed to be fluent and pipeline-friendly.
Import-Module PoshTorch
$metric = New-PrometheusMetric -Name 'ps_script_duration_seconds' `
-Help 'Execution time of the backup script' `
-Type gauge
# Add values with optional labels
$metric | Add-PrometheusMetricValue -Value 45.2 -Labels @{ status = "success"; task = "db_backup" }
$metric | Add-PrometheusMetricValue -Value 12.0 -Labels @{ status = "failed"; task = "log_cleanup" }
# Render to standard Prometheus Text Format
$metric | Out-PrometheusMetricOutput:
# HELP ps_script_duration_seconds Execution time of the backup script
# TYPE ps_script_duration_seconds gauge
ps_script_duration_seconds{status="success",task="db_backup"} 45.2
ps_script_duration_seconds{status="failed",task="log_cleanup"} 12
If a node exporter is running on the system where you need to collect the metrics using this script, the easiest way to export them is by dumping a .prom file for node_exporter to scrape. Export-PrometheusFile handles atomic file writes to ensure Prometheus never scrapes a partially written file (true atomic write with Powershell 7+ only).
# Gather metrics...
$metrics = @(
(New-PrometheusMetric -Name 'ad_locked_accounts' -Help 'Number of locked AD accounts' -Type gauge | Add-PrometheusMetricValue -Value 4),
(New-PrometheusMetric -Name 'ps_script_duration_seconds'-Help 'Execution time of the backup script' -Type gauge |
Add-PrometheusMetricValue -Value 12.0 -Labels @{ status = "failed"; task = "log_cleanup" } |
Add-PrometheusMetricValue -Value 45.2 -Labels @{ status = "success"; task = "db_backup" }
)
)
# Export atomically to the node_exporter drop folder
$metrics | Export-PrometheusFile -Path 'C:\Program Files\windows_exporter\textfile_inputs\metrics.prom'You can also push the metrics to a Prometheus Pushgateway:
$metrics | Export-PrometheusPushgateway -GatewayUrl 'http://pushgateway.internal.corp:9091' `
-Job 'test_metrics' `
-Instance 'DC-01'If you have a long-running PowerShell service and want it to be actively scraped by Prometheus, you can easily combine PoshTorch with Pode, the reference PowerShell web framework.
Import-Module Pode
Import-Module PoshTorch
Start-PodeServer {
# Listen on port 8080
Add-PodeEndpoint -Address * -Port 8080 -Protocol Http
# Define the /metrics route that Prometheus will scrape
Add-PodeRoute -Method Get -Path '/metrics' -ScriptBlock {
# Generate your metrics
$metric = New-PrometheusMetric -Name 'ps_script_duration_seconds' `
-Help 'Execution time of the backup script' `
-Type gauge
$metric | Add-PrometheusMetricValue -Value 45.2 -Labels @{ status = "success"; task = "db_backup" }
$metric | Add-PrometheusMetricValue -Value 12.0 -Labels @{ status = "failed"; task = "log_cleanup" }
# Render to Prometheus format
$payload = $metric | Out-PrometheusMetric
# Return the response using the mandatory content type
Write-PodeTextResponse -Value $payload -ContentType 'text/plain; version=0.0.4'
}
}Several other Prometheus-exporter modules already exist, but they don't fit my usecases. Plus I wanted to give a try to Powershell classes.
Because it's written in Powershell, and it's elegant, and it helps bringing light to your metrics the same way Prometheus did with his Torch to bring light to humanity. Also because it sounds nice and because I'm a really funny guy.
Maybe adapt the module to support the full OpenMetrics standard if my scenarios require it someday.