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"
}
Tip

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-RestMethod for simple calls — it automatically parses JSON responses into PowerShell objects
  • Use Invoke-WebRequest when 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-Sleep between requests prevents rate limiting
  • Use -ErrorAction Stop in scripts to ensure try/catch blocks work correctly with Invoke-RestMethod
  • PowerShell 7+ is recommended — it supports ForEach-Object -Parallel for concurrent page fetching and has improved Invoke-RestMethod behavior