Take the 2-minute tour ×
Server Fault is a question and answer site for professional system and network administrators. It's 100% free, no registration required.

I'm trying to create a script to run as a scheduled task, which will run against multiple servers and retrieve some information.

To start with, I populate the list of servers by querying AD for all servers that match a certain set of criteria, using Get-ADComputer.

The problem is, the list is returned as an object, which I can't then pass to the New-PSSession list. I have tried converting it to a comma-seperated string by doing the following:

foreach ($server in $serverlist) {$newlist += $server.Name + ","}

but this still doesn't work.

the alternative is to iterate through the list and run the various commands against each server one at a time, but my preference would be to avoid this and run them using one-to-many remoting.

UPDATE: To clarify what I want to end up being able to do is using -ComputerName $serverlist, so I want $serverlist to be a string rather than an object.

UPDATE 2: Thanks for all the suggestions. Between them and my original method I'm starting to wonder whether -ComputerName can accept a string variable? I've got varying degrees of success getting the list of computers converted to a comma separated string, but no matter how I do it I always get invalid network address.

share|improve this question
add comment

3 Answers

up vote 3 down vote accepted

To explain it a little more, if you have executed Get-ADComputer then you will get possibly an array of objects or a single object back.

I assume you are calling something like the following:

$serverList = Get-ADComputer -LDAPFilter '(cn=*DC*)';

This would get all the computers with DC in their name.

Because you potentially have an array (more then one) or objects that you have process using the ForEach-Object cmdlet (also aliased as % or foreach) is a good approach. Which is basically execute a script block for each record in the pipeline. However as you have experienced you are getting an object back from the query not a string. So you just have to choose a property to use.

For example if you use:

$serverList[0] | Get-Member

You will get all the properties of a computer object. gm is also an alias for Get-Member. E.g.

PS> $serverList[0] | gm

TypeName: Microsoft.ActiveDirectory.Management.ADComputer

Name              MemberType            Definition
----              ----------            ----------
Contains          Method                bool Contains(string propertyName)
Equals            Method                bool Equals(System.Object obj)
GetEnumerator     Method                System.Collections.IDictionaryEnumerator GetEnumerator()
GetHashCode       Method                int GetHashCode()
GetType           Method                type GetType()
ToString          Method                string ToString()
Item              ParameterizedProperty Microsoft.ActiveDirectory.Management.ADPropertyValueCollection Item(string p...
DistinguishedName Property              System.String DistinguishedName {get;set;}
DNSHostName       Property              System.String DNSHostName {get;set;}
Enabled           Property              System.Boolean Enabled {get;set;}
Name              Property              System.String Name {get;}
ObjectClass       Property              System.String ObjectClass {get;set;}
ObjectGUID        Property              System.Nullable`1[[System.Guid, mscorlib, Version=2.0.0.0, Culture=neutral, ...
SamAccountName    Property              System.String SamAccountName {get;set;}
SID               Property              System.Security.Principal.SecurityIdentifier SID {get;set;}
UserPrincipalName Property              System.String UserPrincipalName {get;set;}

Quickly looking you can see that there is a DNSHostName property.

So to execute your command you could use something like:

$serverList = Get-ADComputer -LDAPFilter '(cn=*DC*)';
$serverList | ForEach-Object { New-PSSession -ComputerName $_.DNSHostName; }

However I will note that the New-PSSession cmdlet doesn't do much except create a remoting session to a computer (PowerShell Remoting has to be enabled to support this). You would need to use the Invoke-Command cmdlet to execute something from a script.

Example 1:

$serverList = Get-ADComputer -LDAPFilter '(cn=*DC*)';
$serverList | ForEach-Object { New-PSSession -ComputerName $_.DNSHostName; } | ForEach-Object { Invoke-Command -Session $_ -ScriptBlock { #Execute commands here }; };

Example 2:

Get-ADComputer -LDAPFilter '(cn=*DC*)' | % { Invoke-Command -ComputerName $_.DNSHostName -ScriptBlock { #Execute commands here }; };

The second example optimises out the New-PSSession because it is not really needed if you are only going to call the Invoke-Command without advanced options.

Also note there is no real need to store the result of Get-ADComputer in a variable, you would only do that if Get-ADComputer was took a long time to execute and you had to use it more then once.

The $_ is a pipeline variable that become whatever object in currently in the pipeline.

Updated

Specifically to use Invoke-Command to execute an identical command against multiple computers you can use the -ComputerName parameter to supply an array of strings. (This can be seen by looking at the help, i.e.-ComputerName <String[]>. This would not be the case for all commands).

As mentioned the output from Get-ADComputer is an object. So a string array compatible with the -ComputerName parameter would be constructed by.

$serverList = @();
Get-ADComputer -LDAPFilter '(cn=*DC*)' | % { $serverList += $_.DNSHostName; }

Basically this creates a new array and adds each computers DNS host name to it, but you end up with string[]. You would then be able to use:

Invoke-Command -ComputerName $serverList -ScriptBlock { #Execute commands here };

However also note that while is may appear you are only executing a single command under the hood it is almost always a number of PowerShell cmdlet. For example command pipeline have a silent | Out-Host appended to them.

You could also wrap any of the commands in a function to execute a single command.

Hope that answers you question.

share|improve this answer
    
This provides me a way to do what I need, but doesn't answer my initial question of using one-to-many ps remoting. I'm guessing that it's not possible. –  Matt Oct 2 '12 at 23:35
    
@Matt updated answer to directly answer the one-to-many specifics. –  Bernie White Oct 3 '12 at 8:10
add comment

Every result on powershell is a .Net object.

When you have a result in powershell like yours (an object) and you need a string for a search or to use on another command you can pipe the result (the object) to the cmdlet Out-String. Alternatively you can use Out-File.

If you want to change something in the Output you can combine it with another cmdlets like the Format-* ones, Format-Table, Format-List, etc.

So, when you get an object and you need a string use something like this:

Command-Let | Out-String

or

Command-Let | Format-Custom (parameters) | Out-String
share|improve this answer
    
Thanks, I tried this but it still doesn't work. –  Matt Oct 12 '11 at 20:52
1  
@Matt Tell us what exactly doesn't work. Thank you. –  Ricardo Polo Oct 13 '11 at 0:17
add comment

I don't have access to AD cmdlets so can only offer something I have done before when needing the object as a string.

I wrote a tip on MSSQLTips.com for backing up databases using SQLPS. So I basically queried SQLPS for the names of the database and then passed that to the BACKUP command, which had to see the name as a string and not the object type it was. You can see it here if you want.

If you take your $serverlist and pass it to Get-Member, see if there is a ToString() method. I think this method shows up for most System object types. If you do see it then you can try your command this way:


$serverlist | foreach {$_.ToString()} | foreach {New-PSSession -computer $_}
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.