PowerShell パイプラインを速習しろ!
おっす!オラ、PowerShell大好き野郎。
今回はPowerShellの速習的なモンについて書いてみたいと思う。
1.PowerShellとはどんなシェルか
さっそくだが、PowerShellがどんなシェルか、ということをまずは提示しておきたい。
PowerShellは完全オブジェクトベースのシェルである。
しかも、.NET Frameworkのオブジェクトだ。
よって、コマンドプロンプトのような従来のテキストベースのシェルとは一線を画す。これはどういうことかと言うと......
オブジェクトが持つメンバーにアクセスできるというわけだゼ!
一例を示してみたい。
下記をプロンプトで打ってみる。
$str = "俺はオブジェクト"
$str.GetType()
ご覧の通り、変数$strは、.NET FrameworkのオブジェクトであるSystem.Stringであることが分かる。
※GetTypeはオブジェクトの型を調べるメソッド
さらに下記を打ってみる。
$str.Length
期待通り、System.StringのメンバーであるLengthプロパティにアクセスして、文字列の長さを取得することができた。
2.パイプラインとは
前セクションで、オブジェクトについて細かく書いたには理由がある。
PowerShellの避けては通れぬ、且つ偉大過ぎる機能、
パイプラインはオブジェクトが命!
だからである。
パイプライン。或いはパイプ処理。
ある処理を実行し、その処理結果(オブジェクト)を、次の処理の入力値にして、処理を流れるように繋げていく。
そう、流れるのはオブジェクトだゼ!
以降で、パイプ処理でよく使う主要なコマンドレットを取り上げ、パイプラインを馳走いたしたく思ふ。
※念のため、パイプ記号は以下の画像のド真ん中にあるやつだ!
3.データを並び替えろ!Sort-Object
Sort-Object(エイリアスSort)は、パイプラインで受け取ったオブジェクトを並び替えるためのコマンドレットだ。
C:¥hogeフォルダにあるファイルを取得し、ファイルサイズの降順で表示する。
Dir | Sort-Object Length -descending
※降順にする場合は、スイッチパラメータdescending(desc)を付ける。
デフォルトはスイッチパラメータなしで昇順となる。
4.欲しいプロパティだけぶっこ抜け!Select-Object
Select-Object(エイリアスSelect)は、パイプラインで受け取ったオブジェクトから、特定のプロパティのみを抜き出すコマンドレットだ。
C:¥hogeフォルダにあるファイルを取得し、Name,Lengthプロパティのみを表示する。
Dir | Select-Object Name,Length
※指定するプロパティはカンマ区切りにする。
5.ふるいにかけろ!Where-Object
Where-Object(エイリアスWhere、?)は、パイプラインで受け取ったオブジェクトから、特定条件にヒットするデータを取得するコマンドレットだ。
C:¥hogeフォルダにあるファイルを取得し、ファイル名に「太子」を含むデータを表示する。
Dir | Where-Object{$_.Name -like "*太子*"}
※条件式はスクリプトブロックと呼ばれる{ }で囲まれた中に記述する。
※$_はパイプラインで受け取ったオブジェクトが格納された特殊な変数(自動変数)。
※$_のあとに、ドットとプロパティ名を付けると、オブジェクトプロパティにアクセスできる。
※-likeはワイルドカード比較に合致する比較演算子
6.この指とまれ!Group-Object
Group-Object(エイリアスGroup)は、パイプラインで受け取ったオブジェクトから、同じプロパティ名同士のオブジェクトでグループ化するコマンドレットだ。
C:¥hogeフォルダにあるファイルを取得し、拡張子別にグルーピングする。
Dir | Group-Object Extension
※特筆すべきは、かなりSQLぽいところ!
※出力されるのは、オブジェクトの個数(Count)、プロパティの値(Name)、オブジェクトのリスト(Group)。
※末尾にスイッチパラメータ -NoElementを付与すると、一番右側に表示されているファイルの一覧を非表示化できる。
7.処理をかまし続けろ!ForEach-Object
ForEach-Object(エイリアスForEach、%)は、パイプラインで受け取ったオブジェクトに対して、1ブロックずつスクリプトブロックで指定した繰り返し作業をする。
C:¥hogeフォルダにあるファイルを取得し、ファイル名のフルパスをWrite-Hostコマンドレットを使ってプロンプト表示する。
Dir | ForEach-Object{Write-Host $_.FullName}
※ForEach-Objectコマンドレットと似て非なるもので、ForEachステートメントというものがある。
記述方法はもちろんだが、処理速度にも違いがある。PowerShellを覚えたての頃は大変に紛らわしかったゼ!
興味がある御仁は、一度調べてみると面白いと思われる。
8.複数パイプでどんどん繋げていけ!
パイプはどんどん繋げていける。SelectとWhereを1ライナーで利用した例。
C:¥hogeフォルダにあるファイルを取得し、拡張子がpdfのファイルだけを取得し、Nameプロパティのみを表示する
Dir | Where{$_.Extension -eq ".pdf"} | Select Name
※-eqは左辺⇔右辺が等しいを示す比較演算子
※パイプを繋げてPowerShellを楽しもうゼ!
以上、パイプライン速習を終了する。
PowerShell、イエーイ!
PowerShell 自動印刷をしろ!
|
毎回、お決まりの作業はとことん自動でやりませう!
ルーチンワークは自動でやりませう!
ちんたらやってたら、日が暮れちまうゼ!
ファイルの大量印刷ってのは、結構めんどくさい。
大昔、俺はファイルを「全選択して右クリック印刷」という手法を試してみた。
しかし、うまくいかなかった場合が多かった。
・選択ファイル数がある一定数を超えると、右クリック印刷の選択肢が消滅する。
・拡張子の異なるファイルがあると、右クリック印刷の選択肢が消滅する。
・印刷はできたが、印刷順がバラバラ。
まるで、話にならんゼ!!
こんなのはPowerShellでさくっとやるべきだ。それはStart-Processコマンドレットで可能となる。
印刷対象となる代表的なファイル分類は以下だろう。
もう、スタンダード過ぎる奴らばかりだ。
Start-Processコマンドレットはファイルに関連付けられているプログラムをまずは起動してくれる。で、その後が大事だ。印刷してくれるんけ?!
心
配
ご
無
用
!
|
起動した後、どうするかという「動詞」に相当するパラメータが用意されているゼ!
verbパラメータというものがあり、それにPrintを指定するだけ。
▼問題点を解消したPowerShellスクリプトはこれ
#-----------------------------------
# 処理名:自動印刷
#-----------------------------------
#対象フォルダ
$folder = "C:¥hoge"
#予告メッセージ
Write-Host "$folder フォルダ直下のファイルをすべて印刷する!"
Write-Host "※ファイル間のスリープ処理:2秒`r`n"
#ファイル名の昇順で印刷実行
Dir $folder | Sort Name | ForEach{
#ファイル名表示後、実行
Write-Host $_.Name
Start-Process $_.FullName -Verb Print | Stop-Process
#2秒スリープ
Start-Sleep -s 2
}
Write-Host "`r`n完了!`r`n"
Read-Host "×ボタンで終了"
・Sort-Object(Sort)コマンドレットのデフォルトは昇順。
・1ファイルの印刷が終わったら、Stop-Processコマンドレットでプロセスを停止する。
・印刷順のズレを解消するために、とりあえず2秒スリープさせる。
4のジャパンの綴りが間違っていますね。
▼資源の無駄使いをしないために、プリンタの電源OFF状態で、印刷キューを確認した。
PowerShell、イエーイ!
|
PowerShell タイムスタンプを変更しろ!
元ボクサーの袴田巌さんの冤罪事件は大変痛ましかったな。
俺は無実であると主張したい。
人の人生ぶっ壊しやがって!48年もだゼ。
それになぁ!コンピュータと違って、
人生のロールバックはできんのじゃ!ボケ
さて、情報技術絡みの事件では昔、これまた証拠捏造によるクソだわけな事があった。
大阪地検特捜部の元主任検事が、捜査資料であるフロッピーディスクに保存されていたファイルのタイムスタンプを意図的に変更して、証拠捏造を図ろうとしたのである。
タイムスタンプとはつまり、ファイルの作成日時、更新日時、アクセス日時のことである。その事件では更新日時を変更したそうである。
今回は、このタイムスタンプの意図的な変更について取り上げてみたいと思う。
意図的な変更をするには、例えばフリーソフトでごろごろ転がっているタイムスタンプ変更ツールを使うというのが一つの手法であろう。その他、OSのシステム日付をいじってファイルを保存すれば、更新日時については簡単に変えられてしまう。
俺もタイムスタンプ変更をやったことがあるが、スゲぇ簡単にできてしまうものだった。なぜなら、PowerShellを使ったからな。待ってたゼ、PowerShell。
PowerShellのSet-ItemPropertyコマンドレットを使えば、できてしまうのだよなこれが。コマンドレットの名称から分かるとおり、タイムスタンプというのはプロパティであるから、変更ができるというわけだ。
どういう目的でタイムスタンプ変更をしたかは割愛するが、悪事のためではないことは宣言する!
では、あるフォルダ直下にあるファイルすべてに対して、作成日時、更新日時、アクセス日時の変更をかけるPowerShellスクリプトを提示したいと思う。
▼ソースはこれ
#----------------------------
# 処理名:タイムスタンプ変更
#----------------------------
#変更対象フォルダ
$folder = "C:\hoge"
#作成日時、更新日時、アクセス日時(yyyy/MM/dd HH:mm:ss形式)
$sakusei = "1999/12/31 12:59:00"
$koushin = "2000/01/01 00:00:00"
$akusesu = "2017/11/21 11:11:00"
Write-Host "実行中......"
#作成日時、更新日時、アクセス日時の変更
Dir $folder | ForEach{
Set-ItemProperty $_.FullName CreationTime $sakusei
Set-ItemProperty $_.FullName LastWriteTime $koushin
Set-ItemProperty $_.FullName LastAccessTime $akusesu
}
#変更結果確認
Dir $folder | Select Name,CreationTime,LastWriteTime,LastAccessTime | Format-List
Write-Host "完了!`r`n"
Read-Host "×ボタンで終了"
・3種類のタイムスタンプ用変数
yyyy/MM/dd HH:mm:ss形式で記述する。
・変更結果が見やすいようにするには?
特定プロパティだけをリスト表示する。
Name,CreationTime,LastWriteTime,LastAccessTime
▼実行するとこんな感じ
良い機会なので、PowerShellのパイプライン処理とオブジェクトのプロパティについても少し触れておきたい。
Dir(Get-ChildItem)で変更対象フォルダにあるファイル群を取得し、パイプ処理をする。
$_はパイプで渡されたオブジェクトが格納される特殊な変数(自動変数)である。
また、$_(自動変数)にドット(.)を付けると、取得したオブジェクトの各プロパティにアクセスできる。
今回は$_.FullNameとなっているので、取得したオブジェクトのファイル名フルパスということになる。
Dirにはどんなプロパティがあるかは下記のコードで知ることができる。
Dir | Get-Member -MemberType Property
PowerShell、イエーイ!
PowerShell シャットダウンを確実にしろ!
その日、俺は急いでいた。
一日の仕事を終えると、速攻でノートPCのシャットダウンをかけ、あばよ!と帰ったのである。
はよ帰って何をやったのかは、ここでは無関係なので、省略する。
次の日。仕事場に着き、ノートPCを開いた。
「シャットダウンされとらんやないけ!このクソボケが。」
という経験が、過去に誰しも一度くらいはあるのではなかろうか?!
ここで、シャットダウンが確実にされなかった原因についての考察をしてみる。
・シャットダウンが確実にされるのを見届けなかった。
(もし、見届ける意思があるならば、途中で異変に気付くはずである。)
・何か未保存のアプリがあって、終了確認の表示が出たままとなって、シャットダウン処理に移行できなかった。
まあ、こんなところだろう。
しかし!正直な話、見届るけなんてダルいことはクソめんどくせえゼ!
さらに、シャットダウンをしようとした直後、「バックグラウンドプログラムの終了を待機しています」という表示が出ることもあって、「はよせんか!この野郎」と思うこともある。
よって、これらの問題点、イライラ解消をするために、俺は立ち上がったのである!
PowerShellスクリプトにより、即時強制シャットダウン実行をさせるのである。
Stop-Computerコマンドレットというものが、PowerShellにはあり、これでシャットダウン処理ができるのである。
そして、何があろうが問答無用で確実に強制実行する。
▼ソースはこれ
#--------------------------------
# 処理名:即時強制シャットダウン
#--------------------------------
$WS = New-Object -com WScript.Shell
$result = $WS.Popup("即時強制実行するか?",0,"即時強制シャットダウン",4)
#実行確認(はい:6、いいえ:7)
If($result -eq 7){Exit}
#予告
Write-Host "1秒後に即時強制実行する!"
Start-Sleep -s 1
#即時強制シャットダウンの実行
Stop-Computer -force
・Stop-Computerコマンドレットのスイッチパラメータ forceで強制処理が可能となる。
▼確認処理で「いいえ」を選ぶと、処理抜け。
「はい」を選べば予告メッセージの後に強制実行される。
しこうして、俺のイライラは無事に解消されたのであった。
PowerShell、イエーイ!
PowerShell パスワードをブチやぶれ!
過日、あるWebアプリケーションの自動ログインスクリプトを作ったときの話である。
ユーザIDはまあスクリプトに埋め込んでも問題ないだろう。
一方のログインパスワードはそうはいかない。スクリプト起動後、Read-Host コマンドレットを使用して、対話入力させることにした。
しかし、このRead-Host コマンドレット、特にパラメータ付与せず、そのまま使ってしまうと、パスワードがプロンプトに丸見えになってしまうのである。
「うおっ、丸見えはヤバすぎる!隠すとこは隠しやがれ。」
ということで、AsSecureString パラメータというものがあり、これを付与すると、プロンプト上で伏字表示(アスタリスク)してくれる。
またパラメータ名からも分かる通り、入力された文字列をセキュアな文字列に変換してくれるのである。
だが、待て。セキュアな文字列に変換されたということはつまり、そのままアプリにパスワードを飛ばしても弾き返されてしまうことは必至ではないか。
平文化しないと、アプリにログインはできない。
よって、今回はプロンプトに伏字表示されたパスワードであるセキュアな文字列を、最終的に平文化する、ということについていろいろ検証していきたいと思う。
パスワードは、PowerShellと打ちこんだ。
▼ソースはこれ
#-----------------------
# セキュア文字列の検証
#-----------------------
#伏字でユーザ入力させる
$secureStr = Read-Host "パスワード" -AsSecureString
#ユーザ入力値(セキュア文字列)
Write-Host "▼セキュア文字列/型"
Write-Host $secureStr
Write-Host $secureStr.GetType().Name
Write-Host ""
#セキュア文字列を記録したメモリのポインタを取得
$pointerStr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($secureStr)
Write-Host "▼ポインタ/型"
Write-Host $pointerStr
Write-Host $pointerStr.GetType().Name
Write-Host ""
#ポインタから平文文字列を取得
$hirabunStr = [System.Runtime.InteropServices.Marshal]::PtrToStringBSTR($pointerStr)
Write-Host "▼平文文字列/型"
Write-Host $hirabunStr
Write-Host $hirabunStr.GetType().Name
Write-Host ""
Read-Host "×ボタンで終了"
・SecureStringの操作について
「System.Runtime.InteropServices.Marshal」クラスのメソッドを2種類利用して、段階的に文字列取得をしていく。
・文字列取得後にやること
各段階で取得した文字列内容と、型の確認をする。
結果はこんな感じで、最終的にパスワードPowerShellを得ることができた。
パスワードをブチやぶることに成功したが、結局一番やりたいことは伏字表示したいだけということだけなのに、アプリに平文文字列を飛ばさねば意味がないわけで、色々やらんといかんわけであった。
PowerShell、裏で色々頑張ってますのよ、アハーン!
PowerShell メッセージボックスを表示しろ!
スクリプトに限らずの話だが、処理というのはクソつまらん処理、面白い処理、けっこうどうでもよい処理、やばい処理とか色々ある。
この中で「やばい処理」というのをひとつ取り上げてみたい。
やばいと言うからには、慎重にやらないといけない。
やっちまった、やり直しがきかないゼ!
「ファイル削除処理」なんかはこれに該当すると思う。
よって、実際のメイン処理の前に、何らかの確認処理を行う必要性が出てくる。
待ってました!ここで、メッセージボックスの出番です。
はてさて、メッセージボックスを利用して注意を促すのは、コマンドラインのシェルスクリプトであるPowerShellにおいて、かなり有効かと思われる。
普段、文字ばっかりのプロンプトの上に、ダイアログがいきなり出現するからな。
では、メッセージボックスを出す手法には、どんなものがあるか。
1..NETのWindows Formsの名前空間におけるMessageBoxクラスを利用する方法。
2.COMオブジェクト Wscript.ShellのPopupメソッドを利用する方法。
今回は、2のCOMオブジェクトを紹介したい。
何てたって、実装がとても簡単!正味たった2行!
(オブジェクト生成&メソッドの戻り値取得)
▼ソースはこれ
#-------------------------------------------
# 処理名:実行確認処理
# 戻り値:ユーザ入力値(はい:6、いいえ:7)
#-------------------------------------------
Function Fn_Confirm(){
$WS = New-Object -com Wscript.Shell
$result = $WS.Popup("志村けんのギャグを表示しますか?",0,"確認",4)
Return $result
}
If((Fn_Confirm) -eq 7){Exit}
Write-Host "だっふんだ!!`r`n"
Read-Host "×ボタン or Enterで終了"
<PopUpメソッド>
・引数について
第1引数:メッセージ内容
第2引数:自動で閉じる秒数(0を指定すると自動で閉じない)
第3引数:タイトル
第4引数:ボタンの種類(はい/いいえの場合は4を指定)
・戻り値について
は い:6
いいえ:7
実行すると、こんな感じでメッセージボックスが出る。
・「はい」を選ぶと、ギャグをプロンプト表示する。
・「いいえ」を選ぶと、処理抜け。
▼はいを選んだ場合
だっふんだ!!
PowerShell、イエーイ!
▼以下の記事にて、より詳細に説明あり
acoustic-groove2.hatenablog.com
ロリポップ!レンタルサーバー!はあなたの「やってみたい!」を応援します!
ロリポップ!なら、ホームページ、ブログ、ネットショップ…
これらが今すぐ、そして簡単にできちゃう!
マニュアルやライブチャットを完備しているので、ホームページ初心者でも安心。
これだけついてるのに月額100円(税抜)~ととってもお得。
もちろん無料のお試し期間も10日間あるので安心ですね。
▼ロリポップ!レンタルサーバーはこちら
PowerShell スクリプトファイルを配布しろ!#2
前回はクソダサい方法で、スクリプト実行をした。
よって、今回はカッコよくいきたいところである。
やはり!!!!
見た目にこだわることは超重要!
カッコつけてPowerShellライフをしたいのですよ。
さて、カッコつけの準備をしよう。まずは、PowerShellがダブルクリック実行できない理由を明らかにしないといけない。
ダブルクリックすると、メモ帳が開いてソースが見れるだけでスクリプトが動かない。
これは、実行ポリシーの問題以前に、プログラムの関連付けがされていないからに他ならない。
さっそく調べてみよう。PowerShellスクリプトファイルのプロパティを見てみると、プログラムのところが、メモ帳になっている。だから、メモ帳が開くのである。
だったら、メモ帳からPowerShellに変更すれば良いやんけ!!と思うかもしれないが、落ち着け、餅つけ!
俺はこう思うのよね。
よって、直接変更しない案を紹介したい。
▼ショートカット実行案
- PowerShellスクリプトファイルのショートカットを作る。
- プロパティを開く。
- ショートカットタブを選ぶ。
- リンク先の先頭に、以下を追加してOKを押す。
PowerShell -ExecutionPolicy ByPass -NoExit
-NoExitの後には半角スペースを必ず入れること。
これは一体何をやったかというと、PowerShellスクリプトファイルに対して、何を使って実行するかというプログラムの指定と実行オプションを付与したのである。
powershell.exe
・実行オプション
-ExecutionPolicy ByPass -NoExit
実行ポリシーを一時的にByPassにする。飽くまでも一時的だゼ。
(他にもRemoteSigned,Unrestrictedを指定しても良い。俺はByPassを使う。綴り短いし!ってのも理由のひとつ)
・-NoExitとは
プログラム実行後、プロンプトを勝手に閉じないようにしてくれる。
これがないと、勝手に閉じる。
これをもってして、ショートカットファイルをダブルクリックすると......
お疲れっす!
あと、これまた見た目だが、ダブルクリック実行できないスクリプトファイルをわざわざ、人に見せる必要ないゼ!
スクリプトファイル本体はScriptフォルダに入れておくと、カッコええ感じが俺はする。
PowerSell、イエーイ!