Reading data from files is essential for parsing log events, processing external data exports, and importing configuration settings. In PowerShell, reading files goes beyond retrieving raw text characters; cmdlets can stream text line by line, load entire files into memory as single strings, or automatically convert structured formats like CSV and JSON into strongly typed .NET objects.
Reading Text with Get-Content
The Get-Content cmdlet (aliases: gc, cat, type) is the primary cmdlet for reading file contents. By default, it reads text files line by line, emitting each line as an individual System.String object. When captured into a variable, PowerShell collects these strings into a zero-indexed array (System.Object[]).
Get-Content -Path "C:\Logs\app.log"2024-03-14 08:30:15 - Service started
2024-03-14 08:31:02 - Connection established
2024-03-14 08:32:47 - Request processed(Get-Content -Path "C:\Logs\app.log").Count3Where:
- Each line of the file becomes a separate element in the returned array, allowing you to index or loop through them individually.
$LogLines[0]retrieves the first line,$LogLines.Countreturns the total number of lines.
$LogPath = "C:\Logs\service.log"
if (Test-Path $LogPath) {
$LogLines = Get-Content -Path $LogPath
Write-Output "Total lines read: $($LogLines.Count)"
if ($LogLines.Count -gt 0) {
Write-Output "First line: $($LogLines[0])"
}
else {
Write-Output "The file is empty."
}
}
else {
Write-Output "Log file not found: $LogPath"
}Total lines read: 450
First line: 2024-10-24 08:00:01 [INFO] Service startup initiated.Reading Entire Files as a Single String (-Raw)
The -Raw switch bypasses line-by-line array splitting. It loads the entire file contents into memory as a single, multi-line string (System.String), preserving all newline characters (\r\n or \n).
$content = Get-Content -Path "C:\Logs\app.log" -Raw
$content.GetType().NameStringUsing -Raw is significantly faster than standard Get-Content on medium-to-large files and is required when:
- Passing content to cmdlets that expect a single string, such as
ConvertFrom-Json. - Performing a find-and-replace across the entire document with
-replace. - Matching regular expression patterns that span multiple lines.
Reading the First N Lines (-TotalCount / -Head)
The -TotalCount parameter (aliased as -Head) limits the number of lines read from the beginning of the file. This is useful for previewing large files without loading them entirely into memory.
Get-Content -Path "C:\Logs\app.log" -TotalCount 22024-03-14 08:30:15 - Service started
2024-03-14 08:31:02 - Connection establishedWhere -TotalCount 2 reads only the first two lines, regardless of the file's total size.
Reading the Last N Lines (-Tail)
The -Tail parameter reads lines from the end of the file, functioning similarly to the Unix tail command in PowerShell. It is commonly used to check the most recent entries in a growing log file.
Get-Content -Path "C:\Logs\service.log" -Tail 22024-10-24 08:15:30 [WARN] High memory consumption detected.
2024-10-24 08:15:32 [INFO] Heartbeat acknowledged.Watching a File in Real Time
Combining -Tail with -Wait streams new lines as they are appended to the file, similar to tail -f in Bash.
Get-Content -Path "C:\Logs\app.log" -Tail 5 -WaitWhere:
-Waitkeeps the command running, printing new lines to the console as they are written to the file.- Press
Ctrl+Cto stop watching.
Reading CSV Files with Import-Csv
Comma-Separated Values (CSV) files are commonly used for exporting system reports and spreadsheets. The Import-Csv cmdlet parses a CSV file directly into an array of [PSCustomObject] instances, taking the first row as property names. This approach is far more useful than treating CSV data as plain text lines.
Given a CSV file servers.csv:
ServerName,IPAddress,Role
web-prod-01,192.168.1.10,WebServer
sql-prod-01,192.168.1.20,Database
app-prod-01,192.168.1.30,ApplicationImport and interact with the data directly using property dot notation:
$ServerList = Import-Csv -Path "$PSScriptRoot\servers.csv"
foreach ($server in $ServerList) {
Write-Output "Node: $($server.ServerName) | IP: $($server.IPAddress) | Role: $($server.Role)"
}./read-csv-demo.ps1Node: web-prod-01 | IP: 192.168.1.10 | Role: WebServer
Node: sql-prod-01 | IP: 192.168.1.20 | Role: Database
Node: app-prod-01 | IP: 192.168.1.30 | Role: ApplicationWhere:
- Each row becomes a distinct object, with column headers automatically mapped to property names.
$server.ServerNameresolves the value directly without manual string splitting.- The result works seamlessly with
Where-Object,Select-Object, and other pipeline cmdlets.
Specifying a Custom Delimiter
Import-Csv -Path "C:\Data\employees.txt" -Delimiter ";"Where:
-Delimiter ";"parses files that use semicolons instead of the default comma.- For tab-separated files, use
-Delimiter "`t".
Reading JSON Files
JSON is the standard data interchange format for modern APIs, cloud configuration templates, and settings files. PowerShell does not include a dedicated Import-Json cmdlet. Instead, JSON files are read as raw text using Get-Content -Raw before being parsed with ConvertFrom-Json.
Given a JSON file config.json:
{
"ClusterName": "West-Production",
"Port": 8443,
"Enabled": true,
"Nodes": ["node-01", "node-02"]
}Read and parse the JSON payload:
$Config = Get-Content -Path "$PSScriptRoot\config.json" -Raw | ConvertFrom-Json
[PSCustomObject]@{
TargetCluster = $Config.ClusterName
ListenPort = $Config.Port
IsActive = $Config.Enabled
FirstNode = $Config.Nodes[0]
TotalNodes = $Config.Nodes.Count
}./read-json-demo.ps1TargetCluster : West-Production
ListenPort : 8443
IsActive : True
FirstNode : node-01
TotalNodes : 2Where:
Get-Content -Rawreads the JSON file as a single uninterrupted text string.ConvertFrom-Jsonparses the JSON string and converts it into a[PSCustomObject]with matching property types (string,int,bool,array).$Config.Nodes[0]accesses elements in the nested JSON array using standard indexing.
Working with Nested JSON
{
"app": {
"name": "InventoryManager",
"version": "2.1.0"
},
"features": ["reporting", "export", "sync"]
}$settings = Get-Content -Path "C:\Config\settings.json" -Raw | ConvertFrom-Json
$settings.app.name
$settings.features[1]InventoryManager
exportWhere:
- Nested JSON objects become nested
PSCustomObjectproperties, accessible via chained dot notation ($settings.app.name). - JSON arrays become standard PowerShell arrays, supporting normal indexing.
Practical Example: Multi-Source Server Ingestion Engine
The following script reads a combination of data sources: it parses a JSON configuration file for environmental settings, uses Import-Csv to read target servers, and checks an existing log file with -Tail for prior errors.
param (
[string]$ConfigPath = "$PSScriptRoot\config.json",
[string]$CsvPath = "$PSScriptRoot\servers.csv",
[string]$LogPath = "$PSScriptRoot\deployment.log"
)
$FilesToVerify = @($ConfigPath, $CsvPath)
foreach ($file in $FilesToVerify) {
if (-not (Test-Path -Path $file -PathType Leaf)) {
Write-Error "Required input file '$file' is missing."
exit 1
}
}
Write-Output "Loading environment parameters from JSON..."
$AppSettings = Get-Content -Path $ConfigPath -Raw | ConvertFrom-Json
Write-Output "Importing server endpoints from CSV..."
$Servers = Import-Csv -Path $CsvPath
$RecentErrors = 0
if (Test-Path -Path $LogPath -PathType Leaf) {
Write-Output "Auditing last 50 log lines for previous failures..."
$RecentErrors = (Get-Content -Path $LogPath -Tail 50 | Select-String -Pattern "ERROR|FAIL").Count
}
[PSCustomObject]@{
ClusterTarget = $AppSettings.ClusterName
TargetPort = $AppSettings.Port
TotalNodesToDeploy = ($Servers.Count)
RecentLoggedErrors = $RecentErrors
ReadyForDeployment = ($RecentErrors -eq 0)
}Where:
Test-Pathvalidates that the required input files exist before reading begins.Get-Content -Raw | ConvertFrom-Jsonparses environment settings from JSON.Import-Csvconverts server rows into structured objects.Get-Content -Tail 50 | Select-Stringscans only the end of the log file for failure keywords.[PSCustomObject]compiles the results into a consolidated summary.
Execute the script from the console:
pwsh ./ingest-server-configs.ps1Loading environment parameters from JSON...
Importing server endpoints from CSV...
Auditing last 50 log lines for previous failures...
ClusterTarget TargetPort TotalNodesToDeploy RecentLoggedErrors ReadyForDeployment
------------- ---------- ------------------ ------------------ ------------------
West-Production 8443 3 0 True