5.3. Work with Structured File FormatsText files are great for storing simple, human-readable information, but they're not ideally suited to representing the structured data that we're becoming accustomed to in MSH. More often than not, we're dealing with objects and properties rather than strings and characters. MSH supports an additional data format with ease: comma-separated variables (CSV). With two additional cmdlets for working with comma-separated data, easy-to-use spreadsheet applications can be combined with the power of the shell. Whether used for input (managing a task list in a friendly interface) or output (such as drawing graphs and performing statistical analysis), the CSV format can be very useful. 5.3.1. How Do I Do That?Like set-content, the export-csv cmdlet takes a filename into which it writes a sequence of linesone per objectwith each field separated by a comma: MSH D:\MshScripts> get-process | export-csv -NoTypeInformation processes.csv The resulting file can now be used in an application such as Microsoft Excel or in other tools that can process CSV files. Figure 5-1 shows a graphical representation of handle count by process. The -NoTypeInformation option is used to suppress the first line of the output (which would otherwise contain MSH-specific formatting information). Figure 5-1. Graph generated from get-process dataexport-csv also has a mirror cmdlet, import-csv, that takes a CSV file from disk, parses the fields, and generates objects corresponding to each row in the file. Imagine using a spreadsheet to manage a list of batch copy taskssources and destinationsused as part of a nightly backup job. A file like the one shown in Example 5-2 could be generated by a program such as Excel. Example 5-2. BackupTasks.csvName,Source,Destination "Copy logs from PRIMARYWEB",\\primaryweb\logs,\\bigdisk\logs\primaryweb "Copy logs from SECONDWEB",\\secondweb\logs,\\bigdisk\logs\secondweb "Backup user dirs on FS",\\fs\users,\\bigdisk\userdirs "Backup INTRA wwwroot",\\intra\wwwroot,\\bigdisk\intra Using import-csv and foreach, it's possible to work through the list of tasks systematically, performing each in turn: MSH D:\MshScripts> $tasks = import-csv BackupTasks.csv MSH D:\MshScripts> foreach ($task in $tasks) { >>echo $task.Name >>robocopy /s $task.Source $task.Destination >>} >> Copy logs from PRIMARYWEB ---------------------------------------------------------------------------- ROBOCOPY :: Robust File Copy for Windows :: Version XP010 ---------------------------------------------------------------------------- Started : Tue May 31 18:48:10 2005 Source : \\primaryweb\logs Dest : \\bigdisk\logs\primaryweb Files : *.* Options : *.* /COPY:DAT /R:1000000 /W:30 /S ---------------------------------------------------------------------------- ... 5.3.2. What About...... Support for other data formats? MSH can parse XML files to form a structured object that can be used in the pipeline. For nested data, XML is often more convenient than comma-separated formats. Let's take the backup job example a step further, this time creating file lists for each job. The listing in Example 5-3 is an XML representation of two new backup jobs, each defining its own source, destination, and file list. Example 5-3. BackupTasks.xml<Jobs> <Job Name="Backup a and b"> <Source>\\server1\files</Source> <Destination>\\server2\backup</Destination> <File>a.txt</File> <File>b.txt</File> </Job> <Job Name="Backup c, d and e"> <Source>\\server1\files</Source> <Destination>\\server3\backup</Destination> <File>c.txt</File> <File>d.txt</File> <File>e.txt</File> </Job> </Jobs> We load the XML file with get-content, casting it to an xml type. (We'll see more about casting in the next section.) The resulting $xml variable contains the data, organized in the same fashion as the source file: MSH D:\MshScripts> $xml = [Xml]$(get-content BackupTasks.xml) MSH D:\MshScripts> $xml Jobs ---- Jobs It's now possible to use standard MSH language to work through the jobs in order, iterating through the collections that are defined in the XML file: MSH D:\MshScripts> foreach ($job in $xml.Jobs.Job) { >>$job.Name >>foreach ($file in $job.File) { >> $source = combine-path $job.Source $file >> $dest = combine-path $job.Destination $file >> copy-item $source $dest >>} >>} >> Backup a and b Backup c, d and e Each deeper level of the XML file can be accessed from within the shell using dot notation. $xml.Jobs.Job gives the collection of <Job> elements for that job, $job.File gives the collection of <File> elements for that job, and so on. 5.3.3. Where Can I Learn More?import-csv and export-csv both have additional usage information available through get-help. We'll see more of the .NET Framework Class Library (which provides the support for XML documents) in the next section and in the upcoming section, "Calling Methods of the .NET Class Library." |