PCの固有情報の取得
- 1.概要
- 2.システム補助
- 2ー1.ワークシート
- 2ー2.標準モジュール
- 2ー2ー1.API関数宣言など
- 2ー2ー2.情報取得と表示
- 3.IPアドレス
- 3ー1.WMI法
- 3ー2.WshShellのipconfig法
- よりみち(事前バインディングでのデータ型指定)
- 4.MACアドレス
- 4ー1.WMI法
- 4ー2.WshShellのgetmac法
- 5.ユーザー名
- 5ー1.WshNetworkオブジェクト法
- 5ー2.WshShellのEcho環境変数法
- 5ー3.WshShellのset環境変数法
- 5ー4.Environ環境変数法
- 5ー5.APIのGetUserName関数法
- 5ー6.ExcelのUserNameプロパティ法
- 6.コンピューター名
- 6ー1.WshNetworkオブジェクト法
- 6ー2.WshShellのipconfig法
- 6ー3.Environ環境変数法
- 7.ドメイン名
- 7ー1.WshNetworkオブジェクト法
- 7ー2.Environ環境変数法
- 8.CPU名
- 8ー1.Environ環境変数法
- よりみち(CPUビット数の取得)
- 9.Excelバージョン
- 9ー1.Versionプロパティ法
- 10.O/Sバージョン
- 10ー1.OperatingSystemプロパティ法
- 10ー2.WMI法
- 10ー3.APIのGetVersionEx関数法
- 11.O/Sプロダクト番号
- 11ー1.WMI法
- 12.ハードディスク シリアル番号
- 12ー1.WMI法
- 13.まとめ
- アプリ実例
- サンプルファイル
アプリを操作しているユーザーやPCを特定するために、固有情報を取得する場面は多くあります。分かり易い例としては、ブラウザにURLを記入すればインターネット上のサイトが表示されますが、これは、要求する側の「PCのIPアドレス」をリクエストと一緒に送信しているためです。
Excelで作ったアプリでも似たような場面があります。例えばExcelで日報を作ってサーバーに保存するシステムの場合、日報作成者の名前をファイル名に添付しておかないと受け取った人は困ってしまいます。と言って、他人の名前で作成・保存できてしまっても困ります。
そのため「ユーザーやPCの固有情報」をVBAで取得し、ファイル名に付けたりする手法を用いる場合があります。もちろん完璧ではありませんが、ユーザーの面倒な作業を減らす事にはなっていると思います。
Excelでは、上記のIPアドレスやユーザー名だけでは無く、他にも色々な固有情報を取得できます。今回は、以下の10種類の情報の取得方法を紹介します。
|
|
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) API関数宣言 ============
- #If Win64 Then
- Private Declare PtrSafe Function GetUserName Lib "advapi32.dll" _
- Alias "GetUserNameA" (ByVal lpBuffer As String, nSize As LongPtr) As LongPtr
- Private Declare PtrSafe Function GetVersionEx Lib "kernel32" _
- Alias "GetVersionExA" (lpVersionInformation As OSVERSIONINFO) As LongPtr
- #Else
- Private Declare Function GetUserName Lib "advapi32.dll" _
- Alias "GetUserNameA" (ByVal lpBuffer As String, nSize As Long) As Long
- Private Declare Function GetVersionEx Lib "kernel32" _
- Alias "GetVersionExA" (lpVersionInformation As OSVERSIONINFO) As Long
- #End If
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関数法」で行います。
- '========== ⇩(2) 構造体宣言 ============
- Private Type OSVERSIONINFO
- dwOSVersionInfoSize As Long '構造体のバイト数
- dwMajorVersion As Long 'メジャー番号
- dwMinorVersion As Long 'マイナー番号
- dwBuildNumber As Long 'ビルド番号
- dwPlatformId As Long 'プラットフォームのID
- szCSDVersion As String * 128 'OSに関する付加情報
- End Type
2ー2ー2.情報取得と表示
シート上のボタンから呼び出されるのが、図06の4つのプロシージャです。4分割したのは説明の都合上の為だけです。- '========== ⇩(3) データ取得と表示1 ============
- Public Sub Info1()
- Dim s As String '←MsgBoxへの表示文字列
- s = "IP-1= " & IPaddress1
- s = s & vbNewLine & "IP-2= " & IPaddress2
- s = s & vbNewLine & "MAC-1= " & MACaddress1
- s = s & vbNewLine & "MAC-2= " & MACaddress2
- MsgBox s
- End Sub
- '========== ⇩(4) データ取得と表示2 ============
- Public Sub Info2()
- Dim s As String '←MsgBoxへの表示文字列
- s = "USER-1= " & USERname1
- s = s & vbNewLine & "USER-2= " & USERname2
- s = s & vbNewLine & "USER-3= " & USERname3
- s = s & vbNewLine & "USER-4= " & USERname4
- s = s & vbNewLine & "USER-5= " & USERname5
- s = s & vbNewLine & "USER-6= " & USERname6
- MsgBox s
- End Sub
- '========== ⇩(5) データ取得と表示3 ============
- Public Sub Info3()
- Dim s As String '←MsgBoxへの表示文字列
- s = "PC-1= " & PCname1
- s = s & vbNewLine & "PC-2= " & PCname2
- s = s & vbNewLine & "PC-3= " & PCname3
- s = s & vbNewLine & "Domain1= " & DOMAINname1
- s = s & vbNewLine & "Domain2= " & DOMAINname2
- MsgBox s
- End Sub
- '========== ⇩(6) データ取得と表示4 ============
- Public Sub Info4()
- Dim s As String '←MsgBoxへの表示文字列
- s = "CPU name1= " & CPUname1
- s = s & vbNewLine & "Excel ver= " & EXCELver1
- s = s & vbNewLine & "O/S ver1= " & OSver1
- s = s & vbNewLine & "O/S ver2= " & OSver2
- s = s & vbNewLine & "O/S ver3= " & OSver3
- s = s & vbNewLine & "O/S product= " & OSprod1
- s = s & vbNewLine & "HD= " & HDserial1
- MsgBox s
- End Sub
今回、固有情報を得る部分は関数プロシージャの形にしています。図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です。- '========== ⇩(7) IPアドレス(WMI法) ============
- Private Function IPaddress1() As String
- Dim ObjSet As Object 'ネットワークアダプタ情報のオブジェクト
- Dim ObjEx As Object '各ネットワークアダプタ情報
- Dim strIP As Variant 'IPアドレス(IPv4、IPv6)
- Set ObjSet = GetObject("winmgmts:¥¥.¥root¥cimv2"). _
- ExecQuery("SELECT * FROM Win32_NetworkAdapterConfiguration Where (IPEnabled = TRUE)")
- For Each ObjEx In ObjSet
- For Each strIP In ObjEx.IPaddress
- If UBound(Split(strIP, "."), 1) = 3 Then
- IPaddress1 = strIP
- Exit For
- End If
- Next strIP
- Next ObjEx
- Set ObjSet = Nothing
- End Function
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つのネットワークアダプタ情報が得られます。97行目「ExecQuery("SELECT * FROM Win32_NetworkAdapterConfiguration Where (IPEnabled = TRUE)")」では、そのWMIオブジェクトの「Win32_NetworkAdapterConfiguration」クラスの中から、有効(IPEnabled = TRUE)なネットワークアダプターの情報を取得し、変数ObjSetに代入します。この「IPEnabledプロパティ」は、下の図09のNo.28で、この値がTrueになっているアダプタが有効という事になります。
図08
得られたネットワークアダプタ(SWbemObjectExオブジェクト)には、図09のように多くのプロパティがあります。
No. | プロパティ | 内容 | 例 |
---|---|---|---|
1 | ArpAlways | ソースルーティング有のプロトコルで送信 | 既定=False |
2 | ArpUse | SNAPエンコードに従う | 既定=False |
3 | Caption | オブジェクトの簡単説明 | [00000001] |
4 | Database | インターネットDBファイルのパス | %SystemRoot% |
5 | DeadGWDetect | 配信不能ゲートウェイを検出 | True or False |
6 | DefaultIP | 既定ゲートウェイのIPアドレス | (配列) |
7 | DefaultTOS | 既定サービス種 | 0(既定)~255 |
8 | DefaultTTL | 既定TTL値 | 1~255 既定=32 |
9 | Description | オブジェクトの説明 | Intel(R) |
10 | DHCPEnabled | DHCP自動割り当て | True |
11 | DHCPLease | IPアドレスの有効期限 | 20230303100000 |
12 | DHCPLease | IPアドレス取得日時 | 2023030200000 |
13 | DHCPServer | DHCPのIPアドレス | 192.168.0.1 |
14 | DNSDomain | DNSドメイン | microsoft.com |
15 | DNSDomain | DNSドメインのサフィックス | (配列) 例=samples |
16 | DNSEnabled | WINS名前解決有効化 | False |
17 | DNSHostName | 識別ホスト名 | 例=corpdns |
18 | DNSServer | クエリで使用するサーバーのIPアドレス | (配列) |
19 | DomainDNS | IPアドレスをドメインに登録する | False |
20 | Forward | IPにより割り当てられたメモリ | 既定=74240 |
21 | FullDNS | IPアドレスをDNSに登録する | True |
22 | Gateway | 整数コストメトリック値 | (配列)1~9999の範囲 |
23 | IGMPLevel | マルチキャストをサポートし、IGMPに参加する範囲 | 0=No Multicast 2(既定)=IP & IGMP Multicast |
24 | Index | ネットワークアダプタのインデックス番号 | 1 |
25 | Interface | インターフェイスを識別するインデックス値 | 18 |
26 | IPAddress | 関連付けられているIPアドレス(IPv4,IPv6) | (配列) |
27 | IPConnection | ルートの重み付け値 | 既定=1 |
28 | IPEnabled | アダプタの有効化 | True |
29 | IPFilter | IPポートセキュリティの有効化 | False |
30 | IPPort | IPポートセキュリティの有効化 (今後使用されず) | Null |
31 | IPSecPermitIP | IP経由で実行可能なプロトコル | (配列) |
32 | IPSecPermitTCP | TCPのアクセスが許可されるポート | (配列) |
33 | IPSecPermitUDP | UDPのアクセスが許可されるポート | (配列) |
34 | IPSubnet | サブネットマスク | (配列)例=255.255.0.0 |
35 | IPUseZero | IPゼロブロードキャストを使用 | 既定=False |
36 | IPXAddress | (IPXサポートされず) | Null |
37 | IPXEnabled | (IPXサポートされず) | Null |
38 | IPXFrame | (IPXサポートされず) | Null |
39 | IPXMedia | (IPXサポートされず) | Null |
40 | IPXNetwork | (IPXサポートされず) | Null |
41 | IPXVirtual | (IPXサポートされず) | Null |
42 | KeepAlive | KeepAlive再送信を分離する間隔(ms) | 既定=1000 |
43 | KeepAlive | 接続維持を確認する頻度(ms) | 既定7,200,000(2時間) |
44 | MACAddress | MACアドレス | 例= 00:80:C7 |
45 | MTU | 最大転送単位(byte) | Null |
46 | NumForward | IPパケットヘッダー数 | 既定値: 50 |
47 | PMTUBHDetect | セグメント再送信の未確認時に送信する | 既定=False |
48 | PMTUDiscovery | 異なるMTUネットワークで断片化を排除 | 既定=True |
49 | ServiceName | アダプターのサービス名 | Elnkii |
50 | SettingID | オブジェクトの識別子 | {00000000 |
51 | TcpipNetbios | TCP/IP経由のNetBIOSの設定ビットマップ | 0=EnableNetbios 1=EnableNetbios 2=DisableNetbios |
52 | TcpMaxConnect | 要求再送信回数 | 既定値=3 |
53 | TcpMaxData | データセグメント再送信回数 | 既定値=5 |
54 | TcpNum | 同時接続最大数 | 既定値=0xFFFFFE |
55 | TcpUseRFC1122 | 緊急データにRFC1122仕様を使用 | Null |
56 | Tcp | TCP受信ウィンドウの最大サイズ | イーサネットの既定値8760 |
57 | WINS | ローカル参照ファイルを使用する | True |
58 | WINS | WINS参照ファイルへのパス | Null |
59 | WINS | プライマリWINSサーバーのIPアドレス | Null |
60 | WINS | NetBIOS名の末尾の値 | (なし) |
61 | WINS | セカンダリWINSサーバーのIPアドレス | Null |
なお図09についての詳細は、Microsoftのサイト「Win32_NetworkAdapterConfigurationクラス」を参照下さい。
またPCの環境によっては、存在しないプロパティもあると思われますので御注意願います。
IPアドレスにはIPv4とIPv6の2種類があり、現状ではIPv4で管理しているところも多いと思います。しかし、IPv6も表示されるようなPC設定になっていれば、図10のように「IPv4アドレス」と「IPv6アドレス」が「IPAddressプロパティ(図09のNo.26)」内に入っている事になります。
図10
なお、図11のように「IPv6を不使用」に設定にしているPCの場合は、IPv4のみの配列となります。
図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の表記の違いは以下の通りです。
種類 | データ数 | 表記 | 分岐コード(例) |
---|---|---|---|
IPv4 | 32ビット | XXX.XXX.XXX.XXX (XXXは0~255の10進数の数値) | UBound(Split(strIP, "."), 1) = 3 |
IPv6 | 128ビット | XXXX:XXXX:XXXX (Xは0~Fの16進数の数値) | InStr(strIP,":")>0 |
今回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アドレスを取得します。- '========== ⇩(8) IPアドレス(WshShellのipconfig法) ============
- Private Function IPaddress2() As String
- Dim wsh As Object 'WSH(Windows Script Host)shellオブジェクト
- Dim cmd As String '実行コマンド
- Dim result As Object 'コマンド実行結果(事前バインディングだとWshExec型)
- Dim rowArray As Variant '実行結果を各行ごとに配列にしたもの
- Dim i As Long 'カウンタ変数(実行結果の行位置)
- Dim Pos As Long '行の中でのIPアドレスの文字位置
- Set wsh = CreateObject("WScript.Shell")
- cmd = "ipconfig"
- Set result = wsh.exec("%ComSpec% /c " & cmd)
- Do While result.Status = 0
- DoEvents: DoEvents
- Loop
- rowArray = Split(result.StdOut.ReadAll, vbCrLf)
- For i = 0 To UBound(rowArray, 1)
- If InStr(rowArray(i), "IPv4") > 0 Then Exit For
- Next i
- Pos = InStr(rowArray(i), ":")
- IPaddress2 = Mid(rowArray(i), Pos + 2)
- Set result = Nothing
- Set wsh = Nothing
- End Function
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の値は架空のものに修正してあります。)
図14
132行目「Set result = wsh.exec("%ComSpec% /c " & cmd)」では、130行目で設定したipconfigコマンドを実行し、その結果を変数resultに代入します。
実行にはWSHのExecメソッドを使用し、その引数(カッコ内)に「"%ComSpec% /c " & cmd」を指定しています。これは図15のように3つの内容を示しています。
図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の右図のように複数のアダプタが接続状態の時は、最初に取得されるアダプタの情報しか入手できないことにも注意が必要です。もし複数のアダプタ情報を戻す場合には、配列戻し等の工夫が必要です。
図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です。- '========== ⇩(9) MACアドレス(WMI) ============
- Private Function MACaddress1() As String
- Dim Locator As Object 'SWbemLocatorオブジェクト
- Dim Service As Object 'SWbemServicesExオブジェクト
- Dim ObjSet As Object 'SWbemObjectSetオブジェクト
- Dim ObjEx As Object 'SWbemObjectExオブジェクト
- Set Locator = CreateObject("WbemScripting.SWbemLocator")
- Set Service = Locator.ConnectServer
- Set ObjSet = Service.ExecQuery("Select * From Win32_NetworkAdapterConfiguration Where (IPEnabled = TRUE)")
- For Each ObjEx In ObjSet
- MACaddress1 = ObjEx.MacAddress
- Next ObjEx
- Set ObjSet = Nothing
- Set Service = Nothing
- Set Locator = Nothing
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)")
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です。- '========== ⇩(10) MACアドレス(WshShellのgetmac法) ============
- Private Function MACaddress2()
- Dim wsh As Object 'WSH(Windows Script Host)shellオブジェクト
- Dim cmd As String '実行コマンド
- Dim result As Object 'コマンド実行結果
- Dim rowArray As Variant '実行結果を各行ごとに配列化したもの
- Set wsh = CreateObject("WScript.Shell")
- cmd = "getmac"
- Set result = wsh.exec("%ComSpec% /c " & cmd)
- Do While result.Status = 0
- DoEvents: DoEvents
- Loop
- rowArray = Split(result.StdOut.ReadAll, vbCrLf)
- MACaddress2 = Left(rowArray(3), 17)
- Set result = Nothing
- Set wsh = Nothing
- End Function
「図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行しか表示されません。
図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」を使うかの方法が良いと思います。
図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です。- '========== ⇩(11) ユーザー名(WshNetworkオブジェクト法) ============
- Private Function USERname1()
- Dim wsh As Object 'WSH(Windows Script Host)Networkオブジェクト
- Set wsh = CreateObject("WScript.Network")
- USERname1 = wsh.UserName
- Set wsh = Nothing
- End Function
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です。- '========== ⇩(12) ユーザー名(WshShellのEcho環境変数法) ============
- Private Function USERname2()
- Dim wsh As Object 'WshShellオブジェクト
- Dim cmd As String '実行コマンド
- Dim result As Object 'コマンド実行結果
- Dim rowArray As Variant '実行結果を各行ごとに配列化したもの
- Set wsh = CreateObject("WScript.Shell")
- cmd = "echo %USERNAME%"
- Set result = wsh.exec("%ComSpec% /c " & cmd)
- Do While result.Status = 0
- DoEvents: DoEvents
- Loop
- rowArray = Split(result.StdOut.ReadAll, vbCrLf)
- USERname2 = rowArray(0)
- Set result = Nothing
- Set wsh = Nothing
- End Function
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です。- '========== ⇩(13) ユーザー名(WshShellのset環境変数法) ============
- Private Function USERname3()
- Dim wsh As Object 'WshShellオブジェクト
- Dim cmd As String '実行コマンド
- Dim result As Object 'コマンド実行結果
- Dim rowArray As Variant '実行結果を各行ごとに配列化したもの
- Set wsh = CreateObject("WScript.Shell")
- cmd = "set USERNAME"
- Set result = wsh.exec("%ComSpec% /c " & cmd)
- Do While result.Status = 0
- DoEvents
- Loop
- rowArray = Split(result.StdOut.ReadAll, vbCrLf)
- PCname3 = Split(rowArray(0), "=")(1)
- Set wsh = Nothing
- Set result = Nothing
- End Function
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」の方が先に表示されます。
図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です。- '========== ⇩(14) ユーザー名(Environ環境変数法) ============
- Private Function USERname4()
- USERname4 = Environ("USERNAME")
- End Function
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」が必要です。- '========== ⇩(15) ユーザー名(GetUserName関数法) ============
- Private Function USERname5()
- Dim UN As String * 255
- Call GetUserName(UN, 255)
- USERname5 = WorksheetFunction.Trim(UN)
' USERname5 = Left(UN, InStr(UN, Chr(0)) - 1)- End Function
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)- '========== ⇩(16) ユーザー名(ExcelのUserNameプロパティ法) ============
- Private Function USERname6()
- USERname6 = Application.UserName
- End Function
312行目「USERname6 = Application.UserName」では、Applicationオブジェクト(=Excel)のUserNameプロパティでユーザー名を取得し、関数プロシージャの戻り値にしています。
但し、このExcelのUserNameプロパティで得られる名前は「Excelをインストール/ライセンス認証する際に入力したユーザー名」であり、今まで説明してきた様な「Windowsのログインユーザー名」ではありません。
ログイン名と同じ場合もあるでしょうが、基本的に異なるものですので注意が必要です。
6.コンピューター名
6ー1.WshNetworkオブジェクト法
WSH(Windows Script Host)のWshNetworkオブジェクトを使ってコンピューター名を取得するのが、図30です。- '========== ⇩(17) コンピューター名(WSH法) ============
- Private Function PCname1()
- Dim wsh As Object 'WSH(Windows Script Host)Networkオブジェクト
- Set wsh = CreateObject("WScript.Network")
- PCname1 = wsh.ComputerName
- Set wsh = Nothing
- End Function
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です。- '========== ⇩(18) コンピューター名(WshShellのipconfig法) ============
- Private Function PCname2()
- Dim wsh As Object 'WshShellオブジェクト
- Dim cmd As String '実行コマンド
- Dim result As Object 'コマンド実行結果
- Dim rowArray As Variant '実行結果を各行ごとに配列化したもの
- Dim i As Long 'カウンタ変数(実行結果の行位置)
- Dim Pos As Long '行の中でのコンピューター名の文字位置
- Set wsh = CreateObject("WScript.Shell")
- cmd = "ipconfig /all"
- Set result = wsh.exec("%ComSpec% /c " & cmd)
- Do While result.Status = 0
- DoEvents
- Loop
- rowArray = Split(result.StdOut.ReadAll, vbCrLf)
- For i = 0 To UBound(rowArray, 1)
- If InStr(rowArray(i), "ホスト名") > 0 Then Exit For
- Next i
- Pos = InStr(rowArray(i), ":")
- PCname2 = Mid(rowArray(i), Pos + 2)
- Set result = Nothing
- Set wsh = Nothing
- End Function
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のように得られます。長々と表示されますので後半を省略していますが、その先頭に「ホスト名」という内容でコンピュータ名が表示されます。
図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です。- '========== ⇩(19) ドメイン名(環境変数法) ============
- Private Function CPname3()
- CPname3 = Environ("COMPUTERNAME")
- End Function
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です。- '========== ⇩(20) ドメイン名(WSH法) ============
- Private Function DOMAINname1()
- Dim wsh As Object 'WSH(Windows Script Host)Networkオブジェクト
- Set wsh = CreateObject("WScript.Network")
- DOMAINname1 = wsh.UserDomain
- Set wsh = Nothing
- End Function
384行目「Set wsh = CreateObject("WScript.Network")」ではWshNetworkオブジェクトを生成しています。
WshNetworkオブジェクトのプロパティには、図22でも説明した通り、3つのプロパティがあります。
① ComputerName(コンピュータ名)
② UserDomain(ドメイン名)
③ UserName(ユーザー名)
ここでは②のUserDomainプロパティを使用して、385行目「PCname1 = wsh.UserDomain」でドメイン名を取得し、関数プロシージャの戻り値にしています。
7ー2.Environ環境変数法
Environ関数+環境変数でドメイン名を取得するのが、図35です。- '========== ⇩(21) ドメイン名(環境変数法) ============
- Private Function DOMAINname2()
- DOMAINname2 = Environ("USERDOMAIN")
- End Function
EnvironはWindowsの環境変数値を返す関数です。402行目「DOMAINname2 = Environ("USERDOMAIN")」では、引数に環境変数「USERDOMAIN」を指定することで「ドメイン名」を取得し、関数プロシージャの戻り値にしています。
尚、この他にも以下のように環境変数を使ってドメイン名を取得する方法があります。
・「echo %USERDOMAIN%」と、echoコマンドを実行し取得(図23を参照下さい)
・「set USERDOMAIN」と、setコマンドを実行し取得(図24を参照下さい)
8.CPU名
8ー1.Environ環境変数法
まず、CPUを表す環境変数は図36のように複数あります。環境変数 | 内容 | 例 |
---|---|---|
NUMBER_OF_PROCESSORS | CPUの論理コア数 | 8 |
PROCESSOR_ARCHITECTURE | アーキテクチャ | x86 |
PROCESSOR_ARCHITEW6432 *1 | アーキテクチャ | AMD64 |
PROCESSOR_IDENTIFIER | CPUの説明 | Intel64 Family 6 Model 30 Stepping 5, GenuineIntel |
PROCESSOR_LEVEL | CPUのモデル番号 | 6 |
PROCESSOR_REVISION | CPUのリビジョン番号 | 1e05 |
*1:図36の「PROCESSOR_ARCHITEW6432」について
CPUのアーキテクチャは本来、環境変数「PROCESSOR_ARCHITECTURE」に入るのですが、64bit版Windows上で WOW64 この「PROCESSOR_ARCHITECTURE」と「PROCESSOR_ARCHITEW6432」の組み合わせで、図37のように本来のCPUのビット数が分かります。
図37を言葉で言うと、「PROCESSOR_ARCHITEW6432」の値が64bit版(AMD64やIA64)の場合は「CPUは64bit」となり、また「PROCESSOR_ARCHITECTURE」の値が64bit版の場合も「CPUは64bit」となります。 それ以外の場合は「CPUは32bit」です。 |
図38では、図36の中の環境変数「PROCESSOR_IDENTIFIER」を使用して、CPU名を取得しています。
- '========== ⇩(22) CPU名(環境変数法1) ============
- Private Function CPUname1()
- CPUname1 = Environ("PROCESSOR_IDENTIFIER")
- End Function
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です。- '========== ⇩(23) Excelバージョン(Excelのプロパティ法) ============
- Private Function EXCELver1()
- EXCELver1 = Application.Version
- End Function
422行目「EXCELver1 = Application.Version」で、Application(この場合はExcel)オブジェクトのVersionプロパティの値(=Excelのバージョン)を取得し、関数プロシージャの戻り値にしています。
10.O/Sバージョン
10ー1.OperatingSystemプロパティ法
ApplicationオブジェクトのOperatingSystemプロパティを使用し、O/S(=Windows)のバージョンを取得するのが図40です。- '========== ⇩(24) O/Sのバージョン(Excelのプロパティ法) ============
- Private Function OSver1()
- OSver1 = Application.OperatingSystem
- End Function
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のように振られています。
|
|
10ー2.WMI法
WMI(Windows Management Instrumentation)で、O/Sのバージョンを取得するのが図42です。- '========== ⇩(25) O/Sのバージョン(WMI法) ============
- Private Function OSver2()
- Dim Locator As Object 'SWbemLocatorオブジェクト
- Dim Service As Object 'SWbemServicesExオブジェクト
- Dim ObjSet As Object 'SWbemObjectSetオブジェクト
- Dim ObjEx As Object 'SWbemObjectExオブジェクト
- Set Locator = CreateObject("WbemScripting.SWbemLocator")
- Set Service = Locator.ConnectServer
- Set ObjSet = Service.ExecQuery("Select * From Win32_OperatingSystem")
- For Each ObjEx In ObjSet
- OSver2 = ObjEx.Caption & "(" & ObjEx.OSArchitecture & ")" & ObjEx.Version
- Next
- Set ObjSet = Nothing
- Set Service = Nothing
- Set Locator = Nothing
- End Function
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. | プロパティ | 内容 | 例 |
---|---|---|---|
1 | BootDevice | 起動元ディスクドライブ | ¥Device |
2 | BuildNumber | O/Sビルド番号 | 22621 |
3 | BuildType | O/Sビルド種類 | Multiprocessor Free |
4 | Caption | O/S名称 | Microsoft Windows |
5 | CodeSet | コードページ値 | 932 |
6 | CountryCode | 国/地域のコード | 81 |
7 | Creation | 継承チェーンに表示されるクラス名 | Win32_Operating |
8 | CSCreation | 作成クラス名 | Win32_Computer |
9 | CSDVersion | サービスパック | Null |
10 | CSName | コンピュータ名 | [コンピュータ名] |
11 | Current | グリニッジ標準時に対するOffSet値 | 540 |
12 | DataExecution | データ実行防止が32bitアプリで機能 | True |
13 | DataExecution | バッファオーバーラン攻撃を防ぐ | True |
14 | DataExecution | データ実行防止をドライバに対して行う | True |
15 | DataExecution | データ実行防止設定 | 0=Always Off 2=オプトイン |
16 | Debug | デバッグバージョンのインストール | False |
17 | Description | O/Sの説明 | (なし) |
18 | Distributed | O/Sは複数ノードに分散 | False |
19 | EncryptionLevel | トランザクションの暗号レベル | 256 |
20 | Foreground | プロセスの優先度 | 0=無し |
21 | FreePhysical | 空き物理メモリ(KB) | 844920 |
22 | FreeSpaceIn | スワップアウトせずにマップできる量(KB) | 5481212 |
23 | FreeVirtual | 空き仮想メモリ(KB) | 1819680 |
24 | InstallDate | インストール日時 | 20221005150000 |
25 | Large | (廃止) | Null |
26 | LastBootUpTime | 最後に再起動した日時 | 20230215210000 |
27 | LocalDateTime | ローカル日時 | 20230228150000 |
28 | Locale | 言語識別子 | 0411 |
29 | Manufacturer | 製造元名 | Microsoft |
30 | MaxNumberOf | サポート可能プロセス数 | -1 |
31 | MaxProcess | 割り当て可能メモリ量(KB) | 137438953344 |
32 | MUILanguages | 多言語UI Pack | Array(ja-JP,en-US) |
33 | Name | O/Sインスタンス | Microsoft Windows |C:¥WINDOWS |¥Device |
34 | NumberOf | O/Sユーザーのライセンス数 | Null |
35 | NumberOf | 起動中プロセス数 | 257 |
36 | NumberOfUsers | ユーザーセッション数 | 2 |
37 | Operating | 在庫保管単位番号 | 101 |
38 | Organization | 登録済みユーザーの会社名 | Null |
39 | OSArchitecture | O/Sのアーキテクチャ | 64 ビット |
40 | OSLanguage | O/Sの言語バージョン | 1041(=日本語) |
41 | OSProduct | 追加製品 | 768 |
42 | OSType | O/Sの種類 | 18(=WinNT) |
43 | OtherType | O/Sバージョンの追加説明 (OSTypeがOther(値1)の時) | ー |
44 | PAEEnabled | 物理アドレス拡張有効 | ー |
45 | PlusProductID | (サポートせず) | Null |
46 | PlusVersion | (サポートせず) | Null |
47 | Portable | O/SがUSB起動か否か | False |
48 | Primary | プライマリO/Sか否か | True |
49 | ProductType | その他のシステム情報 | 1=ワークステーション |
50 | QuantumLength | 量子当りのクロックティック数 (サポートせず) | 0=不明 |
51 | QuantumType | 固定量子or可変長量子 (サポートせず) | 0=不明 |
52 | RegisteredUser | 登録ユーザ | [ユーザー名、メールアドレスなど] |
53 | SerialNumber | O/Sシリアル番号 | 10XXX-OEM |
54 | Service | Service Packのメジャーバージョン | 0(=Service Pack無) |
55 | Service | Service Packのマイナーバージョン | 0(=Service Pack無) |
56 | SizeStoredIn | ページングファイル可能サイズ(KB) | 5628828 |
57 | Status | オブジェクトの状態 | OK, Error, Degraded, Unknown ・・・等 |
58 | SuiteMask | 使用可能な製品識別フラグ | 784 |
59 | SystemDevice | O/Sの物理ディスクパーティション | ¥Device |
60 | SystemDirectory | O/Sのシステムディレクトリ | C:¥WINDOWS |
61 | SystemDrive | O/Sのディスクドライブ名 | C: |
62 | TotalSwap | スワップ領域の合計量(KB) | Null |
63 | TotalVirtual | 仮想メモリのサイズ(KB) | 13839256 |
64 | TotalVisible | 物理メモリのサイズ(KB) | 8210428 |
65 | Version | O/Sのバージョン | 10.0.22621 |
66 | Windows | Windowsディレクトリ | C:¥WINDOWS |
なお図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)」が必要です。
- '========== ⇩(26) O/Sのバージョン(API関数法) ============
- Function OSver3() As String
- Dim osvi As OSVERSIONINFO '図05で指定した構造体
- osvi.dwOSVersionInfoSize = Len(osvi) '構造体のサイズを指定
- If GetVersionEx(osvi) = 0 Then
- OSver3 = ""
- Else
- With osvi
- OSver3 = CStr(.dwMajorVersion) & "." & CStr(.dwMinorVersion) & "." & CStr(.dwBuildNumber)
- End With
- End If
- End Function
472行目「Dim osvi As OSVERSIONINFO」では、図05の構造体と同じデータ形の変数を宣言します。
このOSVERSIONINFO構造体の内容は、図45のようになります。
項目 | 内容 | 詳細 |
---|---|---|
dwOSVersionInfoSize | 構造体のバイト数 | 値=148 |
dwMajorVersion | メジャー番号 | バージョン番号の整数部 |
dwMinorVersion | マイナー番号 | バージョン番号の小数部 |
dwBuildNumber | ビルド番号 | O/Sのビルド番号(Me以前は +バージョン番号) |
dwPlatformId | プラットフォームのID | 値=2(Win9xは1、Win3.1は0) |
szCSDVersion | O/Sに関する付加情報 | サービスパック情報、追加バージョン情報 |
なお、例えば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です。- '========== ⇩(27) O/Sプロダクト番号(WMI法) ============
- Private Function OSprod1()
- Dim Locator As Object 'SWbemLocatorオブジェクト
- Dim Service As Object 'SWbemServicesExオブジェクト
- Dim ObjSet As Object 'SWbemObjectSetオブジェクト
- Dim ObjEx As Object 'SWbemObjectExオブジェクト
- Set Locator = CreateObject("WbemScripting.SWbemLocator")
- Set Service = Locator.ConnectServer
- Set ObjSet = Service.ExecQuery("Select * From Win32_OperatingSystem")
- For Each ObjEx In ObjSet
- OSprod1 = ObjEx.SerialNumber
- Next
- Set ObjSet = Nothing
- Set Service = Nothing
- Set Locator = Nothing
- End Function
このコードは、図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です。- '========== ⇩(28) ハードディスク シリアル番号(WMI法) ============
- Public Function HDserial1()
- Dim Locator As Object 'SWbemLocatorオブジェクト
- Dim Service As Object 'SWbemServicesExオブジェクト
- Dim ObjSet As Object 'SWbemObjectSetオブジェクト
- Dim ObjEx As Object 'SWbemObjectExオブジェクト
- Set Locator = CreateObject("WbemScripting.SWbemLocator")
- Set Service = Locator.ConnectServer
- Set ObjSet = Service.ExecQuery("Select * From Win32_DiskDrive")
- For Each ObjEx In ObjSet
- If ObjEx.MediaType <> "Removable Media" Then
- HDserial1 = Trim(ObjEx.Caption) & "(" & Trim(ObjEx.SerialNumber) & ")"
- Exit For
- End If
- Next
- Set ObjSet = Nothing
- Set Service = Nothing
- Set Locator = Nothing
- End Function
このコードは、図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. | プロパティ | 内容 | 例 |
---|---|---|---|
1 | Availability | デバイスの可用性と状態 | 1~21の番号,又はNull |
2 | BytesPerSector | 各セクタのバイト数 | 512 |
3 | Capabilities | メディアアクセスデバイスの機能 | (0~12の番号の配列) 3=ランダムアクセス |
4 | Capability | アクセスデバイスの詳細説明 | (配列) |
5 | Caption | オブジェクトの簡易説明 | KBG40ZNS128G |
6 | Compression | 圧縮アルゴリズム | Null 等 |
7 | Config | エラーコード | 0(=正常動作) |
8 | Config | ユーザ定義の構成を使用 | False(=使用せず) |
9 | Creation | 具象クラスの名前 | Win32_DiskDrive |
10 | Default | 既定ブロックサイズ(byte) | Null |
11 | Description | オブジェクトの説明 | ディスク ドライブ |
12 | DeviceID | ディスクドライブの一意識別子 | \\.\PHYSICALDRIVE0 |
13 | Error | エラーがクリアされた | Null |
14 | Error | エラーの詳細 | Null |
15 | Error | エラー検出,修正の種類 | Null |
16 | Firmware | ファームウェアのリビジョン | AEMS0000 |
17 | Index | 物理ドライブ番号 | 0 |
18 | Install | インストール日 | Null |
19 | Interface | インターフェイスの種類 | SCSI |
20 | LastError | 最後のエラーコード | Null |
21 | Manufacturer | ドライブ製造元名 | (標準ディスク ドライブ) |
22 | Max | 最大ブロックサイズ(byte) | Null |
23 | Max | サポートされる最大メディアサイズ(KB) | Null |
24 | MediaLoaded | 読み取り可能なFile Systemが有る | True(=固定ディスクは常にTrue) |
25 | MediaType | メディアの種類 | External hard disk media(外部HD) Removable media(リムーバブル) Fixed hard disk media(固定HD) Unknown(不明) |
26 | Min | 最小ブロックサイズ(byte) | Null |
27 | Model | 製造元のモデル番号 | STXXXX1W |
28 | Name | オブジェクトが識別されるラベル | ¥¥.¥PHYSICALDRIVE0 |
29 | Needs | デバイスのクリーニング必要性 | Null |
30 | NumberOf | 挿入可能なメディア最大数 | Null |
31 | Partitions | 物理ドライブのパーティション数 | 3 |
32 | PNPDeviceID | Plug & Playしているデバイス | SCSI\DISK |
33 | Power | 論理デバイスの電源関連機能 | 0~7 又は Null 2=Disabled 3=Enabled 等 |
34 | Power | 中断モード等の電源管理可 | Null |
35 | SCSIBus | SCSIバス番号 | 0 |
36 | SCSILogical | SCSI論理ユニット番号 | 0 |
37 | SCSIPort | SCSIポート番号 | 0 |
38 | SCSITargetId | SCSI識別子番号 | 0 |
39 | SectorsPer | 各トラックのセクター数 | 63 |
40 | SerialNumber | 製造元割り当て番号 | WD-WMxxxxxxxxxx |
41 | Signature | ディスクID | Null |
42 | Size | ドライブサイズ(シリンダ合計数) | 128034708480 |
43 | Status | オブジェクトの状態 | OK ,Error ,Degraded ,・・・他 |
44 | StatusInfo | 論理デバイスの状態 | 1~5 又はNull |
45 | System | スコープシステムの作成クラス名 | Win32 |
46 | SystemName | スコープシステムの名前 | [名前] |
47 | Total | 物理ドライブのシリンダー合計数 | 15566 |
48 | TotalHeads | ドライブのヘッドの合計数 | 255 |
49 | TotalSectors | 物理ドライブのセクター合計数 | 250067790 |
50 | TotalTracks | 物理ドライブのトラック合計数 | 3969330 |
51 | TracksPer | 物理ドライブの各シリンダー内のトラック数 | 255 |
なお図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のようにマトリクスにしました。WMI | Wsh | WshShell | En 環境変数 | Appli プロパティ | API | ||||
---|---|---|---|---|---|---|---|---|---|
Ip | Get | Echo | 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 |
今回、固有情報を得られる事を確認したところは「黄色背景」にしましたが、手法はもちろんの事、得られる固有情報も網羅できたとは思っていません。この表の中でも更に塗りつぶせるところもあるでしょうし、この表から外れたところで得られる情報・手法もあると思います。
表中の「Excelプロダクト番号」は、今回は情報取得の方法が見つかりませんでした。古いバージョンでは取得できた様で、色々なサイトで手法が紹介されていましたが、新しいバージョン(2016以降で確認)では不可でした。
他の項目は現在は情報が取得できますが、Excelプロダクト番号と同様に未来永劫取得できるかは分かりません。新バージョンが出てきたら、今まで使ってきた手法で取得可能かを確認する必要があると思います。
なお、Application(=Excel)オブジェクトのUserNameプロパティで得られる名前(ピンク色背景)は、他のWindowsのユーザー名とは異なるものですので御注意下さい。
アプリ実例
「アンケートの回収と集計方法」「ExcelシートDBを使った会議室予約システム」
「セル変更履歴をコメントに残す」
サンプルファイル
PCの固有情報の取得(its-029.xlsm)
セキュリティ向上を目的として「インターネット経由でダウンロードしたOfficeファイル(Excel等)のマクロは、既定でブロック」されるようにOfficeアプリケーションの既定動作が変更になりました。(2022年4月より切替開始) 解除の方法については「ダウンロードファイルのブロック解除方法」を参照下さい。 |