Search code examples
vbscriptshutdown

Shutdown of remote computers not working


I am writing a script for a class that will look at every computer on the network and then shutdown each computer. I have the first part of the script working. However, the second part of the script doesn't seem to be doing anything.

Here is the part of the Script that is not working.

Sub shutdown
  'Open a text file of computer names with one computer name per line
  'get the next computer name store it in variable strMachine
  'go through the text file
  const READ=1
  Set fso = CreateObject("Scripting.FileSystemObject")
  set objFile = fso.GetFile("c:\comp230\computers.txt")

  If objFile.size > 0 Then
    Set objReadFile=fso.openTextFile("c:\comp230\computers.txt", READ)
    Do Until objReadFile.AtEndOfStream
      strline = objReadFile.ReadLine()
      'If strMachine = Vlab-PC1 Then 
        'Exit Do
      'End If
      Set WshShell = WScript.CreateObject("WScript.Shell")
      WshShell.Run "cmd.exe  /c shutdown -s -f -m" & strline & " /c " & _
        strWarning & " /t " & strDelay, 0, False
    Loop
    objReadFile.Close
  End If
  'close the text file
End Sub

I have narrowed down the problem to this line:

WshShell.Run "cmd.exe  /c shutdown -s -f -m" & strline & " /c " & _
  strWarning & " /t " & strDelay, 0, False

Solution

  • As others have already pointed out, you need a space the parameters of the shutdown command require a space between them and their argument. From the command help:

    Syntax
    shutdown [{-l|-s|-r|-a}] [-f] [-m [\\ComputerName]] [-t xx] [-c "message"] [-d[u][p]:xx:yy]

    Parameters
    […]
    -m [ \\ ComputerName ] : Specifies the computer that you want to shut down.
    -t xx : Sets the timer for system shutdown in xx seconds. The default is 20 seconds.
    -c " message " : Specifies a message to be displayed in the Message area of the System Shutdown window. You can use a maximum of 127 characters. You must enclose the message in quotation marks.

    Whether you use the form -p or /p is irrelevant, shutdown.exe accepts both.

    If you provide IP addresses as arguments for the parameter -m the leading \\ are not required, and the double quotes around the argument for the parameter -c are only required if the text contains spaces. They won't hurt otherwise, though.

    Also, running the command with cmd.exe is optional, since shutdown is an executable (not a CMD builtin command like dir), and you don't use anything CMD-specific, like output redirection.

    Basically, your shutdown commandline should look like this:

    "shutdown -s -f -m " & strline & " -c """ & strWarning & """ -t " & strDelay
    

    or (if you're using hostnames instead of IP addresses) like this:

    "shutdown -s -f -m \\" & strline & " -c """ & strWarning & """ -t " & strDelay
    

    On a more general note, when troubleshooting external commands in a VBScript it's always a good idea to build the command string in a separate variable, so you can echo it in order to a) inspect it for syntactical correctness and b) verify that the inserted values actually are what you expect them to be:

    cmd = "shutdown -s -f -m " & strline & ...
    WScript.Echo cmd
    WshShell.Run cmd, 0, False
    

    If the command produces errors or other output relevant for troubleshooting you need to make its window visible and prevent it from automatically being closed. Run the command with cmd /k and set the 2nd parameter to 1, so you can inspect the output it generates:

    WshShell.Run "%COMSPEC% /k " & cmd, 1, True
    

    Running the command synchronously (3rd parameter set to True) prevents loops from flooding your desktop with command windows.

    An alternative to displaying the window is to redirect the output to a log file:

    WshShell.Run "%COMSPEC% /c " & cmd & " >> ""C:\path\to\your.log"" 2>&1", 0, True
    

    >> appends to the log file (so it doesn't get overwritten in a loop), and 2>&1 includes error output. On the rare occasion that a program generates output on handles other than STDOUT (1) and STDERR (2) you need to redirect those as well (3>&1, 4>&1, …). You'll still want to run the command synchronously here to avoid concurrent write access to the log file.