Permanently removing Windows printers that keeps coming back

A simple change: a new Windows print server requiring a change in the printers installed using a Group Policy Targeting GPO (refer to this post from 2015 for more details).

Not so easy. Removing the old/existing printers were all but impossible. Nothing worked. Nothing. Others have had similar experiences; e.g. here, here, and here.

This is a two part post: 1) the actual removal script and 2) other online resources and discussion around the issue.

Removal Script

This script was used as GPO Computer shutdown script.

  1. Download:
  2. Edit the “shutdown_registry_printer_purge.bat” batch file. Go to Line 19 and 20 and change the server name in quotes for both lines. Two lines per printer.
    REM ------------------------------> Add these two lines per printer to remove and change server name <------------------------------
    rundll32 printui.dll,PrintUIEntry /gd /q /n"\\print\PaperCut"
    rundll32 printui.dll,PrintUIEntry /dn /q /n"\\print\PaperCut"
  3. Go to Line 23 and change the server name in quotes. One line per printer.
    REM ------------------------------> Add this one line per printer to remove and change server name <------------------------------
    ADPRINTX.exe /r "\\print\PaperCut"
  4. Edit the “printer_hive_cleanup.vbs” file. Go to Line 117 and 119 and change the server name in quotes for both lines. Two lines per printer.

    A special thanks to Mick for his wonderful vbs script. If you want a less forceful method, Mick also references a way to do per-user registry edit using Active-Setup (I did not test this method).
  5. Add the .bat file to a shutdown or startup script.
    The script must run as the SYSTEM user.

Other Resources on adding/removing Windows printers

  1. Removing a printer device FULLY – Microsoft Community 
  2. group policy – Deleted printers keeps coming back – and multiply – Server Fault 
  3. Problem with multiple instances of shared printers being installed on client computers when the spooler service is started 
  4. [SOLVED] All network printers automatically added for each user on 2012 R2 RDSH – Microsoft Remote Desktop Services – Spiceworks 
  5. Remove Printers by Name or Server – Script Center – Spiceworks 
  6. script to add new network printers 
  7. Set Default Printer if not in a specific group – Petri IT Knowledgebase Forums 
  8. Adding a network printer from the command line (or bat file) – Networking – Spiceworks 
  9. Script to remove obsolete printer in local profiles – Petri
  10. Hey, Scripting Guy! How Can I Remove All the Network Printers on a Computer?
  11. Printer mapping using GPP 
  12. Intermittent printer delivery failures with GPP – XenDesktop 7.x – Discussions 
  13. Logon Script Example Assign Printer – RUNDLL32 PRINTUI.DLL 
  14. scripting – Need to modify VB script so it deletes all existing network printers first – Server Fault 
  15. Adding and deleting printer drivers on Windows from INF files via command-line | Hajuria’s Blog 
  16. KB3170455 preventing printer installation 
  17. command line – Trying to use rundll32 printui.dll, PrintUIEntry to set up a printer, getting an error – Super User 


Search results aren’t quite ready yet, but we’re working on getting them together. Try back in a few minutes.

While I rely on Windows 10, this is classic example of reliability engineering.
Keep it simple.
Because of time constraints, posts will be short and to the point.

Cortana would not index files and as a result, Windows Search was effective non-functional. A clean reinstall with our current set of GPOs caused my domain account to crash Cortana. Even after excluding the suspect GPO, my user profile would still not allow Cortana to index files and Control Panel/Metro settings. The error was: “Search results aren’t quite ready yet, but we’re working on getting them together.  Try back in a few minutes.”

Google tells me many others are having the same issue: here, here, here here, here, and here if you want to read and learn more.
The fix? This assumes United Status English. If you want a different language, copy/paste the files from the same location from a system with the identical language; e.g. en-GB

  1. Download: en-US
  2. Extract to:
  3. If extracted correctly, double check the path:
  4. Reboot! Cortana and Window Search should be functional with complete results.

Another option is to remove the ability to search for Windows settings; refer to this thread.

Windows 10 Start Menu Crash/Freeze & Repair

For the reasons Windows 10 is an upgrade, a freezing start menu is beyond frustrating. After rebuilding the Windows Search database, confirming DISM is healthy, did a CHKDSK and System File Checker, I was running out of ideas.

Then I came across this: Reset Windows 10 Start Menu “TileDataLayer”. which led to Fix Windows 10 Start Button Does Nothing in 10 Minutes and a repair tool from Microsoft released in June 2016 (direct link). So this is a known issue.

Before becoming aware of the Microsoft utility, I did my own fix. Using a tool called Unlocker (portable version; part of my digital toolbox) you can forcibly rename/delete files locked by the system. FYI, Unlocker can cause false-positives with anti-virus software. If you are concerned, please upload your downloaded copy to VirusTotal for a second scan.

Using Unlocker, I went to the following location:unlocker_choose_folder


Hit “OK”. Action should be “Rename” and change the name to “DatabaseBackup“.


Finally you should get the following prompt; his “Yes”.


Let the system reboot.
Now – Reboot again – a second time

You will have to recreate your tiles but your start button should at least work and search.

What a mess: Exchange 2013 with Direct Booking and the AutoAccept Agent

In short, Direct Booking and all the associated mailbox delegation controls that were in Exchange 2003 became confusing in 2007 and became a mess in Exchange 2013.

This is a short, reference post.

At this point in time (Mid-2016) most people already experienced this pain but, through these links, I finally tracked down multiple issues with Room Resources not sending Accept/Reject emails to Delegates.

  1. Start with a simple explanation between the old and new ways:  Exchange 2003 Auto Accept Agent vs. direct booking & Booking Delegation Vs. Classic Delegation.
  2. Then use this Powershell script to discover which mailboxes and/or resources have Direct Booking enabled: Use Exchange Web Services and PowerShell to Discover and Remove Direct Booking Settings. Then use the “write” method to actually make the changes to the desired mailboxes. Read the include README file closely for prerequisites.
  3. Simple PowerShell to confirm and modify resources one-by-one: Two ways to grant access to a Resource in #MSFTExchange
  4. Lastly, and because we have a manageable number of Room Resources, go one-by-one and save them using the EAC. Decent double check because in at least one Microsoft Exchange Team blog post they mentioned that EAC does cleanup when it is saved post-upgrade. Specifically, a few rooms under “Booking Delegates” had a setting “Use customized setting to accept or decline booking requests”. Change the Room Resource to either “Accept or decline…” or “Select delegates…”.
    Before: custom booking delegates
    After:booking delegates

 Additional Reading:

  1. Setting Calendar Options For Resource Mailboxes In Exchange 2010…
  2. How to Create and configure a meeting room mailbox with Exchange Server 2007
  3. A Look at Exchange Server 2013 Resource Mailboxes
  4. Working with Resource Mailboxes in Exchange Server 2016
  5. Tool before the PowerShell script above: SetAA – Tweak Auto Accept Settings Across Mailboxes and an article explaining how to use it: Disable Direct Booking For All Room Mailboxes.
  6. I found the last step, saving in EAC, does mailbox cleanup. If not you can manually remove the mailbox from a room resource: I can’t disable a resource mailbox? Sez Who?
  7. Before screenshot above which was not well documented: Resources Booking Delegates Fix (AutomateProcessing: AutoUpdate)
  8. Exchange 2007: Resource delegate never receives forwarded meeting requests for approval 
  9. Useful method for appending information to meeting requests: Using Transport Rules to append text to Meeting Requests when Room Mailbox is selected as Resource

Bypassing “This program cannot run under VMWare or Virtual PC”

We had a specific application that did not want to run on as a virtual machine ( VMWare guest).

Sorry, this application cannot run under a Virtual Machine

“This program cannot run under VMWare or Virtual PC”
“Sorry, this application cannot run under a Virtual Machine”

Tell VMWare to prevent the guest from knowing its a virtual machine (VM).
Kudos to this post on

In this particular situation, all access to the guest was done over Remote Desktop Protocol (RDP); in other words, graphics performance was not critical.

NOTE: The modified VM will have poorer performance, especially with graphics, and VMware Tools will not work. This is an experimental configuration and not advised for long term use.

Shut down your VM. Add the following lines to the .VMX file of your VM (refer to this KB article from VMWare showing how to add these lines to different enciroments; e.g. Workstation, vSphere Client, etc.) = “TRUE” = “TRUE” = “TRUE” = “TRUE”
monitor_control.disable_directexec = “TRUE”
monitor_control.disable_chksimd = “TRUE”
monitor_control.disable_ntreloc = “TRUE”
monitor_control.disable_selfmod = “TRUE”
monitor_control.disable_reloc = “TRUE”
monitor_control.disable_btinout = “TRUE”
monitor_control.disable_btmemspace = “TRUE”
monitor_control.disable_btpriv = “TRUE”
monitor_control.disable_btseg = “TRUE”
tools.upgrade.policy = “manual”

Power-on your VM. Remove VMWare tools.
The problematic application should launch and run without issue. Enjoy.

cPanel Email Filtering to Stop Chinese or non-English Character SPAM

Customers complained about “Chinese SPAM” even after filtering was being handled by SpamExperts. This post is based on the good work from Dr. John.

I am long time cPanel/WHM user and customer for LAMP sites. I use EZPZ Hosting and highly recommend them; this an honest referral. Thankfully EZPZ uses SpamExperts to handle the “heavy lifting” for incoming SPAM filtering. However, even with SpamExperts, customers still got “Chinese SPAM” or emails containing non-English characters.

Here is a sample email that got through SpamExperts and needed to be blocked:

Here is how to filter it easily with cPanel regex:

  1. Login to cPanel
  2. Go to “Account-Level Filtering” (or User-Level Filtering if you want to pick a specific email address)
  3. Hit “Create New Filter”
  4. And enter the following:
    The drop-down shows a few good options. You can outright discard the message, which is easy, but I recommend the “Deliver to Folder”. This places the filtered emails in a users’ email folder (e.g. Junk E-mail folder) for review or retrieval in case any of these filtered emails are needed. All email that matches the regex will go to this users’ email folder. If you want to filter per user and not globally for the domain, the User-Level Filtering allows you to create the same regex filter for each user.

Group Policy Preferences + Preference Item-Level Targeting + Security Groups = One Big Mess

Microsoft. While Group Policy Preferences, when they work, work wonders, when they do not work or the UI breaks them, I lose all confidence.

USE CASE: we recently deployed PaperCut across our multi-function printers (MFPs). [PaperCut, BTW, is an excellent product, especially for Healthcare and HIPAA compliant environments.] Globally I pushed the default, PaperCut virtual printer to all PCs. Users can print to the virtual and then then fetch their print jobs securely on any MFP across campus running the PaperCut embedded application.

However, we had certain user AND computer exceptions to the default printer; e.g. local USB printers or Terminal Services/RemoteApp servers. Loopback merging can get complex rather quickly (another good, quick refresher here). Group Policy Preferences Item-Level Targeting is a better solution. Read about it here from Microsoft directly.

In my default printer example, the intent is to exclude users and computers. To make it easy to manage, I created a Security Group name “PaperCut-NonDefault” that contained both users and computers I wanted to exclude. I then set “Targeting…” on the PaperCut preference.

In the Targeting Editor I created the following logic:PaperCut-Targeting

Now, up until this point, every seemed very straight-forward and yet the Targeting refused to work properly. If I added the users and computers directly into the Targeting Editor, I was able to get it working perfectly. The moment I used a Security Group, everything broke.

After sleeping on the problem, I finally came across this wonderful post. In short, do not use the “…” button to select your Security Group. Re-read that. In other words, do not use the DOMAIN\SECURITY_GROUP convention; just use the Security Group name only (as I have highlighted in the screenshot above). Based on the comments it appears that Microsoft has a hotfix which may solve the issue but I chose to fix it by dropping the “DOMAIN\”. Also note that I have two “Items” both calling the “PaperCut-NonDefault” Security Group. Targeting Security Group “Items” can only apply to either a computer or user; not both in one item. By having two items, I have one for users, one for computers.

With this subtle but critical change in place, the default printer Targeting works very effectively excluding certain users and computers. To make it even easier for our users, I added a second printer preference that ONLY applied to those in the “PaperCut-NonDefault” group which adds the PaperCut printer but does not set it as default. In other words, even users who do not want PaperCut as their default printer, they still get the PaperCut printer as an option.PaperCut-Targeting-NonDefault

Enjoy. When Targeting works, its effective and powerful. Here are 10 things Group Policy Preferences can do better than your current script!

Disabling Hidden Shares in Windows 10 (& Windows Vista, Windows 7, and Windows 8.1)

A simple post confirming that the same registry key works in Windows 10.
Based largely off of this ITworld write-up by Paul McFedries.

As is commonly known, a “$” in a Windows share name makes it “hidden”. This does not mean it is any more secure; it only obscures the name. That said, Microsoft, by default, enables hidden shares for “Administrative” purposes, including one for the system drive, C: (C$), and any other hard disk partitions you have on your system. Windows Vista+ also sets up the following hidden shares:

Share Shared Path Purpose
ADMIN$ %SystemRoot% Remote administration
IPC$ N/A Remote interprocess communication
print$ %SystemRoot%\System32\spool\drivers Access to printer drivers

Open an elevated Command Prompt and type “net share” and press Enter. You see a listing similar to this:

Share name   Resource                        Remark
C$           C:\                             Default share
D$           D:\                             Default share
ADMIN$       C:\WINDOWS                      Remote Admin
IPC$                                         Remote IPC
print$       C:\System32\spool\drivers       Printer Drivers
Public       C:\Users\Public                 

So although the C$, D$, and ADMIN$ shares are otherwise hidden, they’re well known, and they represent a small security risk should an intruder get access to your network. To close this hole, you can force Windows Vista to disable these shares. Here are the steps to follow:

    1. Click Start, type “regedit” in the Search box, and then click regedit.exe in the search results. The User Account Control dialog box appears.
    2. Say “Yes” to the UAC prompt and the Registry Editor should open.


  1. Open the HKEY_LOCAL_MACHINE branch.
  2. Open the SYSTEM branch.
  3. Open the CurrentControlSet branch.
  4. Open the Services branch.
  5. Open the LanmanServer branch.
  6. Select the Parameters branch.
  7. Select Edit, New, “DWORD (32-bit) Value”
  8. Type “AutoShareWks” and press Enter. (Leave the default value of 0.)
  9. Reboot or restart the “server” service using a Command Prompt: “net stop server” then “net start server”.

Once again, open an elevated Command Prompt and type “net share” and press Enter. The output should now looks like this:

Share name   Resource                        Remark
IPC$                                         Remote IPC
print$       C:\System32\spool\drivers       Printer Drivers
Public       C:\Users\Public                 

FYI – Its possible certain applications require the hidden shares.  To disable or rollback to “default” simply remove the “AutoShareWks” Registry Key or change the value to “1”.

KeePass batch scripting for secure and automatic databases on boot or login using PASSWORD_ENC

KeePass. The venerable KeePass.
You need to use a password manager. Not a Word or Excel document. Not a napkin or Post-it note. A real password manager. I recommend KeePass. You may prefer LastPass or SplashID. Regardless, I reiterate: you need to use a password manager.

Having used KeePass 8+ years and with hundreds of saved passwords, it is one of my most used applications. Anything that falls under PCI or HIPAA is in a KeePass database.

All that said, KeePass is typically the first program I execute upon logon. If you are following best practices, upon logon, you then have to type a very long password accompanied by a keyfile (optional) to open your KeePass database. I am not going to cover in this post what makes a strong password and what are appropriate password lengths.

You might ask, why not just use Windows user accounts introduced in KeePass 2.x? Two main drawbacks: 1) If your Windows user profile (UID) is corrupt/lost, you cannot access your KeePass database, and 2) if you want to synchronize your database, it cannot use Windows user accounts.

So, how to do you securely launch KeePass using command line without putting your password in the batch file as plaintext?

Based on the excellent post in this superuser thread along with more guidance from this post, you can securely script your KeePass databases. Here is how:

  1. Create a file called “RunMeKeePass.bat”
  2. Right click on the file and choose Edit.
  3. Go into your KeePassdatabase your want to script, and create a new, temporary entry called “RunMeKeePass.bat” (or whatever you called the filename in step 1).
  4. Go to the “Auto-Type” tab and hit the “Override default sequence” radio button, and copy/paste “{PASSWORD_ENC}” into the field.
  5. Leaving KeePassopen, go back to Notepad where you are editing the empty “RunMeKeePass.bat”. Hit Crtl+Alt+A to active the KeePass auto-type feature. Read more here about it if this step does not work or if you changed the default hotkey. Auto-type is one of the best features of KeePass. After hitting Crtl+Alt+A, KeePass should start spitting out a very long password string. You can read more about {PASSWORD_ENC} here, towards the bottom. In short, is long, generated string is a unique password for your KeePassdatabase that only works under your current username. This is what makes the method secure. You assume you have a secure user session because you as a user are scripting it. If someone manages to take this unique password string, it will not work on another PC/user opening the same/original KeePass. It only opens your KeePass database under your Windows user on this unique PC (UID/SID).
    Save this string.
  6. Now its time to script the password string into actually launching KeePass.
    Here is example .bat file script:

    echo KeePass DB #1 without a keyfile
    START "" "%programfiles(x86)%\KeePass Password Safe 2\KeePass.exe" %DATABASE% -pw-enc:%PASSWORD_ENC%
    echo KeePass DB #2 WITH a keyfile
    START "" "%programfiles(x86)%\KeePass Password Safe 2\KeePass.exe" %DATABASE% -keyfile:%KEYFILE% -pw-enc:%PASSWORD_ENC%
    echo Re-opening KeePass DB #1 to bring it in focus
    START "" "%programfiles(x86)%\KeePass Password Safe 2\KeePass.exe" %DATABASE% -pw-enc:%PASSWORD_ENC%
    REM To Generate the pw-enc password string (which is specific to the Window user's UID), create a "dummy entry" in KeePass.
    REM Courtesy of:
    REM and
    REM and

    Basically replace “<COPY/PASTE THE LONG, AUTO-TYPED PASSWORD STRING>” with the auto-typed password from the earlier step. In Line 2, set the correct location for your KeePass database (.dbbx) file. Line 3 is for 64-bit Windows7/8/10; for 32 u(x86) for 32-bit versions.

    I provided multiple examples. The 2nd example uses a keyfile. Should be self-explanatory.

    You may also wonder why I commented “Re-opening KeePass DB #1 to bring it in focus”. KeePass, when it opens multupe tabs, keeps track of the order which files are opened. When you have multiple files and you use auto-type with multiple matches, the order of the UI is based on the order of opened files. By “re-opening” the first file, it bring that database tab to the forefront but it is still opened first keep it at the top of auto-type matches.

  7. The last step is to launch your “RunMeKeePass.bat” file. I chose to use Task Scheduler; Tigger=”At log on” and it calls the .bat file. I unchecked the “Start the task only if the computer is on AC power” (since I primarily use this on a Surface Pro 3). Read here if you need additional help in creating the Scheduled Task. The Task Scheduler “triggers” are rather powerful; e.g. if you configured KeePass to automatically lock your database after a certain amount of time, you could add additional triggers for “On workstation unlock” and “On connection to user session” for local and remote computers and open/close KeePass depending on your application.
    Another option is to run have a shortcut placed in the “Startup” folder; read more here for details on how to create it.

Now that you can more easily launch KeePass, you have no excuse not to use it (or  something like it). Enjoy.

Safely grant only your PowerShell session “bypass” permission; “the file is not digitally signed. You cannot run this script on the current system.”

In short, this is my future quick reference:

Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass

This sets the execution policy for only this session (process) of PowerShell and do not make the change permanent.

In contract, do not run:

Set-ExecutionPolicy RemoteSigned

This will set the policy for your LocalMachine, leaving you open to malicious PowerShell scripts in the future. Don’t do it.

See more here, here, and here if you want more information.

(I most recently used this “byass” for this excellent Exchange script to export all of our internal Distribution groups with one simple command)