PowerShell: 遠程調用

通過本地程序調用 PowerShell 自定義腳本,我們可以有周期、計劃性的執行一些擴展的操作,這在一定程度上提高了本地程序自身邏輯的擴展性。而在編寫一段 PowerShell 腳本的過程中,也難免會遇到需要一段腳本在另一臺計算機上遠程執行的情形。例如,我們在執行一段 PowerShell 腳本時,需要向某個 AD Group 中添加一個 AD User,而這一操作需要在域控機器上才能執行,而此時,我們就會用到 PowerShell 遠程調用執行代碼。

在調用之前,我們需要保證 PowerShell 的遠程調用設置是開啓的。
1 啓用遠端計算機的 Windows Remote Management (WS-Management) service.
(1) 通過 services.msc 啓動服務管理器
(2) 在其中找到 Windows Remote Management (WS-Management) 這一項
(3) 確定該項服務正處於運行狀態,並且啓動類型被設置爲 Automatic

2 設定本地組策略.
(1) 通過 gpedit.msc 開啓本地組策略編輯器
(2) 找到 Computer Configuration > Administrative Templates > Windows Components > Windows Remote Management (WinRM) > WinRM
Service
(3) 在右側的項目中,雙擊 “Allow remote server management through WinRM”
(4) 在新彈出的窗口中,選擇Enabled,從而啓用策略,然後再Options的設置區域,位IPv4和IPv6 filter添加規則"*",從而使所有IP都不受到過濾器的限制。當然,這裏也可以根據具體的環境進行配置,相關配置可參考下圖。

WinRM Local Policy Settings for PowerShell

(6) 應用並保存配置後即可。

隨後,我們就可以通過 PowerShell 的 Invoke-Command 命令使 PowerShell 腳本片段在遠程機器上執行,我們同樣也可以向遠程腳本傳遞參數。

[ps]
# 定義傳遞給遠端服務器腳本的參數,這裏我們定義了一個字典對象來統一存放這些參數。
$tempParams = @{}
$tempParams.Add("adGroups", $adGroups)
$tempParams.Add("targetUsers", $targetUsers)

# 如果下邊不希望指定計算機名,而是IP,則必須提供Credential參數
# 援引 MSDN 的描述:
# To use an IP address in the value of the ComputerName parameter,
# the command must include the Credential parameter. Also,
# the computer must be configured for HTTPS transport or
# the IP address of the remote computer must be included
# in the WinRM TrustedHosts list on the local computer.

$results = Invoke-Command -Credential $登錄認證憑據對象 -ComputerName $遠程執行的計算機名 –ArgumentList $tempParams -ScriptBlock {
# 這裏開始編寫用於遠程執行的 PowerShell 腳本
Param($tempParams)
try
{
# 引用遠端計算機上的某個Module,以完成後續的操作,這裏假定我們的後續操作是修改AD
Import-module ActiveDirectory

# todo ...

return "success"
}
catch
{
return $_
}
}
[/ps]

關於 Invoke-Command 的詳細參數介紹,可參考MSDN

下面給出了一個操縱AD Group的示例,我將一些AD用戶從指定的AD組中移除。
* 這裏 $ADDomainAdminPasswordEncryptedText 保存的是實際密碼的密文,這樣可以防止用戶密碼被顯式的保存在腳本中。關於這一機制的介紹,可以參考我的另一篇blog.
[ps]
#
# Configurations
#
$ADDomainControllerComputerName = "DCHostName"
$ADDomainAdminUsername = "DOMAINDomainAdminUsername"
$ADDomainAdminPasswordEncryptedText = "01000000d08c9ddf0115d1118c7a00c04fc297eb0100000053c3945ec9b08c4b8d63f85a8edcd1190000000002000000000003660000c00000001000000014a97ff6bf4780b14e38d3ef9ae549640000000004800000a0000000100000006f8b17e3fad7da6f892a895a683d8f75180000007fe0d199ace1ed4306af34cdbb9fdcc2745a5bc9bd3abda8140000001bc56921787de674117e8c49f368745ac62400aa"
#

$logger = (Split-Path -Parent $MyInvocation.MyCommand.Definition) + "debug.log"

# Main
try
{

# ... ...

# Add User to AD Group
$targetUsers = $selectedUser.Split(";")
$adGroups = $selectedADGroup.Split(";")

$domainAdminPassword = $ADDomainAdminPasswordEncryptedText | ConvertTo-SecureString
$dcCred = New-Object -TypeName System.Management.Automation.PSCredential($ADDomainAdminUsername, $domainAdminPassword)

$tempParams = @{}
$tempParams.Add("adGroups", $adGroups)
$tempParams.Add("targetUsers", $targetUsers)

$results = Invoke-Command -Credential $dcCred -ComputerName $ADDomainControllerComputerName -ScriptBlock {
Param($tempParams)
try
{
Import-module ActiveDirectory

$adGroups = $tempParams["adGroups"]
$targetUsers = $tempParams["targetUsers"]

foreach($adGroup in $adGroups)
{
if(!$adGroup.Equals(""))
{
if($adGroup.Contains(""))
{
$adGroup = $adGroup.Split("")[1];
}

foreach($targetUser in $targetUsers)
{
try
{
if($targetUser.Contains(""))
{
$targetUser = $targetUser.Split("")[1]
}
$checkIsADGroup = $null
try { $checkIsADGroup = Get-ADGroup '$adGroup' -ErrorAction Continue } catch {}
# if the user is a AD Group and it has the different name with target AD group
if($checkIsADGroup -eq $null -or $checkIsADGroup -ne $null -and $adGroup -ne $targetUser)
{
Add-ADGroupMember -Identity $adGroup -Member $targetUser
}
}
catch
{
if(-not $_.Exception.Message.ToLower().Contains("The specified account name is already a member of the group".ToLower()))
{
throw $_
}
}
}
}
}
return "success"
}
catch
{
return $_
}
} –ArgumentList $tempParams

if($results -eq "success")
{
ac $logger "Add user to AD group successful."
}
else
{
ac $logger "Add user to AD group failed."
ac $logger $results
}
}
catch
{
ac $logger "Main Error: $_"
}
[/ps]

查看原文:http://nap7.com/me/powershell-remote-call/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章