Request - How to get all the alive servers in the domain?
pawanadubey opened this issue ยท 14 comments
Summary of the request
As an admin, have to do a lot of reporting for the servers in the domain, however not all the servers are always running.
Maybe using the ActiveDirectory module, get all the servers, and then do the Test-Connection command on the server to check if it is reachable, and return the alive servers.
- Active Directory Reference: https://docs.microsoft.com/en-us/powershell/module/addsadministration/get-adcomputer?view=win10-ps
- Test-Connection Reference: https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.management/test-connection?view=powershell-7.1
good idea...
If all the servers are in a specific OU, you can perform the following:
$servers = Get-ADComputer -Filter * -SearchBase 'OU=Severs, DC=company, DC=pri'
foreach ($server in $servers) {
Test-Connection -TargetName $server
}
What I did back in the day before foreach -Parallel {}
was:
Invoke-Command -Name (Get-ADComputer -Filter *).Name -ea Silent {
$ENV:COMPUTERNAME
}
If all the servers are in a specific OU, you can perform the following:
$servers = Get-ADComputer -Filter * -SearchBase 'OU=Severs, DC=company, DC=pri'
foreach ($server in $servers) {
Test-Connection -TargetName $server
}
@dr-raypc
I'm not sure that this is the place for this, but in case you're going to write something about this topic, then you may care to know that there's no reason to put a Test-Connection
command inside of a Foreach
language construct. The TargetName
parameter can accept more than a single computer at a time, such as Test-Connection -TargetName 'server1','server2','server3'
. Therefore, you issue the Get-ADComputer
command and then do Test-Connection -TargetName $servers.name
. Don't forget to use dotted notation, or you'll be sending the entire computer object to the Test-Connection command (even in your example), and that's probably not what you want. Anyway, you should write about this!
@tommymaynard that is great information, thank you Tommy!
One issue to remember is that Test-Connection
takes a parameter called ComputerName. In AD, the AD Computer object holds the computer name in the name property. So you can't do this:
Get-ADComputer ... | Test-Connection ...
There a couple of ways to solve this. You can define some Type XML and import it so as to add an alias to the AD Compuer object. I would hope to get a blog article up that shows this.
Alternatively, you can code around it like this:
Get-ADComputer ... | Test-Connection -ComputerName $_.Name ...
@tommymaynard one small error in your code. When you create $Servers, you create an array of computer objects each of which has a Name property. When you pass $Server to Test-Connection
the cmdlet fails with a 'cannot resolve the target name" error. This is because Test-Connection
is looking for a string of the computer name, whereas your code passes it the full DN of the computer object. You can code around this as noted above.
Hi @doctordns. I appreciate the feedback and discussion and I can see how a little back a forth here might actually be helpful for folks, especially if someone opts to take this topic and write about it. I'm not seeing things the same way you have, however. First, Test-Connection
only has a ComputerName parameter in Windows PowerShell. This changed to TargetName
at some time after 5.1. Perhaps it's because we can use ICMP with more than just computers. I'm uncertain whether that change was during the 6.x timeframe or later. Either way, when dr-raypc commented, he did so using the TargetName
parameter, which to me indicated he was using PowerShell (not Windows PowerShell).
Second, in my code example, I specifically wrote Test-Connection -TargetName $servers.name
. I indicated to use dotted notation in order that the entire AD computer objects, with their multiple properties, weren't used by Test-Connection
. This was to ensure that only the name property of each object was being used as the TargetName
parameter value. Let me know if there's any confusion, but if there was an error in my code, then I'm not sure what it was. Thanks.
Edit: It just dawned on me. I think you were looking at the code I quoted from dr-raypc. That wasn't my code.
I was not referring to the change in the parameter name in Test-Connection
. You are correct that PowerShell 7 now uses a -TargetName
parameter, but there is an alias to ComputerName
. For the curious, the code for the Test-Connection
cmdlet describes the parameter as follows:
/// <summary>
/// Gets or sets the destination hostname or IP address.
/// </summary>
[Parameter(
Mandatory = true,
Position = 0,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true)]
[ValidateNotNullOrEmpty]
[Alias("ComputerName")]
public string[]? TargetName { get; set; }
I was, instead, referring to the potential pipeline mismatch between the output of Get-ADComputer
and the pipeline input to the Test-Connection
cmdlet. The former produces objects with a property name of Name
to hold the computer name (the 'NetBIos' name so to speak) of the AD computer. The Test-Connection
cmdlet supports (as shown above) a parameter with a name (TargetName
) and an alias (ComputerName
). All of this means you can not directly pipe Get-ADComputer
to Test-Connection
. You get an error like this:
PS C:\Foo> Get-ADComputer -Identity Cookham1 | Test-Connection
Test-Connection: Cannot validate argument on parameter 'TargetName'. The argument is null, empty, or an element of the argument collection contains a null value. Supply a collection that does not contain any null values and then try the command again.
Instead, you would need to do this:
PS C:\Foo> Get-ADComputer -Identity Cookham1 | ForEach-Object {Test-Connection -TargetName $_.Name}
Destination: COOKHAM1
Ping Source Address Latency BufferSize Status
(ms) (B)
---- ------ ------- ------- ---------- ------
1 cookham24 10.10.10.9 0 32 Success
2 cookham24 10.10.10.9 0 32 Success
3 cookham24 10.10.10.9 0 32 Success
4 cookham24 10.10.10.9 0 32 Success
There is another way to 'fix' this. That is, you can create some PowerShell Type XML that adds an alias (i.e. TargetName
) to the name property in any ADComputerObject by default. You then import that in your profile and from there on in, the initial pipeline works as you might want it too. You might also want to use the AD Computer's DnsHostName
property as it has a FQDN that might be better to use with Test-Connection
.
Another thing - if you are using PowerShell 7, then use ForeachObject -Parallel
to run each test connection in parallel. This would really speed up any script that is waiting for a computer that is not online (and waiting and waiting).
Hope this clarifies things.
I don't like requiring Pwsh JUST to run this test in parallel. If I were stuck in a similar situation, I'd do something like
Test-Connection -ComputerName (Get-ADComputer -Identity MyComputerName).Name
(But with a search base instead of a single identity, of course).
If I really HAD to pipeline it, I'd probably use a calculated property:
Get-ADComputer -Identity MyCoputerName | Select-Object @{n='TargetName';e={$_.Name}} | Test-Connection
Also note that Test-Connection isn't quite the same as using Test-WSMan and I generally try to avoid using Test-Connection for AD Computers.
if you are only going to ping it, I take the point. But if you want to do stuff on each available host (eg check if an update has been applied, clean up old event logs, etc), being able to run things in parallel across a number of machines has real benefit.
There are, so far, 4 ways to bridge the gap between the AD's Name property and the -TargetName
parameter for Test-Connection. :-)
Loved the way the community is discussing each point.
After going through the comments, what I would do is to create the below functions:
- Get-ComputerNameFromAD: It will have parameters to filter the result on the basis of OU, OperatingSystem, etc.
- Check-IsComputerAvailable: The parameters could be an array of strings as ComputerName. And on the basis of what Edition of PowerShell is running, it would use the appropriate parameter name for Test-Connection.
Thanks for the review comments here on GitHub. I love that the community, as @pawanadubey mentions, can discuss the post before it's created. Hopefully, such discussions can lead to a better post. I appreciate, in particular, the reminder over Target-Name.
I have taken the discussion here and created a post and have issued a PR - #42.
I intend to have this post posted next week - comments most welcome!