QA@IT
この質問・回答は、@ITの旧掲示板からインポートされたものです。

ASP(VBSCRIPT)でのネットワークドライブへのファイルコピーについて

お世話になります。
windows2000、IISサーバの環境でASPの開発をしておりますが、技術的に行き詰っております。

VBscriptで、IISサーバ(仮にAサーバとします)にあるPDFファイルを別サーバ(仮にBサーバとします)にコピーしたいのですが、上手くいきません。
下記エラーが出てしまいます。

Microsoft VBScript 実行時エラー (0x800A004C)
パスが見つかりません。

AサーバにはBサーバの共有フォルダのネットワークドライブを割り当てています。
CクライアントのWEBブラウザからAサーバのページを開いてコピー処理を実行するとエラーとなります。
ちなみに、AサーバにログインしてWEBブラウザを開き、Aサーバのプログラムを実行した場合は問題なくBサーバの共有フォルダにPDFファイルがコピーされます。

下記にソースの一部を記します。

<%
filename = "E:\PDF\" 'ローカルパス
filename2 = "F:\PDF\" 'ネットワークドライブのパス
'# PDFファイルをコピーします
Set fs = CreateObject("Scripting.FileSystemObject")
w = fs.CopyFile(filename,filename2,True) '←ここでエラーが発生
%>

なお、プログラムで、ネットワークドライブをオブジェクトにセットし、そのオブジェクトのプロパティを表示してみました。
下記にそのソースと実行結果を記します。

【ソース】
<%
Set fsd = fs.GetDrive("F")
return = fsd.isready
sHTMLpop = ""
sHTMLpop = sHTMLpop & "alert('" & return & "');"
sHTMLpop = sHTMLpop & ""
Response.Write(sHTMLpop)
%>

【結果】
・AサーバのWebブラウザで出力したアラート
true
・CクライアントのWebブラウザからAサーバのページを開いて出力したアラート
false

同じプログラムなのに、実行する端末によってプロパティが変わってしまっています。
なんとかCクライアントでもコピーの処理を実現したいのですが、どなたかご教示願えませんでしょうか。

[ メッセージ編集済み 編集者: 復活したスライム 編集日時 2008-05-10 21:38 ]

質問者:復活したスライム

回答

まず、この掲示板で何度も書かれていることですが、network drive は user 単位で管理するものです。つまり、その Web application が動作されている user 単位で network drive を設定しなければなりません。あと、確か user profile の load が必要だったかと。ASP とか Web application の場合、network logon となるため、user profile は load されません。

早い話、network drive は Web application では使えないと思ったほうが良いです。
では、どうするかというと、file server と Web server を同じ domain に参加させ、UNC で指定することです。

あと、Web application がどの account で動作するか?は IIS の認証方式によって変わってきます。この手の質問をされるときには必ず IIS の認証方式を提示するようにしてください。

投稿者:ちゃっぴ

編集 履歴 (0)

ちゃっぴ様
お世話になります。ご返信、有難うございます。

IIS の認証方式ですが、
「匿名アクセス」です。

workgroupという環境で、ドメインには参加していない状態です。
できればこの状態で実現したいですが、やはり無理そうですね。。。

[ メッセージ編集済み 編集者: 復活したスライム 編集日時 2008-05-10 23:39 ]
[ メッセージ編集済み 編集者: 復活したスライム 編集日時 2008-05-10 23:40 ]

投稿者:復活したスライム

編集 履歴 (0)

Web server の Web browser でまともに動作していることからして、おそらく「統合 Windows 認証」も check が入っているものと推測します。

Classic ASP の場合この手の処理は component で行うというのが王道でした。

File copy 処理を VB6.0 で ActiveX dll を作成します。
VB6.0 で ASP から呼び出し可能な component を作成するにはちとコツがあるので下記を参照してください。

COM を Visual Basic で作成しよう! - Part 1 -
[INFO] ASP で実行する Visual Basic コンポーネントの設計ガイドライン

なお、VB.NET や C# 等でも COM 相互運用を使えば classic ASP から呼び出す component を作成することはできます。まあ、それだったら最初から ASP.NET でやってしまうことをお勧めしますが。

それができたら、COM+ に server application として登録します。COM+ の起動 account は file server 上の resource が扱える account を指定してください。
同じ domain に参加していなくても account password が一致していれば対象の resource を扱うことができます。

一応、これで実現可能ですがこの application を扱える user は制限しておいたほうがよいでしょう。IIS 側で「匿名認証」を off にして任意の認証方法を選択します。その上で対象の ASP source file の ACL を制限します。また、COM+ application の ACL も同様に制限します。

投稿者:ちゃっぴ

編集 履歴 (0)

お世話になります。
大分時間がたってしまいました。
申し訳ありません。

「VB6.0でコンポーネント作成」しました。
そしてASPで、異なるサーバ間のファイルコピーが一応できました。
「一応」といったのは、ちょっと問題が発生してしまいました。

今問題となっているのは、componentの呼び出し方です。
componentを呼び出すときにコピー元のファイルのパス&ファイル名と、
コピー先のパス&ファイル名を引数として与えるのですが、
下記のように直でパスを与えないとエラーが発生してしまいます。

sRe = objCopyFile.comCopy("E:\asptest\test.txt","\NetServer\com\test.txt")

本当は下記のようにしたいのですが、
Microsoft VBScript 実行時エラー (0x800A000D)
型が一致しません。: 'objCopyFile.comCopy'
というエラーが出ます。

sFromPath = "E:\asptest\test.txt"
sToPath = "\NetServer\com\test.txt"
sRe = objCopyFile.comCopy(sFromPath,sToPath)

上記実現は不可能なのでしょうか。

それから、componentから戻り値を受け取りたいのですが、
これもまったく返してくれません。
上記の「sRe」という変数に戻り値が入るはずですが、
何も戻っていないようなのです。
componentから戻り値を受け取ることはできないのでしょうか。

ちなみに、私がVB6.0で作成したcomponentを下記に提示します。

Option Explicit
'-------------------------------------------------------------------------------
' 機能概要   :ファイルをネットワーク経由で別サーバにコピーする
' パタメータ  :ファイルコピー元、コピー先のパス
' 戻り値    :成功 = ok
'         失敗 = エラー情報
'-------------------------------------------------------------------------------
Public Function comCopy(sFilefrom As String, sFileto As String) As String

'# エラートラップを設定する
On Error GoTo ErrorHandler

'# ファイルをコピーする
FileCopy sFilefrom, sFileto

'# 戻り値
comCopy = "ok"

'# エラートラップ
ErrorHandler:
comCopy = Err.Number & ":" & Err.Description

End Function

どなたか、もしご存知の方がおられましたら、
ご教示願います。

投稿者:復活したスライム

編集 履歴 (0)

ちゃっぴ様

ご丁寧なご回答、有難うございます。
ご指摘の通り、「統合 Windows 認証」にもcheckが入っております。

VBでコンポーネント作成というのをやってみたいと思います。
他には手は無いですよね。。。
実現が出来たらまた報告したいと思います。

以上です。

投稿者:復活したスライム

編集 履歴 (0)

たぶんハマルと思ったから、link しておいたんですけど。。。

[INFO] ASP で実行する Visual Basic コンポーネントの設計ガイドライン

上記からたどれる link に下記があります。

[IIS]ASP から参照で VB COM オブジェクトにパラメータを渡す

ほかにもいろいろと重要なこと書いてありますので、もう一度見直してください。

それから、component で path を検証していないようですが、まずいです。
どの account で動作しているか知りませんが、今のままだとその account で書き込める場所へどこでも書き込み可能です。どこでも書き込めていいとは思えないので、compnent 側で制限掛けたほうがいいでしょう。

投稿者:ちゃっぴ

編集 履歴 (0)

チャッピ様

ご回答、有難うございます。
問題は解決しました。
component側で、受け取る引数が「参照渡し」であることを明示してあげればよかったんですね。
ByRef 〜 as Variant
で解決しました。
一応、修正したcomponentのソースを下記に記載しておきます。

Option Explicit
'-------------------------------------------------------------------------------
' 機能概要   :ファイルをネットワーク経由で別サーバにコピーする
' パタメータ  :ファイルコピー元、コピー先のパス
' 戻り値    :成功 = ok
'         失敗 = エラー情報
'-------------------------------------------------------------------------------
Public Function comCopy(ByRef sFilefrom As Variant, ByRef sFileto As Variant) As Variant

'# エラートラップを設定する
On Error GoTo ErrorHandler

'# ファイルをコピーする
FileCopy sFilefrom, sFileto

'# エラートラップ
ErrorHandler:
'# 戻り値
If Err.Number = 0 Then
comCopy = Err.Number
Else
comCopy = Err.Number & ":" & Err.Description
End If

End Function

なお、「component で path を検証」というのはやはり上記ソース内にpath検証用のロジックを追加するということですよね。

了解しました。有難うございました。
[ メッセージ編集済み 編集者: 復活したスライム 編集日時 2008-05-26 19:30 ]

投稿者:復活したスライム

編集 履歴 (0)

引数を ByVal で String 宣言してもいいですね。

なお、「component で path を検証」というのはやはり上記ソース内にpath検証用のロジックを追加するということでしょうか、それとも、com+のところでそういった設定ができるものでしょうか。

Componet に検証用の logic を追加してください。

今回の場合では、 COM+ の呼び出し側である ASP と呼び出される COM+ component の間には明確な secuirty 境界が存在します。そういった security 境界をまたぐものを作る場合には、呼び出される側で入力をしつこいくらい検証するべきです。

投稿者:ちゃっぴ

編集 履歴 (0)
ウォッチ

この質問への回答やコメントをメールでお知らせします。