0

I am writing a super-easy script in PowerShell. The target of this script is to read a list of server names from a txt file and a command block from another txt file. The result of the operation shold be a third txt file containing the information.

Here some code:

cls
$usr = Read-Host "Please insert username, you'll be asked for password later"
$path = Read-Host "Insert a valid path for ServerList.txt file"
$serverList = Get-Content -Path $path | Out-String

$path = Read-Host "Insert a valid path fom Command.txt file"
$commandBlock = Get-Content -Path $path | Out-String


echo "Command: " $commandBlock "will be executed on " $serverList
echo "Press CTRL+Z to abort or"
pause

Invoke-Command -ComputerName $serverList -ScriptBlock { $commandBlock } -credential $usr 

Serverlist.txt is a plain text containing something like "server1,server2,server3" and command.txt contain only this "Get-WmiObject Win32_BIOS | Select-Object SerialNumber"

Why the error is 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. ?

I even tried to substitute $serverlist with $serverlist.toString() but it's not working. I read somewhere that in this case $serverlist is an Array, how do I do to make everything work?

Consider that https://technet.microsoft.com/en-us/library/hh849719.aspx Invoke-Commands work with "server1,server2,server3" format if you put the string via console.

BlacK
  • 241
  • 7
  • 16

2 Answers2

2

Your $serverList isn't a list, it's a single string of server1,server2 etc. To make it into an array, you can use -split to split the string by commas.

$serverList = Get-Content -Path $path | Out-String
$serverList = $serverList -split ","
Vesper
  • 18,599
  • 6
  • 39
  • 61
  • The thing is that "server1,server2,server3" is what the invoke-command needs to work properly. I don't need to split! Don't I? – BlacK Jul 20 '15 at 13:39
  • 1
    @BlacK When you input `server1,server2,server3` as a naked argument, the PowerShell parser recognizes that it should be treated as three individual strings, not a single string. This is not the case when you pass a variable to it – Mathias R. Jessen Jul 20 '15 at 13:43
  • You do, as if you're passing a variable, its value is used unparsed, so that your `gwmi` command searches a computer named `server1,server2,server3` instead of going for three computers `server1`, `server2`, `server3`. But if your `$serverList` would be an array, then `gwmi` will see it and do a call on each computer. – Vesper Jul 20 '15 at 13:43
  • @MathiasR.Jessen Ninja'd by a fraction of a second O_O – Vesper Jul 20 '15 at 13:43
  • @Vesper Sorry, that's just how I roll (⌐■_■), have an upvote for justice – Mathias R. Jessen Jul 20 '15 at 13:46
  • 2
    @BlacK the last entry still has a trailing newline thanks to `Out-String`, see my answer below – Mathias R. Jessen Jul 20 '15 at 13:55
  • Okay, maybe there's a newline in the string. You can also replace newlines like `$serverList = $serverList -replace "[`r`n]",""` (there are backticks before "r" and "n", to make them into CRLF symbols instead of letters, and backticks are also escape symbols here at SO) – Vesper Jul 20 '15 at 13:56
  • 1
    @Vesper, you can get this ``"[`r`n]"`` by using this ```​``"[`r`n]"``​```. – user4003407 Jul 20 '15 at 14:41
  • @PetSerAl Thank you, I didn't know this. – Vesper Jul 20 '15 at 14:41
  • @PetSerAl otherwise, \ can be used to escape the backtick inside – Mathias R. Jessen Jul 20 '15 at 15:25
1

For further understanding of why this doesn't work as you expect, please see the parsing and command syntax help files:

Get-Help about_Parsing
Get-Help about_Command_Syntax

$serverlist

When your text file contains the line server1,server2,server3, this command:

Get-Content -Path .\file.txt | Out-String

Just results in the string server1,server2,server3 and a newline - that's not a valid hostname.

Either format your text file like this (Get-Content automatically splits on line breaks):

server1
server2
server3

or split the string(s) from the file yourself:

$Serverlist = Get-Content -Path $Path | ForEach-Object { $_ -split "," }

$commandblock

For the command block part to work, you can't just drop a string into a ScriptBlock and expect it to execute - you need to recreate it as executable code:

$Code = Get-Content -Path $path -Raw
$CommandBlock = [scriptblock]::Create($Code)

# Now you can do this
Invoke-Command -ScriptBlock $CommandBlock
Mathias R. Jessen
  • 157,619
  • 12
  • 148
  • 206