簡易PC操作ログ取得ソフト構築

知人の会社でPC周辺を保守しているのですが、簡易にPCの操作ログが取れないかと思案、、、。外部サービスだとMotexやSkySeaなどありますが小規模事業ではなかなか敷居が高いですからね。.netで簡易にできればラッキーぐらいで考えていたらアクティブウインドウからプロセスIDを取得して操作しているプロセスとウインドウヘッダがとれるようなので、ログ取得~PotgresSQLへデータインサートを行うプログラムを早速作成です。

まず適当なWindowsFormアプリケーションを作成してLabelとButtonを置いて、下記コードを作成します。

※NuGETでNPGSQLを参照しています。
 サーバーのIPをC:\Work\Serverip\server-ip.txtに書いて配置しておきます。

Imports Npgsql
Imports System
Imports System.IO
Imports System.Runtime.InteropServices
Imports System.Text
Imports System.Net
Imports System.Diagnostics
Imports System.Diagnostics.Eventing.Reader

Public Class Form1

    Public NpgSqlUIDPass As String
    Public inTime As String = "60"
    Public LastTime As Integer = 22
    Public Var As String = "N11.0.0"
    Public sComputer_Name As String = StrConv(System.Net.Dns.GetHostName, vbUpperCase)
    Public adrList As IPAddress() = Dns.GetHostAddresses(sComputer_Name)
    Public sIp As String
    Public os As String

    Public sLogPath As String = "c:\Pclog\"
    Public sIpAddress As String
    Public sUserName As String = Environment.UserName
    Private previousWindow As IntPtr
    Private previousWindowText As String

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        End
    End Sub

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        Var = "11.0.1"

        Dim adrList As IPAddress() = Dns.GetHostAddresses(sComputer_Name)

        For Each address As IPAddress In adrList
            sIpAddress = address.ToString()
        Next

        Dim ServerIP As String
        Me.Text = "PcMonitor"
        '===============================================================================
        'PostgreSQLDB接続文字列 (TEXTファイルから接続先を取得する)
        Dim cReader As New System.IO.StreamReader("C:\Work\Serverip\server-ip.txt", System.Text.Encoding.Default)
        ServerIP = cReader.ReadLine()
        cReader.Close()

        NpgSqlUIDPass = "Server=" & ServerIP & ";Port=5432;User Id=あなたのユーザー;Password=あなたのパスワード;Database=あなたのDB;TimeOut=600;CommandTimeOut=3600;Pooling=false"

        Dim sSql As String

        For Each address As IPAddress In adrList
            If address.AddressFamily = Net.Sockets.AddressFamily.InterNetwork Then
                sIp = address.ToString
            End If
        Next

        Dim moName As String = ""
        Dim moVers As String = ""
        Dim moRevi As String = ""

        Dim mc As New System.Management.ManagementClass("Win32_OperatingSystem")
        Dim moc As System.Management.ManagementObjectCollection = mc.GetInstances()

        For Each mo As System.Management.ManagementObject In moc
            moName = mo("Caption").ToString
            moVers = mo("Version").ToString
            moRevi = mo("BuildNumber").ToString
        Next

        os = moName.ToString & " Ver " & moVers

        Try

            '========================================
            'NpgSQL-PostgreSqlデータベース接続
            Dim PostgreCmd = New NpgsqlCommand
            Dim PostgreReader As Object
            Dim cPostgreSql As NpgsqlConnection = New NpgsqlConnection(NpgSqlUIDPass)
            cPostgreSql.Open()

            sSql = "delete from ms_pc where pc_name='" & sComputer_Name & "'"
            PostgreCmd = New NpgsqlCommand(sSql, cPostgreSql)
            PostgreCmd.ExecuteNonQuery()


            sSql = "insert into ms_pc values('" & sComputer_Name & "','" & sIp & "','" & Date.Now & "')"
            PostgreCmd = New NpgsqlCommand(sSql, cPostgreSql)
            PostgreCmd.ExecuteNonQuery()

            sSql = "select status from ms_status where status_no='00006'"

            PostgreCmd = New NpgsqlCommand(sSql, cPostgreSql)
            PostgreReader = PostgreCmd.ExecuteReader
            PostgreReader.read()

            LastTime = CInt(PostgreReader(0))

            PostgreReader.close()
            cPostgreSql.Close()
            '========================================

            'Me.Text = "最終" & LastTime & "迄使用可"

        Catch ex As Exception
            'オフラインの場合はPCの時間を見て対応
            LastTime = 22

            'Me.Text = "最終" & LastTime & "迄使用可"

        End Try

        Call FileLogMain()
        'Call ActiveWindowMain()
        Dim logger As New USBLogger()
        logger.StartLogging()

        Label1.Text = inTime

        Timer1.Interval = 1000
        Timer1.Start()

        Timer2.Interval = 100
        Timer2.Start()

    End Sub

    Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick

        If Label1.Text = inTime Then
            Me.Hide()
        End If

        Dim sSql As String

        If CInt(Label1.Text) = 0 Then

            Timer1.Stop()
            'ここにソース

            '=================================
            'ディフェンダーイベントログの取得
            '=================================
            Dim eventString As String = ""
            Dim eventString2 As String = ""
            Dim eventLogName As String = "Microsoft-Windows-Windows Defender/Operational"

            ' 指定した日付範囲
            Dim startDate As New DateTime(Date.Today.Year, Date.Today.Month, Date.Today.Day)
            Dim endDate As New DateTime(Date.Today.Year, Date.Today.Month, Date.Today.Day + 1)

            ' イベントログを開く
            Dim iEventLog As New EventLog(eventLogName)

            Using eventLogReader As New EventLogReader(New EventLogQuery(eventLogName, PathType.LogName))
                Dim eventRecord As EventRecord = eventLogReader.ReadEvent()

                ' 指定した日付範囲内のイベントログエントリを取得
                While eventRecord IsNot Nothing
                    If eventRecord.TimeCreated >= startDate AndAlso eventRecord.TimeCreated <= endDate Then

                        eventString = ""

                        Select Case eventRecord.Id
                            Case 1000
                                eventString = eventRecord.TimeCreated.ToString() & "," & "ディフェンダー稼働ログ,ウイルス・マルウェア対策,スキャンの開始"
                            Case 1001
                                eventString = eventRecord.TimeCreated.ToString() & "," & "ディフェンダー稼働ログ,ウイルス・マルウェア対策,スキャンの終了"
                            Case 1002
                                eventString = eventRecord.TimeCreated.ToString() & "," & "ディフェンダー稼働ログ,ウイルス・マルウェア対策,スキャンのキャンセル"
                            Case 1003
                                eventString = eventRecord.TimeCreated.ToString() & "," & "ディフェンダー稼働ログ,ウイルス・マルウェア対策,スキャンの一時停止"
                            Case 1004
                                eventString = eventRecord.TimeCreated.ToString() & "," & "ディフェンダー稼働ログ,ウイルス・マルウェア対策,スキャンの再開"
                            Case 1005
                                eventString = eventRecord.TimeCreated.ToString() & "," & "ディフェンダー稼働ログ,ウイルス・マルウェア対策,スキャンの失敗"
                            Case 1006
                                eventString = eventRecord.TimeCreated.ToString() & "," & "ディフェンダー稼働ログ,ウイルス・マルウェア対策,望ましくないアプリを検出"
                            Case 1007
                                eventString = eventRecord.TimeCreated.ToString() & "," & "ディフェンダー稼働ログ,ウイルス・マルウェア対策,望ましくないアプリの保護実施"
                            Case 1008
                                eventString = eventRecord.TimeCreated.ToString() & "," & "ディフェンダー稼働ログ,ウイルス・マルウェア対策,望ましくないアプリの保護失敗"
                            Case 1015
                                eventString = eventRecord.TimeCreated.ToString() & "," & "ディフェンダー稼働ログ,ウイルス・マルウェア対策,疑わしい動作を検出"
                            Case 1016
                                eventString = eventRecord.TimeCreated.ToString() & "," & "ディフェンダー稼働ログ,ウイルス・マルウェア対策,疑わしいアプリを検出"
                            Case 1017
                                eventString = eventRecord.TimeCreated.ToString() & "," & "ディフェンダー稼働ログ,ウイルス・マルウェア対策,疑わしいアプリの対策実施"
                            Case 1018
                                eventString = eventRecord.TimeCreated.ToString() & "," & "ディフェンダー稼働ログ,ウイルス・マルウェア対策,疑わしいアプリの対策失敗"
                            Case 1019
                                eventString = eventRecord.TimeCreated.ToString() & "," & "ディフェンダー稼働ログ,ウイルス・マルウェア対策,疑わしいアプリの対策失敗"
                            Case 1020, 1150
                                eventString = eventRecord.TimeCreated.ToString() & "," & "ディフェンダー稼働ログ,ウイルス・マルウェア対策,正常に稼働しています"
                            Case 2000
                                eventString = eventRecord.TimeCreated.ToString() & "," & "ディフェンダー稼働ログ,ウイルス・マルウェア対策,定義が正常に更新されました"
                            Case 2002
                                eventString = eventRecord.TimeCreated.ToString() & "," & "ディフェンダー稼働ログ,ウイルス・マルウェア対策,ウイルス・マルウェアエンジンが正常に更新されました"
                            Case 2003
                                eventString = eventRecord.TimeCreated.ToString() & "," & "ディフェンダー稼働ログ,ウイルス・マルウェア対策,ウイルス・マルウェアエンジンの更新に失敗しました"
                            Case 2003
                                eventString = eventRecord.TimeCreated.ToString() & "," & "ディフェンダー稼働ログ,ウイルス・マルウェア対策,リアルタイム保護でエラーが発生しました"
                            Case 5000
                                eventString = eventRecord.TimeCreated.ToString() & "," & "ディフェンダー稼働ログ,ウイルス・マルウェア対策,リアルタイム保護が有効です"
                            Case 5001
                                eventString = eventRecord.TimeCreated.ToString() & "," & "ディフェンダー稼働ログ,ウイルス・マルウェア対策,リアルタイム保護が無効です"
                            Case 5009
                                eventString = eventRecord.TimeCreated.ToString() & "," & "ディフェンダー稼働ログ,ウイルス・マルウェア対策,望ましくないアプリの検出が有効です"
                            Case 5010
                                eventString = eventRecord.TimeCreated.ToString() & "," & "ディフェンダー稼働ログ,ウイルス・マルウェア対策,望ましくないアプリの検出が無効です"
                            Case 5011
                                eventString = eventRecord.TimeCreated.ToString() & "," & "ディフェンダー稼働ログ,ウイルス・マルウェア対策,ウイルススキャンが有効です"
                            Case 5010
                                eventString = eventRecord.TimeCreated.ToString() & "," & "ディフェンダー稼働ログ,ウイルス・マルウェア対策,ウイルススキャンが無効です"
                        End Select

                        If eventString <> "" Then
                            If eventString <> eventString2 Then
                                AppendToLog(eventString)
                                eventString2 = eventString
                            End If
                        End If

                    End If

                    eventRecord = eventLogReader.ReadEvent()
                End While
            End Using

            Dim PostgreCmd = New NpgsqlCommand
            Dim PostgreReader As Object

            Try
                '========================================
                'NpgSQL-PostgreSqlデータベース接続
                Dim cPostgreSql As NpgsqlConnection = New NpgsqlConnection(NpgSqlUIDPass)
                cPostgreSql.Open()

                'ステータスを確認して最新バージョンを確認
                sSql = "select status from ms_status where status_no='00003' and status='" & Var & "'"
                PostgreCmd = New NpgsqlCommand(sSql, cPostgreSql)
                PostgreReader = PostgreCmd.ExecuteReader

                If PostgreReader.hasrows = False Then
                    'ステータスが存在しなかったらリリースバッチ起動
                    System.Diagnostics.Process.Start("C:\WORK\bat\stcreate_real2.bat")
                    End
                End If

                PostgreReader.close()

                sSql = "delete from ms_pc where pc_name='" & sComputer_Name & "';"
                sSql &= " insert into ms_pc values('" & sComputer_Name & "','" & sIp & "','" & Date.Now & "','" & os & "');"
                PostgreCmd = New NpgsqlCommand(sSql, cPostgreSql)
                PostgreCmd.ExecuteNonQuery()

                Select Case sComputer_Name
                    Case "114LC", "013LC", "201LC", "001LC", "211LC", "212LC", "STFILESERVER", "STASV01", "STESV01", "STESV02", "SOFTETHERSV"
                        GoTo 終了飛ばし
                    Case Else
                        GoTo 終了飛ばし
                End Select

                '=====================================================================
                'ステータスを確認して最終時間を確認
                sSql = "select status from ms_status where status_no='00007'"
                PostgreCmd = New NpgsqlCommand(sSql, cPostgreSql)
                PostgreReader = PostgreCmd.ExecuteReader
                PostgreReader.read()

                'ステータスが1の場合は定期シャットダウン運用中
                If Trim(PostgreReader(0)) = "1" Then
                    PostgreReader.close()
                    'ステータスを確認して最終時間を確認
                    sSql = "select status from ms_status where status_no='00006'"
                    PostgreCmd = New NpgsqlCommand(sSql, cPostgreSql)
                    PostgreReader = PostgreCmd.ExecuteReader
                    PostgreReader.read()
                    LastTime = CInt(PostgreReader(0))
                    PostgreReader.close()

                    Me.Text = "最終" & LastTime & "迄使用可"

                    sSql = "select current_timestamp"
                    PostgreCmd = New NpgsqlCommand(sSql, cPostgreSql)
                    PostgreReader = PostgreCmd.ExecuteReader
                    PostgreReader.read()

                    If CDate(PostgreReader(0)).Hour >= LastTime Then
                        '業務時間超の場合
                        '業務時間外申請のチェック
                        sSql = "select * from d_pckyoka where ymd='" & CDate(PostgreReader(0)).ToString("yyyy/MM/dd") & "' and shinsei_pc='" & sComputer_Name & "' and kyoka='1'"
                        PostgreReader.close()

                        PostgreCmd = New NpgsqlCommand(sSql, cPostgreSql)
                        PostgreReader = PostgreCmd.ExecuteReader

                        If PostgreReader.hasrows = False Then
                            PostgreReader.close()
                            'ない場合
                            'sSql = "insert into ms_log values('" & Date.Now & "','" & sComputer_Name & "','自動実行','時間外シャットダウン','R" & Var & "','');"
                            'PostgreCmd = New NpgsqlCommand(sSql, cPostgreSql)
                            'PostgreCmd.ExecuteNonQuery()
                            'System.Diagnostics.Process.Start("C:\WORK\bat\ProcShutdown.bat")
                            'End
                        Else
                            PostgreReader.close()
                        End If
                    Else
                        PostgreReader.close()
                    End If

                Else
                    PostgreReader.close()
                End If

終了飛ばし:

                '=============================
                'ログテキストをDBにインサート

                Dim lines As String()
                Using sr As New StreamReader(sLogPath & Date.Today.ToString("yyyyMMdd") & ".log")
                    lines = sr.ReadToEnd().Split(Environment.NewLine)
                End Using

                Dim i As Integer
                ' SQL文の生成
                For i = 0 To lines.Length - 1 ' ヘッダ行を除く
                    Dim values As String() = lines(i).Split(","c)

                    If values(2).Trim() = "ファイル更新" Then

                        sSql = "select * from"
                        sSql = sSql & vbLf & " ms_nlog"
                        sSql = sSql & vbLf & "where log_ymd       = '" & values(0).Trim() & "'"
                        sSql = sSql & vbLf & "and   log_kbn       = '" & values(1).Trim() & "'"
                        sSql = sSql & vbLf & "and   log_operation = 'ファイル作成'"
                        sSql = sSql & vbLf & "and   log_substance = '" & values(3).Trim() & "'"
                        sSql = sSql & vbLf & "and   log_tm        = '" & sComputer_Name & "'"
                        sSql = sSql & vbLf & "and   log_user      = '" & sUserName & "'"
                        sSql = sSql & vbLf & "and   ipaddress     = '" & sIpAddress & "'"
                        sSql = sSql & vbLf & "and   prg_ver       = '" & Var & "'"

                        PostgreCmd = New NpgsqlCommand(sSql, cPostgreSql)
                        PostgreReader = PostgreCmd.ExecuteReader
                        PostgreReader.read()

                        If Not PostgreReader.hasrows Then

                            PostgreReader.close

                            sSql = "insert into ms_nlog"
                            sSql = sSql & vbLf & "("
                            sSql = sSql & vbLf & "  log_ymd,"
                            sSql = sSql & vbLf & "  log_kbn,"
                            sSql = sSql & vbLf & "  log_operation,"
                            sSql = sSql & vbLf & "  log_substance,"
                            sSql = sSql & vbLf & "  log_tm,"
                            sSql = sSql & vbLf & "  log_user,"
                            sSql = sSql & vbLf & "  ipaddress,"
                            sSql = sSql & vbLf & "  prg_ver"

                            sSql = sSql & vbLf & " )"
                            sSql = sSql & vbLf & " values"
                            sSql = sSql & vbLf & "("
                            sSql = sSql & vbLf & "'" & values(0).Trim() & "',"
                            sSql = sSql & vbLf & "'" & values(1).Trim() & "',"
                            sSql = sSql & vbLf & "'" & values(2).Trim() & "',"
                            sSql = sSql & vbLf & "'" & values(3).Trim() & "',"
                            sSql = sSql & vbLf & "'" & sComputer_Name & "',"
                            sSql = sSql & vbLf & "'" & sUserName & "',"
                            sSql = sSql & vbLf & "'" & sIpAddress & "',"
                            sSql = sSql & vbLf & "'" & Var & "'"
                            sSql = sSql & vbLf & " )"
                            sSql = sSql & vbLf & "On CONFLICT ON CONSTRAINT ms_nlog_pkey"
                            sSql = sSql & vbLf & "Do Nothing"

                            Try
                                PostgreCmd = New NpgsqlCommand(sSql, cPostgreSql)
                                PostgreCmd.ExecuteNonQuery()
                            Catch ex1 As Exception

                            End Try
                        Else
                            PostgreReader.close
                        End If
                    Else

                        sSql = "insert into ms_nlog"
                        sSql = sSql & vbLf & "("
                        sSql = sSql & vbLf & "  log_ymd,"
                        sSql = sSql & vbLf & "  log_kbn,"
                        sSql = sSql & vbLf & "  log_operation,"
                        sSql = sSql & vbLf & "  log_substance,"
                        sSql = sSql & vbLf & "  log_tm,"
                        sSql = sSql & vbLf & "  log_user,"
                        sSql = sSql & vbLf & "  ipaddress,"
                        sSql = sSql & vbLf & "  prg_ver"

                        sSql = sSql & vbLf & " )"
                        sSql = sSql & vbLf & " values"
                        sSql = sSql & vbLf & "("
                        sSql = sSql & vbLf & "'" & values(0).Trim() & "',"
                        sSql = sSql & vbLf & "'" & values(1).Trim() & "',"
                        sSql = sSql & vbLf & "'" & values(2).Trim() & "',"
                        sSql = sSql & vbLf & "'" & values(3).Trim() & "',"
                        sSql = sSql & vbLf & "'" & sComputer_Name & "',"
                        sSql = sSql & vbLf & "'" & sUserName & "',"
                        sSql = sSql & vbLf & "'" & sIpAddress & "',"
                        sSql = sSql & vbLf & "'" & Var & "'"
                        sSql = sSql & vbLf & " )"
                        sSql = sSql & vbLf & "On CONFLICT ON CONSTRAINT ms_nlog_pkey"
                        sSql = sSql & vbLf & "Do Nothing"

                        Try
                            PostgreCmd = New NpgsqlCommand(sSql, cPostgreSql)
                            PostgreCmd.ExecuteNonQuery()
                        Catch ex1 As Exception

                        End Try

                    End If


                Next

            Catch ex As Exception
                'オフラインの場合はPCの時間を見て対応
                Select Case sComputer_Name
                    Case "114LC", "013LC", "201LC", "001LC", "211LC", "212LC", "STFILESERVER", "STASV01", "STESV01", "STESV02", "SOFTETHERSV"
                        GoTo NextStep
                    Case Else
                        GoTo NextStep
                        If Now.Hour >= LastTime Then
                            'System.Diagnostics.Process.Start("C:\WORK\bat\ProcShutdown.bat")
                            End
                        End If
                End Select

            End Try

NextStep:

            Label1.Text = inTime
            Timer1.Start()

        Else

            Label1.Text = CInt(Label1.Text) - 1

        End If

    End Sub

    Private Sub Timer2_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick

        ' 現在のアクティブウィンドウを取得
        Dim CurrentWindow As IntPtr = GetForegroundWindow()
        Dim processId As Integer
        GetWindowThreadProcessId(CurrentWindow, processId)
        Dim processFilePath As String = GetProcessFilePath(processId)
        Dim ProcessName As String = Path.GetFileName(processFilePath)
        Dim process As Process = Process.GetProcessById(processId)

        ' アクティブウィンドウが変更された場合、ログに追記
        If CurrentWindow <> previousWindow Or process.MainWindowTitle <> previousWindowText Then

            Dim sb As New StringBuilder(256)
            GetWindowText(CurrentWindow, sb, sb.Capacity)
            Dim activeWindow As String = sb.ToString().Trim()

            If Not String.IsNullOrEmpty(activeWindow) Then
                'Dim logMessage As String = $"{DateTime.Now},ウインドウ操作ログ," & ProcessName & "," & $"{activeWindow}"
                Dim logMessage As String = $"{DateTime.Now},ウインドウ操作ログ," & ProcessName & "," & process.MainWindowTitle
                AppendToLog(logMessage)
            End If

            ' アクティブウィンドウの更新
            previousWindow = CurrentWindow
            previousWindowText = process.MainWindowTitle

        End If

    End Sub

    Private Sub AppendToLog(logMessage As String)

        Dim inCount As Integer = 1

再実行:

        ' ログファイルにメッセージを追記
        Try

            Using writer As StreamWriter = File.AppendText(sLogPath & Date.Today.ToString("yyyyMMdd") & ".log")
                writer.WriteLine(logMessage)
            End Using

        Catch ex As Exception

            Wait(100)

            inCount = inCount + 1
            If inCount = 10 Then
                GoTo EndStep
            End If
            GoTo 再実行

        End Try

EndStep:

    End Sub
    Public Function GetProcessFilePath(ByVal processId As Integer) As String
        Dim processHandle As IntPtr = OpenProcess(&H400 Or &H10, False, processId)
        Dim sb As New StringBuilder(1024)
        GetModuleFileNameEx(processHandle, IntPtr.Zero, sb, sb.Capacity)
        Return sb.ToString()
    End Function

    Public Sub LogWebAccess(url As String)
        Dim logMessage As String = String.Format("[{0}] Web Access: {1}", DateTime.Now.ToString(), url)
    End Sub

    Public Function GetEdgeBrowserHistory() As List(Of String)
        Dim historyFilePath As String = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Microsoft", "Edge", "User Data", "個人", "History")
        Dim historyItems As New List(Of String)()

        ' Historyファイルが存在するかチェックします
        If File.Exists(historyFilePath) Then
            ' Historyファイルを開きます
            Using stream As FileStream = File.Open(historyFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)
                ' ファイルストリームを使用してバイナリリーダーを作成します
                Using reader As New BinaryReader(stream)
                    ' ヘッダー情報を読み飛ばします
                    reader.ReadBytes(16)

                    ' レコード数を読み取ります
                    Dim recordCountBytes As Byte() = reader.ReadBytes(4)
                    Dim recordCount As Integer = BitConverter.ToInt32(recordCountBytes, 0)

                    ' 各レコードを読み取ります
                    For i As Integer = 0 To recordCount - 1
                        ' URLの長さを読み取ります
                        Try

                            Dim urlLengthBytes As Byte() = reader.ReadBytes(4)
                            Dim urlLength As Integer = BitConverter.ToInt32(urlLengthBytes, 0)

                            ' URLを読み取ります
                            Dim urlBytes As Byte() = reader.ReadBytes(urlLength)
                            Dim url As String = System.Text.Encoding.UTF8.GetString(urlBytes)

                            ' 閲覧履歴に追加します
                            historyItems.Add(url)

                        Catch ex As Exception

                        End Try
                    Next
                End Using
            End Using
        End If

        Return historyItems
    End Function

End Class

続いてModuleを追加して、下記コードを作成します。

Imports System.IO
Imports System.Environment
Imports System.Management
Imports System.Threading
Imports System.Runtime.InteropServices
Imports System.Text
Imports System.Security.Principal
Imports System.Net
Module Module1

    Public sCreateAftopen_Kb As Integer = 0
    Public watcher As FileSystemWatcher
    Public sLogPath As String = "c:\Pclog\"
    Public logonUser = Environment.UserName

    <DllImport("user32.dll", CharSet:=CharSet.Auto, SetLastError:=True)>
    Public Function GetForegroundWindow() As IntPtr
    End Function

    <DllImport("user32.dll", CharSet:=CharSet.Auto, SetLastError:=True)>
    Public Function GetWindowText(ByVal hWnd As IntPtr, ByVal lpString As StringBuilder, ByVal nMaxCount As Integer) As Integer
    End Function

    <DllImport("user32.dll", CharSet:=CharSet.Auto, SetLastError:=True)>
    Public Function GetWindowThreadProcessId(ByVal hWnd As IntPtr, ByRef lpdwProcessId As Integer) As Integer
    End Function

    <DllImport("kernel32.dll", CharSet:=CharSet.Auto, SetLastError:=True)>
    Public Function OpenProcess(ByVal dwDesiredAccess As Integer, ByVal bInheritHandle As Boolean, ByVal dwProcessId As Integer) As IntPtr
    End Function

    <DllImport("psapi.dll", CharSet:=CharSet.Auto, SetLastError:=True)>
    Public Function GetModuleFileNameEx(ByVal hProcess As IntPtr, ByVal hModule As IntPtr, ByVal lpFilename As StringBuilder, ByVal nSize As Integer) As Integer
    End Function

    Function GetActiveWindowTitle() As String
        Dim activeWindowHandle As IntPtr = GetForegroundWindow()

        Dim titleBuilder As New StringBuilder(256)
        Dim titleLength As Integer = GetWindowText(activeWindowHandle, titleBuilder, titleBuilder.Capacity)

        If titleLength > 0 Then
            Return titleBuilder.ToString()
        Else
            Return String.Empty
        End If
    End Function

    Sub FileLogMain()

        ' FileSystemWatcherのインスタンスを作成
        Dim userProfileDirectory As String = GetFolderPath(SpecialFolder.UserProfile)
        Dim targetDirectories As String() = {userProfileDirectory}
        'Dim targetDirectories As String() = {userProfileDirectory & "\desktop\", userProfileDirectory & "\Documents\"}
        Dim watchers As New List(Of FileSystemWatcher)()

        For Each directory As String In targetDirectories

            ' FileSystemWatcherのインスタンスを作成
            watcher = New FileSystemWatcher()

            ' サブディレクトリも監視するように設定
            watcher.IncludeSubdirectories = True

            ' 監視するディレクトリを指定
            watcher.Path = directory

            ' 監視するイベントを指定
            watcher.NotifyFilter = NotifyFilters.FileName Or
                                   NotifyFilters.LastAccess Or
                                   NotifyFilters.LastWrite

            'NotifyFilters.DirectoryName Or


            'watcher.NotifyFilter = NotifyFilters.LastAccess

            ' イベントハンドラを設定
            AddHandler watcher.Created, AddressOf OnFileAccess
            AddHandler watcher.Deleted, AddressOf OnFileAccess
            AddHandler watcher.Changed, AddressOf OnFileAccess
            AddHandler watcher.Renamed, AddressOf OnFileRenamed

            ' ファイルの変更監視を開始
            watcher.EnableRaisingEvents = True

            ' FileSystemWatcherをリストに追加
            watchers.Add(watcher)

        Next

    End Sub

    Private Sub OnFileAccess(sender As Object, e As FileSystemEventArgs)

        ' ファイルアクセスのログを書き込む
        Dim logMessage As String

        Select Case e.ChangeType.ToString()
            Case "Opened"
                logMessage = $"ファイル閲覧,{e.FullPath}"
                sCreateAftopen_Kb = 0
            Case "Created"
                logMessage = $"ファイル作成,{e.FullPath}"
                sCreateAftopen_Kb = 1
            Case "Changed"
                logMessage = $"ファイル更新,{e.FullPath}"
                sCreateAftopen_Kb = 0
            Case "Deleted"
                logMessage = $"ファイル削除,{e.FullPath}"
                sCreateAftopen_Kb = 0
            Case Else
                logMessage = $"その他ファイル操作,{e.FullPath}"
                sCreateAftopen_Kb = 0
        End Select


        If 文字列無視(logMessage) = True Then

            Try

                If File.GetAccessControl(e.FullPath).GetOwner(GetType(SecurityIdentifier)).ToString() = logonUser Then

                End If

                Select Case e.Name.ToUpper
                    Case "DOWNLOADS", "PICTURES", "DESKTOP", "DROPBOX", "DOCUMENTS", "SOURCE", "ONEDRIVE", "APPDATA"
                    Case Else
                        If e.ChangeType.ToString.ToUpper = "CREATED" Then
                            sCreateAftopen_Kb = 1
                        Else
                            sCreateAftopen_Kb = 0
                        End If
                        If e.ChangeType.ToString.ToUpper = "Opened" Then
                            If sCreateAftopen_Kb <> 1 Then
                                WriteLog(logMessage)
                                sCreateAftopen_Kb = 0
                            End If
                        Else
                            WriteLog(logMessage)
                        End If
                End Select

            Catch ex As Exception

            End Try

        End If



    End Sub
    Private Sub OnFileChanged(sender As Object, e As RenamedEventArgs)

        ' ファイル名変更のログを書き込む
        Dim logMessage As String = $"ファイル閲覧,{e.FullPath}"


        If 文字列無視(logMessage) = True Then

            Try

                'If File.GetAccessControl(e.FullPath).GetOwner(GetType(SecurityIdentifier)).ToString() = logonUser Then

                'End If

                Select Case e.Name.ToUpper
                    Case "DOWNLOADS", "PICTURES", "DESKTOP", "DROPBOX", "DOCUMENTS", "SOURCE", "ONEDRIVE", "APPDATA"
                    Case Else
                        If sCreateAftopen_Kb <> 1 Then
                            WriteLog(logMessage)
                        Else
                            sCreateAftopen_Kb = 0
                        End If
                End Select

            Catch ex As Exception

            End Try

        End If



    End Sub

    Private Sub OnFileRenamed(sender As Object, e As RenamedEventArgs)

        ' ファイル名変更のログを書き込む
        Dim logMessage As String = $"ファイル名変更,{e.OldFullPath} -> {e.FullPath}"


        If e.Name = Nothing Then
            If 文字列無視(logMessage) = True Then
                Try
                    'If File.GetAccessControl(e.FullPath).GetOwner(GetType(SecurityIdentifier)).ToString() = logonUser Then
                    'End If
                    WriteLog(logMessage)

                Catch ex As Exception

                End Try
            End If
        Else
            If 文字列無視(logMessage) = True Then
                Try
                    'If File.GetAccessControl(e.FullPath).GetOwner(GetType(SecurityIdentifier)).ToString() = logonUser Then
                    'End If
                    Select Case e.Name.ToUpper
                        Case "DOWNLOADS", "PICTURES", "DESKTOP", "DROPBOX", "DOCUMENTS", "SOURCE", "ONEDRIVE", "APPDATA"
                        Case Else
                            WriteLog(logMessage)
                    End Select

                Catch ex As Exception

                End Try
            End If
        End If


    End Sub

    Private Sub WriteLog(message As String)

        ' ログファイルにメッセージを追記
        Dim inCount As Integer = 1

再実行:

        Try

            Using writer As New StreamWriter(sLogPath & Date.Today.ToString("yyyyMMdd") & ".log", True)

                If 文字列無視($"{message}") = True Then
                    writer.WriteLine($"{DateTime.Now.ToString()}" & ",ファイル操作ログ," & $"{message}")
                End If

            End Using

        Catch ex As Exception

            Wait(100)

            inCount = inCount + 1
            If inCount = 10 Then
                GoTo EndStep
            End If
            GoTo 再実行

        End Try

EndStep:

    End Sub
    Private Function 文字列無視(sString As String) As Boolean

        文字列無視 = False

        If sString.ToUpper.Contains("\APPDATA\") = True Then
        ElseIf sString.ToUpper.Contains(".TEMP") = True Then
        ElseIf sString.ToUpper.Contains(".LNK") = True Then
        ElseIf sString.ToUpper.Contains(".INI") = True Then
        ElseIf sString.ToUpper.Contains(".DLL") = True Then
        ElseIf sString.ToUpper.Contains(".DROPBOX") = True Then
        ElseIf sString.ToUpper.Contains(".PST") = True Then
        ElseIf sString.ToUpper.Contains(".TMP") = True Then
        ElseIf sString.ToUpper.Contains(".NUGET") = True Then
        ElseIf sString.ToUpper.Contains("~$") = True Then
        ElseIf sString.ToUpper.Contains(".LOG") = True Then
        ElseIf sString.ToUpper.Contains(".") = False Then
        Else
            文字列無視 = True
        End If


    End Function

    Public Sub Wait(milliseconds As Integer)
        Thread.Sleep(milliseconds)
    End Sub

    Public Class USBLogger

        Public sLogPath As String = "c:\Pclog\"
        Public WithEvents watcher As ManagementEventWatcher

        Public Sub StartLogging()
            Dim query As New WqlEventQuery("SELECT * FROM Win32_VolumeChangeEvent WHERE EventType = 2 or EventType = 3")
            watcher = New ManagementEventWatcher(query)
            watcher.Start()
        End Sub

        Public Sub StopLogging()
            If watcher IsNot Nothing Then
                watcher.Stop()
                watcher.Dispose()
            End If
        End Sub

        Public Sub HandleEvent(ByVal sender As Object, ByVal e As EventArrivedEventArgs) Handles watcher.EventArrived
            Dim eventType As UInteger = CType(e.NewEvent("EventType"), UInteger)
            Dim driveName As String = CType(e.NewEvent("DriveName"), String)

            Select Case eventType
                Case 2
                    ' USBデバイスが接続された
                    Using writer As New StreamWriter(sLogPath & Date.Today.ToString("yyyyMMdd") & ".log", True)
                        writer.WriteLine($"{DateTime.Now.ToString()}" & ",外部ディバイス接続ログ," & "ドライブ接続,” & driveName)
                    End Using
                Case 3
                    ' USBデバイスが切断された
                    Using writer As New StreamWriter(sLogPath & Date.Today.ToString("yyyyMMdd") & ".log", True)
                        writer.WriteLine($"{DateTime.Now.ToString()}" & ",外部ディバイス接続ログ," & "ドライブ切断,” & driveName)
                    End Using
            End Select
        End Sub

        Public Function GetProcessFilePath(ByVal processId As Integer) As String
            Dim processHandle As IntPtr = OpenProcess(&H400 Or &H10, False, processId)
            Dim sb As New StringBuilder(1024)
            GetModuleFileNameEx(processHandle, IntPtr.Zero, sb, sb.Capacity)
            Return sb.ToString()
        End Function

    End Class

    Public Class MainClass
        Sub UsbMain()
            Dim logger As New USBLogger()
            logger.StartLogging()

            ' ログを取得する間、アプリケーションが実行され続けます
            Console.WriteLine("USBメモリの接続/切断のログを取得中...")
            Console.ReadLine()

            logger.StopLogging()
        End Sub

    End Class

End Module

これでコンパイルして実行すれば、ログインしているユーザー配下のファイル操作・アクティブウインドウのログとプロセス・USBデバイスの接続・MSDefenderの動作ログが c:\Pclog\ 配下に日別CSVファイルを作成され、PostgreSQLのテーブルに1分毎に書き込むようになります(それ以外も書いてありますが・・・汗)。
つたないネット上コードの切り貼りですが、ちゃんと動きましたので良しとしています。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です