Windowsにはコマンド操作を行うプログラムとして「コマンドプロンプト」がありますが、この機能をさらに進化させたのが「PowerShell」です。
使うのが難しそうだと思っている人もいるかもしれませんが、いざ使ってみると意外と便利で、Windows PC上の操作を素早く楽に行うこともできます。
「時短テクニック」にも有効なPowerShellの概要と基本操作、さらにPowerShellで使用できるコマンドレットについて、コマンドプロンプトにはなかったオブジェクトという概念から、パイプライン、関数、変数などより高度にPowerShellを扱うために知っておきたい情報、さらに同じような操作を効率的に行うためにPowerShellで作成した記述をファイルに登録し、そのファイルを実行する方法についてもご説明します。
Windows PowerShellと新登場したPowerShell Core
Windowsにはコマンド操作を行うコマンドプロンプトが備わっており、今でもそれなりに有用なプログラムですが、すでに進化も止まっており力不足の感は否めません。そこで代わりに登場したものがPowerShellです。Windows 7/Windows Server 2008からWindowsに標準搭載されており、2018年11月現在の最新バージョンはWindows 10用の5.1です。
ただし、このPowerShellも今後バージョンアップされず、機能の追加も予定されていません。実はこのPowerShellの後継として、「PowerShell Core」がすでにリリースされています。PowerShell Coreはオープンソースとしてリリースされ、Windowsだけでなく、MACやLinuxでも動作します。2018年11月現在の最新リリース版は6.1.1になります。
つまり、現在はPowerShell 5.1とPowerShell Core 6.1.1という2つの最新バージョンが存在します。PowerShell Core 6.1.1はPowerShell 5.1の上位互換かといえば必ずしもそうではなく、新しく追加された機能がある反面、MACやLinuxでも動作させるために、一部Windows特有の機能が削られていたりします。
PowerShell 5.1とPowerShell Core 6.1.1は同じWindows上に共存可能ですので、必要に応じて両方を使い分けるというのが一番賢い使い方でしょう。本稿では用途に応じて2つを使い分けることにします。以降、単にPowerShellという場合はWindows PowerShellとPowerShell Coreの両方を意味し、個別に呼ぶ場合はWindows PowerShellあるいはPowerShell Coreと呼ぶことにします。
PowerShell Coreのインストール方法
PowerShell CoreはWindowsに標準添付されていませんので、自分でインストールする必要があります。その手順は次のとおりです (画面はWindows 10 バージョン1809の場合)。
下記のサイトからPowerShell Coreの最新版をダウンロードします。
https://github.com/PowerShell/PowerShell/releases
お使いのWindowsに合わせたインストールファイルをダウンロードします。例えば、Windows 10 64ビット版であれば「PowerShell_6.1.1_win_x64.msi」をダウンロードします。
ダウンロードしたmsiファイルをダブルクリックするか、または右クリックして [インストール] をクリックします。その後Setup Wizardが表示されますので、[Next] ボタンをクリックします。
ライセンス画面でAgreementにチェックを付けて [Next] ボタンをクリックします。
インストール先の選択画面が表示されますので、デフォルトでよければ、そのまま [Next] をクリックします。変更する場合は [Change] ボタンをクリックして変更してください。
オプションの選択画面が表示されます。ここでは全部にチェックを付けてから、[Next] ボタンをクリックします。
確認画面で [Install] ボタンをクリックすると、インストールが始まります。
「ユーザーアカウント制御」画面が表示されたら[はい] をクリックします。次の画面が表示されたら、[Finish] ボタンをクリックしてWizard画面を閉じます。
PowerShellの起動方法
ここではWindows 10 バージョン1809での操作方法を説明します。他のバージョンでも大きな違いはありません。Windows PowerShellを起動するには、[スタート] メニュー → [Windows PowerShell] → [Windows PowerShell] または [Windows PowerShell (x86)] をクリックします。前者は64ビット版、後者は32ビット版です。[Windows PowerShell ISE] または [Windows PowerShell ISE (x86)]については別の記事にて解説します。
また、[スタート] メニューの右クリック → [Windows PowerShell] または [Windows PowerShell (管理者)]、あるいはエクスプローラ上の任意の場所で [Shift] + 右クリック → [PowerShellウィンドウをここに開く] でも起動できます。
PowerShell Coreの起動方法
PowerShell Coreがインストールされているなら、[スタート] メニュー → [PowerShell] → [PowerShell (x64)] または [PowerShell (x86)] をクリックするとPowerShell Coreが起動できます。
PowerShell Coreの場合も同様に、エクスプローラの [Shift] + 右クリック → [PowerShell 6] → [Open here] または [Open here as Administrator] でも起動できます。
PowerShellの起動画面
Windows PowerShell 5.1の起動画面、PowerShell 6.1.1の起動画面は次のとおりに、よく似ています。
ウィンドウのサイズや背景色が違っていますが、これはコマンドプロンプトの場合と同様にカスタマイズできます。大きな違いとして、画面からはわかりませんが、デフォルトの文字コードが、Windows PowerShellでは「Shift-JIS」であるのに対し、PowerShell Coreでは「UTF-8」になっています。
コマンドプロンプトのコマンドも使える
コマンドプロンプトでできることのほとんどがPowerShellでもでき、さらにコマンドプロンプトではできない多くの機能もPowerShellならできます。
コマンドプロンプトとPowerShellではコマンドの構文が異なるため、同じ機能でも入力するコマンドは異なりますが、コマンドプロンプトのコマンドのほとんどが同じコマンドとしてPowerShellでも利用できます。
この理由は、PowerShellの設定で、コマンドプロンプトのコマンドがエイリアスとして登録されており、PowerShellはコマンドプロンプトと同じコマンドを受け取ると、内部的にそれを同じ機能を持つPowerShellのコマンドに変換してから実行するのです。
試しにPowerShellコンソールに「get-alias」と入力してみてください。現在登録されているエイリアスの一覧が表示されます。
これを見ると、「cd」コマンドが「Set-Location」に、「copy」コマンドが「Copy-Item」に、「del」コマンドが「Remove-Item」に、「dir」コマンドが「Get-ChildItem」にといった具合にエイリアスとして登録されていることがかわります。
また、このエイリアスにはコマンドプロンプトだけでなくLinuxのコマンドもエイリアスとして登録されているので、Linuxのコマンドの多くもそのまま使えます。なお、エイリアスはユーザーが自由に設定できるので、よく使うコマンドを短くわかりやすいコマンドとして登録しておけば作業効率が飛躍的に高まります。エイリアスの登録方法は別の記事で解説します。
なお、これまでPowerShellの“コマンド”と呼んできましたが、「Set-Location」や「Get-ChildItem」などは正式にはコマンドではなく「コマンドレット」と呼ばれています。そしてコマンドレットと、エイリアスや実行可能な関数・スクリプトを含めてPowerShellのコマンドと呼んでいます。以後はPowerShellではコマンドレットとコマンドを区別することにします。
PowerShellはコマンドレットを含むコマンドの実行環境であると同時に、スクリプト言語でもあります。コマンドプロンプトにも一連のコマンドを連続して実行するバッチファイル機能がありますが、PowerShellはより強力なスクリプト機能を持っていますので、Windowsのほとんどの操作をスクリプトで自動実行することができます。特にサーバーの管理にはほとんど不可欠のツールになります。PowerShell Coreでは、さらにMACやLinuxが混在したクロスプラットフォーム環境で利用できることもポイントです。スクリプトについても別の記事で解説します。
コマンドレットを使ってみる
では、実際にコマンドレットを使ってみましょう。
Windows PowerShellのコンソールに「dir c:」と入力すると次の画面が表示されます。
PowerShell Coreでも同じ結果が表示されます。また「get-childitem c:」と入力しても同じ結果が表示されます。エイリアスですから当然です。
参考までにコマンドプロンプトでの「dir c:」実行結果は次のとおりです。
PowerShellとコマンドプロンプトでは若干表示される内容に違いがあることがわかります。PowerShellでは属性が表示されるのに対し、コマンドプロンプトではボリュームラベルやシリアル番号、ファイルの合計容量・空き容量が表示されるという違いがあります。
コマンドレットの構文
「Get-Alias」コマンドレットや「Get-ChildItem」コマンドレットで見たように、PowerShellのコマンドレット構文は動詞と名詞をハイフンで繋いだ「動詞―名詞」の形になっています。
コマンドレットの後に、半角スペースを空けてパラメーターを記述します。パラメーターはコマンドレットにより必須の場合もありオプションの場合もあります。各パラメーターは先頭にハイフンを付けます。「Get-ChildItem c:」コマンドレットは「Get-ChildItem -Path C:」の「-Path」パラメーター名を省略したものです。
コマンドレットの動詞としては、Getの他に、Add、Copy、Move、New、Open、Select、Set、Writeなどの標準動詞が多数用意されています。また名詞には、Alias、Content、Item、ChildItem、Object、Process、Serviceなどの標準名詞が多数用意されています。
このコマンドレットの命名規則を理解すれば、コマンドレット名からそれがどんな機能を持っているかが容易にわかります。逆にこんな機能を持ったコマンドレットを探したいという場合も、この命名規則から容易にコマンドレット名を推測できます。例えば、今日の日付を取得したいならば、「Get-Date」コマンドレットだろうと推測できます。またある程度の知識が必要になりますが、コマンドレットはユーザーが追加することもできます。
利用できるコマンドレットの一覧は「Get-Command」コマンドレットを実行すれば表示できます。かなり数が多いので、1ページごとに停止させるなら「Get-Command | More」と入力します。コマンドレット以外のエイリアスや関数、スクリプトを含めた全コマンドを表示させるなら「Get-Command *」または「Get-Command * | More」と入力します。「|」はパイプラインを意味しており、「More」は1ページごとに表示するコマンドです。
ヘルプの表示と更新
ヘルプの表示
PowerShellのヘルプを参照するには「Get-Help」コマンドレットを使います。パラメーター無しで実行するとPowerShellの概要が表示されます。なお、PowerShell Coreのヘルプは現在日本語化されていません。ヘルプの表示が長い場合はヘルプの最後までスクロールされてしまいますので、このままでは見にくいでしょう。
「Get-Help」の代わりに「Help」を使うと、1ページごとに表示が停止しますので、この方が見やすくなります。「Help」はコマンドレットではなく、「Get-Help | more」のラッパー関数です。ラッパー関数というと難しく思われるでしょうが、エイリアスのようなものと思えばよいでしょう。ですから「Help」の代わりに「Get-Help | more」と入力しても同じです。個々のコマンドレットに関するヘルプを表示するには「Help -Name コマンドレット名」と入力します。「-Name」は省略可能です。
「Helpコマンドレット名 -Detailed」と「-Detailed」パラメーターを付けると詳細なヘルプを表示します。また「Helpコマンドレット名 -Full」と「-Full」パラメーターを付けると最大に詳細なヘルプを表示します。
「Help」、「Get-Help」には「-Online」パラメーターもあります。このパラメーターを付けるとブラウザが開いて、オンラインのヘルプが表示されます。ただし、すべてのヘルプがオンラインで表示できるわけではありません。
ヘルプの更新
PowerShellのヘルプ内容は最新版に更新可能です。ただし、自動的には更新されませんので、手動で更新します。更新はPowerShellを「管理者として実行」して、以下の「Update-Help」コマンドレットを実行します。
・Update-Help -Force -UICulture en-US
・Update-Help -Force -UICulture ja-JP
なお、PowerShell Coreのヘルプは日本語版が現在はありません。また、Windows PowerShellでもいくつかのヘルプは日本語化されていません。そのため、まず英語版のヘルプを更新してから日本語版のヘルプを更新します。こうすれば日本語化されていないヘルプに関しては英語版を表示することができます。中には英語版のヘルプがないものもあります。
「-Force」パラメーターは一日に何度も「Update-Help」コマンドレットを実行する場合に必要になります。このパラメーターがないと「Update-Help」コマンドレットは一日に一回しか実行できません。上記コマンドレットを実行中は次のような画面が表示されます。
上記コマンドレットを終了すると次のような画面が表示されます。赤字で更新できなかったモジュールが表示されます。
PowerShellを使い続けるのであれば、時々「Update-Help」コマンドレットを実行するとよいでしょう。
コマンドレットに不可欠な「パイプライン」
PowerShellでコマンドレットを扱う上で知っておきたいのが「パイプライン」です。パイプラインはコマンドプロンプトにもありますが、その内容は大きく異なっています。そもそもパイプラインとはどういうものかというと、あるコマンドの実行結果を別のコマンドに引き渡すためのつなぎの役割をするものです。次のコマンドがPowerShellのパイプラインの例です。
「Get-ChildItem -Path c:Windows | More」(-Pathは省略可)
「Get-ChildItem」は現在のディレクトリ情報を取得するコマンドレットです。「More」もコマンドプロンプト時代から利用できるコマンドの1種です。「|」がパイプラインで、「Get-ChildItem -Path c:Windows」の実行結果を「More」コマンドに引渡し、1ページごとに表示します。何かキーを押すと次のページを表示します。
参考として、コマンドプロンプトでも同様のことを実現でき、
「dir c:Windows | More」でできます。
表示の形式が異なっていますが内容は同じものです。これを見る限りPowerShellもコマンドプロンプトもパイプラインは同じ機能に見えますが、内実はまったく異なっています。
コマンドプロンプトではパイプラインで引き渡すことができるのは文字列だけです。一方PowerShellでは「オブジェクト」を引き渡します。「More」コマンドは文字列を表示するだけの機能しかありませんので、結果として同じになっているだけです。
オブジェクト、プロパティ、メソッドとは
ここで「オブジェクト」とは何なのかと思った方もいるでしょう。オブジェクトとはどういうものかを見るために、
「Get-ChildItem c:Windows | Get-Member」を実行してみます。
この画面では、フォルダ (Directory) とファイル (File) が持つオブジェクトの種類が表示されています。それらはリンクタイプ、モード、名前、パス、サイズ、プロバイダ、属性、作成日時、最終アクセス日、最終更新日など、属性情報(=プロパティといいます)を持っています。または、作成、削除、セキュリティ、ファイルシステム、ハッシュなど、可能な処理(=メソッドといいます)の情報を持っています。オブジェクトの中には、こうしたプロパティやメソッドにより分類された形でデータが格納されているのです。
イメージがわきづらいと思いますので人に例えてみましょう。「人間」は必ず年齢、身長、体重などの属性情報を持っています。歩く、話す、見るなど動作や処理もできます。その属性情報がプロパティであり、動作や処理がメソッドだとイメージしてください。そしてそうしたさまざまな情報やデータがまとまった人間を「オブジェクト」と例えると少しわかりやすいかもしれません。
コマンドプロンプトでは、コマンドによって得られたものは、文字列として情報が渡ってくるため分類がなされていません。PowerShellではデータが分類されているので、特定のプロパティやメソッドを指定して、そのデータを簡単に取り出すことができます。
正確ではないのですが次のように例えましょう、コマンドプロンプトでは、「人のデータを収集する」という命令をしたとき、取得した「人A」「人B」というデータは「人A」「人B」であると言う情報しか持っていないのに対し、PowerShellは、その中に、年齢、性別などのさまざまな属性を内包しているため、さらに処理を行うことで、さまざまなデータを抽出できるというイメージです。
コマンドレットの例
ここでパイプラインを使いながらコマンドレットの例を見てみましょう。次のコマンドは指定したサイズ (例では1MB) 以上のファイルだけを取り出して表示します。
「Get-ChildItem c:Windows | Where-Object {$_.Length -ge 1MB}」
「Where-Object」コマンドレットを使ってサイズ (Length) プロパティが1MB以上のファイルを表示しています。ge (greater or equal) は同じか大きいものを示します。これと同じことをコマンドプロンプトでやろうとすると、できないことはないにしても恐ろしく面倒なことになります。
この応用として、cドライブ直下の「temp」というフォルダ以下のすべてのサブフォルダからファイルサイズ0の空ファイルを見つけて削除するには以下のように記述します。
「Get-ChildItem c:temp -recurse | Where-Object {$_.Length -eq 0} | Remove-Item」
「-recurse」パラメータでサブフォルダ以下も検索して削除 (Remove-Item) します。-eq (equal) は等しいことを示します。
PowerShellの変数
PowerShellでは「変数」を利用できます。プログラミングをしたことがある人ならおなじみですが、変数というのは一時的に文字列や数値、オブジェクトなどのデータをしまっておく箱だと思ってください。
コマンドプロンプトでも環境変数を利用できますが、文字列を代入できるだけです。PowerShellの変数はオブジェクトを代入できます。そのため利用範囲ははるかに広くなります。
PowerShellの変数の作り方としては、先頭に「$」を付けた任意の文字列で作成できます。また一度作成した変数は明示的に削除しない限りPowerShellのウィンドウが開いている間は保持されます。例えば次のように3つの変数を作成してそこに数値を格納してみます。
「$a=1」
「$b=2」
「$c=3」
これは”$a”、“$b”、“$c”という名前の箱をつけ、そこに1、2、3という数字を入れていることを意味します。これによって「箱」を使って計算が可能になります。
「$a+$b+$c」とすると、合計の6が表示されます。
「$a+$b*$c」なら7が表示されます。(乗算が加算より優先して計算されます)
「($a+$b)*$c」なら9となります。
PowerShellにはユーザーが作成する変数の他に、PowerShellが自動的に作成する自動変数もあります。現在設定されている変数の一覧は「Get-Variable」で確認できます。
自動変数の中で最もよく使う変数が「$_」です。先に示した「Get-ChildItem c:Windows | Where-Object {$_.Length -ge 1MB}」コマンドでも使っています。この「$_」変数にはパイプラインの前段の実行結果が格納されます。「$_」の後の「.Length」は「$_」からサイズ (Length) を取り出すための指定です。
PowerShellの関数
PowerShellでは関数が利用できます。プログラミングをしたことがないとあまり馴染みがないかもしれませんが、関数というのは、プログラムやコマンド呼び出して、そこに値を与えて何らかの処理を行い、そこで得られた結果を得るプログラムです。PowerShellではユーザーが簡単に関数を作成することができます。また、PowerShellがあらかじめ作成している関数もあります。作成されている関数の一覧は「Get-ChildItem Function:」で表示できます。
この一覧にあるように、これまでで紹介した「Help」コマンドや「More」コマンドも実は関数です。ちなみにWindowsには外部コマンドとしてhelp.exe、more.comがありますが、PowerShellで「Help」あるいは「More」として実行する場合は関数の方が実行されます。
関数の作成は次の書式で入力します。
Function [関数名] (引数1,引数2,・・・・){ 処理内容 }
先ほどの関数の説明で、「プログラムやコマンド呼び出して、そこに値を与えて何らかの処理を行い・・・」と書きましたが、値を関数に与えるためには、関数の構文の中に、この「引数」というものを書く必要があります。値を受け取るには、そこに箱を用意しておく必要があるのだ、という風に感じてもらえればと思います。引数は省略可能です。
では、例として「Get-ChildItem c:temp -recurse | Where-Object {$_.Length -eq 0} | Remove-Item」という先程のコマンドを「del0」という名前の関数にしてみましょう。
Function del0 { Get-ChildItem $args -recurse | Where-Object {$_.Length -eq 0} | Remove-Item }
作成した関数を実行するには「del0 c:temp」のように関数名(del0)を記述し、その後ろに削除対象となるフォルダ(c:temp)を引数として指定します。この引数が関数内の自動変数の「$args」に渡されて実行されます。
このように関数を使うと、定型処理の際に長いコマンドをその都度入力することなく簡単に実行できるようになりますので、PC操作が省力化されます。del0という関数を作っておき、あとは引数(ここではc:temp)の部分を変えるだけでいろいろと応用ができます。
なお、関数はPowerShellのウィンドウが閉じると消えますので、保存しておきたい場合はスクリプトファイルに保存するとよいでしょう。スクリプトについては次回の記事で解説します。
PowerShellでさまざまなリソースを操作する
PowerShellではファイルやフォルダだけでなくさまざまなリソースを操作できます。ハードウェアの情報やレジストリも操作できます。次のコマンドは、BIOS情報とCPU情報を取得し、dドライブ直下の「temp」というフォルダ内に今日の日付をファイル名にしたテキストファイルに保存します。
「$today = (Get-Date).ToString(“yyyyMMdd”)
Get-WMIObject Win32_BIOS > d:temp$today.txt
Get-WMIObject Win32_Processor >> d:temp$today.txt」
1行目では「Get-Date」コマンドレットで今日の日付を20181206 (2018年12月6日) の形式で取得し「$today」という名前をつけた変数に格納します。
2行目でBIOS情報を取得し、d:tempフォルダに [日付].txtのファイル名で書き込みます。「>」はリダイレクト記号で、同名ファイルがなければ新規作成し、同名ファイルがあれば上書きします。3行目でCPU情報を取得し、[日付].txtファイルに追加書き込みします。「>>」は追加書き込みのリダイレクト記号です。
「Get-WMIObject」コマンドレットでは、この他にドメイン情報「Win32_NTDomain」、共有フォルダ情報「Win32_Share」、物理メモリ情報「Win32_PhysicalMemory」、ハードディスク情報「Win32_LogicalDisk」インストールされたアプリケーション情報「Win32_Product」インストールされたHotFix情報「Win32_QuickFixEngineering」、Windowsの起動時に実行されるコマンド情報「Win32_StartupCommand」、アクティベーション情報「Win32_WindowsProductActivation」、サービス情報「Win32_Service」など、システムに関わるほとんどの情報が取得できます。なお、「Get-WMIObject」コマンドレットはWindows PowerShellでのみ利用できるコマンドレットで、残念ながらPowerShell Coreでは利用できません。
次のコマンドはネットワークアダプターの一覧を取得し、CSVファイル (d:tempnetadapter.csv) に書き込みます。「-Encoding Unicode」を指定しないと日本語が文字化けします。
「Get-NetAdapter | Export-Csv d:tempnetadapter.csv -Encoding Unicode」
次のコマンドはレジストリのキー (HKCU:softwaremicrosoft) を取得し、CSVファイル (d:tempregistry.csv) に書き込みます。
「Set-Location HKCU:SoftwareMicrosoft
Get-ChildItem | Export-Csv d:tempregistry.csv」
このように、PowerShellではシステムを管理するための機能が豊富に用意されています。しかも、ネットワーク経由で他のPCをリモート管理することも可能ですので、システム管理者にとってはなくてはならないツールです。リモート管理については別の機会に解説します。
PowerShellのスクリプトを作成
PowerShellのスクリプトは、PowerShellのコマンドなどの記述を1つのファイルに登録したもので、コマンドプロンプトのバッチファイルと似たようなものです。PowerShell自体がコマンドプロンプトよりはるかに豊富な機能を持っていることからPowerShellスクリプトでできることはバッチファイルをはるかに超えています
PowerShellスクリプトがどんなものか知ってもらうためにまず、指定のフォルダ以下のすべてのサブフォルダからファイルサイズ0の空ファイルを見つけて削除する関数「del0」(下記)をスクリプト化してみましょう。
※上記関数については『PowerShellのコマンドレット操作の応用』も参考にしてください。
“PowerShellのコマンドレット操作の応用”
https://www.pc-koubou.jp/magazine/14126
Function del0 { Get-ChildItem $args -recurse | Where-Object {$_.Length -eq 0} | Remove-Item }
上記をメモ帳などのテキストエディタにコピーして次のように書き換えます。
# サイズ0のファイルを削除するスクリプト dele0.ps1 # 引数の定義 Param ($path) # 関数del0の定義 Function del0 { Get-ChildItem $args -recurse | Where-Object {$_.Length -eq 0} | Remove-Item } # 関数del0の実行 del0 $path # 結果の表示 Echo “サイズ0のファイルを削除しました”
見やすいようにインデントと改行を加えています。また、「#」の後の文字列はコメントであり、PowerShellの実行では無視されます。インデント、改行、コメントものいずれも省略可能です。
メモ帳で作成したこのファイルを適当な名前(ここではdele0)を付け、拡張子を「ps1」に変更して保存します。なお、PowerShell Coreの場合は、保存の際に、「文字コード」を「Unicode」または「UTF-8」で保存しないと日本語の表示出力が文字化けします。
スクリプトを実行する
スクリプトを実行するには、PowerShell上で、絶対パスまたは相対パスを付けてスクリプト名(スクリプトのファイル名)を入力します。上記の場合、もちろんそれだけでは実行できません。サイズ0のファイルを削除する場所であるフォルダを指定する必要があるからです。そこでスクリプト名と一緒に該当のフォルダ名を記述してあげなければいけません。以下の例では引数として「c:test」を指定しています。また以下のように、スクリプトファイルがある場所によって記述は少し異なります。
例1:「c:temp」フォルダに、スクリプトファイル「dele0.ps1」があり、「c:test」フォルダ以下を検索して処理を行う(=「c:test」を引数として渡す)場合
c:tempdele0.ps1 c:test
例2:カレントフォルダに、スクリプトファイル「dele0.ps1」があり、「c:test」フォルダ以下を検索して処理を行う(=「c:test」を引数として渡す)場合
.dele0.ps1 c:test
なお上記2つは、拡張子の「.ps1」は省略して以下のように記述しても構いません。
c:tempdele0 c:test
.dele0 c:test
PowerShellでは、コマンドプロンプトと違って、スクリプトの場所としてデフォルトでカレントフォルダを検索しません。これはうっかり危険なスクリプトを実行してしまわないようにするためです。PowerShellのスクリプトはシステムの改変が可能なのでセキュリティ面からこうなっています。
スクリプト実行の制限とポリシー
また、Windows PowerShellでスクリプトを実行した場合に、次のようなエラーが表示されることがあります。
これはスクリプトの実行ポリシーでスクリプトの実行が禁止されているからです。スクリプトの実行ポリシーには次の5つがあります。
Restricted | すべてのスクリプトが実行禁止 |
AllSigned | 署名されているスクリプトのみが実行可能。署名されていないスクリプトは実行禁止 |
RemoteSigned | ローカルに保存されているスクリプトは実行可能。インターネットからダウンロードしたスクリプトは、署名されているもののみ実行可能 |
Unrestricted | すべてのスクリプトが実行可能。ただしインターネットからダウンロードしたスクリプトは、実行するかどうかを確認して許可した場合のみ実行される |
Bypass | 警告・確認なしにすべてのスクリプトが実行可能 |
Windows PowerShellのデフォルトは「Restricted」なので、上記のエラーが表示されるのです。一方、PowerShell Coreをインストールすると、デフォルトで「RemoteSigned」が設定されるため、エラーもなくスクリプトを実行できます。
「Get-ExecutionPolicy」コマンドレットを実行すると現在の実行ポリシーが確認できます。実行ポリシーが「Restricted」や「AllSigned」の場合は、ほとんどスクリプトが実行できないので、スクリプトをよく使うのであれば「RemoteSigned」に変更するとよいでしょう。「Unrestricted」や「Bypass」は危険なので設定しないでください。めったにスクリプトを実行しないのであれば、後で述べる「一時的にポリシーを変更してスクリプトを実行する」方法を使うのがよいでしょう。
実行ポリシーの変更は、管理者としてPowerShellを起動して、「Set-ExecutionPolicy RemoteSigned」コマンドレットで行います。「Set-ExecutionPolicy RemoteSigned」を実行すると本当に変更するかを聞いてきますので、「y」と入力して変更します。
一時的にポリシーを変更してスクリプトを実行する
実行ポリシーを変更しないままで、一時的にスクリプトを実行したい場合は次のコマンドを使います。
「PowerShell -ExecutionPolicy Bypass -Command c:tempdele0 c:test」
「PowerShell」はWindows PowerShellの実行ファイルであり、PowerShell Coreの実行ファイルは「pwsh」です。「-ExecutionPolicy Bypass」が実行ポリシーを「Bypass」に変更するオプションです。「-Command」は省略可能です。
これは、PowerShellの中から、もう1つ第2のPowerShellを起動して、指定した実行ポリシーの下でスクリプトを実行し、終了したら元のPowerShellに戻るという動作をしています。
スクリプトをショートカットに登録する
PowerShellスクリプトの実行方法には他の方法もあります。バッチファイルの場合は、エクスプローラなどからバッチファイル自体をダブルクリックすれば実行できます。しかし、PowerShellスクリプトはダブルクリックするとメモ帳が起動してしまい、実行はできません。これもセキュリティのために、誤って危険なスクリプトを実行してしまわないようにしているためです。
スクリプト自体のダブルクリックでは実行できませんが、ショートカットを編集すればダブルクリックで実行できるようになります。ダブルクリックで実行できるようになれば、いちいちPowerShellのコンソールを起動する手間が省けますので便利です。次にその方法を解説します。前提として実行ポリシーでスクリプトを実行可能にしておきます。
1 スクリプトファイルのショートカットを作成します。ショートカットの作成方法はエクスプローラでスクリプトファイルを右クリックして [ショートカットの作成] をクリックします。名前は適当な名前に変更してください。
2 作成されたショートカットを右クリックして [プロパティ] をクリックします。
3 「プロパティ」画面の「リンク先」欄の先頭に「PowerShell -noexit」と半角スペースを挿入します。「-noexit」オプションはスクリプトの実行が終了してもPowerShellコンソールを開いたままにするものです。これがないとダブルクリックしたときに一瞬コンソールが開いてすぐに閉じてしまいますので、結果が確認できません。結果を確認する必要がない場合は省略して構いません。
4 [OK] ボタンをクリックして「プロパティ」画面を閉じます。これでダブルクリックでスクリプトが実行できるようになりました。
さて、それでは試しにショートカットをダブルクリックしてみましょう。すると次の画面のようにエラーが表示されます。
このエラーの理由は、勘の良い方ならお気づきかもしれませんが、「引数」が指定されていないからです。ここでもう一度Part 2の「del0」関数の内容に戻ってみましょう。
「del0」関数では、実行時に処理対象のフォルダを指定することになっています。フォルダ指定すると、それを受けて関数の中に含まれている「$args」にそのフォルダ名が代入されて、無事処理が実行されるのですが、引数が指定されない場合は、「$args」変数に「null」(何もない) が代入されうまく処理できません。
「Get-ChildItem」コマンドレットのように、引数がない場合はカレントフォルダが指定されたものとみなして、カレントフォルダ以下を処理するなど、エラーが起きないものもありますが、引数を設定するならそのための値を渡す記述を書くというのを意識しておいたほうがよいでしょう。
今回はPowerShellを開かなくてもショートカットだけで使えるように、引数がない場合、このスクリプトをカレントフォルダが指定されたものとみなすように修正してみましょう。修正箇所は「Param ($path)」を「Param ($path = “.”)」と修正するだけです。
この意味は、引数が指定されない場合は、「$path」変数のデフォルト値として「.」(カレントフォルダ=スクリプトファイルのあるフォルダ) が代入されるという指定です。スクリプトをもう一度見ていただくと以下の記述がありますが、これが定義した「del0」を実行する記述です。
del0 $path
最初に示した例のように、もしPowerShell上で引数を指定して実行するならば、その指定した値が$pathの部分に代入されます。ここではそれを行わず、あらかじめスクリプト上に「Param ($path = “.”)」というように、$pathの部分に“.”が代入するように決め打ちにするということです。
もちろん違うフォルダにしたい場合別のものでも構いません。「.」の代わりに「d:」と指定すれば、d:ドライブが処理の対象となります。
フォルダのドラッグ&ドロップで引数を指定する
修正できたら、再度ショートカットを上記の手順で作成します。今度はショートカットをダブルクリックしてもエラーがなく正しく実行されます。ただ、このようにダブルクリックでは引数の指定ができないため、使い勝手はあまりよくありません。GUI画面で引数を指定する方法はないのでしょうか。実はそれがドラッグ&ドロップでできます。使い方は、引数で指定するフォルダ(=処理対象のフォルダ)をドラッグしてスクリプトのショートカットの上にドロップすればよいのです。この方法で引数を指定できます。実行結果は次のとおりです。
関数を使わなくてもスクリプトは作れる
これまで紹介したスクリプトは関数をスクリプト化することで説明してきました。これまで紹介したスクリプトの内容はかなり単純な処理でこのような処理の場合は、別に関数を使わなくてもスクリプトにできます。同じ処理を関数を使わずにスクリプトにしてみましょう。
それではなぜ今まで面倒なスクリプトを説明してきたのかというと、複雑な処理を行うスクリプトの場合は、中に関数を配置することが有効です。複雑な処理を単純な関数に分解して、その組み合わせで複雑な処理を行うようにすれば、スクリプトが見やすくなるだけでなく、複数のスクリプトに関数を使いまわしできたり、スクリプトの修正・変更もやりやすくなります。
次に、上のスクリプトをもう少し手を加えてみましょう。追加した点としては、削除したファイル数を表示するようにするものです。
このスクリプトでは、最初に削除対象のファイル数を「count」プロパティを使って数えて、その数を「$counted」変数に代入しておきます。その次に削除を実行し、最後にcountedに代入した値を表示するものです。
おわかりのように、「Get-ChildItem $args -recurse | Where-Object {$_.Length -eq 0}」コマンドを2度使っています。このように2度くらいでしたら、その都度書いても大した手間ではありませんが、これが何十回、何百回にもなると大変な手間です。その場合は「Get-ChildItem $args -recurse | Where-Object {$_.Length -eq 0}」コマンドを関数にしておけば、その都度書くのが簡単になります。スクリプトで関数を使うのにはそういったメリットがあるのです。なお改善したスクリプトのショートカットの実行結果は次のとおりです。
以上、PowerShellで実行したい処理をスクリプトとして保存し実行するための方法をご説明しました。同じ処理を定期的に実行する必要がある場合などは、このような形でPowerShellを使うことと効率的になるのでぜひ活用してみてはいかがでしょうか。
[ネクスマグ] 編集部
パソコンでできるこんなことやあんなこと、便利な使い方など、様々なパソコン活用方法が「わかる!」「みつかる!」記事を書いています。