I have a report that I have automated. the report is a CSV file, and it is split every 80,000 lines, so I regularly end up with reports in multiple parts. I have a large function that processes the report perfectly fine when I have a single file, but I am having issues with ingesting multiple files at the same time. The report filenames are formatted as such:
Part_1.csv
Part_2.csv
Part_3.csv
What I'm doing is getting the last downloaded file, and checking to see how many parts it had, like this:
$FileName = Get-ChildItem $env:USERPROFILE\Downloads | where Extension -like .csv | Sort-Object -Property LastWriteTime -Descending | Select-Object -First 1
$FileCount = [int]$FileName.basename.substring($FileName.Basename.Length-1)
If the I get isn't Part_1.csv
I know I need to load multiple files, and I'm doing that with this:
if ($FileCount -ne "1")
{
$List = Get-ChildItem $env:USERPROFILE\Downloads | where Extension -like .csv | Sort-Object -Property LastWriteTime -Descending | Select-Object -First $FileCount | Sort-object
After this step, $List
contains the following:
PS C:\> $List
Directory: C:\Users\username\Downloads
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 2/18/2025 3:25 PM 16930338 Report_Part_1.csv
-a---- 2/18/2025 3:25 PM 16930338 Report_Part_2.csv
-a---- 2/18/2025 3:26 PM 1448835 Report_Part_3.csv
PS C:\>
I then load each different part of the report with a foreach loop:
Foreach($File in $List.FullName)
{
$Object += Import-Csv -Path $File
}
Here's this entire part of the script in one block for you.
$Object = @()
$FileName = Get-ChildItem $env:USERPROFILE\Downloads | where Extension -like .csv | Sort-Object -Property LastWriteTime -Descending | Select-Object -First 1
$FileCount = [int]$FileName.basename.substring($FileName.Basename.Length-1)
if ($FileCount -ne "1")
{
$List = Get-ChildItem $env:USERPROFILE\Downloads | where Extension -like .csv | Sort-Object -Property LastWriteTime -Descending | Select-Object -First $FileCount | Sort-object
Foreach($File in $List.FullName)
{
$Object += Import-Csv -Path $File
}
}
Else
{
$Object = Import-Csv -Path $FileName.FullName
}
Here's the kicker, if I run this isolated, all by itself, it works exactly how I expected it to. $Object
contains all of the data from each part. but as soon as I put this at the top of my function that actually processes the report:
Function Read-Report
{
$Object = @()
$FileName = Get-ChildItem $env:USERPROFILE\Downloads | where Extension -like .csv | Sort-Object -Property LastWriteTime -Descending | Select-Object -First 1
$FileCount = [int]$FileName.basename.substring($FileName.Basename.Length-1)
if ($FileCount -ne "1")
{
$List = Get-ChildItem $env:USERPROFILE\Downloads | where Extension -like .csv | Sort-Object -Property LastWriteTime -Descending | Select-Object -First $FileCount | Sort-object #([int]::Parse($filename.basename.substring($Filename.Basename.Length-1))) | Sort-Object
Foreach($File in $List.FullName)
{
$Object += Import-Csv -Path $File
}
}
Else
{
$Object = Import-Csv -Path $FileName.FullName
}
#Working report processing script continues below
I get an error on the line that contains Foreach($File in $List.FullName)
stating:
Cannot convert the "C:\Users\username\Downloads\Report_Part_1.csv" value of type "System.String" to type "System.Management.Automation.SwitchParameter".
At C:\Users\username\Documents\Scripting\Powershell\ReportsFunctions.ps1:43 char:17
+ Foreach($File in $List.FullName)
+ ~~~~~
+ CategoryInfo : InvalidArgument: (:) [], RuntimeException
+ FullyQualifiedErrorId : ConvertToFinalInvalidCastException
I would think that its just choking on the file path, except that it works when its not inside my function.
Also, changing the foreach loop to the following has the exact same error
Foreach($File in $List)
{
$Object += Import-Csv -Path $File.FullName
}
I can reproduce your error with the following:
function Read-Report
{
param( [switch] $File )
foreach( $File in @( "aaa" ) )
{
write-host $File
}
}
Read-Report
What's happening is the function declares a type constrained variable with [switch] $File
so that PowerShell requires $File
to always contain a value of type [switch]
, but you're then using the same variable in a foreach
which tries to iterate over an array of [string]
s.
Powershell's implicit type conversion tries to turn the [string] "aaa"
into a [switch]
but there's no implicit conversion that can do this so you get the error:
Cannot convert the "aaa" value of type "System.String" to type "System.Management.Automation.SwitchParameter".
(Note that [switch]
is a Type Accelerator for [System.Management.Automation.SwitchParameter]
)
Your code doesn't show where you're declaring $File
so I can't suggest a direct fix, but a workaround would be to use a different variable in the foreach
iterator so it doesn't have the same [switch]
type constraint and then PowerShell won't try to convert the [string] "aaa"
value into another type:
function Read-Report
{
param( [switch] $File )
foreach( $MyFile in @( "aaa" ) )
{
write-host $MyFile
}
}
Read-Report