2023/03/05

PCの固有情報の取得




アプリを操作しているユーザーやPCを特定するために、固有情報を取得する場面は多くあります。分かり易い例としては、ブラウザにURLを記入すればインターネット上のサイトが表示されますが、これは、要求する側の「PCのIPアドレス」をリクエストと一緒に送信しているためです。
Excelで作ったアプリでも似たような場面があります。例えばExcelで日報を作ってサーバーに保存するシステムの場合、日報作成者の名前をファイル名に添付しておかないと受け取った人は困ってしまいます。と言って、他人の名前で作成・保存できてしまっても困ります。
そのため「ユーザーやPCの固有情報」をVBAで取得し、ファイル名に付けたりする手法を用いる場合があります。もちろん完璧ではありませんが、ユーザーの面倒な作業を減らす事にはなっていると思います。

Excelでは、上記のIPアドレスやユーザー名だけでは無く、他にも色々な固有情報を取得できます。今回は、以下の10種類の情報の取得方法を紹介します。
固有情報
IPアドレス
MACアドレス
ユーザー名
コンピューター名
ドメイン名
 
固有情報
CPU名
Excelバージョン
O/Sバージョン
O/SプロダクトID
10HDシリアル番号
図01


1.概要

サンプルファイル」では図02のように、ボタンをクリックする事で各固有情報をメッセージボックスで表示するようにしました。手法も含めて項目が多いので、4つに分けてあります。
システム概要
図02


2.システム補助

2ー1.ワークシート(Sheet1)

ワークシート上には、情報取得し結果を表示するためのボタン(フォームコントロール)を4つ配置しています。
各ボタンには、図06の起動プロシージャ(Info1~Info4)をマクロ登録しています。
システム概要
図03


2ー2.標準モジュール(Module1)

2ー2ー1.API関数宣言など

標準モジュール先頭(宣言部)では、ユーザー名を取得(図27)する際に使用するWindows APIの「GetUserName関数」の宣言、及びO/Sのバージョンを取得(図44)する際に使用する「GetVersionEx関数」の宣言をしています。
  1. '========== ⇩(1) API関数宣言 ============
  2. #If Win64 Then
  3.  Private Declare PtrSafe Function GetUserName Lib "advapi32.dll" _
  4.   Alias "GetUserNameA" (ByVal lpBuffer As String, nSize As LongPtr) As LongPtr
  5.  Private Declare PtrSafe Function GetVersionEx Lib "kernel32" _
  6.   Alias "GetVersionExA" (lpVersionInformation As OSVERSIONINFO) As LongPtr
  7. #Else
  8.  Private Declare Function GetUserName Lib "advapi32.dll" _
  9.   Alias "GetUserNameA" (ByVal lpBuffer As String, nSize As Long) As Long
  10.  Private Declare Function GetVersionEx Lib "kernel32" _
  11.   Alias "GetVersionExA" (lpVersionInformation As OSVERSIONINFO) As Long
  12. #End If
図04


Excelが32ビット版か64ビット版かで、宣言文が異なります。01行目「#If Win64 Then」で分岐させ、64ビット版であれば02~05行目を実行し、32ビット版であれば07~10行目を実行します。
64ビット版と32ビット版の違いは、64ビット版ではFunctionの前に「PtrSafe」を付け加える事と、データ型がLong型の場合は「LongPtr」型になることです。

関数の内容を64ビット版を例に説明します。
02~03行目「Private Declare PtrSafe Function GetUserName Lib "advapi32.dll" Alias "GetUserNameA" (ByVal lpBuffer As String, nSize As LongPtr) As LongPtr」では、GetUserName関数を宣言します。得られるユーザー名は、引数lpBufferとして得られます。

04~05行目「Private Declare PtrSafe Function GetVersionEx Lib "kernel32" Alias "GetVersionExA" (lpVersionInformation As OSVERSIONINFO) As LongPtr」では、GetVersionEx関数を宣言します。得られるO/Sのバージョン情報は、図05で構造体宣言を行っている「OSVERSIONINFO」型で渡されます。

図05では、GetVersionEx関数で使用するOSVERSIONINFO構造体の宣言をしています。
構造体の説明等は「APIのGetVersionEx関数法」で行います。
  1. '========== ⇩(2) 構造体宣言 ============
  2. Private Type OSVERSIONINFO
  3.  dwOSVersionInfoSize As Long    '構造体のバイト数
  4.  dwMajorVersion As Long    'メジャー番号
  5.  dwMinorVersion As Long    'マイナー番号
  6.  dwBuildNumber As Long    'ビルド番号
  7.  dwPlatformId As Long    'プラットフォームのID
  8.  szCSDVersion As String * 128    'OSに関する付加情報
  9. End Type
図05


2ー2ー2.情報取得と表示

シート上のボタンから呼び出されるのが、図06の4つのプロシージャです。4分割したのは説明の都合上の為だけです。
  1. '========== ⇩(3) データ取得と表示1 ============
  2. Public Sub Info1()
  3.  Dim s As String    '←MsgBoxへの表示文字列
  4.  s = "IP-1= " & IPaddress1
  5.  s = s & vbNewLine & "IP-2= " & IPaddress2
  6.  s = s & vbNewLine & "MAC-1= " & MACaddress1
  7.  s = s & vbNewLine & "MAC-2= " & MACaddress2
  8.  MsgBox s
  9. End Sub
  10. '========== ⇩(4) データ取得と表示2 ============
  11. Public Sub Info2()
  12.  Dim s As String    '←MsgBoxへの表示文字列
  13.  s = "USER-1= " & USERname1
  14.  s = s & vbNewLine & "USER-2= " & USERname2
  15.  s = s & vbNewLine & "USER-3= " & USERname3
  16.  s = s & vbNewLine & "USER-4= " & USERname4
  17.  s = s & vbNewLine & "USER-5= " & USERname5
  18.  s = s & vbNewLine & "USER-6= " & USERname6
  19.  MsgBox s
  20. End Sub
  21. '========== ⇩(5) データ取得と表示3 ============
  22. Public Sub Info3()
  23.  Dim s As String    '←MsgBoxへの表示文字列
  24.  s = "PC-1= " & PCname1
  25.  s = s & vbNewLine & "PC-2= " & PCname2
  26.  s = s & vbNewLine & "PC-3= " & PCname3
  27.  s = s & vbNewLine & "Domain1= " & DOMAINname1
  28.  s = s & vbNewLine & "Domain2= " & DOMAINname2
  29.  MsgBox s
  30. End Sub
  31. '========== ⇩(6) データ取得と表示4 ============
  32. Public Sub Info4()
  33.  Dim s As String    '←MsgBoxへの表示文字列
  34.  s = "CPU name1= " & CPUname1
  35.  s = s & vbNewLine & "Excel ver= " & EXCELver1
  36.  s = s & vbNewLine & "O/S ver1= " & OSver1
  37.  s = s & vbNewLine & "O/S ver2= " & OSver2
  38.  s = s & vbNewLine & "O/S ver3= " & OSver3
  39.  s = s & vbNewLine & "O/S product= " & OSprod1
  40.  s = s & vbNewLine & "HD= " & HDserial1
  41.  MsgBox s
  42. End Sub
図06


今回、固有情報を得る部分は関数プロシージャの形にしています。図06内では、その関数プロシージャを呼び出して情報を取得し、MsgBoxで表示させています。

ボタン1をクリックした際には、44~47行目で「IPアドレス(2種)」「MACアドレス(2種)」を取得後に連結し、48行目「MsgBox s」でメッセージとして表示します。
ボタン2をクリックした際には、55~60行目で「ユーザー名(6種)」を取得後に連結し、61行目「MsgBox s」でメッセージとして表示します。

ボタン3をクリックした際には、68~72行目で「コンピューター名(3種)」「ドメイン名(2種)」を取得後に連結し、73行目「MsgBox s」でメッセージとして表示します。
ボタン4をクリックした際には、79~85行目で「CPU名(1種)」「Excelのバージョン番号(1種)」「O/Sのバージョン番号(3種)」「O/Sのプロダクト番号(1種)」「ハードディスクのシリアル番号(1種)」を取得後に連結し、86行目「MsgBox s」でメッセージとして表示します。

3.IPアドレス

3ー1.WMI法

WMI(Windows Management Instrumentation)でIPアドレスを取得するのが図07です。
  1. '========== ⇩(7) IPアドレス(WMI法) ============
  2. Private Function IPaddress1() As String
  3.  Dim ObjSet As Object    'ネットワークアダプタ情報のオブジェクト
  4.  Dim ObjEx As Object     '各ネットワークアダプタ情報
  5.  Dim strIP As Variant     'IPアドレス(IPv4、IPv6)
  6.  Set ObjSet = GetObject("winmgmts:¥¥.¥root¥cimv2"). _
  7.   ExecQuery("SELECT * FROM Win32_NetworkAdapterConfiguration Where (IPEnabled = TRUE)")
  8.  For Each ObjEx In ObjSet
  9.   For Each strIP In ObjEx.IPaddress
  10.    If UBound(Split(strIP, "."), 1) = 3 Then
  11.     IPaddress1 = strIP
  12.     Exit For
  13.    End If
  14.   Next strIP
  15.  Next ObjEx
  16.  Set ObjSet = Nothing
  17. End Function
図07


96行目「Set ObjSet = GetObject("winmgmts:¥¥.¥root¥cimv2"). _」は、Windowsを管理するWMI(Windows Management Instrumentation)オブジェクトを取得します。「winmgmts」はWMIオブジェクトのライブラリを意味します。また、オブジェクトの場所は「.(現在のWindows PC)」のレジストリの名前空間 「¥root¥cimv2」になります。
97行目「ExecQuery("SELECT * FROM Win32_NetworkAdapterConfiguration Where (IPEnabled = TRUE)")」では、そのWMIオブジェクトの「Win32_NetworkAdapterConfiguration」クラスの中から、有効(IPEnabled = TRUE)なネットワークアダプターの情報を取得し、変数ObjSetに代入します。この「IPEnabledプロパティ」は、下の図09のNo.28で、この値がTrueになっているアダプタが有効という事になります。

99行目「For Each ObjEx In ObjSet」では、ネットワークアダプタ情報を格納した変数ObjSetの中から、For Each を使って、各ネットワークアダプタ情報(変数ObjEx)を取り出します。「各ネットワークアダプタ」とは「接続されているネットワークアダプタ」ですので、たとえば有線LANと無線LANの両方が接続されている状態の時には、図08の右側のように2つのネットワークアダプタ情報が得られます。
接続している個数だけ、ネットワークアダプタが存在
図08


得られたネットワークアダプタ(SWbemObjectExオブジェクト)には、図09のように多くのプロパティがあります。
No.プロパティ内容
1ArpAlwaysSourceRouteソースルーティング有のプロトコルで送信既定=False
2ArpUseEtherSNAPSNAPエンコードに従う既定=False
3Captionオブジェクトの簡単説明[00000001] Intel(R) Wi-Fi 6 AX201 160MHz
4DatabasePathインターネットDBファイルのパス%SystemRoot%¥System32¥drivers¥etc
5DeadGWDetectEnabled配信不能ゲートウェイを検出True or False
6DefaultIPGateway既定ゲートウェイのIPアドレス(配列)例=192.168.12.1 192.168.46.1
7DefaultTOS既定サービス種0(既定)~255
8DefaultTTL既定TTL値1~255 既定=32
9Descriptionオブジェクトの説明Intel(R) Wi-Fi 6 AX201 160MHz
10DHCPEnabledDHCP自動割り当てTrue
11DHCPLeaseExpiresIPアドレスの有効期限20230303100000.000000+540
12DHCPLeaseObtainedIPアドレス取得日時2023030200000.000000+540
13DHCPServerDHCPのIPアドレス192.168.0.1
14DNSDomainDNSドメインmicrosoft.com
15DNSDomainSuffixSearchOrderDNSドメインのサフィックス(配列)
例=samples.microsoft.com/example.microsoft.com
16DNSEnabledForWINSResolutionWINS名前解決有効化False
17DNSHostName識別ホスト名例=corpdns
18DNSServerSearchOrderクエリで使用するサーバーのIPアドレス(配列)
19DomainDNSRegistrationEnabledIPアドレスをドメインに登録するFalse
20ForwardBufferMemoryIPにより割り当てられたメモリ既定=74240
21FullDNSRegistrationEnabledIPアドレスをDNSに登録するTrue
22GatewayCostMetric整数コストメトリック値(配列)1~9999の範囲
23IGMPLevelマルチキャストをサポートし、IGMPに参加する範囲0=No Multicast 1=IP Multicast
2(既定)=IP & IGMP Multicast
24Indexネットワークアダプタのインデックス番号1
25InterfaceIndexインターフェイスを識別するインデックス値18
26IPAddress関連付けられているIPアドレス(IPv4,IPv6)(配列)
27IPConnectionMetricルートの重み付け値既定=1
28IPEnabledアダプタの有効化True
29IPFilterSecurityEnabledIPポートセキュリティの有効化False
30IPPortSecurityEnabledIPポートセキュリティの有効化
(今後使用されず)
Null
31IPSecPermitIPProtocolsIP経由で実行可能なプロトコル(配列)
32IPSecPermitTCPPortsTCPのアクセスが許可されるポート(配列)
33IPSecPermitUDPPortsUDPのアクセスが許可されるポート(配列)
34IPSubnetサブネットマスク(配列)例=255.255.0.0
35IPUseZeroBroadcastIPゼロブロードキャストを使用既定=False
36IPXAddress(IPXサポートされず)Null
37IPXEnabled(IPXサポートされず)Null
38IPXFrameType(IPXサポートされず)Null
39IPXMediaType(IPXサポートされず)Null
40IPXNetworkNumber(IPXサポートされず)Null
41IPXVirtualNetNumber(IPXサポートされず)Null
42KeepAliveIntervalKeepAlive再送信を分離する間隔(ms)既定=1000
43KeepAliveTime接続維持を確認する頻度(ms)既定7,200,000(2時間)
44MACAddressMACアドレス例= 00:80:C7:8F:6C:96
45MTU最大転送単位(byte)Null
46NumForwardPacketsIPパケットヘッダー数既定値: 50
47PMTUBHDetectEnabledセグメント再送信の未確認時に送信する既定=False
48PMTUDiscoveryEnabled異なるMTUネットワークで断片化を排除既定=True
49ServiceNameアダプターのサービス名Elnkii
50SettingIDオブジェクトの識別子{00000000-0000-0000-0000-0000000000000}
51TcpipNetbiosOptionsTCP/IP経由のNetBIOSの設定ビットマップ0=EnableNetbiosViaDhcp
1=EnableNetbios
2=DisableNetbios
52TcpMaxConnectRetransmissions要求再送信回数既定値=3
53TcpMaxDataRetransmissionsデータセグメント再送信回数既定値=5
54TcpNumConnections同時接続最大数既定値=0xFFFFFE
55TcpUseRFC1122UrgentPointer緊急データにRFC1122仕様を使用Null
56TcpWindowSizeTCP受信ウィンドウの最大サイズイーサネットの既定値8760
57WINSEnableLMHostsLookupローカル参照ファイルを使用するTrue
58WINSHostLookupFileWINS参照ファイルへのパスNull
59WINSPrimaryServerプライマリWINSサーバーのIPアドレスNull
60WINSScopeIDNetBIOS名の末尾の値(なし)
61WINSSecondaryServerセカンダリWINSサーバーのIPアドレスNull
図09


なお図09についての詳細は、Microsoftのサイト「Win32_NetworkAdapterConfigurationクラス」を参照下さい。
またPCの環境によっては、存在しないプロパティもあると思われますので御注意願います。

IPアドレスにはIPv4とIPv6の2種類があり、現状ではIPv4で管理しているところも多いと思います。しかし、IPv6も表示されるようなPC設定になっていれば、図10のように「IPv4アドレス」と「IPv6アドレス」が「IPAddressプロパティ(図09のNo.26)」内に入っている事になります。
IPv4とIPv6が共存する場合の表示
図10


なお、図11のように「IPv6を不使用」に設定にしているPCの場合は、IPv4のみの配列となります。
IPv4とIPv6が共存する場合の表示
図11


この「IPAddressプロパティ値(配列)」を、100行目「For Each strIP In ObjEx.IPaddress」で、1つ1つ取り出して変数strIPにセットします。
101行目「If UBound(Split(strIP, "."), 1) = 3 Then」ではセットされた変数strIPが「IPv4かIPv6か」を調べています。
まず、IPv4・IPv6の表記の違いは以下の通りです。
種類データ数表記分岐コード(例)
IPv432ビットXXX.XXX.XXX.XXX
(XXXは0~255の10進数の数値)
UBound(Split(strIP, "."), 1) = 3
IPv6128ビットXXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX
(Xは0~Fの16進数の数値)
InStr(strIP,":")>0
図12


今回101行目で使用した「UBound(Split(strIP, "."), 1) = 3」は、IPv4表記の中に「.(ピリオド)」が3つ存在することを利用したIF文になっています。
もしIPv6を拾うのであれば、101行目のIF文をNotで否定文にするか、またはIPv6にのみ「:(コロン)」が有ることから「InStr(strIP,":")>0」等とすれば良い事になります。

しかし「IPv4アドレス」「IPv6アドレス」のどちらを取得するにしても、図08に示したように「複数のアダプタが接続状態」の時には、思った通りの値が取得できない可能性はあります。
と言うのは、アダプタの順番は(私のPCの場合は)有線LANの方が先に来るようですが、For~Eachを使っているため「最初に取得するアダプタが有線LAN」である保証は無いからです。
ちなみに今回のコードでは、最終的に「最後のアダプタのIPアドレス」が戻されることになりますが、もし「最初のアダプタのIPアドレス」を戻したければ、103行目「Exit For」を「Exit Function」に変更すれば良いことになります。

102行目「IPaddress1 = strIP」では、101行目で選んだIPアドレスを関数プロシージャの戻り値にしています。

3ー2.WshShellのipconfig法

「コマンドプロンプト(Dos窓)にコマンド入力する事で表示される情報」を使う方法が、図13です。ここでは「ipconfig」コマンドによりIPアドレスを取得します。
  1. '========== ⇩(8) IPアドレス(WshShellのipconfig法) ============
  2. Private Function IPaddress2() As String
  3.  Dim wsh As Object      'WSH(Windows Script Host)shellオブジェクト
  4.  Dim cmd As String      '実行コマンド
  5.  Dim result As Object     'コマンド実行結果(事前バインディングだとWshExec型)
  6.  Dim rowArray As Variant    '実行結果を各行ごとに配列にしたもの
  7.  Dim i As Long         'カウンタ変数(実行結果の行位置)
  8.  Dim Pos As Long    '行の中でのIPアドレスの文字位置
  9.  Set wsh = CreateObject("WScript.Shell")
  10.  cmd = "ipconfig"
  11.  Set result = wsh.exec("%ComSpec% /c " & cmd)
  12.  Do While result.Status = 0
  13.   DoEvents: DoEvents
  14.  Loop
  15.  rowArray = Split(result.StdOut.ReadAll, vbCrLf)
  16.  For i = 0 To UBound(rowArray, 1)
  17.   If InStr(rowArray(i), "IPv4") > 0 Then Exit For
  18.  Next i
  19.  Pos = InStr(rowArray(i), ":")
  20.  IPaddress2 = Mid(rowArray(i), Pos + 2)
  21.  Set result = Nothing
  22.  Set wsh = Nothing
  23. End Function
図13


129行目「Set wsh = CreateObject("WScript.Shell")」は、WSH(Windows Script Host)のWshShellクラスのインスタンスを生成し、変数wshに代入しています。
130行目「cmd = "ipconfig"」は実行するコマンドで、今回は「ipconfig」を使用します。手動でコマンドプロンプト上で「ipconfig」を実行すると、図14のような結果が出力されます。
図14の左側がネットワークアダプタが1つの場合、右側が2つ(この場合は、有線LANと無線LAN)の場合です。
(なお図14は、必要行のみを抜き出して表示し、IPv6の値は架空のものに修正してあります。)
コマンドプロンプトからIpconfigを実行した結果
図14


132行目「Set result = wsh.exec("%ComSpec% /c " & cmd)」では、130行目で設定したipconfigコマンドを実行し、その結果を変数resultに代入します。
実行にはWSHのExecメソッドを使用し、その引数(カッコ内)に「"%ComSpec% /c " & cmd」を指定しています。これは図15のように3つの内容を示しています。
Execメソッドに渡す値
図15


先頭の「%ComSpec%」の、「%」で囲まれた「ComSpec」は、環境変数の1つです。
環境変数とは「Windows等のO/Sが提供するデータ共有機能」で、特定の値やPC内の場所(フォルダー等)、また特定ファイルのフルパス名などが登録されています。
例えば今回使っている環境変数「ComSpec」には、「cmd.exe というファイルのフルパス」が登録されています。

もちろんcmd.exeファイル のフルパスを「直接指定」することも可能ですが、このcmd.exeファイルが置かれている場所がPCによって異なる可能性もあります。
その場合、そのファイルを使うプログラムを作ろうとした時「PC毎にパスを設定し直す」など、非常に使い難いアプリになってしまう事が考えられます。
しかし環境変数『ComSpec』に各PC毎のcmd.exeファイルの場所を登録しておけば、フルパスを知らなくても「環境変数を実行」しさえすれば、どのPCでも「コマンドプロンプトが起動」出来る事になります。

この環境変数に於いて、登録してある値を呼び出す場合は「環境変数を『%』で囲む」ことになっているため、今回の「%ComSpec%」は「cmd.exeのフルパス」を指定することになります。cmd.exeは「実行ファイル」ですので、「コマンドプロンプトが実行される」ことになります。

2番目の「/c」は、コマンドプロンプト実行ファイル(cmd.exe)のオプションで、「コマンドを実行した後、コマンドプロンプトを終了する」ことを指定しています。
最後の「ipconfig」は「コマンドプロンプト上で実行するコマンド」になります。

ですので「"%ComSpec% /c " & cmd」は、「コマンドプロンプトを開き(実行し)、ipconfigを実行し、実行し終わったらコマンドプロンプトを閉じる」という動作になり、得られた結果(図14)は変数resultに代入されます。
寄り道
今回、コマンドの実行結果を受け取る変数resultは、124行目でObject型として宣言しました。これはWSHを実行時バインディングしているためです。
もし事前バインディング(VBE→ツール→参照設定で「Windows Script Host Object Model」を参照)をする時には、実行結果を受取る型は「WshExec型」となりますので、変数resultも「WshExec型」して宣言をします。

134行目「Do While result.Status = 0」から始まるDo~Loopは、132行目の「実行が完了」するのを待っています。
今回の変数resultのStatusプロパティは「プロセスが起動中の間は0を示し、プロセスが終了すると1」になりますので、起動中の間(While result.Status = 0)は次のコードに移行するのを待つことになります。

ただし今回のコマンドプロンプトでの実行は、ウィンドウを使わない「consoleアプリ」なので、Do~Loopを回して待たなくても、138行目の「StdOut.Readall」の部分で「完了するのを待ってくれる」ようです。
ですので、134~136行目のDo~Loopは無くても正常に動作します。

実行した結果は「変数result」に格納されていますが、それを文字列にするには「画面に表示されたものを文字列」にする指示が必要です。138行目の「result.StdOut.ReadAll」がそれに相当し、「標準出力(=画面に表示)を全て読み込む」という意味になります。
得られた文字列は図14のような複数行の文字列です。そのため138行目「rowArray = Split(result.StdOut.ReadAll, vbCrLf)」で、Split関数で「改行(vbCrLf)」で区切った配列にします。
この処理の結果、配列rowArrayの各要素内に1行ずつの文字列が入っていることになります。

140~142行目のFor~Nextでは、配列rowArrayから1要素ずつ取り出します。
140行目「For i = 0 To UBound(rowArray, 1)」で、カウンタ変数iを配列の行数分だけ回し、141行目「If InStr(rowArray(i), "IPv4") > 0 Then Exit For」で、各行の文字列の中に「IPv4」が存在するか否かを調べます。InStr関数なので、存在しなかったら0を返し、存在したら先頭からの位置(0以外の正数)を返してくれます。
ですのでもし存在(> 0 )したら「Exit For」で、140~142行目のFor~Nextを抜け出します。

文字列IPv4が見つかりFor~Nextを抜け出した時点での140行目の変数iの値は、抜け出した後もそのまま保持されています。
そのiの値を使った「rowArray(i)」は「IPv4の文字列がある行」であり、例えば以下のような文字列になります。
 「IPv4 アドレス . . . . . . . . . . . .: 192.168.0.3」

この文字列から右端のIPアドレス値「192.168.0.3」を取り出したいので、その直前にある「:(コロン)」に着目し、143行目「Pos = InStr(rowArray(i), ":")」で、その位置をInStr関数で取得して変数Posに代入します。

「:(コロン)」と「192.168.0.3」の間には、スペースが1つ入っています。ですので145行目「IPaddress2 = Mid(rowArray(i), Pos + 2)」では、切り出し位置を1つ多めに取ることで、IPアドレス「192.168.0.3」が文字列として取り出せます。取り出した値(IPアドレス)は、関数プロシージャの戻り値とします。

図13は「IPv4」のIPアドレスを取り出すコードでしたが、もし「IPv6」の場合は少し手が掛かります。
図14のIPv6の行を見ると、IPv6アドレス「8888::8888: ・・・ :8888 等」の最後に「%18」とか「%7」とかが付いているのが分かると思います。
これは「インタフェース番号」と呼ばれるもので、「IPv6アドレスそのもの」ではありませんので対象外にするため、%の位置を「InStr(rowArray(i), "%")」などで取得し、Mid関数で中央部分だけを切り出す処理が必要になります。
また、図14の右図のように複数のアダプタが接続状態の時は、最初に取得されるアダプタの情報しか入手できないことにも注意が必要です。もし複数のアダプタ情報を戻す場合には、配列戻し等の工夫が必要です。

4.MACアドレス

4ー1.WMI法

WMI(Windows Management Instrumentation)でMACアドレスを取得するのが図16です。
  1. '========== ⇩(9) MACアドレス(WMI) ============
  2. Private Function MACaddress1() As String
  3.  Dim Locator As Object     'SWbemLocatorオブジェクト
  4.  Dim Service As Object    'SWbemServicesExオブジェクト
  5.  Dim ObjSet As Object    'SWbemObjectSetオブジェクト
  6.  Dim ObjEx As Object     'SWbemObjectExオブジェクト
  7.  Set Locator = CreateObject("WbemScripting.SWbemLocator")
  8.  Set Service = Locator.ConnectServer
  9.  Set ObjSet = Service.ExecQuery("Select * From Win32_NetworkAdapterConfiguration Where (IPEnabled = TRUE)")
  10.  For Each ObjEx In ObjSet
  11.   MACaddress1 = ObjEx.MacAddress
  12.  Next ObjEx
  13.  Set ObjSet = Nothing
  14.  Set Service = Nothing
  15.  Set Locator = Nothing
図16


167行目「Set Locator = CreateObject("WbemScripting.SWbemLocator")」でWMIオブジェクトを生成し、168行目「Set Service = Locator.ConnectServer」で、ローカルコンピュータに接続します。
169行目「Set ObjSet = Service.ExecQuery("Select * From Win32_NetworkAdapterConfiguration Where (IPEnabled = TRUE)")」では、クエリー条件(カッコ内のSQL文)を 指定し、得られたデータを変数ObjSetに代入しています。このSQL文の内容は、WMIオブジェクトの「Win32_NetworkAdapterConfiguration」クラスの中から、有効(IPEnabled = TRUE)なネットワークアダプターの情報を取得するもので、得られたデータは「図09」の内容となります。

なお、167~169行目の内容を1行でコード化したものが図17で、この手法を使用したのが「図07(IPアドレスのWMI法)」になります。どちらでも取得できるデータは一緒なので、分かり易い方で良いかと思いますが、直接レジストリ指定でデータを取り出すよりは、オブジェクトを1つ1つ開いていく図16の手法を私としてはお勧めします。
  •  Set ObjSet = GetObject("winmgmts:¥¥.¥root¥cimv2"). _
  •   ExecQuery("SELECT * FROM Win32_NetworkAdapterConfiguration Where (IPEnabled = TRUE)")
図17


171行目「For Each ObjEx In ObjSet」では、ネットワークアダプタ情報を格納した変数ObjSetの中から For Each を使って、各ネットワークアダプタ情報(変数ObjEx)を取り出します。「各ネットワークアダプタ」とは「接続されているネットワークアダプタ」ですので、たとえば有線LANと無線LANの両方が接続されている状態の時には、「図08(右側図)」で示したようにのように、2つのネットワークアダプタ情報が得られます。
169行目「MACaddress1 = ObjEx.MacAddress」では図18のように、ネットワークアダプタ情報の中からMACAddressプロパティを使ってMACアドレスを取り出し、関数プロシージャの戻り値にしています。このMacAddressプロパティは「図09のNo.44」になります。
接続している個数だけ、ネットワークアダプタが存在
図18


なお、「図08」のように、接続されているネットワークアダプタが複数ある場合は、168行目からも複数のネットワークアダプタ情報が得られます。ですので「図16」のコードだと、「最後のネットワークアダプタのMACアドレス」が関数プロシージャの戻り値になりますので、注意が必要です。

4ー2.WshShellのgetmac法

WSH(Windows Script Host)でMACアドレスを取得するものが図19です。
  1. '========== ⇩(10) MACアドレス(WshShellのgetmac法) ============
  2. Private Function MACaddress2()
  3.  Dim wsh As Object      'WSH(Windows Script Host)shellオブジェクト
  4.  Dim cmd As String      '実行コマンド
  5.  Dim result As Object     'コマンド実行結果
  6.  Dim rowArray As Variant   '実行結果を各行ごとに配列化したもの
  7.  Set wsh = CreateObject("WScript.Shell")
  8.  cmd = "getmac"
  9.  Set result = wsh.exec("%ComSpec% /c " & cmd)
  10.  Do While result.Status = 0
  11.   DoEvents: DoEvents
  12.  Loop
  13.  rowArray = Split(result.StdOut.ReadAll, vbCrLf)
  14.  MACaddress2 = Left(rowArray(3), 17)
  15.  Set result = Nothing
  16.  Set wsh = Nothing
  17. End Function
図19


図13」の WSHでIPアドレスを取得する方法と比べると、実行コマンド(ipconfig → getmac)以下が異なります。

187行目「Set wsh = CreateObject("WScript.Shell")」は、WSH(Windows Script Host)のWshShellクラスのインスタンスを生成し、変数wshに代入します。
そして188行目「cmd = "getmac"」では、実行コマンドとして「getmac」を使用します。もちろん「ipconfig /all」でもMACアドレスは取得できますが、getmacはMACアドレスのみが取得できるので、後の処理が楽だと思います。

コマンドプロンプト上で「getmac」を実行すると、図20のような結果が得られます。図20は、実行するPCにネットワークアダプタが2つ存在する場合での実行結果で、且つ左側は一方がOFF状態になっている場合です。
なお、アダプタが1つの時(有線LANまたは無線LANの一方しかない)は、1行しか表示されません。
getmacコマンドでMACアドレスを取得
図20


この「getmac」コマンドを190行目「Set result = wsh.exec("%ComSpec% /c " & cmd)」で実行させ、192~194行目のDo~Loopで実行(result.Status = 0)が完了するまで待ちます(この「待ち」もcmd.exeがconsoleアプリのため、無くてもOKです)。そして196行目「rowArray = Split(result.StdOut.ReadAll, vbCrLf)」のSplit関数で改行マーク(vbCrLf)で各行を配列の各要素に格納しています。

出力例の図20をよく見ると、getmacコマンドを打ち込んだ行と「物理アドレス・・・」と出力されている行の間には空白行が1行入っています。データとしては、この空白行が1行目(=配列の先頭要素)となります。そこから数えると、実際のMACアドレスは4行目以降になります。
Split関数で配列化したものは、インデックスがゼロから始まりますので、実際のMACアドレスはrowArray(3)以降となります。

図20の場合だとrowArray(4)にも物理アドレスが入りますが、1つしかネットワークアダプタが存在しないPCでは「空白行」を取得してしまいますので、確実に目的の物理アドレスを取得するためには、
 ①取得する行をrowArray(3)にする
 ②rowArrayのサイズをUbound等で取得し、必要な物理アドレスのインデックスを求める
 ③getmacで得られる「トランスポート名」に注目し、必要な物理アドレスを探しあてる
の様な手間が必要となりそうです。
なお、使用されているアダプタを取得するのであれば上記の③の方法になりますが、有線LAN・無線LANの両方とも使用されている状態で、例えば「有線LANのMACアドレスを取得したい」ような場合であれば、図21のように実行コマンドを「getmac /v」として取得情報を多くし「接続名」から探し出すか、「ipconfig /all」を使うかの方法が良いと思います。
getmac /vコマンドでMACアドレスの詳細情報を取得
図21


「getmacコマンド」ではMACアドレスが各行の先頭部分にありますので、198行目「MACaddress2 = Left(rowArray(3), 17)」では、Left関数を使ってMACアドレスを切り出しています。切り出す量は、MACアドレスの「XX-XX-XX-XX-XX-XX(xは0~Fの16進数)」という「値部分12文字+ハイフン5文字=17文字」から「17」と指定しています。

5.ユーザー名

5ー1.WshNetworkオブジェクト法

WSH(Windows Script Host)のWshNetworkオブジェクトを使ってユーザー名を取得するのが、図22です。
  1. '========== ⇩(11) ユーザー名(WshNetworkオブジェクト法) ============
  2. Private Function USERname1()
  3.  Dim wsh As Object    'WSH(Windows Script Host)Networkオブジェクト
  4.  Set wsh = CreateObject("WScript.Network")
  5.  USERname1 = wsh.UserName
  6.  Set wsh = Nothing
  7. End Function
図22


214行目「Set wsh = CreateObject("WScript.Network")」では、WshNetworkオブジェクトを生成しています。
WshNetworkオブジェクトには3つのプロパティがあります。
 ① ComputerName(コンピュータ名)
 ② UserDomain(ドメイン名)
 ③ UserName(ユーザー名)
ここでは③のUserNameプロパティを使用して、215行目「USERname1 = wsh.UserName」でユーザー名を取得し、関数プロシージャの戻り値にしています。

5ー2.WshShellのEcho環境変数法

WSH(Windows Script Host)のWshShellオブジェクトを使い、echoコマンド+環境変数でユーザー名を取得するのが、図23です。
  1. '========== ⇩(12) ユーザー名(WshShellのEcho環境変数法) ============
  2. Private Function USERname2()
  3.  Dim wsh As Object       'WshShellオブジェクト
  4.  Dim cmd As String       '実行コマンド
  5.  Dim result As Object      'コマンド実行結果
  6.  Dim rowArray As Variant    '実行結果を各行ごとに配列化したもの
  7.  Set wsh = CreateObject("WScript.Shell")
  8.  cmd = "echo %USERNAME%"
  9.  Set result = wsh.exec("%ComSpec% /c " & cmd)
  10.  Do While result.Status = 0
  11.   DoEvents: DoEvents
  12.  Loop
  13.  rowArray = Split(result.StdOut.ReadAll, vbCrLf)
  14.  USERname2 = rowArray(0)
  15.  Set result = Nothing
  16.  Set wsh = Nothing
  17. End Function
図23


237行目「Set wsh = CreateObject("WScript.Shell")」で、WshShellオブジェクトを生成しています。
238行目「cmd = "echo %USERNAME%"」は、コマンドプロンプト上での実行コマンドを「echo %USERNAME%」としています。

ここで使用している「echo」コマンドは、「そのあとに続く文字列を出力する」という機能があります。今回、その文字列は「%USERNAME%」で、「環境変数」を「%」で囲っているため、「環境変数の値」が出力されることになります。
ですので239行目「Set result = wsh.exec("%ComSpec% /c " & cmd)」を実行することで、環境変数USERNAMEに登録されている「ユーザー名」が、変数resultに格納されます。

241~243行目のDo~Loopは、239行目の実行が完了するのを待っています。

出力された文字列内にはユーザー名だけで無く、改行マークや空白行が含まれていますので、245行目「rowArray = Split(result.StdOut.ReadAll, vbCrLf)」で改行マーク(vbCrLf)で分割し配列化したのち、246行目「USERname2 = rowArray(0)」でその配列の1つ目の要素(Split関数で配列にした場合は、インデックスがゼロからスタートします)を取り出して、関数プロシージャの戻り値にします。

5ー3.WshShellのset環境変数法

WSH(Windows Script Host)のWshShellオブジェクトを使い、setコマンド+環境変数でユーザー名を取得するのが、図24です。
  1. '========== ⇩(13) ユーザー名(WshShellのset環境変数法) ============
  2. Private Function USERname3()
  3.  Dim wsh As Object      'WshShellオブジェクト
  4.  Dim cmd As String      '実行コマンド
  5.  Dim result As Object    'コマンド実行結果
  6.  Dim rowArray As Variant   '実行結果を各行ごとに配列化したもの
  7.  Set wsh = CreateObject("WScript.Shell")
  8.  cmd = "set USERNAME"
  9.  Set result = wsh.exec("%ComSpec% /c " & cmd)
  10.  Do While result.Status = 0
  11.   DoEvents
  12.  Loop
  13.  rowArray = Split(result.StdOut.ReadAll, vbCrLf)
  14.  PCname3 = Split(rowArray(0), "=")(1)
  15.  Set wsh = Nothing
  16.  Set result = Nothing
  17. End Function
図24


267行目「Set wsh = CreateObject("WScript.Shell")」で、WshShellオブジェクトを生成しています。
268行目「cmd = "set USERNAME"」では、使用する実行コマンドを「set USERNAME」とします。なお「USERNAME」と大文字にしていますが、小文字でも問題ありません。
270行目「Set result = wsh.exec("%ComSpec% /c " & cmd)」でコマンドを実行します。
272~274行目のDo~Loopでは、コマンド実行が完了するのを待っています。

「set USERNAME」を実行して得られる結果は、通常は図25の左のようになります。環境変数として「USERNAME」から始まるものは(たぶん)1つのみですが、たとえ「USERNAME1="22222"」みたいなものを「ユーザー環境変数」として作られてしまったとしても、「set USERNAME」と環境変数名を「省略せず」に指定すれば、図25の右側のように本来の「USERNAME」の方が先に表示されます。
et computername コマンドでユーザー名を取得
図25


ですので276行目「rowArray = Split(result.StdOut.ReadAll, vbCrLf)」で、各行を格納した配列の1番目(Splitで配列化しているためインデックスは0番目)に、目的のユーザー名のデータが収められている事になります。
そこで277行目「PCname3 = Split(rowArray(0), "=")(1)」で、1番目のデータ(rowArray(0) )を取り出し、それを「=」で分割して格納した配列の2番目(インデックスは1番目)のデータを取り出し、関数プロシージャの戻り値にしています。

5ー4.Environ環境変数法

Environ関数+環境変数でユーザー名を取得するのが、図26です。
  1. '========== ⇩(14) ユーザー名(Environ環境変数法) ============
  2. Private Function USERname4()
  3.  USERname4 = Environ("USERNAME")
  4. End Function
図26


Environ関数はWindowsの環境変数の値を返す関数です。292行目「USERname4 = Environ("USERNAME")」では、引数に環境変数「USERNAME」を指定することで「ユーザー名」を取得し、関数プロシージャの戻り値にしています。

5ー5.APIのGetUserName関数法

Windows APIのGetUserName関数を使用してユーザー名を取得するのが、図27です。この方法を使うには、図04の04~05行目(32ビットでは09~10行目)で示した、宣言部でのAPI宣言「Private Declare PtrSafe Function GetUserName Lib "advapi32.dll" Alias "GetUserNameA" (ByVal lpBuffer As String, nSize As LongPtr) As LongPtr」が必要です。
  1. '========== ⇩(15) ユーザー名(GetUserName関数法) ============
  2. Private Function USERname5()
  3.  Dim UN As String * 255
  4.  Call GetUserName(UN, 255)
  5.  USERname5 = WorksheetFunction.Trim(UN)
  6. ' USERname5 = Left(UN, InStr(UN, Chr(0)) - 1)  
  7. End Function
図27


302行目「Dim UN As String * 255」では、ユーザー名を格納するため「255文字」の入れ物を変数宣言しています。ユーザー名はWindowsでは最大20文字ですが、余裕を持たせて「ファイル名最大長の255文字分」としました。
このString型宣言(固定長文字列)により、変数UNは「Asciiコード=0 の文字列(ヌル文字)」が255個並んでいる事になります。

304行目ではAPIの「GetUserName関数」を呼び出し、第一引数(今回は変数UN)でユーザー名を受け取ります。第二引数には取り出す文字列長(宣言した255文字の長さ)を指定します。
なお、この第二引数に指定する文字列長は「実際のユーザー名の長さ+1 以上」である必要があります(不足する場合は、ユーザー名は部分的にも取り出される事はありません)。実際のユーザー名の最後にはヌル文字がくっついている様です。なお、302行目で宣言する文字列長さは「実際のユーザー名の長さ」分だけ確保されていれば、問題ありません。

取り出したユーザー名が変数UNにどの様に入っているかですが、図28のように「255文字分の枠」の先頭部分に入ります。ユーザー名の後ろ側は全てヌル文字のままです。
固定長文字列に入ったユーザー名の後ろはヌル文字が並ぶ
図28


このままでも表示は可能ですが、ユーザー名の長さをLen関数で確認しても、ヌル文字も含めた「255文字」となってしまいます。
ですので305行目「USERname5 = WorksheetFunction.Trim(UN)」で、後方のヌル文字を削除しています。なおWorksheetFunction.Trimでヌル文字が削除できる仕組みについては「文字列のスペースを削除・集結するTrim関数」を参照願います。

なお、ユーザー名にはスペースを含める事は可能なため「文字列と文字列の間に複数のスペース」が入っているユーザー名の場合には、WorksheetFunction.Trimを使用すると「スペースが1つに集結」されてしまいますので注意が必要です。
他の手法として、見え消しにしてある306行目「USERname5 = Left(UN, InStr(UN, Chr(0)) - 1) 」のように、左側からヌル文字(Asciiコード=0 → Chr(0) )の位置を探し出し、ユーザー名の実体長さを調べてからLeft関数で後方を切り捨てる事でもOKです。

5ー6.ExcelのUserNameプロパティ法

上記と似たようなものに、ApplicationオブジェクトのUserNameプロパティで取得できるユーザー名があります。(図29)
  1. '========== ⇩(16) ユーザー名(ExcelのUserNameプロパティ法) ============
  2. Private Function USERname6()
  3.  USERname6 = Application.UserName
  4. End Function
図29


312行目「USERname6 = Application.UserName」では、Applicationオブジェクト(=Excel)のUserNameプロパティでユーザー名を取得し、関数プロシージャの戻り値にしています。

但し、このExcelのUserNameプロパティで得られる名前は「Excelをインストール/ライセンス認証する際に入力したユーザー名」であり、今まで説明してきた様な「Windowsのログインユーザー名」ではありません。
ログイン名と同じ場合もあるでしょうが、基本的に異なるものですので注意が必要です。

6.コンピューター名

6ー1.WshNetworkオブジェクト法

WSH(Windows Script Host)のWshNetworkオブジェクトを使ってコンピューター名を取得するのが、図30です。
  1. '========== ⇩(17) コンピューター名(WSH法) ============
  2. Private Function PCname1()
  3.  Dim wsh As Object     'WSH(Windows Script Host)Networkオブジェクト
  4.  Set wsh = CreateObject("WScript.Network")
  5.  PCname1 = wsh.ComputerName
  6.  Set wsh = Nothing
  7. End Function
図30


324行目「Set wsh = CreateObject("WScript.Network")」でWshNetworkオブジェクトを生成しています。
WshNetworkオブジェクトのプロパティには、図22でも説明した通り、3つのプロパティがあります。
 ① ComputerName(コンピュータ名)
 ② UserDomain(ドメイン名)
 ③ UserName(ユーザー名)
ここでは①のComputerNameプロパティを使用して、325行目「PCname1 = wsh.ComputerName」でコンピューター名を取得し、関数プロシージャの戻り値にしています。

6ー2.WshShellのipconfig法

WSH(Windows Script Host)のWshShellオブジェクトでipconfigコマンドを使ってコンピューター名を取得するのが、図31です。
  1. '========== ⇩(18) コンピューター名(WshShellのipconfig法) ============
  2. Private Function PCname2()
  3.  Dim wsh As Object      'WshShellオブジェクト
  4.  Dim cmd As String      '実行コマンド
  5.  Dim result As Object     'コマンド実行結果
  6.  Dim rowArray As Variant    '実行結果を各行ごとに配列化したもの
  7.  Dim i As Long         'カウンタ変数(実行結果の行位置)
  8.  Dim Pos As Long    '行の中でのコンピューター名の文字位置
  9.  Set wsh = CreateObject("WScript.Shell")
  10.  cmd = "ipconfig /all"
  11.  Set result = wsh.exec("%ComSpec% /c " & cmd)
  12.  Do While result.Status = 0
  13.   DoEvents
  14.  Loop
  15.  rowArray = Split(result.StdOut.ReadAll, vbCrLf)
  16.  For i = 0 To UBound(rowArray, 1)
  17.   If InStr(rowArray(i), "ホスト名") > 0 Then Exit For
  18.  Next i
  19.  Pos = InStr(rowArray(i), ":")
  20.  PCname2 = Mid(rowArray(i), Pos + 2)
  21.  Set result = Nothing
  22.  Set wsh = Nothing
  23. End Function
図31


339行目「Set wsh = CreateObject("WScript.Shell")」で、WshShellオブジェクトを生成しています。
340行目「cmd = "ipconfig /all"」は、コマンドプロンプト上での実行コマンドで、「ipconfig /all」とします。このコマンドは「すべて(/all)のネットワーク構成情報」を表示しますので、なんでも取得できる代わりに、多くの情報の中から自分の必要情報を取り出す処理が面倒になるというデメリットも考えてコマンド種類を選ぶべきと思います。

342行目「Set result = wsh.exec("%ComSpec% /c " & cmd)」で、コマンドを実行し、その結果を変数resultに代入します。344~346行目のDo~Loopは、342行目の実行が完了するのを待っています。

「ipconfig /all」の実行結果は、図32のように得られます。長々と表示されますので後半を省略していますが、その先頭に「ホスト名」という内容でコンピュータ名が表示されます。
ipconfig /all コマンドで全てのネットワーク情報を取得
図32


コマンド実行した結果を使い、348行目「rowArray = Split(result.StdOut.ReadAll, vbCrLf)」で、各行単位の配列にします。そしてその配列の中から、「ホスト名」と書いてある行を349~351行目のFor~Nextで探します。
目的の行は「"ホスト名"」と書いてある行ですので、350行目「If InStr(rowArray(i), "ホスト名") > 0 Then Exit For」で探索し、見つかったらExit For でFor~Nextを抜け出します。

For~Nextを抜け出した時(=ホスト名の行が見つかった時)のカウンタ変数iの値はまだ保持されているため、353行目「Pos = InStr(rowArray(i), ":")」で、その行のデータ中から「:(コロン)」を探し、その文字位置を変数Posに代入します。
コンピュータ名は、「:(コロン)」の後のスペースを挟んだその後ろに書かれているので、354行目「PCname2 = Mid(rowArray(i), Pos + 2)」で文字列を取り出し、関数プロシージャの戻り値にします。

6ー3.Environ環境変数法

Environ関数+環境変数でコンピューター名を取得するのが、図33です。
  1. '========== ⇩(19) ドメイン名(環境変数法) ============
  2. Private Function CPname3()
  3.  CPname3 = Environ("COMPUTERNAME")
  4. End Function
図33


Environ関数はWindowsの環境変数値を返す関数です。372行目「CPname3 = Environ("COMPUTERNAME")」では、引数に環境変数「COMPUTERNAME」を指定することで「コンピューター名」を取得し、関数プロシージャの戻り値にしています。

尚、この他にも以下のように環境変数を使ってコンピュータ名を取得する方法があります。
・「echo %COMPUTERNAME%」と、echoコマンドを実行し取得(図23を参照下さい)
・「set COMPUTERNAME」と、setコマンドを実行し取得(図24を参照下さい)

7.ドメイン名

7ー1.WshNetworkオブジェクト法

WSH(Windows Script Host)のWshNetworkオブジェクトを使ってドメイン名を取得するのが、図34です。
  1. '========== ⇩(20) ドメイン名(WSH法) ============
  2. Private Function DOMAINname1()
  3.  Dim wsh As Object      'WSH(Windows Script Host)Networkオブジェクト
  4.  Set wsh = CreateObject("WScript.Network")
  5.  DOMAINname1 = wsh.UserDomain
  6.  Set wsh = Nothing
  7. End Function
図34


384行目「Set wsh = CreateObject("WScript.Network")」ではWshNetworkオブジェクトを生成しています。
WshNetworkオブジェクトのプロパティには、図22でも説明した通り、3つのプロパティがあります。
 ① ComputerName(コンピュータ名)
 ② UserDomain(ドメイン名)
 ③ UserName(ユーザー名)
ここでは②のUserDomainプロパティを使用して、385行目「PCname1 = wsh.UserDomain」でドメイン名を取得し、関数プロシージャの戻り値にしています。

7ー2.Environ環境変数法

Environ関数+環境変数でドメイン名を取得するのが、図35です。
  1. '========== ⇩(21) ドメイン名(環境変数法) ============
  2. Private Function DOMAINname2()
  3.  DOMAINname2 = Environ("USERDOMAIN")
  4. End Function
図35


EnvironはWindowsの環境変数値を返す関数です。402行目「DOMAINname2 = Environ("USERDOMAIN")」では、引数に環境変数「USERDOMAIN」を指定することで「ドメイン名」を取得し、関数プロシージャの戻り値にしています。

尚、この他にも以下のように環境変数を使ってドメイン名を取得する方法があります。
・「echo %USERDOMAIN%」と、echoコマンドを実行し取得(図23を参照下さい)
・「set USERDOMAIN」と、setコマンドを実行し取得(図24を参照下さい)

8.CPU名

8ー1.Environ環境変数法

まず、CPUを表す環境変数は図36のように複数あります。
環境変数内容
NUMBER_OF_PROCESSORSCPUの論理コア数8
PROCESSOR_ARCHITECTUREアーキテクチャx86
PROCESSOR_ARCHITEW6432 *1アーキテクチャAMD64
PROCESSOR_IDENTIFIERCPUの説明Intel64 Family 6 Model 30 Stepping 5, GenuineIntel
PROCESSOR_LEVELCPUのモデル番号6
PROCESSOR_REVISIONCPUのリビジョン番号1e05
図36


寄り道
*1:図36の「PROCESSOR_ARCHITEW6432」について
CPUのアーキテクチャは本来、環境変数「PROCESSOR_ARCHITECTURE」に入るのですが、64bit版Windows上で WOW64Windows 32-bit On Windows 64-bit)という「64bit版のWindows上で32bit版のアプリケーションを動かすエミュレーションシステム」が働いている時には、環境変数「PROCESSOR_ARCHITEW6432」に「プロセッサの本来のCPUアーキテクチャ」が入ります。

この「PROCESSOR_ARCHITECTURE」と「PROCESSOR_ARCHITEW6432」の組み合わせで、図37のように本来のCPUのビット数が分かります。
PROCESSOR_ARCHITEW6432
32bit64bit
PROCESSOR_ARCHITECTURE323264
32bit323264
64bit646464
図37


図37を言葉で言うと、「PROCESSOR_ARCHITEW6432」の値が64bit版(AMD64やIA64)の場合は「CPUは64bit」となり、また「PROCESSOR_ARCHITECTURE」の値が64bit版の場合も「CPUは64bit」となります。
それ以外の場合は「CPUは32bit」です。

図38では、図36の中の環境変数「PROCESSOR_IDENTIFIER」を使用して、CPU名を取得しています。
  1. '========== ⇩(22) CPU名(環境変数法1) ============
  2. Private Function CPUname1()
  3.  CPUname1 = Environ("PROCESSOR_IDENTIFIER")
  4. End Function
図38


412行目「CPUname1 = Environ("PROCESSOR_IDENTIFIER")」では、引数に環境変数「PROCESSOR_IDENTIFIER」を指定することで「CPU名(CPUの説明)」を取得し、関数プロシージャの戻り値にしています。

尚、この他にも以下のように環境変数を使ってCPU名を取得する方法があります。
・「echo %PROCESSOR_IDENTIFIER%」と、echoコマンドを実行し取得(図23を参照下さい)
・「set PROCESSOR_IDENTIFIER」と、setコマンドを実行し取得(図24を参照下さい)

9.Excelバージョン

9ー1.Versionプロパティ法

ApplicationオブジェクトのVersionプロパティを使用し、Excelのバージョンを取得するのが図39です。
  1. '========== ⇩(23) Excelバージョン(Excelのプロパティ法) ============
  2. Private Function EXCELver1()
  3.  EXCELver1 = Application.Version
  4. End Function
図39


422行目「EXCELver1 = Application.Version」で、Application(この場合はExcel)オブジェクトのVersionプロパティの値(=Excelのバージョン)を取得し、関数プロシージャの戻り値にしています。

10.O/Sバージョン

10ー1.OperatingSystemプロパティ法

ApplicationオブジェクトのOperatingSystemプロパティを使用し、O/S(=Windows)のバージョンを取得するのが図40です。
  1. '========== ⇩(24) O/Sのバージョン(Excelのプロパティ法) ============
  2. Private Function OSver1()
  3.  OSver1 = Application.OperatingSystem
  4. End Function
図40


432行目「OSver1 = Application.OperatingSystem」で、Application(この場合はExcel)のOperatingSystemプロパティの値(=O/Sのバージョン)を取得し、関数プロシージャの戻り値にしています。
なお、このOperatingSystemプロパティで得られるバージョンは、例えばWindows10やWindows11であれば「Windows(32-bit)NT 10.00」という様な文字列になります。ここで「64-bit」とカッコ内で表示されているビット数は、O/Sのビット数では無く、Excel等のOfficeアプリのビット数です。ちょっと勘違いしてしまいそうな表示ですので、違う手法を使った方が良いかもしれません。

なお、今までのWindowsのバージョン番号は、図41のように振られています。
Windows バージョン履歴(主なもの)
製品バージョン番号発売年
Windows 1.011.011985
Windows 1.031.031986
Windows 2.032.031987
Windows 2.12.11988
Windows/286 2.02.01988
Windows/386 2.12.11988
Windows 3.03.01990
Windows 3.13.11992
Windows For Workgroups 3.13.111993
Windows NT 3.13.11993
Windows NT 3.53.51994
Windows NT 3.513.511995
Windows 954.01995
Windows NT 4.04.01996
Windows 984.101998
Windows 98 SE4.101999
Windows Me4.902000
Windows 20005.02000
Windows XP5.12001
Windows Server 20035.22003
 
製品バージョン番号発売年
Windows XP 64bit5.22003
Windows XP Pro5.22005
Windows Server 2003 R25.22005
Windows Vista6.02007
Windows Home Server6.02007
Windows Server 20086.02008
Windows 76.12009
Windows Server 2008 R26.12009
Windows Home Server 20116.12011
Windows 86.22012
Windows RT6.22012
Windows Server 20126.22012
Windows 8.16.32013
Windows Server 2012 R26.32013
Windows 1010.02015
Windows Server 201610.02016
Windows Server 2019 10.02018
Windows 1110.02021
Windows Server 202210.02021
 
図41


10ー2.WMI法

WMI(Windows Management Instrumentation)で、O/Sのバージョンを取得するのが図42です。
  1. '========== ⇩(25) O/Sのバージョン(WMI法) ============
  2. Private Function OSver2()
  3.  Dim Locator As Object     'SWbemLocatorオブジェクト
  4.  Dim Service As Object    'SWbemServicesExオブジェクト
  5.  Dim ObjSet As Object    'SWbemObjectSetオブジェクト
  6.  Dim ObjEx As Object     'SWbemObjectExオブジェクト
  7.  Set Locator = CreateObject("WbemScripting.SWbemLocator")
  8.  Set Service = Locator.ConnectServer
  9.  Set ObjSet = Service.ExecQuery("Select * From Win32_OperatingSystem")
  10.  For Each ObjEx In ObjSet
  11.   OSver2 = ObjEx.Caption & "(" & ObjEx.OSArchitecture & ")" & ObjEx.Version
  12.  Next
  13.  Set ObjSet = Nothing
  14.  Set Service = Nothing
  15.  Set Locator = Nothing
  16. End Function
図42


447行目「Set Locator = CreateObject("WbemScripting.SWbemLocator")」でWMIオブジェクトを生成し、448行目「Set Service = Locator.ConnectServer」で、ローカルコンピュータに接続します。
449行目「Set ObjSet = Service.ExecQuery("Select * From Win32_OperatingSystem")」では、 クエリー条件(カッコ内)を 指定してO/S情報を取得します。

取得した変数ObjSetはコレクションなので451行目「For Each ObjEx In ObjSet」で、その中のSWbemObjectExオブジェクト(変数ObjEx)を取り出します。
取り出したSWbemObjectExオブジェクト(データテーブル:Win32_OperatingSystem)には、図43のように多くのプロパティがあります。
No.プロパティ内容
1BootDevice起動元ディスクドライブ¥Device¥HarddiskVolume1
2BuildNumberO/Sビルド番号22621
3BuildTypeO/Sビルド種類Multiprocessor Free
4CaptionO/S名称Microsoft Windows 11 Home
5CodeSetコードページ値932
6CountryCode国/地域のコード81
7CreationClassName継承チェーンに表示されるクラス名Win32_OperatingSystem
8CSCreationClassName作成クラス名Win32_ComputerSystem
9CSDVersionサービスパックNull
10CSNameコンピュータ名[コンピュータ名]
11CurrentTimeZoneグリニッジ標準時に対するOffSet値540
12DataExecutionPrevention_32BitApplicationsデータ実行防止が32bitアプリで機能True
13DataExecutionPrevention_Availableバッファオーバーラン攻撃を防ぐTrue
14DataExecutionPrevention_Driversデータ実行防止をドライバに対して行うTrue
15DataExecutionPreventio_SupportPolicyデータ実行防止設定0=Always Off 1=Always On
2=オプトイン 3=オプトアウト
16DebugデバッグバージョンのインストールFalse
17DescriptionO/Sの説明(なし)
18DistributedO/Sは複数ノードに分散False
19EncryptionLevelトランザクションの暗号レベル256
20ForegroundApplicationBoostプロセスの優先度0=無し 1=最小 2=最大
21FreePhysicalMemory空き物理メモリ(KB)844920
22FreeSpaceInPagingFilesスワップアウトせずにマップできる量(KB)5481212
23FreeVirtualMemory空き仮想メモリ(KB)1819680
24InstallDateインストール日時20221005150000.000000+540
25LargeSystemCache(廃止)Null
26LastBootUpTime最後に再起動した日時20230215210000.000000+540
27LocalDateTimeローカル日時20230228150000.000000+540
28Locale言語識別子0411
29Manufacturer製造元名Microsoft Corporation
30MaxNumberOfProcessesサポート可能プロセス数-1
31MaxProcessMemorySize割り当て可能メモリ量(KB)137438953344
32MUILanguages多言語UI PackArray(ja-JP,en-US)
33NameO/SインスタンスMicrosoft Windows 11 Home
|C:¥WINDOWS
|¥Device¥Harddisk0¥Partition3
34NumberOfLicensedUsersO/Sユーザーのライセンス数Null
35NumberOfProcesses起動中プロセス数257
36NumberOfUsersユーザーセッション数2
37OperatingSystemSKU在庫保管単位番号101
38Organization登録済みユーザーの会社名Null
39OSArchitectureO/Sのアーキテクチャ64 ビット
40OSLanguageO/Sの言語バージョン1041(=日本語)
41OSProductSuite追加製品768
42OSTypeO/Sの種類18(=WinNT)
43OtherTypeDescriptionO/Sバージョンの追加説明
(OSTypeがOther(値1)の時)
44PAEEnabled物理アドレス拡張有効
45PlusProductID(サポートせず)Null
46PlusVersionNumber(サポートせず)Null
47PortableOperatingSystemO/SがUSB起動か否かFalse
48PrimaryプライマリO/Sか否かTrue
49ProductTypeその他のシステム情報1=ワークステーション 2=ドメインコントローラ 3=サーバー
50QuantumLength量子当りのクロックティック数
(サポートせず)
0=不明 1=1ティック 2=2ティック
51QuantumType固定量子or可変長量子
(サポートせず)
0=不明 1=固定 2=変数
52RegisteredUser登録ユーザ[ユーザー名、メールアドレスなど]
53SerialNumberO/Sシリアル番号10XXX-OEM-00XXXXX-XXXXX
54ServicePackMajorVersionService Packのメジャーバージョン0(=Service Pack無)
55ServicePackMinorVersionService Packのマイナーバージョン0(=Service Pack無)
56SizeStoredInPagingFilesページングファイル可能サイズ(KB)5628828
57Statusオブジェクトの状態OK, Error, Degraded, Unknown ・・・等
58SuiteMask使用可能な製品識別フラグ784
59SystemDeviceO/Sの物理ディスクパーティション¥Device¥HarddiskVolume3
60SystemDirectoryO/SのシステムディレクトリC:¥WINDOWS¥system32
61SystemDriveO/Sのディスクドライブ名C:
62TotalSwapSpaceSizeスワップ領域の合計量(KB)Null
63TotalVirtualMemorySize仮想メモリのサイズ(KB)13839256
64TotalVisibleMemorySize物理メモリのサイズ(KB)8210428
65VersionO/Sのバージョン10.0.22621
66WindowsDirectoryWindowsディレクトリC:¥WINDOWS
図43


なお図43についての詳細は、Microsoftのサイト「Win32_OperatingSystemクラス」を参照下さい。
またPCの環境によっては、存在しないプロパティもありますので御注意願います。

452行目「OSver2 = ObjEx.Caption & "(" & ObjEx.OSArchitecture & ")" & ObjEx.Version」では、図43のNo.4(Caption)、No.39(OSArchitecture)、No.65(Version)のプロパティを使い、O/Sのバージョンをもっともらしい文字列に組み立て、関数プロシージャの戻り値にしています。
もちろん、他のプロパティを組み合わせてもOKです。

10ー3.APIのGetVersionEx関数法

Windows APIのGetVersionEx関数を使用してO/Sバージョンを取得する方法が図44です。
この方法には、宣言部での「GetVersionEx関数の宣言(図04)」と「OSVERSIONINFO構造体宣言(図05)」が必要です。
  1. '========== ⇩(26) O/Sのバージョン(API関数法) ============
  2. Function OSver3() As String
  3.  Dim osvi As OSVERSIONINFO   '図05で指定した構造体
  4.  osvi.dwOSVersionInfoSize = Len(osvi)   '構造体のサイズを指定
  5.  If GetVersionEx(osvi) = 0 Then
  6.   OSver3 = ""
  7.  Else
  8.   With osvi
  9.    OSver3 = CStr(.dwMajorVersion) & "." & CStr(.dwMinorVersion) & "." & CStr(.dwBuildNumber)
  10.   End With
  11.  End If
  12. End Function
図44


472行目「Dim osvi As OSVERSIONINFO」では、図05の構造体と同じデータ形の変数を宣言します。
このOSVERSIONINFO構造体の内容は、図45のようになります。
項目内容詳細
dwOSVersionInfoSize構造体のバイト数値=148
dwMajorVersionメジャー番号バージョン番号の整数部
dwMinorVersionマイナー番号バージョン番号の小数部
dwBuildNumberビルド番号O/Sのビルド番号(Me以前は +バージョン番号)
dwPlatformIdプラットフォームのID値=2(Win9xは1、Win3.1は0)
szCSDVersionO/Sに関する付加情報サービスパック情報、追加バージョン情報
図45


なお、例えばWindows10のバージョン番号は「10.0」ですが、この番号の整数部「10」が図45の「メジャー番号」であり、小数点以下の部分「0」がマイナー番号となります。

474行目「osvi.dwOSVersionInfoSize = Len(osvi)」では、構造体のサイズ「dwOSVersionInfoSize」にバイト数を設定します。構造体は「Long型×5個+String型×128文字」なので、Long型は1つ4バイトで「4バイト × 5個 + 128バイト = 148バイト」となります。直接「osvi.dwOSVersionInfoSize = 148」としても支障ありませんが、間違いないように「Len(osvi)」を使った方が安全です。

476行目「If GetVersionEx(osvi) = 0 Then」は、GetVersionEx関数が失敗(474行目のサイズ指定忘れを含む)した場合には、ゼロが戻りますので、その時は477行目「OSver3 = ""」で関数プロシージャの戻り値を""(長さゼロの文字列)にして終了させます。(477行目が無いと、関数プロシージャのString型の初期値の「値ゼロの文字列」が戻ることになります。それでもエラー等にはなりません。)

GetVersionEx関数が成功した場合(478行目「Else」)には、479行目「With osvi」で構造体を基準にし、480行目「OSver3 = CStr(.dwMajorVersion) & "." & CStr(.dwMinorVersion) & "." & CStr(.dwBuildNumber)」でO/Sバージョンの形を作成し、関数プロシージャの戻り値にします。
OSVERSIONINFO構造体から受け取る値は、図45のように(構造体サイズを除いて)5つありますが、480行目ではその内の3つを使用して組み立ています。

11.O/Sプロダクト番号

11ー1.WMI法

WMI(Windows Management Instrumentation)で、O/Sのプロダクト番号を取得するのが図46です。
  1. '========== ⇩(27) O/Sプロダクト番号(WMI法) ============
  2. Private Function OSprod1()
  3.  Dim Locator As Object     'SWbemLocatorオブジェクト
  4.  Dim Service As Object    'SWbemServicesExオブジェクト
  5.  Dim ObjSet As Object    'SWbemObjectSetオブジェクト
  6.  Dim ObjEx As Object     'SWbemObjectExオブジェクト
  7.  Set Locator = CreateObject("WbemScripting.SWbemLocator")
  8.  Set Service = Locator.ConnectServer
  9.  Set ObjSet = Service.ExecQuery("Select * From Win32_OperatingSystem")
  10.  For Each ObjEx In ObjSet
  11.   OSprod1 = ObjEx.SerialNumber
  12.  Next
  13.  Set ObjSet = Nothing
  14.  Set Service = Nothing
  15.  Set Locator = Nothing
  16. End Function
図46


このコードは、図42とほぼ同等です。
497行目「Set Locator = CreateObject("WbemScripting.SWbemLocator")」でWMIオブジェクトを生成し、498行目「Set Service = Locator.ConnectServer」で、ローカルコンピュータに接続します。
499行目「Set ObjSet = Service.ExecQuery("Select * From Win32_OperatingSystem")」では、 クエリー条件(カッコ内)を 指定してO/S情報を取得します。

取得した変数ObjSetはコレクションなので501行目「For Each ObjEx In ObjSet」で、その中のSWbemObjectExオブジェクトを取り出します。
取り出したSWbemObjectExオブジェクト(変数ObjEx)には、図43のように多くのプロパティがありますが、ここではNo.53(SerialNumber)を使用し、502行目「OSprod1 = ObjEx.SerialNumber」でプロダクト番号を取得し、関数プロシージャの戻り値にします。

12.ハードディスク シリアル番号

12ー1.WMI法

WMI(Windows Management Instrumentation)で、ハードディスクのシリアル番号を取得するのが図47です。
  1. '========== ⇩(28) ハードディスク シリアル番号(WMI法) ============
  2. Public Function HDserial1()
  3.  Dim Locator As Object     'SWbemLocatorオブジェクト
  4.  Dim Service As Object    'SWbemServicesExオブジェクト
  5.  Dim ObjSet As Object    'SWbemObjectSetオブジェクト
  6.  Dim ObjEx As Object     'SWbemObjectExオブジェクト
  7.  Set Locator = CreateObject("WbemScripting.SWbemLocator")
  8.  Set Service = Locator.ConnectServer
  9.  Set ObjSet = Service.ExecQuery("Select * From Win32_DiskDrive")
  10.  For Each ObjEx In ObjSet
  11.   If ObjEx.MediaType <> "Removable Media" Then
  12.    HDserial1 = Trim(ObjEx.Caption) & "(" & Trim(ObjEx.SerialNumber) & ")"
  13.    Exit For
  14.   End If
  15.  Next
  16.  Set ObjSet = Nothing
  17.  Set Service = Nothing
  18.  Set Locator = Nothing
  19. End Function
図47


このコードは、図42図46とほぼ同等です。
527行目「Set Locator = CreateObject("WbemScripting.SWbemLocator")」でWMIオブジェクトを生成し、528行目「Set Service = Locator.ConnectServer」で、ローカルコンピュータに接続します。
529行目「Set ObjSet = Service.ExecQuery("Select * From Win32_DiskDrive")」では、クエリー条件(カッコ内)を 指定してディスク情報を取得します。

================================
図42図46では、データテーブル名として「Win32_OperatingSystem」を指定することでO/S情報を取得しましたが、図47では「Win32_DiskDrive」をデータテーブルに指定することで「ドライブ(ハードディスク)」の情報を得ます。

取得した変数ObjSetはコレクションなので531行目「For Each ObjEx In ObjSet」で、その中のSWbemObjectExオブジェクトを取り出します。取り出したSWbemObjectExオブジェクト(データテーブル:Win32_DiskDrive)には、図48のように多くのプロパティがあります。
No.プロパティ内容
1Availabilityデバイスの可用性と状態1~21の番号,又はNull
2BytesPerSector各セクタのバイト数512
3Capabilitiesメディアアクセスデバイスの機能(0~12の番号の配列)
3=ランダムアクセス 4=書き込みサポート 5=暗号化 等
4CapabilityDescriptionsアクセスデバイスの詳細説明(配列)
5Captionオブジェクトの簡易説明KBG40ZNS128G BG4A XXXXXX
6CompressionMethod圧縮アルゴリズムNull 等
7ConfigManagerErrorCodeエラーコード0(=正常動作)
8ConfigManagerUserConfigユーザ定義の構成を使用False(=使用せず)
9CreationClassName具象クラスの名前Win32_DiskDrive
10DefaultBlockSize既定ブロックサイズ(byte)Null
11Descriptionオブジェクトの説明ディスク ドライブ
12DeviceIDディスクドライブの一意識別子\\.\PHYSICALDRIVE0
13ErrorClearedエラーがクリアされたNull
14ErrorDescriptionエラーの詳細Null
15ErrorMethodologyエラー検出,修正の種類Null
16FirmwareRevisionファームウェアのリビジョンAEMS0000
17Index物理ドライブ番号0
18InstallDateインストール日Null
19InterfaceTypeインターフェイスの種類SCSI ,HDC ,IDE ,USB ,1394
20LastErrorCode最後のエラーコードNull
21Manufacturerドライブ製造元名(標準ディスク ドライブ)
22MaxBlockSize最大ブロックサイズ(byte)Null
23MaxMediaSizeサポートされる最大メディアサイズ(KB)Null
24MediaLoaded読み取り可能なFile Systemが有るTrue(=固定ディスクは常にTrue)
25MediaTypeメディアの種類External hard disk media(外部HD)
Removable media(リムーバブル)
Fixed hard disk media(固定HD)
Unknown(不明)
26MinBlockSize最小ブロックサイズ(byte)Null
27Model製造元のモデル番号STXXXX1W
28Nameオブジェクトが識別されるラベル¥¥.¥PHYSICALDRIVE0
29NeedsCleaningデバイスのクリーニング必要性Null
30NumberOfMediaSupported挿入可能なメディア最大数Null
31Partitions物理ドライブのパーティション数3
32PNPDeviceIDPlug & PlayしているデバイスSCSI\DISK&VEN_NVME&PROD_KBGxxZNSxxxG_BGx\x&xxxBxBD&0&000000
33PowerManagementCapabilities論理デバイスの電源関連機能0~7 又は Null
2=Disabled 3=Enabled 等
34PowerManagementSupported中断モード等の電源管理可Null
35SCSIBusSCSIバス番号0
36SCSILogicalUnitSCSI論理ユニット番号0
37SCSIPortSCSIポート番号0
38SCSITargetIdSCSI識別子番号0
39SectorsPerTrack各トラックのセクター数63
40SerialNumber製造元割り当て番号WD-WMxxxxxxxxxx
41SignatureディスクIDNull
42Sizeドライブサイズ(シリンダ合計数)128034708480
43Statusオブジェクトの状態OK ,Error ,Degraded ,・・・他
44StatusInfo論理デバイスの状態1~5 又はNull
45SystemCreationClassNameスコープシステムの作成クラス名Win32_ComputerSystem
46SystemNameスコープシステムの名前[名前]
47TotalCylinders物理ドライブのシリンダー合計数15566
48TotalHeadsドライブのヘッドの合計数255
49TotalSectors物理ドライブのセクター合計数250067790
50TotalTracks物理ドライブのトラック合計数3969330
51TracksPerCylinder物理ドライブの各シリンダー内のトラック数255
図48


なお図48についての詳細は、Microsoftのサイト「Win32_DiskDriveクラス」を参照下さい。
またPCの環境によっては、存在しないプロパティもある可能性があるので御注意願います。

PCの構成によっては、複数のハードディスクが搭載されていたり、リムーバブルディスクが接続されていたりする場合があります。今回はハードディスク情報のみを取得することにし、532行目「If ObjEx.MediaType <> "Removable Media" Then」でリムーバブルディスクを除外しています。
そして1つ目のハードディスクが見つかったところで533行目「HDserial1 = Trim(ObjEx.Caption) & "(" & Trim(ObjEx.SerialNumber) & ")"」で、図48のNo.5(Caption)、No.40(SerialNumber)のプロパティを使い、もっともらしい文字列に組み立てています。もちろん、他のプロパティを組み合わせてもOKです。

最後に534行目「Exit For」でFor Each~Next を抜け出し、1つ目のハードディスク情報だけを関数プロシージャの戻り値にしています。

13.まとめ

取得したい固有情報と取得手法を図49のようにマトリクスにしました。
WMIWshNetworkWshShellEnviron
環境変数
Application
プロパティ
API
IpConfigGetMacEcho環境変数Set環境変数
IPアドレス図07図13
MACアドレス図16図19
ユーザー名図22図23図24図26図29図27
コンピュータ名図30図31図33
ドメイン名図34図35
CPU名図38
Excelバージョン図39
O/Sバージョン図42図40図44
Excelプロダクト
O/Sプロダクト図46
HDシリーズ図47
図49


今回、固有情報を得られる事を確認したところは「黄色背景」にしましたが、手法はもちろんの事、得られる固有情報も網羅できたとは思っていません。この表の中でも更に塗りつぶせるところもあるでしょうし、この表から外れたところで得られる情報・手法もあると思います。

表中の「Excelプロダクト番号」は、今回は情報取得の方法が見つかりませんでした。古いバージョンでは取得できた様で、色々なサイトで手法が紹介されていましたが、新しいバージョン(2016以降で確認)では不可でした。
他の項目は現在は情報が取得できますが、Excelプロダクト番号と同様に未来永劫取得できるかは分かりません。新バージョンが出てきたら、今まで使ってきた手法で取得可能かを確認する必要があると思います。

なお、Application(=Excel)オブジェクトのUserNameプロパティで得られる名前(ピンク色背景)は、他のWindowsのユーザー名とは異なるものですので御注意下さい。

アプリ実例

アンケートの回収と集計方法
ExcelシートDBを使った会議室予約システム
セル変更履歴をコメントに残す

サンプルファイル

PCの固有情報の取得(its-029.xlsm)
セキュリティ向上を目的として「インターネット経由でダウンロードしたOfficeファイル(Excel等)のマクロは、既定でブロック」されるようにOfficeアプリケーションの既定動作が変更になりました。(2022年4月より切替開始)
解除の方法については「ダウンロードファイルのブロック解除方法」を参照下さい。