Capitolo 8 - Comunicazione remota di PowerShell
PowerShell offre vari modi diversi per eseguire comandi su computer remoti. Nell'ultimo capitolo è stato illustrato come eseguire query remote su WMI usando i cmdlet CIM. PowerShell include anche diversi cmdlet con un parametro ComputerName predefinito.
Come illustrato nell'esempio seguente, Get-Command
può essere usato con il parametro ParameterName per determinare quali comandi includono un parametro ComputerName.
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
I comandi come Get-Process
e Get-Hotfix
includono un parametro ComputerName. Questo non è l'orientamento a lungo termine scelto da Microsoft per l'esecuzione di comandi su computer remoti. Anche se si trova un comando con un parametro ComputerName, è probabile che sia necessario specificare credenziali alternative e che non sia incluso un parametro Credential. E se si decide di eseguire PowerShell da un account con privilegi elevati, un firewall tra il computer locale e quello remoto può bloccare la richiesta.
Per usare i comandi di comunicazione remota di PowerShell illustrati in questo capitolo, è necessario abilitare la comunicazione remota di PowerShell nel computer remoto. Usare il cmdlet Enable-PSRemoting
per abilitare la comunicazione remota di PowerShell.
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.
Comunicazione remota uno-a-uno
Se la sessione remota dovrà essere interattiva, è possibile usare la comunicazione remota uno-a-uno.
Questo tipo di comunicazione remota viene fornito tramite il cmdlet Enter-PSSession
.
Nell'ultimo capitolo ho archiviato le mie credenziali di amministratore di dominio in una variabile denominata $Cred
. Se non è già stato fatto, procedere ad archiviare le credenziali di amministratore di dominio nella variabile $Cred
.
In questo modo è possibile immettere le credenziali una sola volta e usarle per ogni singolo comando, purché la sessione di PowerShell corrente sia attiva.
$Cred = Get-Credential
Creare una sessione di comunicazione remota di PowerShell uno-a-uno per il controller di dominio denominato dc01.
Enter-PSSession -ComputerName dc01 -Credential $Cred
[dc01]: PS C:\Users\Administrator\Documents>
Si noti che nell'esempio precedente il prompt di PowerShell è preceduto da [dc01]
. Questo significa che è in corso una sessione interattiva di PowerShell con il computer remoto denominato dc01. Tutti i comandi immessi vengono eseguiti in dc01, non nel computer locale. Tenere inoltre presente che è possibile accedere solo ai comandi di PowerShell presenti nel computer remoto e non a quelli nel computer locale. In altri termini, gli eventuali moduli aggiuntivi installati nel computer locale non saranno accessibili nel computer remoto.
Quando si è connessi a un computer remoto tramite una sessione di comunicazione remota interattiva uno-a-uno di PowerShell, si usa effettivamente il computer remoto. Gli oggetti sono oggetti normali esattamente come quelli usati in questo intero manuale.
[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(System.Object, ...
ErrorDataReceived Event System.Diagnostics.DataReceivedEventHandler ...
Exited Event System.EventHandler Exited(System.Object, Sy...
OutputDataReceived Event System.Diagnostics.DataReceivedEventHandler ...
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 CreateObjRef(...
Dispose Method void Dispose(), void IDisposable.Dispose()
Equals Method bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetLifetimeService Method System.Object GetLifetimeService()
GetType Method type GetType()
InitializeLifetimeService Method System.Object InitializeLifetimeService()
Kill Method void Kill()
Refresh Method void Refresh()
Start Method bool Start()
ToString Method string ToString()
WaitForExit Method bool WaitForExit(int milliseconds), void Wai...
WaitForInputIdle Method bool WaitForInputIdle(int milliseconds), boo...
__NounName NoteProperty string __NounName=Process
BasePriority Property int BasePriority {get;}
Container Property System.ComponentModel.IContainer Container {...
EnableRaisingEvents Property bool EnableRaisingEvents {get;set;}
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.ProcessModule MainModule ...
MainWindowHandle Property System.IntPtr MainWindowHandle {get;}
MainWindowTitle Property string MainWindowTitle {get;}
MaxWorkingSet Property System.IntPtr MaxWorkingSet {get;set;}
MinWorkingSet Property System.IntPtr MinWorkingSet {get;set;}
Modules Property System.Diagnostics.ProcessModuleCollection M...
NonpagedSystemMemorySize Property int NonpagedSystemMemorySize {get;}
NonpagedSystemMemorySize64 Property long NonpagedSystemMemorySize64 {get;}
PagedMemorySize Property int PagedMemorySize {get;}
PagedMemorySize64 Property long PagedMemorySize64 {get;}
PagedSystemMemorySize Property int PagedSystemMemorySize {get;}
PagedSystemMemorySize64 Property long PagedSystemMemorySize64 {get;}
PeakPagedMemorySize Property int PeakPagedMemorySize {get;}
PeakPagedMemorySize64 Property long PeakPagedMemorySize64 {get;}
PeakVirtualMemorySize Property int PeakVirtualMemorySize {get;}
PeakVirtualMemorySize64 Property long PeakVirtualMemorySize64 {get;}
PeakWorkingSet Property int PeakWorkingSet {get;}
PeakWorkingSet64 Property long PeakWorkingSet64 {get;}
PriorityBoostEnabled Property bool PriorityBoostEnabled {get;set;}
PriorityClass Property System.Diagnostics.ProcessPriorityClass Prio...
PrivateMemorySize Property int PrivateMemorySize {get;}
PrivateMemorySize64 Property long PrivateMemorySize64 {get;}
PrivilegedProcessorTime Property timespan PrivilegedProcessorTime {get;}
ProcessName Property string ProcessName {get;}
ProcessorAffinity Property System.IntPtr ProcessorAffinity {get;set;}
Responding Property bool Responding {get;}
SafeHandle Property Microsoft.Win32.SafeHandles.SafeProcessHandl...
SessionId Property int SessionId {get;}
Site Property System.ComponentModel.ISite Site {get;set;}
StandardError Property System.IO.StreamReader StandardError {get;}
StandardInput Property System.IO.StreamWriter StandardInput {get;}
StandardOutput Property System.IO.StreamReader StandardOutput {get;}
StartInfo Property System.Diagnostics.ProcessStartInfo StartInf...
StartTime Property datetime StartTime {get;}
SynchronizingObject Property System.ComponentModel.ISynchronizeInvoke Syn...
Threads Property System.Diagnostics.ProcessThreadCollection T...
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, PriorityClass, Fi...
PSResources PropertySet PSResources {Name, Id, Handlecount, WorkingS...
Company ScriptProperty System.Object Company {get=$this.Mainmodule....
CPU ScriptProperty System.Object CPU {get=$this.TotalProcessorT...
Description ScriptProperty System.Object Description {get=$this.Mainmod...
FileVersion ScriptProperty System.Object FileVersion {get=$this.Mainmod...
Path ScriptProperty System.Object Path {get=$this.Mainmodule.Fil...
Product ScriptProperty System.Object Product {get=$this.Mainmodule....
ProductVersion ScriptProperty System.Object ProductVersion {get=$this.Main...
[dc01]:
Dopo aver completato le operazioni nel computer remoto, usare il cmdlet Exit-PSSession
per uscire dalla sessione di comunicazione remota uno-a-uno.
[dc01]: Exit-PSSession
Comunicazione remota uno-a-molti
In alcuni casi può essere necessario eseguire un'attività in modo interattivo in un computer remoto. Tuttavia, la comunicazione remota è molto più efficace quando si esegue un'attività in più computer remoti contemporaneamente. Usare il cmdlet Invoke-Command
per eseguire un comando su uno o più computer remoti contemporaneamente.
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
Nell'esempio precedente è stata eseguita una query su tre server per recuperare lo stato del servizio Ora di Windows. Il cmdlet Get-Service
è stato inserito nel blocco di script Invoke-Command
. Get-Service
viene effettivamente eseguito nel computer remoto e i risultati vengono restituiti al computer locale come oggetti deserializzati.
Il pipe del comando precedente a Get-Member
mostra che i risultati sono effettivamente oggetti deserializzati.
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(string format, Sys...
Name NoteProperty string Name=W32time
PSComputerName NoteProperty string PSComputerName=sql02
PSShowComputerName NoteProperty bool PSShowComputerName=True
RequiredServices NoteProperty Deserialized.System.ServiceProcess.ServiceController[...
RunspaceId NoteProperty guid RunspaceId=570313c4-ac84-4109-bf67-c6b33236af0a
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.ServiceController[...
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.ServiceController[...
ServiceType Property System.String {get;set;}
Site Property {get;set;}
StartType Property System.String {get;set;}
Status Property System.String {get;set;}
Si noti che la maggior parte dei metodi non è presente negli oggetti deserializzati. Questo significa che non sono oggetti attivi, ma inerti. Non è possibile avviare o arrestare un servizio usando un oggetto deserializzato, perché si tratta di uno snapshot dello stato dell'oggetto, ovvero il punto in cui il comando è stato eseguito nel computer remoto.
Questo non significa però che non è possibile avviare o arrestare un servizio usando un metodo con Invoke-Command
. Significa semplicemente che il metodo deve essere chiamato nella sessione remota.
Per dimostrare questo punto, arresterò il servizio Ora di Windows in tutti e tre i server remoti usando il metodo Stop().
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
Come indicato in un capitolo precedente, se è disponibile un cmdlet per eseguire un'attività, è consigliabile usarlo invece di usare un metodo. Nello scenario precedente è consigliabile usare il cmdlet Stop-Service
invece del metodo stop. Ho scelto di usare il metodoStop() per dimostrare un punto, poiché molti ritengono erroneamente che non sia possibile chiamare i metodi quando si usa la comunicazione remota di PowerShell. Non possono essere chiamati sull'oggetto restituito perché è deserializzato, ma possono essere chiamati nella sessione remota stessa.
Sessioni di PowerShell
Nell'ultimo esempio della sezione precedente ho eseguito due comandi con il cmdlet Invoke-Command
.
Questo significa che è necessario configurare e rimuovere due sessioni separate per eseguire questi due comandi.
Analogamente alle sessioni CIM descritte nel capitolo 7, è possibile usare una sessione di PowerShell in un computer remoto per eseguirvi più comandi senza il sovraccarico di una nuova sessione per ogni singolo comando.
Creare una sessione di PowerShell per ognuno dei tre computer usati in questo capitolo, DC01, SQL02 e WEB01.
$Session = New-PSSession -ComputerName dc01, sql02, web01 -Credential $Cred
Ora usare la variabile denominata $Session
per avviare il servizio Ora di Windows usando un metodo e controllare lo stato del servizio.
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
Una volta creata la sessione usando credenziali alternative, non è più necessario specificare le credenziali ogni volta che viene eseguito un comando.
Dopo aver finito con le sessioni, assicurarsi di rimuoverle.
Get-PSSession | Remove-PSSession
Riepilogo
In questo capitolo sono state fornite informazioni sulla comunicazione remota di PowerShell, su come eseguire i comandi in una sessione interattiva con un computer remoto e su come eseguire i comandi su più computer con la comunicazione remota uno-a-molti. Sono stati inoltre descritti i vantaggi derivanti dall'uso di una sessione di PowerShell quando si eseguono più comandi sullo stesso computer remoto.
Revisione
- Come si abilita la comunicazione remota di PowerShell?
- Qual è il comando di PowerShell per avviare una sessione interattiva con un computer remoto?
- Qual è uno dei vantaggi derivanti dall'uso di una sessione di comunicazione remota di PowerShell rispetto alla semplice specifica del nome computer con ogni comando?
- È possibile usare una sessione di comunicazione remota di PowerShell con una sessione di comunicazione remota uno-a-uno?
- Qual è la differenza nel tipo di oggetti restituiti dai cmdlet rispetto a quelli restituiti quando si eseguono gli stessi cmdlet sui computer remoti con
Invoke-Command
?