Automate Data-Intensive Tasks
1. Problem
You want to invoke a simple task on large amounts of data.
2. Solution
If only one piece of data changes (such as a server name or user name), store the data in a text file. Use the Get-Content cmdlet to retrieve the items, and then use the Foreach-Object cmdlet (which has the standard aliases foreach and %) to work with each item in that list. Example 2-5 illustrates this technique.
Example 2-5. Using information from a text file to automate data-intensive tasks
|
Code View: Scroll / Show All PS >Get-Content servers.txt SERVER1 SERVER2 PS >$computers = Get-Content servers.txt PS >$computers | Foreach-Object { Get-WmiObject Win32_OperatingSystem -Computer $_ }
SystemDirectory : C:\WINDOWS\system32 Organization   :
BuildNumber    : 2600
Version        : 5.1.2600
SystemDirectory : C:\WINDOWS\system32 Organization   :
BuildNumber    : 2600
Version        : 5.1.2600
                                     Â
|
If it becomes cumbersome (or unclear) to include the actions in the Foreach-Object cmdlet, you can also use the foreach scripting keyword as illustrated by Example 2-6.
Example 2-6. Using the foreach scripting keyword to make a looping statement easier to read
$computers = Get-Content servers.txt foreach($computer in $computers) {
   ## Get the information about the operating system from WMI
   $system = Get-WmiObject Win32_OperatingSystem -Computer $computer
   ## Determine if it is running Windows XP
   if($system.Version -eq "5.1.2600")
   {
       "$computer is running Windows XP"
   }
}
|
If several aspects of the data change per task (for example, both the WMI class and the computer name for computers in a large report), create a CSV file with a row for each task. Use the Import-Csv cmdlet to import that data into PowerShell, and then use properties of the resulting objects as multiple sources of related data. Example 2-7 illustrates this technique.
Example 2-7. Using information from a CSV to automate data-intensive tasks
|
Code View: Scroll / Show All PS >Get-Content WmiReport.csv
ComputerName,Class
LEE-DESK,Win32_OperatingSystem
LEE-DESK,Win32_Bios
PS >$data = Import-Csv WmiReport.csv
PS >$data
Â
ComputerName                         Class
------------Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â -----
LEE-DESKÂ Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Win32_OperatingSystem
LEE-DESKÂ Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Win32_Bios
Â
Â
PS >$data |
>>Â Â Â Â Foreach-Object { Get-WmiObject $_.Class -Computer $_.ComputerName }
>>Â
Â
Â
SystemDirectory : C:\WINDOWS\system32
Organization   :
BuildNumber    : 2600
Version        : 5.1.2600
Â
SMBIOSBIOSVersion : ASUS A7N8X Deluxe ACPI BIOS Rev 1009
Manufacturer     : Phoenix Technologies, LTD
Name             : Phoenix - AwardBIOS v6.00PG
SerialNumber     : xxxxxxxxxxx
Version          : Nvidia - 42302e31
Â
Â
                                     Â
|
3. Discussion
One of the major benefits of PowerShell is its capability to automate repetitive tasks. Sometimes, these repetitive tasks are action-intensive (such as system maintenance through registry and file cleanup) and consist of complex sequences of commands that will always be invoked together. In those situations, you can write a script to combine these operations to save time and reduce errors.
Other times, you need only to accomplish a single task (for example, retrieving the results of a WMI query) but need to invoke that task repeatedly for a large amount of data. In those situations, PowerShell’s scripting statements, pipeline support, and data management cmdlets help automate those tasks.
One of the options given by the solution is the Import-Csv cmdlet. The Import-Csv cmdlet reads a CSV file and, for each row, automatically creates an object with properties that correspond to the names of the columns. Example 2-8 shows the results of a CSV that contains a ComputerName and Class header.
Example 2-8. The Import-Csv cmdlet creating objects with Computer Name and Class properties
PS >$data = Import-Csv WmiReport.csv PS >$data ComputerName                        Class ------------                        -----
LEE-DESKÂ Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Win32_OperatingSystem
LEE-DESKÂ Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Win32_Bios
PS > PS >$data[0].ComputerName LEE-DESK
|
As the solution illustrates, you can use the Foreach-Object cmdlet to provide data from these objects to repetitive cmdlet calls. It does this byspecifying each parameter name, followed by the data (taken from a property of the current CSV object) that applies to it.
While this is the most general solution, many cmdlet parameters can automatically retrieve their value from incoming objects if anyproperty of that object has the same name. This can let you to omit the Foreach-Object and property mapping steps altogether. Parameters that support this feature are said to support Value from pipeline by property name. The Move-Item cmdlet is one example of a cmdlet with parameters that support this, as shown by the Accept pipeline input rows in Example 2-9.
Example 2-9. Help content of the Move-Item showing a parameter that accepts value from pipeline by property name
|
Code View: Scroll / Show All PS >Get-Help Move-Item -Full (...) PARAMETERS Â Â Â -path <string[]>
       Specifies the path to the current location of the items. The default
       is the current directory. Wildcards are permitted.
       Required?                   true        Position?                   1        Default value               <current location>        Accept pipeline input?      true (ByValue, ByPropertyName)        Accept wildcard characters? true    -destination <string>
       Specifies the path to the location where the items are being moved.
       The default is the current directory. Wildcards are permitted, but
       the result must specify a single location.
       To rename the item being moved, specify a new name in the value of
       Destination.
       Required?                   false        Position?                   2        Default value               <current location>        Accept pipeline input?      true (ByPropertyName)        Accept wildcard characters? True        (...)
                                     Â
|
If you purposefully name the columns in the CSV to correspond to parameters that take their value from pipeline by propertyname, PowerShell can do some (or all) of the parameter mapping for you. Example 2-10 demonstrates a CSV file that moves items in bulk.
Example 2-10. Using the Import-Csv cmdlet to automate a cmdlet that accepts value from pipeline by property name
PS >Get-Content ItemMoves.csv Path,Destination test.txt,Test1Directory test2.txt,Test2Directory PS >dir test.txt,test2.txt | Select Name Name ---- test.txt test2.txt PS >Import-Csv ItemMoves.csv | Move-Item PS >dir Test1Directory | Select Name Name ---- test.txt PS >dir Test2Directory | Select Name Name ---- test2.txt
|
For more information about the Foreach-Object cmdlet and foreach scripting keyword, see Section 2.4, “Work with Each Item in a List or Command Output.” For more information about working with CSV files, see Section 8.6, “Import Structured Data from a CSV File.” For more information about working with Windows Management Instrumentation (WMI), see Section 15.1, “Access Windows Management Instrumentation Data.”
Tags: auto, automate, manager, powershell, task
