3流プログラマのメモ書き

元開発職→社内SE→派遣で営業支援→開発戻り浦島太郎状態の三流プログラマのIT技術メモ書き。 このメモが忘れっぽい自分とググってきた技術者の役に立ってくれれば幸いです。

WSHを使って特定コンピュータのみフォルダリダイレクトの設定 Part2

WSHを使って特定コンピュータのみフォルダリダイレクトの設定 Part1の続きです。

上記記事の最後でごみ箱無効化に関する問題がありましたが、あれを回避する方法です。

まず、WSHを管理者ユーザで動かすためのexeを作成し、ログインスクリプトに指定します。

今回はドメイン内のどの端末でもこのexeが動くことになるため、C++でWindowsAPIを使ってコーディングしました。

この辺に関しては、(C++)別ユーザでプロセスを起動する(C++)ファイルパスからフォルダパスを取得するを参考に。。

これで、管理者権限で動くWSH側でごみ箱無効のレジストリ設定を書けばいいんですが、レジストリパスに、HKCU(HKEY_CURRENT_USER) を使うとその管理者のレジストリに書き込まれてしまいます。

ここは本来ログインしたユーザのレジストリに設定したいので、SIDを使って HKEY_USERS にアクセスする必要があります。

ということで、WSHを管理者キックするexeで現在のログインユーザ名を取得し、WSHコマンドライン引数として渡し、WSH側でユーザ名から SID を取得するという方法を取ることとしました。

WSHでユーザ名をSIDにする方法と、コマンドライン引数を取得する方法は(WSH)ユーザ名のSIDを取得を、現在のログインユーザを取得する方法は(C++)現在のログインしてるユーザ名を取得するを参考にしてください。

最終的に、WSH(VBScript)側は下記のような感じとなりました。

Option Explicit

 

Dim objNet

'コンピュータ名取得 対象コンピュータなら処理する

Set objNet = CreateObject("WScript.Network")

IF StrComp(objNet.ComputerName , "SV1" ,1 ) = 0 OR _

StrComp(objNet.ComputerName , "SV2" ,1 ) = 0 OR _

StrComp(objNet.ComputerName , "SV3" ,1 ) = 0 OR _

StrComp(objNet.ComputerName , "SV4" ,1 ) = 0 Then

'コマンドライン引数取得(1番目にユーザ名が入る)

Dim args

Set args = WScript.Arguments

'ユーザ名からSID取得

'WMIサービスへの接続

Dim Locator , Service

Set Locator = CreateObject("WbemScripting.SWbemLocator")

Set Service = Locator.ConnectServer

'Administrator以外

IF StrComp(args(0) , "administrator" , vbTextCompare ) <> 0 Then

 

'WMIクエリ生成(引数1番目にユーザ名が入っていることとする)

Dim query , UsrSet , sid , Usr

query = "Select * From Win32_UserAccount WHERE Name = '" _

& args(0) & "'"

'WMIクエリを実行

Set UsrSet = Service.ExecQuery( query )

'クエリから結果取得し文字列生成

For Each Usr In UsrSet

sid = Usr.SID

Next

'リダイレクト設定

Dim strRedirectRegKey

strRedirectRegKey = "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders\"

Dim strRecycleRegKey

strRecycleRegKey = "HKEY_USERS\" & sid & "\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer\NoRecycleFiles"

Dim strBasePath

strBasePath = "\\filesv\user\%username%\"

Dim objShell

Set objShell = WScript.CreateObject("WScript.Shell")

'マイドキュメントリダイレクト

objShell.RegWrite strRedirectRegKey & "Personal", strBasePath & "マイドキュメント" , "REG_EXPAND_SZ"

'デスクトップリダイレクト

objShell.RegWrite strRedirectRegKey & "Desktop", strBasePath & "デスクトップ" , "REG_EXPAND_SZ"

'ごみ箱使用しない

objShell.RegWrite strRecycleRegKey , 1 , "REG_DWORD"

'設定がまだなら設定する。

IF Left(nowDesktop,Len(strBasePath)) <> strBasePath OR Left(nowPersonal,Len(strBasePath)) <> strBasePath Then

'マイドキュメントリダイレクト

objShell.RegWrite strRedirectRegKey & "Personal", strBasePath & "SunRayマイドキュメント" , "REG_EXPAND_SZ"

'デスクトップリダイレクト

objShell.RegWrite strRedirectRegKey & "Desktop", strBasePath & "SunRayデスクトップ" , "REG_EXPAND_SZ"

'ごみ箱使用しない

objShell.RegWrite strRecycleRegKey , 1 , "REG_DWORD"

'メッセージを送り一回ログアウトを促す。

objShell.Run("msg " & args(0) & " 個人フォルダの設定を完了するため、ログオフし再度ログインしてください。")

End If

End If

End If

上記スクリプトをグループポリシーのログオンスクリプトに設定しても、そのあとのログインですぐに適用されないケースもあるようです。(グループポリシーの適用とユーザ環境のロードのタイミングの問題のようですが。。)

それで、設定がまだなら再ログオンを促すメッセージを表示することにしました。(今回の要件はターミナルサーバにログインしたユーザのみが対象なので、 msg コマンドで自身のコンピュータ(ターミナルサーバ)の該当ユーザにメッセージを送ります。)

本当はダイアログボックスを表示してOK押下すればログアウトする仕組みを取りたかったんですが、このスクリプトは管理者権限で動くため、ログアウトスクリプト入れると管理者がログアウトしてしまっていました。

なのでメッセージだけという妥協策になっています。

msg コマンドの使って、他のユーザにメッセージを送信するにはDOS「メッセージ送信」コマンドが参考になります。

あと、上記スクリプトで運用を開始したところ一つ問題が発生しました。

それはデスクトップをリダイレクト対象にした場合、デスクトップのファイル・フォルダリストが最新の情報にならない時があるということです。

最新の情報にならないのは、アプリケーションからファイルを保存するときにリダイレクトされたデスクトップを指定したときや、リダイレクト先の共有フォルダをエクスプローラで開いてそこでファイル・フォルダオブジェクトを操作したときです。

調べてみると、ファイルを作成、移動、または削除しても、エクスプローラのファイル一覧が更新されないで、レジストリの HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer に NoSimpleNetIDList キーを作成し、DWORD値 1 を指定するといいようです。試してみましたが、ダメでした。

MSサポート:Windows Vista または Windows Server 2008 でオフライン ファイルの削除がエクスプローラ上で反映されないでも同様の現象が仕様としてされています。

ただ、グループポリシー→管理テンプレートのフォルダリダイレクトの機能を使うとデスクトップをリダイレクトしても上記の現象は発生しません。

リダイレクト先を監視する常駐アプリでも作ろうかと思いましたが、そこまでの必要性はないとのことだったのでユーザがF5を押下して手動で更新してもらう運用としました。