Home > Windows にまつわる e.t.c.

SendTo を処理する PowerShell スクリプトの作り方


SendTo でファイル名を受け取って処理をするスクリプトを書きました。

 

色々悩んだ所もあるので、まとめておきます。

まず何を作ろうとしたかというと、「送る」で指定したファイルのフルパスを <file://...> みたいな感じにしてクリップボードに転送するってスクリプトを書きたかったのです。

これは、ファイルの存在場所を共有する目的なので、subst でドライブ割り当てされたファイルサーバー上のファイルを指定した場合は、UNC フルパスにしたいです。

更に、ショートカットの場合は、リンク先にしないといけません。

これを実装するためには、以下の課題を解決する必要があったので、その解決方法を解説します。

解決すべき課題

・ .ps1 をどう起動するか
・ SendTo からファイル名をどう受け取るか
・ 実行時の PowerShell Window をどうするか
・ どうやってインストールするか
・ All Users にどうやって展開するか

おまけ課題

・ ドライブマウントされたネットワークドライブを UNC フルパスにする
・ ショートカットの場合、リンク先を対象にする
・ 日本語をクリップボードに転送する
・ ネットワークドライブを UNC にする

 

.ps1 をどう起動するか

.ps1 を SendTo フォルダに置くのはみっともないので、スクリプトを実行するショートカットを SendTo フォルダ に置きます。

実行コマンドラインは、タスクスケジューラで .ps1 を組み込み時にも使うテクニックなので、ご存知の方も多いですよね。

SendTo で叩かれるのはコマンドプロント相当なので、実行コマンドライン(リンク先のフィールド)で powershell.exe を指定し、その実行ファイルとして .ps1 を指定します。

powershell -File "hogehoge.ps1"

(-File オプションは省略可能)

 

確実に動かすために、powershell.exe と .ps1 はフルパスを指定するのがセオリーです。

powershell.exe のフルパスを取得するには、僕は where コマンドを使っていますが、「where」をそのまま使うと Where-Object と誤認識されるので、「cmd /c」でコマンドプロンプトを呼び出すって手を僕はよく使います。

$PowerShellFullPath = cmd /c where powershell

 

SendTo からファイル名をどう受け取るか

SendTo で選択されたファイルは $args 配列に格納されていますので、これを分解します。

例えばこんな感じ

foreach( $arg in $args ){
    # ここに処理を書く
}

 

実行時の PowerShell Window をどうするか

SendTo で PowerShell を起動すると、コンソールアプリの仕様で .ps1 実行の間 PowerShell Window が開いてしまいます。

.vbs だとこの制限を回避できるのですが、なんだか負けた気がする(.vbs から移植したかった)ので、別の手として最小化して実行することにしました。

 

タスクバーに PowerShell アンコンが表示されますが... これは見なかった事にしてもらうってことで(苦笑)

最小化実行は、SendTo を受け取るショートカットで指定できるので、具体的な方法は後述のインストーラー作成で解説します。

 

どうやってインストールするか

実行するショートカットを SendTo フォルダに作ると、「送る」として表示されるようになります。

このフォルダをエクスプローラーで開くには「shell:sendto」で開く事が出来るので、ここにショートカットを置けばいいのですが、ここは GUI ポチポチではなく インストール用の .ps1 でやりたいですよね。

ショートカットを作りるには、WScript の力を借りなくてはいけないのですが、PowerShell の良いところは WScript もハンドリング出来るので、ショートカットを作るのも PowerShell で可能です。

こんな感じですですね。

# WScript オブジェクトを作る
$WsShell = New-Object -ComObject WScript.Shell

# ショートカットの Path
$Shortcut = $WsShell.CreateShortcut("ショートカットの Path")

# 実行プログラム
$Shortcut.TargetPath = "powershell.exe のフルパス"

# 引数
$Shortcut.Arguments = "powershell.exe へ渡す引数"

# アイコン
$Shortcut.IconLocation = $PowerShellPath

# 実行時の大きさ(1:通常/2:最大/7:最小)
$Shortcut.WindowStyle = 7

# ショートカットの保存
$Shortcut.Save()

 

SendToフォルダパスは、環境変数 %APPDATA% + "\Microsoft\Windows\SendTo" なので、以下のようにするとフルパスが得られます。

$SendToDirectory = Join-Path $env:APPDATA "\Microsoft\Windows\SendTo"

 

インストールした「送る」の SendTo を取り除くのは、ショートカットを削除するだけです。

 

All Users にどうやって展開するか

残念ながら、これは断念しました。

All User の振る舞いをコントロールしているディレクトリは、「HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\User Shell」で定義されいるのですが、ここに SendTo の設定が無いんですよね... orz

レジストを追加すればイケそうな気もしましたが、そこまでの深追いはやめました。

 

ドライブマウントされたネットワークドライブを UNC フルパスにする

ここから先は、今回僕が書いたスクリプト特有の課題ですので、SendTo を処理するには不要な話ですが、せっかく書いたのでまとめを...

 

subst コマンドでドライブマウントされたネットワーク共有の UNC は Get-PSDrive の DisplayRoot でえられますので、こいつを使ってドライブレターを UNC で置き換えれば、UNC ブルパスにする事が出来ます。

 

ショートカットの場合、リンク先を対象にする

ショートカットを SendTo した時は、ショートカットが指し示している先にしたいですよね。

そんな時も WScript の力を借りてリンク先を得ます。

本筋な話では無いので、詳細は割愛しますが、具体的な方法を知りたい場合は、リポジトリ公開しているスクリプトを見てください。(function GetLink)

 

日本語をクリップボードに転送する

クリップボードに任意の文字列を送るのは、clip.exe コマンドを使うと簡単に実装できます。

が... clip.exe は S-JIS を受け取る想定なんですよね。

このため UTF-8 文字コードの PowerSehll 出力をそのまま clip.exe に渡すと日本語が化けてしまいます。

この問題を解決するには、一時的にエンコードを S-JIS に変更します。

# エンコードを S-JIS に変更
$OutputEncoding = [Console]::OutputEncoding

# リップボードへ
"日本語文字列" | clip

# エンコードを US-ASCII に戻す
$OutputEncoding = New-Object System.Text.ASCIIEncoding

 

実装サンプルリポジトリ

https://github.com/MuraAtVwnet/Conv2UNC

git@github.com:MuraAtVwnet/Conv2UNC.git

 

関連情報

Powershell で文字コードを変更する(clip.exe へのリダイレクトもね)
http://www.vwnet.jp/windows/PowerShell/CharCode.htm

 

back.gif (1980 バイト)

home.gif (1907 バイト)

Copyright © MURA All rights reserved.