Public/Invoke-DataTableColumnReorder.ps1
function Invoke-DataTableColumnReorder { <# .SYNOPSIS Takes a DataTable, and reorders and removes columns based on an array of column names you pass in .DESCRIPTION I wrote this function while building a process to load many CSV and TXT files that were produced by a third party vendor into our staging database. Not all files would be loaded regularly, but we needed to get them loaded quickly to identify which files were needed and which were not. There are times that the files are not consistant between runs, which was where this specific function came into play. .INPUTS DataTable - A System.Data.DataTable that we will be acting on. Can be passed in by pipeline .OUTPUTS System.Data.DataTable .PARAMETER DataTable .PARAMETER columnOrder An string array of column names in the order that you would like the DataTable columns to be in. .EXAMPLE Takes a csv file with headers located at $inputFilePath and injects 2 columns to the front of the DataTable to stamp the row with a DateTime of when it was loaded, and what parent folder the file was in. This is done prior to loading the DataTable into SQL Server $ColumnNames_FileOrder = (Get-Content $inputFilePath | select-Object -first 1).Split(",") $data = Import-Csv $inputFilePath $data | Add-Member -MemberType NoteProperty -Name rowLoadedDTTM -Value $(Get-Date -Format "yyyy-MM-dd HH:mm:ss") $data | Add-Member -MemberType NoteProperty -Name fileParentFolder -Value $parentFolderName $dataAsDataTable = $data | Out-DataTable #$columnIndex = 0 $ColumnNames_DesiredOrder = @() $ColumnNames_DesiredOrder += "rowLoadedDTTM" $ColumnNames_DesiredOrder += "fileParentFolder" $ColumnNames_DesiredOrder += $ColumnNames_FileOrder $dataAsDataTable = Invoke-DataTableColumnReorder -DataTable $dataAsDataTable -columnOrder $ColumnNames_DesiredOrder .EXAMPLE Building upon the previous example, this one takes the previous data table with data from a CSV file and values determined at run time and loads it into a table in SQL server. It is possible that table in SQL Server does not have columns that exist in our data table. This example uses Invoke-DataTableColumnReorder to ensure that the local DataTable and the SQL table have consistent column mappings by reordering columns that exist in both, and removing columns that do not exist on the SQL server. $destServerName and $destDatabase are set at script run time. $schemaName and $tableName are set dynamically based on the files that will be loaded. Write-Log "Checking if the column order of my datatable matches the ordering on the SQL server" Debug $ColumnNames_SqlServer = (Invoke-Sqlcmd -ServerInstance $destServerName -Database $destDatabase -Query "select Column_name from INFORMATION_SCHEMA.COLUMNS col where col.TABLE_CATALOG = '$destDatabase' and col.TABLE_SCHEMA = '$schemaName' and col.TABLE_NAME = '$tableName' order by ORDINAL_POSITION").Column_name $columnIndex = 0 $columnsToRemoveIndex =0 foreach ($column in $ColumnNames_DesiredOrder){ if ($column -ne $ColumnNames_SqlServer[$columnIndex - $columnsToRemoveIndex]){ $ColumnNames_DesiredOrder = $ColumnNames_DesiredOrder | where {$_ -ne $column} $columnsToRemoveIndex += 1 } $columnIndex += 1 } $dataAsDataTable = Invoke-DataTableColumnReorder -DataTable $dataAsDataTable -columnOrder $ColumnNames_DesiredOrder Write-Log "Loading data into $FQTableName" -tabLevel 1 Write-DataTable -serverInstance $destServerName -Database $destDatabase -TableName $FQTableName -data $dataAsDataTable -ErrorAction Stop #> [OutputType([Data.datatable])] param([Parameter(Position = 0,Mandatory = $true,ValueFromPipeline = $true)] [Data.datatable]$DataTable,[string[]]$columnOrder) if(($columnOrder | Measure-Object | select -ExpandProperty COunt) -eq 0){ Write-Log "You need to pass a value to columnOrder" Error -ErrorAction stop return } $columnIndex = 0 foreach ($column in $columnOrder) { if ($DataTable.Columns.Contains($column)) { $DataTable.Columns[$column].SetOrdinal($columnIndex) $columnIndex++ } else { Write-Log "Column named: $column does not exist" Warning } } Write-Log "Removing other columns from the data table" Debug $removeColumnIndex = $DataTable.Columns.count for ($removeColumnIndex = $DataTable.Columns.count - 1; $removeColumnIndex -ge $columnIndex; $removeColumnIndex --) { Write-Log "Removing column: $($DataTable.Columns[$removeColumnIndex])" Warning $DataTable.Columns.RemoveAt($removeColumnIndex) } Write-Output @(,($DataTable)) } Export-ModuleMember -Function Invoke-DataTableColumnReorder |