PowerShell ConvertFrom-Csv: Parse CSV Text Without a File

PowerShell ConvertFrom-Csv: Parse CSV Text Without a File

PowerShell Tips Editor 2 min read
PowerShell ConvertFrom-Csv: Parse CSV Text Without a File

Some APIs return CSV-formatted text in an HTTP response body rather than JSON. Legacy tools output comma-separated data you need to process. PowerShell ConvertFrom-Csv parses CSV-formatted strings directly into objects without needing to write the data to a file first. This post covers how to use it for API responses, command output, and in-memory data transformation.

Quick Answer / TL;DR

Pipe a CSV string to ConvertFrom-Csv to get objects. Use -Header when the first row is data (no header row). Use -Delimiter for non-comma separators.

Basic ConvertFrom-Csv Usage

ConvertFrom-Csv reads the first row as column headers and subsequent rows as values, converting each row into a PSCustomObject. The input can be a single multiline string or an array of strings — one string per CSV row.

# Parse a CSV string with headers
$csvData = @"
Name,Department,Email
John Smith,IT,[email protected]
Jane Doe,Finance,[email protected]
Bob Wilson,HR,[email protected]
"@

$users = $csvData | ConvertFrom-Csv

$users | Format-Table -AutoSize
Name       Department Email
----       ---------- -----
John Smith IT         [email protected]
Jane Doe   Finance    [email protected]
Bob Wilson HR         [email protected]

Specify Custom Headers

When the CSV data has no header row — just raw data — use -Header to supply column names. Without it, the first data row becomes the property names, which is usually wrong for headerless files.

# Data without a header row
$rawData = @"
jsmith,John Smith,IT,[email protected]
jdoe,Jane Doe,Finance,[email protected]
"@

# Supply headers explicitly
$users = $rawData | ConvertFrom-Csv -Header 'SamAccountName','DisplayName','Department','Email'

# Now properties are correctly named
$users | Where-Object Department -eq 'IT' | Select-Object SamAccountName, Email

Parse API CSV Response

When an API returns CSV text in the response body, use Invoke-RestMethod or Invoke-WebRequest to fetch the data, then pipe directly to ConvertFrom-Csv. This is cleaner than writing to a temp file and using Import-Csv.

# API that returns CSV content-type
$response = Invoke-WebRequest -Uri 'https://api.example.com/export/users' -UseDefaultCredentials
$csvText  = $response.Content

$users = $csvText | ConvertFrom-Csv

# Filter and process in-memory
$activeUsers = $users | Where-Object Status -eq 'Active'
Write-Host "Active users: $($activeUsers.Count)"
$activeUsers | Export-Csv C:\Reports\active_users.csv -NoTypeInformation

Convert Command Output to CSV Objects

Some command-line tools output CSV-formatted text. Capture the output, skip any non-CSV header lines, then pipe to ConvertFrom-Csv to get usable objects.

# wmic output is tab-separated — use -Delimiter
$wmicOutput = wmic process get Name,ProcessId,WorkingSetSize /FORMAT:CSV 2>$null |
    Where-Object { $_ -and $_ -notmatch '^Node' }

$processes = $wmicOutput | ConvertFrom-Csv

$processes |
    Where-Object { [long]$_.WorkingSetSize -gt 100MB } |
    Select-Object Name, ProcessId, @{N='RAM_MB';E={[math]::Round([long]$_.WorkingSetSize/1MB,1)}} |
    Sort-Object RAM_MB -Descending |
    Format-Table -AutoSize

ConvertFrom-Csv vs Import-Csv

The functional difference is simple: Import-Csv reads from a file on disk; ConvertFrom-Csv reads from a string in memory. Both produce identical PSCustomObject output with the same property access and pipeline behavior. Use Import-Csv when data is in a file, ConvertFrom-Csv when data is in a variable or pipeline string.

# These produce equivalent results
$fromFile   = Import-Csv -Path C:\Data\users.csv
$fromString = Get-Content -Path C:\Data\users.csv -Raw | ConvertFrom-Csv

# Verify they are equivalent
$fromFile.Count -eq $fromString.Count
$fromFile[0].Name -eq $fromString[0].Name

Pipeline Chain Example

A complete pipeline that fetches CSV from a URL, filters, transforms, and exports — all without writing any intermediate files.

$reportData = (Invoke-WebRequest -Uri 'https://reports.contoso.com/api/monthly.csv').Content |
    ConvertFrom-Csv |
    Where-Object { [int]$_.Amount -gt 1000 } |
    Select-Object Date, Category,
        @{N='Amount'; E={[int]$_.Amount}},
        @{N='Formatted'; E={ '$' + '{0:N2}' -f [int]$_.Amount }}

$reportData | Export-Csv C:\Reports\high_value.csv -NoTypeInformation
Write-Host "Exported $($reportData.Count) high-value records"

Common Errors and Fixes

  • No header row in input — must specify -Header parameter. If your CSV data has no first-row headers and you omit -Header, the first data row becomes the property names. You lose one record and property names are meaningless data values. Always add -Header when working with headerless CSV data.
  • Custom delimiter needed for semicolon-separated data. European locale CSV files often use semicolons as delimiters. Pass -Delimiter ';' to ConvertFrom-Csv. Tab-separated data uses -Delimiter "`t" (backtick-t for the tab character in PowerShell strings).

Related Cmdlets / See Also

Wrapping Up

ConvertFrom-Csv is the in-memory counterpart to Import-Csv. Use it when your CSV data arrives as a string from an API, command output, or variable. It produces the same objects as Import-Csv, integrates with the full pipeline, and eliminates the need for intermediate temp files when processing CSV data in memory.

Send-Item -To