以下のようなTipsを見かけたのでメモしておく。
通常、「出力結果を変数に代入しつつコンソールに出力する」というと「Tee-Object」を思い浮かべるのだが、
PS>ps | tee -Variable a |
代わりにこんな感じでもよろしいのだと。
PS>($a = ps) |
「へぇー」
共通パラメータ(OutVariable)でも。
PS>ps -OutVariable a |
以下のようなTipsを見かけたのでメモしておく。
通常、「出力結果を変数に代入しつつコンソールに出力する」というと「Tee-Object」を思い浮かべるのだが、
PS>ps | tee -Variable a |
代わりにこんな感じでもよろしいのだと。
PS>($a = ps) |
「へぇー」
共通パラメータ(OutVariable)でも。
PS>ps -OutVariable a |
前回に引き続き、残業時間をチェックし警告メールを送信するスクリプトを作っている。
サブリーダーに「Cc」でメールすることにしたのだが、リーダーとサブリーダーの関係をどこに持つか・・・。
今のところ「上司」-「直属の部下」プロパティは使われていないので、簡便的にこのプロパティを使うこととした。
リーダーが上司、サブリーダー達がその部下という扱いだ。
「直属の部下」プロパティが見つかればなんてことはないと思ったのだが、そのプロパティが「属性エディタ」で見つからない。
実は、「上司」プロパティと「直属の部下」プロパティは一体管理されており、通常はメンバー側から見た「上司」プロパティとして表示されているようだ。
「直属の部下」プロパティを「属性エディタ」で表示するには、「フィルター」ボタンをクリックして「後方リンク」をチェックしてあげればよい。
プロパティを確認していくと、「直属の部下」は「directReports」だと判る。
直属の部下からメールアドレスを取得するのはこんな感じ。
001 002 | (Get-ADUser hara_tatsunori -Properties DirectReports).DirectReports | %{Get-ADUser $_ -Properties mail} | select -expand mail |
あとはこれをこのまま「Cc」に指定すればよい。
残業時間をチェックして、しきい値を超えたらリーダーにメールを送るなんて処理を作っている。
サブリーダーが存在するグループには「Cc」でサブリーダーにも送信する。
データによって、「Cc」パラメータがあったりなかったりするので、それぞれのパターンのコマンドを用意しておけば良いのだが、「Bcc」も追加なんてことになるとパターンが増えて面倒だ。
こんな時はどうするのがベストなのでしょうね。
さしあたって(以前もどこかで使った気がするが)、分配演算子を使って以下のようにすることとした。
001 002 003 004 005 006 007 | $names = "a*","c*","" $names | %{ $optParam = @{} if($_){$optParam.name = $_} ps -ComputerName (hostname) @optParam | Out-String } |
以前、以下の記事で調査したのだが、同じ目的の記事が有ったので紹介しておく。
PowerShell: ◆パイプライン中の処理かどうかを判定する(挫折)
--
Pipeline Used Or Not? - Power Tips - Powershell.com Powershell Scripts, Tips and Resources
--
前回調査してからちょっと間が空いたのと、前回なんとなく紆余曲折していたのでもう一度確認。
結局のところ「$myinvocation.ExpectingInput」を使うのがベスト?
001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 | function test { [CmdletBinding(DefaultParameterSetName='NonPipeline')] param( [Parameter(ValueFromPipeline=$true)] $Data ) begin { $myinvocation.ExpectingInput } process {$myinvocation.ExpectingInput} end { $myinvocation.ExpectingInput } } "パイプライン" 1,2 | test "ダイレクト" test 1,2 |
自作の関数にて、「confirm」と「whtif」をサポートするためには以下の属性をつければ良さそうだ。
CmdletBinding(SupportsShouldProcess=$true) |
001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 | function CommandWithConfirm { [CmdletBinding(SupportsShouldProcess=$true)] param() $mailAddr = "test1@hoge.co.jp","test2@hoge.co.jp" foreach($addr in $mailAddr) { if ($PSCmdlet.ShouldProcess($addr, "メールを送信")) { "$($addr)にメールを送信しました。" } else { "$($addr)へのメール送信をバイパスしました。" } } } CommandWithConfirm -confirm |
ここで、confirmを付け忘れるといきなり大量のメールを送信してしまうおそれがある。これを防ぐには必ず確認メッセージを表示するようにしておけば良い。
予めCmdletBindingにそういった機能が用意されていて、以下のようにすれば良い。
[CmdletBinding(SupportsShouldProcess=$true,ConfirmImpact="high")] |
要はこの処理は非常に危険だよということで、”high”を指定するという事なのだろう。
PowerShellから管理者宛にメールを送ることはよくある。
ある程度の人数に送ったりする場合は、変なメールを大量に送り付けないようテスト方法に気を遣う。
なにか良い方法は無いかと思うのだが、あまりコレといった方法が思いつかない。
とりあえず、関数を作って置き換える事とした。
(本来は関数自体が何らかのパラメータを受けて、実送信とテスト送信を切り替えれば良いのかもしれない)
001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 | function Send-MailMessageTest { param($To,$Cc,$From,$Subject,$SmtpServer,$body,$Attachments,$Encoding) $mailArgs = $PSBoundParameters if(!$globalMailTo){Write-Host "GlobaMailTo not found" -f Red;return} $body = @" *** (Start)メール確認モジュールによる追加メッセージです *** To:{0} Cc:{1} *** (End) 以下、本文です *** {2} "@ $mailArgs.Body = $body -f $mailArgs.To,($mailArgs.Cc | Out-String),$mailArgs.Body $mailArgs.To = $globalMailTo $mailArgs.Remove("Cc") Send-MailMessage @mailArgs } |
とりあえず、テスト用のメール送信先を「$globalMailTo」として外から与えることとした。
あとは本来の送信先とCcを本文に追記して送信する。
その他のパラメータは、そのままフォワード。
これでもメールアドレスの形式チェックや存在チェックはできないが、いくらか本番らしくテストできるかも・・・。
以下にイベントログからディスクコントローラのエラーを拾う方法(というかインスタンスID)が載っていたのでメモしておく。
Finding Disk Controller Errors - Power Tips - Powershell.com – Powershell Scripts, Tips and Resources
私は特別ハードに詳しいわけではないので、このエラーが出たらどうするかといった事は判らないが、頻繁に出るようであればHDDに何かしらの不具合がある可能性が高いと思うので、それなりの対策が必要かも。
(1回2回出たからといって必ずしもハード障害というわけ無いみたいだが・・・)
PS>Get-EventLog -LogName System -InstanceId 3221487627 -ea 0 | ft TimeWritten,Message -auto TimeWritten Message |