PowerShell
PowerShell is a natural fit for automating EnergyCAP tasks — bulk data imports, scheduled exports, reporting, and ad-hoc queries. You can call the EnergyCAP API directly with Invoke-RestMethod or load the C# SDK assembly for typed access to every endpoint.
Approach 1: Direct REST API Calls
The simplest approach — no dependencies, works in PowerShell 5.1+ and PowerShell 7+.
Setup
# Set your environment and API key
$baseUrl = "https://app.energycap.com"
$apiKey = "YOUR_API_KEY"
# Common headers for all requests
$headers = @{
"ECI-ApiKey" = $apiKey
"Content-Type" = "application/json"
}
Store your API key in a secure location — not in your script files. Use Get-Secret (SecretManagement module), environment variables, or Azure Key Vault.
# Using environment variable
$apiKey = $env:ENERGYCAP_API_KEY
# Using SecretManagement module
$apiKey = Get-Secret -Name "EnergyCapApiKey" -AsPlainText
Retrieve a single resource
# Get a specific meter
$meter = Invoke-RestMethod -Uri "$baseUrl/api/v3/meter/1234" -Headers $headers
Write-Host "$($meter.meterId): $($meter.meterCode) — $($meter.meterInfo)"
List resources with filters
# Get all electric meters
$filter = [uri]::EscapeDataString("commodityCode equals 'ELECTRIC'")
$meters = Invoke-RestMethod -Uri "$baseUrl/api/v3/meter?filter=$filter" -Headers $headers
foreach ($meter in $meters) {
Write-Host "$($meter.meterId): $($meter.meterCode)"
}
See Filters for the full filter syntax.
Create a resource
# Create a new account
$body = @{
accountCode = "ACCT-NEW-001"
accountInfo = "New Office Account"
vendorId = 10
accountTypeId = 1
} | ConvertTo-Json
$account = Invoke-RestMethod -Uri "$baseUrl/api/v3/account" `
-Method Post -Headers $headers -Body $body
Write-Host "Created account $($account.accountId)"
Update a resource
# Update an existing meter
$body = @{
meterCode = "MTR-001-UPDATED"
meterInfo = "Updated Meter Description"
} | ConvertTo-Json
$meter = Invoke-RestMethod -Uri "$baseUrl/api/v3/meter/1234" `
-Method Put -Headers $headers -Body $body
Delete a resource
Invoke-RestMethod -Uri "$baseUrl/api/v3/meter/1234" `
-Method Delete -Headers $headers
Field reduction
# Only return meterId, meterCode, and meterInfo
$meters = Invoke-RestMethod `
-Uri "$baseUrl/api/v3/meter?field=meterId,meterCode,meterInfo" `
-Headers $headers
See Field Reduction for include/exclude modes.
Pagination
List endpoints return paginated results. Pagination metadata is in the response headers, so you need Invoke-WebRequest (not Invoke-RestMethod) to access them.
Iterating through all pages
function Get-AllPages {
param(
[string]$Url,
[hashtable]$Headers,
[int]$PageSize = 500
)
$allResults = @()
$page = 1
$totalPages = 1
while ($page -le $totalPages) {
$separator = if ($Url -match "\?") { "&" } else { "?" }
$pagedUrl = "$Url${separator}pageSize=$PageSize&pageNumber=$page"
$response = Invoke-WebRequest -Uri $pagedUrl -Headers $Headers
$allResults += ($response.Content | ConvertFrom-Json)
$totalPages = [int]$response.Headers["TotalPages"][0]
$total = $response.Headers["TotalNumberOfRecords"][0]
Write-Host "Page $page of $totalPages ($total total records)"
$page++
}
return $allResults
}
# Usage
$allMeters = Get-AllPages -Url "$baseUrl/api/v3/meter" -Headers $headers
Write-Host "Retrieved $($allMeters.Count) meters"
See Pagination for more details.
Parallel page fetching (PowerShell 7+)
# Get first page to determine total pages
$firstResponse = Invoke-WebRequest `
-Uri "$baseUrl/api/v3/meter?pageSize=500&pageNumber=1" -Headers $headers
$firstPage = $firstResponse.Content | ConvertFrom-Json
$totalPages = [int]$firstResponse.Headers["TotalPages"][0]
# Fetch remaining pages in parallel
$remainingPages = 2..$totalPages | ForEach-Object -ThrottleLimit 5 -Parallel {
$response = Invoke-WebRequest `
-Uri "$using:baseUrl/api/v3/meter?pageSize=500&pageNumber=$_" `
-Headers $using:headers
$response.Content | ConvertFrom-Json
}
$allMeters = @($firstPage) + @($remainingPages)
Write-Host "Retrieved $($allMeters.Count) meters"
Error Handling
try {
$meter = Invoke-RestMethod -Uri "$baseUrl/api/v3/meter/99999" -Headers $headers
}
catch {
$statusCode = $_.Exception.Response.StatusCode.value__
$body = $_.ErrorDetails.Message
switch ($statusCode) {
400 { Write-Warning "Bad request — check your parameters" }
401 { Write-Warning "Unauthorized — check your API key" }
404 { Write-Warning "Resource not found" }
429 {
Write-Warning "Rate limited — waiting 10 seconds..."
Start-Sleep -Seconds 10
# Retry the request
}
default { Write-Error "HTTP $statusCode : $body" }
}
}
Approach 2: Using the C# SDK from PowerShell
For more complex integrations, you can load the C# SDK assembly directly in PowerShell 7+. This gives you typed objects, IntelliSense in compatible editors, and access to the EnergyCapApiClientFactory.
Install the NuGet package
# Download the SDK package (one-time setup)
$sdkVersion = "8.2512.6600"
$nugetUrl = "https://api.nuget.org/v3-flatcontainer/energycap.sdk/$sdkVersion/energycap.sdk.$sdkVersion.nupkg"
$downloadPath = "$HOME/.energycap-sdk"
New-Item -ItemType Directory -Path $downloadPath -Force | Out-Null
Invoke-WebRequest -Uri $nugetUrl -OutFile "$downloadPath/energycap.sdk.nupkg"
Expand-Archive -Path "$downloadPath/energycap.sdk.nupkg" -DestinationPath "$downloadPath/sdk" -Force
Load the assembly
# Load the SDK assembly
Add-Type -Path "$HOME/.energycap-sdk/sdk/lib/netstandard2.0/EnergyCap.Sdk.dll"
# You may also need the Microsoft.Rest.ClientRuntime dependency
# Install-Package Microsoft.Rest.ClientRuntime -Destination $downloadPath
Create a client and make requests
# Create settings
$settings = [EnergyCap.Sdk.Extensions.EnergyCapClientSettingsApiKeyAuth]::new()
$settings.ApiKey = "YOUR_API_KEY"
# Create the client
$client = [EnergyCap.Sdk.Extensions.EnergyCapApiClientFactory]::CreateClientAsync($settings).Result
# Get meters with pagination headers
$response = $client.GetMetersWithHttpMessagesAsync("", 500, 1).Result
$meters = $response.Body
$totalPages = $response.Headers.TotalPages
Write-Host "Page 1 of $totalPages"
foreach ($meter in $meters) {
Write-Host "$($meter.MeterId): $($meter.MeterCode)"
}
Create a resource with the SDK
$request = [EnergyCap.Sdk.Models.AccountCreateRequest]::new()
$request.AccountCode = "ACCT-PS-001"
$request.AccountInfo = "Created from PowerShell"
$request.VendorId = 10
$request.AccountTypeId = 1
$account = $client.CreateAccountAsync($request).Result
Write-Host "Created account $($account.AccountId)"
Practical Examples
Export meters to CSV
$allMeters = Get-AllPages -Url "$baseUrl/api/v3/meter?field=meterId,meterCode,meterInfo,city,state" `
-Headers $headers
$allMeters | Select-Object meterId, meterCode, meterInfo, city, state |
Export-Csv -Path "meters.csv" -NoTypeInformation
Write-Host "Exported $($allMeters.Count) meters to meters.csv"
Export bills for a date range
$filter = [uri]::EscapeDataString("periodStart between '2025-01-01'|'2025-12-31'")
$fields = "billId,accountId,totalCost,totalUse,periodStart,periodEnd"
$bills = Get-AllPages `
-Url "$baseUrl/api/v3/bill?filter=$filter&field=$fields" `
-Headers $headers
$bills | Export-Csv -Path "bills_2025.csv" -NoTypeInformation
Write-Host "Exported $($bills.Count) bills"
Bulk update meters from a CSV
$updates = Import-Csv -Path "meter_updates.csv"
foreach ($row in $updates) {
$body = @{
meterInfo = $row.NewDescription
} | ConvertTo-Json
try {
Invoke-RestMethod -Uri "$baseUrl/api/v3/meter/$($row.MeterId)" `
-Method Put -Headers $headers -Body $body | Out-Null
Write-Host "Updated meter $($row.MeterId)" -ForegroundColor Green
}
catch {
Write-Warning "Failed to update meter $($row.MeterId): $($_.Exception.Message)"
}
# Brief delay to avoid rate limiting
Start-Sleep -Milliseconds 200
}
Scheduled data sync
# Sync accounts modified in the last 24 hours
$yesterday = (Get-Date).AddDays(-1).ToString("yyyy-MM-dd")
$filter = [uri]::EscapeDataString("modifiedDate greater than '$yesterday'")
$modifiedAccounts = Get-AllPages `
-Url "$baseUrl/api/v3/account?filter=$filter" `
-Headers $headers
if ($modifiedAccounts.Count -gt 0) {
Write-Host "$($modifiedAccounts.Count) accounts modified since $yesterday"
# Process changes — sync to external system, send notifications, etc.
foreach ($account in $modifiedAccounts) {
Write-Host " $($account.accountCode): modified $($account.modifiedDate)"
}
}
else {
Write-Host "No accounts modified since $yesterday"
}
Create a reusable module
For repeated use, wrap common operations in a PowerShell module:
# EnergyCapHelper.psm1
function Connect-EnergyCapApi {
param(
[Parameter(Mandatory)]
[string]$ApiKey,
[string]$Environment = "https://app.energycap.com"
)
$script:ECHeaders = @{
"ECI-ApiKey" = $ApiKey
"Content-Type" = "application/json"
}
$script:ECBaseUrl = $Environment
Write-Host "Connected to $Environment"
}
function Get-ECMeter {
param(
[int]$MeterId,
[string]$Filter,
[int]$PageSize = 500
)
if ($MeterId) {
return Invoke-RestMethod -Uri "$script:ECBaseUrl/api/v3/meter/$MeterId" `
-Headers $script:ECHeaders
}
$url = "$script:ECBaseUrl/api/v3/meter"
if ($Filter) {
$url += "?filter=$([uri]::EscapeDataString($Filter))"
}
return Get-AllPages -Url $url -Headers $script:ECHeaders -PageSize $PageSize
}
function Get-ECBill {
param(
[int]$BillId,
[string]$Filter,
[int]$PageSize = 500
)
if ($BillId) {
return Invoke-RestMethod -Uri "$script:ECBaseUrl/api/v3/bill/$BillId" `
-Headers $script:ECHeaders
}
$url = "$script:ECBaseUrl/api/v3/bill"
if ($Filter) {
$url += "?filter=$([uri]::EscapeDataString($Filter))"
}
return Get-AllPages -Url $url -Headers $script:ECHeaders -PageSize $PageSize
}
Export-ModuleMember -Function Connect-EnergyCapApi, Get-ECMeter, Get-ECBill
Usage:
Import-Module ./EnergyCapHelper.psm1
Connect-EnergyCapApi -ApiKey $env:ENERGYCAP_API_KEY
$meters = Get-ECMeter -Filter "commodityCode equals 'ELECTRIC'"
$bill = Get-ECBill -BillId 5678
Tips
- Use
Invoke-RestMethodfor simple calls — it automatically parses JSON responses into PowerShell objects - Use
Invoke-WebRequestwhen you need response headers — required for pagination metadata - URL-encode filter values — use
[uri]::EscapeDataString()to properly encode filter strings containing spaces and special characters - Add delays for bulk operations — a short
Start-Sleepbetween requests prevents rate limiting - Use
-ErrorAction Stopin scripts to ensuretry/catchblocks work correctly withInvoke-RestMethod - PowerShell 7+ is recommended — it supports
ForEach-Object -Parallelfor concurrent page fetching and has improvedInvoke-RestMethodbehavior