Write-Host で表示されるメッセージに色をつける
なんとなく検索していたら面白いもの見つけたのでメモメモ。
Write-Hostで表示されるメッセージに色つけれるみたい!
Write-Host "コメント" -foregroundcolor red -backgroundcolor yellow
ってことで、各サーバのCドライブの利用状況を色別けして表示させてみるスクリプトとか作ってみた。
# 本体 function MyFunction { $serverlist = @("192.168.1.1"; "192.168.1.2"; "192.168.1.3") #サーバリストの分だけループ foreach ($ipaddress in $serverlist) { Write-Host "`n" Write-Host "★☆★-----------------【" $ipaddress "】-----------------★☆★" -foregroundcolor red -backgroundcolor yellow #実行 #Cドライブの使用状況を表示する CheckDiskSize #Read-Host "実行結果を確認して、エンターを押してください!" } }
function CheckDiskSize { Write-Host "■□■ Cドライブの使用状況を表示します。 ■□■" #Session作成 $Session = New-PSSession -ComputerName $ipaddress #コマンド実行 Invoke-Command -Session $Session -Scriptblock{ $drive = $args[0] #ドライブの容量チエック $used = (Get-PSDrive $drive).Used / 1GB $free = (Get-PSDrive $drive).Free / 1GB #使用率(四捨五入) $rate = [math]::Truncate((($used / ($free + $used)) * 100)+.5) #メッセージ作成 $Message = $scriptName + "`n" + "`n" + $drive + "ドライブの使用量:" + ([math]::Truncate($used)+.5) + "GB" + "`n" + $drive + "ドライブの空き容量:" + ([math]::Truncate($free)+.5) + "GB" + "`n" + $drive + "ドライブの使用率:" + $rate + "%" #使用率が70%以上で80%未満だったら黄色で表示 if ($rate -gt "70" -and $rate -le "80") { Write-Host $Message -foregroundcolor Yellow } #使用率が80%以上だったら赤字で表示 elseif ($rate -gt "80") { Write-Host $Message -foregroundcolor Red } #それ以外はセーフ else { Write-Host $Message -foregroundcolor Green } } -ArgumentList "C" #Session削除 Remove-PSSession $Session } }
WinRMでリストの端末に対して実行していってます。
中身読めば解りますけど、使用率に応じて色を変えて表示してます。
表示結果はこんな感じ。
(IPの部分はちょっと隠してますゴメンナサイ)
手動でさっと確認したいときには良い感じかも。
そろそろ転職活動
したいと思っているので、とりあえず現場で書き溜めたPowerShellを忘れないようにアップしまくりたいと思います。来週から。
完全に備忘録です。
Invoke-CommandでリモートPCに引数を渡す
備忘録も込めたPowerShellネタです。
PowerShellでリモートPCを操作する時の方法は以下の3つみたい。
- <コマンドレット> -ComputerName
- コマンドを指定のリモートPCに対して実行。
- 主体はコマンドを投げる側。
- 当然だが、「-ComputerName」がそもそも存在しないコマンドも多数。
- Invoke-Command -ComputerName
-scriptblock{Get-Service} - 「-scriptblock{}」をリモートPCで実行。
- 主体はリモートPC側。
- Enter-PSSession -ComputerName
- 対話モード(SSHのログインみたいな感じ)でリモートPCに接続してゴニョゴニョ。
- 主体はリモートPC側。
1で全ての業務が片付けば問題無しだが、まぁそうは問屋がおろさない。
んで、2を使ってリモートPCの操作をスクリプト化するんだけど、スコープがリモートPC側にあるので投げる側の変数がそのまま使用できない。
リモート側に「C:\Windows」は存在するが、
$hostname = "192.168.1.2" Invoke-Command -Computername $hostname -Scriptblock{Test-Path C:\Windows}
True
変数として渡してしまうとエラーとなる。
$hostname = "192.168.1.2" $a = "C:\Windows" Invoke-Command -Computername $hostname -Scriptblock{Test-Path $a}
引数が null であるため、パラメーター 'Path' にバインドできません。 + CategoryInfo : InvalidData: (:) [Test-Path]、ParameterBindingVal idationException + FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,M icrosoft.PowerShell.Commands.TestPathCommand + PSComputerName : 192.168.1.2
さて、どうしましょ。。
ということで、Invoke-Commandのヘルプとにらめっこしてみると。。
あやしいのを発見。
-ArgumentList
さっそく実行。配列で渡るということなので
$hostname = "192.168.1.2" $a = "C:\Windows" $b = "C:\Program Files" Invoke-Command -Computername $hostname -Scriptblock{Test-Path $args[0];Test-Path $args[1]} -ArgumentList $a,$b
True True
とりあえず上記を使用すれば目的は達成できそうです。
(という記事を書いてて見つけたんですが)こちらのような方法でも良いかも。
【PowerShell】Invole-Command –FilePath パラメタの魔法 - フィールドSEあがりの安納です - Site Home - TechNet Blogs
FizzBuzz問題をやってみる
先生に「手始めにお約束のFizzBuzz問題を解いてみるのはどうか|д゚)チラッ」って言われたので、プログラムの定番問題と呼ばれるFizzBuzz問題をやってみる
とりあえずPowerShellでやってみるかーということで書いてみる
# 3で割り切れる場合は 「Fizz」、 # 5で割り切れる場合は 「Buzz」、 # 両者で割り切れる場合は 「Fizz Buzz」 を数の代わりに発言する。 function fizzbuzz ([int]$a){ for ( $i = 1; $i -le $a; $i++){ #3の余剰 $s = $i % 3 #5の余剰 $p = $i % 5 if ( $p -eq 0 -and $s -eq 0 ){ write-host "FizzBuzz" } elseif( $s -eq 0 ) { write-host "Fizz" } elseif( $p -eq 0 ) { write-host "Buzz" } else { write-host $i } } } #実行 fizzbuzz 100
15分位?で書きました。
おー。できたできたー。って喜んでグーグル先生にお問い合わせしたら、世の中の達人プログラマーは60文字以内とかで解いててひっそりと枕を涙で濡らしました。。
Windows PowerShell でイベントログを取得する 2
前回の続き。
参照されて処理を実行するスクリプト、実行スクリプトに引数を渡すスクリプト、サーバの定義が書いてあるxmlに別けて実装。
- 参照されて処理を実行するスクリプト
#================================================== # イベントログ取得スクリプト # 3日前までのイベントログを取得する #================================================== #-------------------------------------------------- #GetEventlog.ps1 # 第1引数:対象端末名 # 第2引数:イベントログ名(Application,System) #-------------------------------------------------- function GetEventlog ([string]$_servername, [string]$_eventlogname) { #変数定義--------------------- $scriptName = "イベントログ取得スクリプト" #XMLファイル $XML = "C:\hogehoge\config\serverlist.xml" #引数 $servername = $_servername $eventlogname = $_eventlogname #期間の設定 $startdate = get-date $enddate = $startdate - (new-timespan -day 3) #ログファイルの出力先 $filetime = get-date -format yyyyMMddhhmmss $file = "C:\temp\" + $servername + "_" + $eventlogname + "_" + $filetime + ".txt" try { #イベントログに開始ログを出力--------------------- Write-EventLog "Application" "PowerShell Script" 0 -Message ($scriptName + "開始" + "`n" + "対象端末名は " + $servername + " です。" + "`n" + "対象イベントログは " + $eventlogname + " です。") -EntryType "Information" #XMLファイル読み込み--------------------- $xmlDoc = [XML](Get-Content $XML) #XMLファイルの子要素を取得 $config = $xmlDoc.get_DocumentElement() $childs = $config.get_ChildNodes() #xmlから値の取り出し #IPアドレス $ipaddress = $config.SelectSingleNode("server[@name='$servername']").ipaddress #イベントログ取得--------------------- $logArray = get-eventlog -computername $ipaddress -logname $eventlogname -after $enddate -before $startdate | Select-Object EntryType,EventID,Source,TimeGenerated,Message #取得したイベントログをファイルに書き込む--------------------- foreach ($row in $logArray){ #Messageに入っている改行コードを変換 $workMessage = [string]$row.Message.Replace("`n"," ") #日付の書式を整形 $workTimeGenerated = [string]$row.TimeGenerated.ToString("yyyy/MM/dd HH:ss:mm") #タブ区切りで一行としてまとめる $line = $workTimeGenerated + "`t" + [string]$row.EntryType + "`t" + [string]$row.EventID + "`t" + [string]$row.Source + "`t" + $workMessage #ファイルに書き込む $line | Out-File -filepath $file -Append } #ファイルの存在チェック--------------------- if (test-path $file) { #イベントログに終了ログを書き込む Write-EventLog "Application" "PowerShell Script" 0 -Message ($scriptName + "`n" + $file + "`n" + "を作成しました。") -EntryType "Information" } else { #イベントログにファイルが無いことを書き込む Write-EventLog "Application" "PowerShell Script" 0 -Message ($scriptName + "`n" + $file + "`n" + "が作成されていません。") -EntryType "Warning" } } catch [exception] { #イベントログに書き込んで終了 Write-EventLog "Application" "PowerShell Script" 1 -Message ($scriptName + "`n" + $error[0]) -EntryType "Error" } finally { #イベントログに終了ログを書き込む Write-EventLog "Application" "PowerShell Script" 0 -Message ($scriptName + "終了" + "`n" + "対象端末名は " + $servername + " です。" + "`n" + "対象イベントログは " + $eventlogname + " です。") -EntryType "Information" } }
上記「GetEventlog.ps1」は、引数に「端末名」と「イベントログ名」(Application,Systemなど)をもらい実行されるスクリプト。
このファイルを「C:\hogehoge\script」に配置しておく。
途中で端末名とIPを紐付けるserverlist.xmlを読み込んでいるが、xmlの中身はこんな↓感じ。
- サーバの定義が書いてあるxml
<?xml version="1.0" encoding="utf-16"?> <config> <server name="hogehoge1"> <ipaddress>192.168.1.1</ipaddress> </server> <server name="hogehoge2"> <ipaddress>192.168.1.2</ipaddress> </server> </config>
んで、GetEventlog.ps1を実行するスクリプト
#================================================== # イベントログ取得スクリプト #================================================== #-------------------------------------------------- #GetEventlog # 第1引数:対象端末名 # 第2引数:イベントログ名(Application,System) #-------------------------------------------------- #インクルード . C:\hogehoge\script\GetEventlog.ps1 #引数 $_servername = "hogehoge1" $_eventlogname = "Application" #実行 GetEventlog $_servername $_eventlogname
出力される実行結果テキストは以下な感じ。
2012/06/18 12:00:01 Information 6013 EventLog システムの稼働時間は 98037 秒です。 2012/06/18 08:46:35 Warning 36 W32Time ソース 'W32Time' のイベント ID '-2108030940' の説明が見つかりません。必要なレジストリ情報またはメッセージを表示するメッセージ DLL ファイルがローカル コンピュータに存在しない可能性があります。または、これらのデータへのアクセス許可がユーザーに与えられていない可能性があります。次の情報はイベントの一部です:'86400' 2012/06/18 00:31:35 Error 48 W32Time ソース 'W32Time' のイベント ID '-2108030928' の説明が見つかりません。必要なレジストリ情報またはメッセージを表示するメッセージ DLL ファイルがローカル コンピュータに存在しない可能性があります。または、これらのデータへのアクセス許可がユーザーに与えられていない可能性があります。次の情報はイベントの一部です:'time.windows.com,0x1', '到達できないホストに対してソケット操作を実行しようとしました。 (0x80072751)', '960'
後は、引数を渡すスクリプトを 端末数 × イベントログの数 だけ用意すれば良い感じにしてみた。
と、windowsのメモ帳で開くと良い感じなんだけどsakuraエディタみたいなので開くと改行コードが色々で、変な所で改行されてたりする。。。
ココらへんの改修はまた今度(´・ω・`)
Windows PowerShell でイベントログを取得する
「イベントログを取得するバッチ作って」って言われました。
イベントログ開いて右クリック→別名で保存でいいんじゃまいかとも思いましたが、まぁご要望らしいので。
イベントログを取得するコマンドは以下。
名前 Get-EventLog 概要 ローカル コンピューターまたはリモート コンピューター上のイベント ログまたはイベント ログの一覧のイベントを取得しま す。 構文 Get-EventLog [-AsString] [-ComputerName <string[]>] [-List] [<CommonParameters>] Get-EventLog [-LogName] <string> [[-InstanceId] <Int64[]>] [-After <DateTime>] [-AsBaseObject] [-Before <DateTime>] [-ComputerName <string[]>] [-EntryType <string[]>] [-Index <Int32[]>] [-Message <string>] [-Newest <int>] [-Source <string[]>] [-UserName <string[]>] [<CommonParameters>] 説明 Get-EventLog コマンドレットは、ローカル コンピューターおよびリモート コンピューター上のイベントおよびイベント ログ を取得します。 プロパティ値を使用してイベントを検索するには、Get-EventLog のパラメーターを使用します。Get-EventLog は、指定された プロパティ値のすべてと一致するイベントのみを取得します。 EventLog という名詞を含むコマンドレット (EventLog コマンドレット) は、従来のイベント ログでのみ有効です。Windows Vi sta 以降のバージョンで Windows イベント ログ技術を使用しているログからイベントを取得するには、Get-WinEvent を使用し ます。
簡単にイベントログを引っ張ってこれるんだけど、結構要らない情報もついてくる。
一旦、CSVやXMLにexportしてから任意の列を取り出そうなんてコソコソ考えてたんだけど、同僚がもうちょっとシンプルに欲しい情報だけ引っ張ってこれるよーと教えてくれたのが以下。
#アプリケーションイベントログを取得 $logArray = Get-EventLog -ComputerName 192.168.0.1 -LogName "Application" | Select-Object EntryType,EventID,Source,TimeGenerated,Message
こんな感じに取得できる。
EntryType : Information EventID : 9003 Source : Desktop Window Manager TimeGenerated : 2012/06/14 13:26:33 Message : 合成テーマが使用されていないので、デスクトップ ウィンドウ マネージャを開始できませんでした EntryType : Information EventID : 9003 Source : Desktop Window Manager TimeGenerated : 2012/06/14 13:26:33 Message : 合成テーマが使用されていないので、デスクトップ ウィンドウ マネージャを開始できませんでした
- EntryType Error,Warning で、エラー警告のみとか、
- newest 5 で、最新の5件とか、
- After,-Before で日付を絞ったりできるのでお好みで。
続いてファイル出力。
#1件ずつ取り出して、ファイルに1行づつ書き出す foreach ($row in $logArray) { $line = [string]$row.EntryType + "," + [string]$row.EventID + "," + [string]$row.Source + "," + [string]$row.TimeGenerated + "," + [string]$row.Message #ファイル書込み $line | Out-File -filepath C:\tmp\eventLog.txt -Append }
C:\tmp\eventLog.txt の中身はこんな感じ。
Information,9003,Desktop Window Manager,06/14/2012 15:10:10,合成テーマが使用されていないので、デスクトップ ウィンドウ マネージャを開始できませんでした Information,9003,Desktop Window Manager,06/14/2012 15:10:10,合成テーマが使用されていないので、デスクトップ ウィンドウ マネージャを開始できませんでした
select-objectで欲しい情報を選択して、foreachで回しながらそれぞれのオブジェクトをカンマ区切りで一行にしてtxtに追記していく。
あとはこのtxtをExcelにでも取り込んでいただければ調査しやすいと思う。
と、なかなか良い感じなのだが、Message(本文)の中に改行コードが入っているとそのままファイルに出力されてしまい、ちょっと残念な感じになってしまう。
改行コードを何とかしたいと思ったところで時間切れとなったのでまた明日格闘してみる。
それにしても、はてなってpowershellのハイライト表示とかできないのかなぁ?