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
foreachis a language statement and as such (unfortunately) cannot directly participate in a pipeline; that is, in your case you cannot directly append| FormatTable -Wrapto 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 allowederror is that theforeachlanguage statement is invariably considered a complete PowerShell statement, causing| Format-Table -Wrapto 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 operatorIn your simple case, switch from a
foreachstatement to the analogousForEach-Objectcmdlet.Note that, unlike the
foreachstatement, theForEach-Objectcmdlet has no explicit iterator variable, and requires you to refer to the pipeline input object at hand via the automatic$_variableAs an aside: Somewhat confusingly,
foreach(in addition to%) also exists as an alias ofForEach-Object. It is the syntactic context that determines whetherforeachrefers to the cmdlet or to the language statement.Here's a simplified version of a
ForEach-Objectsolution: