しばたテックブログ

気分で書いている技術ブログです。

PowerShell on Linuxに普通にPSRemotingしてみる - その3

その1その2の続き的な。

以前のエントリで書いた、

github.com

のIssueがクローズされ、OMIおよびPowerShell on Linux OMI Providerpackages.microsoft.comリポジトリからインストール可能になったので試してみました。

インストール

私が使い慣れているCentOS 7.3で検証します。

はじめにpackages.microsoft.comリポジトリの追加とPowerShellのインストールをしておきます。

# CentOS 7, Bash
curl https://packages.microsoft.com/config/rhel/7/prod.repo | sudo tee /etc/yum.repos.d/microsoft.repo
sudo yum install -y powershell

こちらは以前のエントリで書いた通りですのでとくに問題はないでしょう。

続けてPowerShell on Linux OMI Providerをインストールします。

パッケージ名はomi-psrp-serverで、依存パッケージにOMI(omi)が登録されているので、こちらをインストールすればOMIも同時にインストールされます。
ですので以下の様にyum install一回でインストールできます。

# CentOS 7, Bash
sudo yum install -y omi-psrp-server

実行結果は以下の様な感じになります。

f:id:stknohg:20170309185812p:plain

インストールが完了したあとはOMIDが動いてればOKです。

OMIDが起動しているかはservice(またはsystemctl status)コマンドで確認してください。

# OMIDが動作しているのを確認
service omid status
# または
# systemctl status omid.service

f:id:stknohg:20170309190015p:plain

ちなみに、現時点の各パッケージのバージョンは、

  • PowerShell - Ver.6.0.0.alpha16
  • PowerShell on Linux OMI Provider - Ver.1.1.0-alpha18 (1.0.0.18)
  • OMI - Ver.1.2.0

となっています。

接続確認

例によってWindows Server 2012 R2(PowerShell 5.1)から接続確認をしてみます。
接続先のIPは192.168.33.209、ユーザーはvagrantおよびrootで試しています。

# Enter-PSSessionで接続
$o = New-PSSessionOption -SkipCACheck -SkipRevocationCheck -SkipCNCheck
Enter-PSSession -ComputerName 192.168.33.209 -Credential vagrant -Authentication basic -UseSSL -SessionOption $o

f:id:stknohg:20170309183812p:plain

普通に使えますが、切断時に謎なエラーが出ました...

f:id:stknohg:20170309183837p:plain

とりあえずこいつは気にしないことにして、CIM情報の取得をします。

# Get-CimInstanceで情報取得
# こっちは要root
$o = New-CimSessionOption -SkipCACheck -SkipRevocationCheck -SkipCNCheck -UseSsl
$s = New-CimSession -ComputerName 192.168.33.209 -Credential root -Authentication Basic -SessionOption $o
Get-CimInstance -CimSession $s -Namespace root/omi -ClassName OMI_Identify

f:id:stknohg:20170309183853p:plain

こちらもこれまで試した結果と同じです。

最後に

とりあえずこんな感じです。

各パッケージのインストールがかなり楽になったのであとは動作が安定してくれれば使い物になるのかな、と思います。

AdmxPolicyというPowerShellモジュールを公開しました

ちょっとしたきっかけから、AdmxPolicyというADMXファイルの中身を解析して各グループポリシーが使用するレジストリキーの値を取得するPowerShellモジュールを作ってみました。

ソースと基本的な使い方はGitHubに上げています。

github.com

またPowerShell Galleryでも公開しており以下のコマンドでインストール可能です。

www.powershellgallery.com

Install-Module -Name AdmxPolicy -Scope CurrentUser

なお動作環境はPowerShell 2.0以上です。
PowerShell 2.0の環境ではReleaseにあるZipファイルを解凍してAdmxPolicyフォルダをImport-Moduleしてください。

モジュールを作るきっかけ

このモジュールを作ろうと思ったきっかけはteratailのこの質問になります。

teratail.com

この質問で参考にして頂いているエントリに以下の様に書きましたが、各グループポリシーが取るレジストリ値を調べるのは容易ではありません。

そして各ポリシーがどの様なレジストリ値を取るのかについては、
* Group Policy Registry Reference や、
* Group Policy Settings Reference for Windows and Windows Server からダウンロードできるExcelファイルを参照することである程度わかります。
(2014/12/12追記:上記の他にポリシーのadm/admxファイルをテキストエディタ等で直接参照することでもレジストリ値の情報を知ることができます。)

そこでADMXファイルを解析するツールを作れば少しは楽ができるかなと思い作ってみました。

作った結果

現時点でこのモジュールは個々のADMXファイルを解析して各ポリシーが取りうるレジストのキーとその値を取得することができます。

ただし、各ポリシーが取りうる値は非常に多岐にわたり、このモジュールがあればグループポリシーの設定をすべて自動化できるという訳にはいきませんでした。
また、ADMXファイルに記載されているレジストリの設定情報はグループポリシーエディタのUIと非常に強く結びついており、一見しただけでは何の設定値か判別しにくい(グループポリシーエディタのUI上でみてはじめて意味が通る)ものも結構あります。

そのためコレはあくまでも補助ツールとして使うのが良いかなと思っています。

きっかけとなる問題に対して完璧なソリューションにはなりませんでしたが、それでも何もないよりはマシかなといったところです。

使用例

使用例として、実際のグループポリシーの設定とこのモジュールの結果を突き合わせてみます。

0. 試験環境について

適当なドメインcontoso.localに設定したポリシーTextPolicyを例にします。
このTestPolicyではコマンド プロンプトにアクセスできないようにするポリシーを有効に設定しておきます。

f:id:stknohg:20170307002922p:plain

f:id:stknohg:20170307002938p:plain

1. ポリシーの検索

まずはコマンド プロンプトにアクセスできないようにするポリシーを検索する必要があります。

ADMXファイルがインストールされているディレクトリ(ここではセントラルストア)のADMXファイルを対象に以下の様にポリシーを検索します。

$admxPath = "C:\Windows\SYSVOL\domain\Policies\PolicyDefinitions\*.admx"
ls $admxPath | Get-AdmxPolicies | ? { $_.DisplayName -like "*コマンド プロンプト*" }

ちょっと時間がかかりますが、結果はこんな感じになり、Shell-CommandPrompt-RegEditTools.admxにあるDisableCMDというポリシーであることがわかります。

f:id:stknohg:20170307003423p:plain

2. ポリシーの取得

該当のポリシーがわかったのでポリシー情報を取得してみます。

$admxPath = "C:\Windows\SYSVOL\domain\Policies\PolicyDefinitions\Shell-CommandPrompt-RegEditTools.admx"
$policy = Get-AdmxPolicies -FilePath $admxPath | ? { $_.Name -eq "DisableCMD" }

取得した結果はこんな感じになります。

f:id:stknohg:20170307003731p:plain

この結果のRegistryTypeRegistryRootKeysRegistryPathプロパティからレジストリのキー情報を取得することができます。

$policy.RegistryType     # マシンポリシー、ユーザーポリシー、その両方かの種別
$policy.RegistryRootKeys # RegistryTypeに応じたルートキー
$policy.RegistryPath     # レジストリのサブキー

f:id:stknohg:20170307004207p:plain

結果、このポリシーはHKEY_CURRENT_USER\Software\Policies\Microsoft\Windows\Systemキーを使うことがわかります。

次に、レジストリ値についてはValueInfoプロパティから取得可能です。

$policy.ValueInfo # レジストリ値情報

f:id:stknohg:20170307004457p:plain

ここからが厄介なところで、ADMXファイルで定義されるレジストリ値は大きく3パターンに分類されます。

  1. 単純なEnabled/Disabled値
    • RegistryValueName、EnabledValue、DisabledValue
  2. Enabled/Disabledのリストを取るEnabledList/DisabledList
    • HasEnabledList、EnabledList、HasDisabledList、DisabledList
  3. グループポリシーエディタのUIと紐づく値となるElement値
    • HasElements、Elements

今回のポリシーは3.のElement値だけをもっています。*1

ですので、このElementにアクセスしてみると以下の様な情報を得ることができます。

f:id:stknohg:20170307005546p:plain

この結果はElementの中の列挙体であるEnumElementで、レジストリ値がDisableCMD、取りうる値が1または2であることを示しています。

Keyはいいいえについてはグループポリシーエディタのコンボボックスに表示される名称になり、こういったところがぱっと見でわからない感じになっています…

f:id:stknohg:20170307010100p:plain

ちなみに、ElementはEnumElementを含めて

  • BooleanElement
  • DecimalElement
  • LongDecimalElement
  • TextElement
  • MultiTextElement
  • EnumElement
  • ListElement

の7種類存在します。
これらの詳細はADMX Policy Definition Schemaに定義されています。

本エントリでは個々の詳細まで触れませんが、実際に見ればそれなりに予測はつくかと思います。

これで情報は全て集まり、

  • キー : HKEY_CURRENT_USER\Software\Policies\Microsoft\Windows\System
  • 値 : DisableCMD
  • 設定値 : 1または2

であることがわかりました。

3. 実際のポリシーと付け合わせる

前項の結果が正しければGet-GPRegistryValueコマンドで値を取得できるはずです。
実際に確認してみます。

Get-GPRegistryValue -Name TestPolicy -Key HKEY_CURRENT_USER\Software\Policies\Microsoft\Windows\System

結果は以下の様になりAdmxPolicyモジュールで得た情報と合っていることがわかります。

f:id:stknohg:20170307011215p:plain

補足 : POLファイルを解析する

AdmxPolicyモジュールではテンプレートであるADMXファイルの情報からレジストリ値を探しましたが、補足として、実際のポリシー定義の情報であるPOLファイルからレジストリ情報を取得する方法について説明します。

GPRegistryPolicyParser

PowerShell Teamが公式にグループポリシーのPOLファイルを解析するモジュールGPRegistryPolicyParserを提供しているのでこれを使います。

github.com

このモジュールは、もともと、Nano Serverに対してグループポリシーを適用する・情報を取得することを目的としている様でPowerShell 5.0以上でないと動作しませんので注意してください。

POLファイルはSYSVOLなどから直接取得しても構いませんが、安全のためにBackup-GPOコマンドでとったバックアップから抜くなどした方が良いでしょう。

本エントリではその辺の手順は端折りますが、取得したPOLファイルに対して以下のコマンドを実行するとPOLファイルの中身を見ることができます。

Parse-PolFile -Path [POLファイルのパス]

実行例)

f:id:stknohg:20170307012735p:plain

テスト用のポリシーを自由に作れる環境であればこちらを使う方が楽ができるでしょう。

最後に

とりあえずこんな感じです。

グループポリシーで使うレジストリ値の取得は一筋縄ではいきませんが、AdmxPolicy、GPRegistryPolicyParserといったツールを使うことで多少は楽ができるかと思います。

*1:なお、これらのパターンはどれか一つというわけではなく組み合わせで設定されます…

Nano ServerにPowerShell 6.0をインストールする

公式に手順が追加されたのでまとめてみました。

公式な手順について

公式な手順はこちら。

https://github.com/PowerShell/PowerShell/blob/master/docs/installation/windows.md#deploying-on-nano-server

PowerShell 6.0のインストール

基本的にPowerShell 6.0のインストールはWindows 10/Windows Server 2016向けのZipファイルを展開するだけでOKです。

Nano Serverは初期ビルドではInvoke-WebRequestが使えないため、公式な手順ではPowerShell DirectなどによりZipファイルを転送したうえで展開する様になっています。

指定例)

# ZipファイルはPowerShell Directなどであらかじめ転送しておく前提
Expand-Archive -Path C:\powershell-<version>-win10-win2016-x64.zip -DestinationPath "C:\Program Files\PowerShell\<version>"

ちなみに現時点で最新のWindows Updateを適用すればInvoke-WebRequestが使える様になりますので直接ダウンロードして展開しても構いません。

PowerShell Remotingエンドポイントの追加

PowerShellをインストールした後にPowerShell Remoting用のエンドポイントを追加します。

Install-PowerShellRemoting.ps1というスクリプトを実行することでWinRMにPowerShell 6.0の設定を追加し、New-PSSessionEnter-PSSessionでPowerShell 6.0に接続可能にすることができます。

このスクリプトは以下の様に-PowerShellHome-PowerShellVersionの2つの引数を指定する必要があります。
-PowerShellHomeにはインストールしたPowerShell 6.0の$PSHOME(=インストールディレクトリ)の絶対パスを、-PowerShellVersionにはバージョンに応じた任意の名称を指定します。

指定例)

.\Install-PowerShellRemoting.ps1 -PowerShellHome "<PowerShell 6.0の$PSHOMEの絶対パス>" -PowerShellVersion "<識別用のバージョン名>"

実行例)

# これはPowerShell 5.1から実行して良い
.\Install-PowerShellRemoting.ps1 -PowerShellHome "C:\Program Files\PowerShell\6.0.0.16\" -PowerShellVersion "6.0.0-alpha.16" 

なお、このスクリプトはPowerShell 5.1から実行して構いませんが、実行するには管理者権限が必要です。

また、処理の最後にWinRMサービスを再起動するのでリモートセッション中で実行すると最後にセッションが切断されてしまいますので注意してください。

そしてエンドポイントが追加された後は、New-PSSessionEnter-PSSession-ConfigurationNameパラメーターを指定することでPowerShell 6.0に接続することができます。
-ConfigurationNameパラメーターには先のInstall-PowerShellRemoting.ps1スクリプトで-PowerShellVersionに指定した名称を設定します。

指定例)

# Enter-PSSessionの場合
Enter-PSSession -ComputerName nanoserver -Credential $cred -ConfigurationName "powershell.6.0.0-alpha.16"

実行例)

PS C:\> Enter-PSSession -ComputerName nanoserver -Credential $cred -ConfigurationName "powershell.6.0.0-alpha.16"
[nanoserver]: PS C:\Users\Administrator\Documents> $PSVersionTable

Name                           Value
----                           -----
PSRemotingProtocolVersion      2.3
CLRVersion
BuildVersion                   3.0.0.0
PSVersion                      6.0.0-alpha
WSManStackVersion              3.0
SerializationVersion           1.1.0.1
PSEdition                      Core
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}
GitCommitId                    v6.0.0-alpha.16

ちなみにエンドポイントの情報はGet-PSSessionConfigurationで確認することができ、実際に見てみると以下の様になっています。

[nanoserver]: PS C:\> Get-PSSessionConfiguration -Name "powershell.6.0.0-alpha.16" | Format-List *


AutoRestart                   : false
Uri                           : http://schemas.microsoft.com/powershell/powershell.6.0.0-alpha.16
PSVersion                     : 5.0
OutputBufferingMode           : Block
MaxConcurrentUsers            : 5
RunAsPassword                 :
MaxShells                     : 25
MaxConcurrentCommandsPerShell : 1000
SDKVersion                    : 2
ExactMatch                    : true
XmlRenderingType              : text
RunAsUser                     :
IdleTimeoutms                 : 7200000
Name                          : powershell.6.0.0-alpha.16
SecurityDescriptorSddl        : O:NSG:BAD:P(A;;GA;;;BA)S:P(AU;FA;GA;;;WD)(AU;SA;GXGW;;;WD)
RunAsVirtualAccount           : false
RunAsVirtualAccountGroups     :
SupportsOptions               : true
MaxShellsPerUser              : 25
MaxProcessesPerShell          : 15
Filename                      : C:\Windows\System32\PowerShell\6.0.0-alpha.16\pwrshplugin.dll
ResourceUri                   : http://schemas.microsoft.com/powershell/powershell.6.0.0-alpha.16
ProcessIdleTimeoutSec         : 0
MaxMemoryPerShellMB           : 1024
Enabled                       : True
ParentResourceUri             : http://schemas.microsoft.com/powershell/powershell.6.0.0-alpha.16
xmlns                         : http://schemas.microsoft.com/wbem/wsman/1/config/PluginConfiguration
lang                          : en-US
UseSharedProcess              : false
Architecture                  : 64
MaxIdleTimeoutms              : 43200000
Capability                    : {Shell}
Permission                    : BUILTIN\Administrators AccessAllowed

Nano ServerにPowerShell 6.0を一発でインストールする

私は以前からNano Serverへのインストールを試していたので、上記の手順を一発で行うスクリプトを作っていました。
スクリプトはGistに登録しています。

gist.github.com

このスクリプトではZipファイルとInstall-PowerShellRemoting.ps1をダウンロードしインストールを実行します。
ダウンロードは自前でやっているのでInvoke-WebRequestが無い環境でも動作します。

リモートセッションからこのスクリプトをコピペして実行すればよしなやってくれるはずです。
コピペしやすいようにスクリプトをBASE64エンコードしたバージョンも用意しあります。

最後に

とりあえずこんな感じです。
いずれは公式に一発インストールできるインストーラーが出るとは思います。