カテゴリ:TIPSとかKludgeとか( 23 )

ASP.NETでFCKEditorを使う覚え書き

ここではMicrosoft Visual Web Developer 2008 Express Editionで、IISは使用せずWeb Developer 2008組み込みのWebサーバを使用するものとする。
  1. 本家サイトダウンロードページから、最新のZIPファイル(本項記述時点ではFCKeditor_2.6.2.zip)とFCKeditor.Net(FCKeditor.Net_2.5.zip)をダウンロード。
  2. それぞれ展開する。
  3. デフォルトではIISに専用の仮想ディレクトリを作成するが、IISは使わないのでここではプロジェクトのWebサイトの下に配置する。
  4. FCKeditor_2.6.2.zipを展開したディレクトリ(FCKeditor)をまるごとプロジェクトのWebサイトの下にコピーする(_(アンダーバー)付きのファイル・ディレクトリ、使用しないスキンは省ける)。
  5. プロジェクトのWebサイトにbinディレクトリを作成する。
  6. FCKeditor.Netを展開したディレクトリの\bin\Release\2.0にあるFredCK.FCKeditorV2.dllをbinディレクトリに配置する(bin右クリック→「既存項目の追加」で展開したFredCK.FCKeditorV2.dllを指定すると、binにコピーされる)。
  7. FredCK.FCKeditorV2.dllを参照追加。
  8. 必要であれば、ツールボックスにも追加(「ツールボックス」→右クリック→「アイテムの選択」→「.NET Frameworkコンポーネント」で「参照」ボタン→FredCK.FCKeditorV2.dllを指定。ただしこれをやるならFredCK.FCKeditorV2.dllはサイト配下のbinではなく適切な共通ディレクトリの方がよかろう)
  9. 組み込みたいページの先頭に、
    <%@ Register Assembly="FredCK.FCKeditorV2" Namespace="FredCK.FCKeditorV2" TagPrefix="FCKeditorV2" %>
    を追加。
  10. さらにコントロールのコード
    <FCKeditorV2:FCKeditor ID="FCKeditor1" runat="server" BasePath="fckeditor/" Height="400px"></FCKeditorV2:FCKeditor>
    を追加(BasePathがデフォルトだと"/fckeditor/"なので、アタマの/を除外)
  11. 念のため、fckeditor/fckeditor.jsのFCKeditor.BasePath = '/fckeditor/'のアタマの/もとっておく。
  12. ページをビルドして確認(BasePathの設定がおかしいとhttp 404が出る)。
プログラム中ではFCKeditor1.Valueで入力内容が参照できる。

ただしナマのデータなので、そのまま使おうとすると局面によってはASP.NETがValidateRequestで引っ掛けてHttpRequestValidationException する場合がある。開発時には@pageでValidateRequest="false"にしておくとかすると便利かも(外し忘れると大変だが)。
[PR]
by SIGNAL-9 | 2008-07-10 14:13 | TIPSとかKludgeとか | Comments(0)

PDFの連続印刷

 …というお題でぐぐっても結構な数がヒットするし、解決方法はいろいろあるようだ。フリーウェアでよさげなものもある。

 車輪の再発明というのは基本的に行わないのだが、金の絡んだ頼まれ仕事だと、「フリーウェア使って!」つーわけにもいかなかったりするし、事前・事後処理が必要だったりもするので、仕方が無いので自前でナントカすることにした。

 のだが。
 Webを漁ってみると、どうも思ったとおりにいかないという記録も多い。
 結局、引っかかるところはみな同じなわけである。

 対象ファイルがひとつふたつならいいのだが、数千ファイル想定の連続印刷の場合、前の印刷が完了してから、次の印刷を開始しないとキューが溜まり過ぎて破綻する恐れがある。
 特に俺の場合、後流でキューファイルを操作する必要があり、できれば「溜めたく」ない。

 またできるだけ安価にやりたいので、Acrobat Readerを使って…というセンが真っ先に思いつくが、コイツがなかなか難物である。
 Adobeのドキュメントを読むと、AcroRd32.exeにはコマンドラインオプションがあるので一瞬バッチファイルでずらずら並べりゃいいやシメシメと思うが、これが書いてある通りに動かない(/tオプションとか。バージョンにもよるのかもしれないが、Acrobat7でなきゃいけないという条件なので)。
 こちらの期待通りに動いてくれないので、印刷が終わったという情報が上手く得られず、印刷終了を待って次の印刷つーことが難しい。

 結局のところ、
  1. 印刷という挙動を監視して、前の印刷が終わったことを確認する
  2. Acrobat Readerで印刷開始。印刷終了を待つ。
  3. すべての処理が終わったら、AcrobatReaderのプロセスをきちんと始末する。
つーことが必要だ、たぶん。と結論した。

 Acrobat Reader自体はActiveXなのでCOMインタフェイスを持っているから、殆どの言語から生成してメソッドを呼べる。ところが印刷関係のメソッドは印刷終了の戻り値もなきゃコールバックも出来ないらしく、「印刷終了」の感知が難しいのである。

 うううううううむ。と10分ばかり考え込んでしまったが、仕方が無いのでこうすることにした。
 発想を変えて、Acrobat自体の終了報告には頼らずに、出した結果の方を監視することにしたのである。
  1. プリントキュー側を監視して、投入したジョブが消えたら終了したと<見なす>。共有プリンタではないので他からのアクセスについては考えない(爆)
  2. 基本的にはこれでAcrobatのプロセスがゾンビることはないと思うが、ダメ押しで、アプリ終了時にAcroRD32を強制的にKill(爆笑)
この線で手元にあるDelphi6で書いてみた。キモの部分はこんな感じ。

 まずは、出力しているプリンタの状態を見て登録されているジョブ数を確認する関数を用意する。Win API の GetPrinter を使うが、ここでは出し先がネットワークプリンタなので、PrinterInfo2構造体へ突っ込む。

//=============================================================================
// プリンタのステータスとジョブ数返す。
// PrinterName : プリンタ名
// JobCount(var): 登録されているジョブ数
// 戻り:ステータス
//=============================================================================
function PrinterStatus(const PrinterName: String; var JobCount: Cardinal): LongWord;
var
Count: LongWord;
hPrinter: THandle;
JobInfoCount: LongWord;
JobInfo2: PJobInfo2;
PrinterInfo2: PPrinterInfo2;
begin
Result := 0;

if OpenPrinter(PChar(PrinterName),hPrinter,nil) then begin
Count := 0;
GetPrinter(hPrinter,2,nil,0,@Count);
GetMem(PrinterInfo2,Count);
GetPrinter(hPrinter,2,PrinterInfo2,Count,@Count);
FreeMem(PrinterInfo2);
Count := 0;
EnumJobs(hPrinter,0,1,2,nil,0,Count,JobInfoCount);
GetMem(JobInfo2,Count);
EnumJobs(hPrinter,0,1,2,JobInfo2,Count,Count,JobInfoCount);
JobCount := JobInfoCount;
if (JobInfoCount > 0) and (JobInfo2.Status <> 0) then begin
if (JobInfo2.Status and JOB_STATUS_BLOCKED_DEVQ) <> 0 then
Result := Result or PRINTER_STATUS_ERROR;
if (JobInfo2.Status and JOB_STATUS_DELETING) <> 0 then
Result := Result or PRINTER_STATUS_PENDING_DELETION;
if (JobInfo2.Status and JOB_STATUS_ERROR) <> 0 then
Result := Result or PRINTER_STATUS_ERROR;
if (JobInfo2.Status and JOB_STATUS_OFFLINE) <> 0 then
Result := Result or PRINTER_STATUS_OFFLINE;
if (JobInfo2.Status and JOB_STATUS_PAPEROUT) <> 0 then
Result := Result or PRINTER_STATUS_PAPER_OUT;
if (JobInfo2.Status and JOB_STATUS_PAUSED) <> 0 then
Result := Result or PRINTER_STATUS_PAUSED;
if (JobInfo2.Status and (JOB_STATUS_PRINTING or JOB_STATUS_RESTART)) <> 0 then
Result := Result or PRINTER_STATUS_PRINTING;
if (JobInfo2.Status and JOB_STATUS_USER_INTERVENTION) <> 0 then
Result := Result or PRINTER_STATUS_USER_INTERVENTION;
end;
FreeMem(JobInfo2);
ClosePrinter(hPrinter);
end
end;

//=============================================================================
// PrinterNameのプリンタの印刷ジョブ数を返す関数
//=============================================================================
function TForm1.GetPrintJobCount(PrinterName: String): Cardinal;
var
aJobCount: Cardinal;
PrnStat: LongWord;
begin
aJobCount := 0;
PrnStat := PrinterStatus(PrinterName, aJobCount );
// ホントはステータス(PrnStat)をみるべきだが、めんどいので略
Result := aJobCount;
end;

こういう関数を用意し、大筋こんな感じでループ内で監視することにした。

PrintCount := GetPrintJobCount(Printername); // 印刷前の取得数を印字待ちなしと看做す
AcroPDF1.LoadFile(WideString(FileName)); // ファイルをロードして
AcroPDF1.printAllFit(True); // ダイアログなし印刷で

// データのポスト待ち
if GetPrintJobCount(Printername)=PrintCount then begin
while True do begin
Application.ProcessMessages;
if GetPrintJobCount(Printername)>PrintCount then break;
Sleep(1);
end;
end;

// 終了待ち
while True do begin
Application.ProcessMessages;
if GetPrintJobCount(Printername)<=PrintCount then break;
Sleep(1);
end;

どうもなんともカッコ悪いうえに、動作環境の仮定が多く、破綻するケースが容易に想像できる方法であるが(核爆)、しょせん一発モノなんで(笑)

いちおう、1万ファイル程度処理してみたが上手くいったのでよかったよかった。
[PR]
by SIGNAL-9 | 2008-03-27 15:52 | TIPSとかKludgeとか | Comments(0)

覚書:CDOSYSのCreateMHTMLBodyがエラーを吐く

CDOSYSを使ってMHTML形式(Multipart HTML。よーするにメールのMultipart MIMEと同じ)で単一のファイルとして保存しておく、つーのはけっこう使っている人も多いようで。
いちいちIEで「名前をつけて保存」つーのは芸が無いので、一気にやりたい、というのは天然自然の要求であろう。

 俺も今(笑)、複数のページを保存しときたいという要求があったんで、これで保存しときゃいいかと、ちょっとスクリプトを書いてみた。
URL = "http://www.google.com/"
DiskFile = "test.mht"

Set CDO = CreateObject("CDO.Message")

CDO.CreateMHTMLBody URL, 0,"",""
CDO.GetStream.SaveToFile DiskFile, 2

Set CDO = Nothing
いや、実際はもうちょっと綺麗に(定数のハードコードなんかさすがにやらないよ)書いてるが、概略こんな感じで。

 CDOのCreateMHTMLBodyで取得してそのままSaveToFile…という方法なのだが、簡単に終わってしめしめ…と思ったら落とし穴があった。

 接続先URLによってエラーが出るのである。
CDO.Message.1: インターフェイスが登録されていません
www.msn.comは取れるけどwww.google.comは取れないとか、ヘンなエラーの出方だ。

?と思ってちょっとググって見たら、回答を見つけているひとがいた。JasonJoh's [MSFT] WebLog
なるほど、煎じ詰めるとCDOが下請けに使ってるURLMON.DLLとの関係がアレなんで、http1.1の圧縮使っているページではエラーが出ると。
単純にはIEの設定でhttp1.1を切れ、と。

 う~ん。CDO Configのパラメータを見ると、プロトコルバージョンを明示できるようなパラメータはないようなので、スクリプトからだと簡単には操作できそうも無いなぁ。

 俺はとりあえずIEの設定を変えちゃって用は済ませたが、マジメに実装するのならJasonJoh氏がおっしゃっているようにInternetSetOptionを上書きするような何かを用意する必要がありそうだ。

ちなみにWinXP SP2で、CDOSYS.DLLが6.2.4.0,URLMON.DLLが6.0.2900.3268という環境。
[PR]
by SIGNAL-9 | 2008-02-19 13:02 | TIPSとかKludgeとか | Comments(0)

IEXPRESSでバッチファイルをEXEにする場合に。

 Windows2000、XPに付属しているIEXPRESS.EXEで、バッチファイルやVBSを擬似的にEXEにする(自己伸張形式のCABにする)というTIPSは良く知られている。
これによりバッチファイルの中身を見にくくするとか、右クリック→「別ユーザとして実行」を有効にするとか、ショートカットとして扱うことも簡単になる、つーアレだ。

 俺もたまに使うのだが、ちゃんと拡張子を見てくれてるみたいだ、ということに最近気づいた。

 つまり、*.BATのファイルをEXEにするとCOMMAND.EXEcommand.comが、*.CMDだとCMD.EXEが動いてくれるようなのだ。

 例えば、こういうバッチファイル。
@ECHO OFF
: TEST
ECHO NOTEPAD起動
START /W C:\WINDOWS\system32\NOTEPAD.EXE
ECHO NOTEPAD終了
:
ECHO CALC起動
START /W C:\WINDOWS\system32\Calc.EXE
ECHO CALC終了
:
ECHO COPY開始
COPY "C:\Documents and Settings\SIGNAL9\デスクトップ\TEST\DUMMY.TXT" "C:\Documents and Settings\SIGNAL9\デスクトップ\TEST\DUMMY2.TXT"
ECHO COPY終了
PAUSE
これをうっかり、TEST.BATという名前でセーブしてしまった。
 単純にダブルクリックすればこのBATはきちんと動作するので気づかなかったのだが、これをIEXPRESSでEXEにすると動かない。

 原因はファイルの拡張子がBATだったためらしく、CMDに直して再度EXE化するとうまく行ったのである。

 要するに、STARTとかLFNのパスとかはcommandではサポートされてないためで、拡張子BATでやりたいのなら、こう書かなきゃいけなかった。
@ECHO OFF
: TEST
ECHO NOTEPAD起動
C:\WINDOWS\system32\NOTEPAD.EXE
ECHO NOTEPAD終了
:
ECHO CALC起動
C:\WINDOWS\system32\Calc.EXE
ECHO CALC終了
:
ECHO COPY開始
CD C:\DOCUME~1\SIGNAL9~1\TEST
COPY DUMMY.TXT DUMMY2.TXT
ECHO COPY終了
PAUSE

 デスクトップから動かすと適当に按配してくれるくせに、なんでIEXPRESSを通すとこういう仕様なのかに関しては、まあ推測できる理由はあるのだが、よくわからない(爆)
[PR]
by SIGNAL-9 | 2008-01-09 17:03 | TIPSとかKludgeとか | Comments(2)

iTextSharpでPDFの文書プロパティを書き換える

 仕事で大量のドキュメントをPDFで集めたのはいいのだが、どいつもこいつも文書タイトルや作者名の文書のプロパティを埋めてきやがらない。
 これじゃあ、後で検索するときに困るだろうが。ちゃんと指示書に書いといたのに、まったく最近の若い奴ときたら…と、ジジイの繰言は置いておくとして、さて、どうしよう?と困ってしまった。

 いくらなんでも一件一件Acrobatで設定つーのはかっちょ悪いではないか。
 そんなくだらない作業に時間を費やしているほど、先行き長い人生でも無いし

 もちろん愛用のpdftkなど、既存ツールでもいいのだが、ちょっとプログラム的に操作したいようなこともあるので、簡単なツールを作ることにした。

 先だって、Javaで、FOPの代替としてiTextを使ったプログラムを作ったばかりだったので、iTextならできるだろうと判っちゃいたのだが、生来Javaという言語がキラいだし(笑)、同じことをやってもあまり面白くないので、iTextのC#へのポーティングであるiTextSharpを使ってみることにした。

 iTextSharpに関してはCodeZine:iTextSharpを利用して.NETでPDF帳票を出力するなどに詳しい。PDFを作成したいのならこのあたりの記事を読めばよろしかろう。俺的にはプロパティを変えたいだけなのでもっと簡単。

iTextSharpをしかるべく配置し、概略こんな感じで文書プロパティは読み出せた。
using iTextSharp.text;
using iTextSharp.text.pdf;



string ReadFile; // 読み出すファイル名(パス名)

PdfReader reader = new PdfReader(ReadFile); // パスワード付だとここで例外を吐くので対処要

infoTitle = (string)reader.Info["Title"];

 文書プロパティを保持してくれるreader.Infoはリストなので、全部読み出したいのなら

foreach (string infostr in reader.Info.Keys) {
… infostrに対する処理
みたいにすればよかろう。俺的には変えたいトコは決め打ちなんで reader.Info["Title"] みたいにダイレクトに指定してる。

で、問題は書き換えである。
いちおう別ファイルとして出力しておこうか。バグってると困るしな(笑)
当初ストリーム作ってコピって…みたいな操作が必要かと思ったのだが、マニュアル読んだらPdfStamperつー便利なものがあるではないか。
// 拡張子を変える
newFile = Path.ChangeExtension(ReadFile, ".FDF");

// PdfStamperを作成。
PdfStamper stamper = new PdfStamper(reader, new FileStream(newFile, FileMode.Create));

// 一時格納用のハッシュテーブル。
Hashtable info = new Hashtable();

// ハッシュに値を設定する
info["Title"] = "超極秘文書 マジェスティック12";
info["Author"] = "少年密偵 禿田正太郎";

// Stamperにハッシュテーブルの内容を入れて
stamper.MoreInfo = info;

// Stamperを閉じればア~ラ不思議ファイルの出来上がり
stamper.FormFlattening = true;
stamper.Close();
 iTextSharpは、オリジナルと比べるとまだ多少「こなれて」いない印象だが、C#からは使いやすい。今後が楽しみなソフトである。
[PR]
by SIGNAL-9 | 2006-12-28 11:17 | TIPSとかKludgeとか | Comments(0)

メモ:プロキシ自動構成PACファイルから使用するProxyを取得する

 以前から「どうやるんだろ? JScript.DLLキックつーのもなぁ…」と思っていたのだが、WinHTTPでサービス用APIが提供されていたのは知らんかった。
MSの解説はこちら
WinHttpGetProxyForUrlを使えばよい、とのこと。

 テスト用にDelphi6で書いてみる。残念ながらD6にはWinHTTPのヘッダファイルは付いていないので、とりあえず必要な定数と型(WINHTTP_AUTOPROXY_OPTIONS、WINHTTP_PROXY_INFO)WinHttpOpen、WinHttpGetProxyForUrl だけMSDN見ながらポーティング。抜粋しとくとこんな感じ。


PWINHTTP_AUTOPROXY_OPTIONS
= ^WINHTTP_AUTOPROXY_OPTIONS;
WINHTTP_AUTOPROXY_OPTIONS = record
dwFlags: DWORD;
dwAutoDetectFlags: DWORD;
lpszAutoConfigUrl: LPCWSTR;
lpvReserved: Pointer;
dwReserved: DWORD;
fAutoLogonIfChallenged: BOOL;
{$EXTERNALSYM WINHTTP_AUTOPROXY_OPTIONS}
TWINHTTP_AUTOPROXY_OPTIONS
= WINHTTP_AUTOPROXY_OPTIONS;
LPWINHTTP_AUTOPROXY_OPTIONS
= PWINHTTP_AUTOPROXY_OPTIONS;
{$EXTERNALSYM LPWINHTTP_AUTOPROXY_OPTIONS}

PWINHTTP_PROXY_INFO
= ^WINHTTP_PROXY_INFO;
WINHTTP_PROXY_INFO = record
dwAccessType: DWORD;
lpszProxy: LPWSTR;
lpszProxyBypass: LPWSTR;
{$EXTERNALSYM WINHTTP_PROXY_INFO}
TWINHTTP_PROXY_INFO = WINHTTP_PROXY_INFO;
LPWINHTTP_PROXY_INFO = PWINHTTP_PROXY_INFO;
{$EXTERNALSYM LPWINHTTP_PROXY_INFO}

function WinHttpOpen(
pwszUserAgent: PWideChar;
dwAccessType: DWORD;
pwszProxyName, pwszProxyBypass: PWideChar;
dwFlags: DWORD
): HINTERNET; stdcall;

function WinHttpGetProxyForUrl(
hSession: HINTERNET;
lpcwszUrl: LPCWSTR;
lpAutoProxyOptions:
PWINHTTP_AUTOPROXY_OPTIONS;
pProxyInfo: PWINHTTP_PROXY_INFO
): BOOL; stdcall;

implementation
const
winhttpdll = 'winhttp.dll';

function WinHttpOpen;
external winhttpdll name 'WinHttpOpen';
function WinHttpGetProxyForUrl;
external winhttpdll name 'WinHttpGetProxyForUrl';

で、呼び出してみる。要するに、評価対象にしたいURLをWinHttpGetProxyForUrlに食わせてみると、PACを取ってきてキャッシュし、中の FindProxyForURL(url, host) で評価して結果を返してくれる。

var
hHttpSession: HINTERNET ;
AutoProxyOptions: WINHTTP_AUTOPROXY_OPTIONS;
ProxyInfo : WINHTTP_PROXY_INFO;

begin
 // セッションを作る
hHttpSession := WinHttpOpen('TEST',
WINHTTP_ACCESS_TYPE_NO_PROXY,
WINHTTP_NO_PROXY_NAME,
WINHTTP_NO_PROXY_BYPASS,
0 );

AutoProxyOptions.dwFlags
:= WINHTTP_AUTOPROXY_CONFIG_URL;
AutoProxyOptions.lpszAutoConfigUrl
:= 'http://my.pac.server/Proxy.Pac';
AutoProxyOptions.fAutoLogonIfChallenged
:= FALSE;

 // PAC評価
if (WinHttpGetProxyForUrl(
hHttpSession,
'http://www.dest.com/', // 評価したいURL
@AutoProxyOptions,
@ProxyInfo
)) then …


 結果はProxyInfo(WINHTTP_PROXY_INFO)に返ってくる。

 ProxyInfo.dwAccessType:
  WINHTTP_ACCESS_TYPE_DEFAULT_PROXY (0) 設定時のみ
  WINHTTP_ACCESS_TYPE_NO_PROXY (1) 直接接続
  WINHTTP_ACCESS_TYPE_NAMED_PROXY (3) Proxy経由

 ProxyInfo.lpszProxy: Proxyのリスト
 Proxyinfo.lpszProxyBypass:プロクシのバイパスのリスト
[PR]
by SIGNAL-9 | 2006-12-27 14:14 | TIPSとかKludgeとか | Comments(0)

WSHで作るRSSアグリゲータ

 今時はRSSでサイト更新のチェックをやってる方は多いと思うが、RSSの走りの頃に「アグリゲータやRSSニュースリーダのタグイをいちいちクライアントに入れるのもウザい」→「Webページにしてしまえ」という甚だ安直な発想の元作成したASP(マイクロソフトのCGIプログラム用のスクリプト環境)プログラムがあったので、キモのところをWSHに焼きなおして晒しておく。

 かなり古いシロモノなので、今ではほとんど意味がないと思うがどなたかの参考にでもなれば幸いである。

 プログラムの中でWindowsからhttpアクセスを行わせるために、ServerXMLHTTPを使っている。これはWindowsXPあたりは標準で入っていると思うが、古めの2000だと入ってないかも。
ServerXMLHTTP に関してよく寄せられる質問 (FAQ) 文書番号290761

 それと、Proxyを踏んでいるときには、Proxycfg.exeで設定しないとダメなので注意されたい。
[INFO] ServerXMLHTTP が動作するにはプロキシ構成ユーティリティを使用する文書番号 : 289481

 サンプルではcnetジャパンのRSSを読んで、html文書に整形してエコー表示する。ファイルにリダイレクトするなり、FileSystemObject使うように改造してファイルに吐くなりご自由に。

 元々のASPではオンデマンドで照会してブラウザに返していたが、こういうものはやはりWSHで、定期的にスケジューラから動かす的な使い方の方がいいだろう。

ソース
[PR]
by SIGNAL-9 | 2005-04-19 15:52 | TIPSとかKludgeとか | Comments(0)

官能用語ジェネレータ(笑)

 俺も健康な男性なのでエロは大好きだ。というか、「科学とエロしか信じない」(Copyright 堂高しげる in 全日本妹選手権)。

 最近のお気に入りは立花理子嬢なのだが、それはまあ置いておいて。

 官能小説の類も好きで、フランス書院文庫なんかにはだいぶんお世話になった口ではあるが、いつも感心していたのは官能小説特有の、普通の辞書には載っていないが、字面だけで愚息も昇天(厨房か俺は)、だがけっして下品ではなくブンガクな香りを漂わせる一群の用語である。
 
 「官能小説用語表現辞典」なんて本があるくらいだ。

 最近読んだレポート漫画「カオスだもんね!」に、このフランス書院の取材記事が載っていたが、ようするにあの造語は、お上の手入れを避けるためのものだったとか。
 必要は発明の母とはよくいったもので、それが独特の文化(ああ、文化だよこれは)として成立するのであるから、ある意味で権力の弾圧というのは必要なのだな。
「ボルジア家30年の圧制はルネサンスを生んだが、スイス500年の平和は何を生んだ?鳩時計さ」というわけだな。違うかもしれないが。

 才能ある作家が呻吟しつつ生み出した独特の用語を俺のごときが云々するのは僭越だが、テキトーな文字の順列組み合わせなんてのはコンピュータの得意とするところだ。と、思いついたので今パっと書いてみた。
VBScriptなので、大抵のWindowsで動くはず。適当な名前(拡張子.vbs)でセーブ。

Sub LoadToArray(ByVal MyFileName, ByRef ResultArray )
Const ForReading = 1
Dim fso, MyFile, i
Set fso = CreateObject("Scripting.FileSystemObject")
Set MyFile = fso.OpenTextFile(MyFileName, ForReading, False)
i = 1
Do While MyFile.AtEndOfStream <> True
Redim Preserve ResultArray(i) 'おいおい(^^;)
ResultArray(i-1) = MyFile.ReadLine
i = i + 1
Loop
MyFile.Close
Set MyFile = Nothing
Set fso = Nothing
End Sub
' ----------- main
Dim MyArray()

Call LoadToArray( "data.txt", MyArray )
Randomize
a=0
b=0
Do While(a=b)
a = Int((UBound(MyArray))*Rnd())
b = Int((UBound(MyArray))*Rnd())
Loop
Wscript.Echo MyArray(a) & MyArray(b)

もちろんこれだけだと動かないので、データを用意する。要するに、それらしい文字をズラズラ並べたテキストファイルだ(data.txtとしてセーブ)。
















動かしてみると、バカな「単語」をズラズラ作り出すのでお試しあれ。もちろんこういうものはデータの量が命なので、なるべくエロい字を登録するのがコツだ。

…しかし、「肉陰」あたりはまあいいとして、「股美」つーのはなんだ(笑)。
[PR]
by SIGNAL-9 | 2005-04-05 18:06 | TIPSとかKludgeとか | Comments(1)

Windowsイベントログの保存

 個人情報保護法やら何やらの件で、今まで余裕ぶっこいてあまり真面目に考えていなかったWindowsマシンのログもいちおう取っておこうかなという気になった(笑)

 仕事関係の中核マシンは監視の絡みもあるので、Snareみたいな仕掛けを使って比較的しっかり作っているのだが、さほど重要度の高くないWindowsサーバはほとんどローテートするに任せていた。

ようするに何もしていなかったわけである(爆)

 これだとイザという時困るかも…ということで、せめてバックアップくらいは取って置こうかと思ったわけである。

 どんな時がイザという時なのか…と問われると、よくわからんのだが(笑)。

 イベントログファイルは、リソースキットツールのDumpel.exeとかElogDmp.exeなどでもエクスポートできるが、パージといっしょに行いたかったので、WMIを使ったスクリプトを用意した。
 実際には纏めて圧縮アーカイブしたり二次記憶媒体に書き込んだりで、もっと複雑だが、キモ的にはこんな感じ。

ソース
[PR]
by SIGNAL-9 | 2005-03-28 15:00 | TIPSとかKludgeとか | Comments(0)

古いSolarisで大量ユーザ登録

 何の因果か応報か、今時Solaris2.6(爆)でメールサーバ動かしてくれと頼まれた。
 どーしてそーゆー事になったのかは、我ながら信じられない事情なので省く。

しいていえば太陽のせいだ

 でまあ、OSやらsendmailやらqpopperやら、指定されたソフトのインストール自体は問題なかったのだが、ちょっと困ったのがここに数百人分のユーザ登録が必要、ということだったのである。

 Solaris2.6ではユーザ登録はadduserコマンドで行える。ユーザ自体の登録とホームディレクトリ掘りは、このコマンドで一発である。
 が、これを使ってもadmintoolを使っても、初期登録時はパスワードロックされており、必ずパスワードを登録しなければ使用開始できない。
 問題は、このパスワードの設定である。

 初期パスワード自体はアカウント名からのハナモゲラでよいということなので、自動生成できるとして、問題はそれをどうやってSolaris君に喰わせるか。

 ちょっと見てみたらSolaris2.6のpasswdコマンドは、入出力ともstderrであり、普通のシェルスクリプトでリダイレクトでコントロールするのが難しい。つまり、

passwd foo 12346
passwd baz 12346


みたいなコマンドをズラズラ書いたシェルスクリプトで一括登録!ってわけにはいかないんである。
 cryptを使って自前で暗号化したpasswdファイルを生成して差し替えてしまおうか、と思ったが、よく考えりゃあshadowパスワードだ。んな事やったことないからなぁ。Linuxみたいにshadow on/offができりゃあいいのだが、残念なことにSolaris2.6君はできないみたいだ。
 いずれにしてもこの方法だと、差し替える時にシングルユーザモードでないとまずそうだし、現に生きて動いているサーバの場合、こりゃあちょっとまずそうだ。

 うううううううううううううん。
 と10分ばかり考えた末、結局、telnetソフトのTeraTermを立ち上げた。


timeout = 1
fileopen fhandle 'passwd.txt' 0
:loop
filereadln fhandle uname
if result goto fclose
filereadln fhandle passtext
if result goto fclose
passcmd = 'passwd '
strconcat passcmd uname
sendln passcmd
wait "New password:"
sendln passtext
wait "Re-enter new password:"
sendln passtext
waitln "#"
goto loop
:fclose
fileclose fhandle


TeraTerm用に、概略上のようなマクロを書いた。

要するに、


ユーザー名
パスワード



というファイルを順次読み込んで、自動的にpasswdコマンドを次から次へと動かしてしまえ、という甚だカッチョ悪い方法である。おまけに死ぬほど遅い

 がこれにもいいところはあって、あくまでも正規のpasswdコマンドを通しているので間違いは少ないし、システムを停止する必要もない上、動かしっぱなしで帰ってしまえば翌日には終わってる(笑)

まあ、どう考えても良い方法ではないが、どうせ一発ものだし、うまくいったからどうでもいいか(爆)
[PR]
by SIGNAL-9 | 2005-03-25 18:42 | TIPSとかKludgeとか | Comments(1)