> ## Documentation Index
> Fetch the complete documentation index at: https://developers.scoutworks.app/llms.txt
> Use this file to discover all available pages before exploring further.

# PowerShell

> Save any list to a CSV file on Windows, with the PowerShell that is already on your computer.

This script reads every member and saves them to `members.csv`, ready to open in Excel. It works in Windows PowerShell 5.1, which every Windows 10 and 11 computer has, and in PowerShell 7 on Windows, Mac or Linux.

```powershell members.ps1 theme={null}
# Scoutworks → CSV. https://developers.scoutworks.app/recipes/powershell

$Base = 'https://api-demo.scoutworks.app/api/v1'
# The sandbox key reads a demo group. Set $env:SCOUTWORKS_API_KEY to use your own.
$ApiKey = if ($env:SCOUTWORKS_API_KEY) { $env:SCOUTWORKS_API_KEY } else {
    'sw_live_473adcc6c7236916021f0f24559db36576a53bab071d0f0c08a025adb510b6ab'
}
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12

# Every item in a list, following nextCursor to the last page.
function Read-All([string]$Path) {
    $items = @()
    $cursor = $null
    while ($true) {
        $url = "$Base$Path" + $(if ($Path.Contains('?')) { '&' } else { '?' }) + 'limit=200'
        if ($cursor) { $url += '&cursor=' + [uri]::EscapeDataString($cursor) }
        try {
            $page = Invoke-RestMethod -Uri $url -Headers @{ Authorization = "Bearer $ApiKey" }
        } catch {
            if ([int]$_.Exception.Response.StatusCode -eq 429) {
                Start-Sleep -Seconds 30   # The rate limit. Wait, then try the same page again.
                continue
            }
            throw
        }
        $items += $page.data
        $cursor = $page.nextCursor
        if (-not $cursor) { return $items }
    }
}

# 2026-09-24T18:30:00.000Z → 2026-09-24. PowerShell 7 reads it as a date first.
function Day($Value) {
    if ($Value -is [datetime]) { $Value.ToUniversalTime().ToString('yyyy-MM-dd') }
    else { ([string]$Value).Substring(0, 10) }
}

# Stops Excel running a cell that starts with = + - or @.
function Safe($Value) {
    $text = [string]$Value
    if ($text -match '^\s*[=+\-@]') { "'$text" } else { $text }
}

$members = Read-All '/members'

$rows = $members | ForEach-Object {
    [pscustomobject]@{
        'First name' = Safe $_.firstName
        'Last name'  = Safe $_.lastName
        'Sections'   = Safe (($_.sections | ForEach-Object { $_.name }) -join ', ')
        'Patrol'     = Safe $(if ($_.patrol) { $_.patrol.name } else { '' })
        'Joined'     = Day $_.joinedAt
    }
}
if ($rows) {
    $rows | Export-Csv -Path members.csv -NoTypeInformation -Encoding UTF8
} else {
    # No members: still write the headings, so the file has its columns.
    Set-Content -Path members.csv -Value '"First name","Last name","Sections","Patrol","Joined"' -Encoding UTF8
}

Write-Host "Saved $($members.Count) members to members.csv"
```

## Run it

<Steps>
  <Step title="Save the script">
    Save it as `members.ps1` in a folder of its own, for example `Documents\Scoutworks`.
  </Step>

  <Step title="Open PowerShell in that folder">
    In File Explorer, open the folder. Type `powershell` in the address bar and press **Enter**.
  </Step>

  <Step title="Run it">
    ```powershell theme={null}
    powershell -ExecutionPolicy Bypass -File .\members.ps1
    ```

    `-ExecutionPolicy Bypass` lets this one script run. It does not change the settings of your computer.
  </Step>
</Steps>

Open `members.csv` in Excel.

## Switch to your group

Change `api-demo.scoutworks.app` to `api.scoutworks.app`. Then set your key for this window only, and run the script:

```powershell theme={null}
$secure = Read-Host 'Scoutworks API key' -AsSecureString
$env:SCOUTWORKS_API_KEY = [Runtime.InteropServices.Marshal]::PtrToStringBSTR(
    [Runtime.InteropServices.Marshal]::SecureStringToBSTR($secure))
powershell -ExecutionPolicy Bypass -File .\members.ps1
```

PowerShell asks for the key and does not show it as you type, so it stays out of your command history. The key is gone when you close the window. It is never saved in the script. Your key needs the `members:read` scope.

## Notes

* **Accented names look wrong in Excel?** In PowerShell 7, change `-Encoding UTF8` to `-Encoding utf8BOM`. Windows PowerShell 5.1 already adds the marker that Excel needs.
* **Other lists.** Change `/members` and the columns. For example, `Read-All '/badges?status=awarded'`. The [API reference](/api-reference/introduction) lists every field.
