none
PowerShellにおいて、切断するネットワークドライブが開かれている場合は、切断するか、切断しないかを判定させる方法について RRS feed

  • 質問

  • 【環境】クライアント:Windows 10 Enterprise 2016 LTSB,PowerShell サーバー:Windows Server 2012 R2(ActiveDirectoryドメインサーバー、ファイルサーバー)

    【事象および状況】

    ログインスクリプトにてネットワークドライブの割り当てを行うようになっておりますが、時々 ネットワークドライブの割り当てに失敗することがあります。

    パソコンの再起動を行うことによってネットワークドライブの割り当てが行えることもありますが、ネットワークドライブの割り当てが行えない場合、手動でネットワークドライブの割り当てを行うために以下のスクリプトを作成しました。

    以下のスクリプトでは、ネットワークドライブの割り当てはされているが、ネットワークドライブでのファイル操作に問題が発生した場合には一度、切断をして再度 割り当てを行うことも考慮されています。

    割り当てをするファイルサーバーのフォルダの情報については、ActivityDirectoryドメインサーバーの「拡張属性29」に「FILESERVER\Kameda」のように記載されているため、その情報を取得しています。

    # ------------------+---------------------------------------------------------- #
    #  プログラム名     | Network_Drive_Mapping.ps1                                 #
    # ------------------+---------------------------------------------------------- #
    #  プログラムの概要 | ログインスクリプトによるネットワークドライブの割り当てに  #
    #                   | 失敗した場合、本スクリプトを使用してネットワークドライブ  #
    #                   | の割り当てを行う。                                       #
    # ------------------+-----------------------------------------------------------#
    
    # ------------------------------------
    #  □ 定義 (フォーム)
     # ------------------------------------
    
    # -- アセンブリの読み込み --
    Add-Type -AssemblyName System.Windows.Forms
    Add-Type -AssemblyName System.Drawing
    
    # ------------------------------------
    #  □ 定義 (ログ)
    # ------------------------------------
    
    # -- ログフォルダ --
    $LogFolder="E:\$env:USERNAME\Log"
    
    # -- ログファイル --
    $LogFile="Network_Drive_Mapping.log"
    
    # ------------------------------------
    #  □ 定義 (ユーザー名)
    # ------------------------------------
    
    # -- ユーザー名 --
    $UserName=$env:USERNAME
    
    # ------------------------------------
    #  ■ 処理
    # ------------------------------------
    
    # -- ログフォルダの確認 --
    if (!(Test-Path -Path $LogFolder)){
          New-Item -ItemType Directory -Path $LogFolder
          if ($? -eq $True) {
              [System.Windows.Forms.MessageBox]::Show("【情報】ログフォルダを作成しました")
          } else {
              [System.Windows.Forms.MessageBox]::Show("【エラー】ログフォルダの作成に失敗しました")
              Exit
          }
    }
    
    # -- ログファイルの確認 --
    if (!(Test-Path -Path $LogFolder\$LogFile)){
          New-Item $LogFolder\$LogFile
          if ($? -eq $True) {
              [System.Windows.Forms.MessageBox]::Show("【情報】ログファイルを作成しました")
          } else {
              [System.Windows.Forms.MessageBox]::Show("【エラー】ログファイルの作成に失敗しました")
              Exit
          }
    }
    
    # -- Active Directoryドメインサーバーの「拡張属性29」に格納されているファイルサーバーの共有フォルダ情報取得 --
    $ds = New-Object System.DirectoryServices.DirectorySearcher
    $ds.PageSize = 1000
    $ds.Filter = "(sAMAccountName=$UserName)"
    $result = $ds.FindOne()
    $value = $result.Properties.Item("msExchExtensionAttributes29")
    
    $result = (Test-Path "d:")
    if ($result) {
        $Date = Get-Date
        "【情報】日付と時刻:" + $Date + " 説明:Dドライブは割り当てされています。" >> $LogFolder\$LogFile
        net use D: /delete
        if ($? -eq $True) {
            $Date = Get-Date
            "【情報】日付と時刻:" + $Date + " 説明:Dドライブを切断しました。" >> $LogFolder\$LogFile
            net use D: \\$value\DATA
            if ($? -eq $True) {
                $Date = Get-Date
                "【情報】日付と時刻:" + $Date + " 説明:Dドライブを割り当てしました。" >> $LogFolder\$LogFile
                [System.Windows.Forms.MessageBox]::Show("【情報】Dドライブを割り当てしました")
            } else {
                $Date = Get-Date
                "【エラー】日付と時刻:" + $Date + " 説明:Dドライブの割り当てに失敗しました。" >> $LogFolder\$LogFile
                [System.Windows.Forms.MessageBox]::Show("【エラー】Dドライブを割り当てに失敗しました")
            }
        } else {
            $Date = Get-Date
            "【エラー】日付と時刻:" + $Date + " 説明:Dドライブの切断に失敗しました。" >> $LogFolder\$LogFile
            [System.Windows.Forms.MessageBox]::Show("【エラー】Dドライブの切断に失敗しました")
        }
    } else {
        $Date = Get-Date
        "【情報】日付と時刻:" + $Date + " 説明:Dドライブは割り当てされていません。" >> $LogFolder\$LogFile
        net use D: \\$value\DATA
        if ($? -eq $True) {
            $Date = Get-Date
            "【情報】日付と時刻:" + $Date + " 説明:Dドライブを割り当てしました。" >> $LogFolder\$LogFile
            [System.Windows.Forms.MessageBox]::Show("【情報】Dドライブを割り当てしました")
        } else {
            $Date = Get-Date
            "【エラー】日付と時刻:" + $Date + " 説明:Dドライブの割り当てに失敗しました。" >> $LogFolder\$LogFile
            [System.Windows.Forms.MessageBox]::Show("【エラー】Dドライブを割り当てに失敗しました")
        }
    }
    
    $result = (Test-Path "l:")
    if ($result) {
        $Date = Get-Date
        "【情報】日付と時刻:" + $Date + " 説明:Lドライブは割り当てされています。" >> $LogFolder\$LogFile
        net use L: /delete
        if ($? -eq $True) {
            $Date = Get-Date
            "【情報】日付と時刻:" + $Date + " 説明:Lドライブを切断しました。" >> $LogFolder\$LogFile
            net use L: \\$value\MAIL
            if ($? -eq $True) {
                $Date = Get-Date
                "【情報】日付と時刻:" + $Date + " 説明:Lドライブを割り当てしました。" >> $LogFolder\$LogFile
                [System.Windows.Forms.MessageBox]::Show("【情報】Lドライブを割り当てしました")
            } else {
                $Date = Get-Date
                "【エラー】日付と時刻:" + $Date + " 説明:Lドライブの割り当てに失敗しました。" >> $LogFolder\$LogFile
                [System.Windows.Forms.MessageBox]::Show("【エラー】Lドライブを割り当てに失敗しました")
            }
        } else {
            $Date = Get-Date
            "【エラー】日付と時刻:" + $Date + " 説明:Lドライブの切断に失敗しました。" >> $LogFolder\$LogFile
            [System.Windows.Forms.MessageBox]::Show("【エラー】Lドライブの切断に失敗しました")
        }
    } else {
        $Date = Get-Date
        "【情報】日付と時刻:" + $Date + " 説明:Lドライブは割り当てされていません。" >> $LogFolder\$LogFile
        net use L: \\$value\MAIL
        if ($? -eq $True) {
            $Date = Get-Date
            "【情報】日付と時刻:" + $Date + " 説明:Lドライブを割り当てしました。" >> $LogFolder\$LogFile
            [System.Windows.Forms.MessageBox]::Show("【情報】Lドライブを割り当てしました")
        } else {
            $Date = Get-Date
            "【エラー】日付と時刻:" + $Date + " 説明:Lドライブの割り当てに失敗しました。" >> $LogFolder\$LogFile
            [System.Windows.Forms.MessageBox]::Show("【エラー】Lドライブを割り当てに失敗しました")
        }
    }

    【ご教示いただきたい点】

    割り当てをしようとしているネットワークドライブが割り当てされていて、割り当てされたネットワークドライブを開いていない場合は、切断を行います。
    しかし、割り当てをしようとしているネットワークドライブが割り当てされていて、割り当てされたネットワークドライブが開かれている場合は、「開かれていますが切断しますか?」のダイアログを表示させて、「はい」ボタンを押下した場合は、ネットワークドライブを切断して、「いいえ」ボタンを押下した場合は、割り当てされているネットワークドライブは切断しない処理をさせたいと考えておりますが、その方法についてご教示いただけますでしょうか。





    2019年9月18日 13:01

回答

  • net use D: /delete /n

    とすれば、ドライブを開いているときは

    D: との接続にオープン ファイルや未実行のディレクトリ検索があります。

    のメッセージで失敗して $? が False になると思いますががどうでしょう?

    2019年9月19日 3:23
  • なるほど。
    いつも「ダイアログボックス」を略して「ダイアログ」と呼んでいるので、思い込みがありました。

    >何かしらの要因でDドライブ、Lドライブ切断できなかった場合も $? が False になることがあるのではと考えております。

    そう言われると何とも言えませんが、エラーとメッセージが一致しないことはWindowsにもあることですし、レアケースなら心配してもキリがないように思います。
    私の勤め先のIT専門部隊が作る業務ソフトの中に最初にユーザーパスワードを入力してから購入ソフトに引き渡して起動するものがありますが、購入ソフトの不具合で起動に失敗しても「パスワードが間違っています」なんてメッセージです。

    ちなみに、サーバーは触ったことがないのでログインスクリプトがどういうものか分かりませんが、接続の失敗を検知したら、一定時間を置いてリトライはできないのでしょうか?


    2019年9月19日 15:08
  • ネットで調べてみたら、ファイルを開いている全てのプロセスを列挙して調べる方法もあるようです。

    詳しくは調べていませんが取り急ぎ。

    2019年9月19日 21:31
  • net use D: /delete /noを実行した時、ユーザーがファイルを開いている状態だった場合のステータスコードを取得する方法は分かりませんでしたが、「D: との接続にオープン ファイルや未実行のディレクトリ検索があります。」とのメッセージがコンソールに表示されることを判定条件にすればいいのではないでしょうか。

    流れとしては、
    ① net use D: /delete /no を実行する。特に問題なく切断された場合は④へ。

    ②-1 $?がFalseかつ「D: との接続にオープン ファイルや未実行のディレクトリ検索があります。」と表示されたら、ユーザーに切断確認のダイアログを表示

    ②-2 $?がFalseかつ他のエラーが表示された場合(何かしらの要因で切断できなかった場合)は、切断に失敗したとして終了

    ③-1 ダイアログで「はい」が押下されたら、net use D: /delete /yes を実行して強制切断

    ③-2 ダイアログで「いいえ」が押下されたら、そのまま終了する

    ④ D:を共有フォルダに割り当て

    …という流れをコードに起こしてみました。共通のルーチンが多く、上記を反映させるとさらにネストが深くなってしまうので関数に切り出しました。またログ記録は省略しているので適宜補完ください。

    Add-Type -AssemblyName System.Windows.Forms
    Add-Type -AssemblyName System.Drawing
    
    #ログフォルダの作成、共有フォルダ情報取得などの処理は略
    
    # 指定ドライブを切断する関数
    function delete_drive
    {
        param(
            [string]$Drive
        )
    
        # 切断する
        $msg = net use $Drive /delete /no
    
        if($? -eq $true) # 切断できた
        {
            return $true
        }
    
        if($null -eq $msg -or 
            -not @($msg)[0].Contains("との接続にオープン ファイルや未実行のディレクトリ検索があります。"))
        {
            # 理由は不明だが切断できない
    
            $dialogResult =
                [System.Windows.Forms.MessageBox]::Show("【エラー】${Drive}ドライブの切断に失敗しました")
            return $false
        }
    
        $dialogResult =
            [System.Windows.Forms.MessageBox]::Show(
                "開かれていますが切断しますか?",
                "",
                [System.Windows.Forms.MessageBoxButtons]::YesNo
            )
        
        if($dialogResult -eq [System.Windows.Forms.DialogResult]::No)
        {
            #ドライブを切断せず終了
            return $false
        }
    
        # 強制切断する
        $msg = net use $Drive /delete /yes
    
        if($? -eq $false) # 切断できなかった
        {
            $dialogResult =
                [System.Windows.Forms.MessageBox]::Show("【エラー】${Drive}ドライブの切断に失敗しました")
            return $false
        }
    
        return $true
    }
    
    # ドライブを指定共有フォルダに割り当てる関数
    function map_drive
    {
        param(
            [string]$Drive,
            [string]$Folder
        )
    
        if(Test-Path $Drive) # ドライブが既に割り当てられている
        {
            # ドライブを切断
            $result = delete_drive -Drive $Drive
    
            if($result -eq $false) # 切断に失敗した場合は終了
            {
                return
            }
        }
    
        # ドライブを指定共有フォルダに割り当てる
        $msg = net use $Drive $Folder
    
        if($? -eq $true)
        {
            $dialogResult =
                [System.Windows.Forms.MessageBox]::Show("【情報】${Drive}ドライブを割り当てしました")
        }
        else
        {
            $dialogResult =
                [System.Windows.Forms.MessageBox]::Show("【エラー】${Drive}ドライブを割り当てに失敗しました")
        }
    }
    
    map_drive -Drive "D:" -Folder "\\$value\DATA"
    map_drive -Drive "L:" -Folder "\\$value\MAIL"



    2019年9月19日 22:05
    モデレータ
  • ファイルを開いているプロセスを調べるツールは下記です。

    https://docs.microsoft.com/ja-jp/previous-versions/bb896655(v=msdn.10)?redirectedfrom=MSDN

    これの handle.exe が使えるかと思ったら、共有ドライブはドライブレターでは表示してくれませんでした。
    また、情報収集にも少々時間がかかりますし、これは無いかな、と思います。

    牟田口大介様の方法でも良いと思いますが、プログラミングをやっていると、値でないものはどうにも不安を感じてしまっていけません。(という意味では handle.exe も五十歩百歩)

    net.exe のエラーコードの定義が分かれば良いのですが・・・

    最終手段ですが、WIN32API の WNetCancelConnection2() はどうでしょう?

    https://msdn.microsoft.com/ja-jp/windows/aa385427%28v=vs.80%29?f=255&MSPPError=-2147217396

    これもエラーコードが定義されているものの、言語明瞭意味不明瞭で、ERROR_DEVICE_IN_USE って何?という感じで、完璧に把握できているわけではありません。


    2019年9月20日 15:39
  • >開かれていないにもかかわらず、「との接続にオープンファイルや未実行のディレクトリ検索があります。切断を続行し、強制的に閉じますか?(Y/N)  [N]:」が表示された場合は、Microsoftのバグになると思うのでその点は考慮する必要はないと思っています。

    どうでも良いことですが、バグに限らず、バックグラウンドプロセスが開くケースもあると思います。

    Administrator作業でドメインアカウントで共有フォルダにに接続した後、長時間処理のため一旦離れる際に、Administrator のパスワードを知っている人が結構いるので、net use * /d で切断するのですが、共有フォルダにアクセスしたフォルダは全て閉じているのにしばしば切断されないことがあって悩まされます。Explorerを強制終了しても切断されなかったので、アンチウィルスか監視ソフトを疑っています。

    2019年9月20日 15:44
  • > 「map_drive」関数で$dialogResultにセットしていますが、if文での判定に使用していないように見られるのですが、「map_drive」関数で$dialogResultにセットは必要になりますでしょうか。

     [System.Windows.Forms.MessageBox]::Show()メソッドは、DialogResult列挙型の値を返却します。そのため、変数に代入しないとDialogResultの値が関数の出力として、コンソールに表示されてしまいます。OKボタンを押下した場合は「OK」と表示されます。それを防ぐのが目的ですね。

     [System.Windows.Forms.MessageBox]::Show() | Out-Null

    のようにすることでも出力を抑制できますが、変数代入の方が一貫性があって良いかと思いました。

    2019年9月21日 2:10
    モデレータ
  • >システムエンジニアにサーバーを確認してもらうと他のユーザーが開いている場合もあるのですが、
    >DドライブとLドライブは個人用に割り当てをしているネットワークドライブで、他のユーザーがアクセスすることなないので、

    これ、矛盾してませんか?(繋がってないなら良いですが)

    >開いているユーザーがいない場合もあり、そのときはパソコンの再起動を行ってもらうと改善することもありますので、システムがつかんでしまっているときがあるのではと思っています。

    システムであろうと、何らかのアカウントで開いているはずですので、探し方がは悪いのでは?と思ってしまいます。

    2019年9月21日 7:17
  • >ファイルが見当たらないという問い合わせがときどきあります。
    >〜原因不明で終わらせてしまう

    脱線させて済みませんが、見過ごせないなと思いまして。
    私もシステム管理をやっていて、誤削除/上書き等で泣きつかれることもよくありますが、シャドウコピーは取られているでしょうか?
    ハードエラー時は別媒体へのバックアップでないと役に立ちませんが、ヒューマンエラー対策としてはシャドウコピーの手軽さは非常に強力です。

    しかし、保存場所や移動したことを忘れた可能性もあると思いますし、複数人で共有しているフォルダでは、誰かが意図的に移動した可能性もあるので、復元前の調査をどこまでするか難しいところです。

    私もやらなきゃと思いつつ3年くらい先延ばしにしてしまいましたが、私が触れる範囲の Windows の共有フォルダーは監査ログの記録を始めようと思います。

    参考までに、先程、下記を読みました。
    https://www.netassist.ne.jp/blog/?p=10733

    そんなの既にやっている、ということでしたら済みません。
    私の所属部門では、私が部内のシステム管理者になってサーバー管理部門に要求するまでシャドウコピーはとっていませんでした。


    2019年9月22日 1:01
  • シャドウコピーは取られているのですね。

    失礼しました。

    2019年9月22日 7:51
  • ネットワークパスが間違っているならシステムエラー53になると思うのですが。

    システムエラー67は確かに Workstaion サービスが起動していないと発生するエラーのようですが、ネットワークパスの最初の \\ を \ にしても出るようです。スクリプトが正しく記述されているかご確認頂けますでしょうか?

    2019年9月25日 14:43
  • パターン1で「開かれていますが切断しますか?」が表示されるのは、実際にそのエラーが出ている(フォルダが開かれている)からと思いますが、本当に何も開いていないのにそのエラーが出る原因については何とも言えません。
    パターン2で「切断しました」が条件に表示されるのは、メッセージを表示する文が、If(Test-Path $Drive) {} を抜けた後にあるからです。
    パターン3は、エラー出力を拾うため、2>&1 を追加して下さい。
    $msg 2>&1 >> $LogFolder\$LogFile
    システムエラー67が残るだけですが・・・。
    システムエラー67の原因究明が本題ではないでしょうか?
    2019年9月26日 21:26
  • 詳細までは把握できていませんが、delete_drive関数内で、ご自身で追加された[System.Windows.Forms.MessageBox]::Show()メソッドの戻り値を変数で受けていない部分があり、そのために関数出力に$true/$false以外に、DialogResultの値が混ざってしまっている可能性があります。関数の出力を条件判定に利用しているので、$true/$false以外の値が出力されないようにしてください。

    また、

        $msg = net use $Drive /delete /yes
        $msg 2>&1 >> $LogFolder\$LogFile 

        if($? -eq $false) # 切断できなかった
        {…

    この部分には複数の問題があります。

    まず、ネイティブコマンド(ここではnet.exe)の実行結果を$msg変数に代入していますが、この記述だと標準出力のみ代入され、標準エラー出力の値は捨てられます。

    net.exe実行時の標準エラー出力を2>&1により標準出力に合成し、その結果を$msgに代入する必要があります。

    次に、$?自動変数は、直前の行のコマンドが失敗した時にFalseが格納されます。しかし、net.exe実行直後に$msg変数の値をファイルにリダイレクトするという行を実行しているので、$?は必ずTrueになってしまっています。

    net.exe実行直後の$?の値を変数に格納しておく等の対策が必要です。

    さらにPowerShellはネイティブコマンドが出力する標準エラー出力を、文字列ではなくErrorRecord型のオブジェクトにラッピングする仕様があるため、2>&1を用いて標準エラー出力に出された文字列を得るには、ToString()メソッドを使う等してstring型に変換する必要もあります。

    (このあたりはPowerShellでネイティブコマンドを扱うときの面倒くさい部分で、個人的にもしんどく感じる部分ではあります…)

    まとめると以下のような方法があるかと思います。

    $msg = net use $Drive /delete /yes 2>&1
    $result = $?
    $msg | foreach {$_.ToString()} >> $LogFolder\$LogFile
    if($result -eq $false)
    {…

    別解としては$LASTEXITCODE変数の値を見て、コマンド成功かどうかを確認する方法があります。$LASTEXITCODE変数は直前のコマンドがExitCodeを出力しない限りは、内容が書き換わらないことを利用します。

    ところで、スクリプトのデバッグはどのようにされていますか?
    PowerShell ISEをご利用であれば、任意の行にブレークポイントを挿入してデバッグを実行すると、ブレークポイントでデバッグを停止し、その時点での変数値を読み取ったり、ステップ実行で1行ずつ実行していくといったことが可能です。

    スクリプトがうまく動作しない場合は、まずはご自身で、変数に意図した値が格納されているか、条件分岐では想定したブロックが実行されているか等をデバッグして確認してみてください。



    2019年9月27日 18:43
    モデレータ
  • >> $msg 2>&1 >> $LogFolder\$LogFile

    失礼しました。これは恥ずかしい・・・。
    既に牟田口大介様コメントで直されてますが、$msg の実行結果の標準エラー出力拾ってもしょうがないので、net.exe の標準エラー拾わないとダメです。

    >しかし、net.exe実行直後に$msg変数の値をファイルにリダイレクトするという行を実行しているので、$?は必ずTrueになってしまっています。

    確かに、これも詰めが甘くて済みません。

    ところで、D: L: に対するTest-Path に成功しても一旦切断されていますが、
    (1) ユーザが勝手に別のネットワークリソースに割り当てたもの
    を想定されているのでしょうか?
    (2) ログオンスクリプトが成功したもの
    (3) ログオンスクリプトの失敗の処置としてユーザーがルールに従って手動で割り当てたもの
    だとしたら、Test-Pathに成功する場合でも、何か不具合があるのでしょうか?

    全く別のアプローチとして、ドライブレターは割り当てないでUNCのみの運用への切り替えは不可能でしょうか?

    私の勤め先では20年くらい前からUNCで定着しています。

    ただし、未だにUNCに対応してくれないアプリがひとつだけあり、それはバッチ起動として、ドライブレターを割り当てています。

    2019年9月28日 0:39
  • >自分が作成したスクリプトでは、D/Lドライブの切断、D/Lドライブの割り当てが行えており、

    であるなら、それを元に改修した方が早いでしょう。
    改修のポイントは

    $msg = net use D: /delete /no

    のようにして net コマンドの出力を変数で受けて、 

    if($null -eq $msg -or 
            -not @($msg)[0].Contains("との接続にオープン ファイルや未実行のディレクトリ検索があります。"))

    で判定です。
    $null -eq $msg で比較しているのは、出力が空で $msg が Null の場合、Contains が失敗するからです。
    -or は左辺が $True であれば、右辺は評価されません。


    Powershell ISE は、スクリプトファイル(.ps1) を右クリックして「編集」で起動できます。(スタートからでも起動できます)
    一時停止したい行で右クリックして「ブレークポイントの設定/解除」でブレークポイントを設定後、F5キーで実行すると設定した行で止まり、一時停止中に調べたい変数にマウスポインタを合わせると、変数の内容が表示されます。
    1行ずつ実行するには、F10でステップオーバー(関数の中は止めない)、F11でステップイン(関数の中に入って止める)、F12でステップアウト(関数を抜ける)を使います。

    2019年9月29日 0:34

すべての返信

  • net use D: /delete /n

    とすれば、ドライブを開いているときは

    D: との接続にオープン ファイルや未実行のディレクトリ検索があります。

    のメッセージで失敗して $? が False になると思いますががどうでしょう?

    2019年9月19日 3:23
  • ありがとうございます。

    現在のスクリプトでもDドライブ、Lドライブを開いている状態であれば、「D:との接続にオープンファイルや未実行のディレクトリ検索があります。切断を続行し、強制的に閉じますか?(Y/N) [N]:」、「L:との接続にオープンファイルや未実行のディレクトリ検索があります。切断を続行し、強制的に閉じますか?(Y/N) [N]:」が表示されております。

    ① Dドライブの場合
    1.「D:との接続にオープンファイルや未実行のディレクトリ検索があります。切断を続行し、強制的に閉じますか?(Y/N) [N]:」のメッセージが表示される。

    ② Lドライブの場合
    1.「L:との接続にオープンファイルや未実行のディレクトリ検索があります。切断を続行し、強制的に閉じますか?(Y/N) [N]:」のメッセージが表示される。

    ご教示いただきました「net use D: /delete /n」、「net use L: /delete /n」に修正を行った場合、Dドライブ、Lドライブを開いている状態では、以下になることを確認いたしました。

    ① Dドライブの場合
    1.「【エラー】Dドライブの切断に失敗しました」のダイアログが表示される。
    2.「D:との接続にオープンファイルや未実行のディレクトリ検索があります。切断を続行し、強制的に閉じますか?(Y/N) [N]:」のメッセージが表示される。

    ② Lドライブの場合
    1.「【エラー】Lドライブの切断に失敗しました」のダイアログが表示される。
    2.「L:との接続にオープンファイルや未実行のディレクトリ検索があります。切断を続行し、強制的に閉じますか?(Y/N) [N]:」のメッセージが表示される。

    ユーザーがファイルを開いている状態であれば、$? が False になりますが、何かしらの要因でDドライブ、Lドライブ切断できなかった場合も $? が False になることがあるのではと考えております。ユーザーがファイルを開いている以外の条件で$?がFalseになるような状況については再現させることはできませんでしたがそのような可能性もあるのではと思っています。

    ユーザーがファイルを開いている状態であれば、ユーザーに閉じるように促すダイアログを表示したいと思いますが、何かしらの要因でDドライブ、Lドライブ切断できなかった場合、ユーザーがファイルを開いている訳ではないので閉じるようなダイアログを表示しても意味がないのではと思っております。

    そのため、ユーザーがファイルを開いていている状態のときのステータスコードと何かしらの要因でネットワークドライブであるDドライブ、Lドライブ切断できなかった場合のステータスコードが取得できないかと思っています。
    それが可能であれば、ユーザーがファイルを開いていている状態のときのステータスコードが取得された場合は、ユーザーにファイルを閉じるように促すダイアログを表示して、何かしらの要因でDドライブ、Lドライブ切断できないステータスコードが取得された場合は、切断できなかった旨のダイアログを表示したいと考えています。

    Dドライブであれば、Wordファイル/Excelファイル/PowerPointファイル/PDFファイルなどが格納されているのでユーザーがファイルを開いていれば、「D:との接続にオープンファイルや未実行のディレクトリ検索があります。切断を続行し、強制的に閉じますか?(Y/N) [N]:」が表示されることで気がつくユーザーもいるとは思います。

    しかし、Lドライブには、メールデータが格納されているOutlookデータファイル(pst)があり、Outlookデータファイル(pst)はWordファイル/Excelファイル/PowerPointファイル/PDFファイルなどのようにユーザーがファイルをクリックして開くのとは異なり、Outlook2016から「開く/エクスポート」ー「Outlookデータファイルを開く」からOutlookデータファイル(pst)開きますが、そのままにしておけば、Outlook2016を起動するたびにOutlookデータファイル(pst)が開らかれるので、「L:との接続にオープンファイルや未実行のディレクトリ検索があります。切断を続行し、強制的に閉じますか?(Y/N) [N]:」が表示されても、開いているという意識がないユーザーもいることから、そのユーザーの場合、何のことだろうと思うため、Lドライブが開かれていたり、Outlookデータファイル(pst)を開いている場合、Outlook2016を終了させるように促すメッセージとLドライブを閉じるように促すメッセージのダイアログを表示するようにしたいと考えています。

    2019年9月19日 12:50
  • なるほど。
    いつも「ダイアログボックス」を略して「ダイアログ」と呼んでいるので、思い込みがありました。

    >何かしらの要因でDドライブ、Lドライブ切断できなかった場合も $? が False になることがあるのではと考えております。

    そう言われると何とも言えませんが、エラーとメッセージが一致しないことはWindowsにもあることですし、レアケースなら心配してもキリがないように思います。
    私の勤め先のIT専門部隊が作る業務ソフトの中に最初にユーザーパスワードを入力してから購入ソフトに引き渡して起動するものがありますが、購入ソフトの不具合で起動に失敗しても「パスワードが間違っています」なんてメッセージです。

    ちなみに、サーバーは触ったことがないのでログインスクリプトがどういうものか分かりませんが、接続の失敗を検知したら、一定時間を置いてリトライはできないのでしょうか?


    2019年9月19日 15:08
  • ネットで調べてみたら、ファイルを開いている全てのプロセスを列挙して調べる方法もあるようです。

    詳しくは調べていませんが取り急ぎ。

    2019年9月19日 21:31
  • net use D: /delete /noを実行した時、ユーザーがファイルを開いている状態だった場合のステータスコードを取得する方法は分かりませんでしたが、「D: との接続にオープン ファイルや未実行のディレクトリ検索があります。」とのメッセージがコンソールに表示されることを判定条件にすればいいのではないでしょうか。

    流れとしては、
    ① net use D: /delete /no を実行する。特に問題なく切断された場合は④へ。

    ②-1 $?がFalseかつ「D: との接続にオープン ファイルや未実行のディレクトリ検索があります。」と表示されたら、ユーザーに切断確認のダイアログを表示

    ②-2 $?がFalseかつ他のエラーが表示された場合(何かしらの要因で切断できなかった場合)は、切断に失敗したとして終了

    ③-1 ダイアログで「はい」が押下されたら、net use D: /delete /yes を実行して強制切断

    ③-2 ダイアログで「いいえ」が押下されたら、そのまま終了する

    ④ D:を共有フォルダに割り当て

    …という流れをコードに起こしてみました。共通のルーチンが多く、上記を反映させるとさらにネストが深くなってしまうので関数に切り出しました。またログ記録は省略しているので適宜補完ください。

    Add-Type -AssemblyName System.Windows.Forms
    Add-Type -AssemblyName System.Drawing
    
    #ログフォルダの作成、共有フォルダ情報取得などの処理は略
    
    # 指定ドライブを切断する関数
    function delete_drive
    {
        param(
            [string]$Drive
        )
    
        # 切断する
        $msg = net use $Drive /delete /no
    
        if($? -eq $true) # 切断できた
        {
            return $true
        }
    
        if($null -eq $msg -or 
            -not @($msg)[0].Contains("との接続にオープン ファイルや未実行のディレクトリ検索があります。"))
        {
            # 理由は不明だが切断できない
    
            $dialogResult =
                [System.Windows.Forms.MessageBox]::Show("【エラー】${Drive}ドライブの切断に失敗しました")
            return $false
        }
    
        $dialogResult =
            [System.Windows.Forms.MessageBox]::Show(
                "開かれていますが切断しますか?",
                "",
                [System.Windows.Forms.MessageBoxButtons]::YesNo
            )
        
        if($dialogResult -eq [System.Windows.Forms.DialogResult]::No)
        {
            #ドライブを切断せず終了
            return $false
        }
    
        # 強制切断する
        $msg = net use $Drive /delete /yes
    
        if($? -eq $false) # 切断できなかった
        {
            $dialogResult =
                [System.Windows.Forms.MessageBox]::Show("【エラー】${Drive}ドライブの切断に失敗しました")
            return $false
        }
    
        return $true
    }
    
    # ドライブを指定共有フォルダに割り当てる関数
    function map_drive
    {
        param(
            [string]$Drive,
            [string]$Folder
        )
    
        if(Test-Path $Drive) # ドライブが既に割り当てられている
        {
            # ドライブを切断
            $result = delete_drive -Drive $Drive
    
            if($result -eq $false) # 切断に失敗した場合は終了
            {
                return
            }
        }
    
        # ドライブを指定共有フォルダに割り当てる
        $msg = net use $Drive $Folder
    
        if($? -eq $true)
        {
            $dialogResult =
                [System.Windows.Forms.MessageBox]::Show("【情報】${Drive}ドライブを割り当てしました")
        }
        else
        {
            $dialogResult =
                [System.Windows.Forms.MessageBox]::Show("【エラー】${Drive}ドライブを割り当てに失敗しました")
        }
    }
    
    map_drive -Drive "D:" -Folder "\\$value\DATA"
    map_drive -Drive "L:" -Folder "\\$value\MAIL"



    2019年9月19日 22:05
    モデレータ
  • ありがとうございます。

    $? が False になるパターンをすべて網羅することはMicrosoftが情報を公開していないので、すべてのパターンを処理させようと考えてはいません。
    仮にMicrosoftが情報を公開していたとしても、Microsoftが気がついていないパターンが情報から漏れていることがあるのではと思っております。

    そのため、「との接続にオープンファイルや未実行のディレクトリ検索があります。切断を続行し、強制的に閉じますか?(Y/N)  [N]:」が表示された場合は、ユーザーによって開かれていると判断してもよいのではと思っています。
    開かれていないにもかかわらず、「との接続にオープンファイルや未実行のディレクトリ検索があります。切断を続行し、強制的に閉じますか?(Y/N)  [N]:」が表示された場合は、Microsoftのバグになると思うのでその点は考慮する必要はないと思っています。

    「との接続にオープンファイルや未実行のディレクトリ検索があります。切断を続行し、強制的に閉じますか?(Y/N)  [N]:」だけのパターンを考慮しておいて、それ以外は考慮せず処理をしない場合、仮にそれ以外のパターンが発生した場合、その条件がないので、どれにも該当せずプログラムはABENDすると考えられ、それ以外という条件にして処理する必要があると思っています。

    ログオンスクリプトは、ActiveDirectoryドメインにログオン時に実行されるスクリプトになります。ログオンスクリプトは、BAT、VBScript、PowerShellであればよいようです。

    客先ではテレワークを推奨しており、ユーザーが自宅等からSSL-VPNで社内のActiveDirectoryドメインにログオンして業務を行うこともあり、その場合にネットワークドライブの割り当てに失敗することも考えられてるため、リトライは行うようにしているようです。
    しかし、死活監視のように定期的にリトライを繰り返すことはしていないようなので、リトライしてもネットワークドライブの割り当てに失敗することもあります。



    2019年9月20日 12:44
  • ありがとうございます。

    「openfiles」でしょうか。 現在開かれている共有フォルダや共有ファイルの情報について表示することができるようですが、管理者権限が必要のようです。ユーザーには管理者権限を与えていないので、「openfiles」は実行できないようです。

    2019年9月20日 13:07
  • ファイルを開いているプロセスを調べるツールは下記です。

    https://docs.microsoft.com/ja-jp/previous-versions/bb896655(v=msdn.10)?redirectedfrom=MSDN

    これの handle.exe が使えるかと思ったら、共有ドライブはドライブレターでは表示してくれませんでした。
    また、情報収集にも少々時間がかかりますし、これは無いかな、と思います。

    牟田口大介様の方法でも良いと思いますが、プログラミングをやっていると、値でないものはどうにも不安を感じてしまっていけません。(という意味では handle.exe も五十歩百歩)

    net.exe のエラーコードの定義が分かれば良いのですが・・・

    最終手段ですが、WIN32API の WNetCancelConnection2() はどうでしょう?

    https://msdn.microsoft.com/ja-jp/windows/aa385427%28v=vs.80%29?f=255&MSPPError=-2147217396

    これもエラーコードが定義されているものの、言語明瞭意味不明瞭で、ERROR_DEVICE_IN_USE って何?という感じで、完璧に把握できているわけではありません。


    2019年9月20日 15:39
  • >開かれていないにもかかわらず、「との接続にオープンファイルや未実行のディレクトリ検索があります。切断を続行し、強制的に閉じますか?(Y/N)  [N]:」が表示された場合は、Microsoftのバグになると思うのでその点は考慮する必要はないと思っています。

    どうでも良いことですが、バグに限らず、バックグラウンドプロセスが開くケースもあると思います。

    Administrator作業でドメインアカウントで共有フォルダにに接続した後、長時間処理のため一旦離れる際に、Administrator のパスワードを知っている人が結構いるので、net use * /d で切断するのですが、共有フォルダにアクセスしたフォルダは全て閉じているのにしばしば切断されないことがあって悩まされます。Explorerを強制終了しても切断されなかったので、アンチウィルスか監視ソフトを疑っています。

    2019年9月20日 15:44
  • ありがとうございます。

    ご教示いただきましたプログラムにログフォルダ/ログファイルの作成、ActiveDirectoryドメインサーバーからの共有フォルダ情報取得を追加しましたので、連休明けに実際の環境で試してみたいと思います。

    「delete_drive」関数では、$dialogResultにセットしてif文での判定に使用しています。 「map_drive」関数で$dialogResultにセットしていますが、if文での判定に使用していないように見られるのですが、「map_drive」関数で$dialogResultにセットは必要になりますでしょうか。

    # ------------------+---------------------------------------------------------- #
    #  プログラム名     | Network_Drive_Mapping.ps1                                 #
    # ------------------+---------------------------------------------------------- #
    #  プログラムの概要 | ログオンスクリプトによるネットワークドライブの割り当てに  #
    #                   | 失敗した場合、本スクリプトを使用してネットワークドライブ  #
    #                   | の割り当てを行う。                                        #
    # ------------------+-----------------------------------------------------------#
    
    # ------------------------------------
    #  □ 定義 (フォーム)
    # ------------------------------------
    
    # -- アセンブリの読み込み --
    Add-Type -AssemblyName System.Windows.Forms
    Add-Type -AssemblyName System.Drawing
    
    # ------------------------------------
    #  □ 定義 (ログ)
    # ------------------------------------
    
    # -- ログフォルダ --
    $LogFolder = "E:\$env:USERNAME\Log"
    
    # -- ログファイル --
    $LogFile = "Network_Drive_Mapping.log"
    
    # ------------------------------------
    #  □ 定義 (ユーザー名)
    # ------------------------------------
    
    # -- ユーザー名 --
    $UserName=$env:USERNAME
    
    # ----------+---------------------------------- #
    #   関数   | delete_drive                      #
    # ----------+---------------------------------- #
    #    概要   | ネットワークドライブを切断する。  #
    # ----------+---------------------------------- #
    #    引数   | $Drive                            #
    # ----------+---------------------------------- #
    #   戻り値  | $true または $false               #
    # ----------+---------------------------------- #
    function delete_drive
    {
        param(
            [string]$Drive
        )
    
        # 切断する
        $msg = net use $Drive /delete /no
    
        if($? -eq $true) # 切断できた
        {
            return $true
        }
    
        if($null -eq $msg -or 
            -not @($msg)[0].Contains("との接続にオープン ファイルや未実行のディレクトリ検索があります。"))
        {
            # 理由は不明だが切断できない
            $Date = Get-Date
            "【エラー】日付と時刻:" + $Date + " 説明:${Drive}ドライブの切断に失敗しました。" >> $LogFolder\$LogFile
    
            $dialogResult =
                [System.Windows.Forms.MessageBox]::Show("【エラー】${Drive}ドライブの切断に失敗しました")
            return $false
        }
    
        $dialogResult =
            [System.Windows.Forms.MessageBox]::Show(
                "開かれていますが切断しますか?",
                "",
                [System.Windows.Forms.MessageBoxButtons]::YesNo
            )
    
        if($dialogResult -eq [System.Windows.Forms.DialogResult]::No)
        {
            #ドライブを切断せず終了
            $Date = Get-Date
            "【情報】日付と時刻:" + $Date + " 説明:${Drive}ドライブが開かれており、切断を行いませんでした。" >> $LogFolder\$LogFile
            [System.Windows.Forms.MessageBox]::Show("【情報】${Drive}が開かれており、切断を行いませんでした")
            return $false
        }
    
        # 強制切断する
        $msg = net use $Drive /delete /yes
    
        if($? -eq $false) # 切断できなかった
        {
           $Date = Get-Date
            "【エラー】日付と時刻:" + $Date + " 説明:${Drive}ドライブの切断に失敗しました。" >> $LogFolder\$LogFile
            $dialogResult =
                [System.Windows.Forms.MessageBox]::Show("【エラー】${Drive}ドライブの切断に失敗しました")
            return $false
        }
    
        return $true
    }
    
    
    # ----------+---------------------------------- #
    #   関数   | map_drive                         #
    # ----------+---------------------------------- #
    #    概要   | ネットワークドライブを指定した    #
    #           | 共有フォルダに割り当てる。        #
    # ----------+---------------------------------- #
    #    引数   | $Drive, $Folder                   #
    # ----------+---------------------------------- #
    #   戻り値  | なし                       #
    # ----------+---------------------------------- #
    function map_drive
    {
        param(
            [string]$Drive,
            [string]$Folder
        )
    
        if(Test-Path $Drive) # ドライブが既に割り当てられている
        {
            # ドライブを切断
            $result = delete_drive -Drive $Drive
    
            if($result -eq $false) # 切断に失敗した場合は終了
            {        
                return
            }
        }
    
        # ドライブを指定共有フォルダに割り当てる
        $msg = net use $Drive $Folder
    
        if($? -eq $true)
        {
            $Date = Get-Date
                "【情報】日付と時刻:" + $Date + " 説明:${Drive}ドライブを切断しました。" >> $LogFolder\$LogFile
            [System.Windows.Forms.MessageBox]::Show("【情報】${Drive}ドライブを切断しました")
            $Date = Get-Date
                "【情報】日付と時刻:" + $Date + " 説明:${Drive}ドライブを割り当てしました。" >> $LogFolder\$LogFile
        $dialogResult =
                [System.Windows.Forms.MessageBox]::Show("【情報】${Drive}ドライブを割り当てしました")
        }
        else
        {
            $Date = Get-Date
                "【情報】日付と時刻:" + $Date + " 説明:${Drive}ドライブを切断しました。" >> $LogFolder\$LogFile
        [System.Windows.Forms.MessageBox]::Show("【情報】${Drive}ドライブを切断しました")
            $Date = Get-Date
                "【エラー】日付と時刻:" + $Date + " 説明:${Drive}ドライブの割り当てに失敗しました。" >> $LogFolder\$LogFil
        $dialogResult =
                [System.Windows.Forms.MessageBox]::Show("【エラー】${Drive}ドライブの割り当てに失敗しました")
        }
    }
    
    # ------------------------------------
    #  ■ 処理
    # ------------------------------------
    
    # -- ログフォルダの確認 --
    if (!(Test-Path -Path $LogFolder)){
          New-Item -ItemType Directory -Path $LogFolder
          if ($? -eq $True) {
              [System.Windows.Forms.MessageBox]::Show("【情報】ログフォルダを作成しました")
          } else {
              [System.Windows.Forms.MessageBox]::Show("【エラー】ログフォルダの作成に失敗しました")
              Exit
          }
    }
    
    # -- ログファイルの確認 --
    if (!(Test-Path -Path $LogFolder\$LogFile)){
          New-Item $LogFolder\$LogFile
          if ($? -eq $True) {
              [System.Windows.Forms.MessageBox]::Show("【情報】ログファイルを作成しました")
          } else {
              [System.Windows.Forms.MessageBox]::Show("【エラー】ログファイルの作成に失敗しました")
              Exit
          }
    }
    
    # -- Active Directoryドメインサーバーの「拡張属性29」に格納されているファイルサーバーの共有フォルダ情報取得 --
    $ds = New-Object System.DirectoryServices.DirectorySearcher
    $ds.PageSize = 1000
    $ds.Filter = "(sAMAccountName=$UserName)"
    $result = $ds.FindOne()
    $value = $result.Properties.Item("msExchExtensionAttributes29")
    
    map_drive -Drive "D:" -Folder "\\$value\DATA"
    map_drive -Drive "L:" -Folder "\\$value\MAIL"




    2019年9月21日 1:19
  • ありがとうございます。

    「handle.exe」を使用するとなるとキッティングの際のマスターイメージに追加する必要があり、客先の管理者に理由を説明して許可を得る必要があり、おそらく、追加する許可は得られない可能性が高いのではと考えております。

    イベントビューアーでのメッセージについては、日立のJP1で通報されないようにメッセージ抑止するためにDLLを調べたことはあるのですが、「NET.EXE」については、ステータスコード、メッセージ情報がMicrosoftから公開されていないため、牟田口大介様からご教示いただきましたメッセージで判断させるしかないのかなと思っています。

    すでにプログラマーを引退していますが、昔にCOBOLでプログラムを行っていたので、コード、フラグで判定させたい気持ちはわかります。

    プロセスが開いているファイルをユーザーに通知して閉じてもらうようにするのはユーザーが開いているファイルを認識できるのでユーザー視点としてはとってはいいのですが、処理を考える側としては大変なので、今回はよいのかなと思っています。

    例えば、「WINWORD.EXE」がWordのプロセスであるとユーザーが理解している場合は「WINWORD.EXEでD:\XXXXにあるファイルYYYY.DOCXが開かれていますので、閉じますか?」でいいのですが、恐らくわからない可能性もあるのでプロセス名ではなく、「WordでD:\XXXXにあるファイルYYYY.DOCXが開かれていますので、閉じますか?」のようにアプリケーション名にしないといけないと思われ、プロセス名とアプリケーション名を対比するものを作らないといけなくなり、ユーザーが業務で必要なソフトウェアがあり、「ソフトウェア導入申請」を行い、承認されて追加された場合は、それについてもプロセス名とアプリケーション名を対比するものをつくらないといけないので大変になるのではと思っています。


    2019年9月21日 1:50
  • > 「map_drive」関数で$dialogResultにセットしていますが、if文での判定に使用していないように見られるのですが、「map_drive」関数で$dialogResultにセットは必要になりますでしょうか。

     [System.Windows.Forms.MessageBox]::Show()メソッドは、DialogResult列挙型の値を返却します。そのため、変数に代入しないとDialogResultの値が関数の出力として、コンソールに表示されてしまいます。OKボタンを押下した場合は「OK」と表示されます。それを防ぐのが目的ですね。

     [System.Windows.Forms.MessageBox]::Show() | Out-Null

    のようにすることでも出力を抑制できますが、変数代入の方が一貫性があって良いかと思いました。

    2019年9月21日 2:10
    モデレータ
  • ありがとうございます。

    たまにネットワークドライブにあるファイルを開こうとすると開かれているメッセージが表示されるということで問い合わせをいただくことがあります。

    システムエンジニアにサーバーを確認してもらうと他のユーザーが開いている場合もあるのですが、開いているユーザーがいない場合もあり、そのときはパソコンの再起動を行ってもらうと改善することもありますので、システムがつかんでしまっているときがあるのではと思っています。

    DドライブとLドライブは個人用に割り当てをしているネットワークドライブで、他のユーザーがアクセスすることなないので、ユーザーが開いていないと言うことであれば、システムがつかんでしまっていると思っています。

    「との接続にオープンファイルや未実行のディレクトリ検索があります。切断を続行し、強制的に閉じますか?(Y/N)  [N]:」がユーザーが開いているのか、それともシステムがつかんでいるのかを判断することが難しいので、システムがつかんで閉じられない場合は諦める以外には方法がないのかなと思っています。

    仮にアンチウィルスソフトが原因だとしてもユーザー権限では停止させることはできないですし、停止できたとしても停止されては困るので・・・。

    2019年9月21日 2:21
  • >システムエンジニアにサーバーを確認してもらうと他のユーザーが開いている場合もあるのですが、
    >DドライブとLドライブは個人用に割り当てをしているネットワークドライブで、他のユーザーがアクセスすることなないので、

    これ、矛盾してませんか?(繋がってないなら良いですが)

    >開いているユーザーがいない場合もあり、そのときはパソコンの再起動を行ってもらうと改善することもありますので、システムがつかんでしまっているときがあるのではと思っています。

    システムであろうと、何らかのアカウントで開いているはずですので、探し方がは悪いのでは?と思ってしまいます。

    2019年9月21日 7:17
  • DとLは個人用に割り当てをしているネットワークドライブで他のユーザーが開いているということはないですが、Oドライブについては部のドライブ、Rドライブについては客先の全ユーザーが利用可能なドライブですが、たまにアクセスしていないにも関わらず、編集できないという問い合わせをいただくことがあります。

    D、Lドライブについては、個人用のドライブなので、ユーザーかファイルサーバーを管理しているシステムエンジニアしか
    アクセスできないはずですが、ファイルが見当たらないという問い合わせがときどきあります。
    ユーザーは、ファイルを削除していないとのことで、ファイルサーバーを管理しているシステムエンジニアに確認しても何もしていないとのことで、原因不明で終わらせてしまうということがよくあるので、システムエンジニア自体がまともに調べる気がないという可能性はあります。システム切り替えをして半年間くらいネットワークドライブにまともに接続できない状態が続いていて、ユーザーからクレームがかなり来たほどなので・・・。

    客先の元請けは、日系大手IT企業で、その子会社が親会社から請負というかたちで子会社のシステムエンジニアが入っています。
    うちの会社もその客先に日系大手IT企業の子会社の請負という形で常駐しておりますが、日系大手IT企業の近くに会社があるだけで、子会社でも関連企業でもありません。





    2019年9月21日 13:30
  • >ファイルが見当たらないという問い合わせがときどきあります。
    >〜原因不明で終わらせてしまう

    脱線させて済みませんが、見過ごせないなと思いまして。
    私もシステム管理をやっていて、誤削除/上書き等で泣きつかれることもよくありますが、シャドウコピーは取られているでしょうか?
    ハードエラー時は別媒体へのバックアップでないと役に立ちませんが、ヒューマンエラー対策としてはシャドウコピーの手軽さは非常に強力です。

    しかし、保存場所や移動したことを忘れた可能性もあると思いますし、複数人で共有しているフォルダでは、誰かが意図的に移動した可能性もあるので、復元前の調査をどこまでするか難しいところです。

    私もやらなきゃと思いつつ3年くらい先延ばしにしてしまいましたが、私が触れる範囲の Windows の共有フォルダーは監査ログの記録を始めようと思います。

    参考までに、先程、下記を読みました。
    https://www.netassist.ne.jp/blog/?p=10733

    そんなの既にやっている、ということでしたら済みません。
    私の所属部門では、私が部内のシステム管理者になってサーバー管理部門に要求するまでシャドウコピーはとっていませんでした。


    2019年9月22日 1:01
  • ローカルドライブについては、バックアップを取っていませんが、ネットワークドライブについては、シャドウ・コピーで14日のバックアップがあり、その間であれば、「以前のバージョン」から確認してもらって残っていれば、ユーザー自ら戻してもらっております。しかし、それより古いバックアップはないため、ない場合は、ユーザーには諦めてもらっています。

    ユーザーが間違えて削除したものも確かにあって戻したいという問い合わせもあるのですが、私以外にはアクセスしないフォルダなので、他のユーザーはアクセスしないはずですが、いつの間にか消えていたという問い合わせもあります。私以外にはアクセスしないフォルダと言っても、部/課のフォルダ内にそのユーザーが作成しているフォルダで、部/課のユーザーに対してアクセス権が設定されているので、同じ部/課に所属している他のユーザーもアクセスしようと思えばアクセスできてしまうので、間違えて他のユーザーが削除した可能性はないわけではありません。

    SKYSEAが導入されているため、操作ログが取られていれば、操作ログから誰が削除したかを確認することは可能なので、「操作ログがあれば、見てもらえないか」と依頼しても、操作ログの調査をほぼ100%断られております。


    2019年9月22日 5:14
  • シャドウコピーは取られているのですね。

    失礼しました。

    2019年9月22日 7:51
  • 本日、試しましたが、「システムエラー67が発生しました。ネットワーク名が見つかりません。」のメッセージでDドライブ、Lドライブの割り当てが行えませんでした。

    サービス「Workstation」が「実行中」であることは確認しています。

    <パターン1> D/Lドライブの割り当てがされていて、Dドライブ、Lドライブを開いていない状態

    1.「【情報】Dドライブを切断しました」のダイアログが表示。
    2.「システムエラー67が発生しました。ネットワーク名が見つかりません。」のメッセージが表示。
    3.「【エラー】Dドライブの割り当てに失敗しました」のダイアログが表示。
    4.「【情報】Lドライブを切断しました」のダイアログが表示。
    5.「システムエラー67が発生しました。ネットワーク名が見つかりません。」のメッセージが表示。
    6.「【エラー】Lドライブの割り当てに失敗しました」のダイアログが表示。
    7.「E:\<ユーザー名>\log\Network_Drive_Mapping.log」を確認すると以下のログが出力されている。

    【情報】 日付と時刻:09/24/2019 09:52:41 説明:Dドライブを切断しました。
    【情報】 日付と時刻:09/24/2019 09:52:42 説明:Lドライブを切断しました。

    <パターン2>  D/Lドライブの割り当てがされていて、Dドライブ、Lドライブを開いている状態

    1.「開かれていますが切断しますか?」のダイアログで「はい」ボタンを押下。
    2.「【情報】Dドライブを切断しました」のダイアログが表示。
    3.「システムエラー67が発生しました。ネットワーク名が見つかりません。」のメッセージが表示。
    4.「【エラー】Dドライブの割り当てに失敗しました」のダイアログが表示。
    5.「開かれていますが切断しますか?」のダイアログで「はい」ボタンを押下。
    6.「【情報】Lドライブを切断しました」のダイアログが表示。
    7.「システムエラー67が発生しました。ネットワーク名が見つかりません。」のメッセージが表示。
    8.「【エラー】Lドライブの割り当てに失敗しました」のダイアログが表示。
    9.「E:\<ユーザー名>\log\Network_Drive_Mapping.log」を確認すると以下のログが出力されている。

    【情報】 日付と時刻:09/24/2019 10:32:08 説明:Dドライブを切断しました。
    【情報】 日付と時刻:09/24/2019 10:32:09 説明:Lドライブを切断しました。




    2019年9月24日 12:00
  • ありがとうございます。

    そのような目的があるとは知りませんでした。勉強になります。

    2019年9月24日 20:30
  • ネットワークパスが間違っているならシステムエラー53になると思うのですが。

    システムエラー67は確かに Workstaion サービスが起動していないと発生するエラーのようですが、ネットワークパスの最初の \\ を \ にしても出るようです。スクリプトが正しく記述されているかご確認頂けますでしょうか?

    2019年9月25日 14:43
  • ありがとうございます。

    再度確認しました。

    パターン1では、Dドライブ、Lドライブを開いていない状態ですが、「開かれていますが切断しますか?」のダイアログが表示されました。

    <パターン1> D/Lドライブの割り当てがされていて、Dドライブ、Lドライブを開いていない状態

    1.「開かれていますが切断しますか?」のダイアログで「はい」ボタンを押下。
    2.「【情報】Dドライブを切断しました」のダイアログが表示。
    3.「システムエラー67が発生しました。ネットワーク名が見つかりません。」のメッセージが表示。
    4.「【エラー】Dドライブの割り当てに失敗しました」のダイアログが表示。
    5.「開かれていますが切断しますか?」のダイアログで「はい」ボタンを押下。
    6.「【情報】Lドライブを切断しました」のダイアログが表示。
    7.「システムエラー67が発生しました。ネットワーク名が見つかりません。」のメッセージが表示。
    8.「【エラー】Lドライブの割り当てに失敗しました」のダイアログが表示。
    9.「E:\<ユーザー名>\log\Network_Drive_Mapping.log」を確認すると以下のログが出力されている。

    【情報】 日付と時刻:09/26/2019 12:48:23 説明:Dドライブを切断しました。
    【エラー】 日付と時刻:09/26/2019 12:48:25 説明:Dドライブの割り当てに失敗しました。
    【情報】 日付と時刻:09/26/2019 12:48:26 説明:Lドライブを切断しました。
    【エラー】 日付と時刻:09/26/2019 12:48:27 説明:Lドライブの割り当てに失敗しました。

    パターン2では、Dドライブ、Lドライブが割り当てられていない状態ですが、「切断しました」のダイアログが表示されました。

    <パターン2> D/Lドライブの割り当てがされていない状態

    1.「【情報】Dドライブを切断しました」のダイアログが表示。
    2.「システムエラー67が発生しました。ネットワーク名が見つかりません。」のメッセージが表示。
    3.「【エラー】Dドライブの割り当てに失敗しました」のダイアログが表示。
    4.「【情報】Lドライブを切断しました」のダイアログが表示。
    5.「システムエラー67が発生しました。ネットワーク名が見つかりません。」のメッセージが表示。
    6.「【エラー】Lドライブの割り当てに失敗しました」のダイアログが表示。
    7.「E:\<ユーザー名>\log\Network_Drive_Mapping.log」を確認すると以下のログが出力されている。

    【情報】 日付と時刻:09/26/2019 12:52:13 説明:Dドライブを切断しました。
    【エラー】 日付と時刻:09/26/2019 12:52:15 説明:Dドライブの割り当てに失敗しました。
    【情報】 日付と時刻:09/26/2019 12:52:16 説明:Lドライブを切断しました。
    【エラー】 日付と時刻:09/26/2019 12:52:18 説明:Lドライブの割り当てに失敗しました。

    パターン3では、Dドライブ、Lドライブを開いていない状態ですが、「開かれていますが切断しますか?」のダイアログが表示され、D/Lドライブが割り当てられていないのに「割り当てをしました」のダイアログが表示されました。「msg >> LogFolder\LogFile」の実行結果は、「E:\<ユーザー名>\log\Network_Drive_Mapping.log」にありませんでした。

    <パターン3> D/Lドライブの割り当てがされていて、Dドライブ、Lドライブを開いていない状態で「msg >> LogFolder\LogFile」を追加。


    1.「開かれていますが切断しますか?」のダイアログで「はい」ボタンを押下。
    2.「【情報】Dドライブを切断しました」のダイアログが表示。
    3.「システムエラー67が発生しました。ネットワーク名が見つかりません。」のメッセージが表示。
    4.「【情報】Dドライブの割り当てをしました」のダイアログが表示。
    5.「開かれていますが切断しますか?」のダイアログで「はい」ボタンを押下。
    6.「【情報】Lドライブを切断しました」のダイアログが表示。
    7.「システムエラー67が発生しました。ネットワーク名が見つかりません。」のメッセージが表示。
    8.「【情報】Lドライブの割り当てをしました」のダイアログが表示。
    9.「E:\<ユーザー名>\log\Network_Drive_Mapping.log」を確認すると以下のログが出力されている。

    【情報】 日付と時刻:09/26/2019 13:22:23 説明:Dドライブを切断しました。
    【情報】 日付と時刻:09/26/2019 13:22:25 説明:Dドライブを割り当てしました。
    【情報】 日付と時刻:09/26/2019 13:22:36 説明:Lドライブを切断しました。
    【情報】 日付と時刻:09/26/2019 13:22:38 説明:Lドライブを割り当てしました。

    10.D/Lドライブの割り当てが行われていない。

    # ------------------+---------------------------------------------------------- # # プログラム名 | Network_Drive_Mapping.ps1 # # ------------------+---------------------------------------------------------- # # プログラムの概要 | ログオンスクリプトによるネットワークドライブの割り当てに # # | 失敗した場合、本スクリプトを使用してネットワークドライブ # # | の割り当てを行う。 # # ------------------+-----------------------------------------------------------# # ------------------------------------ # □ 定義 (フォーム) # ------------------------------------ # -- アセンブリの読み込み -- Add-Type -AssemblyName System.Windows.Forms Add-Type -AssemblyName System.Drawing # ------------------------------------ # □ 定義 (ログ) # ------------------------------------ # -- ログフォルダ -- $LogFolder = "E:\$env:USERNAME\Log" # -- ログファイル -- $LogFile = "Network_Drive_Mapping.log" # ------------------------------------ # □ 定義 (ユーザー名) # ------------------------------------ # -- ユーザー名 -- $UserName=$env:USERNAME # ----------+---------------------------------- # #  関数 | delete_drive # # ----------+---------------------------------- # # 概要 | ネットワークドライブを切断する。 # # ----------+---------------------------------- # # 引数 | $Drive # # ----------+---------------------------------- # # 戻り値 | $true または $false # # ----------+---------------------------------- # function delete_drive { param( [string]$Drive ) # 切断する $msg = net use $Drive /delete /no if($? -eq $true) # 切断できた { return $true } if($null -eq $msg -or -not @($msg)[0].Contains("との接続にオープン ファイルや未実行のディレクトリ検索があります。")) { # 理由は不明だが切断できない $Date = Get-Date "【エラー】日付と時刻:" + $Date + " 説明:${Drive}ドライブの切断に失敗しました。" >> $LogFolder\$LogFile $dialogResult = [System.Windows.Forms.MessageBox]::Show("【エラー】${Drive}ドライブの切断に失敗しました") return $false } $dialogResult = [System.Windows.Forms.MessageBox]::Show( "開かれていますが切断しますか?", "", [System.Windows.Forms.MessageBoxButtons]::YesNo ) if($dialogResult -eq [System.Windows.Forms.DialogResult]::No) { #ドライブを切断せず終了 $Date = Get-Date "【情報】日付と時刻:" + $Date + " 説明:${Drive}ドライブが開かれており、切断を行いませんでした。" >> $LogFolder\$LogFile [System.Windows.Forms.MessageBox]::Show("【情報】${Drive}が開かれており、切断を行いませんでした") return $false } # 強制切断する $msg = net use $Drive /delete /yes if($? -eq $false) # 切断できなかった {  $Date = Get-Date "【エラー】日付と時刻:" + $Date + " 説明:${Drive}ドライブの切断に失敗しました。" >> $LogFolder\$LogFile $dialogResult = [System.Windows.Forms.MessageBox]::Show("【エラー】${Drive}ドライブの切断に失敗しました") return $false } return $true } # ----------+---------------------------------- # #  関数 | map_drive # # ----------+---------------------------------- # # 概要 | ネットワークドライブを指定した # # | 共有フォルダに割り当てる。 # # ----------+---------------------------------- # # 引数 | $Drive, $Folder # # ----------+---------------------------------- # # 戻り値 | なし         # # ----------+---------------------------------- # function map_drive { param( [string]$Drive, [string]$Folder ) if(Test-Path $Drive) # ドライブが既に割り当てられている { # ドライブを切断 $result = delete_drive -Drive $Drive if($result -eq $false) # 切断に失敗した場合は終了 { return } } # ドライブを指定共有フォルダに割り当てる $msg = net use $Drive $Folder
      $msg >> $LogFolder\$LogFile if($? -eq $true) { $Date = Get-Date "【情報】日付と時刻:" + $Date + " 説明:${Drive}ドライブを切断しました。" >> $LogFolder\$LogFile [System.Windows.Forms.MessageBox]::Show("【情報】${Drive}ドライブを切断しました") $Date = Get-Date "【情報】日付と時刻:" + $Date + " 説明:${Drive}ドライブを割り当てしました。" >> $LogFolder\$LogFile     $dialogResult = [System.Windows.Forms.MessageBox]::Show("【情報】${Drive}ドライブを割り当てしました") } else { $Date = Get-Date "【情報】日付と時刻:" + $Date + " 説明:${Drive}ドライブを切断しました。" >> $LogFolder\$LogFile     [System.Windows.Forms.MessageBox]::Show("【情報】${Drive}ドライブを切断しました") $Date = Get-Date "【エラー】日付と時刻:" + $Date + " 説明:${Drive}ドライブの割り当てに失敗しました。" >> $LogFolder\$LogFil     $dialogResult = [System.Windows.Forms.MessageBox]::Show("【エラー】${Drive}ドライブの割り当てに失敗しました") } } # ------------------------------------ # ■ 処理 # ------------------------------------ # -- ログフォルダの確認 -- if (!(Test-Path -Path $LogFolder)){ New-Item -ItemType Directory -Path $LogFolder if ($? -eq $True) { [System.Windows.Forms.MessageBox]::Show("【情報】ログフォルダを作成しました") } else { [System.Windows.Forms.MessageBox]::Show("【エラー】ログフォルダの作成に失敗しました") Exit } } # -- ログファイルの確認 -- if (!(Test-Path -Path $LogFolder\$LogFile)){ New-Item $LogFolder\$LogFile if ($? -eq $True) { [System.Windows.Forms.MessageBox]::Show("【情報】ログファイルを作成しました") } else { [System.Windows.Forms.MessageBox]::Show("【エラー】ログファイルの作成に失敗しました") Exit } } # -- Active Directoryドメインサーバーの「拡張属性29」に格納されているファイルサーバーの共有フォルダ情報取得 -- $ds = New-Object System.DirectoryServices.DirectorySearcher $ds.PageSize = 1000 $ds.Filter = "(sAMAccountName=$UserName)" $result = $ds.FindOne() $value = $result.Properties.Item("msExchExtensionAttributes29")

    map_drive -Drive "D:" -Folder "\\$value\DATA" map_drive -Drive "L:" -Folder "\\$value\MAIL"






    2019年9月26日 12:17
  • パターン1で「開かれていますが切断しますか?」が表示されるのは、実際にそのエラーが出ている(フォルダが開かれている)からと思いますが、本当に何も開いていないのにそのエラーが出る原因については何とも言えません。
    パターン2で「切断しました」が条件に表示されるのは、メッセージを表示する文が、If(Test-Path $Drive) {} を抜けた後にあるからです。
    パターン3は、エラー出力を拾うため、2>&1 を追加して下さい。
    $msg 2>&1 >> $LogFolder\$LogFile
    システムエラー67が残るだけですが・・・。
    システムエラー67の原因究明が本題ではないでしょうか?
    2019年9月26日 21:26
  •   

    パターン1で「開かれていますが切断しますか?」が表示されるのは、一度開いて閉じても、開かれているという情報はしばらく残っているため、「開かれていますが切断しますか?」が表示されるのではと推測をしています。ただ、どのくらいすると、開いてないと判断されるのかがよくわかっていません。

    <手順>

    1.D/Lドライブのフォルダを開く。
    2.D/LドライブのフォルダもD/Lドライブ閉じる。
    3.「開かれていますが切断しますか?」のダイアログで「はい」ボタンを押下。
    4.「【情報】Dドライブを切断しました」のダイアログが表示。
    5.「システムエラー67が発生しました。ネットワーク名が見つかりません。」のメッセージが表示。
    6.「【エラー】Dドライブの割り当てに失敗しました」のダイアログが表示。
    7.「開かれていますが切断しますか?」のダイアログで「はい」ボタンを押下。
    8.「【情報】Lドライブを切断しました」のダイアログが表示。
    9.「システムエラー67が発生しました。ネットワーク名が見つかりません。」のメッセージが表示。
    10.「【エラー】Lドライブの割り当てに失敗しました」のダイアログが表示。
    11.「E:\<ユーザー名>\log\Network_Drive_Mapping.log」を確認すると以下のログが出力されている。

    【情報】 日付と時刻:09/27/2019 10:26:23 説明:Dドライブを切断しました。
    【エラー】 日付と時刻:09/27/2019 10:26:23 説明:Dドライブの割り当てに失敗しました。
    【情報】 日付と時刻:09/27/2019 10:07:07 説明:Lドライブを切断しました。
    【エラー】 日付と時刻:09/27/2019 10:07:01 説明:Lドライブの割り当てに失敗しました。


    2019年9月27日 14:01
  • 「システムエラー67が発生しました。ネットワーク名が見つかりません。」のメッセージでネットワークドライブの割り当てが行えないと言う問題が現時点での本題になります。

    「$msg 2>&1 >> $LogFolder\$LogFile」を仕掛けましたが、「E:\<ユーザー名>\log\Network_Drive_Mapping.log」に出力されていませんでした。

    1.「【情報】Dドライブを切断しました」のダイアログが表示。
    2.「システムエラー67が発生しました。ネットワーク名が見つかりません。」のメッセージが表示。
    3.「【情報】Dドライブを割り当てしました」のダイアログが表示。
    4.「【情報】Lドライブを切断しました」のダイアログが表示。
    5.「システムエラー67が発生しました。ネットワーク名が見つかりません。」のメッセージが表示。
    6.「【情報】Lドライブを割り当てしました」のダイアログが表示。
    7.「E:\<ユーザー名>\log\Network_Drive_Mapping.log」を確認すると以下のログが出力されている。

    【情報】 日付と時刻:09/27/2019 09:33:11 説明:Dドライブを切断しました。
    【情報】 日付と時刻:09/27/2019 09:33:12 説明:Dドライブを割り当てしました。
    【情報】 日付と時刻:09/27/2019 09:33:13 説明:Lドライブを切断しました。
    【情報】 日付と時刻:09/27/2019 09:33:14 説明:Lドライブを割り当てしました。

    8.D/Lドライブの割り当てが行われていない。

    # ------------------+---------------------------------------------------------- #
    #  プログラム名     | Network_Drive_Mapping.ps1                                 #
    # ------------------+---------------------------------------------------------- #
    #  プログラムの概要 | ログオンスクリプトによるネットワークドライブの割り当てに  #
    #                   | 失敗した場合、本スクリプトを使用してネットワークドライブ  #
    #                   | の割り当てを行う。                                        #
    # ------------------+-----------------------------------------------------------#
    
    # ------------------------------------
    #  □ 定義 (フォーム)
    # ------------------------------------
    
    # -- アセンブリの読み込み --
    Add-Type -AssemblyName System.Windows.Forms
    Add-Type -AssemblyName System.Drawing
    
    # ------------------------------------
    #  □ 定義 (ログ)
    # ------------------------------------
    
    # -- ログフォルダ --
    $LogFolder = "E:\$env:USERNAME\Log"
    
    # -- ログファイル --
    $LogFile = "Network_Drive_Mapping.log"
    
    # ------------------------------------
    #  □ 定義 (ユーザー名)
    # ------------------------------------
    
    # -- ユーザー名 --
    $UserName=$env:USERNAME
    
    # ----------+---------------------------------- #
    #   関数   | delete_drive                      #
    # ----------+---------------------------------- #
    #    概要   | ネットワークドライブを切断する。  #
    # ----------+---------------------------------- #
    #    引数   | $Drive                            #
    # ----------+---------------------------------- #
    #   戻り値  | $true または $false               #
    # ----------+---------------------------------- #
    function delete_drive
    {
        param(
            [string]$Drive
        )
    
        # 切断する
        $msg = net use $Drive /delete /no
    $msg 2>&1 >> $LogFolder\$LogFile if($? -eq $true) # 切断できた { return $true } if($null -eq $msg -or -not @($msg)[0].Contains("との接続にオープン ファイルや未実行のディレクトリ検索があります。")) { # 理由は不明だが切断できない $Date = Get-Date "【エラー】日付と時刻:" + $Date + " 説明:${Drive}ドライブの切断に失敗しました。" >> $LogFolder\$LogFile $dialogResult = [System.Windows.Forms.MessageBox]::Show("【エラー】${Drive}ドライブの切断に失敗しました") return $false } $dialogResult = [System.Windows.Forms.MessageBox]::Show( "開かれていますが切断しますか?", "", [System.Windows.Forms.MessageBoxButtons]::YesNo ) if($dialogResult -eq [System.Windows.Forms.DialogResult]::No) { #ドライブを切断せず終了 $Date = Get-Date "【情報】日付と時刻:" + $Date + " 説明:${Drive}ドライブが開かれており、切断を行いませんでした。" >> $LogFolder\$LogFile [System.Windows.Forms.MessageBox]::Show("【情報】${Drive}が開かれており、切断を行いませんでした") return $false } # 強制切断する $msg = net use $Drive /delete /yes
    $msg 2>&1 >> $LogFolder\$LogFile  if($? -eq $false) # 切断できなかった {  $Date = Get-Date "【エラー】日付と時刻:" + $Date + " 説明:${Drive}ドライブの切断に失敗しました。" >> $LogFolder\$LogFile $dialogResult = [System.Windows.Forms.MessageBox]::Show("【エラー】${Drive}ドライブの切断に失敗しました") return $false } return $true } # ----------+---------------------------------- # #  関数 | map_drive # # ----------+---------------------------------- # # 概要 | ネットワークドライブを指定した # # | 共有フォルダに割り当てる。 # # ----------+---------------------------------- # # 引数 | $Drive, $Folder # # ----------+---------------------------------- # # 戻り値 | なし         # # ----------+---------------------------------- # function map_drive { param( [string]$Drive, [string]$Folder ) if(Test-Path $Drive) # ドライブが既に割り当てられている { # ドライブを切断 $result = delete_drive -Drive $Drive if($result -eq $false) # 切断に失敗した場合は終了 { return } } # ドライブを指定共有フォルダに割り当てる $msg = net use $Drive $Folder   $msg 2>&1 >> $LogFolder\$LogFile if($? -eq $true) { $Date = Get-Date "【情報】日付と時刻:" + $Date + " 説明:${Drive}ドライブを切断しました。" >> $LogFolder\$LogFile [System.Windows.Forms.MessageBox]::Show("【情報】${Drive}ドライブを切断しました") $Date = Get-Date "【情報】日付と時刻:" + $Date + " 説明:${Drive}ドライブを割り当てしました。" >> $LogFolder\$LogFile     $dialogResult = [System.Windows.Forms.MessageBox]::Show("【情報】${Drive}ドライブを割り当てしました") } else { $Date = Get-Date "【情報】日付と時刻:" + $Date + " 説明:${Drive}ドライブを切断しました。" >> $LogFolder\$LogFile     [System.Windows.Forms.MessageBox]::Show("【情報】${Drive}ドライブを切断しました") $Date = Get-Date "【エラー】日付と時刻:" + $Date + " 説明:${Drive}ドライブの割り当てに失敗しました。" >> $LogFolder\$LogFil     $dialogResult = [System.Windows.Forms.MessageBox]::Show("【エラー】${Drive}ドライブの割り当てに失敗しました") } } # ------------------------------------ # ■ 処理 # ------------------------------------ # -- ログフォルダの確認 -- if (!(Test-Path -Path $LogFolder)){ New-Item -ItemType Directory -Path $LogFolder if ($? -eq $True) { [System.Windows.Forms.MessageBox]::Show("【情報】ログフォルダを作成しました") } else { [System.Windows.Forms.MessageBox]::Show("【エラー】ログフォルダの作成に失敗しました") Exit } } # -- ログファイルの確認 -- if (!(Test-Path -Path $LogFolder\$LogFile)){ New-Item $LogFolder\$LogFile if ($? -eq $True) { [System.Windows.Forms.MessageBox]::Show("【情報】ログファイルを作成しました") } else { [System.Windows.Forms.MessageBox]::Show("【エラー】ログファイルの作成に失敗しました") Exit } } # -- Active Directoryドメインサーバーの「拡張属性29」に格納されているファイルサーバーの共有フォルダ情報取得 -- $ds = New-Object System.DirectoryServices.DirectorySearcher $ds.PageSize = 1000 $ds.Filter = "(sAMAccountName=$UserName)" $result = $ds.FindOne() $value = $result.Properties.Item("msExchExtensionAttributes29") map_drive -Drive "D:" -Folder "\\$value\DATA2" map_drive -Drive "L:" -Folder "\\$value\MAIL"

    自分が作成したスクリプトでは、D/Lドライブの切断、D/Lドライブの割り当てが行えており、「システムエラー67が発生しました。ネットワーク名が見つかりません。」のメッセージになる理由を調べていますが、調べても特に問題となる箇所が見られないので、わからない状況です。

    1.「D: が削除されました。コマンドが正常に実行されました。」のメッセージが表示。
    2.「【情報】Dドライブを割り当てしました」のダイアログが表示。
    3.「L: が削除されました。コマンドが正常に実行されました。」のメッセージが表示。
    4.「【情報】Lドライブを割り当てしました」のダイアログが表示。
    5.「E:\<ユーザー名>\log\Network_Drive_Mapping.log」を確認すると以下のログが出力されている。

    【情報】 日付と時刻: 09/27/2019 10:26:23 説明:Dドライブは割り当てをされています。
    【情報】 日付と時刻:09/27/2019 10:26:23 説明:Dドライブを切断しました。
    【情報】 日付と時刻:09/27/2019 10:26:23 説明:Dドライブを割り当てしました。
    【情報】 日付と時刻:09/27/2019 10:28:21 説明:Lドライブは割り当てをされています。
    【情報】 日付と時刻:09/27/2019 10:28:21 説明:Lドライブを切断しました。
    【情報】 日付と時刻:09/27/2019 10:28:21 説明:Lドライブを割り当てしました。

    6.D/Lドライブの割り当てが行われている。

    # ------------------+---------------------------------------------------------- #
    #  プログラム名     | Network_Drive_Mapping.ps1                                 #
    # ------------------+---------------------------------------------------------- #
    #  プログラムの概要 | ログインスクリプトによるネットワークドライブの割り当てに  #
    #                   | 失敗した場合、本スクリプトを使用してネットワークドライブ  #
    #                   | の割り当てを行う。                                       #
    # ------------------+-----------------------------------------------------------#
    
    # ------------------------------------
    #  □ 定義 (フォーム)
     # ------------------------------------
    
    # -- アセンブリの読み込み --
    Add-Type -AssemblyName System.Windows.Forms
    Add-Type -AssemblyName System.Drawing
    
    # ------------------------------------
    #  □ 定義 (ログ)
    # ------------------------------------
    
    # -- ログフォルダ --
    $LogFolder="E:\$env:USERNAME\Log"
    
    # -- ログファイル --
    $LogFile="Network_Drive_Mapping.log"
    
    # ------------------------------------
    #  □ 定義 (ユーザー名)
    # ------------------------------------
    
    # -- ユーザー名 --
    $UserName=$env:USERNAME
    
    # ------------------------------------
    #  ■ 処理
    # ------------------------------------
    
    # -- ログフォルダの確認 --
    if (!(Test-Path -Path $LogFolder)){
          New-Item -ItemType Directory -Path $LogFolder
          if ($? -eq $True) {
              [System.Windows.Forms.MessageBox]::Show("【情報】ログフォルダを作成しました")
          } else {
              [System.Windows.Forms.MessageBox]::Show("【エラー】ログフォルダの作成に失敗しました")
              Exit
          }
    }
    
    # -- ログファイルの確認 --
    if (!(Test-Path -Path $LogFolder\$LogFile)){
          New-Item $LogFolder\$LogFile
          if ($? -eq $True) {
              [System.Windows.Forms.MessageBox]::Show("【情報】ログファイルを作成しました")
          } else {
              [System.Windows.Forms.MessageBox]::Show("【エラー】ログファイルの作成に失敗しました")
              Exit
          }
    }
    
    # -- Active Directoryドメインサーバーの「拡張属性29」に格納されているファイルサーバーの共有フォルダ情報取得 --
    $ds = New-Object System.DirectoryServices.DirectorySearcher
    $ds.PageSize = 1000
    $ds.Filter = "(sAMAccountName=$UserName)"
    $result = $ds.FindOne()
    $value = $result.Properties.Item("msExchExtensionAttributes29")
    
    $result = (Test-Path "d:")
    if ($result) {
        $Date = Get-Date
        "【情報】日付と時刻:" + $Date + " 説明:Dドライブは割り当てされています。" >> $LogFolder\$LogFile
        net use D: /delete
        if ($? -eq $True) {
            $Date = Get-Date
            "【情報】日付と時刻:" + $Date + " 説明:Dドライブを切断しました。" >> $LogFolder\$LogFile
            net use D: \\$value\DATA
            if ($? -eq $True) {
                $Date = Get-Date
                "【情報】日付と時刻:" + $Date + " 説明:Dドライブを割り当てしました。" >> $LogFolder\$LogFile
                [System.Windows.Forms.MessageBox]::Show("【情報】Dドライブを割り当てしました")
            } else {
                $Date = Get-Date
                "【エラー】日付と時刻:" + $Date + " 説明:Dドライブの割り当てに失敗しました。" >> $LogFolder\$LogFile
                [System.Windows.Forms.MessageBox]::Show("【エラー】Dドライブを割り当てに失敗しました")
            }
        } else {
            $Date = Get-Date
            "【エラー】日付と時刻:" + $Date + " 説明:Dドライブの切断に失敗しました。" >> $LogFolder\$LogFile
            [System.Windows.Forms.MessageBox]::Show("【エラー】Dドライブの切断に失敗しました")
        }
    } else {
        $Date = Get-Date
        "【情報】日付と時刻:" + $Date + " 説明:Dドライブは割り当てされていません。" >> $LogFolder\$LogFile
        net use D: \\$value\DATA
        if ($? -eq $True) {
            $Date = Get-Date
            "【情報】日付と時刻:" + $Date + " 説明:Dドライブを割り当てしました。" >> $LogFolder\$LogFile
            [System.Windows.Forms.MessageBox]::Show("【情報】Dドライブを割り当てしました")
        } else {
            $Date = Get-Date
            "【エラー】日付と時刻:" + $Date + " 説明:Dドライブの割り当てに失敗しました。" >> $LogFolder\$LogFile
            [System.Windows.Forms.MessageBox]::Show("【エラー】Dドライブを割り当てに失敗しました")
        }
    }
    
    $result = (Test-Path "l:")
    if ($result) {
        $Date = Get-Date
        "【情報】日付と時刻:" + $Date + " 説明:Lドライブは割り当てされています。" >> $LogFolder\$LogFile
        net use L: /delete
        if ($? -eq $True) {
            $Date = Get-Date
            "【情報】日付と時刻:" + $Date + " 説明:Lドライブを切断しました。" >> $LogFolder\$LogFile
            net use L: \\$value\MAIL
            if ($? -eq $True) {
                $Date = Get-Date
                "【情報】日付と時刻:" + $Date + " 説明:Lドライブを割り当てしました。" >> $LogFolder\$LogFile
                [System.Windows.Forms.MessageBox]::Show("【情報】Lドライブを割り当てしました")
            } else {
                $Date = Get-Date
                "【エラー】日付と時刻:" + $Date + " 説明:Lドライブの割り当てに失敗しました。" >> $LogFolder\$LogFile
                [System.Windows.Forms.MessageBox]::Show("【エラー】Lドライブを割り当てに失敗しました")
            }
        } else {
            $Date = Get-Date
            "【エラー】日付と時刻:" + $Date + " 説明:Lドライブの切断に失敗しました。" >> $LogFolder\$LogFile
            [System.Windows.Forms.MessageBox]::Show("【エラー】Lドライブの切断に失敗しました")
        }
    } else {
        $Date = Get-Date
        "【情報】日付と時刻:" + $Date + " 説明:Lドライブは割り当てされていません。" >> $LogFolder\$LogFile
        net use L: \\$value\MAIL
        if ($? -eq $True) {
            $Date = Get-Date
            "【情報】日付と時刻:" + $Date + " 説明:Lドライブを割り当てしました。" >> $LogFolder\$LogFile
            [System.Windows.Forms.MessageBox]::Show("【情報】Lドライブを割り当てしました")
        } else {
            $Date = Get-Date
            "【エラー】日付と時刻:" + $Date + " 説明:Lドライブの割り当てに失敗しました。" >> $LogFolder\$LogFile
            [System.Windows.Forms.MessageBox]::Show("【エラー】Lドライブを割り当てに失敗しました")
        }
    }



    2019年9月27日 14:13
  • 詳細までは把握できていませんが、delete_drive関数内で、ご自身で追加された[System.Windows.Forms.MessageBox]::Show()メソッドの戻り値を変数で受けていない部分があり、そのために関数出力に$true/$false以外に、DialogResultの値が混ざってしまっている可能性があります。関数の出力を条件判定に利用しているので、$true/$false以外の値が出力されないようにしてください。

    また、

        $msg = net use $Drive /delete /yes
        $msg 2>&1 >> $LogFolder\$LogFile 

        if($? -eq $false) # 切断できなかった
        {…

    この部分には複数の問題があります。

    まず、ネイティブコマンド(ここではnet.exe)の実行結果を$msg変数に代入していますが、この記述だと標準出力のみ代入され、標準エラー出力の値は捨てられます。

    net.exe実行時の標準エラー出力を2>&1により標準出力に合成し、その結果を$msgに代入する必要があります。

    次に、$?自動変数は、直前の行のコマンドが失敗した時にFalseが格納されます。しかし、net.exe実行直後に$msg変数の値をファイルにリダイレクトするという行を実行しているので、$?は必ずTrueになってしまっています。

    net.exe実行直後の$?の値を変数に格納しておく等の対策が必要です。

    さらにPowerShellはネイティブコマンドが出力する標準エラー出力を、文字列ではなくErrorRecord型のオブジェクトにラッピングする仕様があるため、2>&1を用いて標準エラー出力に出された文字列を得るには、ToString()メソッドを使う等してstring型に変換する必要もあります。

    (このあたりはPowerShellでネイティブコマンドを扱うときの面倒くさい部分で、個人的にもしんどく感じる部分ではあります…)

    まとめると以下のような方法があるかと思います。

    $msg = net use $Drive /delete /yes 2>&1
    $result = $?
    $msg | foreach {$_.ToString()} >> $LogFolder\$LogFile
    if($result -eq $false)
    {…

    別解としては$LASTEXITCODE変数の値を見て、コマンド成功かどうかを確認する方法があります。$LASTEXITCODE変数は直前のコマンドがExitCodeを出力しない限りは、内容が書き換わらないことを利用します。

    ところで、スクリプトのデバッグはどのようにされていますか?
    PowerShell ISEをご利用であれば、任意の行にブレークポイントを挿入してデバッグを実行すると、ブレークポイントでデバッグを停止し、その時点での変数値を読み取ったり、ステップ実行で1行ずつ実行していくといったことが可能です。

    スクリプトがうまく動作しない場合は、まずはご自身で、変数に意図した値が格納されているか、条件分岐では想定したブロックが実行されているか等をデバッグして確認してみてください。



    2019年9月27日 18:43
    モデレータ
  • >> $msg 2>&1 >> $LogFolder\$LogFile

    失礼しました。これは恥ずかしい・・・。
    既に牟田口大介様コメントで直されてますが、$msg の実行結果の標準エラー出力拾ってもしょうがないので、net.exe の標準エラー拾わないとダメです。

    >しかし、net.exe実行直後に$msg変数の値をファイルにリダイレクトするという行を実行しているので、$?は必ずTrueになってしまっています。

    確かに、これも詰めが甘くて済みません。

    ところで、D: L: に対するTest-Path に成功しても一旦切断されていますが、
    (1) ユーザが勝手に別のネットワークリソースに割り当てたもの
    を想定されているのでしょうか?
    (2) ログオンスクリプトが成功したもの
    (3) ログオンスクリプトの失敗の処置としてユーザーがルールに従って手動で割り当てたもの
    だとしたら、Test-Pathに成功する場合でも、何か不具合があるのでしょうか?

    全く別のアプローチとして、ドライブレターは割り当てないでUNCのみの運用への切り替えは不可能でしょうか?

    私の勤め先では20年くらい前からUNCで定着しています。

    ただし、未だにUNCに対応してくれないアプリがひとつだけあり、それはバッチ起動として、ドライブレターを割り当てています。

    2019年9月28日 0:39
  • ありがとうございます。

    D: L: に対するTest-Path に成功しても一旦切断されている理由ですが、ときどき、ネットワークドライブにフォルダを作成しようとしても「このフォルダーまたはファイルが保管されているドライブでは、長いファイル名やスペースや特殊文字を含んだファイル名は扱えません。特殊文字には次の文字が含まれます。¥/ : * ? " < > |」のメッセージでフォルダを作成することができない事象になることがあり、ネットワークドライブを切断して、再度割り当てをすると改善するためそのようにしています。

    ネットワークドライブに作成しようとしているフォルダ名は長いファイル名ではなく、スペースが含まれてもおらず、特殊文字が含まれていないにもかかわらず、そのような事象になります。

    そのため、今回、ネットワークドライブを切断して、再度割り当てをするスクリプトを作成しています。

    UNCだとパスが長くなってしまい、255文字の制限に引っかかるため、ドライブレターでの割り当てで対応する運用をしています。

    UNCパスの場合、サポートする際には、すべてパスを読み上げてもらっての確認になります。
    例えば、UNCパスの場合は、\\FISESV\Sales\West/Sales1/Yamadaを読み上げてもらいますが、ドライブレターの場合、\\FISESV\Sales\West/Sales1/YamadaがDドライブで割当たっている場合、その部分は読み上げなくてよいので幾分かは楽になります。

    サポート側はどのサーバーどのフォルダにユーザーのフォルダがあるかわからないため、長いと読み上げてもらったのを書き写すのが大変になるためになります。

    ドライブレターでもその先のあるフォルダ階層が深いとヒアリングするのも大変なことは変わりがなく、たまにフォルダやファイル名の箇所が漢字になっていると異口同音の漢字があるため、間違えてしまうことはありますが・・・。

    2019年9月28日 4:30
  • ありがとうございます。

    ご教示いただきました点を確認してみることにします。

    COBOLで開発をしていた頃はDISPLAY文で変数の中身を確認してデバッグしていたのですが、PowerShellで作成し始めたばかりで、まだ、理解できていない点があるため、デバッグの方法についても勉強することにします。

    2019年9月28日 4:47
  • >自分が作成したスクリプトでは、D/Lドライブの切断、D/Lドライブの割り当てが行えており、

    であるなら、それを元に改修した方が早いでしょう。
    改修のポイントは

    $msg = net use D: /delete /no

    のようにして net コマンドの出力を変数で受けて、 

    if($null -eq $msg -or 
            -not @($msg)[0].Contains("との接続にオープン ファイルや未実行のディレクトリ検索があります。"))

    で判定です。
    $null -eq $msg で比較しているのは、出力が空で $msg が Null の場合、Contains が失敗するからです。
    -or は左辺が $True であれば、右辺は評価されません。


    Powershell ISE は、スクリプトファイル(.ps1) を右クリックして「編集」で起動できます。(スタートからでも起動できます)
    一時停止したい行で右クリックして「ブレークポイントの設定/解除」でブレークポイントを設定後、F5キーで実行すると設定した行で止まり、一時停止中に調べたい変数にマウスポインタを合わせると、変数の内容が表示されます。
    1行ずつ実行するには、F10でステップオーバー(関数の中は止めない)、F11でステップイン(関数の中に入って止める)、F12でステップアウト(関数を抜ける)を使います。

    2019年9月29日 0:34
  • ありがとうございます。

    せっかく、ご教示いただいたスクリプトなので、そちらをご使用させていただき、ログ出力、ActiveDiretoryサーバーからファイルサーバーの情報を取得する箇所を追加することで考えておりましたが、自分のスクリプトではうまくいっているので、ご教示いただいた個所を自分のスクリプトに組み入れる方法も試してみたいと思います。

    Dドライブについては、Officeなどのファイルが保存されるので「ファイルが開かれていますが、閉じますか?」でも恐らく、わかると思いますが、Lドライブについては、Outlookデータファイル(pst)が置かれるので「OutlookでOutlookデータファイル(pst)を開いていますが、Outlookを終了しますか?」にする必要があるので、そのほうが良いのかなと思っています。

    ご教示いただきましたPowershell ISEでブレークポイントを設定して変数の中身を確認することも行ってみようと思います。
    2019年9月29日 5:25
  • 自分のスクリプトに組み入れたスクリプトを作成しましたので、試してみたいと思います。

    # ------------------+---------------------------------------------------------- #
    #  プログラム名     | Network_Drive_Mapping.ps1                                 #
    # ------------------+---------------------------------------------------------- #
    #  プログラムの概要 | ログインスクリプトによるネットワークドライブの割り当てに  #
    #                   | 失敗した場合、本スクリプトを使用してネットワークドライブ  #
    #                   | の割り当てを行う。                                       #
    # ------------------+-----------------------------------------------------------#
    
    # ------------------------------------
    #  □ 定義 (フォーム)
     # ------------------------------------
    
    # -- アセンブリの読み込み --
    Add-Type -AssemblyName System.Windows.Forms
    Add-Type -AssemblyName System.Drawing
    
    # ------------------------------------
    #  □ 定義 (ログ)
    # ------------------------------------
    
    # -- ログフォルダ --
    $LogFolder="E:\$env:USERNAME\Log"
    
    # -- ログファイル --
    $LogFile="Network_Drive_Mapping.log"
    
    # ------------------------------------
    #  □ 定義 (ユーザー名)
    # ------------------------------------
    
    # -- ユーザー名 --
    $UserName=$env:USERNAME
    
    # ------------------------------------
    #  ■ 処理
    # ------------------------------------
    
    # -- ログフォルダの確認 --
    if (!(Test-Path -Path $LogFolder)){
          New-Item -ItemType Directory -Path $LogFolder
          if ($? -eq $True) {
              [System.Windows.Forms.MessageBox]::Show("【情報】ログフォルダを作成しました")
          } else {
              [System.Windows.Forms.MessageBox]::Show("【エラー】ログフォルダの作成に失敗しました")
              Exit
          }
    }
    
    # -- ログファイルの確認 --
    if (!(Test-Path -Path $LogFolder\$LogFile)){
          New-Item $LogFolder\$LogFile
          if ($? -eq $True) {
              [System.Windows.Forms.MessageBox]::Show("【情報】ログファイルを作成しました")
          } else {
              [System.Windows.Forms.MessageBox]::Show("【エラー】ログファイルの作成に失敗しました")
              Exit
          }
    }
    
    # -- Active Directoryドメインサーバーの「拡張属性29」に格納されているファイルサーバーの共有フォルダ情報取得 --
    $ds = New-Object System.DirectoryServices.DirectorySearcher
    $ds.PageSize = 1000
    $ds.Filter = "(sAMAccountName=$UserName)"
    $result = $ds.FindOne()
    $value = $result.Properties.Item("msExchExtensionAttributes29")
    
    $result = (Test-Path "d:")
    if ($result) {
        $Date = Get-Date
        "【情報】日付と時刻:" + $Date + " 説明:Dドライブは割り当てされています。" >> $LogFolder\$LogFile
        [System.Windows.Forms.MessageBox]::Show("【情報】Dドライブは割り当てをされています")
    
        $msg = net use D: /delete /no
    
        if ($? -eq $True) {
            $Date = Get-Date
            "【情報】日付と時刻:" + $Date + " 説明:Dドライブを切断しました。" >> $LogFolder\$LogFile
            [System.Windows.Forms.MessageBox]::Show("【情報】Dドライブを切断しました")
    
          net use D: \\$value\DATA
    
            if ($? -eq $True) {
                $Date = Get-Date
                "【情報】日付と時刻:" + $Date + " 説明:Dドライブを割り当てしました。" >> $LogFolder\$LogFile
                [System.Windows.Forms.MessageBox]::Show("【情報】Dドライブを割り当てしました")
            } else {
                $Date = Get-Date
                "【エラー】日付と時刻:" + $Date + " 説明:Dドライブの割り当てに失敗しました。" >> $LogFolder\$LogFile
                [System.Windows.Forms.MessageBox]::Show("【エラー】Dドライブを割り当てに失敗しました")
            }
        } else {
            if ($null -eq $msg -or
               -not @($msg)[0].Contains("との接続にオープン ファイルや未実行のディレクトリ検索があります。"))
            {
               $Date = Get-Date
               "【エラー】日付と時刻:" + $Date + " 説明:Dドライブの切断に失敗しました。" >> $LogFolder\$LogFile
               $dialogResult = [System.Windows.Forms.MessageBox]::Show("【エラー】Dドライブの切断に失敗しました")
            }
    
            $dialogResult =
            [System.Windows.Forms.MessageBox]::Show(
                "ファイルが開かれていますが切断しますか?",
                "",
                [System.Windows.Forms.MessageBoxButtons]::YesNo
            )
    
            if($dialogResult -eq [System.Windows.Forms.DialogResult]::No)
            {
               $Date = Get-Date
               "【情報】日付と時刻:" + $Date + " 説明:Dドライブを切断をしませんでしたので終了しました。" >> $LogFolder\$LogFile
               $dialogResult = [System.Windows.Forms.MessageBox]::Show("【情報】:Dドライブを切断をしませんでしたので終了しました")
            }
    
             $msg = net use D: /delete /yes
    
             if($? -eq $False)
             {
                 $Date = Get-Date
                "【エラー】日付と時刻:" + $Date + " 説明:Dドライブの切断に失敗しました" >> $LogFolder\$LogFile
                $dialogResult =
                [System.Windows.Forms.MessageBox]::Show("【エラー】Dドライブの切断に失敗しました")
             }
    
             $Date = Get-Date
             "【情報】日付と時刻:" + $Date + " 説明:Dドライブを切断しました。" >> $LogFolder\$LogFile
             $dialogResult =
              [System.Windows.Forms.MessageBox]::Show("【情報】Dドライブの切断にしました")
             net use D: \\$value\DATA
    
             if ($? -eq $True) {
                 $Date = Get-Date
                 "【情報】日付と時刻:" + $Date + " 説明:Dドライブを割り当てしました。" >> $LogFolder\$LogFile
                 [System.Windows.Forms.MessageBox]::Show("【情報】Dドライブを割り当てしました")
             } else {
                 $Date = Get-Date
                 "【エラー】日付と時刻:" + $Date + " 説明:Dドライブの割り当てに失敗しました。" >> $LogFolder\$LogFile
                [System.Windows.Forms.MessageBox]::Show("【エラー】Dドライブを割り当てに失敗しました")
             }
        }
    } else {
        $Date = Get-Date
        "【情報】日付と時刻:" + $Date + " 説明:Dドライブは割り当てされていません。" >> $LogFolder\$LogFile
        [System.Windows.Forms.MessageBox]::Show("【情報】Dドライブは割り当てされていません")
    
        net use D: \\$value\DATA
    
        if ($? -eq $True) {
            $Date = Get-Date
            "【情報】日付と時刻:" + $Date + " 説明:Dドライブを割り当てしました。" >> $LogFolder\$LogFile
            [System.Windows.Forms.MessageBox]::Show("【情報】Dドライブを割り当てしました")
        } else {
            $Date = Get-Date
            "【エラー】日付と時刻:" + $Date + " 説明:Dドライブの割り当てに失敗しました。" >> $LogFolder\$LogFile
           [System.Windows.Forms.MessageBox]::Show("【エラー】Dドライブを割り当てに失敗しました")
        }
    }
    
    $result = (Test-Path "l:")
    if ($result) {
        $Date = Get-Date
        "【情報】日付と時刻:" + $Date + " 説明:Lドライブは割り当てされています。" >> $LogFolder\$LogFile
        [System.Windows.Forms.MessageBox]::Show("【情報】Lドライブは割り当てをされています")
    
        $msg = net use L: /delete /no
    
        if ($? -eq $True) {
            $Date = Get-Date
            "【情報】日付と時刻:" + $Date + " 説明:Lドライブを切断しました。" >> $LogFolder\$LogFile
            [System.Windows.Forms.MessageBox]::Show("【情報】Lドライブを切断しました")
    
          net use L: \\$value\MAIL
    
            if ($? -eq $True) {
                $Date = Get-Date
                "【情報】日付と時刻:" + $Date + " 説明:Lドライブを割り当てしました。" >> $LogFolder\$LogFile
                [System.Windows.Forms.MessageBox]::Show("【情報】Lドライブを割り当てしました")
            } else {
                $Date = Get-Date
                "【エラー】日付と時刻:" + $Date + " 説明:Lドライブの割り当てに失敗しました。" >> $LogFolder\$LogFile
                [System.Windows.Forms.MessageBox]::Show("【エラー】Lドライブを割り当てに失敗しました")
            }
        } else {
            if ($null -eq $msg -or
               -not @($msg)[0].Contains("との接続にオープン ファイルや未実行のディレクトリ検索があります。"))
            {
               $Date = Get-Date
               "【エラー】日付と時刻:" + $Date + " 説明:Lドライブの切断に失敗しました。" >> $LogFolder\$LogFile
               $dialogResult = [System.Windows.Forms.MessageBox]::Show("【エラー】Lドライブの切断に失敗しました")
            }
    
            $dialogResult =
            [System.Windows.Forms.MessageBox]::Show(
                "OutlookでOutlookデータファイル(pst)が開かれていますがOutlookを終了せずに切断しますか?",
                "",
                [System.Windows.Forms.MessageBoxButtons]::YesNo
            )
    
            if($dialogResult -eq [System.Windows.Forms.DialogResult]::No)
            {
               $Date = Get-Date
               "【情報】日付と時刻:" + $Date + " 説明:Lドライブを切断をしませんでしたので終了しました。" >> $LogFolder\$LogFile
               $dialogResult = [System.Windows.Forms.MessageBox]::Show("【情報】:Lドライブを切断をしませんでしたので終了しました")
            }
    
             $msg = net use L: /delete /yes
    
             if($? -eq $False)
             {
                 $Date = Get-Date
                "【エラー】日付と時刻:" + $Date + " 説明:Lドライブの切断に失敗しました" >> $LogFolder\$LogFile
                $dialogResult =
                [System.Windows.Forms.MessageBox]::Show("【エラー】Lドライブの切断に失敗しました")
             }
    
             $Date = Get-Date
             "【情報】日付と時刻:" + $Date + " 説明:Lドライブを切断しました。" >> $LogFolder\$LogFile
             $dialogResult =
              [System.Windows.Forms.MessageBox]::Show("【情報】Lドライブの切断にしました")
             net use L: \\$value\MAIL
    
             if ($? -eq $True) {
                 $Date = Get-Date
                 "【情報】日付と時刻:" + $Date + " 説明:Lドライブを割り当てしました。" >> $LogFolder\$LogFile
                 [System.Windows.Forms.MessageBox]::Show("【情報】Lドライブを割り当てしました")
             } else {
                 $Date = Get-Date
                 "【エラー】日付と時刻:" + $Date + " 説明:Lドライブの割り当てに失敗しました。" >> $LogFolder\$LogFile
                [System.Windows.Forms.MessageBox]::Show("【エラー】Lドライブを割り当てに失敗しました")
             }
        }
    } else {
        $Date = Get-Date
        "【情報】日付と時刻:" + $Date + " 説明:Lドライブは割り当てされていません。" >> $LogFolder\$LogFile
        [System.Windows.Forms.MessageBox]::Show("【情報】Lドライブは割り当てされていません")
    
        net use L: \\$value\MAIL
    
        if ($? -eq $True) {
            $Date = Get-Date
            "【情報】日付と時刻:" + $Date + " 説明:Lドライブを割り当てしました。" >> $LogFolder\$LogFile
            [System.Windows.Forms.MessageBox]::Show("【情報】Lドライブを割り当てしました")
        } else {
            $Date = Get-Date
            "【エラー】日付と時刻:" + $Date + " 説明:Lドライブの割り当てに失敗しました。" >> $LogFolder\$LogFile
           [System.Windows.Forms.MessageBox]::Show("【エラー】Lドライブを割り当てに失敗しました")
        }
    }

    2019年9月29日 12:34
  • PowerShell ISEにおいて、ブレークポイントを「$msg = net use $Drive $Folder」にして確認しましたところ、$valuseに情報がありませんでした。そのため、「net user D: \\\DATA」、「net user L: \\\MAIL」で実行されてしまい、.「システムエラー67が発生しました。ネットワーク名が見つかりません。」のメッセージが表示されたようです。

    以下の箇所を、コピーし直して問題は解決しました。しかし、以下の箇所は手入力したものではなく、問題なかったものからコピーしてきたので、疑問は残りますが、解決いたしました。

    $ds = New-Object System.DirectoryServices.DirectorySearcher
    $ds.PageSize = 1000
    $ds.Filter = "(sAMAccountName=$UserName)"
    $result = $ds.FindOne()
    $value = $result.Properties.Item("msExchExtensionAttributes29")

    また、D/Lドライブが割り当てられていないにもかかわらず、「切断されました」が表示される件についても修正を行いました。

    # ------------------+---------------------------------------------------------- #
    #  プログラム名     | Network_Drive_Mapping.ps1                                 #
    # ------------------+---------------------------------------------------------- #
    #  プログラムの概要 | ログオンスクリプトによるネットワークドライブの割り当てに  #
    #                   | 失敗した場合、本スクリプトを使用してネットワークドライブ  #
    #                   | の割り当てを行う。                                        #
    # ------------------+-----------------------------------------------------------#
    
    # ------------------------------------
    #  □ 定義 (フォーム)
    # ------------------------------------
    
    # -- アセンブリの読み込み --
    Add-Type -AssemblyName System.Windows.Forms
    Add-Type -AssemblyName System.Drawing
    
    # ------------------------------------
    #  □ 定義 (ログ)
    # ------------------------------------
    
    # -- ログフォルダ --
    $LogFolder = "E:\$env:USERNAME\Log"
    
    # -- ログファイル --
    $LogFile = "Network_Drive_Mapping.log"
    
    # ------------------------------------
    #  □ 定義 (ユーザー名)
    # ------------------------------------
    
    # -- ユーザー名 --
    $UserName=$env:USERNAME
    
    # ----------+---------------------------------- #
    #   関数   | delete_drive                      #
    # ----------+---------------------------------- #
    #    概要   | ネットワークドライブを切断する。  #
    # ----------+---------------------------------- #
    #    引数   | $Drive                            #
    # ----------+---------------------------------- #
    #   戻り値  | $true または $false               #
    # ----------+---------------------------------- #
    function delete_drive
    {
        param(
            [string]$Drive
        )
    
        # 切断する
        $msg = net use $Drive /delete /no
    
        if($? -eq $true) # 切断できた
        {
            return $true
        }
    
        if($null -eq $msg -or 
            -not @($msg)[0].Contains("との接続にオープン ファイルや未実行のディレクトリ検索があります。"))
        {
            # 理由は不明だが切断できない
            $Date = Get-Date
            "【エラー】日付と時刻:" + $Date + " 説明:${Drive}ドライブの切断に失敗しました。" >> $LogFolder\$LogFile
    
            $dialogResult =
                [System.Windows.Forms.MessageBox]::Show("【エラー】${Drive}ドライブの切断に失敗しました")
            return $false
        }
    
        $dialogResult =
            [System.Windows.Forms.MessageBox]::Show(
                "開かれていますが切断しますか?",
                "",
                [System.Windows.Forms.MessageBoxButtons]::YesNo
            )
    
        if($dialogResult -eq [System.Windows.Forms.DialogResult]::No)
        {
            #ドライブを切断せず終了
            $Date = Get-Date
            "【情報】日付と時刻:" + $Date + " 説明:${Drive}ドライブが開かれており、切断を行いませんでした。" >> $LogFolder\$LogFile
            [System.Windows.Forms.MessageBox]::Show("【情報】${Drive}が開かれており、切断を行いませんでした")
            return $false
        }
    
        # 強制切断する
        $msg = net use $Drive /delete /yes
    
        if($? -eq $false) # 切断できなかった
        {
           $Date = Get-Date
            "【エラー】日付と時刻:" + $Date + " 説明:${Drive}ドライブの切断に失敗しました。" >> $LogFolder\$LogFile
            $dialogResult =
                [System.Windows.Forms.MessageBox]::Show("【エラー】${Drive}ドライブの切断に失敗しました")
            return $false
        }
    
        return $true
    }
    
    
    # ----------+---------------------------------- #
    #   関数   | map_drive                         #
    # ----------+---------------------------------- #
    #    概要   | ネットワークドライブを指定した    #
    #           | 共有フォルダに割り当てる。        #
    # ----------+---------------------------------- #
    #    引数   | $Drive, $Folder                   #
    # ----------+---------------------------------- #
    #   戻り値  | なし                       #
    # ----------+---------------------------------- #
    function map_drive
    {
        param(
            [string]$Drive,
            [string]$Folder
        )
    
        if(Test-Path $Drive) # ドライブが既に割り当てられている
        {
            # ドライブを切断
            $result = delete_drive -Drive $Drive
    
            if($result -eq $false) # 切断に失敗した場合は終了
            {        
                $Date = Get-Date
                "【エラー】日付と時刻:" + $Date + " 説明:${Drive}ドライブの切断に失敗しました。" >> $LogFolder\$LogFile
                [System.Windows.Forms.MessageBox]::Show("【エラー】${Drive}ドライブの切断に失敗しました")
                return
            } else {
                $Date = Get-Date
                "【情報】日付と時刻:" + $Date + " 説明:${Drive}ドライブを切断しました。" >> $LogFolder\$LogFile
                [System.Windows.Forms.MessageBox]::Show("【情報】${Drive}ドライブを切断しました")
            } 
        }
    
        # ドライブを指定共有フォルダに割り当てる
        $msg = net use $Drive $Folder
    
        if($? -eq $true)
        {
           
            $Date = Get-Date
                "【情報】日付と時刻:" + $Date + " 説明:${Drive}ドライブを割り当てしました。" >> $LogFolder\$LogFile
        $dialogResult =
                [System.Windows.Forms.MessageBox]::Show("【情報】${Drive}ドライブを割り当てしました")
        }
        else
        {
            $Date = Get-Date
                "【エラー】日付と時刻:" + $Date + " 説明:${Drive}ドライブの割り当てに失敗しました。" >> $LogFolder\$LogFil
        $dialogResult =
                [System.Windows.Forms.MessageBox]::Show("【エラー】${Drive}ドライブの割り当てに失敗しました")
        }
    }
    
    # ------------------------------------
    #  ■ 処理
    # ------------------------------------
    
    # -- ログフォルダの確認 --
    if (!(Test-Path -Path $LogFolder)){
          New-Item -ItemType Directory -Path $LogFolder
          if ($? -eq $True) {
              [System.Windows.Forms.MessageBox]::Show("【情報】ログフォルダを作成しました")
          } else {
              [System.Windows.Forms.MessageBox]::Show("【エラー】ログフォルダの作成に失敗しました")
              Exit
          }
    }
    
    # -- ログファイルの確認 --
    if (!(Test-Path -Path $LogFolder\$LogFile)){
          New-Item $LogFolder\$LogFile
          if ($? -eq $True) {
              [System.Windows.Forms.MessageBox]::Show("【情報】ログファイルを作成しました")
          } else {
              [System.Windows.Forms.MessageBox]::Show("【エラー】ログファイルの作成に失敗しました")
              Exit
          }
    }
    
    # -- Active Directoryドメインサーバーの「拡張属性29」に格納されているファイルサーバーの共有フォルダ情報取得 --
    $ds = New-Object System.DirectoryServices.DirectorySearcher
    $ds.PageSize = 1000
    $ds.Filter = "(sAMAccountName=$UserName)"
    $result = $ds.FindOne()
    $value = $result.Properties.Item("msExchExtensionAttributes29")
    
    map_drive -Drive "D:" -Folder "\\$value\DATA"
    map_drive -Drive "L:" -Folder "\\$value\MAIL"

    2019年9月30日 12:32
  • 以下が検証結果になります。

    <パターン1> D/Lドライブの割り当てがされていて、Dドライブ、Lドライブを開いていない状態

    1.「【情報】Dドライブを切断しました」のダイアログが表示。
    2.「【情報】Dドライブを割り当てしました」のダイアログが表示。
    3.「【情報】Lドライブを切断しました」のダイアログが表示。
    4.「【情報】Lドライブを割り当てしました」のダイアログが表示。
    5.「E:\<ユーザー名>\log\Network_Drive_Mapping.log」を確認すると以下のログが出力されている。

    【情報】 日付と時刻:09/30/2019 10:05:25 説明:Dドライブを切断しました。
    【情報】 日付と時刻:09/30/2019 10:05:25 説明:Dドライブを割り当てしました。
    【情報】 日付と時刻:09/30/2019 10:05:27 説明:Lドライブを切断しました。
    【情報】 日付と時刻:09/30/2019 10:05:27 説明:Lドライブを割り当てしました。
    6.D/Lドライブが割り当てられていることを確認しました。

    <パターン2> D/Lドライブの割り当てがされていて、Dドライブ、Lドライブを開いている状態

    1.「開かれていますが切断しますか?」のダイアログで「はい」ボタンを押下。
    2.「【情報】Dドライブを切断しました」のダイアログが表示。
    3.「【情報】Dドライブの割り当てをしました」のダイアログが表示。
    4.「開かれていますが切断しますか?」のダイアログで「はい」ボタンを押下。
    5.「【情報】Lドライブを切断しました」のダイアログが表示。
    6.「【情報】Lドライブの割り当てをしました」のダイアログが表示。
    7.「E:\<ユーザー名>\log\Network_Drive_Mapping.log」を確認すると以下のログが出力されている。

    【情報】 日付と時刻:09/30/2019 10:20:43 説明:Dドライブを切断しました。
    【情報】 日付と時刻:09/30/2019 10:20:44 説明:Dドライブを割り当てしました。
    【情報】 日付と時刻:09/30/2019 10:20:48 説明:Lドライブを切断しました。
    【情報】 日付と時刻:09/30/2019 10:20:49 説明:Lドライブを割り当てしました。
    8.D/Lドライブが割り当てられていることを確認しました。
    2019年9月30日 12:55