带有 HTA 和类型不匹配错误的 VBScript 奇怪问题

VBScript Strange Issue with HTA and Type mismatch error

当我 运行 通过双击单独运行以下脚本时,它工作正常。它 returns 是预期的最后登录用户。但是当我从 HTA 运行 它作为我所有脚本的前端开发时,我在 "wscript.echo strvalue" 行上收到类型不匹配错误。我已尽一切努力使其正常工作,例如更改 mshta.exe 的权限以完全控制我自己。我根本无法在不出错的情况下从 HTA 将其发送到 运行,但它本身可以按预期 100% 工作。我完全被难住了。

strinput = "myserver"
Set objRegistry = GetObject("winmgmts:{impersonationLevel=impersonate}!\" & _ 
strinput & "\root\default:StdRegProv")
 strKeyPath = "SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\LogonUI"
strValueName = "LastLoggedOnUser"
 objRegistry.GetStringValue HKEY_LOCAL_MACHINE, strKeyPath, strValueName, strValue
 Wscript.Echo strValue

使用Msgbox function instead of Wscript.Echo method. HTAs use the Internet Explorer Scripting Object Model which does not contain Wscript object (this belongs to Windows Script Host Object Model)。

阅读HTA: Why Can’t I Use Wscript.Echo?:

You might have noticed that when it came time to report back the operating system version we used the VBScript Msgbox function rather than the more common Wscript.Echo. Why didn’t we use Wscript.Echo? Here’s why:

As it turns out the various Wscript methods - Wscript.Echo, Wscript.Sleep, Wscript.Quit, etc. - are designed solely to run under the Windows Script Host environment. When we’re working in an HTA we’re not running under WSH; instead we’re running under the MSHTA process. Because of that the Wscript methods are not available to us (nor can we create them). Consequently we need to find workarounds for each method, and Msgbox is a perfectly adequate replacement for Wscript.Echo. (We’ll talk about workarounds for other methods - such as Wscript.Sleep - when we get to them.)

The moral of the story: Don’t bother with Wscript.Echo; it won’t work.

编辑:与Wscript.Echo TypeName(strValue) & vbNewLine & VarType(strValue):

==> C:\Windows\System32\cscript.exe D:\VB_scripts\SO505295.vbs
String
8

==> C:\Windows\SysWOW64\cscript.exe D:\VB_scripts\SO505295.vbs
Null
1

尝试了一个简单的 HTA,结果相同(不同)

==> C:\Windows\System32\mshta.exe 33505295.hta

对比

==> C:\Windows\SysWOW64\mshta.exe 33505295.hta

结论。检查 HTA 文件类型关联。例如,ftype htafile 在我的 Windows 8(64 位)returns(令人惊讶的是?)导致双击错误行为的相同值:

==> assoc .hta
.hta=htafile

==> ftype htafile
htafile=C:\Windows\SysWOW64\mshta.exe "%1" {1E460BD7-F1C3-4B2E-88BF-4E770A288AF5}%U{1E460BD7-F1C3-4B2E-88BF-4E770A288AF5} %*    

默认情况下,Windows 64 位使用 MSHTA.EXE 32 位。注册表对 64 位和 32 位应用程序有单独的分支,因此 WMI 无法找到您要查找的注册表值。 将下面的代码保存到e。 G。 C:\test\tmp.hta,尝试通过双击从资源管理器启动它(默认为 32 位)- 你会得到 null,然后通过 运行 对话框启动(Win +R) 路径:%windir%\system32\mshta.exe "C:\test\tmp.hta"(64 位),结果将是您的用户名。

<html>
    <head>
        <script language="vbscript">
            Sub window_onload()
                Const HKEY_LOCAL_MACHINE = &H80000002 
                Set objRegistry = GetObject("winmgmts:{impersonationLevel=impersonate}!\.\root\default:StdRegProv")
                strKeyPath = "SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\LogonUI"
                strValueName = "LastLoggedOnUser"
                objRegistry.GetStringValue HKEY_LOCAL_MACHINE, strKeyPath, strValueName, strValue
                document.body.innerText = strValue
            End Sub
        </script>
    </head>
    <body>
    </body>
</html>

请注意,脚本中的许多其他内容取决于应用程序架构,例如。 G。许多 ActiveX 仅在 32 位版本中可用,因此应通过 %windir%\SysWOW64\ 启动它们(Windows 32 位在 Windows 64 位子系统上)。

几周前我遇到了同样的挑战。 下面的代码让我可以查看谁当前登录到远程计算机。

希望对您有所帮助

Sub ActionGetCurrentUser(strCPU) 'strCPU is the computername
set objWMI = GetObject("winmgmts:{impersonationLevel=impersonate}!\" & strCPU & "\root\cimv2")
    set Items = objWMI.ExecQuery("Select * From Win32_ComputerSystem")

    For Each obj in Items
        OutStr = right(obj.username,9)
    Next

    Resultstring = "Logged in User is: " & OutStr   

    Set objRootDSE = GetObject("LDAP://RootDSE")
    strDNSDomain = objRootDSE.Get("defaultNamingContext")
    strTarget = "LDAP://" & strDNSDomain
' ---------------- Write the User's account & password to a variable -------------------
    strCurrentuser = Currentuser.value
    strPassword = PasswordArea.value
' ---------------- Connect to Ad Provider ----------------
    Set objConnection = CreateObject("ADODB.Connection")
    objConnection.Provider = "ADsDSOObject"
    objConnection.Properties("User ID") = strCurrentUser     ' pass credentials - if you omit this, the search is performed....
    objConnection.Properties("Password") = strPassword       ' ... with the current credentials
    objConnection.Properties("Encrypt Password") = True      ' only needed if you set "User ID" and "Password"
    objConnection.Open "Active Directory Provider"
    Set objCmd =   CreateObject("ADODB.Command")
    Set objCmd.ActiveConnection = objConnection 

    objCmd.CommandText = "SELECT DisplayName FROM '" & strTarget & "' WHERE extensionAttribute11 = '" & OutStr & "'"    

    Const ADS_SCOPE_SUBTREE = 2
    objCmd.Properties("Page Size") = 100
    objCmd.Properties("Timeout") = 30
    objCmd.Properties("Searchscope") = ADS_SCOPE_SUBTREE
    objCmd.Properties("Cache Results") = False

    Set objRecordSet = objCmd.Execute

    If objRecordset.Recordcount = 0 then    ' If no user is found then the recordcount will be 0
        msgbox "No user is logged on"
        Resultstring = ""
        Set objCmd = Nothing
        Set objRootDSE = Nothing
        Set objRecordSet = Nothing
        Set objWMI = Nothing
        Set Items = Nothing
        exit sub
    End if

    Set objRecordSet = objCmd.Execute

    objRecordSet.MoveFirst

    Resultstring = Resultstring & vbcrlf & "Name: " & objRecordset.fields("DisplayName")        

    Msgbox Resultstring

    Resultstring = ""

    Set objCmd = Nothing
    Set objRootDSE = Nothing
    Set objRecordSet = Nothing
    Set objWMI = Nothing
    Set Items = Nothing
End Sub