はじめに (対象読者・この記事でわかること)

この記事は、Excel VBAをある程度理解している方、Windowsシステム管理や自動化スクリプト作成に興味がある方を対象としています。特に、複数のユーザーセッションを管理する必要がある環境や、特定のセッションに依存する処理を実装したい場合に役立ちます。

この記事を読むことで、VBAを使用してWindows PCのセッションIDを取得する方法を理解し、実際のコードを自分の環境で実行できるようになります。また、取得したセッションIDを活用した具体的な応用例についても学ぶことができます。

前提知識

この記事を読み進める上で、以下の知識があるとスムーズです。

  • VBAの基本的な知識(変数、関数、オブジェクトなど)
  • Windows APIの基本的な概念(あれば尚良い)
  • ExcelのVBAエディタの操作方法

セッションIDとは何か - なぜ取得が必要なのか

セッションIDとは、Windowsオペレーティングシステム上で実行されているユーザーセッションを識別するための一意の識別子です。Windowsは複数のユーザーが同時にログオンできる環境(リモートデスクトップやターミナルサービスなど)をサポートしており、各セッションには固有のIDが割り当てられます。

セッションIDを取得する必要性は主に以下のケースで発生します:

  1. リモートデスクトップ環境での特定セッション操作: 特定のユーザーセッションにのみ影響を与える処理を実行したい場合
  2. システム監視ログの詳細化: どのセッションで特定のイベントが発生したかを記録する必要がある場合
  3. セッション依存リソースの管理: 特定のセッションに紐づくリソースを適切に管理したい場合
  4. セッション状態の監視: ユーザーのログオン/ログオフイベントを検知して自動処理を実行したい場合

VBAでセッションIDを取得することで、これらの要件を満たすカスタムソリューションを構築できます。

VBAでセッションIDを取得する具体的な方法

ここでは、Windows APIを利用してVBAからPCのセッションIDを取得する方法を詳しく解説します。主にWTSApi32.dllを使用するアプローチと、Kernel32.dllを使用するアプローチの2つを紹介します。

方法1: WTSApi32.dllを使用する方法

WTSApi32.dllはWindows Terminal Services APIの一部で、セッション関連の情報を取得するための関数が含まれています。以下に実装手順を示します。

ステップ1: 必要なAPI宣言を追加

まず、VBAエディタの標準モジュールに以下のAPI宣言を追加します。

Vba
' WTSApi32.dllの関数を宣言 Declare Function WTSGetActiveSession Lib "wtsapi32.dll" () As Long Declare Function WTSQuerySessionInformation Lib "wtsapi32.dll" _ (ByVal hServer As Long, ByVal SessionId As Long, _ ByVal WTSInfoClass As Long, ByRef ppBuffer As Long, _ ByVal pBytesReturned As Long) As Long Declare Function WTSFreeMemory Lib "wtsapi32.dll" (ByPtr pMemory As Long) As Long ' 定数の定義 Const WTS_CURRENT_SESSION As Long = -1 Const WTS_SESSIONINFO As Long = 13

ステップ2: セッションIDを取得する関数を作成

次に、セッションIDを取得するための関数を実装します。

Vba
Function GetSessionID() As Long ' 現在のセッションIDを取得 GetSessionID = WTSGetActiveSession() End Function Function GetSessionInfo() As String Dim hServer As Long Dim SessionId As Long Dim pBuffer As Long BytesReturned As Long Dim sessionInfo As String Dim result As Long ' 現在のセッションIDを取得 SessionId = GetSessionID() ' セッション情報を取得 result = WTSQuerySessionInformation(hServer, SessionId, WTS_SESSIONINFO, pBuffer, BytesReturned) If result <> 0 Then ' 取得したセッション情報を文字列に変換 sessionInfo = Space$(BytesReturned) CopyMemory ByVal sessionInfo, ByVal pBuffer, BytesReturned ' メモリを解放 Call WTSFreeMemory(pBuffer) GetSessionInfo = sessionInfo Else GetSessionInfo = "取得に失敗しました" End If End Function

ステップ3: 関数を呼び出して使用

以下のように関数を呼び出してセッションIDを取得できます。

Vba
Sub TestGetSessionID() Dim sessionId As Long Dim sessionInfo As String ' セッションIDを取得 sessionId = GetSessionID() Debug.Print "現在のセッションID: " & sessionId ' セッション情報を取得 sessionInfo = GetSessionInfo() Debug.Print "セッション情報: " & sessionInfo End Sub

方法2: Kernel32.dllを使用する方法

WTSApi32.dllが利用できない環境や、より低レベルのセッション情報が必要な場合は、Kernel32.dllを使用する方法も有効です。

ステップ1: 必要なAPI宣言を追加

Vba
' Kernel32.dllの関数を宣言 Declare Function WTSGetActiveSession Lib "kernel32.dll" () As Long Declare Function WTSQuerySessionInformationA Lib "kernel32.dll" _ (ByVal hServer As Long, ByVal SessionId As Long, _ ByVal WTSInfoClass As Long, ByRef ppBuffer As Long, _ ByVal pBytesReturned As Long) As Long Declare Function WTSFreeMemory Lib "kernel32.dll" (ByPtr pMemory As Long) As Long ' 定数の定義 Const WTS_CURRENT_SESSION As Long = -1 Const WTS_SESSIONINFO As Long = 13

ステップ2: セッションIDを取得する関数を作成

Vba
Function GetKernelSessionID() As Long ' 現在のセッションIDを取得 GetKernelSessionID = WTSGetActiveSession() End Function

ハマった点やエラー解決

問題1: Declareステートメントで「コンパイルエラー:プロシージャの定義が有効ではありません」というエラーが発生する

原因: 64ビット版のOfficeで32ビットDLLの関数を宣言しようとしている場合に発生します。

解決策: 以下の修正を行います。

Vba
#If VBA7 Then ' 64ビット版Office用 Declare PtrSafe Function WTSGetActiveSession Lib "wtsapi32.dll" () As Long Declare PtrSafe Function WTSQuerySessionInformation Lib "wtsapi32.dll" _ (ByVal hServer As LongPtr, ByVal SessionId As Long, _ ByVal WTSInfoClass As Long, ByRef ppBuffer As LongPtr, _ ByVal pBytesReturned As Long) As Long Declare PtrSafe Function WTSFreeMemory Lib "wtsapi32.dll" (ByVal pMemory As LongPtr) As Long #Else ' 32ビット版Office用 Declare Function WTSGetActiveSession Lib "wtsapi32.dll" () As Long Declare Function WTSQuerySessionInformation Lib "wtsapi32.dll" _ (ByVal hServer As Long, ByVal SessionId As Long, _ ByVal WTSInfoClass As Long, ByRef ppBuffer As Long, _ ByVal pBytesReturned As Long) As Long Declare Function WTSFreeMemory Lib "wtsapi32.dll" (ByVal pMemory As Long) As Long #End If

問題2: WTSQuerySessionInformation関数が0を返す(失敗)

原因: サーバー名(hServer)の指定が間違っているか、セッションIDが存在しない場合に発生します。

解決策: サーバー名を指定せずに0(ローカルコンピュータ)を渡すように修正します。

Vba
' hServerに0を指定してローカルコンピュータを対象とする result = WTSQuerySessionInformation(0, SessionId, WTS_SESSIONINFO, pBuffer, BytesReturned)

問題3: 取得したセッション情報が文字化けする

原因: バッファの処理方法が適切でない場合に発生します。

解決策: バッファから文字列を正しく抽出するための処理を追加します。

Vba
Function GetSessionInfoAsString() As String Dim hServer As Long Dim SessionId As Long Dim pBuffer As Long BytesReturned As Long Dim sessionInfo As String Dim result As Long ' 現在のセッションIDを取得 SessionId = GetSessionID() ' セッション情報を取得 result = WTSQuerySessionInformation(0, SessionId, WTS_SESSIONINFO, pBuffer, BytesReturned) If result <> 0 Then ' バッファから文字列を抽出 sessionInfo = String$(BytesReturned, 0) CopyMemory ByVal sessionInfo, ByVal pBuffer, BytesReturned ' メモリを解放 Call WTSFreeMemory(pBuffer) ' 不要なnull文字を削除 If InStr(sessionInfo, Chr$(0)) > 0 Then sessionInfo = Left$(sessionInfo, InStr(sessionInfo, Chr$(0)) - 1) End If GetSessionInfoAsString = sessionInfo Else GetSessionInfoAsString = "取得に失敗しました" End If End Function

セッションIDの応用例

取得したセッションIDを活用した具体的な応用例をいくつか紹介します。

応用例1: 現在のセッションがリモートセッションかどうかを判定

Vba
Function IsRemoteSession() As Boolean Dim sessionId As Long Dim sessionInfo As String sessionId = GetSessionID() ' セッションIDが0以外の場合はリモートセッションと判定 IsRemoteSession = (sessionId <> 0) End Function Sub TestIsRemoteSession() If IsRemoteSession() Then MsgBox "現在はリモートセッションです" Else MsgBox "現在はローカルセッションです" End If End Sub

応用例2: セッションごとのユーザー名を取得

Vba
Function GetSessionUserName() As String Dim hServer As Long Dim SessionId As Long Dim pBuffer As Long BytesReturned As Long Dim userName As String Dim result As Long ' 現在のセッションIDを取得 SessionId = GetSessionID() ' セッションのユーザー名を取得 result = WTSQuerySessionInformation(0, SessionId, 5, pBuffer, BytesReturned) ' 5はWTSUserName If result <> 0 Then ' バッファからユーザー名を抽出 userName = String$(BytesReturned, 0) CopyMemory ByVal userName, ByVal pBuffer, BytesReturned ' メモリを解放 Call WTSFreeMemory(pBuffer) ' 不要なnull文字を削除 If InStr(userName, Chr$(0)) > 0 Then userName = Left$(userName, InStr(userName, Chr$(0)) - 1) End If GetSessionUserName = userName Else GetSessionUserName = "取得に失敗しました" End If End Function Sub TestGetSessionUserName() Dim userName As String userName = GetSessionUserName() MsgBox "現在のセッションのユーザー名: " & userName End Sub

応用例3: セッション状態の監視と自動処理

Vba
' タイマーイベントを使用してセッション状態を監視 Private Sub Workbook_Open() Application.OnTime Now + TimeValue("00:00:10"), "CheckSessionStatus" End Sub Sub CheckSessionStatus() Dim sessionId As Long Dim prevSessionId As Long Dim sessionInfo As String ' 前回のセッションIDを保存(グローバル変数を使用) Static storedSessionId As Long sessionId = GetSessionID() ' セッションIDが変更された場合 If storedSessionId <> sessionId Then sessionInfo = GetSessionInfo() Debug.Print "セッションが変更されました: " & sessionId & " - " & sessionInfo ' ここにセッション変更時の処理を記述 ' 例: メール通知、ログファイルへの記録など storedSessionId = sessionId End If ' 10秒後に再度チェック Application.OnTime Now + TimeValue("00:00:10"), "CheckSessionStatus" End Sub

まとめ

本記事では、VBAを使用してPCのセッションIDを取得する方法について詳しく解説しました。

  • 要点1: WTSApi32.dllやKernel32.dllを使用してセッションIDを取得する方法を学びました
  • 要点2: 64ビット版OfficeでのAPI宣言方法やエラー処理のポイントを理解しました
  • 要点3: セッションIDを活用した応用例として、リモートセッションの判定やユーザー名の取得方法を紹介しました

この記事を通して、Windowsシステム管理や自動化スクリプト作成において、セッション情報を正確に取得・活用する技術を習得できたことと思います。セッションIDの取得は、ユーザーごとの処理を分岐させたり、セッション状態に応じた自動化を実現したりする上で非常に有用です。

今後は、複数セッションの一括管理やセッションイベントの詳細な監視方法についても記事にする予定です。