第 8 章 - PowerShell 远程处理功能

PowerShell 提供了多种针对远程计算机运行命令的方法。 上一章介绍了如何使用 CIM cmdlet 远程查询 WMI。 PowerShell 还包括一些具有内置 ComputerName 参数的 cmdlet。

如以下示例所示,可以使用 Get-CommandParameterName 参数来标识包含 ComputerName 参数的 cmdlet。

Get-Command -ParameterName ComputerName
CommandType Name              Version Source                         
----------- ----              ------- ------                         
Cmdlet      Add-Computer      3.1.0.0 Microsoft.PowerShell.Management
Cmdlet      Clear-EventLog    3.1.0.0 Microsoft.PowerShell.Management
Cmdlet      Connect-PSSession 3.0.0.0 Microsoft.PowerShell.Core      
Cmdlet      Enter-PSSession   3.0.0.0 Microsoft.PowerShell.Core      
Cmdlet      Get-EventLog      3.1.0.0 Microsoft.PowerShell.Management
Cmdlet      Get-HotFix        3.1.0.0 Microsoft.PowerShell.Management
Cmdlet      Get-Process       3.1.0.0 Microsoft.PowerShell.Management
Cmdlet      Get-PSSession     3.0.0.0 Microsoft.PowerShell.Core      
Cmdlet      Get-Service       3.1.0.0 Microsoft.PowerShell.Management
Cmdlet      Get-WmiObject     3.1.0.0 Microsoft.PowerShell.Management
Cmdlet      Invoke-Command    3.0.0.0 Microsoft.PowerShell.Core      
Cmdlet      Invoke-WmiMethod  3.1.0.0 Microsoft.PowerShell.Management
Cmdlet      Limit-EventLog    3.1.0.0 Microsoft.PowerShell.Management
Cmdlet      New-EventLog      3.1.0.0 Microsoft.PowerShell.Management
Cmdlet      New-PSSession     3.0.0.0 Microsoft.PowerShell.Core      
Cmdlet      Receive-Job       3.0.0.0 Microsoft.PowerShell.Core      
Cmdlet      Receive-PSSession 3.0.0.0 Microsoft.PowerShell.Core      
Cmdlet      Register-WmiEvent 3.1.0.0 Microsoft.PowerShell.Management
Cmdlet      Remove-Computer   3.1.0.0 Microsoft.PowerShell.Management
Cmdlet      Remove-EventLog   3.1.0.0 Microsoft.PowerShell.Management
Cmdlet      Remove-PSSession  3.0.0.0 Microsoft.PowerShell.Core      
Cmdlet      Remove-WmiObject  3.1.0.0 Microsoft.PowerShell.Management
Cmdlet      Rename-Computer   3.1.0.0 Microsoft.PowerShell.Management
Cmdlet      Restart-Computer  3.1.0.0 Microsoft.PowerShell.Management
Cmdlet      Send-MailMessage  3.1.0.0 Microsoft.PowerShell.Utility   
Cmdlet      Set-Service       3.1.0.0 Microsoft.PowerShell.Management
Cmdlet      Set-WmiInstance   3.1.0.0 Microsoft.PowerShell.Management
Cmdlet      Show-EventLog     3.1.0.0 Microsoft.PowerShell.Management
Cmdlet      Stop-Computer     3.1.0.0 Microsoft.PowerShell.Management
Cmdlet      Test-Connection   3.1.0.0 Microsoft.PowerShell.Management
Cmdlet      Write-EventLog    3.1.0.0 Microsoft.PowerShell.Management

诸如 Get-ProcessGet-HotFix 这样包含 ComputerName 参数的命令,但此方法不是 Microsoft 推荐的针对远程系统运行命令的长期方案。 即使找到具有 ComputerName 参数的命令,它通常也缺少 Credential 参数,因此很难指定备用凭据。 在具有管理员权限的会话中运行 PowerShell 并不能保证一定成功,因为网络防火墙可能会阻止系统与远程计算机之间请求。

若要使用本章中演示的 PowerShell 远程处理命令,必须在远程计算机上启用 PowerShell 远程处理。 可以通过运行 Enable-PSRemoting cmdlet 来启用它。

Enable-PSRemoting
WinRM has been updated to receive requests.
WinRM service type changed successfully.
WinRM service started.

WinRM has been updated for remote management.
WinRM firewall exception enabled.

一对一远程处理

如果需要交互式远程会话,则需要一对一远程处理。 这种类型的远程处理是通过 Enter-PSSession cmdlet 提供的。

将域管理员凭据存储在变量中 $Cred 。 只要当前 PowerShell 会话保持活动状态,此方法允许你输入凭据一次,并按命令重复使用它们。

$Cred = Get-Credential

与名为 dc01 的域控制器建立一对一 PowerShell 远程处理会话。

Enter-PSSession -ComputerName dc01 -Credential $Cred

请注意,PowerShell 提示符前面有 [dc01]。 此前缀指示你正在与名为 dc01 的远程计算机进行交互式会话。 现在运行的任何命令在 dc01 上执行,而不是本地计算机。

[dc01]: PS C:\Users\Administrator\Documents>

请记住,只能访问远程计算机上安装的 PowerShell 命令和模块。 如果在本地安装了其他模块,则这些模块在远程会话中不可用。

通过一对一交互式远程处理会话进行连接时,就好像直接坐在远程计算机上一样。

[dc01]: Get-Process | Get-Member
   TypeName: System.Diagnostics.Process

Name                       MemberType     Definition
----                       ----------     ----------
Handles                    AliasProperty  Handles = Handlecount
Name                       AliasProperty  Name = ProcessName
NPM                        AliasProperty  NPM = NonpagedSystemMemorySize64
PM                         AliasProperty  PM = PagedMemorySize64
SI                         AliasProperty  SI = SessionId
VM                         AliasProperty  VM = VirtualMemorySize64
WS                         AliasProperty  WS = WorkingSet64
Disposed                   Event          System.EventHandler Disposed(Sy...
ErrorDataReceived          Event          System.Diagnostics.DataReceived...
Exited                     Event          System.EventHandler Exited(Syst...
OutputDataReceived         Event          System.Diagnostics.DataReceived...
BeginErrorReadLine         Method         void BeginErrorReadLine()
BeginOutputReadLine        Method         void BeginOutputReadLine()
CancelErrorRead            Method         void CancelErrorRead()
CancelOutputRead           Method         void CancelOutputRead()
Close                      Method         void Close()
CloseMainWindow            Method         bool CloseMainWindow()
CreateObjRef               Method         System.Runtime.Remoting.ObjRef ...
Dispose                    Method         void Dispose(), void IDisposabl...
Equals                     Method         bool Equals(System.Object obj)
GetHashCode                Method         int GetHashCode()
GetLifetimeService         Method         System.Object GetLifetimeService()
GetType                    Method         type GetType()
InitializeLifetimeService  Method         System.Object InitializeLifetim...
Kill                       Method         void Kill()
Refresh                    Method         void Refresh()
Start                      Method         bool Start()
ToString                   Method         string ToString()
WaitForExit                Method         bool WaitForExit(int millisecon...
WaitForInputIdle           Method         bool WaitForInputIdle(int milli...
__NounName                 NoteProperty   string __NounName=Process
BasePriority               Property       int BasePriority {get;}
Container                  Property       System.ComponentModel.IContaine...
EnableRaisingEvents        Property       bool EnableRaisingEvents {get;s...
ExitCode                   Property       int ExitCode {get;}
ExitTime                   Property       datetime ExitTime {get;}
Handle                     Property       System.IntPtr Handle {get;}
HandleCount                Property       int HandleCount {get;}
HasExited                  Property       bool HasExited {get;}
Id                         Property       int Id {get;}
MachineName                Property       string MachineName {get;}
MainModule                 Property       System.Diagnostics.ProcessModul...
MainWindowHandle           Property       System.IntPtr MainWindowHandle ...
MainWindowTitle            Property       string MainWindowTitle {get;}
MaxWorkingSet              Property       System.IntPtr MaxWorkingSet {ge...
MinWorkingSet              Property       System.IntPtr MinWorkingSet {ge...
Modules                    Property       System.Diagnostics.ProcessModul...
NonpagedSystemMemorySize   Property       int NonpagedSystemMemorySize {g...
NonpagedSystemMemorySize64 Property       long NonpagedSystemMemorySize64...
PagedMemorySize            Property       int PagedMemorySize {get;}
PagedMemorySize64          Property       long PagedMemorySize64 {get;}
PagedSystemMemorySize      Property       int PagedSystemMemorySize {get;}
PagedSystemMemorySize64    Property       long PagedSystemMemorySize64 {g...
PeakPagedMemorySize        Property       int PeakPagedMemorySize {get;}
PeakPagedMemorySize64      Property       long PeakPagedMemorySize64 {get;}
PeakVirtualMemorySize      Property       int PeakVirtualMemorySize {get;}
PeakVirtualMemorySize64    Property       long PeakVirtualMemorySize64 {g...
PeakWorkingSet             Property       int PeakWorkingSet {get;}
PeakWorkingSet64           Property       long PeakWorkingSet64 {get;}
PriorityBoostEnabled       Property       bool PriorityBoostEnabled {get;...
PriorityClass              Property       System.Diagnostics.ProcessPrior...
PrivateMemorySize          Property       int PrivateMemorySize {get;}
PrivateMemorySize64        Property       long PrivateMemorySize64 {get;}
PrivilegedProcessorTime    Property       timespan PrivilegedProcessorTim...
ProcessName                Property       string ProcessName {get;}
ProcessorAffinity          Property       System.IntPtr ProcessorAffinity...
Responding                 Property       bool Responding {get;}
SafeHandle                 Property       Microsoft.Win32.SafeHandles.Saf...
SessionId                  Property       int SessionId {get;}
Site                       Property       System.ComponentModel.ISite Sit...
StandardError              Property       System.IO.StreamReader Standard...
StandardInput              Property       System.IO.StreamWriter Standard...
StandardOutput             Property       System.IO.StreamReader Standard...
StartInfo                  Property       System.Diagnostics.ProcessStart...
StartTime                  Property       datetime StartTime {get;}
SynchronizingObject        Property       System.ComponentModel.ISynchron...
Threads                    Property       System.Diagnostics.ProcessThrea...
TotalProcessorTime         Property       timespan TotalProcessorTime {get;}
UserProcessorTime          Property       timespan UserProcessorTime {get;}
VirtualMemorySize          Property       int VirtualMemorySize {get;}
VirtualMemorySize64        Property       long VirtualMemorySize64 {get;}
WorkingSet                 Property       int WorkingSet {get;}
WorkingSet64               Property       long WorkingSet64 {get;}
PSConfiguration            PropertySet    PSConfiguration {Name, Id, Prio...
PSResources                PropertySet    PSResources {Name, Id, Handleco...
Company                    ScriptProperty System.Object Company {get=$thi...
CPU                        ScriptProperty System.Object CPU {get=$this.To...
Description                ScriptProperty System.Object Description {get=...
FileVersion                ScriptProperty System.Object FileVersion {get=...
Path                       ScriptProperty System.Object Path {get=$this.M...
Product                    ScriptProperty System.Object Product {get=$thi...
ProductVersion             ScriptProperty System.Object ProductVersion {g...

使用完远程计算机后,运行 Exit-PSSession cmdlet 以结束远程会话。

[dc01]:  Exit-PSSession

一对多远程处理

虽然有时可能需要在远程计算机上以交互方式执行任务,但当你同时跨多个远程系统执行命令时,PowerShell 远程处理会变得更加强大。 使用 Invoke-Command cmdlet 来同时在一个或多个远程计算机上运行命令。

在以下示例中,你将查询三个服务器以获取 Windows 时间服务的状态。 该 Get-Service cmdlet 放置在脚本块 Invoke-Command内,这意味着它在每台远程计算机上执行。

Invoke-Command -ComputerName dc01, sql02, web01 {
    Get-Service -Name W32time
} -Credential $Cred

结果作为反序列化对象返回到本地会话。

Status   Name        DisplayName       PSComputerName
------   ----        -----------       --------------
Running  W32time     Windows Time      web01
Start... W32time     Windows Time      dc01
Running  W32time     Windows Time      sql02

要确认返回的对象已反序列化,请将输出通过管道传递给 Get-Member

Invoke-Command -ComputerName dc01, sql02, web01 {
    Get-Service -Name W32time
} -Credential $Cred | Get-Member
   TypeName: Deserialized.System.ServiceProcess.ServiceController

Name                MemberType   Definition
----                ----------   ----------
GetType             Method       type GetType()
ToString            Method       string ToString(), string ToString(strin...
Name                NoteProperty string Name=W32time
PSComputerName      NoteProperty string PSComputerName=dc01
PSShowComputerName  NoteProperty bool PSShowComputerName=True
RequiredServices    NoteProperty Deserialized.System.ServiceProcess.Servi...
RunspaceId          NoteProperty guid RunspaceId=5ed06925-8037-43ef-9072-...
CanPauseAndContinue Property     System.Boolean {get;set;}
CanShutdown         Property     System.Boolean {get;set;}
CanStop             Property     System.Boolean {get;set;}
Container           Property      {get;set;}
DependentServices   Property     Deserialized.System.ServiceProcess.Servi...
DisplayName         Property     System.String {get;set;}
MachineName         Property     System.String {get;set;}
ServiceHandle       Property     System.String {get;set;}
ServiceName         Property     System.String {get;set;}
ServicesDependedOn  Property     Deserialized.System.ServiceProcess.Servi...
ServiceType         Property     System.String {get;set;}
Site                Property      {get;set;}
StartType           Property     System.String {get;set;}
Status              Property     System.String {get;set;}

请注意,反序列化对象缺少大多数方法。 缺少这些方法,因为这些对象不是实时的。 当对远程计算机执行命令时,它们是对象状态的惰性快照。 例如,不能使用反序列化对象启动或停止服务,因为它不再有权访问所需的方法。

但是,这并不意味着不能使用类似于Stop()Invoke-Command的方法。 密钥是必须在远程会话中调用该方法。

若要演示,请通过远程调用 Stop() 该方法来停止所有三个远程服务器上的 Windows 时间服务。

Invoke-Command -ComputerName dc01, sql02, web01 {
    (Get-Service -Name W32time).Stop()
} -Credential $Cred

Invoke-Command -ComputerName dc01, sql02, web01 {
    Get-Service -Name W32time
} -Credential $Cred
Status   Name        DisplayName       PSComputerName
------   ----        -----------       --------------
Stopped  W32time     Windows Time      web01
Stopped  W32time     Windows Time      dc01
Stopped  W32time     Windows Time      sql02

如前一章所述,如果有可用于完成任务的 cmdlet,最好使用它,而不是直接调用方法。 例如,使用 Stop-Service cmdlet 而不是 Stop() 方法停止服务。

在前面的示例中,使用 Stop() 方法来强调一个观点。 有些人错误地认为不能在 PowerShell 远程处理中使用方法。 虽然无法对返回到本地会话的反序列化对象调用方法,但可以在远程会话中调用它们。

PowerShell 会话

在上一部分的最后一个示例中,使用 Invoke-Command cmdlet 运行了两个命令。 这种情况导致建立并终止了两个独立的会话。 每个命令对应一个。

与 CIM 会话一样,持久性 PowerShell 会话允许针对远程计算机运行多个命令,而无需为每个命令创建新会话的开销。

在本章(DC01、SQL02 和 WEB01)中,为每个正在使用的三台计算机创建一个 PowerShell 会话。

$Session = New-PSSession -ComputerName dc01, sql02, web01 -Credential $Cred

现在,使用 $Session 变量通过调用其方法来启动 Windows 时间服务,然后验证服务状态。

Invoke-Command -Session $Session {(Get-Service -Name W32time).Start()}
Invoke-Command -Session $Session {Get-Service -Name W32time}
Status   Name        DisplayName       PSComputerName
------   ----        -----------       --------------
Running  W32time     Windows Time      web01
Start... W32time     Windows Time      dc01
Running  W32time     Windows Time      sql02

使用备用凭据创建会话后,无需为每个命令再次指定这些凭据。

使用完后,请务必删除会话。

Get-PSSession | Remove-PSSession

摘要

在本章中,你了解了 PowerShell 远程处理的基本知识,包括以交互方式在单个远程计算机上运行命令,并使用一对多远程处理跨多个系统执行命令。 此外,还探讨了在针对同一远程计算机运行多个命令时使用持久性 PowerShell 会话的优点。

回顾

  1. 如何启用 PowerShell 远程处理?
  2. 使用哪个 PowerShell 命令来启动与远程计算机的交互式会话?
  3. 使用 PowerShell 远程会话而不是在每个命令中指定计算机名称有什么好处?
  4. 是否可以在一对一交互式远程处理方案中使用 PowerShell 会话?
  5. 在本地运行的 cmdlet 返回的对象与在远程计算机上使用 Invoke-Command 执行相同 cmdlet 返回的对象之间有何区别?

参考