Powershell」カテゴリーアーカイブ

Powershellでパスを結合する

Powershellを使っていると良くあるのがパスとフォルダ名や、パスとファイル名を結合するという場面です。ほとんどの場合パスやファイル名は変数に格納されているので、結合する時に少々工夫が必要になります。

例として、パスが”C:\hoge”でその中に格納された”piyo.txt”というファイルを開くコードを考えます。そのままパスとファイル名を結合すると間に\が無くて動かないので、何らかの方法で\を入れる必要があります。

力技

単純に文字列結合で行うのであればこんな感じになります。

[Powershell]
###パスとファイル名を結合して実行するスクリプト###
#パス変数
$Path = 'C:\hoge'

#ファイル名変数
$Filename = 'piyo.txt'

#パス結合
$Fullpath = $Path +'\'+ $Filename

#ファイル実行
#Invoke-Item $Fullpath

やっていることの分かりやすさという点では良いと思うのですが、結合する対象が3つ以上になると可読性が著しく悪くなるという難点があります。

Microsoft Learnのドキュメントに参考になる情報があったので、これを見ながら改良してみます。

文字列での変数の代入について知りたかったことのすべて

[Microsoft Learn]

変数を置換して結合

変数が含まれる場合でも、二重引用符でくくることによって変数を置換しつつ文字列結合を行うことができます。

最初のコードを書き換えるとこんな感じになります。

[Powershell]
###パスとファイル名を結合して実行するスクリプト###
#パス変数
$Path = 'C:\hoge'

#ファイル名変数
$Filename = 'piyo.txt'

#変数の置換を使ってパス結合
$Fullpath = "$Path\$Filename"

#ファイル実行
Invoke-Item $Fullpath

必ず二重引用符を使う必要があるというところがちょっと難しいですが、可読性という点では良いのではないかと思います。

Join-Pathコマンドを使う

パス結合用のコマンドがあるので、これを使う方法もあります。ドキュメント内で触れられている通り、この方法は\マークのことを気にしなくていいのが便利です。

[Powershell]
###パスとファイル名を結合して実行するスクリプト###
#パス変数
$Path = 'C:\hoge'

#ファイル名変数
$Filename = 'piyo.txt'

#Join-Pathコマンドを使ってパス結合
Join-Path -Path $Path -ChildPath $Filename

#ファイル実行
Invoke-Item $Fullpath

文字数的には冗長になりますが、パスを結合していることが明瞭なので分かりやすさはかなり優れていると思います。

○○について知りたかったことのすべてシリーズはオススメ

Microsoft LearnにKevin Marquette氏が書いているブログエントリが”○○について知りたかったことの全て”という題名で掲載されているのですが、いずれも非常に参考になります。

powershellexplained.com

[powershellexplained.com]

リファレンスほど難解ではなく、Kevin氏の私見も交えてコマンドや構文が紹介されているので今まで知らなかった記述方法やコマンドを知ることができます。

PowershellでTPMの情報を調べる

Windows11の動作要件になったことからよく知られるようになったTPM(Trusted Platform Module)ですが、PCに搭載されているのか、有効になっているのかなどの情報がPowershellで調べられることを最近知りました。

Get-Tpm

[Microsoft Docs]

コマンドレットは非常に簡単で、 Get-Tpm と入力するだけです。Powershellは管理者モードでないとこのコマンドレットが使えないのでその点だけは注意が必要です。

TPMの搭載/非搭載のほか、有効になっているかなどの情報を調べられます。Powershellですのでログオンスクリプトに組み込んで、組織内のPCのTPMの状態をまとめて調査するなんていうこともできそうです。

Powershellでアプリケーションのインストールを検出する

最近アプリケーションのインストール有無を検出して、その結果に応じて違う処理を行うという用事がありました。Powershellで自動的に判定と処理が行えたのでまとめておきます。

アプリケーションのインストール有無を検出する方法はいくつか考えられましたが、最も単純な”そのアプリケーションの実行ファイルが存在するか否か”を検出することにしました。

Test-Pathというコマンドレットがパスやファイルの有無を検出するのに使えそうだったので、以下のようなスクリプトにしてみました。

<Powershell>
#C:\Program Files\hoge\hoge.exeの検出
$Appexist = Test-Path 'C:\Program Files\hoge\hoge.exe'

#検出結果による分岐
if($Appexist -eq $true){
 #存在した時の処理
}else{
  #存在しなかった時の処理
}

こんな感じで大丈夫でした。Test-Pathの結果を変数に格納すると、パスやファイルが存在した場合はTrue、存在しない場合はFalseが代入されます。

Test-Pathはパス以外にも今回のように個別のファイルやレジストリエントリの存在も検出できるそうなので、かなり応用が利きそうなコマンドレットです。

Windows11のターミナルをPowershell7にする

このエントリを書いている時点での最新版のPowershellはバージョン7.2となっています。インストーラによるインストールや、コマンドのwingetによりインストールすることができます。

Windows への PowerShell のインストール

[Microsoft Docs]

Powershell7をインストールしても、スタートボタンから起動するWindowsターミナルでは従来のPowershell5系統のものが起動します。

Powershell7を起動する度にスタートメニューから選ぶのは面倒だと思っていたのですが、WindowsターミナルでPowershell7を起動する設定がありました。

設定方法は以下の通りです。

  1. Windowsターミナルを起動する
  2. キーボードで Ctrlキーと,キーを同時押しする
  3. ターミナルのオプション画面が開くので既定のプロファイルをPowershell7にする

Windowsターミナルの設定画面がWindowsの”設定”の中にあるのかと思っていましたが、そうではないようです。

Powershell5もWindows10と同時の登場で、当時は目新しさもありましたが気づけばリリース後7年近い年月が経っています。最新版にしておいた方が何かとトラブル回避にもなるのではないかと思います。

コマンドプロンプトでドライブを移動する

コマンドプロンプトでディレクトリを移動する際にはcdコマンドを使います。通常コマンドプロンプトを起動するとカレントディレクトリは”C:\Users\[ユーザ名]”になっています。

ここからカレントディレクトリを例えば”C:\hoge”にしたい場合、

[command prompt]
cd C:\hoge

と入力してEnterキーを押せばOKです。

Dドライブにも同様にhogeというフォルダがある場合、C:\hogeの部分をD:\hogeにすれば良さそうなのですが、この入力だとディレクトリを移動できません。ドライブに変更が加わる場合は/dオプションをつけて、

[command prompt]
cd /d D:\hoge

とすればOKです。

結構長いことコマンドプロンプトを触っているつもりでしたが、この操作は最近まで知りませんでした。コマンドを打ち込むときには大体Cドライブに用事があるからなのかもしれません。

ちなみにPowershellの場合は別ドライブであってもcdコマンドのみで移動ができるので簡単です。

【参考情報】

cd|Microsoft Docs

[ Microsoft Docs ]

Powershellによるファイルのリネーム

画像や音楽データを整理していると、一括でファイル名を変更したくなる場面があります。

私の場合はかつて採用していたファイル命名ルールに問題があることが分かり、新しく決めたファイル命名ルールに更新したくなるというケースが多いです。

リネーム用ツールなども色々あるとは思うのですが、柔軟に運用できるという点でこういう時はPowershellの出番です。

Powershellによるファイルのパラメータ取得

Powershellでリネームを行う場合は”Get-Childitem”コマンドレットを使うのが一般的ではないかと思います。このコマンドレットはフォルダ内のファイルのパラメータを一括取得してくれます。私はもっぱらファイルやフォルダの処理に使いますが、レジストリハイブや証明書ストアにも使えるそうです。

今回はC:\Photoに入っているyyyymmdd.jpgという命名ルールで名前のついている画像データをyymmdd.jpgに変更するという場面を想定します。

まず、フォルダ内のjpgファイルの情報を取得するには以下の通りの記述でOKです。

[Powershell]
Get-Childitem "C:\Photo" *.jpg

拡張子を指定するとその拡張子に当てはまるファイルだけのパラメータを取得できます。

Powershellによるパイプライン接続

次にリネーム処理を行うためのパイプライン接続を行います。パイプラインというのはちょっと難しそうですが、連続した処理を行う際に1つ目の処理と2つ目の処理を接続する役割を果たします。

例えば、 フォルダ内のファイル名を取得する→特定のファイル名でフィルタする→結果をcsv出力する といった処理があった場合、矢印部分にパイプライン処理が使われます。記述は簡単で、専用の演算子”|”を入れるだけです。

Powershellによるリネーム

リネームを行います。取得されたファイル名のデータはパイプライン経由で使用できます。パイプライン経由のデータは自動変数”$_”に格納されているので、この変数に対して処理を行えば大丈夫です。

ファイルのリネームの場合は”Rename-Item”コマンドレットが使えます。コードはこんな感じになります。

[Powershell]
Get-Childitem "C:\Photo" *.jpg | Rename-Item -NewName {$_.Name -replace "20", ""}

自動変数のNameパラメータに対して”20″を””(空)に置き換える処理を行っています。

続きを読む

PowershellによるCSVファイルからのデータ抽出

CSV形式のデータから特定の文字列を含む行だけ取り出す必要が生じた場合、通常はExcelで読み込んでオートフィルタで抽出するのがお手軽だと思いますが、

  1. データ量がExcelで取り扱うには多い
  2. 抽出条件が複雑
  3. 作業を行うPCにExcelがない

などといった理由からPowershellを使ってデータ抽出をすることがあります。

例えば下のようなCSVデータがあったと仮定して、ここからデータ抽出を行います。

PowershellにはCSVのインポート/エクスポートを行うコマンドレットがあるので、入出力はこれでOKです。

データ抽出にあたってはインポートした内容を変数に格納し、Where-Objectコマンドレットで抽出します。これは正規表現が使えるので、複雑な抽出条件も設定できます。

下のスクリプトはCSVから駅名に”信濃”を含む行を取り出して、CSVと同じフォルダに”result.csv”として出力するものです。

#Powershell
#CSVがあるディレクトリに移動
Set-Location 'C:Users\hoge\csv'

#CSV読み込み
$csv = Import-Csv .\nagaden.csv -Encoding Default

#データを抽出("信濃"を含む駅名のみ抽出)後、CSV出力
$csv | Where-Object {$_.駅名 -match '.*信濃.*'} | Export-Csv ./result.csv -Encoding Default -NoTypeInformation

結果はこうなりました。

Powershellの地味にありがたいところはWindows10には絶対入っているということです。突然借りたPCでも基本的には使えるので、突発的にアドリブで何かしなくてはならない時に助かっています。

Powershellのエスケープシーケンス

Powershellで文字列を整形するときに、タブの取り扱いに苦労していました。
例えばタブが含まれる文字列からタブ部分を置換して除去できると良いのですが、その方法が良く分かっていませんでした。

Powershellは以下のドキュメントにある通りの特殊文字シーケンス(いわゆるエスケープシーケンス)を認識してくれるため、これを使えば特殊文字を含む文字列操作が可能だそうです。

特殊文字について

[Microsoft Docs]

改行コード(`n)とキャリッジリターン(`r)もあるので、LFとCRLF間での改行コード変換なんかもこれで大丈夫そうです。

UWPアプリをPowershellでアンインストールする

Windows10にはストアでダウンロードできるUWPアプリ(ストアアプリ・モダンアプリとも)がありますが、Windowsに付属しているアプリは”アプリと機能”でアンインストールすることができません。

Powershellを使うとアンインストールすることができます。限界まで不要なアプリをそぎ落としたい時や、付属のUWPアプリの再インストール時に便利です。

アプリの名前を調べる

アプリのアンインストールにあたって、最初にPowershellで指定するアプリの名前を特定する必要があります。

まず、PC内のUWPアプリ一覧を以下のPowershellスクリプトで表示します。

[Powershell]
Get-AppxPackage | Select-Object -Property Name

アプリケーション名が列挙されるので、それらしい物を探します。今回は”フォト”を例に使ってみようと思います。

名前からして”Microsoft.Windows.Photos”で間違いなさそうですが、本当にこの名前がフォトを指しているのかどうかを念のため確認します。

アプリの名前を確認する

以下のPowershellスクリプトを実行します。

[Powershell]
$PackageFamilyName = (Get-AppxPackage Microsoft.Windows.Photos*).PackageFamilyName

$AppID = (Get-AppxPackage -Name *Microsoft.Windows.Photos* | Get-AppxPackageManifest).Package.Applications.Application.Id[0]

$Run = "Start-Process shell:AppsFolder\" + $PackageFamilyName + "!" + $AppID
Invoke-Expression $Run

スクリプト中の”Microsoft.Windows.Photos”の部分は調査したいアプリに応じて読み替えてください。

このスクリプトを実行して、アンインストールしたいUWPアプリが起動すればOKです。アプリの名前についてはネット上にも色々情報があるので、それらを参考にするのも良いと思います。

アプリのアンインストール

先ほど確認したアプリ名を使って、以下のスクリプトを実行します。

[Powershell]
Remove-AppxPackage -Package "Microsoft.Windows.Photos"

これでアンインストールが行われます。

アプリの再インストール

UWPアプリの再インストールはMicrosoftストアから再度インストールすればOKです。

参考情報

UWP アプリを PowerShell から起動する

[MURA’s HomePage 様]

こちらの情報を参考にさせていただきました。ありがとうございました。

自己昇格するバッチファイルを作成する

PCにあまり詳しくない人にバッチファイルを実行してもらう時に困るのが、”管理者実行”の問題です。コマンドの内容によっては管理者権限で実行しないといけないものもあるのですが、事前に説明しておいても右クリックして管理者実行してもらえないというケースがよくあります。

ネットで調べてみると、バッチファイルの書き方次第ではバッチファイル自身が権限を昇格してコマンドを実行できるような書き方ができるようなので、試してみました。

管理者権限の判定

今バッチファイルが管理者権限・ユーザ権限どちらで実行されているかを判断するには、openfilesコマンドを使います。

このコマンドは現在開かれている共有フォルダや共有ファイルを列挙するコマンドなのですが、管理者権限がないと実行できません。

ユーザ権限で実行した場合は変数errorlevelに1、管理者権限で実行した場合は0が格納されるので、これを権限の判定に使用します。

自己昇格

自分自身の権限を昇格して実行するには、powershellの力を借ります。powershellでよく使う”start-process hogehoge -verb runas”という管理者でプロセス実行する文がありますが、ここで実行するプロセスにコマンドプロンプトの変数である”%~0”を使用します。

%~0はバッチファイル自身を意味する変数で、これにより自分自身を再度管理者権限で実行することができます。

表示上の一工夫

最初に権限確認のため実行するopenfilesですが、実行結果が1枚目のコマンドプロンプトに表示されてしまいます。ちょっとうっとうしいのでこれを表示させないために、結果を標準ログにまとめて捨ててしまいます。

記述としては”openfiles > NUL 2>&1”となり、”2>&1”の部分が「エラーログを標準ログにまとめる」の意で、”>NUL”の部分が「出力を捨てる」という意味合いになります。

なので、口語に直すと「openfilesの出力を捨てる。ただし、エラーログと標準ログはまとめる」といった感じになります。ちなみに”>NUL”と”2>&1”の順序を逆にすると普通に結果が画面に出力されてきますのでご注意下さい。

できあがったバッチファイル

[bat]
@echo off

rem openfilesを実行して実行権限を判定できる数値をerrorlevelに格納する
rem このopenfilesの結果はウインドウに出力しない
openfiles >NUL 2>&1 

rem errorlevelの値が1(ユーザ権限)だった場合は管理者権限により自身を再実行
if %errorlevel% equ 1 (
	powershell start-process %~0 -verb runas
) else (
	rem 実行したい処理(例としてopenfiles)
	openfiles
)

参考情報

こちらのサイトの情報が大変参考になりました。ありがとうございました。

How to check in a batch file if you are running it elevated

[winaero.com]