• 【PowerShell】長時間バッチ処理中に停電でサーバーがシャットダウン!でも Workflow ならば安心です

    Windows PowerShell 3.0 にはワークフロー機能が実装されています。もちろん、そのベースとなっているのは Windows Workflow Foundation 4.0 です。

    例えば、以下のようなワークフローがあったとします。このワークフローでは、UserList.csv ファイルにの保存されたユーザー一覧を読みこんで、大量のユーザーを順次作成する処理を想定していると考えてください。

    Workflow CreateUser
    {
        Get-Content -Path \\junichia-vdi\tools\ps\wf\UserList.csv -Encoding String | `
                Out-File -Path .\UserList_Unicode.csv -Encoding unicode

        $UserList = Import-Csv -Path .\UserList_Unicode.csv

        foreach  ($u in $UserList)
        {
            $UserID = $u.userID
            Echo -InputObject "$(Get-Date) $UserID を作成します"
            $password = convertto-securestring -Input $u.initialpassword -asplaintext -force
            $Department = $u.Department
            $FirstName = $u.FirstName
            $LastName = $u.LastName
            $HomeDirectory = \\Home\Share\$userID

            InlineScript
            {
                New-ADUser `
                   -Name $using:UserID `
                   -AccountExpirationDate 2012/12/31 `
                   -AccountPassword $using:password `
                   -ChangePasswordAtLogon $using:true `
                   -Department $using:Department `
                   -GivenName $using:FirstName `
                   -Surname $using:LastName `
                   -HomeDirectory $using:HomeDirectory `
                   -HomeDrive "Z:" `
                   -ErrorAction SilentlyContinue `
                   -ErrorVariable ERRORMESSAGE

                If ($ERRORMESSAGE.Count -eq 0)
                {
                  Echo -InputObject "$(Get-Date),$using:UserID を作成しました"
                } else {
                  Echo -InputObject "$(Get-Date),$using:UserID $ERRORMESSAGE"
                }
            }

            Checkpoint-Workflow

        }
    }

    ワークフローの実行までの流れは以下の通りです。

    image

    この例では、Invoke-Command を使用してリモートのドメインコントローラー上で、ワークフローをバックグラウンドジョブとして実行しています。

    上図の左側に「Stopped」や「Running」と書かれているのはワークフローの状態です。

    処理も半ばに差し掛かったころ、なんと停電の影響によりUPSからの指示でサーバーがシャットダウンを始めてしまいました。

    このとき、ワークフローは自動的に「Syspended」という状態に移行します。

    つまり、実行中のコマンドレットを、その状態ごとフリーズし保存してくれます。

    ワークフロー内部で扱っていた変数や出力結果もそのまま残されています。

    復電してドメインコントローラーが起動すると、ワークフローは自分ではレジュームできません。

    管理者が再度ドメインコントローラーに接続して Resume-Job コマンドレットによりジョブを再起動してあげる必要があります。

    通常、ジョブはサスペンドする直後からの処理を再開するので、ユーザー登録は漏れ無く実行することができます。

    もし、UPS管理ソフトがコマンドを発行できるタイプであれば、シャットダウン前にジョブをサスペンドし、次回起動時に自動的にレジュームするようスケジューリングすることもできます。

    VBSを使用していた時代は、サーバーが落ちたりクライアントが落ちると、ログを解析して続きのバッチを組みなおさなければなりませんでしたが、PowerShell 3.0 ではワークフローによって不測の事態の復旧が、とても簡単になりました。

  • 【PowerShell】PowerShell 3.0 を使用した Windows Server 2012 管理の自動化

    2012年6月は、毎週1回、10:00~11:30に Windows PowerShell 3.0 のセミナーを継続的に開催しています。

    これまでに、2回開催し、残すところあと2回となりました。

    • 基礎編(終了)
    • リモーティング編(終了)
    • ワークフロー編(6月19日)
    • 開発者編(PowerShell コマンドレットを使って管理アプリを作る)(6月25日)

    既に満席となっておりお申込みいただくことはできないのですが、ひとまずワークフロー編までの資料を以下に公開しました。

    随時アップデートしていく予定ですので、興味のある方はダウンロードしてお使いください。

  • 【PowerShell】リモートコンピューターが再起動するまで待ち合わせるには

    Windows PowerShell には Restart-Computer という便利なコマンドレットが用意されています。

    Restart-Computer –ComputerName TARGETCOMPUTER とすれば、リモートコンピューターを再起動することができます。

    もしリモートコンピューターに誰かがログオンしていても、-Force を指定することで強制的に再起動できます。もちろん管理者権限が必須です。

    さて、ここで問題です。

    リモートコンピューターに対して複雑な処理をしているとき、一度再起動が必要な処理があったとします。

    もちろん、再起動後にも処理は継続しなければなりません。

    どうしましょう?

    例えば、以下のようなスクリプトを作れば、待ち合わせは可能です。

    ※ 2012.6.18 14:21 スクリプトに不備があったので修正しました...すみません

    New-PSSession -ComputerName $ServerName
    Restart-Computer -ComputerName $ServerName -Force
    do #セッションが切断されるまで待ち合わせ
    {
        Start-Sleep -Seconds 1
    } Until ((Get-PSSession -ComputerName $ServerName).count -eq 0)
    do #セッションが再接続されるまで待ち合わせ
    {
        Start-Sleep -Seconds 1
        $S = New-PSSession -ComputerName $ServerName
    } Until ((Get-PSSession -ComputerName $ServerName).count -ne 0)
    echo 再接続されました $S
    Enter-PSSession $S

    比較的簡単に待ち合わせができることに、PowerShell 初心者の方は驚くかもしれませんが、まだ驚くのは早いです。

    PowerShell 3.0 では、たった1行で待ち合わせが可能です。

    Restart-Computer –ComputerName SERVERNAME –wait

    これだけです。

    すばらしすぎて腰が抜けそうです。

  • 【PowerShell】ループバック PS セッションとは

    Windows PowerShell 3.0 では、PowerShell のセッションから一旦切断して、別のコンピューターから再度接続する...ということが可能になっています。

    image

    PowerShell Web Accessを使用すれば自宅からの再接続も可能となり、どこからでも仕事がしたいエンジニアにとっては垂涎の機能です。PSWAを経由すればスマートフォンからでも接続できます。すばらしいです。

    image

    ここで、こんな疑問が出てきます。

    普通はサーバーに「ローカルログオン」して作業しているから、
    そこに再接続できるとうれしいんですけど

    はい、可能です。

    それがループバックPSセッションです。

    仕組みも使い方も、リモーティングと全く同じです。

    PowerShell コンソールを開いたら、以下のようにしてローカルコンピューターに対して PS セッションを開設します。

    PS C:\> $Session = New-PSSession

    PS C:\> Enter-PSSession $Session

    [LOCALHOST] PS C:\>

    プロンプトが [LOCALHOST] となったことに注意してください。これで、ローカルコンピューターに PS セッションを経由して入り込んだことになります。

    業が完了したら PowerShell コンソールを閉じる前に以下のコマンドを入力します。

    [LOCALHOST] PS C:\> Exit

    PS C:\> Disconnect-PSSession $Session

    Id Name            ComputerName    State         ConfigurationName        Availability
    -- ----            ------------    -----         -----------------        --------
    1 Session1        localhost       Disconnected  Microsoft.PowerShell     None

    そうすると、これまで行っていた環境は、Session1 という名前で、State=Disconnected(切断中)、Availability=None(誰も使っていない) となり、未使用のセッションとして保存されます。

    あとは、のマシンから以下のように入力して再接続することができます。

    PS C:\> $MySession = Connect-PSSession –ComputerName <サーバー> –Name Session1

    PS C:\> Enter-PSSession $MySession

    [サーバー] PS C:\>

    で、ですね。

    おそらく、こう思うはずなのです。

    めんどくせっ!

    そうなんです。せめて、PowerShell コンソールを開いたら、自動的にループバックセッションが有効になるようにできれば...と思うわけです。

    そこで、この処理をプロファイルに埋め込んでしまう方法を考えてみます。プロファイルに埋め込めば、起動時に自動的にセッションの作成や接続を行ってくれます。

    PowerShell プロファイルの場所は、$PROFILE に格納されていますので、確認してください。おそらく、以下のパスだと思います。

    C:\Users\<ユーザーID>\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1

    フォルダが無い場合には自分で作り、その下に Microsoft.PowerShell_profile.ps1 ファイルを作成します。テキストファイルです。

    メモ帳か PowerShell ISE で開いたら、以下のように入力してください。

    $LoopbackPSSessioin = New-PSSession
    Enter-PSSession $LoopbackPSSessioin

    function quit ()
    {
       Disconnect-PSSession $LoopbackPSSessioin
       exit
    }

    何やってるかわかりますか?

    1行目と2行目は、コンソールの起動時に実行されます。つまり、ローカルに PSセッションを張って、そこに乗り込んでいるわけですね。コンソールを起動すると、自動的に以下のような表示になります。

    [localhost]: PS C:\Users\administrator.TF\Documents>

    そして閉じるときは....

    [localhost]: PS C:\> Exit  ← これは PS セッションから抜けるため

    C:\PS > quit  ← $LoopbackPSSession を残すためにこのコマンドで抜ける

    と入力します。 Quit コマンドにより、Disconnect-PSSession $LoopbackPSSessioin が実行され、セッションが正常に切断されてコンソールが閉じます。

    コンソールを右上の[×]で閉じてしまったり、Exit コマンドで閉じてしまった場合は残念ながら保存されません。

    ・・・・・・・・・・・・・・・・・・・

    うーん、いまいちだなぁ...と金曜日の夜に物思いにふけるのでした...。

  • 【PowerShell】Invole-Command –FilePath パラメタの魔法

    Invoke-Command を使用するとリモートコンピューター上でコマンドレットを実行することができます。このとき、コマンドレット単体ではなく、スクリプトファイル(.ps1)を使用することができます。

    Invoke-Command で .ps1 ファイルを使用する方法は2つあります。

    Invoke-Command -ComputerName SV01 -FilePath .\hogehoge.ps1

    Invoke-Command -ComputerName SV02 {.\hogehoge.ps1}

    前者と後者の違い、わかりますか?

    前者の場合は、スクリプトファイルのパスはローカルコンピューターです。後者の場合は、リモートコンピューター内のパスになります。

    image

    リモートコンピューターにコマンドレットが存在することさえ確認できていれば、スクリプトファイルをいちいち送信しなくてもよいというのは非常に便利なことです。

    (参考)【PowerShell】Hyper-V 系コマンドレットを手元の Windows 7 から実行するには ~ Import-PSSession

    ちなみに、指定した ps1 ファイルに引数を指定したい場合にはどうしたらよいでしょう?

    以下のように、-ArgumentList パラメタを使用して指定します。

    Invoke-Command -ComputerName SV01 -FilePath .\hogehoge.ps1 -ArgumentList “Arg1",“Arg2",“Arg3"

    PowerShell...知れば知るほど奥が深いです。