FC2ブログ

PowerShellでトラックバックを送信するスクリプト

私事で年一回程度、トラックバック送信機能を持たない静的なHTMLのページをトラックバック送信しなければならないことがあります(スパム目的ではない)。
そういう場合は、JavaScriptで記述された汎用のトラックバック送信フォーム等を使うことになるのですが、JavaScript製の場合はUser-Agentをトラックバック用に変えておかないと相手に受信してもらえないことが多いようです。PHPやPerlで書かれたものと思われる送信フォームもあるのですが、よそ様のサイトのサーバーを経由して送信するというのはちょっと気が引けます。
わざわざブラウザのUser-Agentを変えるのも面倒だし、PowerShellを使ってトラックバックを送信するスクリプトを書いてみました。形式はTrackBack Technical Specificationのものを参考にしましたが、User-Agentに関する仕様が書いていないので、"TrackBack/1.0"を名乗っています(UAのバージョン番号によっては.htaccessで弾くブログもあるらしいので、もっとちゃんとした名前のほうがいいかも)。あと、例外処理とかはしてません。


#trackback.ps1 -ping_url 相手のトラックバックURL -title 自分の記事のタイトル -excerpt 記事の要約 -url 自分の記事のURL -blog_name 自分のブログのタイトル

param($ping_url,$title,$excerpt,$url,$blog_name)

[void][System.Reflection.Assembly]::LoadWithPartialName("System.Web")
$encoded_title=[System.Web.HttpUtility]::UrlEncode($title)
$encoded_excerpt=[System.Web.HttpUtility]::UrlEncode($excerpt)
$encoded_url=[System.Web.HttpUtility]::UrlEncode($url)
$encoded_blog_name=[System.Web.HttpUtility]::UrlEncode($blog_name)

$request=[System.Net.HttpWebRequest][System.Net.WebRequest]::Create($ping_url)
$request.Method = "POST"
$request.ContentType = "application/x-www-form-urlencoded; charset=utf-8"
$request.UserAgent="TrackBack/1.0"
$data="title=$encoded_title&excerpt=$encoded_excerpt&url=$encoded_url&blog_name=$encoded_blog_name"
$buffer=(new-object System.Text.ASCIIEncoding).GetBytes($data)
$request.ContentLength=$buffer.Length
$stream=[System.IO.Stream]$request.GetRequestStream()
$stream.Write($buffer,0,$buffer.Length)
$stream.Close()
$response=[System.Net.HttpWebResponse]$request.GetResponse()
$sr=new-object System.IO.StreamReader($response.GetResponseStream())
$response_result=$sr.ReadToEnd()
$sr.Close()
Write-Host $response_result



これで、
./trackback.ps1 -ping_url "http://kakikukekou.blog83.fc2.com/tb.php/483-0d08108a" -title "ようこ
そバーボンハウスへ" -excerpt "このテキーラは私のオゴリだ" -url "http://www.barbonhouse.gov/" -blog_name "バーボンハウス"
と記述すればそういう内容のトラックバックが送られる……はずなのですが、fc2ではどうもトラックバック避けが厳しいらしく、以下のようなレスポンスが返ってきてしまいます。

<?xml version="1.0" encoding="utf-8" ?>
<response>
<error>1</error>
<message>Error: Forbidden Your Blog (Black List)</message>
</response>

多分、言及リンクが要約に書いていないとか、自分の記事のURLに問題があるなどの理由が考えられます。
スポンサーサイト



PowerShellでGMailにファイルを送るスクリプト

前回の続き。OutlookExpressで同じHTMLのファイルを添付して送ってみたところ、ちゃんとGMail上では検索できることがわかりました。ヘッダー情報を見てみると、どうやらContent-typeを設定していなかったのが拙かったようです。
そういうわけで、以下のように記述したところ、GMailにファイルを送信することができました。

#Send2GMail.ps1
param($item) #$item=送信するファイルのパス

$gmail_address="ほげほげ@gmail.com" #GMAILの送信先アドレス
$gmail_password="GMAILのパスワード" #GMAILのパスワード
$txtfile_extensions="txt|log" #BODYのみに文字列を出力する拡張子
$htmlfile_extensions="html|htm|xhtml" #「ContentType=text/html;」な添付ファイルを送る拡張子

$msg=new-object System.Net.Mail.MailMessage
$msg.From=new-object System.Net.Mail.MailAddress($gmail_address)
$msg.To.Add($gmail_address)
$msg.Subject=$item
if ($item -match "^.*\.(" + $txtfile_extensions + ")$")
{
$msg.Body=get-content $item
}
else
{
$atc=new-object System.Net.Mail.Attachment($item)
if ($item -match "^.*\.(" + $htmlfile_extensions +")$")
{
$atc.ContentType=new-object System.Net.Mime.ContentType("text/html;")
}
$msg.Attachments.Add($atc)
}
$mailer=new-object System.Net.Mail.SmtpClient("smtp.gmail.com",587)
$mailer.EnableSsl=$True
$mailer.Credentials=new-object System.Net.NetworkCredential($gmail_address,$gmail_password)
$mailer.Send($msg)


PowerShell上で、
./Send2GMail.ps1 目的ファイルのパス
とすれば、多分送信してくれると思います(Set-ExecutionPolicyの設定をしていない場合は、スクリプトを実行できるように予め設定しておく)。
SMTPサーバーにはGMAILのものを使っており、FromもToも同じアドレスになります。また、パスの値がSubjectに設定されます。テキストファイルの場合はBodyに内容が出力され、それ以外の場合は添付ファイルになります。
HTMLの処理のあたりとかは多分もっといい方法があるのではないかと思いますが、あんまり詳しくないのでわかりません。
Hey, Scripting Guy!Windows PowerShell を使用してドライブ上のすべての _TMP ファイルを削除する方法はありますかの記述を応用して、
get-childitem c:\ -include *.txt -recurse | foreach ($_) {./Send2GMail.ps1 $_.fullname}
みたいにすれば、Cドライブ上にある全てのテキストファイルをGMailに送ったりすることもできます(時間がかかるので止めた方がいいと思いますが)。

情熱に枯れました

PowerShellでファイルをGMailに送るスクリプトを書いたのですが、HTMLファイルの場合だとなんだかうまくいきません。
「ローカルにあるファイルを列挙してGMailに送り、GMail上の検索機能をgrepの代わりにしよう」という目論みで、最初は「テキストファイルだったらメールのBodyに内容を出力し、そうでないものは添付ファイルに添付する」という風にしたのですが、こうするとHTMLファイルを添付したときにその中を検索できない場合がありました。
これを解消するために、HTML形式の場合はHTMLからタグを除去したものをBodyに出力するようにしたのですが、文字化けしてしまってダメでした。それ以外の問題は完全にクリアできているようなので、あとちょっと弄くれば何とかなりそうな気もするのですが、正直このごろ忍耐力が無くて、だんだん飽きてきました。飽きてくると加速度的に仕事が遅くなりますorz。
多分既に他の人が同じようなことをやっているだろうというのもあって、昔はそういう場合でも自分で何とかしてみせるぞーとか思っていたのですが、最近はもう面倒くさがりというか、そういう情熱に枯れてしまいました。私事でサーバー関連の勉強とかもしなければダメで、本当はWebサーバーを実際に立てたりするべきなのですが、なんだかこれも今ひとつ有効な利用目的が見出せずやる気が出ません(昔だったら利用目的とか全然考えずにそういうことをやっていただろうと思う)。贅沢病。
それにしてもまた米国株下がっていますね。月曜日も自動売買を仕掛けない可能性が出てきました。

Windows PowerShellは面白そう

2chのム板を見ていたらWindows PowerShellという新しいシェルに関するスレが立っていて、かなり面白そうだったのでインストールしてみました。
このシェルはドライブの概念が拡張されていて、物理ドライブだけじゃなく、レジストリや環境変数などもあたかもドライブとして扱うことができます(「プロバイダ」と呼ぶらしい)。SQLのプロバイダをインストールすれば、データベース内をcdやdirで歩いていくこともできるみたいです
また、コマンドラインで.NETのオブジェクトを扱うことができたり(例えばWebClientクラスを呼び出してWebサイトからデータをダウンロードできたりする)、結果をXMLやCSV形式で出力する機能も付いています。
CSVのインポートはUnicodeじゃないと文字化けするみたいですが(詳しいことはよく知らない)、文字コードを変換する機能も備わっているので、Shift-JISなCSVファイルは一旦Unicodeに変換すればインポートできます。
試しに、
22日の日足のごく一部
みたいな形式のCSVファイルを、
gc hoge.csv | set-content temp.csv -encoding unicode
としてUnicode化したCSVファイルを作り、
import-csv temp.csv | select-object Code,Name,Close,Volume | export-csv Piyo.csv -encoding default -notype
とすると、もとのCSVファイルから、CodeとNameとCloseとVolumeの列だけを抽出したCSVを得ることができました(もっと簡単に書けるかも)。select-objectのところをwhere-objectにすれば、特定の値を持った行だけを抽出することもできるはずです。データマイニングの前処理に使うこともできるかも。

参考スレ
[プログラム板]PowerShell
[Windows板]Windows PowerShell (正式版リリース)1.0