忍者ブログ

ショートカットファイルのリンク先を置換するマクロの改良~実用版~

2024年05月07日

会社で使っているNASのリンク切れが激しい。。。
もういい加減、旧NASへのリンクは撲滅したい!

そんな思いから、NAS上にあるリンク切れショートカットファイルのリンク先をVBAを使って
一括で置換することにした。

まてよ。そういや昔に同じようなものを作ったような。。。
どこまでできてたっけか。


ショートカットファイルのリンク先を置換するマクロ



使おうとして最初につまずくのが、
ショートカットファイルの一覧を集めてフルパスで指定するところ。

なんでこんな仕様にした!?


どうやら以下の記事で作ったマクロがあるので、
拡張子が.lnkでフィルタをかけて、フルパスをコピペすることを考えたみたい。

ファイル・フォルダ一覧取得ツール_VBAファイルリスト編

.lnkを集めるだけなら、コマンドプロンプトに以下のコマンドを打ち込んでもいける。

dir /b /s "対象フォルダ\*.lnk" > "出力ファイル名"



ショートカットファイルの一覧が用意できたところで
さっそく動かそうとしたらうまく動かない。

リンク先の一覧は取得できるのに、リンク先を置換するところで止まる。
あれ、止まってるところってリンク先を取得する処理なんだけど。。。

よくよく見るとソースコードちげーじゃん。

以下の記事のとおり、リンク先の一覧を取得するところについては
256バイト以上のパスでもエラーが出ないように改良したけど
リンク先を置換するモジュールにはその処理を適用してなかった。

ショートカットファイルのリンク先をショートパスで指定して文字数制限対策をした話

さぼったツケがここで出てくるとは・・・。


本当だったら、リンク先を置換するリストを用意して
一括でやってくれれば良いんだけど、修正前後のリンク先を確認するのって
それなりに手作業が入るからシートの構成はそのままにした。

ただ、NASにある全lnkファイルに対して高速で処理できるように
処理を修正。


リンク先の一覧を取得してから置換するだろうから、
リンク先のパスに置換対象文字列が含まれるかを最初に判定することにした。


あと、リンク先の置換に成功したあとも、
別のパスを指定して動作させるので、
置換に成功したパスは、ログに残すことにした。


その他のエラー処理まで見直しはできてないけど、
普通に使えるレベルにはなったな。


そんな感じで以下ソース。

Option Explicit
 
Sub ショートカットファイルリンク先を置換2()
    Dim objFS As Object:  Set objFS = CreateObject("Scripting.FileSystemObject")
    Dim objFile As Object
    Dim WSH, LnkFile, DeskTopPath As String, LnkFileName As String
    Set WSH = CreateObject("WScript.Shell")
    Dim 検索文字列 As String: 検索文字列 = Cells(4, "C")
    Dim 置換文字列 As String: 置換文字列 = Cells(5, "C")
    Dim Gyo As Long, GyoSt As Long, GyoEnd As Long
    GyoSt = 8
    GyoEnd = Cells(Rows.Count, "B").End(xlUp).Row
    '初期化処理
    Range(Cells(GyoSt, "D"), Cells(Rows.Count, "F")).ClearContents
    Range(Cells(GyoSt, "C"), Cells(Rows.Count, "C")).Font.Color = RGB(0, 0, 0)  '文字色修正
    Range(Cells(GyoSt, "B"), Cells(Rows.Count, "F")).Interior.Pattern = xlNone  '網掛け解除
    Dim bf_lnk As String, af_lnk As String, nextLogCell As Range
    For Gyo = GyoSt To GyoEnd
        DoEvents
        Application.StatusBar = Format(Gyo, "#,##0") & "/" & Format(GyoEnd, "#,##0") & "件目を処理中"
        Cells(Gyo, "A") = Gyo - GyoSt + 1
        LnkFileName = Cells(Gyo, "B").Value
        If InStr(Cells(Gyo, "C"), 検索文字列) > 0 Then
            If Right(LnkFileName, 4) = ".lnk" Then
                If リンク先のチェック(LnkFileName) > 0 Then
                    If LenB(LnkFileName) > 250 Then
                        Set objFile = objFS.GetFile(LnkFileName)    'FSOを使ってショートネームを取得する
                        Set LnkFile = WSH.CreateShortcut(objFile.shortPath)   'lenb 256を超えるとエラーになるのでショートネームに
                        Set objFile = Nothing
                    Else
                        Set LnkFile = WSH.CreateShortcut(LnkFileName)   'lenb 256を超えるとエラーになる
                    End If
                    bf_lnk = LnkFile.TargetPath
                    Cells(Gyo, "C") = bf_lnk
                    'If リンク先のチェック(bf_lnk) = 0 Then Call 黄色網掛け(Gyo, "C")
                    If UBound(Split(StrConv(bf_lnk, 2), StrConv(検索文字列, 2))) = 1 Then
                        af_lnk = Replace(bf_lnk, 検索文字列, 置換文字列, compare:=vbTextCompare)
                        Cells(Gyo, "D") = af_lnk
                        If リンク先のチェック(af_lnk) > 0 Then
                            LnkFile.TargetPath = af_lnk
                            LnkFile.Save
                            Cells(Gyo, "E").Value = "Complete !"
                            Cells(Gyo, "C").Font.Color = RGB(128, 128, 128)
                            With Worksheets("ログ")                            '成功ログを保存
                                Set nextLogCell = .Cells(Rows.Count, 1).End(xlUp).Offset(1, 0)
                                Range(Cells(Gyo, "A"), Cells(Gyo, "E")).Copy nextLogCell
                                .Cells(nextLogCell.Row, "F") = Now
                            End With
                        Else
                            Cells(Gyo, "E").Value = "Replace Link Error"
                            Call 黄色網掛け(Gyo, "D")
                        End If
                    Else
                        Cells(Gyo, "E").Value = "Search Text Error " & UBound(Split(StrConv(bf_lnk, 2), StrConv(検索文字列, 2)))
                    End If
                Else
                    Cells(Gyo, "E").Value = "No File"
                    Call 黄色網掛け(Gyo, "B")
                End If
            Else
                Cells(Gyo, "E").Value = "Link Error"
                Call 黄色網掛け(Gyo, "C")
            End If  'If Right(LnkFileName, 4) = ".lnk" Then
        Else
            Cells(Gyo, "E") = "Search Text Error "
        End If
    Next Gyo
    Set LnkFile = Nothing
    Set WSH = Nothing
        Application.StatusBar = ""
End Sub
Function リンク先のチェック(フルパス) As Long
 
    Dim fso: Set fso = CreateObject("Scripting.FileSystemObject")
    Dim flag As Long
    If fso.FileExists(フルパス) Then flag = 1
    If fso.FolderExists(フルパス) Then flag = 2
    リンク先のチェック = flag
 
    Set fso = Nothing
End Function
Function リンク先のチェックdir(フルパス) As Long
    If Dir(フルパス) <> "" Then flag = 1
    If Dir(フルパス, vbDirectory) <> "" Then flag = 2
    リンク先のチェック = flag
End Function
 
Function getshrotPath(Target As String)
    Dim fso As Object:    Set fso = CreateObject("Scripting.FileSystemObject")
    ''「C:\PROGRA~1\WINDOW~2\Skins\WINDOW~1.WMZ」を表示します
    getshrotPath = fso.GetFile(Target).shortPath
    Set fso = Nothing
End Function
 
Function shortName(ByVal FileName As String)
'ショートネイム用のユーザー定義関数 https://oshiete.goo.ne.jp/qa/9758260.html
  Dim objFS As Object:  Set objFS = CreateObject("Scripting.FileSystemObject")
  Dim objFile As Object
  If Right(FileName, 1) <> "\" Then  'フォルダーとファイルの区分け
    Set objFile = objFS.GetFile(FileName)
  Else
    Set objFile = objFS.GetFolder(FileName)
  End If
  shortName = objFile.shortPath
End Function
 
Function getTargetPath_copy(LnkFileName As String)
    Dim LfileName As String: LfileName = ThisWorkbook.path & "\tmp‡.lnk"
    With CreateObject("Scripting.FileSystemObject")
        If .FileExists(LnkFileName) = True Then
            If .FileExists(LfileName) = True Then .DeleteFile LfileName    'コピー先ファイルの削除
            .CopyFile LnkFileName, LfileName
            'With CreateObject("WScript.Shell").CreateShortcut(LfileName)
                getTargetPath_copy = CreateObject("WScript.Shell").CreateShortcut(LfileName).TargetPath
           ' End With
        Else
            Debug.Print "getTargetPath_copy LnkFileName=nothing"
            getTargetPath_copy = ""
        End If
        If .FileExists(LfileName) = True Then .DeleteFile LfileName    '後始末
    End With
End Function
 
Sub ショートカットファイルからリンク先を取得()
    '初期化処理
    Range(Cells(GyoSt, "C"), Cells(Rows.Count, "F")).ClearContents
    Range(Cells(GyoSt, "C"), Cells(Rows.Count, "C")).Font.Color = RGB(0, 0, 0)  '文字色修正
    Range(Cells(GyoSt, "B"), Cells(Rows.Count, "F")).Interior.Pattern = xlNone  '網掛け解除
    Dim objFS As Object:  Set objFS = CreateObject("Scripting.FileSystemObject")
    Dim objFile As Object
    Dim WSH: Set WSH = CreateObject("WScript.Shell")
    Dim LnkFile, DeskTopPath As String, LnkFileName As String
    Dim Gyo As Long, GyoSt As Long, GyoEnd As Long
    GyoSt = 8
    GyoEnd = Cells(Rows.Count, "B").End(xlUp).Row
    For Gyo = GyoSt To GyoEnd
        DoEvents
        Application.StatusBar = Format(Gyo, "#,##0") & "/" & Format(GyoEnd, "#,##0") & "件目を処理中"
        Cells(Gyo, "A") = Gyo - GyoSt + 1
        LnkFileName = Cells(Gyo, "B").Value
        If Right(LnkFileName, 4) = ".lnk" Then           '
            If objFS.FileExists(LnkFileName) = True Then
                If LenB(LnkFileName) > 250 Then
                    Set objFile = objFS.GetFile(LnkFileName)    'FSOを使ってショートネームを取得する
                    Set LnkFile = WSH.CreateShortcut(objFile.shortPath)   'lenb 256を超えるとエラーになるのでショートネームに
                Else
                    Set LnkFile = WSH.CreateShortcut(LnkFileName)   'lenb 256を超えるとエラーになる
                End If
                Cells(Gyo, "C") = LnkFile.TargetPath
'                If リンク先のチェック(LnkFile.TargetPath) = 0 Then
'                    Cells(Gyo, "E").Value = "Link OK"
'                Else
'                    Cells(Gyo, "E").Value = "Link Error"
'                Call 黄色網掛け(Gyo, "C")
'                End If
            Else
                Debug.Print LnkFileName
                Cells(Gyo, "E").Value = "No File"
                Call 黄色網掛け(Gyo, "B")
            End If
        Else
            Cells(Gyo, "E").Value = "Link Error"
            Call 黄色網掛け(Gyo, "C")
        End If  'If Right(LnkFileName, 4) = ".lnk" Then
    Next Gyo
    Set LnkFile = Nothing
    Set WSH = Nothing
    Application.StatusBar = ""
End Sub
 
Sub 黄色網掛け(行, 列)
    Cells(行, 列).Interior.Color = 65535
End Sub
Sub 網掛け解除(行, 列)
    Cells(行, 列).Interior.Pattern = xlNone
End Sub

Sub カレントディレクトリを取得()
    Dim fPath As String
    fPath = "\\10.20.18.2\(樹脂の生産中止について) - ショートカット.lnk"

    Dim yPos As String: yPos = InStrRev(fPath, "\")
    Dim tPath As String: tPath = Left(fPath, yPos)
    Dim fName As String: fName = Mid(fPath, yPos + 1)
    Dim shPath As String: shPath = shortName(tPath)

    With CreateObject("WScript.Shell")
        Debug.Print .CreateShortcut(shortName(tPath) & "\" & fName)
    End With
End Sub


 


 


Function shortName(ByVal FileName As String)
'ショートネイム用のユーザー定義関数
  Dim objFS As Object
  Dim objFile As Object
  Set objFS = CreateObject("Scripting.FileSystemObject")
  If Right(FileName, 1) <> "\" Then  'フォルダーとファイルの区分け
    Set objFile = objFS.GetFile(FileName)
  Else
    Set objFile = objFS.GetFolder(FileName)
  End If
  shortName = objFile.shortPath
End Function


 


Function ファイルの存在チェックfso2(フルパス) As Long
    Dim flag As Long, objFile As Object
    With CreateObject("Scripting.FileSystemObject")
        Set objFile = .GetFile(フルパス)
            If .FileExists(objFile.shortPath) Then flag = 1
            ファイルの存在チェックfso2 = flag
        Set objFile = Nothing
    End With
End Function


 


Function ファイルの存在チェックfso(フルパス) As Long
    Dim flag As Long
    With CreateObject("Scripting.FileSystemObject")
        If .FileExists(フルパス) Then flag = 1
        ファイルの存在チェックfso = flag
    End With
End Function
Function ファイルの存在チェックdir(フルパス) As Long
    Dim flag As Long
    If Dir(フルパス) <> "" Then flag = 1
    ファイルの存在チェックdir = flag
End Function
Function ファイルの存在チェックhybrid(フルパス) As Long
    Dim flag As Long
    If Dir(フルパス) <> "" Then flag = 1
    If flag = 0 Then
    With CreateObject("Scripting.FileSystemObject")
        If .FileExists(フルパス) Then flag = 1
    End With
    End If
    ファイルの存在チェックhybrid = flag
End Function


 


Sub flagtest()
    On Error Resume Next
    Dim WSH, LnkFile, DeskTopPath As String, LnkFileName As String
    Set WSH = CreateObject("WScript.Shell")

    Dim Gyo As Long, GyoSt As Long, GyoEnd As Long
    GyoSt = 8
    GyoEnd = Cells(Rows.Count, "B").End(xlUp).Row

    Dim tictoc As Double:    tictoc = Timer
    Dim buf As Long

    For Gyo = GyoSt To GyoEnd
        DoEvents
        buf = buf + ファイルの存在チェックfso2(Cells(Gyo, "B"))
    Next Gyo

    Debug.Print "ファイルの存在チェックfso2", Timer - tictoc & "秒", buf
    tictoc = Timer
    buf = 0
    Stop
    For Gyo = GyoSt To GyoEnd
        DoEvents
        buf = buf + ファイルの存在チェックdir(Cells(Gyo, "B"))
    Next Gyo

    Debug.Print "ファイルの存在チェックdir", Timer - tictoc & "秒", buf
    tictoc = Timer
    buf = 0

    For Gyo = GyoSt To GyoEnd
        DoEvents
        buf = buf + ファイルの存在チェックfso(Cells(Gyo, "B"))
    Next Gyo

    Debug.Print "ファイルの存在チェックfso", Timer - tictoc & "秒", buf
    tictoc = Timer
    buf = 0

    For Gyo = GyoSt To GyoEnd
        DoEvents
        buf = buf + ファイルの存在チェックhybrid(Cells(Gyo, "B"))
    Next Gyo

    Debug.Print "ファイルの存在チェックhybrid", Timer - tictoc & "秒", buf
    tictoc = Timer
    buf = 0

    Set LnkFile = Nothing
    Set WSH = Nothing

End Sub


PR
Comment
  Vodafone絵文字 i-mode絵文字 Ezweb絵文字