Фев 292012
 
PowerShell

В предыдущей статье, я рассказал о том, как настроить выполнение команд на удаленных серверах. В показанном примере использовался одна пара логин\пароль для всех серверов. А что делать, если у нас много серверов и на каждом из них разные пароли да и к тому же они не находятся в одной сети? Выходов из этой ситуации можно найти много, но я нашел для себя оптимальный способ. Рассмотрим скрипт:

$credential=Get-Credential
$credential.Password | ConvertFrom-SecureString

или

$out = "c:\password.txt"
$credential=Get-Credential
$credential.Password | ConvertFrom-SecureString | Add-Content $out

при выполнении этих двух скриптов (необходимо ввести в открывшимся окне логин и пароль) мы получим некую строку или на экран (первый скрипт) или в файл (второй скрипт). Данная строка будет не что иной как зашифрованный пароль, который вы ввели. Вот этот самый пароль мы и будем использовать далее. Теперь создадим файл и назовем его  server_all.txt с таким содержанием:

Administrator;01000000d08c9ddf011.....7adb2;server1,server2
Administrator;01000000d08c9ddf011.....8fa35;server3,server7,server10,srv2
Administrator;01000000d08c9ddf011.....dea73;srv1

В этом файле я “обрезал” пароль, т.к. приводить его в полном варианте нет смысла. Заметьте, что у сервера с одинаковым паролем я объединил в одну строку. Это сделано умышленно для того, чтобы можно было выполнять команды параллельно на этих серверах. Далее пишем скрипт, который читает файл и выполняет одинаковые команды на этих серверах.

cls
 
$srv = Get-Content "x:\[path]\server_all.txt";
 
# Скрипт, который будем выполнять на удаленных серверах
$script_txt = "Get-Process exp*"
# Переводим его в "ScriptBlock"
$script = $executioncontext.invokecommand.NewScriptBlock($script_txt)
 
#Забиваем массивы с данными
foreach ($var in $srv) {
 
	# проверяем на комментарий, если есть в строке #- значит это коментарий.
	# или пустую строку
	if (($var -notmatch "#") -and ($var.Length -ne 0)){
 
		# разделим строку
		$tmp = $var -split ";"
 
		# преобразуем пароль
		$pass = $tmp[1] | ConvertTo-SecureString
		$cred = New-Object System.Management.Automation.PSCredential $tmp[0],$pass
 
		$s = $tmp[2] -split ","
 
		# создаем сессию
		$session = New-PSSession -ComputerName $s -Credential $cred
 
		# выполняем запрос (найдем процесс "explorer")
		$result = Invoke-Command -Session $session -ScriptBlock $script
 
		# Обработаем результат
		for ($i=0; $i -lt $result.Count; $i++){
			Write-Host $result[$i].PSComputerName,"`t",$result[$i].Name
		}
 
		#Выходим из сессии.
		Remove-PSSession -Session $session
 
	}
}

Результат работы скрипта будет следующий:

server1   explorer
server2   explorer
server3   explorer
server7   explorer
server10   explorer
srv2   explorer
srv1   explorer

Вот собственно и все.
Единственное на что хотелось бы обратить внимание, так это на то, что если перенести этот скрипт на другой компьютер (или запустить под другой учетной записью), то это работать не будет, т.к. пароли “привязываются” к учетной записи и компьютеру. И в этом есть плюс!