-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Describe the change
Below are clear, concise guidelines for using Write-Debug and Write-Verbose in PowerShell, distilled from industry best practices and practical reasoning:
1. Write-Verbose: For "What" and "High-Level Progress"
Use Write-Verbose to log:
- What the code is doing (e.g., steps, milestones, progress).
- Non-sensitive operational details (e.g., "Connecting to database...", "Processing 100 items...").
- User-triggered insights for troubleshooting or auditing workflows.
Example:
Write-Verbose "Starting data import from $FilePath"
Write-Verbose "Validating user permissions for $UserName" Why?
- Enabled via
-Verboseswitch or$VerbosePreference. - Ideal for users/administrators who need context without technical depth.
2. Write-Debug: For "Why" and "Diagnostic Details"
Use Write-Debug to expose:
- Internal state (e.g., variable values, conditions, loop counters).
- Diagnostic clues for developers (e.g., "Value of $x is 42", "Skipping item due to condition X").
- Critical decision points where execution flow may break.
Example:
Write-Debug "Parameter validation failed: $ErrorDetails"
Write-Debug "Retry count: $Retry (Max: $MaxRetries)" Why?
- Enabled via
-Debugswitch or$DebugPreference = 'Continue'. - Pauses execution (by default) to allow developer inspection of state.
- Targets script authors/maintainers during debugging.
3. Key Differences & Rules of Thumb
| Aspect | Write-Verbose |
Write-Debug |
|---|---|---|
| Audience | End-users, admins, support teams | Developers, maintainers |
| Content | What is happening | Why something happened (diagnostics) |
| Execution Impact | Non-blocking | Pauses execution (when -Debug used) |
| Use Case | Logging, progress tracking | Deep troubleshooting, variable dumps |
| Default Visibility | Hidden (requires -Verbose) |
Hidden (requires -Debug) |
4. When to Avoid Both
- Never expose secrets (passwords, keys) via either stream.
- Avoid trivial messages (e.g., "Loop iteration 1", "Function started") unless they add value.
- Prefer
Write-Error/Write-Warningfor actual errors/warnings.
5. Best Practices
- Use
[CmdletBinding()]in functions to enable-Verbose/-Debugsupport. - Leverage pipeline: Pipe verbose/debug output to logs during automation.
- Conditional checks: For performance-critical code:
if ($PSCmdlet.MyInvocation.BoundParameters["Verbose"]) { ... }
- Consistency: Adopt a team standard (e.g., "Verbose for milestones, Debug for state dumps").
Example Implementation
function Get-SystemInfo {
[CmdletBinding()]
param()
Write-Verbose "Initializing system scan..."
$os = Get-CimInstance Win32_OperatingSystem
Write-Debug "OS details: $($os | Out-String)"
Write-Verbose "Calculating uptime..."
$uptime = (Get-Date) - $os.LastBootUpTime
Write-Debug "Uptime calculated: $($uptime.TotalHours) hours"
Write-Verbose "Scan complete."
}Summary
Write-Verbose= User-focused progress tracker.Write-Debug= Developer-focused diagnostics tool.- Rule: If you’re explaining behavior, use
Verbose. If you’re exposing state, useDebug.
Adhering to these guidelines ensures your scripts are maintainable, user-friendly, and debuggable while avoiding noise.
Best Practices: Using Write-Verbose vs. Write-Debug in PowerShell Scripts
Understanding Verbose vs. Debug Output
PowerShell provides two streams for optional diagnostic output: Verbose and Debug. Both are suppressed by default, and only show up when enabled (via script parameters or preference variables). However, they serve different purposes:
- Write-Verbose writes text to the verbose stream. These messages are meant for trace/log information about script execution (e.g. progress, decisions made, values of parameters). They do not display unless you run the script with the
-Verboseswitch (which sets$VerbosePreference='Continue'). In normal runs, they stay hidden, keeping output clean. - Write-Debug writes text to the debug stream. These messages are intended for debugging and troubleshooting deeper issues. By default they are also hidden (
$DebugPreference='SilentlyContinue'), but if you run with the-Debugswitch, PowerShell sets$DebugPreference='Inquire'. This means it not only displays debug messages, but also pauses execution at each Write-Debug call and prompts you for action (entering an interactive debug mode). In other words, Write-Debug can act like a breakpoint in your script when-Debugis used.
Understanding this difference is key to using them effectively. In summary, use Write-Verbose for optional runtime logs and Write-Debug for developer-centric debugging. Below are guidelines on when to choose each.
When to Use Write-Verbose
Use Write-Verbose for informational messages about normal script operations that can help users or maintainers understand what the script is doing when needed (but aren’t necessary in default output). Some guidelines for using Write-Verbose:
-
Trace Script Flow and Progress: Emit messages for major steps or decision points in your script (e.g. "Connecting to server X", "Processed N items", "Operation completed successfully"). This makes it easier to follow the script’s flow when verbose mode is on. By including such messages at each significant step, you provide a built-in way to see what the script is doing without cluttering standard output.
-
Troubleshooting and Auditing: Rely on verbose output to diagnose issues. In day-to-day runs, the script will be quiet, but if a problem arises, running it with
-Verbosewill reveal the internal steps and data involved. This is a common practice in PowerShell – run with-Verbosewhen you need to troubleshoot, and run normally when you don’t. -
Non-Intrusive Logging: Because verbose messages are hidden by default, you can add them generously without worrying about spamming the console or logs in normal operation. In fact, a well-written script “uses Write-Verbose a lot” to provide insight when needed. Think of verbose messages as optional log entries or “live documentation” of what your code is doing.
-
Example – Using Write-Verbose:
function Update-Data { [CmdletBinding()] # Enables -Verbose automatically param($Server, $File) Write-Verbose "Connecting to server $Server" # ... perform connection Write-Verbose "Importing data from $File" # ... perform import Write-Verbose "Operation completed." }
If you run
Update-Data -Server "Prod01" -File "data.csv" -Verbose, you might see output like:
VERBOSE: Connecting to server Prod01
VERBOSE: Importing data from data.csv
VERBOSE: Operation completed.
These messages won’t appear without-Verbose, so in normal runs the function would only output actual results or nothing at all.
Why Write-Verbose: It provides optional runtime information to the user or operator. This is ideal for scripts used in both automated and interactive scenarios – it keeps default output clean, but allows anyone running the script to opt-in to detailed logs when needed. Always favor Write-Verbose for general logging over something like Write-Host, because verbose messages go to a dedicated stream that can be enabled, captured, or ignored easily.
When to Use Write-Debug
Use Write-Debug for debugging messages that are primarily of interest to developers or advanced users diagnosing problems. These are deeper insights or checkpoints in code execution, used less frequently than verbose messages. Guidelines for Write-Debug:
-
Interactive Debugging Breakpoints: A Write-Debug call acts like a breakpoint when the script is run with
-Debug. PowerShell will halt at that line and prompt the user (with options to continue, suspend, etc.). This is extremely useful during development or troubleshooting a script interactively – you can inspect variables, step through code, and then continue execution. For example, you might sprinkle a fewWrite-Debug "Checkpoint: variable X = $X"lines in a loop or complex function, so that if you run-Debugyou can examine state at those points. -
Extra-Verbose Logging (Developer Focused): Use Write-Debug for messages that are even more detailed or technical than verbose output – for instance, dumping full objects or internal data structures that typical users don’t need to see. These messages can be output without breaking execution if you adjust
$DebugPreference, but by default they won’t appear at all unless debugging is enabled. Think of Write-Debug as a way to get “even deeper” logs when you explicitly want them. For example, after a complex calculation you might includeWrite-Debug "Calculated matrix: $(ConvertTo-Json $matrix)"so you can review the data structure when debugging. -
Use Sparingly in Production Code: Because Write-Debug is tied to the interactive debugging mode, use it thoughtfully. It’s best for scenarios where a developer (or power user) might intentionally run the script with
-Debugto diagnose an issue. It’s less suitable for routine logging – you wouldn’t generally turn on-Debugin daily runs or in automation, since it will pause for input by default. Many teams actually rely more on verbose logging and rarely use Write-Debug unless they plan to attach a debugger or step through manually. If you do include Write-Debug statements, ensure they serve a clear purpose for debugging, and document that they exist (so others know running with-Debugwill trigger breakpoints). -
Example – Using Write-Debug:
function Get-Config { [CmdletBinding()] param($Path) Write-Verbose "Reading configuration from $Path" $config = Import-Clixml $Path Write-Debug "Raw config data: $($config | Out-String)" # ... process $config }
In normal runs,
Get-Configjust reads the file. If run with-Verbose, it will print the "Reading configuration..." message. If run with-Debug, PowerShell will pause when it hits the Write-Debug line, showing the debug message and entering debug mode. This allows the operator to inspect$config(since we output its raw data in the debug message) before continuing. If you simply want to see the debug message without stopping, you could manually set$DebugPreference = "Continue"and run the function (this would printDEBUG: Raw config data: ...to the console without prompting). However, in most cases it's easier to reserve Write-Debug for interactive use.
Why Write-Debug: It provides a built-in mechanism for interactive debugging in PowerShell. When developing or maintaining scripts, Write-Debug lets you mark spots to check, and if something goes wrong, you can rerun the script with -Debug to drop into a debug session at those spots. It’s like placing breakpoints via code. For everyday logging or user-facing detail, though, Write-Verbose is the better choice (since it won't interrupt execution).
Best Practices for CI/CD Pipeline Runs (Automation)
When running PowerShell scripts in CI/CD or other non-interactive automation, you need to be careful with debug vs verbose output:
- Prefer Verbose Logging in CI/CD: In automated pipelines, you typically want to keep output minimal unless there’s a failure or need for diagnostics. Using
Write-Verboseallows you to emit detailed logs that can be turned on when needed. For example, you might run your deployment script normally to keep logs clean, but if a pipeline job fails or you need more insight, you can re-run it with the-Verboseflag (or set an environment variable to enable verbose output) to get the detailed trace of what the script is doing. This is a standard practice: run verbose logs “on demand” for troubleshooting, but not always by default. - Avoid Interactive Debug Prompts: Do not use
-Debugin a CI/CD run. The-Debugswitch will set PowerShell to inquire mode and pause on each Write-Debug, expecting a person to respond. In a pipeline, there is no interactive user, so the script would hang indefinitely. As a rule, never enable full debug mode in unattended execution. Any Write-Debug statements in your code will simply be skipped over (since$DebugPreferencestaysSilentlyContinue), which is usually fine. Design your scripts such that all necessary logging for automation is done via Write-Verbose (and Write-Warning/Write-Error as appropriate), reserving Write-Debug for human troubleshooting sessions. - Capturing Verbose Output: Ensure your pipeline is set up to capture or display verbose output when enabled. Many CI systems will print verbose messages if the script is run with
-Verbose. For instance, Azure Pipelines treats verbose and debug streams as “diagnostic logs” that show up when you enable debugging in the pipeline. Check your CI tool’s documentation – you might need to set a variable (likeSystem.Debug=truein Azure DevOps) or run the script with a parameter to see verbose output. This way, developers can get detailed logs from pipeline runs without modifying the script. - Use Debug Messages Only for Development: It’s okay to include
Write-Debugin your script for the benefit of developers, but consider them inactive in CI. They will not appear unless someone intentionally runs with debug mode (which we avoid in CI) – essentially, they serve as inline breakpoints or deep diagnostics for use on a local machine. If you find yourself needing the kind of information Write-Debug provides during an automated run, that’s a sign you should promote that information to a verbose message or explicit log output. In other words, pipeline logging should rely on verbose output and proper error handling, not on debug breaks.
Best Practices for Interactive/Local Use
When running scripts on a local machine or in an interactive session (e.g. a developer running the script in PowerShell console or ISE), you can leverage both verbose and debug output for a better experience:
- Leverage
-Verbosefor Insight: Encourage your team to run scripts with-Verboseif they want to understand the script’s behavior or troubleshoot an issue. The verbose messages you added will act as a guided commentary of the script’s actions. This is especially helpful for new users of the script or when running a long complex process – they can see that “now we’re doing step X, now step Y,” etc., which provides reassurance and insight. It’s an optional comfort level for interactive use. - Use
-Debugfor Troubleshooting Code: When a developer needs to step through the script logic, they can run with the-Debugswitch. As explained, this will pause at each Write-Debug call and allow the person to examine or modify variables, then continue or quit. This is a powerful way to troubleshoot live – essentially, your Write-Debug calls are predefined breakpoints. For example, running a script with-Debugmight yield output like:
DEBUG: Raw config data: {...}
Confirm Debugging? [Y]es [A]ll [H]alt ...(this is the prompt on a Write-Debug line).
The user can press Suspend to enter the debugger, inspect the environment (check variables, run commands), then type Continue to resume the script. This technique should be used when you suspect a logic error or need to inspect intermediate state that verbose logs alone aren’t explaining. It’s especially useful during development or when replicating an issue locally that was hard to diagnose just from logs. - Combine Verbose and Debug for Clarity: You can use both output types in a script. In fact, advanced functions support both
-Verboseand-Debugsimultaneously. For example, you might include many Write-Verbose messages for general steps, and a few targeted Write-Debug messages for critical internals. A developer can run with both-Verboseand-Debugswitches at once – verbose messages will stream out continuously, and the script will pause at debug points. This gives a full picture: the verbose output shows the high-level flow, and the debug breakpoints let the dev inspect state at key moments. While this is powerful, it’s up to the developer’s discretion to use it. In normal interactive use,-Verbosealone is usually sufficient to understand script behavior, and-Debugis only invoked when deeper investigation is needed. - Tip: Enable CmdletBinding: Always define your scripts or functions with
[CmdletBinding()](and use aparam()block) to automatically enable the-Verboseand-Debugcommon parameters. This way, you don’t have to manually code switches for verbose/debug; PowerShell will handle it. Then calls to Write-Verbose/Write-Debug will respect the user’s-Verbose/-Debugchoice. In interactive scenarios, this means any user can easily toggle verbose or debug mode when running the script, without any extra work on your part.
Summary
Write-Verbose and Write-Debug are invaluable tools for building maintainable PowerShell scripts. As a simple rule of thumb: use Write-Verbose for optional informational output (logging the script’s normal operations), and use Write-Debug for optional debugging output (investigating issues during development). Verbose output is the go-to for running in both CI pipelines and everyday use with minimal risk – it provides detail on demand without disrupting execution. Debug output is there for the rare occasions you need to pause and inspect the inner workings interactively, but should be enabled intentionally and avoided in automated runs.
By following these guidelines, developers can instrument their scripts with useful messages that stay out of the way during normal operation, yet greatly assist in troubleshooting and debugging when the need arises. This leads to cleaner scripts, easier debugging, and more transparency in both automated and interactive environments.