How to create a registry key with VBS? - vbscript

Okay, I will try asking this question again.
I used this code:
Dim WshShell
Set WshShell = WScript.CreateObject("WScript.Shell")
WshShell.RegWrite "HKCU\Software\Microsoft\Windows\CurrentVersion\Policies\System\test", 1, "REG_DWORD"
I get the error 'Invalid root in registry key' Code: 80070005 (Access Denied)
The code works with other registry roots. I am logged on as an administrator. It works when I run it from an elevated command prompt. But I am making this VBS as a prank to a friend to make him not know what I'm doing. Any ideas?

The best way to distribute registry setting is by exporting the part of a registry where this setting is active to a .reg file with the registry editor. In the save part of the export dialog you choose Win9x/NT4 as format. You can check the .reg file with an editor. The user only has to double click the .reg file and confirm the prompt and possibly reboot his pc. Even normal users should be able to do this. If the registrybranch you try to change is protected by security he wil have to do this with admin right and possibly (depenidng on OS version) start regedit with the the regedt32.exe executable and first adapt the security of that branch so that it can be changed.
Doing this with a script means having to pass additional layers of security to make sure this isn't a malicious script.

Sub x86Win32ScriptingElevate()
in WinXP and Win7 - its works fine:
Call x86Win32ScriptingElevate()
Dim WshShell
Set WshShell = WScript.CreateObject("WScript.Shell")
WshShell.RegWrite "HKCU\Software\Microsoft\Windows\CurrentVersion\Policies\System\test", 1, "REG_DWORD"
WScript.Quit
'*** v13.3 *** www.dieseyer.de *****************************
Sub x86Win32ScriptingElevate()
'***********************************************************
' http://dieseyer.de/scr/elevate.vbs
' Unter Windows x64 laufen VBS' nach einem Doppelklick in der x64-Umgebung
' mit %WinDi%\System32\wscript.exe oder mit %WinDi%\System32\cscript.exe.
' In der x64-Umgebung laufen VBS aber nicht (richtig). Die Prozedur
' x86Win32ScriptingElevate() erkennt dies und startet ggf. das VBS in der
' x86-Umgebung mit
' %WinDirr%\SysWOW64\wscript.exe bzw. mit
' %WinDirr%\SysWOW64\cscript.exe
Dim VBSExe, Tst, TxtArg, i
' MsgBox WScript.FullName & vbCRLF & vbFalse & "..." & False & vbCRLF & wscript.arguments.named.exists("elevated"), , "173 :: "
If wscript.arguments.named.exists("elevated") = True then Exit Sub
' Argumentte sammeln
Dim Args : Set Args = Wscript.Arguments
For i = 0 to Args.Count - 1 ' hole alle Argumente
TxtArg = TxtArg & " " & Args( i )
Next
TxtArg = Trim( TxtArg )
' MsgBox ">" & TxtArg & "<", , "184 :: "
VBSExe = UCase( WScript.FullName )
' x86- / Win32-Systeme haben KEIN %WinDir%\SysWOW64\ - Verzeichnis
Tst = Replace( VBSExe, "\SYSTEM32\", "\SYSWOW64\" )
If CreateObject("Scripting.FileSystemObject").FileExists( Tst ) Then VBSExe = Tst
' VBS mit /elevate starten - ggf. auf x64-System in Win32-Umgebung
' Msgbox """" & VBSExe & """ """ & WScript.ScriptFullName & """ " & TxtArg , , "196 :: "
Tst = createobject("Shell.Application").ShellExecute( """" & VBSExe & """", """" & wscript.scriptfullname & """ " & TxtArg & " /elevated", "", "runas", 1 )
WScript.Quit( Tst )
End Sub ' x86Win32ScriptingElevate()

Related

Searching the registry with vbs to find an unknown part of the path

I use a path to locate pieces of information that contains a guid that can change. I had the guid value hard coded, but when it changes it doesn't function. I need to discover that guid dynamically. I know a value on the other side of the guid and have a REG Query that finds the entire path, but I can't figure out how to capture that path.
Here's the REG Query:
REG Query HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Products /D /V /F "Microsoft Office Professional Plus 2010" /S /E
It returns the Value "DisplayName" and it's contents "Microsoft Office Professional Plus"
When run from a batch file it also displays the entire path that includes the elusive guid. I would like to do this from a vb script.
Also the newer Windows Scripting Host Shell object also makes registry access easy.
Set wshshell = CreateObject("WScript.Shell")
wshshell.RegDelete(strName)
wshshell.RegRead(strName)
wshshell.RegWrite(strName, anyValue [,strType])
See https://msdn.microsoft.com/en-us/library/293bt9hh(v=vs.84).aspx
Also WMI can access registry. Unlike both above methods it can ennumerate, so you can see what is there without having to know in advance.
Dim proglist()
Set oReg=GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\default:StdRegProv")
ret = oReg.EnumKey(&H80000002, "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall", proglist)
If err.num =0 then
For each prog in proglist
msgbox prog
Next
Else
Msgbox err.num & " " & err.description & " " & err.source
err.clear
End If
https://msdn.microsoft.com/en-us/library/aa390387(v=vs.85).aspx
It can also check security and monitor changes to keys.
This monitors changes to Windows Uninstall key.
Set objWMIService = GetObject("winmgmts:root/default")
Set objEvents = objWMIService.ExecNotificationQuery("SELECT * FROM RegistryTreeChangeEvent WHERE Hive='HKEY_LOCAL_MACHINE' AND RootPath='SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall'")
Do
Set objReceivedEvent = objEvents.NextEvent
msgbox objReceivedEvent.GetObjectText_()
Loop
https://msdn.microsoft.com/en-us/library/aa393041(v=vs.85).aspx‎
Recursion is used to walk each node in a tree. The function calls itself every time it comes across a node. Start below program using cscript to avoid a few thousand msgboxs - cscript //nologo c:\folder\RecurseReg.vbs.
Set wshshell = CreateObject("WScript.Shell")
EnumReg "SOFTWARE\CLASSES"
Sub EnumReg(RegKey)
On Error Resume Next
wscript.echo "---------------------------------------"
wscript.echo "HKLM\" & RegKey & " = " & wshshell.RegRead("HKLM\" & RegKey & "\")
err.clear
Dim KeyList()
Dim ValueNameList()
Dim ValueList()
Set oReg=GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\default:StdRegProv")
If err.number <> 0 then
wscript.echo err.number
err.clear
End If
ret = oReg.EnumValues(&H80000002, RegKey, ValueNameList, ValueList)
If err.number = 0 then
For each valuename in ValueNameList
If valuename <> "" then
Value = wshshell.RegRead("HKLM\" & RegKey & "\" & valuename)
err.clear
wscript.echo valuename & " - " & Value
End If
Next
Else
Msgbox err.num & " " & err.description & " " & err.source
err.clear
End If
ret = oReg.EnumKey(&H80000002, RegKey, Keylist)
If err.number =0 then
For each key in keylist
EnumReg RegKey & "\" & key
Next
Else
Msgbox err.num & " " & err.description & " " & err.source
err.clear
End If
End Sub
Putting both together (this does VC 2008 Runtime which should be on all computers)
Dim proglist()
Set wshshell = CreateObject("WScript.Shell")
On Error Resume Next
Set oReg=GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\default:StdRegProv")
ret = oReg.EnumKey(&H80000002, "SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Products", proglist)
If err.num =0 then
For each prog in proglist
' msgbox prog
If wshshell.RegRead("HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Products\" & Prog & "\InstallProperties\DisplayName") = "Microsoft Visual C++ 2008 Redistributable - x64 9.0.30729.17" then
Msgbox "Found " & Prog
End If
Next
Else
Msgbox err.num & " " & err.description & " " & err.source
err.clear
End If
For V6 or VBA
The registry is simple in VBA. It's is very limited and uses ini file concepts.
There's a few of them such as (from Object Browser [F2] in VBA editor)
Function GetAllSettings(AppName As String, Section As String)
Member of VBA.Interaction
Sub SaveSetting(AppName As String, Section As String, Key As String, Setting As String)
Member of VBA.Interaction
Sub DeleteSetting(AppName As String, [Section], [Key])
Member of VBA.Interaction
Function GetSetting(AppName As String, Section As String, Key As String, [Default]) As String
Member of VBA.Interaction
Also the Windows API calls can be used.
RegOpenKeyEx
The RegOpenKeyEx function opens the specified registry key.
LONG RegOpenKeyEx(
HKEY hKey, // handle to open key
LPCTSTR lpSubKey, // subkey name
DWORD ulOptions, // reserved
REGSAM samDesired, // security access mask
PHKEY phkResult // handle to open key
);

create folder(trusted), copy of MDE and shortcut

I have put together a script that I think will work, but the only code I know is some VBA. Never tried to create a vbscript before, so my apologies if some errors are obvious, but pointers and corrections would be appreciated.
I am hoping I can give users in my company a link to this script and have them run it. It will create a folder on their C Drive, make it a trusted location, copy a database frontend from the server into it and create a shortcut on their desktop linking to the new file. (I'm hoping the file will auto-update when a new version is made - I think that bit works though).
The code comes from various sources, including my own addled mind but would I need to download Visual Studio to test this? Slightly concerned as it includes creating a registry key and I don't know how to stop the code if it all goes horribly wrong. I don't even know how to break a loop (although I think I read somewhere you need to hit Esc twice). Any tips on how to signify which sub is the main one to run on start would be good too.
EDIT : Code has been amended to my end result incase it is of use to others. Please use with caution. The 'update' vbs deletes the folder created on the local drive.
'FrontEnd Setup
call CreateTrustedFolder
'Const HKEY_CLASSES_ROOT = &H80000000
Const HKEY_CURRENT_USER = &H80000001
'Const HKEY_LOCAL_MACHINE = &H80000002
'Const HKEY_USERS = &H80000003
'Const HKEY_CURRENT_CONFIG = &H80000005
Dim lclFolder
Dim blnUpdate
Sub CreateTrustedFolder()
On error resume next
Call RunAdmin
Call FolderFileShortcut
Call CreateReg
if err then
MsgBox "The following error has occurred " & Err & " " & Err.Description
exit Sub
end if
End Sub
'Run as Administrator
Sub RunAdmin()
On error resume next
If Not WScript.Arguments.Named.Exists("elevate") Then
CreateObject("Shell.Application").ShellExecute WScript.FullName _
, WScript.ScriptFullName & " /elevate", "", "runas", 1
WScript.Quit
End If
if err then
MsgBox "The following error has occurred " & Err & " " & Err.Description
exit Sub
end if
End Sub
'Check if folder exists, add file and desktop shortcut
Sub FolderFileShortcut()
On error resume next
Dim oWS
Dim FSO
Dim svrFolder
Dim myShortcut
Dim strLocalDB
Dim strServerDB
Dim strUpdate
Dim strIcon
Dim objFile
Dim counter
Set oWS = WScript.CreateObject("WScript.Shell")
Set FSO = WScript.CreateObject("Scripting.FileSystemObject")
svrFolder = "\\192.168.1.2\DeptFolder\DatabaseFolder\Auto-Update"
lclFolder = "C:\Program Files\Orrible Database"
If (FSO.FolderExists(lclFolder)) Then
oWS.run "icacls """ & lclFolder & """ /reset /grant:r Users:(W) /t" '/T required for existing folders
FSO.DeleteFolder lclFolder
blnUpdate = True
end if
If Not (FSO.FolderExists(svrFolder)) Then
msgbox "Unable to connect to Location Server", vbCritical, "Installation Failed"
WScript.Quit
End If
For Each objFile in FSO.Getfolder(svrFolder).Files
if LCase(FSO.GetExtensionName(objFile.name)) = LCase("mde") then
counter = counter + 1
strServerDB = FSO.GetFileName(objFile)
end if
Next
If strServerDB = "" or counter <> 1 then
msgbox "Unable to locate the Front End" & strServerDB & "-" & counter, vbCritical, "Installation Failed"
wScript.Quit
end if
strLocalDB = "Co Database.mde"
strUpdate = "DB_UpdateCheck.vbs"
strIcon = "Frontend Update.ico"
FSO.CreateFolder(lclFolder)
oWS.run "icacls """ & lclFolder & """ /grant Users:(OI)(CI)F /t" '/T required for existing folders
FSO.CopyFile svrFolder & "\" & strUpdate, lclFolder & "\" & strUpdate, True
FSO.CopyFile svrFolder & "\" & strServerDB, lclFolder & "\" & strLocalDB, True
FSO.CopyFile svrFolder & "\" & strIcon, lclFolder & "\" & strIcon, True
strDesktop = oWS.SpecialFolders("Desktop")
set myShortcut = oWS.CreateShortcut(strDesktop + "\New Database.lnk")
myShortcut.TargetPath = lclFolder & "\" & strUpdate
myShortcut.WindowStyle = 1
myShortcut.IconLocation = lclFolder & "\" & strIcon
myShortcut.WorkingDirectory = strDesktop
myShortcut.Save
if err then
MsgBox "The following error has occurred " & Err & " " & Err.Description
exit Sub
end if
End Sub
Sub CreateReg()
On error resume next
Dim objRegistry 'registry object
Dim strDescription 'Description of the Trusted Location
Dim strParentKey 'Registry location of Application
Dim strNewKey 'strParentKey and myFolder
Dim oWS 'WSH shell object
strDescription = "DB Folder"
strParentKey = "Software\Microsoft\Office\15.0\Access\Security\Trusted Locations"
strNewKey = strParentKey & "\" & strDescription & "\"
Set objRegistry = GetObject("winmgmts:\\.\root\default:StdRegProv")
'objRegistry.GetStringValue HKEY_CURRENT_USER, strParentKey & "\" & strDescription
If Not objRegistry.EnumKey(HKEY_CURRENT_USER, strNewKey) = 0 then '0=true
objRegistry.CreateKey HKEY_CURRENT_USER, strNewKey
objRegistry.SetStringValue HKEY_CURRENT_USER, strNewKey, "Path", lclFolder
objRegistry.SetStringValue HKEY_CURRENT_USER, strNewKey, "Description", strDescription
End if
If not blnUpdate = True then
msgbox "The Database is now available from your desktop", vbInformation, "Setup Complete"
Else
msgbox "The update is now complete."
End if
if err then
MsgBox "The following error has occurred " & Err & " " & Err.Description
exit Sub
end if
End Sub
There is also a separate Update vbs which is what runs when the link is clicked. This checks to see if the 'created date' of the database on the server is newer than that on the local drive. The new DB name MUST NOT be the same as the one it is replacing. It might run a little fast, but this is as far as I have taken this.
Call CheckForUpdate
Sub CheckForUpdate()
On Error Resume Next
Dim FSO
Dim oWS
Dim svrFolder
Dim lclFolder
Dim svrFail
Dim strLocalDB
Dim strServerDB
Dim lclDate
Dim svrDate
Dim strFileName
Dim intDBcount
Dim fCheck
Set oWS = WScript.CreateObject("WScript.Shell")
Set FSO = WScript.CreateObject("Scripting.FileSystemObject")
svrFolder = "\\192.168.1.2\DeptFolder\DatabaseFolder\Auto-Update"
lclFolder = "C:\Program Files\Orrible Database"
strLocalDB = "Co Database.mde"
If Not (FSO.FolderExists(svrFolder)) Then
msgbox "Unable to connect to Location Server", vbCritical, "Update Check Failed"
svrFail = True
End If
If Not svrFail = True Then
For Each fCheck in FSO.GetFolder(svrFolder).Files
If Ucase(Right(fCheck.Name, 3)) = "MDE" Then
intDBcount = intDBcount + 1
strServerDB = fCheck.name
End If
Next
If Not intDBcount = 1 Then
MsgBox "Please inform the Administrator that there is a problem with the Automated Update System.", _
vbCritical, "Update Failed (" & intDBcount & ")"
svrFail = True 'not quit - need to see if old version available
End If
End If
If Not (FSO.FolderExists(lclFolder)) Then
If svrFail = True Then 'If no lcl folder or server
If Not intDBcount = 1 then WScript.Quit
msgbox "You are unable to use the Database." & vbcrlf & _
"Please try again when you have access to the Location Server.", _
vbcritical, "Database Not Installed"
WScript.Quit
Else 'If no lclfolder, get it from svr
'Do normal initial install
oWS.Run svrFolder & "\" & "DB_Install.vbs", 1, True
WScript.Quit
End If
Else
If svrFail = True Then 'If lcl folder, but no svr
'open db
oWS.Run CHR(34) & lclFolder & "\" & strLocalDB & CHR(34)
WScript.Quit
Else 'If lcl folder and svr access, check for update.
lclDate = fso.getfile(lclFolder & "\" & strLocalDB).DateCreated
svrDate = fso.getfile(svrFolder & "\" & strServerDB).DateCreated
If lclDate < svrDate Then 'Update available
intMsg = MsgBox("An update is available - Do you wish to update now?", vbQuestion + vbYesNo, "Update Found")
If intMsg = vbYes Then
oWS.Run svrFolder & "\" & "DB_Install.vbs", 1, True ',1,true should pause the code until install closes
oWS.Run CHR(34) & lclFolder & "\" & strLocalDB & CHR(34)
WScript.Quit
Else
oWS.Run CHR(34) & lclFolder & "\" & strLocalDB & CHR(34)
WScript.Quit
End If
Else
oWS.Run CHR(34) & lclFolder & "\" & strLocalDB & CHR(34)
WScript.Quit
End If
End If
End If
If err Then
MsgBox "The following error has occurred " & Err & " " & Err.Description
Exit Sub
End If
End Sub

Update registry using VBS

I'm trying to update the legal caption on our PCs using a VBScript. So far, I've been able to read values but I can't seem to get it to write any values. I don't get an error when I run the script, it just doesn't change anything. It's the first time I'm doing this and I have limited experience; any insight would be appreciated:
Dim objShell
Dim strMessage, strWelcome, strWinLogon
' Set the string values
strWelcome = "legalnoticecaption"
strMessage = "did this work"
strWinLogon = "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\"
' Create the Shell object
Set wshShell = CreateObject("WScript.Shell")
'Display string Values
Wscript.Echo "key to update: " & strWelcome
Wscript.Echo "key value to enter: " & strMessage
Wscript.Echo "Existing key value: " & wshShell.RegRead(strWinLogon & strWelcome)
' the crucial command in this script - rewrite the registry
wshShell.RegWrite strWinLogon & strWelcome, strMessage, "REG_SZ"
' Did it work?
Wscript.Echo "new key value: " & wshShell.RegRead(strWinLogon & strWelcome)
set wshShell = Nothing
NOTE: These are testing values at the moment.
Your script seems to be bug-less. However, launched by cscript 28416995.vbs returns next error (where 22 = WshShell.RegWrite line):
28416995.vbs(22, 1) WshShell.RegWrite: Invalid root in registry key "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\legalnoticecaption".
It's not invalid root, it's something like access denied rather because writing to HKLM requires elevated privileges (or run as administrator).
Note:
You should change LegalNoticeText value together with LegalNoticeCaption one.
Under the HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\ registry key there both values reside as well. For this case (if a computer is not connected to a domain or with group policy disabled) should work next script.
Run as administrator:
option explicit
On Error Goto 0
Dim wshShell
Dim strResult, strMessage, strWelcome, strWinLogon, strWinLog_2, strWinLTxt
strResult=Wscript.ScriptName
' Set the string values
strWinLTxt = "legalnoticetext"
strWelcome = "legalnoticecaption"
strMessage = "did this work"
strWinLogon = "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\"
strWinLog_2 = "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\"
' Create the Shell object
Set wshShell = CreateObject("WScript.Shell")
'Display string Values
' continue execution if requested registry values not present
On Error Resume Next
strResult = strResult & vbNewLine & "Existing Caption Policies: " _
& wshShell.RegRead(strWinLog_2 & strWelcome)
strResult = strResult & vbNewLine & "Existing Text Policies: " _
& wshShell.RegRead(strWinLog_2 & strWinLTxt)
On Error Goto 0
strResult = strResult & vbNewLine & "Existing Caption Winlogon: " _
& wshShell.RegRead(strWinLogon & strWelcome)
strResult = strResult & vbNewLine & "Existing Text Winlogon: " _
& wshShell.RegRead(strWinLogon & strWinLTxt)
strResult = strResult & vbNewLine
strResult = strResult & vbNewLine & "key to update: " & strWelcome
strResult = strResult & vbNewLine & "key value to enter: " & strMessage
' the crucial command in this script - rewrite the registry
wshShell.RegWrite strWinLogon & strWelcome, strMessage, "REG_SZ"
wshShell.RegWrite strWinLogon & strWinLTxt, UCase( strMessage), "REG_SZ"
' Did it work?
strResult = strResult & vbNewLine
strResult = strResult & vbNewLine _
& "new key Capt. value: " & wshShell.RegRead(strWinLogon & strWelcome)
strResult = strResult & vbNewLine _
& "new key Text value: " & wshShell.RegRead(strWinLogon & strWinLTxt)
Wscript.Echo strResult
set wshShell = Nothing
For me your code run perfect.
For other user that want details over this i recommend this site: http://ss64.com/vb/regread.html and ss64.com/vb/regwrite.html
Both links detail exactly the procedure that you create.
Make sure to add this:
Function RunAsAdmin()
If WScript.Arguments.length = 0 Then
CreateObject("Shell.Application").ShellExecute "wscript.exe", """" & _
WScript.ScriptFullName & """" & " RunAsAdministrator",,"runas", 1
WScript.Quit
End If
End Function
It will run as Admin and if it doesnt work then your key is incorrect.

Delete Windows 7 network printer driver remotely using WMI

I need some help with deleting network printer driver remotely on a Windows 7 client machine using a vbscript with an account having administrator privileges (Elevated Account) on the remote computer. The problem is that I can't delete the connected printer the user have connected. Everything else seems to work. Below is the code for the script.
The script does several things, but the ultimate goal is to physically remove the printer-drivers. The current version of the script fails since the driver files are in use. The script contains code to avoid deleting special printers. It also stops and starts the print spooler.
intSleep = 4000
strService = " 'Spooler' "
strComputer = "<remote computer name>"
Set fsobj = CreateObject("Scripting.FileSystemObject") 'Calls the File System Object
Set objNetwork = CreateObject("WScript.Network")
arrPrinters = Array("PDF", "Adobe", "Remote", "Fax", "Microsoft", "Send To", "Generic")
Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
' List drivers
Set colInstalledPrinters = objWMIService.ExecQuery _
("Select * from Win32_PrinterDriver")
Set drivrutinCol = CreateObject("Scripting.Dictionary")
For each objPrinter in colInstalledPrinters
' Wscript.Echo "Configuration File: " & objPrinter.ConfigFile
' Wscript.Echo "Data File: " & objPrinter.DataFile
' Wscript.Echo "Description: " & objPrinter.Description
' Wscript.Echo "Driver Path: " & objPrinter.DriverPath
' Wscript.Echo "File Path: " & objPrinter.FilePath
' Wscript.Echo "Help File: " & objPrinter.HelpFile
' Wscript.Echo "INF Name: " & objPrinter.InfName
' Wscript.Echo "Monitor Name: " & objPrinter.MonitorName
' Wscript.Echo "Name: " & objPrinter.Name
' Wscript.Echo "OEM Url: " & objPrinter.OEMUrl
' Wscript.Echo "Supported Platform: " & objPrinter.SupportedPlatform
' Wscript.Echo "Version: " & objPrinter.Version
if InArray(objPrinter.Name, arrPrinters ) = False then
Wscript.Echo "Name: " & objPrinter.Name
drivrutinCol.Add drivrutinCol.Count, Replace(objPrinter.ConfigFile, "C:", "\\" & strComputer & "\c$")
drivrutinCol.Add drivrutinCol.Count, Replace(objPrinter.DataFile, "C:", "\\" & strComputer & "\c$")
drivrutinCol.Add drivrutinCol.Count, Replace(objPrinter.DriverPath, "C:", "\\" & strComputer & "\c$")
end if
Next
' Remove network printers
Const NETWORK = 22
Set colInstalledPrinters = objWMIService.ExecQuery _
("Select * From Win32_Printer")
For Each objPrinter in colInstalledPrinters
If objPrinter.Attributes And NETWORK Then
' The code never gets here for user connected network printers
End If
Next
' Stop Print Spooler Service
Set colListOfServices = objWMIService.ExecQuery _
("Select * from Win32_Service Where Name ="_
& strService & " ")
For Each objService in colListOfServices
objService.StopService()
WSCript.Sleep intSleep
Next
' Delete drivers
for i = 0 to drivrutinCol.Count-1
Wscript.Echo "Deleting driver: " & drivrutinCol.Item(i)
fsobj.DeleteFile(drivrutinCol.Item(i))
Next
' Start Print Spooler Service
For Each objService in colListOfServices
WSCript.Sleep intSleep
objService.StartService()
Next
Function InArray(item,myarray)
Dim i
For i=0 To UBound(myarray) Step 1
If InStr(lcase(item), lcase(myarray(i)))>0 Then
InArray=True
Exit Function
End If
Next
InArray=False
End Function
The failing part of the code is the "Remove network printers" - part. The script does not list the network printers that the user have connected in the user profile, but only the local printers connected to the computer profile.
To remove a (network) printer connection of a user who isn't logged in you need to load the user hive into the registry and delete the respective value from the Printers\Connections subkey:
Function qq(str) : qq = Chr(34) & str & Chr(34) : End Function
Set sh = CreateObject("WScript.Shell")
username = "..."
hive = "\\" & strComputer & "\C$\Users\" & username & "\ntuser.dat"
sh.Run "reg load HKU\temp " & qq(hive), 0, True
sh.RegDelete "HKEY_USERS\temp\Printers\Connections\server,printer"
sh.Run "reg unload HKU\temp", 0, True
You need to load the hive from a network share, because unlike other subcommands load and unload don't work with remote registries.
To delete a printer driver (after you removed the printer connection from the user's config) you need to acquire the SeLoadDriverPrivilege first and then remove the respective instance of the Win32_PrinterDriver class (see section "Remarks"):
objWMIService.Security_.Privileges.AddAsString "SeLoadDriverPrivilege", True
qry = "SELECT * FROM Win32_PrinterDriver"
For Each driver In objWMIService.ExecQuery(qry)
If driver.Name = "..." Then driver.Delete_
Next

VbScript, Install exe remotely without user input?

I'm really stuck on a problem so I figured I would get a second opinion(s).
I'm trying to remotely install .exe and .msi to client computers. I have a vb script that downloads the file and runs the file, but there's a few problems. First, I'm having trouble getting it to the run on the local admin account. For testing purposes I'm running it as an Admin and it works fine, but if put on a client computer it would need access to the local Admin.
Secondly, and more importantly, microsoft requires some amount of user input before installing an exe file. I know silent msi install is possible, but I assume silent exe is impossible?
As a solution I'm looking into PsExec, but I feel like I'm missing something here.
For reference, here is my vb script:
Dim TApp
Dim IEObj
Dim tArea
Dim tButton
Const HIDDEN_WINDOW = 12
Const SHOW_WINDOW=1
'Array of Patch files to install.
Dim InstallFiles()
'maximum of 100 workstations to install patches to.
Dim wsNames(100)
Dim numComputers
Dim retVal
Dim PatchFolder
'Create explorer window
Set IEObj=CreateObject("InternetExplorer.Application")
IEObj.Navigate "about:blank"
IEObj.Height=400
IEObj.Width=500
IEObj.MenuBar=False
IEObj.StatusBar=False
IEObj.ToolBar=0
set outputWin=IEObj.Document
outputWin.Writeln "<title>RemotePatchInstall version 1.0</title>"
outputWin.writeln "<HTA:APPLICATION ID='objPatchomatic' APPLICATIONNAME='Patchomatic' SCROLL='no' SINGLEINSTANCE='yes' WINDOWSTATE='normal'>"
outputWin.writeln "<BODY bgcolor=ButtonFace ScrollBar='No'>"
outputWin.writeln "<TABLE cellSpacing=1 cellPadding=1 width='75pt' border=1>"
outputWin.writeln "<TBODY>"
outputWin.writeln "<TR>"
outputWin.writeln "<TD>"
outputWin.writeln "<P align=center><TEXTAREA name=Information rows=6 cols=57 style='WIDTH: 412px; HEIGHT: 284px'></TEXTAREA></P></TD></TR>"
outputWin.writeln "<TR>"
' outputWin.writeln "<TD><P align=center><INPUT id=button1 style='WIDTH: 112px; HEIGHT: 24px' type=button size=38 value='Install Patches' name=button1></P></TD>"
outputWin.writeln "</TR>"
outputWin.writeln "<TR>"
outputWin.writeln "<TD></TD></TR></TBODY></TABLE>"
outputWin.writeln "</BODY>"
IEObj.Visible=True
'Get the Information textarea object from the window
set tempObj=outputWin.getElementsByName("Information")
objFound=false
'loop through its object to find what we need
For each objN in tempObj
if objN.name="Information" then
objFound=true
set tArea=objN
end if
next
'if we didnt find the object theres a problem
if ObjFound=False then
'so show an error and bail
MsgBox "Unable to access the TextBox on IE Window",32,"Error"
WScript.Quit
end if
'*************************
'ADMINS: The below is all you should really have to change.
'*************************
'Change this to the location of the patches that will be installed.
'they should be limited to the amout you try to install at one time.
'ALSO the order they are installed is how explorer would list them by alphabetically.
'So given file names:
'patch1.exe
'patch2.exe
'patch11.exe
'installation order would be patch1.exe,patch11.exe, patch2.exe
PatchFolder="C:\IUware Online\Install\"
'Change this to location where the patches will be copied to on remote cp. This directory must exist on remote computer.
'I have it hidden on all workstations.
RemotePatchFolder="C:\Users\jorblume\Backup\"
'Workstation names to refer to as array
wsNames(1)="129.79.205.153"
'wsNames(2)="192.168.0.11"
'number of remote computers
numComputers=1
'**********************
'ADMINS: The above is all you should really have to change.
'**********************
'Copy files to remote computers.
'Get a list of the executable file in the folder and put them into the InstallFiles array
'on return, retVal will be number of files found.
retVal=GetPatchFileList (PatchFolder,InstallFiles)
'for each file copy to remote computers
For cc=1 to numComputers 'for each computer
For i = 1 to retVal 'for each file
Dim copySuccess
Dim SharedDriveFolder
'do a replacement on the : to $, this means you must have admin priv
'this is because i want to copy to "\\remotecpname\c$\PathName"
SharedDriveFolder=replace(RemotePatchFolder,":","$")
'copy it from the PatchFolder to the path on destination computer
'USE: RemoteCopyFile (SourceFilePath,DestinationFilePath, RemoteComputerName)
CurrentCP=cc
copySuccess=RemoteCopyFile(PatchFolder & "\" & InstallFiles(i),SharedDriveFolder,wsNames(CurrentCP))
if copySuccess=true then
tArea.Value=tArea.Value & PatchFolder & "\" & InstallFiles(i) & " copy - OK" & vbcrlf
else
tArea.Value=tArea.Value & PatchFolder & "\" & InstallFiles(i) & " copy - FAILED" & vbcrlf
end if
Next
Next
'Install the files on remote computer
'go through each filename and start that process on remote PC.
'for each file install them on the computers.
For cc=1 to numComputers
'if theres more than one patch
if retVal>1 then
For i=1 to retVal-1
CurrentCp=cc
'Now create a process on remote computer
'USE: CreateProcessandwait( ComputerName, ExecutablePathonRemoteComputer
'Create a process on the remote computer and waits. Now this can return a program terminated which is ok,
'if it returns cancelled it means the process was stopped, this could happen if the update required a
'computer restart.
CreateProcessandWait wsNames(CurrentCP), RemotePatchFolder & InstallFiles(i) & " /quiet /norestart", tArea
next
end if
'do the last patch with a forcereboot
CreateProcessandWait wsNames(CurrentCP), RemotePatchFolder & InstallFiles(retVal) & " /quiet" & " /forcereboot" , tArea
next
tArea.value=tArea.Value & "Script Complete!" & vbcrlf
'**************************** FUNCTIONS
'Get list of files in Folder.
Function GetPatchFileList(FileFolder, FileStringArray())
'create file system object
Set objFS=CreateObject("Scripting.FileSystemObject")
'set the a variable to point to our folder with the patches in it.
Set objFolder=objFS.GetFolder(FileFolder)
'set the initial file count to 0
numPatches=0
for each objFile in objFolder.Files
if UCase(Right(objFile.Name,4))=".EXE" then
numPatches=numPatches+1
redim preserve FileStringArray(numPatches)
FileStringArray(numPatches)=objFile.Name
end if
next
GetPatchFileList=numPatches
End Function
'Copy files to remote computer.
Function RemoteCopyFile(SrcFileName,DstFileName,DestinationComputer)
Dim lRetVal
'create file system object
Set objFS=CreateObject("Scripting.FileSystemObject")
lRetVal=objFS.CopyFile (SrcFileName, "\\" & DestinationComputer & "\" & DstFileName)
if lRetVal=0 then
RemoteCopyFile=True
else
RemoteCopyFile=False
end if
End Function
'Create process on remote computer and wait for it to complete.
Function CreateProcessAndWait(DestinationComputer,ExecutableFullPath,OutPutText)
Dim lretVal
strComputer= DestinationComputer
Set objWMIService = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2:Win32_Process")
Set objWMIServiceStart= GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2:Win32_ProcessStartup")
Set objConfig = objWMIServiceStart.SpawnInstance_
objConfig.ShowWindow = 1 'show window or use HIDDEN_WINDOW
lretVal= objWMIService.Create(ExecutableFullPath, null, objConfig, intProcessID)
if lretVal=0 then
OutPutText.Value = OutPutText.Value & "Process created with ID of " & intProcessID & " on " & DestinationComputer & vbcrlf
OutPutText.Value = OutPutText.Value & " Waiting for process " & intProcessID & " to complete." & vbcrlf
WaitForPID strComputer, intProcessID,OutPutText
OutPutText.Value = OutPutText.Value & "Process complete." & vbcrlf
else
OutPutText.Value = OutPutText.Value & "Unable to start process " & ExecutableFullPath & " on " & DestinationComputer & vbcrlf
end if
End Function
'Wait for PRocess to complete
Function WaitForPID(ComputerName,PIDNUMBER,OutPutText)
Dim ProcessNumber
Set objWMIServiceQ = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\" & ComputerName & "\root\cimv2")
Set colItems = objWMIServiceQ.ExecQuery("Select * from Win32_Process",,48)
For Each objItem in colItems
'check if this process is the one we are waiting for
if objItem.ProcessID=PIDNUMBER then
OutPutText.Value = OutPutText.Value & "Process Info:" & vbcrlf
OutPutText.Value = OutPutText.Value & " Description: " & objItem.Description & vbcrlf
OutPutText.Value = OutPutText.Value & " ExecutablePath: " & objItem.ExecutablePath & vbcrlf
OutPutText.Value = OutPutText.Value & " Name: " & objItem.Name & vbcrlf
OutPutText.Value = OutPutText.Value & " Status: " & objItem.Status & vbcrlf
OutPutText.Value = OutPutText.Value & " ThreadCount: " & objItem.ThreadCount & vbcrlf
ProcessNumber=objItem.ProcessID
end if
Next
PidWaitSQL="SELECT TargetInstance.ProcessID " & " FROM __InstanceDeletionEvent WITHIN 4 " _
& "WHERE TargetInstance ISA 'Win32_Process' AND " _
& "TargetInstance.ProcessID= '" & ProcessNumber & "'"
Set Events = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\" & ComputerName & "\root\cimv2").ExecNotificationQuery (PidWaitSQL)
Set TerminationEvent = Events.nextevent
OutPutText.Value = OutPutText.Value & "Program " & TerminationEvent.TargetInstance.ProcessID & _
" terminated. " & vbcrlf
set TerminationEvent=Nothing
exit function
End Function
As suggested in the comments, psexec will be your best solution for this scenario. Just don't forget to use /accepteula in its syntax to ensure it doesn't effectively "hang" while waiting for someone to accept its EULA. :) If you have questions or issues with psexec in your installs, comment back here.

Resources