Search code examples
arrayspowershellhostnamecomputer-nameread-host

Powershell Script to get list of local admins on multiple remote PC's


I almost have this but getting an error when inputting multiple computer names through the prompt input separated by comma. Individual computer name works.

$hostname = Read-Host -Prompt "Enter PC names (separated by comma)"
Invoke-Command -ComputerName $hostname -ScriptBlock{Get-LocalGroupMember -Group "Administrators"} | Export-Csv C:\temp\localadmins.csv

When running it without the Read-Host prompt, it works fine to input multiple separated by comma, but when using prompt input and entering multiple computer names it comes back with "one or more computer names are not valid". I'm expecting to to convert the $hostname from the input given over to the -ComputerName exactly as its typed in the input, but I think I'm missing something.

Error Output:

Enter PC names (separated by comma): computername1, computername2
Invoke-Command : One or more computer names are not valid. If you are trying to pass a URI, use the -ConnectionUri parameter, or pass URI objects 
instead of strings.
At \\usblfs003.global.baxter.com\users$\parksd2\docs\Scripts\LocalAdminsExport_EntitlementReview.ps1:2 char:1
+ Invoke-Command -ComputerName "$hostname" -ScriptBlock{Get-LocalGroupM ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (System.String[]:String[]) [Invoke-Command], ArgumentException
    + FullyQualifiedErrorId : PSSessionInvalidComputerName,Microsoft.PowerShell.Commands.InvokeCommandCommand

Solution

  • When running it without the Read-Host prompt, it works fine to input multiple separated by comma

    That is because something like the following:

    Invoke-Command -ComputerName server1, server2 -ScriptBlock …
    

    uses an array literal (via , the array constructor operator) to specify the individual computer names that bind to the [string[]]-typed -ComputerName parameter of the Invoke-Command cmdlet.

    By contrast, what Read-Host returns is invariably a string (a [string] instance), so using the response from the user typing server1, server in response to the a Read-Host prompt is equivalent to using
    … -ComputerName 'server1, server2' …
    which cannot work: it tells Invoke-Command to look for a single computer whose name is verbatim server1, server2

    To interpret a string as a list of values delineated by a separator, you need to explicitly convert it to an array:

    # Simulate a Read-host call
    $hostnameListString = 'server1, server2'
    
    # Convert the user input to an *array*
    $hostnames = ($hostnameListString -split ',').Trim()
    
    # Now you can pass the $hostnames array to Invoke-Command
    Invoke-Command -ComputerName $hostnames -ScriptBlock {
      Get-LocalGroupMember -Group Administrators
    } |
      Export-Csv C:\temp\localadmins.csv
    

    Note:

    • -split ',' uses the -split operator to split the input string into tokens by ,

    • .Trim(), applied to the resulting array of tokens, uses member-access enumeration, to strip any leading or trailing whitespace from each element.