2014/08/07

PowerShell Invoke-Command のScriptBlock オプションに関数を記述し実行したい

以前投稿した記事「PowerShell 手動追加したサービスをリモートから再起動するスクリプト」のスクリプトを実行した際、一部プロセスが正常終了しない現象に遭遇しました。
該当プロセスのチェック→終了する処理や関数化を行い、(個人的にスクリプトが)見やすい状態に修正。
しかし、書き方が悪かったためか、スクリプト ファイルに記述した関数をリモート先で実行できない事が判明。
今回は、Invoke-Command コマンドレットのScriptBlock オプションに関数を記述し実行する方法+αをメモ。
色々な手法があるかもしれません、ご紹介するスクリプトは一例だと思ってくださいね。

サンプル

サンプル内容は、「PowerShell 手動追加したサービスをリモートから再起動するスクリプト」のスクリプトを修正したものです。
環境等は上記リンクを参照願います。
Invoke-Command コマンドレットのScriptBlock オプションに関数を記述・実行する場合は
  1. リモートで実行したい関数をラップする($func1 = {~}の記述)
  2. リモート先に接続(New-PSSession ~)
  3. ラップ関数を実行する(Invoke-Command ~ -ScriptBlock $func1)
  4. 同上、メイン関数を実行する(Invoke-Command ~ -ScriptBlock {~})
の流れになります。
<#
-------------------------------------------------------------------
【  PS名  】 ScanSnap用サービス再起動スクリプト
【バージョン 】 1.1.0.0
-------------------------------------------------------------------
#>
$func1 = {
 function Reset-PfuServices()
 {
  Write-Host "サーバ接続 OK!!!"
  Write-Host "操作を開始します"
  
  #変数セット
  $fileFolder = "x:\ServerFolders\スキャンフォルダ"
  $ServiceName1 = "PfuSsMon"
  $ServiceName2 = "PfuSsWiaChecker"
  
  #サービス停止
  Stop-Service $ServiceName1 -Force 
  Stop-Service $ServiceName2 -Force 
  Write-Host " →サービスを停止しました"
  
  #プロセス終了
  # - 補足:サービス停止時に[PfuSsMon.exe]は終了するが、稀にプロセスが残り続ける場合あります。
  # - 本処理はその場合に強制終了させる処理です。
  $prcess = Get-Process | where{ $_.ProcessName -eq $ServiceName1 }
  if($process -ne $null)
  {
      Stop-Process -ProcessName $ServiceName1 -Force
      Write-Host " →プロセス「PfuSsMon」を削除しました"
  }
  
  #一時ファイル削除
  Set-Location $fileFolder
  $cnt =  (gci .\*pd~ | measure).Count
  if($cnt -gt 0)
  {
      Remove-Item .\*pd~ -Force
      Write-Host " →一時ファイルを削除しました"
  }
  
  #サービス開始
  Start-Service $ServiceName1
  Start-Service $ServiceName2
  Write-Host " →サービス開始しました"
  
  #サーバ切断
  Write-Host "全ての操作が完了しました"
 }
}

[string]$serverName = "xxxx"
[string]$adminUser = "administrator"
[string]$adminPwd = "P@ssword"

#資格認証
if($adminPwd -ne ""){
    $password = ConvertTo-SecureString $adminPwd -AsPlainText -Force
    $credential = New-Object System.Management.Automation.PSCredential("$serverName\$adminUser",$password)
}
else{
    $credential = "$serverName\$adminUser"
}

#接続
$s = New-PSSession -ComputerName $serverName -Credential $credential

#ラップ関数実行
Invoke-Command -Session $s -ScriptBlock $func1

#メイン関数実行
Invoke-Command -Session $s -ScriptBlock{ Reset-PfuServices }

#切断
Remove-PSSession -Session $s

メイン関数を記述した ps1 ファイルを実行する手もある!

当初、メイン関数の実行を
Invoke-Command -Session $s -ScriptBlock {function:Reset-PfuServices}
のように記述しましたが、失敗に終わりました。
理由は、リモート先に[Reset-PfuServices]関数が存在していないからです。
マイクロソフト エバンジェリスト 安納さんのブログで図解入りで説明されています。
すごくわかりやすいので、是非記事を読んでみてください。
【PowerShell】Invole-Command –FilePath パラメタの魔法(フィールドSEあがりの安納です)
安納さんが説明されている通り、メイン関数を記述したps1 ファイルをリモート先に送信、実行する方法も試してみました。
問題なく実行できますね!
関数を使いまわす場合は、スクリプト ファイル(.ps1)にしてしまった方が便利かな。
スクリプト ファイル(.ps1)のサンプル
Write-Host "サーバ接続 OK!!!"
Write-Host "操作を開始します"

#変数セット
$fileFolder = "D:\ServerFolders\スキャンフォルダ"
$ServiceName1 = "PfuSsMon"
$ServiceName2 = "PfuSsWiaChecker"

#サービス停止
Stop-Service $ServiceName1 -Force 
Stop-Service $ServiceName2 -Force
Write-Host " →サービスを停止しました"

#プロセス終了
# - 補足:サービス停止時に[PfuSsMon.exe]は終了するが、稀にプロセスが残り続ける場合あります。
# - 本処理はその場合に強制終了させる処理です。
$prcess = Get-Process | where{ $_.ProcessName -eq $ServiceName1 }
if($process -ne $null)
{
    Stop-Process -ProcessName $ServiceName1 -Force
    Write-Host " →プロセス「PfuSsMon」を削除しました"
}

#一時ファイル削除
Set-Location $fileFolder
$cnt =  (gci .\*pd~ | measure).Count
if($cnt -gt 0)
{
    Remove-Item .\*pd~ -Force
    Write-Host " →一時ファイルを削除しました"
}

#サービス開始
Start-Service $ServiceName1
Start-Service $ServiceName2
Write-Host " →サービス開始しました"

#サーバ切断
Write-Host "全ての操作が完了しました"
実行スクリプト
[string]$serverName = "xxxx"
[string]$adminUser = "administrator"
[string]$adminPwd = "P@ssword"

#資格認証
if($adminPwd -ne ""){
    $password = ConvertTo-SecureString $adminPwd -AsPlainText -Force
    $credential = New-Object System.Management.Automation.PSCredential("$serverName\$adminUser",$password)
}
else{
    $credential = "$serverName\$adminUser"
}

#接続
$s = New-PSSession -ComputerName $serverName -Credential $credential

#関数実行
Invoke-Command -Session $s -FilePath "x:\SampleScript.ps1"

#切断
Remove-PSSession -Session $s
スポンサーリンク

スポンサーリンク