Status: Reviewed
Stack: PowerShell → SQL / stored procs → Blazor
Depends on: SQL-CLI-01 helpful for verify / EXEC usp_*; not required to start
Goal: Training expansion of the original lean deep-dive — choose bcp vs BULK INSERT vs OPENROWSET vs SqlBulkCopy vs Invoke-Sqlcmd loops correctly, then run the labs and recipes until inventory dumps and vendor CSVs → staging → proc → Blazor are muscle memory for Rick’s AD/Windows/PowerShell stack.
Cross-links (do not duplicate): SQL-CLI-01 sqlcmd / go-sqlcmd · SQL-CLI-03 SqlServer module / Write-SqlTableData · SQL-CLI-06 auth cheat sheet · SQL-CLI-07 PS→SQL→Blazor patterns
This page owns the bcp client: install, PATH, directions (in / out / queryout / format), practical flags, format files, and PowerShell orchestration that feeds staging tables. Auth matrix and Encrypt/TSC across every tool live in CLI-06. Object shaping / Write-SqlTableData / SqlBulkCopy live in CLI-03. End-to-end Collect→Stage→Load→EXEC→Blazor lives in CLI-07. Verify hops use CLI-01.
After this page you can:
bcp.exe from the same Client SDK as classic sqlcmd, prove which binary PATH will run, and pin a full path in Agent jobs.-T), SQL auth, and Entra (-G) using documented flags only; know when -Y / -u (bcp 18+) matter.in, out, queryout, format nul — and pick -c / -w / -n / -N / -f correctly.$LASTEXITCODE, stage → EXEC usp_*, verify with sqlcmd.Rick’s typical loads: inventory extracts, vendor CSV drops, staging → EXEC dbo.usp_* → Blazor reads procs/views. Pick the tool by where the file lives and who owns the process.
| Need | bcp | BULK INSERT | OPENROWSET(BULK) | SqlBulkCopy (.NET) | Invoke-Sqlcmd row loops |
|---|---|---|---|---|---|
| File on jump box / Agent host; SQL never sees the path | ✅ Best | ❌ Server must read path | ❌ Server must read path | ✅ In-app | ❌ Slow |
| File already on SQL host / UNC SQL can reach | OK | ✅ Best (T-SQL job) | ✅ Ad-hoc SELECT | Possible | ❌ |
| Export table / filtered query to file | ✅ out / queryout |
❌ | ❌ | ❌ | Possible but slow |
| Format file / column remap / skip identity | ✅ -f |
✅ FORMATFILE |
✅ | Manual mapping | N/A |
| App already in Blazor / worker process | Possible via Process | Via SQL | Via SQL | ✅ Preferred | Only tiny sets |
| Azure SQL (no host filesystem) | ✅ Client-side file | Limited / EXTERNAL DATA SOURCE patterns | Similar constraints | ✅ | ❌ |
| Permissions story | Table SELECT/INSERT (+ ALTER in some cases) — not bulkadmin |
Needs ADMINISTER BULK OPERATIONS / bulkadmin (Azure: ADMINISTER DATABASE BULK OPERATIONS) |
Same family as BULK INSERT | App login INSERT |
App login |
| Throughput for multi‑GB inventory | ✅ High | ✅ High | High | ✅ High | ❌ Don’t |
Ops / Agent / scheduled extract-import on Windows box → bcp + PowerShell + $LASTEXITCODE
File already next to SQL (T-SQL job / proc) → BULK INSERT
Blazor Server / .NET worker already holding DataTable → SqlBulkCopy / Write-SqlTableData (CLI-03)
Verify row counts / run post-load procs → sqlcmd / go-sqlcmd (CLI-01)
Need objects → JSON for Blazor shaping → Invoke-Sqlcmd (CLI-03) — not for bulk load
Never row-by-row INSERT loops for inventory dumps → use bcp / BULK INSERT / SqlBulkCopy
Kerberos / Encrypt / full auth matrix → CLI-06
Collect → Stage → Load → EXEC → Blazor → CLI-07
Rule of thumb: if the next hop is a file on the client, use bcp. If the next hop is a T-SQL job that can see the file, use BULK INSERT. If the next hop is already a .NET DataTable/IDataReader, use SqlBulkCopy. If you only need to verify / EXEC, use sqlcmd (CLI-01).
Same Client SDK ODBC Tools\Binn family as classic sqlcmd (see SQL-CLI-01 §2). Do this on the jump box before you trust any script.
| Source | Notes |
|---|---|
| Microsoft Command Line Utilities for SQL Server | Official standalone; installs bcp + ODBC sqlcmd; needs Microsoft ODBC Driver for SQL Server (driver 18 recommended). |
| SQL Server engine / CU tools | Often already on DBA jump boxes. Standalone build number may differ from CU — expected (Learn). |
| Linux / macOS | mssql-tools packages — not Rick’s primary path. |
Typical paths (version folders vary — 170 vs 180):
C:\Program Files\Microsoft SQL Server\Client SDK\ODBC\170\Tools\Binn\bcp.exe
C:\Program Files\Microsoft SQL Server\Client SDK\ODBC\180\Tools\Binn\bcp.exe
| bcp major | Ships with / notes |
|---|---|
| 18 | SQL Server 2025 (17.x) tools — adds -Y (TLS mode), -u (trust server cert). TDS 8.0 support. |
| 15 | Command Line Utilities 15; also with SQL Server 2019/2022 tooling. |
OS floor from Learn: Windows 10 / Windows Server 2016 or later.
where.exe bcp
bcp -v
# If multiple: PATH wins. Prefer the ODBC\180 (or newest) Binn that matches your driver.
Get-ChildItem 'C:\Program Files\Microsoft SQL Server\Client SDK\ODBC\*\Tools\Binn\bcp.exe'
| Situation | Practice |
|---|---|
| Laptop / jump box | Let newest Client SDK win PATH. |
| SQL Agent CmdExec | Store the full path to bcp.exe in the jobstep. Do not rely on the service account’s PATH. |
| Both 15 and 18 installed | Prefer 18 for Azure / Encrypt flags; pin deliberately. |
Download hub: Download and install bcp.
Flags here. The decision matrix (when Integrated vs SQL vs Entra, plus Kerberos/double-hop, Encrypt across every tool) is SQL-CLI-06. Do not copy that sheet into scripts — link it.
bcp "AppDb.dbo.Inventory" out .\inv.bcp -S sql01.contoso.local -T -n
-T = trusted connection (Windows Integrated). Do not use -T against Azure SQL Database / Synapse — Learn: not supported. For Entra, use -G.
# Prefer prompt (omit -P) or SecretStore / env — never -P on shared cmdline / Agent args / transcripts
bcp dbo.InventoryStaging in .\vendor.csv -S sql01 -d AppDb -U deploy_user -f .\fmt\InventoryStaging.fmt -F 2
# bcp prompts for password when -U is set and -P is omitted
If you must automate SQL auth: SecretManagement / Key Vault → env var for the process only → scrub after. Same discipline as sqlcmd’s SQLCMDPASSWORD (CLI-01) — bcp itself does not read SQLCMDPASSWORD.
-G requires bcp ≥ 14.0.3008.27. Applies to Azure SQL Database, Azure SQL MI, Synapse, SQL database in Fabric, and SQL Server 2022 (16.x)+.
| Scenario | Shape | Notes |
|---|---|---|
| Entra interactive (Windows MFA) | -G -U 'rick@contoso.com' (no -P) |
Browser / MFA |
| Entra integrated (federated Windows) | -G alone |
When the Windows identity is federated to Entra |
| Entra password (no MFA) | -G -U user -P pwd |
Prefer secrets from env/store, not argv |
| Token file (Linux/macOS, tools v17.8+) | -G without -U, -P = token file path |
UTF-16 LE, no BOM — Windows ops usually use interactive / integrated instead |
# Entra interactive (Windows MFA)
bcp dbo.Inventory out .\inv.bcp -S contoso.database.windows.net -d AppDb -G -U 'rick@contoso.com' -w -l 60
# Entra integrated (federated Windows identity)
bcp dbo.Inventory out .\inv.bcp -S contoso.database.windows.net -d AppDb -G -w -l 60
Azure login timeout: bump -l (default 15s) — 30–60 is common. Firewall / private endpoint must allow the jump-box IP. Entra principal must exist in-DB (CREATE USER … FROM EXTERNAL PROVIDER) — DBA step, not a flag.
Full Entra matrix across tools: CLI-06. Auth deep-dive for bcp: Authenticate with Microsoft Entra ID in bcp.
| Flag | Meaning |
|---|---|
-Y[s\|m\|o] |
TLS mode: s Strict (TDS 8.0), m Mandatory (default if omitted), o Optional. |
-u |
Trust server certificate (lab / self-signed). Analogous to sqlcmd -C — not “Unicode” (Unicode char is -w). |
-H hostname_in_certificate |
Connect name ≠ cert CN/SAN. |
-J path\to\server.pem |
Explicit server cert (PEM). |
SQL Server 2025 / bcp 18: omit -Y → -Ym (mandatory). Lab boxes with self-signed certs usually need -u. Prefer real certs in prod.
Older bcp without -u/-Y: use a DSN (-D -S MyDsn) with TrustServerCertificate=yes / encrypt options the driver supports.
Cross-tool Encrypt / TSC matrix: CLI-06.
| Scenario | Flags | Notes |
|---|---|---|
| DSN (MI, MultiSubnetFailover, hide secrets) | -D -S MyDsn |
-S value is a DSN name. bcp major version must match the ODBC driver used to create the DSN. |
| Read-only AG secondary | -K ReadOnly |
Required to hit readable secondaries. |
| Login timeout | -l 30 |
Default 15s; bump for Azure. |
Server forms: -S sql01, -S sql01\INST, -S tcp:sql01,1433, -S contoso.database.windows.net.
Database: prefer either three-part name AppDb.dbo.Inventory or -d AppDb — not both (error).
Quoted identifiers / weird names: -q and quote the three-part name:
bcp "AppDb.dbo.My Table" out .\t.bcp -S sql01 -T -w -q
-q does not apply to values passed to -d.
bcp {table|view|"query"} { in | out | queryout | format nul } {data_file|nul} [options]
| Direction | Meaning | Typical Rick use |
|---|---|---|
in |
File → table/view | Vendor CSV / inventory dump → staging |
out |
Table/view → file (overwrites existing) | Nightly extract for vendor / archive |
queryout |
T-SQL query (first result set only) → file | Delta extract / filtered inventory |
format nul |
Generate format file (-f required; -x for XML). Data path must be nul. |
Build .fmt / .xml once per staging table |
| Switch | Mode | Use when |
|---|---|---|
-n |
Native | SQL → SQL round-trip; fastest; not for Excel/CSV consumers |
-N |
Unicode native | SQL → SQL with extended chars; Windows only; higher perf than -w for character data |
-c |
Character (char, tab / \r\n) |
Simple ASCII/OEM text; not compatible with -w |
-w |
Unicode character (nchar) |
Export humans/Excel will open; safe default for mixed text |
-f |
Format file drives layout | CSV/pipe remap, skip columns, non-default terminators |
Pick once: native (-n / -N) for internal hops; -w or format + -t, for vendor CSV; never mix a native file with a -c import.
queryout rules (Learn)bcp → land results in a real/staging table first, then out.out overwrites an existing file — no prompt.Only what ops actually touch. Full list: bcp utility (Learn, ver17).
| Flag | Purpose | Why it matters in scripts |
|---|---|---|
-S |
Server / instance / (with -D) DSN |
Force tcp:host,1433 for remote. |
-d |
Database | Don’t also use three-part DB name. |
-T |
Windows Integrated | On-prem default. Not for Azure SQL. |
-U / -P |
SQL or Entra user / password | Prefer prompt or secret store. Never bake -P into Agent args. |
-G |
Microsoft Entra auth | Needs modern bcp; Azure / SQL 2022+. |
-D |
Treat -S as DSN |
MultiSubnetFailover, hide secrets, driver options. |
-l |
Login timeout (seconds) | Default 15. Azure: ≥ 30. 0 = infinite. |
-K ReadOnly |
AG application intent | Omit = no readable secondary. |
-Y[s\|m\|o] |
Encrypt mode (bcp 18+) | Default mandatory. Pin in prod scripts. |
-u |
Trust server certificate (bcp 18+) | Lab / broken PKI. Not Unicode. |
-H |
Hostname in certificate | DNS alias ≠ cert CN. |
-J |
PEM server certificate | Explicit trust store. |
| Flag | Purpose | Why it matters in scripts |
|---|---|---|
-c / -w / -n / -N |
Character / Unicode char / native / Unicode native | Pick one mode; don’t mix file formats. |
-f |
Format file path | Create with format nul, or consume on in/out. |
-x |
XML format file | Only with format + -f; Windows. |
-t / -r |
Field / row terminator | Default \t / \n. CSV: -t, ; Windows rows often need \r\n in the format file. |
-F / -L |
First / last row (1-based) | Skip CSV header with -F 2. |
-C |
Code page: ACP / OEM / RAW / 65001 |
UTF-8 = 65001 (SQL 2016+). Windows only. Format-file collation can override. |
-q |
QUOTED_IDENTIFIER ON |
Names with spaces/quotes; quote the three-part name. |
-E |
Keep identity values from file (in) |
Needs extra permission path; or skip column via format file. |
-k |
Keep nulls (don’t substitute defaults) | Empty columns stay NULL. |
-R |
Regional formats for currency/date/time | Default ignores regional settings — leave off unless you mean it. |
| Flag | Purpose | Why it matters in scripts |
|---|---|---|
-b |
Rows per batch (in) |
Each batch = one transaction. Default = whole file. |
-a |
Network packet size (4096–65535) | Often 32768–65535 for big loads. |
-h "…" |
Hints (Windows; mainly in) |
TABLOCK, CHECK_CONSTRAINTS, FIRE_TRIGGERS, ORDER(…), ROWS_PER_BATCH=, KILOBYTES_PER_BATCH=. |
-b and -h "ROWS_PER_BATCH=…" are mutually exclusive. Use -b when you want bcp to control batching; use ROWS_PER_BATCH to hint the optimizer when sending as a single transaction.
| Flag | Purpose | Why it matters in scripts |
|---|---|---|
-e |
Error file (rows that failed client-side conversion) | Unique path per run. |
-m |
Max conversion errors before abort (default 10) | Does not apply to server-side constraint failures; does not apply to money/bigint conversion. |
-o |
Redirect stdout to file (Windows) | Unique path per run; not concurrent-safe. |
-v |
Version | Identify which bcp PATH ran. |
-V 80…170 |
Data-type compatibility version (Windows) | Rare; import native/char from earlier engine versions. |
Exit code: 0 success; non-zero failure — always check in PowerShell ($LASTEXITCODE). Native exe does not throw.
| Kind | Extension | Notes |
|---|---|---|
| Non-XML | .fmt |
Portable, easy to edit terminators by hand; original format |
| XML | .xml |
Learn recommends for readability; generate with -x (Windows only) |
Generally interchangeable. Reader bcp version must be ≥ creator version (e.g. 2025/17.0 bcp can read a 2022/16.0 file; 2022 bcp cannot read a 17.0 file).
# Non-XML (.fmt) — portable, easy to edit terminators
bcp AppDb.dbo.InventoryStaging format nul -c -t, -r\n -f .\fmt\InventoryStaging.fmt -S sql01 -d AppDb -T
# XML (.xml) — Learn-recommended readability; Windows (-x)
bcp AppDb.dbo.InventoryStaging format nul -c -x -t, -f .\fmt\InventoryStaging.xml -S sql01 -d AppDb -T
format always requires -f. Data path must be nul.
-c -t,.\r\n (Windows files) or \n (Unix).0 to skip a table column (identity, audit cols) — non-XML column 6 is the server column order..fmt/.xml with deploy scripts under .\fmt\ or Deploy\Bcp\.-C65001: format-file collation/code-page stamps override -C65001 — strip collation from .fmt columns (Learn).| Goal | Approach |
|---|---|
| Engine generates identity | Omit values via format file (server column 0) — preferred for staging loads |
| Keep file identity values | -E on in (needs ALTER TABLE permission path per Learn) |
| Both wrong | Importing identity values without -E — engine ignores file values and generates new ones |
12.0
4
1 SQLCHAR 0 50 "," 1 Sku ""
2 SQLCHAR 0 20 "," 2 Qty ""
3 SQLCHAR 0 30 "," 3 Location ""
4 SQLCHAR 0 24 "\r\n" 4 UpdatedUtc ""
(Version line / column count / field defs — edit terminators and server ordinals to match your table. Generate first; don’t hand-author from scratch.)
Pattern: file → staging (bcp) → stored proc → app views/procs → Blazor.
CLI-07 owns the full pipeline contract. This section is the bcp hop plus the sqlcmd verify/EXEC handoff (CLI-01).
# Secrets: Integrated (-T) or SecretManagement — never commit -P
$Server = 'sql01'
$Db = 'AppDb'
$Data = 'D:\drops\inventory_20260912.csv'
$Fmt = 'D:\deploy\fmt\InventoryStaging.fmt'
$stamp = Get-Date -Format 'yyyyMMdd_HHmmss'
$Err = "D:\logs\bcp_inv_$stamp.err"
$OutLog = "D:\logs\bcp_inv_$stamp.out"
bcp "dbo.InventoryStaging" in $Data `
-S $Server -d $Db -T -f $Fmt -F 2 -b 50000 -m 10 `
-e $Err -o $OutLog -a 65535 `
-h "TABLOCK, CHECK_CONSTRAINTS"
if ($LASTEXITCODE -ne 0) {
throw "bcp in failed exit=$LASTEXITCODE; see $Err / $OutLog"
}
# Verify + transform via sqlcmd (SQL-CLI-01)
sqlcmd -S $Server -d $Db -E -b -V 11 -Q `
"SET NOCOUNT ON; EXEC dbo.usp_Inventory_LoadFromStaging; SELECT COUNT(*) AS Staged FROM dbo.InventoryStaging;"
if ($LASTEXITCODE -ne 0) { throw "usp_Inventory_LoadFromStaging failed" }
# Blazor Server reads dbo.vw_Inventory_Current / EXEC dbo.usp_Inventory_GetPage — not the flat file
$Fmt = 'D:\deploy\fmt\InventoryStaging.fmt'
$servers = @('sql01','sql02')
Get-ChildItem D:\drops\*.csv | ForEach-Object {
foreach ($s in $servers) {
$err = "D:\logs\$($_.BaseName)_$s.err"
Write-Host "=== $($_.Name) → $s ===" -ForegroundColor Cyan
bcp dbo.InventoryStaging in $_.FullName `
-S $s -d AppDb -T -f $Fmt -F 2 -b 50000 -e $err
if ($LASTEXITCODE -ne 0) {
Write-Error "Fail $($_.Name) on $s exit=$LASTEXITCODE; see $err"
continue
}
sqlcmd -S $s -d AppDb -E -b -V 11 -Q "SET NOCOUNT ON; EXEC dbo.usp_Inventory_LoadFromStaging;"
if ($LASTEXITCODE -ne 0) { Write-Error "proc failed on $s"; continue }
}
}
function Invoke-Bcp {
param([Parameter(ValueFromRemainingArguments)]$BcpArgs)
& bcp @BcpArgs
if ($LASTEXITCODE -ne 0) {
throw "bcp failed exit=$LASTEXITCODE args=$($BcpArgs -join ' ')"
}
}
Invoke-Bcp dbo.Inventory out D:\export\Inventory.bcp -S sql01 -d AppDb -T -n
| Do | Don’t |
|---|---|
-T or prompt / SecretStore |
-P 'Secret' on cmdline, scheduled task args, or transcript logs |
Unique -e / -o per run |
Silent overwrite of last error file |
| Stage → proc (set-based) | bcp straight into hot OLTP tables Blazor reads mid-load |
$LASTEXITCODE after every bcp/sqlcmd |
Assume success because no exception (native exe doesn’t throw) |
| Truncate/switch staging in proc under transaction | Leave half-loaded staging visible to app |
Pin full bcp.exe path in Agent |
Rely on service-account PATH after CU installs |
Already holding rows in PowerShell / .NET? Prefer CLI-03 — no temp file, typed mapping, same staging→proc pattern. Use bcp when the artifact is a file (vendor drop, inventory extract on disk).
| Topic | Reality |
|---|---|
| Unicode / code page | Prefer -w for text exports. -c uses client OEM unless -C. UTF-8: -C 65001 (SQL 2016+). Format-file collation overrides -C65001 — strip collation from .fmt. |
Empty string ↔ NULL on out |
Learn: empty string exported as null; null exported as empty string. Spot-check with sqlcmd. |
| Identity | Without -E, identity values in file are ignored (engine generates). With -E, need permission path that allows it (ALTER TABLE scenario per Learn). Or omit column via format file. |
| Triggers | Default off on in. Use -h "FIRE_TRIGGERS" to enable. Ignored for out / queryout / format. |
| CHECK / FK | Default not checked; constraints left untrusted. Use -h "CHECK_CONSTRAINTS" or re-check after load. PK / UNIQUE / NOT NULL always enforced. -m does not apply to constraint checking. |
| TABLOCK | Speeds bulk; blocks writers. Good for staging; careful on live tables Blazor reads. |
| Azure SQL | Client-side bcp works; firewall must allow jump-box IP. Watch DTU/CPU on large -b. No Windows -T — use -G. Path still limited to 255 chars on the client. |
| Wide rows / LOBs | Huge row size → lower -b, raise -a, watch memory. Native often better than character for LOBs. |
queryout + temp tables |
Temp tables created inside a proc aren’t visible to bcp statement metadata — land in a real/staging table first. |
| Permissions | out: SELECT. in: SELECT+INSERT; often ALTER TABLE if constraints/triggers disabled by default or using -E. bulkadmin / ADMINISTER BULK OPERATIONS is for BULK INSERT/OPENROWSET — not required for bcp. |
| Error file | -e captures rows bcp couldn’t convert client-side; server-side constraint failures may roll back the batch without those rows appearing in -e. |
| Message truncation | bcp shows only first 512 bytes of an error message — check SQL error log / -o for more context. |
| Format file version | Reader ≥ creator. Don’t generate with bcp 18 and consume with bcp 15. |
-b vs ROWS_PER_BATCH |
Mutually exclusive. Failed batch rolls back only that batch; prior committed batches stay. |
-c vs -w |
Incompatible — never combine. |
-u vs -w |
-u = trust cert (bcp 18+). -w = Unicode character. Do not confuse with sqlcmd’s -u (Unicode output file). |
| Locking / concurrency | Multiple clients can load a heap with TABLOCK; indexes change the story. Columnstore has its own concurrent load behavior (Learn). |
Vector (-z) |
bcp 18.6.1.1+; niche for SQL 2025 vector type — ignore unless you use vectors. |
Placeholders: sql01 / AppDb / contoso.database.windows.net. Swap in yours. Every recipe checks $LASTEXITCODE after native exes.
bcp "AppDb.dbo.Inventory" out "D:\export\Inventory.csv" -S sql01 -T -w -t, -r\n
if ($LASTEXITCODE -ne 0) { throw "bcp out failed: $LASTEXITCODE" }
queryout filtered extractbcp "SELECT Sku, Qty, UpdatedUtc FROM AppDb.dbo.Inventory WHERE UpdatedUtc >= '2026-09-01'" `
queryout "D:\export\Inventory_delta.csv" -S sql01 -d AppDb -T -w -t,
if ($LASTEXITCODE -ne 0) { throw "queryout failed: $LASTEXITCODE" }
bcp AppDb.dbo.InventoryStaging format nul -c -t, -f D:\deploy\fmt\InventoryStaging.fmt -S sql01 -T
if ($LASTEXITCODE -ne 0) { throw "format failed: $LASTEXITCODE" }
# Edit .fmt: skip identity (server column ordinal 0), confirm \r\n on last field
bcp dbo.InventoryStaging in "D:\drops\vendor.csv" `
-S sql01 -d AppDb -T -f D:\deploy\fmt\InventoryStaging.fmt `
-F 2 -b 50000 -m 10 -e D:\logs\vendor.err -h "TABLOCK"
if ($LASTEXITCODE -ne 0) { throw "bcp in failed: $LASTEXITCODE" }
bcp AppDb.dbo.Inventory out D:\backup\Inventory.bcp -S sql01 -T -n -a 65535
if ($LASTEXITCODE -ne 0) { throw "native out failed" }
bcp AppDb.dbo.Inventory_Clone in D:\backup\Inventory.bcp -S sql01 -T -n -b 100000 -h "TABLOCK"
if ($LASTEXITCODE -ne 0) { throw "native in failed" }
-C65001)# After generating .fmt, strip collation names from character columns so 65001 wins
bcp dbo.InventoryStaging in D:\drops\vendor_utf8.csv `
-S sql01 -d AppDb -T -c -C 65001 -t, -F 2 -f D:\deploy\fmt\InventoryStaging_utf8.fmt `
-b 50000 -e D:\logs\vendor_utf8.err
if ($LASTEXITCODE -ne 0) { throw "UTF-8 import failed: $LASTEXITCODE" }
$LASTEXITCODEfunction Invoke-Bcp {
param([Parameter(ValueFromRemainingArguments)]$BcpArgs)
& bcp @BcpArgs
if ($LASTEXITCODE -ne 0) {
throw "bcp failed exit=$LASTEXITCODE args=$($BcpArgs -join ' ')"
}
}
Invoke-Bcp dbo.Inventory out D:\export\Inventory.bcp -S sql01 -d AppDb -T -n
$S='sql01'; $D='AppDb'
bcp dbo.InventoryStaging in D:\drops\inv.csv -S $S -d $D -T `
-f D:\deploy\fmt\InventoryStaging.fmt -F 2 -b 50000 -e D:\logs\inv.err
if ($LASTEXITCODE -ne 0) { throw "bcp in failed" }
sqlcmd -S $S -d $D -E -b -V 11 -Q "SET NOCOUNT ON; EXEC dbo.usp_Inventory_LoadFromStaging;"
if ($LASTEXITCODE -ne 0) { throw "proc failed" }
# Blazor uses: EXEC dbo.usp_Inventory_GetPage @Skip=@p0, @Take=@p1
sqlcmd -S $S -d $D -E -b -Q "SET NOCOUNT ON; SELECT TOP 5 * FROM dbo.vw_Inventory_Current;"
if ($LASTEXITCODE -ne 0) { throw "verify failed" }
bcp dbo.Inventory in D:\restore\Inventory.bcp -S sql01 -d AppDb -T -n -E `
-h "FIRE_TRIGGERS, CHECK_CONSTRAINTS" -b 10000 -e D:\logs\id_restore.err
if ($LASTEXITCODE -ne 0) { throw "identity restore failed: $LASTEXITCODE" }
bcp dbo.Inventory out D:\export\Inventory_az.csv `
-S contoso.database.windows.net -d AppDb -G -U 'rick@contoso.com' `
-w -t, -l 60
if ($LASTEXITCODE -ne 0) { throw "Azure bcp out failed: $LASTEXITCODE" }
bcp dbo.InventoryStaging in D:\drops\inv.csv `
-S "tcp:sql01.contoso.local,1433" -d AppDb -T `
-f D:\deploy\fmt\InventoryStaging.fmt -F 2 `
-Y m -u -b 50000 -e D:\logs\lab.err
if ($LASTEXITCODE -ne 0) { throw "lab bcp in failed: $LASTEXITCODE" }
-F / -L)# Import only rows 2–10001 (skip header, first 10k data rows) for a staging dry-run
bcp dbo.InventoryStaging in D:\drops\big_vendor.csv `
-S sql01 -d AppDb -T -f D:\deploy\fmt\InventoryStaging.fmt `
-F 2 -L 10001 -b 5000 -e D:\logs\sample.err -h "TABLOCK"
if ($LASTEXITCODE -ne 0) { throw "sample import failed: $LASTEXITCODE" }
File on client / Agent, need speed? → bcp
File on SQL host, T-SQL job? → BULK INSERT
In-process .NET / Blazor worker? → SqlBulkCopy / Write-SqlTableData (CLI-03)
Verify / EXEC proc / row samples? → sqlcmd (CLI-01)
SQL↔SQL internal hop? → bcp -n / -N
Vendor CSV / Excel-friendly? → bcp -w or -c -t, + format file
Azure SQL? → bcp -G (not -T); watch firewall/DTU
Need Encrypt/TSC / Kerberos matrix? → CLI-06
Need full Collect→Stage→Load→Blazor? → CLI-07
| Go here | When |
|---|---|
| SQL-CLI-01 — sqlcmd / go-sqlcmd | Verify counts, EXEC usp_*, exit-code discipline after the bcp hop. |
| SQL-CLI-03 — SqlServer module | Write-SqlTableData / SqlBulkCopy / Invoke-Sqlcmd objects when you already hold rows in PS/.NET. |
| SQL-CLI-06 — Connection & auth | Kerberos/double-hop, Encrypt/TSC across every tool, “never put secrets on argv”. |
| SQL-CLI-07 — PS → SQL → Blazor | Full Collect→Stage→Load→EXEC→Blazor contract, watermarks, multi-server glue. |
Need verify / EXEC after load? → sqlcmd -b + $LASTEXITCODE (CLI-01)
Need in-process bulk without a file? → Write-SqlTableData / SqlBulkCopy (CLI-03)
Need hop / Encrypt / identity matrix? → CLI-06
Need the pipeline, not the client? → CLI-07
Sources (verify periodically):
bcp utility · Download/install bcp · Entra auth in bcp · Create a format file · BULK INSERT · Use a format file to skip a table column