uncategorized

用Powershell執行遠端VM內的Powershell Script

遇到VSTS佈署到遠端VM後,必須執行一些遠端VM中的Powershell的情境,執行佈署的Server和遠端VM並不在同一個網域內,所以,無法透過網域的方式去執行遠端VM中的PowerShell指令。因此,為了要達到這個目的,就必須在遠端VM中安裝WinRM( Windows remote management),這樣才有辦法在Clinet端呼叫遠端VM中的Powersehll

設定WINRM


首先,必須在遠端VM安裝Winrm元件,我們才可以透過WinRM和遠端的PowerShell溝通。安裝完畢後,執行啟動PSRemote功能

1
Enable-PSRemoting

為了確保WINRM有啟動,可以再執行下面指令確認

1
winrm quickconfig

若有出現詢問視窗,基本上都選擇Y,完畢後會出現下面資訊

WinRM service is already running on this machine.
WinRM is already set up for remote management on this computer.

遠端VM設定好之後,還要設定呼叫端的TrustedHosts,不然,會出現連線驗證的問題,所以,可以在呼叫端先查詢TrustedHosts設定,一般來說預設並沒有設定任何Trusted的Hosts

1
get-item wsman:\localhost\Client\TrustedHosts

要設定TrustedHosts其指令如下,其中*,代表任何位置都可以,如果要特定的位置,就把星號改成IP或是HostName

1
set-item wsman:\localhost\Client\TrustedHosts -value *

這樣基本雙方環境就設定的差不多,接下來就可以開始撰寫Powershell的Script,這邊把要呼叫遠端VM的Powershell的指令,也寫成一個Script

執行Remote PowerShell


在呼叫遠端的Powershell指令前,我們需要幾個參數

  • $machineaddress : 遠端VM的IP
  • $machineName : 登入VM的帳號
  • $machinePwd : 登入VM的密碼

因為,後續要把這個Powershell Script放到VSTS做自動化佈署用,所以,必須讓密碼能直接被使用,而不是彈跳出輸入密碼的對話框

1
$pw = convertto-securestring -AsPlainText -Force -String $machinePwd

建立登入VM的憑證

1
$cred = new-object -typename System.Management.Automation.PSCredential -argumentlist $machineName,$pw

設定Clinet連線到遠端VM的Session,並且要Keep這個Session,讓後續指令可以使用

1
$s = New-PSSession -ComputerName $machineaddress -Credential $cred

取得遠端VM要被執行的Powershell檔案的路徑

1
$filepath='C:\test\test.ps1'

使用Invoke-Command來執行呼叫test.ps1的動作,基本寫法可以這樣

1
Invoke-Command -Session $s -scriptblock {& 'C:\test\test.ps1'}

另一種寫法就是把-scriptblock {}中的值作為一個Local變數來處理,後面再用帶參數的方式填入$filepath,所以,寫法可以改成下面這樣,這樣寫法的彈性個人覺得會比較好

1
Invoke-Command -Session $s -scriptblock {& $args[0]} -ArgumentList $filepath

今日,如果要被執行的Powershell Script,本身有需要外部帶入參數時候,就可以擴充如下,等同執行C:\test\test.ps1 Hello world意思是相同的

1
Invoke-Command -Session $s -scriptblock {& $args[0] $args[1] $args[2]} -ArgumentList $filepath,'Hello','world'

所以,完整的程式碼如下

1
2
3
4
5
6
7
8
9
$machineaddress=$args[0]
$machineName=$args[1]
$machinePwd=$args[2]
$pw = convertto-securestring -AsPlainText -Force -String $machinePwd
$cred = new-object -typename System.Management.Automation.PSCredential -argumentlist $machineName,$pw
$s = New-PSSession -ComputerName $machineaddress -Credential $cred
$filepath='C:\test\test.ps1'
Invoke-Command -Session $s -scriptblock {& $args[0] $args[1] $args[2]} -ArgumentList $filepath,'Hello','world'