> 文档中心 > PowerShell: 如何使用PowerShell同时操作多台服务器

PowerShell: 如何使用PowerShell同时操作多台服务器

PowerShell 的强大之一 在于对远程计算机进行很方便的管理,我自己在日常工作中使用了大量PowerShell脚本来进行服务器维护,自动化管理,甚至提供更多更高级的服务.
在远程管理中要用到一个非常有用的命令Invoke-Command,这可以说时服务器管理的神器. 接下来我会用一些列的文章来介绍我在日常工作中是如何使用这个命令的.

认识 Invoke-Command

从微软的官方文档上可以看到Invoke-Command的解释非常简短,就一句话:

Runs commands on local and remote computers.

在本地或者远程计算机上执行命令. 一个可以在本地或者远程计算机上执行命令的命令是多么的牛逼.

这个命令的用法有很多,这里只介绍两种最基本的用法, 本地执行命令/远程执行命令. 在执行脚本的过程中还会涉及到安全和认证. 都是在这两个用法的基础上扩展起来的.

#在当前计算机执行命令Invoke-Command      [-ScriptBlock]  #要执行的命令 由一对{}括起来的代码片段.      [-NoNewScope]      [-InputObject ]      [-ArgumentList <Object[]>] #如果你的代码片段中需要动态传递参数可以通过参数传进去      []
#在远程计算机上执行代码Invoke-Command      [[-ComputerName] <String[]>] #远程计算机名 可以是一台或者多台      [-Credential ]      [-Port ]      [-UseSSL]      [-ConfigurationName ]      [-ApplicationName ]      [-ThrottleLimit ]      [-AsJob]      [-InDisconnectedSession]      [-SessionName <String[]>]      [-HideComputerName]      [-JobName ]      [-ScriptBlock]  #要执行的命令 由一对{}括起来的代码片段.      [-SessionOption ]      [-Authentication ]      [-EnableNetworkAccess]      [-RemoteDebug]      [-InputObject ]      [-ArgumentList <Object[]>] #如果你的代码片段中需要动态传递参数可以通过参数传进去      [-CertificateThumbprint ]      []

最常用到的参数就是 -ScriptBlock, -ArgumentList, -ComputerName

尝试一下

接下来举几个例子来说明Invoke-Command的用法

1. 在当前机器上执行脚本

#获取本机所有进程Invoke-Command {Get-Process | ft -AutoSize}  

执行结果
可能会问直接执行 Get-Process | ft -AutoSize 不是一样的吗? 的确在本机执行Invoke-Command有点浪费,也不推荐这么用.

2. 在单台远程机器上执行脚本

#获取本机所有进程Invoke-Command {Get-Process | ft -AutoSize}  -ComputerName "remoteserver1"

和单台上执行效果差不多, 不过多解释
执行结果

3. 在多台远程机器上执行命令

由于安全原因,不能把我在公司使用的代码拷出来给大家参考(抱歉). 但是我们可以用微软官方的列子来说道说道.

  • 使用变量存储代码片段,并在多台机器执行

Example 5: Enter a command stored in a local variable

#代码片段可以直接存储到一个变量里面$command = { Get-WinEvent -LogName PowerShellCore/Operational |  Where-Object {$_.Message -like "*certificate*"} } Invoke-Command -ComputerName S1, S2 -ScriptBlock $command
  • 在多台机器上执行同一条命令

Example 6: Run a single command on several computers

#嫌一个个输参数太麻烦可以直接整到一个变量里面,@{Key=Value}表示实生成一个哈希表$parameters = @{  ComputerName = "Server01", "Server02", "TST-0143", "localhost"  ConfigurationName = 'MySession.PowerShell'  ScriptBlock = { Get-WinEvent -LogName PowerShellCore/Operational }}#注意这里引用的时候前面是 @ 不是 $. 这就相当于把$parameters这个哈希表里面的Key-Value和命令的参数名称-值自动匹配上Invoke-Command @parameters 
  • 使用配置文件输入服务器名字

Example 7: Get the version of the host program on multiple computers

$version = Invoke-Command -ComputerName (Get-Content Machines.txt) -ScriptBlock {(Get-Host).Version}# 服务器名字被放入Machines.txt 中并且按行分割. # (Get-Content Machines.txt) 得到的是一个机器名的字符串数组
  • 异步执行远程命令

Example 8: Run a background job on several remote computers

 $s = New-PSSession -ComputerName Server01, Server02Invoke-Command -Session $s -ScriptBlock {Get-EventLog system} -AsJob# -AsJob 命令以后台Job的形式异步执行Id   Name    State      HasMoreData   Location    Command---  ----    -----      -----  ----------- ---------------1    Job1    Running    True   Server01,Server02  Get-EventLog system$j = Get-Job$j | Format-List -Property *#获取Job的执行状态HasMoreData   : TrueStatusMessage :Location      : Server01,Server02Command: Get-EventLog systemJobStateInfo  : RunningFinished      : System.Threading.ManualResetEventInstanceId    : e124bb59-8cb2-498b-a0d2-2e07d4e030caId     : 1Name   : Job1ChildJobs     : {Job2, Job3}Output : {}Error  : {}Progress      : {}Verbose: {}Debug  : {}Warning: {}StateChanged  :$results = $j | Receive-Job#接收执行结果

这种方式在执行长时间运行的脚本的时候非常管用.
但是要注意的是:

– 在执行脚本的过程中不能退出PowerShell否则脚本不能完全执行
– 不管是执行的远程脚本还是本地脚本只要是以-AsJob (Start-Job 也一样)形式执行的, PowerShell都不能退出,否则脚本不能完全执行.
这两个坑是很多新手容易遇到,其实只要好好想一下不难理解-AsJob实际上它是以线程池的方式运行以-AsJob方式启动的命令行.

  • 执行的远程脚本中引用本地变量

Example 9: Include local variables in a command run on a remote computer

$Log = "PowerShellCore/Operational"Invoke-Command -ComputerName Server01 -ScriptBlock {Get-WinEvent -LogName $Using:Log -MaxEvents 10}

注意了:
– 这个$Log变量是不能直接引用的,因为$Log 变量实在当前机器上声明的, 而要执行的脚本在远程机器上运行. 所以要使用$Using 这个要和别的脚本语言区别开
– 即使是在本机 Invoke-Command或者Start-Job也是不能直接引用上下文变量的

  • 向执行的脚本传递参数

Example 11: Use the Param keyword in a script block

$parameters = @{    ComputerName = "Server01"    ScriptBlock = { Param ($param1,$param2) Get-ChildItem -Name $param1 -Include $param2 }    ArgumenArgtList = "a*", "*.pdf"}Invoke-Command @parametersaa.pdfab.pdfac.pdfaz.pdf

通过 -ArgumenArgtList 传进去的参数会按照顺序赋值给Param() 声明的参数变量
相当于
$param1等于"a*"
$param2等于"*.pdf"
当然ScriptBlock里面不声明Param ($param1,$param2)也是可以的,只不过使用的时候就要按照ArgumenArgtList 里面传递参数的顺序使用$arg[index]的方式来获取对应的参数.
例如:

$parameters = @{    ComputerName = "Server01"    ScriptBlock = { Get-ChildItem $args[0] $args[1] }    ArgumentList = "C:\Test", "*.txt*"}Invoke-Command @parametersDirectory: C:\TestMode   LastWriteTime  Length Name----   -------------  ------ -----a---    6/12/2019    15:15     128 alog.txt-a---    7/27/2019    15:16     256 blog.txt-a---    9/28/2019    17:10      64 zlog.txt

结束语

Invoke-Command在远程服务器管理中确实是非常灵活和方便的. 但是在使用过程中会遇到各种安全相关的问题. 在接下来的文章中会给大家分享一些我使用这个命令时遇到的一些坑以及怎么解决.

整理了部分近期发布的文章仅供大家参考:

  1. 为什么大神们的文章看起来那么酷?除了写的好还使用了生动的动图(gif)。一款【免费】的动图工具screentogif了解一下
  2. Powershell:使用PSCustomObject,序列化执行结果
  3. PowerShell: 为啥大神们的PowerShell窗口还有智能提示?因为他设置了这个
  4. PowerShell: 远程管理除了知道Invoke-Command,还应该掌握Enter-PSSession这个命令
  5. PowerShell: RDP管理服务器效率低下,使用invoke-command同时维护多台服务器不再难
  6. PowerShell:用原生PowerShell就能解决访问web资源时的ADFS认证问题
  7. PowerShell:不需要学Python,使用powershell也能处理Excel提高办公效率
  8. PowerShell:作为一个PowerShell菜鸟,如何快速入门?掌握这些就够了