Learn about Windows PowerShell
Hey, Scripting Guy! I am writing a Visual Basic script which runs a command-line installation of Exchange 2007. However as soon as the installation starts in a separate DOS window, the script goes to the next line and does not wait for that one to finish. I have looked at How Can I Wait Until One Application Has Quit Before Starting a Second Application?, but it does not seem to match my needs. Thank you in advance, and keep up the good work.
Good morning! I know it is 4:00 PM where you are in the United Kingdom, but it is still morning for me—and I love mornings because each new morning offers a new day that is full of potential. The example that you referred to is exactly what you need to be doing, although it is a bit complex to control.
An easier method might be to use the third parameter of the Run method from the WshShell object that you are creating. This is discussed in the Scripting Guide. The third parameter is named blnWaitOnReturn and what it does is wait for the command to complete before moving to the next line of code in your script. The DemoBlnWaitOnReturn.vbs script shows this technique. We create two variables to hold the name of the programs that will be started. We then create a variable blnWaitOnReturn and set it equal to true. This is the third parameter of the Run method that will cause the script execution to stop until the program returns. The last variable we create is ActivateWindow, which we set equal to 1 (causes the program to start and to display a window).
Next we create an instance of the WshShell object and store it in the wshShell variable. We then call the Run method and pass each of the three parameters: the program name, the window state, and blnWaitOnReturn. When the script is run, it opens Notepad and waits. As soon as you close Notepad, Calculator starts. When you close Calculator, you are greeted with the dialog box seen here:
The DemoBlnWaitOnReturn.vbs script is seen here:
Prog1 = "Notepad"Prog2 = "Calc"blnWaitOnReturn = TrueActivateWindow = 1set wshShell = CreateObject("WScript.Shell")wshShell.Run Prog1,ActivateWindow,blnWaitOnReturnwshShell.Run Prog2,ActivateWindow,blnWaitOnReturnwshShell.Popup("Calculator was closed. Script exiting.")
When Exchange Server is finished installing, it may very well close the cmd window. If it does, you will be able to just use WshShell. Otherwise, you will be stuck with trying to create a temporary event consumer. I am adding some additional information about temporary event consumers as well as additional examples because if you have to go down that road, the syntax can be a bear. I know, I wrote the book on WMI (really), and it was very tedious.
By the way, in the Microsoft Press book on WMI, I have a complete chapter about how to work with events. The book is Microsoft Windows Scripting with WMI: Self-Paced Learning Guide.
Hey, Scripting Guy! I enjoy reading your “Hey, Scripting Guy!” articles, and I have a question. I have to log off a user when they become idle after a certain period of time. I want to do this by using script. Can you help me?
I am glad you are enjoying reading the “Hey, Scripting Guy!” articles. The only way I know how to log a user off from a computer is to use Windows Management Instrumentation (WMI). The WIN32_OperatingSystem WMI class provides this capability. This class is discussed in the Scripting Guide.
The only way I know how to detect when a computer is idle is to use a scheduled task on Windows Vista or later. This was recently discussed in the How Can I Run a Script When My Computer Is Idle “Hey, Scripting Guy!” article.
To log off a user by using Windows PowerShell, you would use a command similar to this one:
(Get-WmiObject -Class Win32_OperatingSystem).Win32ShutDown(0)
To log off a user using VBScript, the script would resemble the following:
strComputer = "."Set SWBemlocator = CreateObject("WbemScripting.SWbemLocator")Set objWMIService = SWBemlocator.ConnectServer(strComputer,"root\CIMV2")Set colItems = objWMIService.ExecQuery("Select * from Win32_OperatingSystem",,48)For Each objItem in colItems WScript.Echo "Logging off User" & objItem.Win32Shutdown(0)Next
Hey, Scripting Guy! Can you give me an explanation why running sample script on this MSDN page gives me an error? Here is the script:
strComputer = "."Set objWMIService = GetObject("winmgmts:\\" & _ strComputer & "\root\cimv2")set colProcesses = _ objWMIService.Execquery("Select * from Win32_Process")Wscript.Echo colProcesses.ItemIndex(0).NameWscript.Echo colProcesses.ItemIndex(1).NameWscript.Echo colProcesses.ItemIndex(2).Name
When I run the script, it gives me the following error:
C:\Temp\temp.vbs(10, 1) Microsoft VBScript runtime error: Object doesn't support this property or method: 'colProcesses.ItemIndex'
I (Ed) did not write the script. In fact it comes from MSDN and not from the Script Center. But it’s still a good question. If you examine the error message that you are receiving, you will see that VBScript is doing its best to tell you where the problem is. It tells you the Object does not support this property or method: 'colProcesses.ItemIndex'.
Now, this is where things become a bit difficult. The object that you have in the variable colProcesses is a SWbemObjectSet object, which in versions of Windows earlier than Windows Vista did not have an ItemIndex method. One of the new things that was added to WMI in Windows Vista is the ItemIndex method. So my guess is that you are trying to run the script on Windows Server 2003, Windows XP, or even Windows 2000 because the ItemIndex method did not exist on those versions of the operating system. We have a script that will work on those older operating systems in the Script Center Script Repository. It is in the Processes and Threads section of the Script Repository.
Hey, Scripting Guy! How do I close a folder after I open it with this script?
Set objShell = CreateObject("Shell.Application")objShell.Open("d:\")
What occurs is that occasionally a networked drive will go to sleep. I use this script to poke it, and then tell it to wake up. However, I do not want to leave it open all the time.
The Open method is documented on MSDN. It does not return anything, and the only thing we can do is dereference the Shell.Application object by setting it equal to nothing. This is seen here:
Dim objShellset objShell = CreateObject("Shell.Application")objShell.Open("C:\")Set objShell = nothing
Hey, Scripting Guy! I am trying to create an HTA script that will enable me to use standard Open/Save dialog boxes so that the client can browse for a file or folder and select it, passing the selected item back to my HTA script for processing. I know that you could do this under Windows XP. But all our computers are running Windows Vista.
The first bit of code I tried resembles the following:
'Opens Common file dialog allowing file selectionSub fileSelect set objShell = createobject("wscript.shell") strDir = objShell.CurrentDirectory Set ObjFSO = CreateObject("UserAccounts.CommonDialog") ObjFSO.Filter = "All Files|*.*" ObjFSO.InitialDir = strDir InitFSO = ObjFSO.ShowOpen If InitFSO = False Then exit sub Else strFileName.value = ObjFSO.FileName objOpenButton.disabled = "False" objResetButton.disabled = "False" End IfEnd Sub
The problem is that it gives me an error. Any assistance on this one would be greatly appreciated. By the way, the Wrap Your Scripts Up in a GUI Interface is absolutely fantastic. It is well written and very informative.
We are glad you like the Script Center. The UserAccounts.CommonDialog object was one of those weird things that just showed up in Windows XP one day. We have several articles that talk about how to use them, but the object was never even documented on MSDN. Unfortunately, we do not know of a workaround because the UserAccounts.CommonDialog object was removed because of security issues. But all is not completely lost. Here is a function that may work for you.
Make sure that the MSComDlg.CommonDialog program ID (MSCOMDLG32.OCX) is registered for the below to work. This object does not, however, seem to be available on all systems; it might be included with Visual Studio or Microsoft Office. We are not sure.
Function BrowseForFile(pstrPath, pstrFilter) Set objDialog = CreateObject("MSComDlg.CommonDialog") objDialog.Filter = pstrFilter objDialog.InitDir = pstrPath objDialog.MaxFileSize = 256 objDialog.Flags = &H80000 + &H4 + &H8 intResult = objDialog.ShowOpen() BrowseForFile = objDialog.FileNameEnd FunctionBrowseForFile "c:","*.vbs"
The BrowseForFileDialog.vbs script opens up the dialog box shown here:
If the previous code will not work for you, you still have access to items from shell.application object, which has a large number of methods for you to use. Here is an example of using the BrowseForFolder object from our Hey Scripting Guy! Archives.
We have reached the end of our mail bag for this week. This also brings to an end another exciting week in the world of scripting. Join us on Monday for a new set of topics as we dive into another “Hey, Scripting Guy!” series. By the way, we had a great week at Tech∙Ed 2009 in Los Angeles. We have enjoyed seeing all of you who were able to stop by the Scripting Guys booth and those who attended Ed’s presentation about scripting Windows 7. We will begin talking about Windows 7 on the Script Center as soon as Windows 7 ships. Until then, take care and enjoy the weekend.
Ed Wilson and Craig Liebendorfer, Scripting Guys
Regarding the ItemIndex method not being available on XP: then how does one access a particular item in a SWbemObjectSet collection? For example, I'm trying to use WMI to get the name of the default printer and I know it returns only one item in the collection, by definition, so it bugs me (as a fastidious programmer) that I seem to have to loop through a collection of 1 item to get what I want. Any pointers?
Thanks in advance.