Small VBScript Does Not Work in HTA - vbscript

I'm using the following VBSript and it works fine, however when I a attempt to add it to a .hta app I've created, it does not function correctly.
Firstly, the 'strValue' does not show in the MsgBox and secondly script errors appear such as "Type mismatch: 'fso.FolderExists'"
Any help would be greatly appreciated as I've been struggling to figure this out.
sub LyncFix
dim oReg, strKeyPath, strValueName, strValue, oWS, userProfile
Const HKEY_LOCAL_MACHINE = &H80000002
Set oReg=GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & _
strComputer & "\root\default:StdRegProv")
strKeyPath = "SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Components\C7376A18AE70EB645A6EA7E5F5CE44F9"
strValueName = "71B0EB18B3654D541B8975126E6C56DC"
oReg.GetStringValue HKEY_LOCAL_MACHINE,strKeyPath,strValueName,strValue
MsgBox "Folder required to resolve Lync Install prompt: " & strValue
Dim fso
Dim Folder
Set fso = CreateObject("Scripting.FileSystemObject")
If (fso.FolderExists(strValue)) Then
MsgBox("The folder '" + strValue + "' already exists")
end If
If NOT (fso.FolderExists(strValue)) Then
' Delete this if you don't want the MsgBox to show
MsgBox("Local folder doesn't exist, creating...")
' Create folder
MsgBox("'" + strValue + "'" + " created")
fso.CreateFolder(strValue)
MsgBox("Please now try launching Lync again")
End If
end sub

Two side-notes only:
querying HTML with GetStringValue method gives different results for different Windows Script Host executable versions (32 bit vs. 64 bit as manifested in next example);
CreateFolder method might require elevated privileges.
Example: with strComputer = "." and next amendment
'
oReg.GetStringValue HKEY_LOCAL_MACHINE,strKeyPath,strValueName,strValue
' the amendment in 29026643.vbs as follows:
Wscript.Echo VarType(strValue) & vbTab & TypeName(strValue)
'
I have got next output on Windows 8, 64 bit:
==>%windir%\sysWOW64\cscript.exe D:\VB_scripts\SO\29026643.vbs
1 Null
==>%windir%\system32\cscript.exe D:\VB_scripts\SO\29026643.vbs
8 String
==>
Analogous output (with windowed echo) with different versions of wscript.exe.
Analogous output with sub LyncFix defined and used in a basic hta (with msgbox instead of Wscript.Echo) and with different versions of mshta.exe as follows:
==>%winDir%\sysWOW64\mshta.exe D:\VB_scripts\SO\29026643.hta
==>%winDir%\system32\mshta.exe D:\VB_scripts\SO\29026643.hta

Related

800A0408, 800A0400 errors [duplicate]

I am trying to create a registry key and subkey for enabling IE 11 enterprise mode for all users on a machine. This is what I am using for my VBScript currently and it is failing horribly (does not add the key). I could use some assistance in getting this corrected.
Const HKEY_LOCAL_MACHINE = &H80000002
strComputer = "."
Set ObjRegistry = _
GetObject("winmgmts:{impersonationLevel = impersonate}! \\" & _
strComputer & "\root\default:StdRegProv")
strPath = strKeyPath & "\" & strSubPath
strKeyPath = "Software\Policies\Microsoft"
strSubPath = "Internet Explorer\Main\EnterpriseMode"
strName = "Enabled"
ObjRegistry.CreateKey (HKEY_LOCAL_MACHINE, strPath)
ObjRegistry.SetStringValue HKEY_LOCAL_MACHINE, strPath, strName, strValue
MsgBox "Successfully enabled Internet Explorer Enterprise Mode."
End Function
There are several issues with your code, aside from the fact that you posted an incomplete code sample.
"winmgmts:{impersonationLevel = impersonate}! \\" & strComputer & "\root\default:StdRegProv"
The WMI moniker contains a spurious space between security settings and path (...! \\...). Remove it.
As a side note, it's pointless to use a variable for the hostname if that hostname never changes.
strPath = strKeyPath & "\" & strSubPath
You define strPath before you define the variables you build the path from. Also, your path components are defined as string literals, so you could drop the concatenation and the additional variables and simply define strPath as a string literal.
ObjRegistry.CreateKey (HKEY_LOCAL_MACHINE, strPath)
You must not put argument lists in parentheses unless you're calling the function/method/procedure in a subexpression context. See here for more details. However, you may want to check the return value of your method calls to see if they were successful.
And FTR, hungarian notation is pointless code bloat. Don't use it.
Modified code:
Function SetEnterpriseMode(value)
Const HKLM = &h80000002
Set reg = GetObject("winmgmts:{impersonationLevel=impersonate}!//./root/default:StdRegProv")
path = "Software\Policies\Microsoft\Internet Explorer\Main\EnterpriseMode"
name = "Enabled"
rc = reg.CreateKey(HKLM, path)
If rc <> 0 Then
MsgBox "Cannot create key (" & rc & ")."
Exit Function
End If
rc = reg.SetStringValue(HKLM, path, name, value)
If rc = 0 Then
MsgBox "Successfully enabled Internet Explorer Enterprise Mode."
Else
MsgBox "Cannot set value (" & rc & ")."
End If
End Function

VBScript - need to query on two different paths for getting the list of installed program

i am kinda newbie for vbscript. i am working to get the list of all programs using vbscript through registry. My problem is I want to search on two paths which is "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\" and "SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\" then compile it to one CSV.
Here is my code:
const HKEY_LOCAL_MACHINE = &H80000002
Dim strComputer, strKeyPath,strKeyPath2
strComputer = "."
Sub Check_Installed(strKeyPath)
Dim objReg, strSubkey, arrSubkeys
Set objReg=GetObject( _
"winmgmts:{impersonationLevel=impersonate}!\\" & _
strComputer & "\root\default:StdRegProv")
objReg.EnumKey HKEY_LOCAL_MACHINE, strKeyPath, arrSubkeys
Dim objFSO, objCSVFile
Const ForWriting = 2
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objCSVFile = objFSO.CreateTextFile("Installed-Softwares_final.csv", _
ForWriting, True)
Dim Name,Version,Publisher,Location,Size
For Each strSubkey In arrSubkeys
objReg.GetStringValue HKEY_LOCAL_MACHINE, strKeyPath & strSubkey, "DisplayName" , Name
If Name <> "" Then
objReg.GetStringValue HKEY_LOCAL_MACHINE, strKeyPath & strSubkey, "DisplayVersion", Version
objReg.GetStringValue HKEY_LOCAL_MACHINE, strKeyPath & strSubkey, "Publisher",Publisher
objReg.GetDWORDValue HKEY_LOCAL_MACHINE, strKeyPath & strSubkey, "EstimatedSize" , Size
If Size <> "" Then
Size= Round(Size/1024, 3) & " MB"
Else
Size= "0 MB"
End If
objCSVFile.Write Name &","&Version&","&Publisher&","&Size
objCSVFile.Writeline ' New Line
End If
Next
End Sub
strKeyPath = "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\"
strKeyPath2 = "SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\"
Check_Installed(strKeyPath)
Check_Installed(strKeyPath2)
WScript.Echo "Installed Softwares exported successfully into CSV file through Registry using VBScript."
WScript.Quit
This is my standard answer. Use /format:csv for CSV output.
Start - All Programs - Accessories - Right click Command Prompt and choose Run As Administrator. Type (or copy and paste by right clicking in the Command Prompt window and choosing Paste). Type for table format
wmic /output:"%userprofile%\desktop\WindowsInstaller.html" product get /format:htable
or in a form format
wmic /output:"%userprofile%\desktop\WindowsInstaller.html" product get /format:hform
It will create a html file on the desktop.
Note
This is not a full list. This is only products installed with Windows Installer. There is no feature for everything.
However as I said in my previous post nearly everything is listed in the registry.
So to see it in a command prompt
reg query HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall /s
or in a file
reg query HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall /s>"%userprofile%\desktop\WindowsUninstall.txt"
To see it in notepad in a different format
Click Start - All Programs - Accessories - Right click Command Prompt and choose Run As Administrator. Type Regedit and navigate to
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall
Right click the Uninstall key and choose Export. If you save as a reg file (there is also text file, they are slightly different text formats) you need to right click the file and choose Edit to view it.
To view Windows Updates
wmic /output:"%userprofile%\desktop\WindowsUpdate.html" qfe get /format:htable
The same in VBS is (which means the best way is batch).
Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
Set colItems = objWMIService.ExecQuery("Select * From Win32_Product")
For Each objItem in colItems
msgbox objItem.Name & " " & objItem.Version
Next

VBScript Strange Issue with HTA and Type mismatch error

When I run the following script on it's own by double clicking, it works just fine. It returns the last logged on user as expected. But when I run it from the HTA I have been developing as a front end to all of my scripts, I get a type mismatch error on the "wscript.echo strvalue" line. I have tried everything to get it to work, like changing permissions on mshta.exe to full control for myself. I simply can't get it to run from the HTA without getting an error, but it works 100% as expected on its own. I am completely stumped.
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
By default, Windows 64-bit uses MSHTA.EXE 32-bit. The registry has a separate branches for 64-bit and 32-bit apps, thus WMI can't find the registry value you are looking for.
Save the code below to e. g. C:\test\tmp.hta, try to launch it from explorer by double-click (32-bit by default) - you will get null, and then launch via Run dialog (Win+R) with path: %windir%\system32\mshta.exe "C:\test\tmp.hta" (64-bit), the result will be your username.
<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>
Note that many other stuff within scripts depends on application architecture, e. g. number of ActiveX are available only in 32-bit version, so they should be launched via %windir%\SysWOW64\ (Windows 32-bit on Windows 64-bit subsystem).
Use 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).
Read 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.
Edit: with Wscript.Echo TypeName(strValue) & vbNewLine & VarType(strValue):
==> C:\Windows\System32\cscript.exe D:\VB_scripts\SO\33505295.vbs
String
8
==> C:\Windows\SysWOW64\cscript.exe D:\VB_scripts\SO\33505295.vbs
Null
1
Tried in a simple HTA which gives the same (different) result
==> C:\Windows\System32\mshta.exe 33505295.hta
versus
==> C:\Windows\SysWOW64\mshta.exe 33505295.hta
Conclusion. Check HTA file type association. For instance, ftype htafile in my Windows 8 (64bit) returns (surprisingly?) the same value which causes wrong behaviour on double click:
==> assoc .hta
.hta=htafile
==> ftype htafile
htafile=C:\Windows\SysWOW64\mshta.exe "%1" {1E460BD7-F1C3-4B2E-88BF-4E770A288AF5}%U{1E460BD7-F1C3-4B2E-88BF-4E770A288AF5} %*
I have had the same challenge a few weeks ago.
The following code provided me the possibility to see who is currently logged onto a remote computer.
I hope this can help you.
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

Log disk clean up VBScript

So i have a little script that runs a disk clean up, but i want to log this. Is it possible via f.writeline or something? I already tryed to add some write lines but that didnt work, so i removed these..
Option Explicit
On Error Resume Next
SetRegKeys
DoCleanup
Sub DoCleanup()
Dim WshShell
Set WshShell=CreateObject("WScript.Shell")
WshShell.Run "C:\WINDOWS\SYSTEM32\cleanmgr /sagerun:1"
End Sub
Sub SetRegKeys
Dim strKeyPath
Dim strComputer
Dim objReg
Dim arrSubKeys
Dim SubKey
Dim strValueName
Dim fso
Const HKLM=&H80000002
strKeyPath="SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches"
strComputer="."
strValueName="StateFlags0001"
Set objReg=GetObject("winmgmts:\\" & strComputer & "\root\default:StdRegProv")
objReg.Enumkey HKLM ,strKeyPath,arrSubKeys
For Each SubKey In arrSubKeys
objReg.SetDWORDValue HKLM,strKeyPath & "\" & SubKey,strValueName,2
Next
End Sub
Thanks!
I have a standard subroutine that I use to log to an output file (path "logfileName" specified at the top of the script) that also appends the time on each line:
Sub Logwrite (aMsg)
Dim a
Const ForAppending = 8
' This Appends a line of text to a Logwrite file
' creating it if required
If Len(aMsg) = 0 Then
If fso.FileExists(logfileName) Then fso.DeleteFile(logfileName)
Exit Sub
End If
Set a = fso.OpenTextFile(logfileName, ForAppending, TRUE, 0)
a.WriteLine(Now() & " -- " & aMsg)
a.Close
Set a = Nothing
End Sub
For example, you can call the subroutine in the For Each loop, and you can specify the message that gets logged:
For Each SubKey In arrSubKeys
objReg.SetDWORDValue HKLM,strKeyPath & "\" & SubKey,strValueName,2
Logwrite "Set value for " & strKeyPath & "\" & SubKey & " to " & strValueName
Next
Note that if I want to erase the previous file if it exists, then I will first call the subroutine at the top of the script with a blank message to log -- Logwrite "" -- which tells it to delete the previous log file.
Hope this helps!

VBScript FTP Login with Username and Password

I am trying to update a VBScript (very little experience with this, I do a lot of VB.NET), that reads an FTP directory and moves certain files to a new local directory on a daily basis. I have old code that works on an FTP site that uses anonymous logins, but I now need it to access an FTP site that requires username and password.
Here is my current code -
Sub MoveNSPurolatorFile()
Dim NSPurolatorFTPSite, NSPurolatorMoveFilePath, NSPurolatorFTPFolder, NSPurolatorFTPFileName
Dim folder, files
Dim fso
set fso = CreateObject("Scripting.FileSystemObject")
NSPurolatorFTPSite="\\xxx.xxx.x.xx\"
NSPurolatorMoveFilePath = "F:\TestDirectory"
NSPurolatorFTPFolder = "TestFolder"
NSPurolatorFTPFileName = "MAN0201.CSV"
If InStr(NSPurolatorFTPFileName, "_processed") = 0 and InStr(NSPurolatorFTPFileName, ".CSV") > 0 Then
If fso.FolderExists(NSPurolatorFTPSite & NSPurolatorFTPFolder) Then
If fso.FileExists(NSPurolatorFTPSite & NSPurolatorFTPFolder & NSPurolatorFTPFileName) Then
objfile.writeline "NS Purolator File Found: " & NSPurolatorFTPSite & NSPurolatorFTPFolder & NSPurolatorFTPFileName
fso.copyFile NSPurolatorFTPSite & NSPurolatorFTPFolder & NSPurolatorFTPFileName, NSPurolatorMoveFilePath & "\"
Else
objfile.writeline "File does not exist: " & NSPurolatorFTPSite & NSPurolatorFTPFolder & NSPurolatorFTPFileName
End If
End If
End If
Next
End Sub
It says the folder does not exist, but I know it does and when I run this code against an ftp site that does not require username and password it works fine. I guess my question is - How do I pass in the username and password using VBScript to the ftp site before trying to access folders, etc?
Thanks.
This really is an incredibly bad way to do this. You can't just treat folders on a remote FTP site as local folders.
You really should be using InetCtrls.Inet.1
Here's an example I lifted from somewhere else that does not do what you want, but contains all the parts you need - you need to pick it apart to suit your needs.
'Option Explicit
'const progname="FTP upload script by Richard Finegold"
'const url = "ftp://ftp.myftpsite.com"
'const rdir = "mydir"
'const user = "anonymous"
'const pass = "myname#mymailsite.com"
'This is an example of ftp'ing without calling the external "FTP" command
'It uses InetCtrls.Inet.1 instead
'Included is a "hint" for simple downloading
'Sources:
'http://msdn.microsoft.com/library/partbook/ipwvb5/loggingontoftpserver.htm
'http://msdn.microsoft.com/library/partbook/egvb6/addinginternettransfercontrol.htm
'http://cwashington.netreach.net/ - search on "ftp" - inspiration only!
'Insist on arguments
dim objArgs
Set objArgs = Wscript.Arguments
If 0=objArgs.Count Then
MsgBox "No files selected for operation!", vbOkOnly + vbCritical, progname
WScript.Quit
End If
'Force console mode - csforce.vbs (with some reorganization for efficiency)
dim i
if right(ucase(wscript.FullName),11)="WSCRIPT.EXE" then
dim args, y
For i = 0 to objArgs.Count - 1
args = args + " " + objArgs(i)
Next
Set y = WScript.CreateObject("WScript.Shell")
y.Run "cscript.exe " & wscript.ScriptFullName + " " + args, 1
wscript.quit
end if
'Do actual work
dim fso, ftpo
set fso = WScript.CreateObject("Scripting.FileSystemObject")
set ftpo = WScript.CreateObject("InetCtls.Inet.1") 'Msinet.ocx
ftpo.URL = url
ftpo.UserName = user
ftpo.Password = pass
WScript.Echo "Connecting..."
ftpo.Execute , "CD " & rdir
do
' WScript.Echo "."
WScript.Sleep 100 'This can take a while loop while ftpo.StillExecuting
for i = 0 to objArgs.Count - 1
dim sLFile
sLFile = objArgs(i)
if (fso.FileExists(sLFile)) then
WScript.Echo "Uploading " & sLFile & " as " & FSO.GetFileName(sLFile) & " "
ftpo.Execute , "Put " & sLFile & " " & FSO.GetFileName(sLFile)
'ftpo.Execute , "Get " & sRemoteFile & " C:\" & sLFile
do
'WScript.Echo "."
WScript.Sleep 100 'This can take a while
loop while ftpo.StillExecuting
else
MsgBox Chr(34) & sLFile & Chr(34) & " does not exist!", _
vbOkOnly, progname
end if
next
WScript.Echo "Closing"
ftpo.Execute , "Close"
WScript.Echo "Done!"
Here's a pretty nice way to do it - I'm sure this could be improved upon, but I just got it going.. :-)
Dim fso, folder1, folder2, folder2a
Set fso = CreateObject("Scripting.FileSystemObject")
Set folder2a = fso.GetFolder("C:\temp")
ftpFolderString = "ftp://username:password#ftp.ftpsite.com/folderpath"
targetFoldder = "C:\temp"
fileSearchStr = "searchstring"
Dim SH, txtFolderToOpen, thing
Set SH = CreateObject("Shell.Application")
'SH.Open txtFolderToOpen
Set folder1 = SH.NameSpace(ftpFolderString)
Set folder2 = SH.NameSpace(targetFoldder)
For Each item In folder1.items
If InStr(LCase(item.Name),fileSearchStr) > 0 Then
Debug.WriteLine item.Name
folder2.CopyHere item,4
WScript.Sleep(200)
For Each item2 In folder2a.Files
If item2.Name = item.Name Then
While item2.Size < item.Size
WScript.Sleep(200)
Wend
End If
Next
WScript.Sleep(200)
End If
Next
Set SH = Nothing
Debug.WriteLine "Done"
How is the script being run? Manually, automatically? By a service?
Mapped-letter drives are not always available when running as a service.
Experiment with the script to ensure that it even able to see the F:\ drive, and then see what else is visible.
Is the FTP site accessed by a UNC path (looks like it is)? If it is just a standard FTP address then you can incorporate the username / password in the URL e.g. ftp://user:pass#myftpsite.com. If it is a UNC path that you are trying to access using different credentials then the easiest way would probably be to map a drive, do the work and then unmap the drive. 2 different approaches can be found here

Resources