From 0364889518517522753a154a23a7b3fa7eab1f39 Mon Sep 17 00:00:00 2001 From: mk688ba Date: Fri, 3 Oct 2025 14:45:49 +0200 Subject: [PATCH 1/2] Fix issue #25836 --- .../commands/utility/CsvCommands.cs | 10 ++++++- .../ConvertTo-Csv.Tests.ps1 | 12 ++++++++ .../Export-Csv.Tests.ps1 | 28 +++++++++++++++++++ 3 files changed, 49 insertions(+), 1 deletion(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/CsvCommands.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/CsvCommands.cs index 414b472e640..ad34e7fb2b4 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/CsvCommands.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/CsvCommands.cs @@ -1044,7 +1044,15 @@ internal string ConvertPSObjectToCSV(PSObject mshObject, IList propertyN { if (dictionary.Contains(propertyName)) { - value = dictionary[propertyName].ToString(); + //Handle null reference exception for existing property with null value + if (dictionary[propertyName] == null) + { + value = null; + } + else + { + value = dictionary[propertyName].ToString(); + } } else if (mshObject.Properties[propertyName] is PSPropertyInfo property) { diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/ConvertTo-Csv.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/ConvertTo-Csv.Tests.ps1 index 0d484260813..ac71de2286c 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/ConvertTo-Csv.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/ConvertTo-Csv.Tests.ps1 @@ -212,6 +212,7 @@ Describe "ConvertTo-Csv" -Tags "CI" { [ordered]@{ Number = $_; Letter = $Letters[$_] } } $CsvString = $Items | ConvertTo-Csv + $TestHashTable = [ordered]@{ 'first' = 'value1'; 'second' = $null; 'third' = 'value3' } } It 'should treat dictionary entries as properties' { @@ -235,5 +236,16 @@ Describe "ConvertTo-Csv" -Tags "CI" { $NewCsvString[0] | Should -MatchExactly 'Extra' $NewCsvString | Select-Object -Skip 1 | Should -MatchExactly 'Surprise!' } + + It 'should convert hashtable with null values without error'{ + { $TestHashTable | ConvertTo-Csv } | Should -Not -Throw + } + + It 'should properly convert hashtable with null and non-null values'{ + $CsvResult = $TestHashTable | ConvertTo-Csv + + $CsvResult[0] | Should -BeExactly "`"first`",`"second`",`"third`"" + $CsvResult[1] | Should -BeExactly "`"value1`",$null,`"value3`"" + } } } diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/Export-Csv.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/Export-Csv.Tests.ps1 index 67234f24c58..db5c6aff9e3 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/Export-Csv.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/Export-Csv.Tests.ps1 @@ -11,6 +11,7 @@ Describe "Export-Csv" -Tags "CI" { $P1 = [pscustomobject]@{"P1" = "first"} $P2 = [pscustomobject]@{"P2" = "second"} $P11 = [pscustomobject]@{"P1" = "eleventh"} + $testHashTable = @{ 'first' = "value1"; 'second' = $null; 'third' = "value3" } } AfterEach { @@ -249,6 +250,33 @@ Describe "Export-Csv" -Tags "CI" { $contents[1].Contains($delimiter) | Should -BeTrue } + It "Should not throw when exporting hashtable with property that has null value"{ + { $testHashTable | Export-Csv -Path $testCsv } | Should -Not -Throw + } + + It "Should not throw when exporting PSCustomObject with property that has null value"{ + $testObject = [pscustomobject]$testHashTable + { $testObject | Export-Csv -Path $testCsv } | Should -Not -Throw + } + + It "Export hashtable with null and non-null values"{ + $testHashTable | Export-Csv -Path $testCsv + $result2 = Import-CSV -Path $testCsv + + $result2.first | Should -BeExactly "value1" + $result2.second | Should -BeNullOrEmpty + $result2.third | Should -BeExactly "value3" + } + + It "Export hashtable with non-null values"{ + $testTable = @{ 'first' = "value1"; 'second' = "value2" } + $testTable | Export-Csv -Path $testCsv + $results = Import-CSV -Path $testCsv + + $results.first | Should -BeExactly "value1" + $results.second | Should -BeExactly "value2" + } + Context "UseQuotes parameter" { # A minimum of tests. The rest are in ConvertTo-Csv.Tests.ps1 From 4f3a6f532351463bf5b566a918ee1d6f6143cd2d Mon Sep 17 00:00:00 2001 From: mk688ba Date: Fri, 3 Oct 2025 15:57:09 +0200 Subject: [PATCH 2/2] Simplify null check, remove unnecessary test --- .../commands/utility/CsvCommands.cs | 10 +--------- .../ConvertTo-Csv.Tests.ps1 | 4 ---- 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/CsvCommands.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/CsvCommands.cs index ad34e7fb2b4..0ff52372864 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/CsvCommands.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/CsvCommands.cs @@ -1044,15 +1044,7 @@ internal string ConvertPSObjectToCSV(PSObject mshObject, IList propertyN { if (dictionary.Contains(propertyName)) { - //Handle null reference exception for existing property with null value - if (dictionary[propertyName] == null) - { - value = null; - } - else - { - value = dictionary[propertyName].ToString(); - } + value = dictionary[propertyName]?.ToString(); } else if (mshObject.Properties[propertyName] is PSPropertyInfo property) { diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/ConvertTo-Csv.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/ConvertTo-Csv.Tests.ps1 index ac71de2286c..298b8140468 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/ConvertTo-Csv.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/ConvertTo-Csv.Tests.ps1 @@ -237,10 +237,6 @@ Describe "ConvertTo-Csv" -Tags "CI" { $NewCsvString | Select-Object -Skip 1 | Should -MatchExactly 'Surprise!' } - It 'should convert hashtable with null values without error'{ - { $TestHashTable | ConvertTo-Csv } | Should -Not -Throw - } - It 'should properly convert hashtable with null and non-null values'{ $CsvResult = $TestHashTable | ConvertTo-Csv