9

I have a requirement to run a batch script every time a system is shut down, no matter if the computer is connected to the network or not. (It shouldn't matter for the question, but the script in question clears the print queue of the machine.

However, I can't get this script to run when the PC is offline from the network, when I use this method below.

I might also add that the PC in question is running Windows 10 Pro x64 (version 1809). The domain controller is running Windows Server 2008 R2, and this is also where I've run gpedit.msc.

What I have done so far :

  • Created an Active Directory Group Policy Object with a machine shutdown script.
  • Added the script to the GPO folder on the SYSVOL.
  • Confirmed that this GPO is indeed downloaded to the hard disk of the workstation in question and should therefore be accessible offline.
  • The paths specified in the GPO are relative, not absolute.

What I want to happen:

  • When the PC is shut down, the ClearPrintQueue.bat script is run irrespective of whether the PC currently has a network connection or not.

What actually happens:

  • When the PC is shut down, the ClearPrintQueue.bat script is only run if the PC can currently reach the SYSVOL share over the network.

Details:

What I have done is to create a Group Policy Object in the domain and link it to a Test OU that contains the machine in question.

I edited the GPO and navigated to Computer Configuration -> Policies -> Windows Settings -> Scripts (Startup/Shutdown) -> Shutdown

The Shutdown Properties as as per below:

Shutdown Properties

When clicking on Show Files... the explorer opens to reveal the folder \\example.com\SysVol\example.com\Policies\{1B61F884-9D14-4065-8265-F04FFDE41683}\Machine\Scripts\Shutdown

The contents of this folder and the file ClearPrintQueue.bat are as per below:

PS C:\> Get-ChildItem "\\example.com\SysVol\example.com\Policies\{1B61F884-9D14-4065-8265-F04FFDE41683}\Machine\Scripts\Shutdown"


    Directory: \\example.com\SysVol\example.com\Policies\{1B61F884-9D14-4065-8265-F04FFDE41683}\Machine\Scripts\Shutdown


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----       2019-04-23     15:00             71 ClearPrintQueue.bat


PS C:\> Get-Content "\\example.com\SysVol\example.com\Policies\{1B61F884-9D14-4065-8265-F04FFDE41683}\Machine\Scripts\Shutdown\ClearPrintQueue.bat"
net stop spooler
del %systemroot%\System32\spool\printers\* /Q /F /S
PS C:\>

When investigating a local PC, I can find that the script is indeed copied down into the PC:s local GPO store:

PS C:\> Get-ChildItem -Recurse -Force -File "C:\Windows\System32\GroupPolicy\DataStore\0\SysVol\example.com\Policies\{1B61F884-9D14-4065-8265-F04FFDE41683}"  


    Directory: C:\Windows\System32\GroupPolicy\DataStore\0\SysVol\example.com\Policies\{1B61F884-9D14-4065-8265-F04FFDE41683}                            


Mode                LastWriteTime         Length Name                           
----                -------------         ------ ----                           
-a----       2019-04-23     15:00             59 gpt.ini                        


    Directory: C:\Windows\System32\GroupPolicy\DataStore\0\SysVol\example.com\Policies\{1B61F884-9D14-4065-8265-F04FFDE41683}\Machine\Scripts            


Mode                LastWriteTime         Length Name                           
----                -------------         ------ ----                           
-a-h--       2019-04-23     15:00            118 scripts.ini                    


    Directory: C:\Windows\System32\GroupPolicy\DataStore\0\SysVol\example.com\Policies\{1B61F884-9D14-4065-8265-F04FFDE41683}\Machine\Scripts\Shutdown   


Mode                LastWriteTime         Length Name                           
----                -------------         ------ ----                           
-a----       2019-04-23     15:00             71 ClearPrintQueue.bat            


PS C:\>

Investigating into scripts.ini and ClearPrintQueue.bat on the local disk of the PC we find:

PS C:\> Get-Content "C:\Windows\System32\GroupPolicy\DataStore\0\SysVol\example.com\Policies\{1B61F884-9D14-4065-8265-F04FFDE41683}\Machine\Scripts\scripts.ini"                                                                              

[Shutdown]                                                                      
0CmdLine=ClearPrintQueue.bat                                                    
0Parameters=                                                                    
PS C:\> Get-Content "C:\Windows\System32\GroupPolicy\DataStore\0\SysVol\example.com\Policies\{1B61F884-9D14-4065-8265-F04FFDE41683}\Machine\Scripts\Shutdown\ClearPrintQueue.bat"                                                             
net stop spooler                                                                
del %systemroot%\System32\spool\printers\* /Q /F /S                             
PS C:\>

I.e. the computer has everything it needs to actually run the shutdown script without reaching out to the network. But yet, I have observed that the script does not seem to run when a network connection is missing.

Further investigation using a packet capture and WireShark further seems to prove that the PC does in fact pull the script down from the SYSVOL share (why! It's right there on disk...) The time stamps correspond to when the computer was being shut down.

Wireshark packet capture showing how the script is pulled down from disk at shutdown time

Possible workaround:

One possible workaround that I have not yet tested involves manually specifying the absolute path of the script C:\Windows\System32\GroupPolicy\DataStore\0\SysVol\example.com\Policies\{1B61F884-9D14-4065-8265-F04FFDE41683}\Machine\Scripts\Shutdown\ClearPrintQueue.bat rather than just specifying ClearPrintQueue.bat as a relative path. This seems very hacky though, and doesn't seem to be how it's "meant" to work. Before I go down that route I'd love to see if anyone else has a better idea.

Why I am even trying to do this:

I have mobile users who like to accidentally print to the wrong printer, and those are then queued up locally on each workstation, and subsequently when the PC is connected to the site where that printer is, a deluge of paper comes out of the printer. VPN software is run on the "user" level, and thus the VPN software might well not be running when it's time for shutdown.

I'm trying to mitigate this by clearing the print queue on shutdown, so that ancient print jobs don't sit in the queue forever.

Per von Zweigbergk
  • 2,615
  • 2
  • 17
  • 27

1 Answers1

10

It's by design. Microsoft never said that the startup/shutdown scripts will be executed when the computer is offline.

The local cache you found is not there for offline processing, but to avoid that the clients overwhelms the domain controllers. You can find more details about this particular point here: Group Policy Core Protocol: Cache of GPO Version

Additionally, the Group Policy Script Extension requires that the client must be able to validate the source of the script. And as you can see on the following diagram, the GP Server (Domain Controller) is the core of the Group Policy Scripts Extension:

https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-gpscr/ms-gpscr_files/image001.png

In order to solve your problem, I suggest you to try this instead:

Create a Scheduled Task via Group Policies Preferences (Computer Configuration -> Preferences -> Control Panel -> Scheduled Tasks) and create a New Scheduled Task (at Least Windows 7), configure the task to run as System, add the following trigger: On disconnect from user session.

Then, create another Preference ("File" instead of "Scheduled Task") to copy your script in a secured local path on the computers (the users must not be able to write in this file to avoid privilege escalation). You can use something else to copy the file if you want, but don't forget to reference it in the Scheduled Task Preference.

Swisstone
  • 6,357
  • 7
  • 21
  • 32
  • 3
    It doesn't have to be a scheduled task, you can still use a shutdown script, the script just needs to be on the local disk rather than sitting in the GPO. – Harry Johnston Apr 23 '19 at 19:43
  • 2
    Thank you for the links, they do indeed elucidate why Group Policy does what it does. From my understanding, this tells me that there's no good reason to put a script inside of a GPO folder anyway. Putting it outside stops it getting copied to each workstation needlessly, and putting it inside confers no benefits. I ended up using a "File" in GPO to explicitly copy the script onto the machine from a network share, and then use an absolute file path to execute it. I didn't end up using a scheduled task. Thanks for the tip about security also. – Per von Zweigbergk Apr 24 '19 at 08:43