見出し画像

PowerShellに独自コマンドレットを定義する【再】

この記事は過去記事の再エントリーになります。


PowerShellに独自コマンドレットを定義する

 PowerShellは起動時にプロファイルを読み込むようになっています。 このプロファイルの中で関数定義を行うことでPowerShellに独自コマンドレットを追加することができます。
プロファイルのパスは$PROFILEに格納されています。

PS C:\> $profile
C:\Users\GodaGo\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1


この「Microsoft.PowerShell_profile.ps1」の中を編集すれば独自コマンドレットを追加できます。

確か前回の記事では
Function test1 {
    write-host "こんにちわコルタナです"
}
このようなコードを追加してみました。
これだとサンプルとしてあんまりのなので
もう少し使えるサンプルでこのプロファイル機能を紹介したいと思います。


プロファイルの作成

 まず$PROFILEが示すファイルは存在しない可能性があるのでNew-Itemコマンドレットを使って生成しておく必要があります。
つぎのコードで作成します。

if(-not(test-path $profile)){
    New-Item -Path $profile -ItemType file -Force
}


実行ポリシーの緩和

 このプロファイルを作成した後に新しくPowerShellを開こうとすると実行ポリシーのセキュリティエラーが発生する場合があります。
これはps1ファイルの実行が許可されていないからです。


. : このシステムではスクリプトの実行が無効になっているため、ファイル C:\Users\GodaGo\Documents\WindowsPowerShell\Mi
crosoft.PowerShell_profile.ps1 を読み込むことができません。詳細については、「about_Execution_Policies」(https://go.micr
osoft.com/fwlink/?LinkID=135170) を参照してください。
発生場所 行:1 文字:3
+ . 'C:\Users\GodaGo\Documents\WindowsPowerShell\Microsoft.PowerShe ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 + CategoryInfo : セキュリティ エラー: (: ) []、PSSecurityException
 + FullyQualifiedErrorId : UnauthorizedAccess

もし上のようなエラーが出たら次のようにSet-ExecutionPolicyコマンドレットを実行します。エラーが無かったら実行は不要。

Set-ExecutionPolicy RemoteSigned -scope CurrentUser -force

 ここで指定しているRemoteSignedポリシーは、署名付きスクリプトかローカルコンピューター上のスクリプトの実行を許可するポリシーです。
セキュリティとかあんまり気にしないんだったら
「Set-ExecutionPolicy RemoteSigned -force」のコマンドでもいいです。

プロファイルの設定例

 次の記事を参考にMicrosoft.PowerShell_profile.ps1を編集します。

エディタでMicrosoft.PowerShell_profile.ps1を開いて次のコードを張り付けます。文字コードをSJISかUFT8 BOM付きで保存します。普通のUTF8で保存すると文字化けします。


function minesweeper(){
	$masu_size = 8 #マスの大きさ
	$boom_cnt = 8 #爆弾の数
	$unopened_cnt = $masu_size*$masu_size #未開封の数
	$boom_char = '*' #爆弾の文字
	$unopened_char = '+' #開いていないマスの文字
	$turn = 0 #ターン数


	#####
	# マスの作成

	#爆弾マス
	$masu_boom = New-Object "System.Object[,]"$masu_size,$masu_size
	#表示用マス
	$masu_disp = New-Object "System.Object[,]"$masu_size,$masu_size

	#表示用マス 未開封マーク
	for($i=0;$i -lt $masu_size;$i++){
		for($j=0;$j -lt $masu_size;$j++){
			$masu_boom[$i,$j] = " "
			$masu_disp[$i,$j] = $unopened_char
		}
	}

	#爆弾を置く処理
	for($i=0;$i -lt $boom_cnt;$i++){
		$x = Get-Random -Maximum $masu_size -Minimum 0
		$y = Get-Random -Maximum $masu_size -Minimum 0
		#同じ場所に置かない処理
		if($masu_boom[$y,$x] -eq $boom_char){
			$i--  #同じ場所に爆弾を置くときは再度処理するためにループカウンタを減らす
		} else {
			$masu_boom[$y,$x] = $boom_char
		}
	}

	#周りの爆弾の数を数え、マスに書き込む処理
	$dx=@(-1,-1, 0, 1, 1, 1, 0,-1)
	$dy=@(0 ,-1,-1,-1, 0, 1, 1, 1)
	for($i=0;$i -lt $masu_size;$i++){
	  for($j=0;$j -lt $masu_size;$j++){
		if($masu_boom[$i,$j] -ne $boom_char){
			$cnt=0
			for($k=0;$k -lt 8;$k++){
				if( ($($i+$dy[$k]) -ge 0) -and ($($i+$dy[$k]) -lt $masu_size) -and ($($j+$dx[$k]) -ge 0) -and ($($j+$dx[$k]) -lt $masu_size)){
					if($masu_boom[$($i+$dy[$k]),$($j+$dx[$k])] -eq $boom_char){
						$cnt+=1
					}
				}
			}
			if($cnt -ne 0) { # 0個の場合は書き込まない
				$masu_boom[$i,$j]=$cnt
			}
		}
	  }
	}

	# マスの表示関数
	function disp-masu($masu,$size){

		$disp_tmp="  ABCDEFGH"

		write-host " "
		write-host $disp_tmp

		for($i=0;$i -lt $size;$i++){
			write-host " $($i+1)" -NoNewline
			for($j=0;$j -lt $size;$j++){
				if($masu[$i,$j] -eq $boom_char){
					write-host  $masu[$i,$j] -NoNewline
				} elseif($masu[$i,$j] -eq $unopened_char) {
					write-host  $masu[$i,$j] -NoNewline -BackgroundColor DarkGray 
				} elseif($masu[$i,$j] -eq '1') {
					write-host  $masu[$i,$j] -NoNewline -ForegroundColor Blue 
				} elseif($masu[$i,$j] -eq '2') {
					write-host  $masu[$i,$j] -NoNewline -ForegroundColor DarkGreen 
				} elseif($masu[$i,$j] -eq '3' -or $masu[$i,$j] -eq '4' -or $masu[$i,$j] -eq '5' -or $masu[$i,$j] -eq '6' -or $masu[$i,$j] -eq '7' -or $masu[$i,$j] -eq '8' ) {
					write-host  $masu[$i,$j] -NoNewline -ForegroundColor red 
				} else {
					write-host  $masu[$i,$j] -NoNewline
				}
			}
   			write-host ""

		}
	}

	# 未開封のカウント関数
	function cnt-unopened($masu,$size){
		$cnt=0
		for($i=0;$i -lt $size;$i++){
			for($j=0;$j -lt $size;$j++){
				if($masu[$i,$j] -eq $unopened_char){
					$cnt+=1
				}
			}
		}
		return $cnt
	}

	#disp-masu $masu_boom $masu_size


	#####
	# 解答の入力

	#未開封の数
	$unopened_cnt = (cnt-unopened $masu_disp $masu_size)

	#タイマーセット
	$start_time = Get-Date
	$flg_loop=$True
	while($flg_loop){
		$turn+=1
		disp-masu $masu_disp $masu_size
		write-host "残り爆弾数 $boom_cnt"
		write-host "未開封の数 $unopened_cnt"
		$Input_x = '?'
		while( ($Input_x.Length -ne 1) -or ([Byte][Char]($Input_x) -lt 65) -or ([Byte][Char]($Input_x) -gt 72)){
			$Input_x = Read-Host "調べる座標 横位置(A~H)"
		}
		$Input_y = -1
		while( ($Input_y -lt 1) -or ($Input_y -gt $masu_size)  ){
			$Input_y = Read-Host "調べる座標 縦位置(1~$masu_size)"
		}
		write-host "入力されたのは 横 $Input_x 縦 $Input_y"
		write-host ""

		#入力補正
		$x = [Byte][Char]($Input_x) - 65
		$y = $Input_y - 1

		$flg_out = $False

		if($masu_boom[$y,$x] -eq $boom_char){
			#爆弾
			$flg_loop = $False
		} else {
			#周りの表示
			$search_que=@()
			$search_que+=,($y,$x)
			while($search_que.length -ne 0){
				$y = $search_que[0][0];
				$x = $search_que[0][1];
				$search_que = $search_que[1..($search_que.length)] #キューの先頭を削除
				$masu_disp[$y,$x] = $masu_boom[$y,$x]

				for($k=0;$k -lt 8;$k++){
					if( ($($y+$dy[$k]) -ge 0) -and ($($y+$dy[$k]) -lt $masu_size) -and ($($x+$dx[$k]) -ge 0) -and ($($x+$dx[$k]) -lt $masu_size)){
						#未開封マス
						if($masu_disp[$($y+$dy[$k]),$($x+$dx[$k])] -eq $unopened_char){
							#爆弾発見判定
							if($masu_boom[$($y+$dy[$k]),$($x+$dx[$k])] -eq $boom_char){
								$boom_cnt-=1
							}
							#空白発見判定 検索キューに加える
							if($masu_boom[$($y+$dy[$k]),$($x+$dx[$k])] -eq ' '){
								$search_que+= ,($($y+$dy[$k]),$($x+$dx[$k]))
							}
							#マスを開く
							$masu_disp[$($y+$dy[$k]),$($x+$dx[$k])] = $masu_boom[$($y+$dy[$k]),$($x+$dx[$k])]
						}
					}
				}
			}

			$unopened_cnt = (cnt-unopened $masu_disp $masu_size)
			if(($boom_cnt -eq 0) -or ($unopened_cnt -eq $boom_cnt)){
				$flg_loop = $False
			}
		}
	}


	if(($boom_cnt -eq 0) -or ($unopened_cnt -eq $boom_cnt)){
		write-host "★★★爆弾を全て発見しました★★★"
	} else {
		write-host "☆☆☆爆弾に当たってしまいました☆☆☆"
	}
	write-host "調べた数:$turn"
	$rap_time=(Get-Date) - $start_time
	write-host "掛かった時間(時:分:秒):$rap_time"

	disp-masu $masu_boom $masu_size
}


Microsoft.PowerShell_profile.ps1を保存した後、
新しくPowerShellを開き、コマンドレット「minesweeper」を実行します。



これでいつでもminesweeperが遊べます。

下のリンクを使えば
「間違い探し」や「10秒でSTOPするゲーム」も追加できます。



#PowerShell #コマンドレット #プロファイル #独自コマンドレット #マインスイーパー #プログラミング初心者 #プログラミング学習




この記事が気に入ったらサポートをしてみませんか?