[Automation]Modular Scripts & Error Handling

Summary: Use AI to write solid modular scripts — errors won't break them, and every run leaves a traceable log.


1. The Problem

You've probably been burned by this kind of thing:

  • You asked AI for a PowerShell script, a 200–300 line "blob" that looked runnable; then the third file errored out, the whole script crashed on the spot, everything before it ran for nothing, and you had to start over.
  • When something failed it just threw a single line of red text — you had no idea which file or which step blew up, so you had to test files one by one by hand.
  • The next day your boss wanted the same processing again, and you found the path hardcoded on line 80 of the code; renaming a folder meant digging through the code for ages.

At its core, three things were missing: the script wasn't split into modules, didn't catch errors, and didn't log. In this article we'll use Qwen as our assistant to write a PowerShell script that is "split-apart, catch-capable, traceable" — it won't crash on errors, and if it does crash you can trace it, and editing it won't be a headache.

First, get to know a few terms (no more explaining later):

  • PowerShell = Windows' built-in "supercharged command line," purpose-built for batch automation — no install needed.
  • function / module = slicing a big script into independent little functions, like LEGO — change whichever block you need.
  • try/catch = putting a seatbelt on your script; it won't crash on errors, and it can record where things went wrong.
  • log = writing the script's run process into a txt file, the script's equivalent of a "dashcam."
  • parameterization = pulling the things that change (paths, file names) to the top of the script and controlling them with parameters, so editing doesn't touch the main code body.

2. What You'll Build

By following this article, you'll get a truly runnable PowerShell script that does three things:

  1. Merge all CSVs in the "Reports" folder into one master table (each row gets an extra "SourceFile" column for traceability);
  2. If one file is broken (won't open, or is locked) it won't affect the others — try/catch catches it, the bad one gets logged, the good ones merge as usual;
  3. Every step's success/failure is written to a log file, so afterward you can check "who succeeded, who failed, and why."

And the script uses function to split into three modules, with all paths parameterized via param — you change paths without touching the main code body.

3. Hands-On Walkthrough

Our workflow: First translate the requirement into a prompt for the AI → get a first draft → we refine it into a "modular + error handling + logging" finished product → run it and see the result.

Step 1: Translate the requirement into a prompt for "Qwen"

Open Qwen (tongyi.aliyun.com or the Qwen Qwen app), and paste the following directly in. The key point: the more specific your "requirements," the closer the AI's first draft is to something usable:

I'm on Windows using PowerShell. Please write me a script: merge every CSV in the "报表" folder into one master table — all files share the same fields. Requirements:
1) Split it into modules with functions (a logging function, a merge-one-file function, a main flow);
2) Wrap each file in try/catch so one bad file doesn't affect the others;
3) Write every step's success/failure to a log file;
4) Control the source folder, output file, and log file paths via param parameters so they're easy for me to change;
5) The code must run directly under Windows PowerShell 5.1, with comments in English.
Give me the complete code.

Qwen will output a version. But AI first drafts often fall into two traps: no -ErrorAction Stop inside try (so errors don't go into catch), and Chinese comments without considering encoding (see Section 5). So we take the draft as a base and turn it into the battle-tested finished product below.

Step 2: The finished script (modular + try/catch + logging + parameterized)

Save the entire block below as 合并报表.ps1 (when saving, note item 1 of Section 5 — Chinese must have a BOM):

powershell
<# B19 sample: batch-merge CSVs (modular + try/catch + logging + parameterized) Works on both Windows PowerShell 5.1 and PowerShell 7, runs as-is Usage: powershell -ExecutionPolicy Bypass -File 合并报表.ps1 -SourceFolder ".\报表" -OutputFile ".\总表.csv" -LogFile ".\运行日志.log" (On PowerShell 7, just replace powershell with pwsh in the command above) #> # ========== Parameterized entry point (must sit at the very top of the script) ========== param( [string]$SourceFolder = ".\报表", [string]$OutputFile = ".\总表.csv", [string]$LogFile = ".\运行日志.log" ) # Store the log path as a script-level variable for Write-Log below $script:LogFile = $LogFile # ========== Module 1: logging function ========== # try/catch = a seatbelt for the script: it won't crash on errors, and it records where things went wrong function Write-Log { param( [Parameter(Mandatory = $true)] [string]$Message, [ValidateSet("INFO", "WARN", "ERROR")] [string]$Level = "INFO" ) $time = Get-Date -Format "yyyy-MM-dd HH:mm:ss" $line = "[" + $time + "][" + $Level + "] " + $Message # Write to both screen and log file; UTF8 avoids garbled characters Add-Content -Path $script:LogFile -Value $line -Encoding UTF8 Write-Host $line } # ========== Module 2: merge a single CSV ========== function Merge-OneCsv { param( [Parameter(Mandatory = $true)] [string]$SourceFile, [Parameter(Mandatory = $true)] [string]$OutputFile ) try { # ErrorAction Stop: make Import-Csv errors actually enter catch instead of just warning $rows = Import-Csv -Path $SourceFile -Encoding UTF8 -ErrorAction Stop # Add a SourceFile column to every row for later traceability $rows | ForEach-Object { $_ | Add-Member -MemberType NoteProperty -Name "SourceFile" -Value (Split-Path $SourceFile -Leaf) -Force } # -Append: append the multiple files onto the same master table $rows | Export-Csv -Path $OutputFile -Encoding UTF8 -NoTypeInformation -Append -ErrorAction Stop $count = ($rows | Measure-Object).Count Write-Log -Message ("Merged: $SourceFile ($count rows)") -Level "INFO" } catch { # $_ is PowerShell's "current error object"; it carries the error details Write-Log -Message ("Merge failed: $SourceFile -- " + $_.Exception.Message) -Level "ERROR" # Note: no throw here - let the script move on to the next file } } # ========== Module 3: main flow ========== Write-Log -Message "===== Merge job started =====" -Level "INFO" Write-Log -Message ("Source folder: $SourceFolder") -Level "INFO" # If the source folder doesn't exist, log an error and exit right away if (-not (Test-Path -Path $SourceFolder)) { Write-Log -Message ("Source folder not found: $SourceFolder") -Level "ERROR" exit 1 } # Clear the old master table first so -Append doesn't stack historical data on top if (Test-Path -Path $OutputFile) { Remove-Item -Path $OutputFile -Force } # Process the CSVs one by one Get-ChildItem -Path $SourceFolder -Filter *.csv -File | ForEach-Object { Merge-OneCsv -SourceFile $_.FullName -OutputFile $OutputFile } Write-Log -Message "===== Merge job finished =====" -Level "INFO"

How to read this (the three modules at a glance):

  • Module 1 Write-Log: solely responsible for "writing a line." Anywhere you want to leave a trace later, just call it — no need to repeat the file operations.
  • Module 2 Merge-OneCsv: does only one thing — merge "one" CSV. The key is the try/catch wrapping it: once the Import-Csv inside errors (file locked, corrupted), it jumps to catch and logs the error, without throwing or interrupting, so the next file is processed as normal.
  • Module 3 main flow: first logs the start, checks whether the folder exists, clears the old master table, then uses Get-ChildItem to feed each CSV in "Reports" to Module 2 one by one. The few lines of param(...) at the top are the parameterization — change paths by editing only these three lines, no need to dig through the code.

Step 3: Run it and see the result

Prepare a "Reports" folder with two same-field CSVs inside (e.g., a.csv, b.csv, both with "Name,Amount" columns). Then run it by any of the three methods:

  • Method A (most reliable): In File Explorer, go to the script's directory, hold Shift and right-click empty space → "Open in Terminal" → enter:
    powershell
    powershell -ExecutionPolicy Bypass -File .\合并报表.ps1 -SourceFolder ".\报表" -OutputFile ".\总表.csv" -LogFile ".\运行日志.log" # on PowerShell 7, replace powershell with pwsh
  • Method B (VS Code): Install the PowerShell extension, open the script, and click "Run" in the top right.
  • Method C (ISE): Search "PowerShell ISE" in the Start menu, open the script, and press F5.

After running, two extra files appear: 总表.csv (the merge result, with the "SourceFile" column) and 运行日志.log (the success/failure record of every step). Want to switch folders? Just change the -SourceFolder value, e.g. -SourceFolder "D:\DailyReports", without touching the script body — that's the beauty of parameterization.

4. How It Works

Modularization, error handling, and logging are the "iron triangle": modules make scripts readable and editable (fix just the broken block, no ripple effect); try/catch keeps localized failures from spreading (one file blows up, the others keep running, the script survives); logging makes failures traceable (open the log to know who failed and why). AI is good at spitting out first drafts along this skeleton, but it often misses two boundaries — errors without -ErrorAction Stop can't be caught, and Chinese without a BOM turns to garbage — these two spots you must check yourself. What's left is reusing this template and swapping "merge CSV" for your own task.

5. Pitfall Guide

  1. Script has Chinese? Always save as "UTF-8 with BOM." This is the easiest trap to fall into. PowerShell 5.1 reads .ps1 by default in the system encoding (GBK on Chinese systems); UTF-8 without BOM makes Chinese get read in as garbage wholesale, causing all sorts of inexplicable parse errors (e.g., "The Try statement is missing its Catch or Finally block," "missing terminator," etc. — this very script was tormented by that). In VS Code: click the encoding at the bottom right → "Save with Encoding" → choose UTF-8 with BOM; or just upgrade to PowerShell 7, which reads UTF-8 without BOM. The laziest fix: minimize Chinese comments, or use Chinese only in strings and never touch code keywords.
  2. Always add -ErrorAction Stop inside try. Many PowerShell commands only "warn" on error and don't enter catch by default; only with Stop added does the error truly get caught by try/catch. The -ErrorAction Stop after Import-Csv in this article cannot be omitted by a single character.
  3. Use -Encoding UTF8 for logging, not the default encoding. PowerShell 5.1 doesn't write files as UTF-8 by default; on a different machine the Chinese may turn to garbage; Add-Content -Encoding UTF8 is the most reliable explicit choice.
  4. Export-Csv -Append needs PowerShell 3.0+. Old environments (e.g., very old Windows) lack -Append; you'd have to first collect all rows into a variable and then Export-Csv once, otherwise it overwrites instead of appending.
  5. When controlling Excel with a COM object, always Quit + release in finally. Otherwise the Excel process gets stuck in the background and won't close, piling up the more you run (see the snippet in Section 6).

6. Going Further

  • Cross-reference B17 (afraid of the black window? AI teaches you to run your first command): If you haven't set up the environment and break into a sweat at the sight of the black window, review B17 first and get "your first command running," so this article's script has somewhere to land.
  • Cross-reference B17 "Write Your First PowerShell Command with AI": the three-check method, the dangerous-command blacklist, and the execution-policy explanation all live in that article — lay a solid foundation of "running commands without tripping up" first, then this article will read much more smoothly.
  • Go deeper to L4: make the script run itself on a schedule. Hook today's 合并报表.ps1 up to Windows' "Task Scheduler," set it to auto-merge yesterday's reports at dawn every day, and you wake up to the master table. Or skip code entirely — Power Query in Excel (Data → Get Data → From File → From Folder) merges CSVs with a few mouse clicks, a "no-code alternative" to the script.
  • Dive into COM objects (the next layer of basics): To drive Excel directly with PowerShell for batch filling or batch format conversion, you rely on the "remote-control Excel" approach below. It requires Excel installed on the local machine; the logic is standard, but this article's environment has no Excel and was not actually run — you can copy it as-is when you have Excel locally:
powershell
# A COM object = Component Object Model; plainly put, it lets PowerShell directly "remote-control" the already-installed Excel program # This snippet ships its own minimal logging function, so you can copy it as-is and run it standalone (no dependency on Write-Log from the earlier script) function Write-Log { param([string]$Message, [string]$Level = "INFO") $line = "[" + (Get-Date -Format "yyyy-MM-dd HH:mm:ss") + "][$Level] " + $Message Write-Host $line } $excel = New-Object -ComObject Excel.Application $excel.Visible = $false # run in the background, no window $excel.DisplayAlerts = $false # don't pop the "do you want to save" confirmation box try { $wb = $excel.Workbooks.Open("C:\报表\样例.xlsx") # hardcoded Chinese path kept as-is $ws = $wb.Worksheets.Item(1) $ws.Range("A1").Value2 = "Processed" # put the given content into A1 $wb.Save() } catch { Write-Log -Message ("Excel operation failed: " + $_.Exception.Message) -Level "ERROR" } finally { # finally = the cleanup that always runs, success or fail; release Excel here or the process lingers in the background if ($wb) { $wb.Close($false) } $excel.Quit() # Release COM references in reverse order: worksheet first, then workbook, finally the Excel process if ($ws) { [System.Runtime.Interopservices.Marshal]::ReleaseComObject($ws) | Out-Null } if ($wb) { [System.Runtime.Interopservices.Marshal]::ReleaseComObject($wb) | Out-Null } if ($excel) { [System.Runtime.Interopservices.Marshal]::ReleaseComObject($excel) | Out-Null } }

To sum up: what you got today is a "reusable script skeleton" — swap the work inside Merge-OneCsv for your own (renaming, format conversion, sending email, anything goes), keep the modules and logging as-is, and you get a stable, traceable automation tool.