Skip to content

Mark Export-Csv -Path and -LiteralPath parameters as mandatory in separate parameter sets (#27670) - #27856

Open
Vedaang Sharma (gtathelegend) wants to merge 1 commit into
PowerShell:masterfrom
gtathelegend:fix/export-csv-mandatory-path
Open

Mark Export-Csv -Path and -LiteralPath parameters as mandatory in separate parameter sets (#27670)#27856
Vedaang Sharma (gtathelegend) wants to merge 1 commit into
PowerShell:masterfrom
gtathelegend:fix/export-csv-mandatory-path

Conversation

@gtathelegend

Copy link
Copy Markdown

Description

This PR resolves issue #27670 where Export-Csv did not declare -Path and -LiteralPath as mandatory parameters or assign them to parameter sets in command metadata.

Previously, Export-Csv relied on imperative runtime validation in BeginProcessing() and CreateFileStream() to throw a custom CannotSpecifyPathAndLiteralPath exception when path parameters were missing or mutually specified. This prevented PowerShell's parameter binder from enforcing these requirements declaratively.

Motivation

Relying on manual imperative checks inside cmdlet processing bypasses PowerShell's engine parameter binding framework:

  1. Get-Command Export-Csv metadata did not report -Path or -LiteralPath as mandatory parameters.
  2. Parameter metadata did not describe the path parameters as belonging to mutually exclusive parameter sets.
  3. Interactive sessions could not use the native parameter binder behavior for missing mandatory parameters.
  4. Parameter binding errors occurred during cmdlet processing rather than during parameter binding.

Aligning Export-Csv with sibling utility cmdlets such as Export-Clixml and Out-File by marking -Path and -LiteralPath as Mandatory = true in mutually exclusive parameter sets (Path and LiteralPath) provides declarative binding, accurate command metadata, and consistent parameter-set behavior.

Investigation

Inspection of existing PowerShell utility cmdlets established clear precedents:

  • Export-Clixml (src/Microsoft.PowerShell.Commands.Utility/commands/utility/XmlCommands.cs) uses separate path parameter sets with mandatory -Path and -LiteralPath parameters.
  • Out-File (src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/out-file/Out-File.cs) similarly uses separate parameter sets with mandatory path parameters.
  • Export-Csv already declared DefaultParameterSetName = "Path" on its [Cmdlet] attribute, but its path parameters did not explicitly declare ParameterSetName and Mandatory = true.

By declaring Path and LiteralPath as mandatory parameters in separate parameter sets:

  • Omitting both parameters is handled by PowerShell's parameter binder as a missing mandatory parameter.
  • Supplying both parameters results in an AmbiguousParameterSet binding error.
  • The command metadata accurately describes the mandatory parameters and their parameter sets.

The change also required reviewing the existing delimiter/culture parameter-set handling. ImportExportCSVHelper.SetDelimiter() previously depended on parameter-set names associated with the older delimiter/culture matrix. The delimiter calculation was simplified so that it derives the effective delimiter from UseCulture, an explicitly supplied delimiter, or the default comma, independently of whether Path or LiteralPath is selected.

Implementation

In src/Microsoft.PowerShell.Commands.Utility/commands/utility/CsvCommands.cs:

  1. ExportCsvCommand.Path

    • Updated the parameter attribute to:
      [Parameter(Position = 0, Mandatory = true, ParameterSetName = "Path")]
    • Removed the obsolete _specifiedPath tracking field.
  2. ExportCsvCommand.LiteralPath

    • Updated the parameter attribute to:
      [Parameter(Mandatory = true, ParameterSetName = "LiteralPath")]
    • Preserved _isLiteralPath = true in the setter.
  3. Path validation

    • Removed the imperative !(_specifiedPath ^ _isLiteralPath) validation.
    • Removed the custom CannotSpecifyPathAndLiteralPath exception path.
    • Removed the redundant _path == null runtime validation from CreateFileStream().
  4. Delimiter and culture handling

    • Added explicit validation preventing -Delimiter and -UseCulture from being specified together.
    • Simplified ImportExportCSVHelper.SetDelimiter() to calculate the effective delimiter independently of the selected path parameter set.

In src/Microsoft.PowerShell.Commands.Utility/resources/CsvCommandStrings.resx:

  • Added the localized CannotSpecifyDelimiterAndUseCulture error message.

Tests

In test/powershell/Modules/Microsoft.PowerShell.Utility/Export-Csv.Tests.ps1:

  1. Updated the missing-path test to verify that execution fails through parameter binding rather than the previous custom error ID.
  2. Added a test verifying that specifying both -Path and -LiteralPath produces AmbiguousParameterSet.
  3. Added coverage for -LiteralPath with -Delimiter.
  4. Added coverage for -LiteralPath with -UseCulture.
  5. Added coverage for literal bracket paths such as [output].csv.
  6. Added parameter metadata verification through Get-Command Export-Csv.
  7. Added coverage for -LiteralPath by itself.
  8. Added coverage verifying that -Delimiter and -UseCulture cannot be specified together.

Verification

  • Build: powershell-win-core (net11.0\win7-x64) built successfully with 0 errors.
  • Pester: 4.10.1.
  • Focused test file: test/powershell/Modules/Microsoft.PowerShell.Utility/Export-Csv.Tests.ps1
  • Result: 40 Passed, 0 Failed, 0 Skipped, 0 Pending, 0 Inconclusive.
  • Manual verification:
    • Missing path fails during parameter binding.
    • -Path works when specified individually.
    • -LiteralPath works when specified individually.
    • Specifying both path parameters produces a parameter-set resolution error.
    • Get-Command Export-Csv reports both path parameters as mandatory in their respective parameter sets.

Compatibility / Behavior

  • Omitting both -Path and -LiteralPath now fails during parameter binding because the selected path parameter is mandatory.
  • Specifying both -Path and -LiteralPath now fails during parameter binding with AmbiguousParameterSet.
  • Existing tested -Path and -LiteralPath invocation patterns continue to work.
  • -LiteralPath continues to preserve literal path semantics.
  • Mutual exclusion between -Path and -LiteralPath is now represented directly through parameter sets.

Files Changed

  • src/Microsoft.PowerShell.Commands.Utility/commands/utility/CsvCommands.cs
  • src/Microsoft.PowerShell.Commands.Utility/resources/CsvCommandStrings.resx
  • test/powershell/Modules/Microsoft.PowerShell.Utility/Export-Csv.Tests.ps1

Issue

Fixes #27670

@gtathelegend
Vedaang Sharma (gtathelegend) requested a review from a team as a code owner August 14, 2026 19:51
Copilot AI lite review requested due to automatic review settings August 14, 2026 19:51
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
There may be pipelines that require an authorized user to comment /azp run to run.

@gtathelegend

Copy link
Copy Markdown
Author

@microsoft-github-policy-service agree

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request updates Export-Csv to make -Path and -LiteralPath declaratively mandatory in mutually exclusive parameter sets, so PowerShell’s parameter binder (and Get-Command metadata) enforces the required path semantics instead of relying on imperative runtime checks. It also simplifies delimiter selection logic and adds new validation/tests around delimiter/culture and literal path behavior.

Changes:

  • Mark Export-Csv -Path and -LiteralPath as Mandatory = true in separate parameter sets (Path vs LiteralPath) and remove the previous runtime “must specify exactly one” validation.
  • Add explicit validation preventing -Delimiter and -UseCulture from being specified together, and simplify delimiter resolution logic.
  • Expand Pester coverage for -LiteralPath scenarios, parameter set metadata, and new validation behavior.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

File Description
src/Microsoft.PowerShell.Commands.Utility/commands/utility/CsvCommands.cs Adds mandatory Path/LiteralPath parameter sets for Export-Csv, removes old path validation, and introduces delimiter/culture mutual-exclusion + simplified delimiter selection.
src/Microsoft.PowerShell.Commands.Utility/resources/CsvCommandStrings.resx Adds a localized error string for delimiter/culture mutual exclusion.
test/powershell/Modules/Microsoft.PowerShell.Utility/Export-Csv.Tests.ps1 Updates/extends tests for binder-enforced path requirements, parameter-set ambiguity, literal-path behavior, and delimiter/culture validation.

💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +125 to +130
if (this.MyInvocation.BoundParameters.ContainsKey(nameof(Delimiter)) && this.MyInvocation.BoundParameters.ContainsKey(nameof(UseCulture)))
{
InvalidOperationException exception = new(CsvCommandStrings.CannotSpecifyDelimiterAndUseCulture);
ErrorRecord errorRecord = new(exception, "CannotSpecifyDelimiterAndUseCulture", ErrorCategory.InvalidData, null);
this.ThrowTerminatingError(errorRecord);
}
Comment on lines 25 to +27
It "Should throw if an output file isn't specified" {
{ $testObject | Export-Csv -ErrorAction Stop } | Should -Throw -ErrorId "CannotSpecifyPathAndLiteralPath,Microsoft.PowerShell.Commands.ExportCsvCommand"
{ $testObject | Export-Csv -ErrorAction Stop } | Should -Throw
}
Comment on lines +31 to 33
[Parameter(Position = 1)]
[ValidateNotNull]
public char Delimiter { get; set; }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Export-Csv doesn't mark -Path and -LiteralPath as mandatory, although Export-Clixml does

2 participants