Trying to loop this code through multiple XML docs listed in a CSV, and not sure where to move my Format-Table without getting the An empty pipe element is not allowed
error.
$CSV = Import-Csv "C:\Users\Megan\Documents\EC_Export\AllDocs.csv"
foreach($LINE in $CSV)
{
$docPath = $LINE.filepath
# Note: The following should be preferred over Get-Content which
# doesn't respect XML encoding!
$xmlFile = [xml]::new(); $xmlFile.Load(( Convert-Path -LiteralPath $docPath ))
# Create an ordered hashtable as a precursor for a PSCustomObject
$ht = [ordered] @{}
# Process all ChildNodes
$xmlFile.files.file.ChildNodes |
# Filter by Name property (which is either element name or Name attribute) (Can only do 10 fields at a time this way)
Where-Object Name -match 'title|lcmSubject|lcmPrincipal|lcmClosingDate|lcmAclList' |
ForEach-Object {
# Get element text, trim whitespace, replace any line breaks by comma.
$value = $_.'#text' #.Trim() -replace '\r?\n', ','
# Add hashtable entry (associate name with value)
$ht[ $_.Name ] = $value
}
# Convert hashtable to a PSCustomObject so Format-Table prints it as expected.
[PSCustomObject] $ht} | Format-Table -Wrap
foreach
is a language statement and as such (unfortunately) cannot directly participate in a pipeline; that is, in your case you cannot directly append | FormatTable -Wrap
to it.
This limitation is rooted in the fundamentals of PowerShell grammar; see GitHub issue #10967 for background information.
The reason for the An empty pipe element is not allowed
error is that the foreach
language statement is invariably considered a complete PowerShell statement, causing | Format-Table -Wrap
to be considered the next statement - which breaks, given that you cannot start a statement with |
, the pipeline operator.
There are various workarounds:
To stream your language statement's output to the pipeline, enclose it in & { ... }
, i.e. enclose it in a script block ({ ... }
) that you invoke via &
, the call operator.
To collect your language statement's output up front before sending it to the pipeline (still object by object, enclose it in $(...)
, the subexpression operator
In your simple case, switch from a foreach
statement to the analogous ForEach-Object
cmdlet.
Note that, unlike the foreach
statement, the ForEach-Object
cmdlet has no explicit iterator variable, and requires you to refer to the pipeline input object at hand via the automatic $_
variable
As an aside: Somewhat confusingly, foreach
(in addition to %
) also exists as an alias of ForEach-Object
. It is the syntactic context that determines whether foreach
refers to the cmdlet or to the language statement.
Here's a simplified version of a ForEach-Object
solution:
$CSV | ForEach-Object {
# Note the need to use of $_ to refer to the input object at hand
$docPath = $_.filepath
# ...
} | Format-Table -Wrap