PSMDTAG:FAQ: Why do I sometimes get different types or different behaviors?
PSMDTAG:FAQ: When I pipe a heterogenous set of objects to an cmdlet that expects a homogenous stream – what happens and why?
In our newgroup ( Microsoft.public.Windows.PowerShell ), Alex A asked these questions with the following example:
$( gci ; gci hkcu:\ ) | Export-Csv -Path c:\temp\f1.csv
$( gci hkcu:\ ; gci ) | Export-Csv -Path c:\temp\f2.csv
Compare the output of the following 2 commands. In the first case I get all objects being type System.IO.DirectoryInfo; in the second, the only type header is Microsoft.Win32.RegistryKey.
In this example, the first element of the pipeline generates a heterogenous set of objects and then pipes them to Export-CSV. Export-CSV acts upon a homogeneous stream of objects. Here is literally what Export-CSV does:
Get the first object in the stream.
Use its type to look up user-defined serialization directives.
If found, use them, if not, use a default algorithm.
In either case, we now have a well defined set of properties to serialize
Open the CSV file and write what type of object we are going to serialize, then write the list of properties that will be serialized
Foreach object in the pipeline:
Write a new line in the file with values for each of the properties. If the value does not exist on that object, write a null
Now if you look at the contents of the files, what you will see in the first example is the headers described above, then a set of well-formed lines for the FileInfos in c:\temp and then a set of sparsely populated lines for the registry keys in hkcu:\ . In the second file, you’ll find the opposite, a well formed header, a set of well-formed lines for the registy stuff followed by a set of sparsely populated lines for the files in c:\temp.
In many cases – the type of the first object in the stream determines the processing for the entire stream.
Now it is important to understand thateach command gets to determine how they are going to handle this case. We’ve see what Export-CSV does but now see how out-default handles exactly the same situation. out-default is what gets called if you just run a command so just run the following commands:
$(gci . ;gci hkcu:\ )
$(Gci hkcu:\ ; gci .)
What you should see is that the first expression outputs a regular table for the filesystem objects and then outputs the registry entries as a LIST. The second command outputs the registy objects as a TABLE and outputs the filesystem objects as a LIST.
Jeffrey Snover [MSFT]
Windows PowerShell/Aspen Architect
Visit the Windows PowerShell Team blog at: http://blogs.msdn.com/PowerShell
Visit the Windows PowerShell ScriptCenter at: http://www.microsoft.com/technet/scriptcenter/hubs/msh.mspx