Getting confused with simple piping semantics

I think I am confusing myself with some piping semantics.

I am playing around with Get-ADComputer and want to pass it a few computers to check through the pipeline.

So this is how it looks.

'Server01' | get-adcomputer | export-clixml 'c:\reports\xml\$_.xml'

Basically I want that computer name to appear as the file name.

I thought I could pass the name through but it looks like it didn’t go through…Its been coming as blank. Any ideas? TIA

Probably it needs an object from the pipline, your putting in a string.
Cant test in, dont have ad, but this exmple should be simular:

PS C:\Users> Get-Process ‘firefox’

Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id SI ProcessName


660      48   217676     211960   528    35,66   3336   1 firefox          

PS C:\Users>‘firefox’|Get-Process
Get-Process : The input object cannot be bound to any parameters for the comman
d either because the command does not take pipeline input or the input and its
properties do not match any of the parameters that take pipeline input.
At line:1 char:12

  • ‘firefox’|Get-Process
  •        ~~~~~~~~~~~
    
    • CategoryInfo : InvalidArgument: (firefox:String) [Get-Process],
      ParameterBindingException
    • FullyQualifiedErrorId : InputObjectNotBound,Microsoft.PowerShell.Command
      s.GetProcessCommand

PS C:\Users> $fire= Get-Process ‘firefox’

PS C:\Users> $fire|Get-Process

Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id SI ProcessName


628      34   220488     215880   530    39,73   3336   1 firefox          

PS C:\Users>

Chris is correct. Try something like this:

'server1','server2' | ForEach-Object {
    $server= Get-ADComputer $PSItem
    $file = "C:\temp\$($server.name).xml"
    Export-Clixml -InputObject $server -Path $file 
}

This should work. Using Get-Help will show you if a parameter accepts pipeline input.

$servers = 'Server01'
foreach ($server in $servers){get-adcomputer | export-clixml "c:\reports\xml\$server.xml"}

Hey @wei-yen-tan,
I think I’m reading your question a little different than the rest of the folks that have replied so far. As I read it the question is not so much about the command being used, but rather how the pipeline works and why $_ does not represent the name of the server you passed in at the beginning of the pipeline in the below oneliner:

'Server01' | get-adcomputer | export-clixml 'c:\reports\xml\$_.xml'

You are expecting this to result in the export-clixml command being

export-clixml 'c:\reports\xml\Server01.xml'

There are two reasons for why $_ does not resolve to Server01 in the above command.

  1. The use of single quotes.
    When single quotes are used, variables, such as $_, are not resolved to their content; rather, they are taken as literal characters. As a result your command ends up being literally
export-clixml 'c:\reports\xml\$_.xml'

If you want $_ to resolve to the variable value, used double quotes instead. In the following command, $_ will be replace with the value of the variable before the command is executed:

export-clixml "c:\reports\xml\$_.xml"
  1. The second issue is what is expected to be in the $_ variable at the point in the pipeline that it is being used. Let me lay it out like this. The pipe symbol “|” in the commandline represents the pipeline. The command before the | is putting data into the pipeline. The command after the | is taking data from the pipeline. Let me lay out how this workes using the provided sample oneliner.
'Server01' | get-adcomputer | export-clixml 'c:\reports\xml\$_.xml'
  1. The first command: ‘Server01’ outputs a literal string Server01
  2. This string Server01 is sent to the Pipeline to hold until it is passed to the next commandlet
  3. The first object in the pipeline, in this case Server01, is sent to the next command in the onliner
  4. The second command: get-adcomputer uses Server01 as input and outputs an object represending the computer object in AD
  5. This computer object is sent to the Pipeline to hold until it is passed to the next commandlet. Note: The pipeline at this point is not holding a string with a value of Server01. It is holding an object with all the data it pulled from Active Directory. By default, this includes data such as DistinguishedName, DNSHostName, Name, ObjectClass, etc, etc.
  6. The first object in the pipeline, in this case the Object containing all of the data for Server01 from AD is sent to the next command in the oneliner
  7. The third command: export-clixml 'c:\reports\xml$.xml’ uses the Object from the pipeline as input as well as tries to use the $, which represents the current object from the pipeline when used with a loop, as the name of the file to export to. Since no commandlet that loops is being used, such as foreach-object, the $_ variable is blank.
#From about_Automatic_Variables
$_
       Same as $PSItem. Contains the current object in the pipeline object.
       You can use this variable in commands that perform an action on every
       object or on selected objects in a pipeline.

When foreach-object is added to the oneliner, like below, $_ represents the current object from the pipeline as each object from the pipeline is processed

'Server01' | get-adcomputer | ForEach-Object {export-clixml -InputObject $_ -Path "c:\reports\xml\$_.xml"}

Another problem is what $_ represents

An example of the object representation is below:

@'
DistinguishedName : CN=SERVER1,CN=Computers,DC=ca,DC=lab
DNSHostName       : Server1.ca.lab
Enabled           : True
Name              : SERVER1
ObjectClass       : computer
ObjectGUID        : fa78f3b3-0458-4a39-ab41-5e1f13ac40c9
SamAccountName    : SERVER1$
SID               : S-1-5-21-607888948-3061123872-308631077-1143
UserPrincipalName : 
'@

Obviously you cannot have a filename that looks like the above + .xml

Fortunately when a computer object producted by Get-AdComputer is resolved as a string, it outputs the DistringuishedName Property as a string.

So the result of:

‘Server01’ | get-adcomputer | ForEach-Object {export-clixml -InputObject $_ -Path “c:\reports\xml$_.xml”}

will be a file called something like:

CN=SERVER01,CN=Computers,DC=ca,DC=lab.xml

Which is not your desired result.

What you want is a specific piece of data from that object. For this you need to use a subexpression to get the desired property from the current object that is represented by $_

export-clixml "c:\reports\xml\$($_.Name).xml"

What the above does is tell PowerShell to interpret variables due to the use of double-quotes. Additionally, the $() tells PowerShell that there is an expression between the parenthesis that needs to be processed before plugging it’s value into the string. In this case it is to read the value of the Name property from the Current Object received from the pipeline.

$_.name equals SERVER01 as shown above, so the command resolves out to the following before executing

export-clixml “c:\reports\xml\SERVER1.xml”

'Server01' | get-adcomputer | ForEach-Object {export-clixml -InputObject $_ -Path "c:\reports\xml\$($_.Name).xml"}

This, of course, will work with multiple server names passed in at the beginning

'Server01', 'Server02' | get-adcomputer | ForEach-Object {export-clixml -InputObject $_ -Path "c:\reports\xml\$($_.Name).xml"}

Thanks for that @Curtis Smith for the explanation. This exactly what I was looking for. I was actually looking at a problem that I was having with one of my own custom objects(collections) and after you have explained how piping works I know where the fault lies.

Thanks for the time you spent with my on parsing sql. I sat down and worked out how it worked and got the relevant information. It is working beautifully,