しばたテックブログ

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

VagrantのWinSSH Communicatorを試してみた

www.vagrantup.com

Vagrant 1.9.4からWindowsゲストに対してWindowsにポートされたWin32-OpenSSHを使いSSHで通信を行うWinSSH Communicatorが導入されており*1、先日この機能を知り気になったので試してみました。

WinSSH Communicatorは利用者が全然いないのかドキュメントがあまり整備されておらず本エントリの内容もかなりてさぐりな感じとなっています。

検証環境について

今回は以下の環境で検証しました。

ホスト

  • 64bit版 Windows 10 Pro (1703)
  • Vagrant 2.0.1
  • VirtualBox 5.2.6
  • OpenSSH Client 0.0.24.0

ゲスト

  • Windows Server 2016 (GUIあり)
    • OSインストール直後の状態に最新のWindows Updateを適用
  • OpenSSH Server 0.0.24.0

Win32-OpenSSH Serverのインストール

WinSSH CommunicatorではゲストのWindowsにWin32-OpenSSHをインストールしてsshdを動作させておく必要があります。

インストール手順

基本的に公式サイトの手順をそのまま実行するだけです。

github.com

本エントリでは最新のVer.0.0.24.0を使用します。
以降の作業は要管理者権限です。

# 要管理者権限
# OpenSSHのダウンロードと展開
# C:\Program Files\配下に展開しています
Invoke-WebRequest -Uri "https://github.com/PowerShell/Win32-OpenSSH/releases/download/0.0.24.0/OpenSSH-Win64.zip" -OutFile "OpenSSH-Win64.zip"
Expand-Archive -Path ".\OpenSSH-Win64.zip" -DestinationPath "$env:ProgramFiles"

# Pathの追加
[Environment]::SetEnvironmentVariable('PATH', [Environment]::GetEnvironmentVariable('PATH') + ";$(Join-Path $env:ProgramFiles "OpenSSH-Win64")")

# sshdのセットアップ
# カレントディレクトリを移動しておかないと ssh-keygen で作られるキーの場所が不正になる
cd (Join-Path $env:ProgramFiles "OpenSSH-Win64")
.\install-sshd.ps1

# ホストキーの作成とアクセス権の更新
.\ssh-keygen.exe -A
.\FixHostFilePermissions.ps1 -Confirm:$false

# Firewallを設定しポートを開けておく
New-NetFirewallRule -Name sshd -DisplayName 'OpenSSH Server (sshd)' -Service sshd -Enabled True -Direction Inbound -Protocol TCP -Action Allow

続けて鍵認証を許可するためにsshd_configの以下のコメントを解除します。

#RSAAuthentication yes
#PubkeyAuthentication yes

↓ コメント解除

RSAAuthentication yes
PubkeyAuthentication yes

PowerShellからだと以下の様にして置換できます。

# sshd_configを更新し、鍵認証を許可する
cd (Join-Path $env:ProgramFiles "OpenSSH-Win64")
(Get-Content .\sshd_config -Encoding utf8) -replace '#RSAAuthentication yes','RSAAuthentication yes' -replace '#PubkeyAuthentication yes','PubkeyAuthentication yes' `
  | Out-String `
  | % { [Text.Encoding]::UTF8.GetBytes($_) } `
  | Set-Content -Path .\sshd_config -Encoding Byte

また、OpenSSHで接続した際のデフォルトシェルはコマンドプロンプトなのですが、レジストリ設定で変更することが可能です。
本エントリでは以下のコマンドを実行してPowerShellに変えておきます。

# OpenSSHのデフォルトシェルをPowerShellに変更
$RegPath = "HKLM:\SOFTWARE\OpenSSH"
If ( !(Test-Path $RegPath -PathType Container) ) {
    New-Item $RegPath
}
Set-ItemProperty $RegPath -Name DefaultShell -Type String -value "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe"

最後にsshdサービスの設定を変更し起動します。

Set-Service sshd -StartupType Automatic
Set-Service ssh-agent -StartupType Automatic
Start-Service sshd

これでOpenSSH Serverの設定は完了です。

Vagrant Boxの設定

WinSSH Communicatorを使う際のVagrant Boxの設定については残念ながらドキュメント化されていません。

基本的にはWinRM Communicatorを使う際の手順にSSHで接続するための設定を追加しておけば良いかと思います。
以前に書いたこちらのエントリを参考にしてください。

blog.shibata.tech

本エントリでは、上記エントリをベースにしつつできるだけ最小限の設定にできないか試し、以降の手順で動作させることができました。

1. WinRMの有効化

WinSSH CommunicatorではWinRMを使わないのでWinRMの設定は不要かと思っていたのですが、Vagrantのネットワーク設定にWinRMのバージョンチェックがあり、Communicatorの設定に関わらずこの処理が呼ばれているためWinRMを有効にしていないとvagrant up時に異常終了してしまいます。

今後この挙動は改善されるかもしれませんが現状WinSSH Communicatorを使う際もWinRMを有効にしておく必要があります。

PowerShellから以下のコマンドを実行しておいてください。

# 要管理者権限
winrm quickconfig -q
winrm set winrm/config/winrs '@{MaxMemoryPerShellMB="512"}'
winrm set winrm/config '@{MaxTimeoutms="1800000"}'
winrm set winrm/config/service '@{AllowUnencrypted="true"}'
winrm set winrm/config/service/auth '@{Basic="true"}'
sc.exe config WinRM start= auto

また、Vagrantと直接関連しないのですが、Windows Server 2012 R2以降であればSet-WSManQuickConfigを実行しておいた方が良いでしょう。

# Windows Server 2012 R2以降
Set-WSManQuickConfig -Force

blogs.technet.microsoft.com

2. シャットダウンイベントの追跡ツールの無効化(Server Core以外)

vagrant haltコマンド実行時にシャットダウンの問い合わせを出さない様にするためにシャットダウンイベントの追跡ツールの無効化を行います。

# このコマンドからシャットダウンイベントの追跡ツールを無効化した場合、ローカルグループポリシーエディタ上に反映されません。

# デフォルト状態ではReliabilityキーは存在していません。
$RegPath = "HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\Reliability"
If ( ! (Test-Path $RegPath -PathType Container) ) {
    New-Item $RegPath
}
Set-ItemProperty $RegPath -name ShutdownReasonOn -Type DWord -value 0
Set-ItemProperty $RegPath -name ShutdownReasonUI -Type DWord -value 0

3. サーバーマネージャがログオン時に表示されないようにする(Server Core以外)

サーバーマネージャがログオン時に表示されないようにするため、以下の手順で現在ログオンしているユーザーとDefaultユーザーのレジストリ設定を変更しておきます。

# 現在ログオンしているユーザーと`Default`ユーザーの設定を更新します。
# この更新により新しくユーザープロファイルが作られる際にサーバーマネージャーを自動的に表示しない様にしています。

# Change Current User Setting
$RegPath = "HKCU:\SOFTWARE\Microsoft\ServerManager"
If ( Test-Path $RegPath -PathType Container ) {
    Set-ItemProperty $RegPath -name DoNotOpenServerManagerAtLogon -Type DWord -value 1
}

# Change 'Default' User Setting
$DefaultRegFile = Join-Path (Split-Path $env:USERPROFILE -Parent) 'default\NTUSER.dat'
try {
    reg load HKLM\DefaultUser "$DefaultRegFile"
    $RegPath = "HKLM:\DefaultUser\SOFTWARE\Microsoft\ServerManager"
    If ( Test-Path $RegPath -PathType Container ) {
        Set-ItemProperty $RegPath -name DoNotOpenServerManagerAtLogon -Type DWord -value 1
    }
} finally {
    reg unload HKLM\DefaultUser
}

4. パスワードの複雑性の無効化

次の手順で作るvagrantユーザーに対して単純なパスワードを設定するためにパスワードの複雑性を無効化します。 PowerShellから以下のコマンドを実行してください。

$TempCfgFile = ".\_secpol_{0}.inf" -F [System.IO.Path]::GetRandomFileName()
# Export temp file
secedit /export /cfg $TempCfgFile
# Disable PasswordComplexity and Change password age.
( Get-Content $TempCfgFile -Encoding Unicode ) -replace 'PasswordComplexity = 1','PasswordComplexity = 0' -replace 'MaximumPasswordAge = 42','MaximumPasswordAge = -1' | Out-File $TempCfgFile
# Update security policy
secedit /configure /db $env:windir\security\database\secedit-new.sdb /cfg $TempCfgFile /areas SECURITYPOLICY
# Delete temp file
If( Test-Path -Path $TempCfgFile -PathType Leaf ) {
    Remove-Item -Path $TempCfgFile
}

ちなみにWindows Server 2016であれば上記の代わりにBackup-SecurityPolicyRestore-SecurityPolicyコマンドレットを使うことも可能です。

#
# Windows Server 2016以降であれば以下の様にしても良い。
#
$TempCfgFile = ".\_secpol_{0}.inf" -F [System.IO.Path]::GetRandomFileName()
# Export temp file
Backup-SecurityPolicy $TempCfgFile
# Disable PasswordComplexity and Change password age.
( Get-Content $TempCfgFile -Encoding Unicode ) -replace 'PasswordComplexity = 1','PasswordComplexity = 0' -replace 'MaximumPasswordAge = 42','MaximumPasswordAge = -1' | Out-File $TempCfgFile
# Restore security policy
Restore-SecurityPolicy -Path (Resolve-Path $TempCfgFile)
# Delete temp file
If( Test-Path -Path $TempCfgFile -PathType Leaf ) {
    Remove-Item -Path $TempCfgFile
}

5. Vagrantユーザーの追加

ローカルユーザーにVagrantユーザーを追加し、Administratorsグループに参加させます。
ユーザーのパスワードは"vagrant"にしています。

ADSIを使う場合は以下の手順となります。

# Create Vagrant User
$Computer = [ADSI]"WinNT://$Env:COMPUTERNAME,Computer"
$NewUser = $Computer.Create("user","vagrant")
$NewUser.SetPassword("vagrant")
$NewUser.SetInfo()
$NewUser.FullName = "Vagrant"
$NewUser.UserFlags = 65536 # ADS_UF_DONT_EXPIRE_PASSWD
$NewUser.SetInfo()
# Join Administrators Group
$AdminGroup = [ADSI]"WinNT://$Env:COMPUTERNAME/Administrators,group"
$AdminGroup.Add($NewUser.Path)

Windows Server 2016であれば上記の代わりにNew-LocalUserAdd-LocalGroupMemberコマンドレットを使うことも可能です。

#
# Windows Server 2016以降であれば以下の様にしても良い。
#
New-LocalUser -Name "vagrant" -Password (ConvertTo-SecureString "vagrant" -AsPlainText -Force) -AccountNeverExpires -PasswordNeverExpires
Add-LocalGroupMember -Member "vagrant" -Group "Users"
Add-LocalGroupMember -Member "vagrant" -Group "Administrators"

6. Vagrantユーザーの公開鍵配置

この手順はWinSSH Communicatorに特有のものです。

VagrantがゲストVMに初回接続する際に必要な鍵(insecure_key)をVagrantユーザーの~\.sshディレクトリに配置しておきます。

この処理を行うためにはユーザープロファイルが出来ている必要があるため、前項の手順でVagrantユーザーを作った後にVagrantユーザーでログインして行ってください。

# Vagrantユーザーでログインして行う前提

# ~\.sshディレクトリの作成
if ( -not (Test-Path "~\.ssh" -PathType Container)) {
    mkdir "~\.ssh"
}
# insecure_key の配置
Invoke-WebRequest -Uri "https://raw.github.com/mitchellh/vagrant/master/keys/vagrant.pub" -OutFile "~\.ssh\authorized_keys"
# キーのアクセス権を設定
$acl = Get-Acl "~\.ssh\authorized_keys"
$ar = New-Object System.Security.AccessControl.FileSystemAccessRule("NT Service\sshd", "Read", "Allow")
$acl.SetAccessRule($ar)
Set-Acl "~\.ssh\authorized_keys" $acl

ちなみに、このinsecure_keyconfig.ssh.insert_key = trueと設定されていれば初回接続後に別の新しい鍵に差し替えられる様になっています。

Boxファイルの作成と登録

Boxファイルの作成と登録についてはこちらのエントリを参照してください。

blog.shibata.tech

Vagrantfile設定例

WinSSH Communicatorを使う際はVagrantfileのCommunicatorを

config.vm.communicator = "winssh"

の様にwinsshと指定するだけでOKです。
SSHに関する設定はSSH Communicatorと共用されており、そのほかの設定についてはWinRM Communicatorの場合と同様です。

以下に簡単な設定例を挙げておきます。

# -*- mode: ruby -*-
# vi: set ft=ruby :

# All Vagrant configuration is done below. The "2" in Vagrant.configure
# configures the configuration version (we support older styles for
# backwards compatibility). Please don't change it unless you know what
# you're doing.
Vagrant.configure("2") do |config|

  config.vm.box = "Win2016SSHBox"
  config.vm.guest = "windows"

  # WinSSH Communicatorを使う
  config.vm.communicator = "winssh"
  
  # VMの設定は適当に
  config.vm.provider "virtualbox" do |vb|
    vb.gui = true
    vb.memory = "4096"
    vb.customize ["modifyvm", :id, "--cpus", "2"]
    vb.customize ["modifyvm", :id, "--paravirtprovider", "hyperv"]
  end
end

実行例

ここまで設定できればあとはvagrant upでゲストVMが立ち上がり良しなに設定がなされるはずです。

f:id:stknohg:20180119153233p:plain

vagrant sshコマンドでゲストに接続することが可能です。

f:id:stknohg:20180119153250p:plain

ちなみに、上手く動作しない場合は--debugオプションをつけて実行し、デバッグログを読んで気合で対処してください。

注意事項

ざっとWinSSH Communicatorについて説明してきましたがいくつか注意事項があります。

vagrant ssh -cコマンドが正しく動作しません

vagrant sshコマンドには-c [実行したいコマンド]をつけることでコマンドの単体実行が可能です。

ただ、このオプションの実装が、

[config.ssh.shellで設定されるシェル] -c [実行したいコマンド]

となっており、config.ssh.shellのデフォルトはbash -lである点、-cがハードコーディングされている点からWindowsゲストに対しては実質使えない*2ものとなっています。

一応、

config.ssh.shell = "powershell"

とすれば上手くいきそうなのですが、私の環境ではコンソールの描画が上手くいかずコマンドが成功しているのか判別できませんでした。

これは明らかに実装の考慮漏れなのでいずれ改善されるとは思います。
(気になるひとはIssue上げてください...)

Windows 10 Fall Creators Updateに組み込まれているOpenSSHを使う場合

本エントリを書くにあたり、事前にWindows 10 Fall Creators Update(1709)に組み込まれているOpenSSH Serverの機能を使った検証を行ったのですが、OSに組み込まれているOpenSSH Serverは現状ホストキーがed25519鍵しか対応しておらず、そのためかVagrantで上手く操作できませんでした。
根本的な原因を突き止めることはできませんでした...

github.com

このOpenSSH Serverの問題は今後のリリースで解消される見込みですがVagrant BoxにWindows 10を使う際はご注意ください。

*1:通常Windowsゲストに対してはWinRMで通信します。

*2:WLSがある環境ならワンチャンあるかも...

PowerShell 6.0がリリースされました

既に日本語情報も出回っていますが、2018/1/10(PST)*1にPowerShell 6.0が正式リリースされました。

f:id:stknohg:20180115003255p:plain

公式情報は以下になります。

blogs.msdn.microsoft.com

2016年にPowerShellがオープンソースになりPowerShell 6.0のアルファ版がリリースされてから約1年半経ってのリリースとなりました。
ここ最近のPowerShellの変化についていろいろと思うところはあるのですが、それはひとまず置いておいてこのリリースを祝いたいと思います。

本エントリでは先のPowerShell Team Blogの内容をベースにPowerShell 6.0の新機能などについて触れていきます。

PowerShell 6.0のインストール

PowerShell 6.0は.NET Coreを基盤としたクロスプラットフォームなアプリケーションになりました。
WindowsだけでなくLinuxやMacにもインストール可能となり、

  • Windows 7, 8.1, and 10
  • Windows Server 2008 R2, 2012 R2, 2016
  • Windows Server Semi-Annual Channel
  • Ubuntu 14.04, 16.04, and 17.04
  • Debian 8.7+, and 9
  • CentOS 7
  • Red Hat Enterprise Linux 7
  • OpenSUSE 42.2
  • Fedora 25, 26
  • macOS 10.12+

といったプラットフォームをサポートしています。
また、まだ公式なサポートはしていませんが、

  • Arch Linux
  • Kali Linux
  • AppImage (works on multiple Linux platforms)
  • Windows on ARM32/ARM64
  • Raspbian (Stretch)

でも動作させることが可能です。

インストール方法についてはこちらから各プラットフォーム毎のインストーラーを入手することができます。

WindowsではMSIインストーラーからのインストール、LinuxではYumやApt、MacではHomebrew Caskといったパッケージ管理ツールからのインストールも可能です。

blog.shibata.tech

blog.shibata.tech

blog.shibata.tech

PowerShellのエディションと下位互換について

blog.shibata.tech

以前にも説明しましたが、PowerShellは従来のWindows PowerShellと.NET CoreをベースとしたPowerShell Coreに分類され、PowerShell 6.0はPowerShell Coreのみのリリースとなります。

Windows PowerShell

  • PowerShell 1.0~5.0、およびDesktop EdtionのPowerShell 5.1
  • Windowsの.NET Framework上で動作するバージョン
  • PowerShell 5.1では $PSVersionTable.PSEdition = 'Desktop'となる

PowerShell Core

  • Nano Server向けのPowerShell 5.1、およびPowerShell 6.0
  • (Windowsを含め)プラットフォームを問わず.NET Core上で動作するバージョン
  • $PSVersionTable.PSEdition = 'Core'となる

f:id:stknohg:20170719234440p:plain

バージョン番号は連続していますがアプリケーション基盤が異なるためPowerShell 6.0はこれまでのPowerShellとは実質別物です。

基盤となる.NET Core自体が.NET Frameworkのサブセットということもあり、できるだけ互換性を維持する様にされているものの、これまでのWindows PowerShellに対して多くの点で互換性の不足、破壊的変更がなされれています。

たとえばPowerShell 6.0では以下の機能が削除されました。

  • PowerShell Workflows
  • PowerShell Snap-ins
  • WMIv1 Cmdlets (Get-WmiObject, Invoke-WmiMethod, etc.) : 代わりにCIM Cmdlets(Get-CimInstance, Invoke-CimMethod, etc.)を使います
  • DSCリソースの実行基盤 : 代わりにDSC Coreがリリースされる予定です

そして、PowerShell 6.0における破壊的変更については以下にまとめられています。

* https://github.com/PowerShell/PowerShell/blob/master/docs/BREAKINGCHANGES.md

【2018/02/11追記】

破壊的変更についてまとめました。

blog.shibata.tech

【追記ここまで】

今後の方針としてPowerShell CoreでWindows PowerShellを置き換えていきたい展望はある様ですが、現時点ではとてもその水準には達していないのが率直なところです。

このためWindows環境においてはWindows PoweShell + PowerShell Coreと併用して運用し、少しずつPowerShell Coreへのシフトを図っていくのが良いでしょう。
(個人的にはクロスプラットフォーム化を意識する必要がないのであれば いまのところは 無理にPowerShell Coreに手を出さなくても良いと思っています。ただWindows PowerShellは今後大きな変更はなされないため先を見据えておくこと自体は必要でしょう。)

PowerShell 6.0の新機能について

PowerShell 6.0の新機能については以下にまとめられています。
(量が多いので近いうちに別エントリでまとめたいですね...まとめました。)

【2018/02/09追記】

新機能についてまとめました。

blog.shibata.tech

【追記ここまで】

本ブログでもその一部についてエントリを起こしているので参考にしてください。

PowerShell Coreのサポートサイクルについて

PowerShell CoreのサポートはMicrosoft Modern Lifecycle Policyに準じる様になり、基本的には、

  • 従来の有償サポートを受けるには最新版のプログラムを使用しておくこと
  • コミュニティサポートはGitHubで行う(なお、Windows PowerShellについては従来通りUserVoiceを使う)
  • PowerShell 6.xは約半年毎に更新され新しいバージョン(6.1、6.2...)をリリースする予定

といった方針になるそうです。

細かい話はPowerShell Core Support Lifecycleをご覧ください。

Windows PowerShellのサポートサイクルについて

【2018/01/16追記】

Windows PowerShellは今後大きな機能追加や優先度の低い不具合の修正は行われませんがサポート自体はOSのサポートと共に引き続きます。
(つまりOSのサポート終了までWindows PowerShellはサポートされます)

ただし、PowerShell 2.0の利用はすでに非推奨となっています ので最新のPowerShell 5.1に更新しておくのが良いでしょう。

blogs.msdn.microsoft.com

最後に

まだまだお伝えしなければならないことは多いのですが1エントリでまとめるには流石に厳しいので本エントリはこの辺にしておきます。

これからも新しく生まれ変わったPowerShellの情報をできる限りお伝えしていきたいと思います。

*1:日本時刻だと2018/1/11

Windows 7にPowerShell 6.0をインストールする - 再び

blog.shibata.tech

の続きです。

前回はPowerShell 6.0アルファ版で試しましたが、今回はGAリリース直前のRC2で試しています。

基本的な手順は前回と変わらないのですが、前提条件が若干変わったため、その点を補足するかたちで本エントリを書きます。

前提条件

Windows 7にPowerShell 6.0をインストールするための前提条件は以下となります。

  1. SP1が適用されていること
  2. Universal C Runtimeがインストールされていること
  3. KB2533623が適用されていること
  4. WMF 4.0 ~ 5.1がインストールされていること

SP1の適用について

前回はSP1の適用について明記されていませんでしたが、現在は公式のインストール手順

To install PowerShell on Windows Full SKU (works on Windows 7 SP1 and later), download either the MSI from AppVeyor for a nightly build, or a released package from our GitHub releases page. The MSI file looks like this - PowerShell-6.0.0..<os-arch>.msi

と Windows 7 SP1以降であることが明記されています。

この点に関しては、前回の時点でSP1未適用のWindows 7はすでにサポート切れであったため単純に記載していなかっただけの様です。

Universal C Runtimeのインストールについて

前回はVisual Studio 2015 の Visual C++ 再頒布可能パッケージのインストールが要求されていましたが、これがUniversal C Runtimeに変更されています。

現在はインストーラーでUniversal C Runtimeが必要かを判断し、必要とされる場合は下図の様に警告が表示されてインストールが中断されます。

f:id:stknohg:20171227174300p:plain

リンク先からZipファイルをダウンロードし、該当する.msuファイルを適用してください。

  • Windows 7 SP1(32Bit版) : Windows6.1-KB3118401-x86.msu
  • Windows 7 SP1(64Bit版) : Windows6.1-KB3118401-x64.msu

なお、Universal C RuntimeのインストールにはSP1が適用されている必要があります。

KB2533623の適用について

.NET Coreの利用に必要な事前条件としてKB2533623の適用が必要です。

こちらは前回から変わっていません。

WMF 4.0 ~ 5.1のインストールについて

前回とは異なりWMF 4.0 ~ 5.1の事前インストールが必要となりました。
こちらのPull Requestにその理由が記載されており、

github.com

On Win7, WMF 4.0 or higher version needs to be installed so that the WinRM can support the side-by-side remoting plugin. So I make the WMF 4.0 a prerequisite too.

とPowerShell Remotingを有効にするために必要になったそうです。

こちらもインストーラーでPowerShell Remoting Plugin(pwrshplugin.dll)のインストールを判断し、WMF 4.0以降がインストールされていないと判断された場合は警告が表示されてインストールが中断されます。

f:id:stknohg:20171227174340p:plain

特に制限が無いのであればWMF 5.1をインストールすれば良いでしょう。
手順は以下のエントリを参考にしてください。

blog.shibata.tech


ちなみに、あまりお勧めできない裏技として、PowerShell 6.0をZipファイルからインストールすればWMF 4.0 ~ 5.1がインストールされていない環境でも動作させることは可能です。
ただし、PowerShell Remotingは使えませんし、予期せぬエラーが起きても自己責任でお願いします。

f:id:stknohg:20171227174419p:plain

(右がZipファイルをダウンロードして動かしたpwsh.exeです。)

WMF 4.0以降をインストールできない事情のある環境で役に立つこともある...やもしれません。

インストール手順

事前条件をクリアしていれば、インストールはMSIインストーラーの指示に従うだけでOKです。

前項で触れた様にZipファイルからインストールしても構いません。

細かい説明はしませんがMSIインストーラーのスクリーンショットだけ貼っておきます。


f:id:stknohg:20171227174447p:plain


f:id:stknohg:20171227174504p:plain


f:id:stknohg:20171227174520p:plain


f:id:stknohg:20171227174532p:plain


f:id:stknohg:20171227174546p:plain


f:id:stknohg:20171227174559p:plain


これで無事PowerShell 6.0を起動することができます。

f:id:stknohg:20171227174622p:plain