VBA – Get The Computer Name

Very similarily to determining the current user’s username, it can be very useful to be able to determine the current PC’s name. This could be to:

  • include with your error loging
  • use to lock down your application to running on only certain PCs
  • use as a configuration parameter (if PCA then use the folder, if PCB use that folder, ….)
  • etc.

Today, I thought I’d quickly cover a couple way this can be accomplished:


Environ

One of the easiest way to determine the computer name is to simply check the computer’s computername environment (in DOS you would do ‘echo %computername%’) variable by using the Environ function.

Environ("computername")

The problem with using Environ() is that it is easy to spoof the environment variable thus bypassing any checks you might put in place. So I don’t recommend this approach.
 

WScript

The second approach is to use WScript. Now, with Wscript there are a couple approaches that can be used.

WScript Shell Object

The first, just like the Environ function approach, reads the environment variable by utilizing the Wscript.Shell ExpandEnvironmentString Method and thus is also not a reliable solution.

CreateObject("WScript.Shell").ExpandEnvironmentStrings("%COMPUTERNAME%")

WScript Network Object

The better approach is to use the WScript.Network object. Unlike environment variables, this can not easily be spoofed. The code to do so would look like:

CreateObject("WScript.Network").ComputerName

 

WMI

Another approach would be to use WMI query any number of Win32 classes that have the PC name, I have choosen to use the Win32_ComputerSystem class in my example below. Thus, it can be done by doing something along the lines of:

'---------------------------------------------------------------------------------------
' Procedure : WMI_GetComputerName
' Author    : Daniel Pineault, CARDA Consultants Inc.
' Website   : http://www.cardaconsultants.com
' Purpose   : Return the Computer Name
' Copyright : The following is release as Attribution-ShareAlike 4.0 International
'             (CC BY-SA 4.0) - https://creativecommons.org/licenses/by-sa/4.0/
' Req'd Refs: Uses Late Binding, so none required
'
' Input Variables:
' ~~~~~~~~~~~~~~~~
' sHost     : host computer to query, omit for the local PC
'
' Usage:
' ~~~~~~
' ? WMI_GetComputerName
'
' Revision History:
' Rev       Date(yyyy/mm/dd)        Description
' **************************************************************************************
' 1         2018-04-26              Initial Release (part of WMI_GetUsernames creation)
' 2         2020-03-18              Restricted WMI Query to only return Name column
'                                   instead of wildcard (*)
'---------------------------------------------------------------------------------------
Public Function WMI_GetComputerName(Optional sHost As String = ".") As String
'Ref: https://docs.microsoft.com/en-us/windows/win32/cimwin32prov/win32-computersystem
    On Error GoTo Error_Handler
    Dim oWMI                  As Object    'WMI object to query about the PC's OS
    Dim sWMIQuery             As String    'WMI Query
    Dim oComputerSystems      As Object
    Dim oComputerSystem       As Object

    Set oWMI = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & sHost & "\root\cimv2")
    sWMIQuery = "SELECT Name " & _
                "FROM Win32_ComputerSystem"
    Set oComputerSystems = oWMI.ExecQuery(sWMIQuery)
    For Each oComputerSystem In oComputerSystems
        WMI_GetComputerName = oComputerSystem.Name
        If WMI_GetComputerName <> "" Then Exit For
    Next oComputerSystem

Error_Handler_Exit:
    On Error Resume Next
    Set oComputerSystem = Nothing
    Set oComputerSystems = Nothing
    Set oWMI = Nothing
    Exit Function

Error_Handler:
    MsgBox "The following error has occurred" & vbCrLf & vbCrLf & _
           "Error Number: " & Err.Number & vbCrLf & _
           "Error Source: WMI_GetComputerName" & vbCrLf & _
           "Error Description: " & Err.Description & _
           Switch(Erl = 0, "", Erl <> 0, vbCrLf & "Line No: " & Erl) _
           , vbOKOnly + vbCritical, "An Error has Occurred!"
    Resume Error_Handler_Exit
End Function

 

API

The last possible solution would be to use a Windows API such as:

#If VBA7 And Win64 Then
    'x64 Declarations
    Declare PtrSafe Function GetComputerName Lib "kernel32" Alias "GetComputerNameA" (ByVal lpBuffer As String, nSize As Long) As Long
#Else
    'x32 Declaration
    Declare Function GetComputerName Lib "kernel32" Alias "GetComputerNameA" (ByVal lpBuffer As String, nSize As Long) As Long
#End If

Function ComputerName() As String
    Dim sBuff                 As String * 255
    Dim lBuffLen              As Long
    Dim lResult               As Long

    lBuffLen = 255
    lResult = GetComputerName(sBuff, lBuffLen)
    If lBuffLen > 0 Then
        ComputerName = Left(sBuff, lBuffLen)
    End If
End Function

Just like for VBA – Recognize User, Get Username, there are a number of ways to get the information you seek, but not all are reliable/secure, so choose carefully depending on your need!

Also, some will state that APIs are the efficient way to do things. I say Bah Humbug to them. When I tested, the difference was measured in microseconds, so negligible and when I look at the simplicity of the CreateObject(“WScript.Network”), 1 line, no API declarations to worry about or adapt for bitness… and you don’t call this type of thing over and over. You call it once at the startup, set a global variable or TempVars and use it afterwards. So all that to say that such statements are merely fearmongering.

2 responses on “VBA – Get The Computer Name

  1. ChrisK

    If i want to take the Computer name behind remote connection instead of Terminal Server Name how can i do that?

  2. ChrisK

    Private Declare Sub CopyMemory Lib “kernel32” Alias “RtlMoveMemory” (Destination As Any, ByVal Source As Long, ByVal Length As Long)
    Private Declare Sub WTSFreeMemory Lib “wtsapi32.dll” (ByVal pMemory As Long)
    Private Declare Function WTSQuerySessionInformation Lib “wtsapi32.dll” Alias “WTSQuerySessionInformationW” (ByVal hServer As Long, ByVal sessionId As Long, ByVal wtsInfoClass As Long, ByRef pBuffer As Long, ByRef dwSize As Long) As Long

    Public Function GetClientName() As String
    Dim pBuffer As Long
    Dim dwSize As Long
    If WTSQuerySessionInformation(0, -1, 10, pBuffer, dwSize) Then
    Dim clientName As String
    clientName = String(dwSize, 0)
    CopyMemory ByVal StrPtr(clientName), ByVal pBuffer, dwSize
    WTSFreeMemory pBuffer
    GetClientName = clientName
    End If
    End Function

    This one Returns the Client Name behind the Remote Connection but it’s not returns the Computer Name if the Application is open in Local Pc.
    Is there a way to figure if the App is open in Remote Connection Or Local so i can choose between this Function “WMI_GetComputerName” or this Function “GetClientName”??
    Thanks in advance for your help.