Tuesday, 7 November 2023

PrintNighmare-safe Printer Management

Hello Folks,

Hopefully this post will help many out there who may struggle to emulate a Point-and-Print solution but without compromising the security of the corporate network.

For those new to the topic, Microsoft tightened the security of the printing subsystem as a result of a number of critical vulnerabilities, commonly referred to as PrintNighmare - details here. The fix consists in limiting driver installation to administrators only. To clarify, before the PrintNightmare security measures, end users were allowed to install printer drivers.

Given that lots of administrators have implemented Point-and-Print, this security measure broke printing for lots of organizations. Microsoft provided a workaround, which effectively cancels the security measures, by means of a Registry setting. It is well documented in various places such as this. Basically by implementing the Registry hack, you'd revert back your printing subsystem to its pre-patch, vulnerable state  by allowing end users to install printer drivers.

The core of the problem is to get the drivers onto the client computers without user interaction.

This post is meant to address the following issues:

  1. Install printer drivers on users' computers.
  2. Eliminate security prompts and user interaction.
  3. Automate the process and centralize administration.
  4. Maintain security (no need to undo Microsoft's security measures via the Registry hack).
  5. Use only built-in tools pre-canned with the operating system.

CAVEAT: I do not claim by any means that it is a perfect solutions. There is plenty of room for improvement. Likely you'll have to adapt it to your needs in case you run a large, multi-department and/or geographically distributed environment. Make it suit your needs.

In a nutshell the process is as follows:

  1. Set up the print server: install drivers, create ports, install, configure and share printers (ensure they are published in Active Directory).
  2. Create a new GPO or nominate an existing one to distribute printers to users. Create shared printer definitions in User Configuration / Preferences / Control Panel Settings / Printers. Link it to the OU holding your users.
  3. Use item-level targeting to define who gets what printer. Also make sure that the process runs in the logged-on user's security context.
  4. On the print server, export device drivers to a shared folder that client computers can access.
  5. Create a new GPO or nominate an existing one to distribute a computer startup script. Link it to the OU holding your client computer objects.
  6. Reboot the client computers to make them run the computer startup script. The script imports the drivers that have been exported at point 4 above. It runs in the System security context, administrator by definition, therefore no security prompt is displayed.
  7. Users will be connected to their printers as defined in the GPO at point 2 above.
At points 2 and 5, depending on your environment, you may use a single, dedicated GPO linked to both user and computer OUs (or to the domain root to that matter if such is your environment - I recommend against it though).

At the core of the solution there are two PowerShell scripts:
  1. A server-side script running on the print server that exports drivers.
  2. A client-side script running on client computers that imports pre-filtered drivers of shared printers.
We will not go into configuring GPOs and shared printer setup as it is well documented on the Internet. The 7 steps above should provide sufficient information to get you started.

Following is the two-step process to set up the scripts.

I. Setting up the print server

The following is to be done on the print server:
  1. Create a folder to store the exported drivers, e.g. C:\SharedPrinterDrivers.
  2. Share the folder, e.g. Drivers$ (I like to create hidden shares for such things).
  3. Grant the Domain Computers security group Read permission at share and NTFS level.
  4. Create the driver export script and save it to folder, e.g. C:\Scripts\ExportSharedPrinterDrivers.ps1
  5. Create a scheduled task to run the driver export script on a regular basis.
My suggestion is to run the script daily, early in the morning, before users power on their computers,. This way drivers updated overnight by Windows Updates (or equivalent server maintenance tools) would be captured in the export and distributed to users when they log on.


The driver export script:

Wednesday, 18 October 2023

List Details of AD-joined Servers

Hello again,

I had a task recently to install an update on a number of AD domain-joined servers. I had to make sure that no server was missed.

In my case checking that all servers are at a given build number was sufficient.

Here is the one-liner that will display this information:

$arrServers = @(); Get-ADComputer -Filter * -Properties OperatingSystem | ?{$_.OperatingSystem -match "Server"} | sort Name | ForEach-Object {$Name = $_.Name; $OS = $_.OperatingSystem; $Version = $null; $Build = $null; $osDetails = $null; $osDetails = Invoke-Command -ComputerName $Name -ScriptBlock {Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion"}; if ($osDetails.CurrentMajorVersionNumber) {$Version = $osDetails.ReleaseId; $build = $osDetails.CurrentMajorVersionNumber.ToString() + "." + $osDetails.CurrentMinorVersionNumber.ToString() + "." + $osDetails.CurrentBuildNumber.ToString() + "." + $osDetails.UBR.ToString()}; $arrServers += New-Object -TypeName PSObject -Property @{Name = $Name; OS = $OS; Version = $Version; Build = $Build}}; $arrServers | ft

Open PowerShell as Administrator and simply paste the script.

To be noted that it does no error handling except for checking for the existence of the CurrentMajorVersionNumber value of the "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion" Registry key as a rudimentary means to filter out old operating systems. If you'd like something more sophisticated then you'll want it turned  into a proper script with all the bells and whistles.

However, for a one-off quick check it does the job.

Sample output:


Have a great scripting day!



Friday, 6 October 2023

Find Entra Connect / AADConnect Versions in Partner Tenants

Hello again,


I have been tasked to find out which of our M365 client tenants need their Entra Connect / AADConnect agent updated. Came up with this little script:


Connect-MsolService

$tenants = Get-MsolPartnerContract

$arrCI = @()

ForEach ($tenantId in ($tenants).TenantId) { $arrCI += Try { Get-MsolCompanyInformation -TenantId $tenantId -ErrorAction Stop} Catch { "Error" } }

$arrCI | ?{$_.DisplayName} | sort DisplayName | select DisplayName,DirSyncClientMachineName,DirSyncClientVersion,DirectorySynchronizationStatus


Tweak it to your liking.

Monday, 29 May 2023

Enable Remote Event Log Access

I was in a situation recently when I had to collect RDS host logon details from a farm with 20-odd servers. While I already had a script that collected this kind of information from another set of servers, it didn't work on this particular farm.

As it turned out, the firewall blocked RPC access to event logs. I had to enable the "Remote Event Log Management (RPC)" firewall rule on each server.

Yes, it can be done manually one by one. No, that's not how I prefer to do things at scale.

Run this one-liner as administrator on the RDS Broker server to do it the quick way:

(Get-RDServer -Role RDS-RD-SERVER).Server | ForEach-Object { Invoke-Command -ComputerName $_ { Set-NetFirewallRule -DisplayName "Remote Event Log Management (RPC)" -Enabled true }}

More generically, you can run the following to achieve the same for any firewall rule on an arbitrary list of servers:

@("SERVER1","SERVER2", ..., "SERVERn") | ForEach-Object { Invoke-Command -ComputerName $_ { Set-NetFirewallRule -DisplayName "display_name_of_firewall_rule" -Enabled true }}

Replace -Enabled true with -Enabled false to disable the rule.

A word of caution: since we are playing with firewall rules on a large number of servers, one wrong parameter will have a spectacular effect in a bad way - have your your resignation letter handy. Before you unleash your custom code on your entire infrastructure, make sure you've tested it thoroughly.

You've been warned.

Have fun!


Tuesday, 17 August 2021

PrintNightmare Nightmare

Hello folks, Zoltan again. This time with a printer story.

The short version: Have you installed the August 2021 update, KB5005030n update and started seeing the infamous "Do you trust this printer?" warning? Well, learn to live with it or disable the security measures implemented by the update.

The meat around the bone: as a consultant and system admin, I've deployed numerous systems where printers are deployed and administered centrally using Microsoft's Point and Print technology. Moved all local and shared printers from individual PCs to a central print server. Give a user a new laptop, join the domain, and (s)he'll get all the printers. Life's good. Or so it was until PrintNightmare has been identified and Microsoft released its August 2021 security update, KB5005030.

The update changes the the security model of the Point and Print driver installation, requiring administrative approval to install or update signed or unsigned printer drivers. Yes, signed drivers too. From the article:

Since then, August the 10th 2021 that is, users who installed this update and their printers are installed via Point and Print, have been plagued with this warning, unable to print their documents:



The gist of it: all, (and by that Microsoft means ALL) computers running the Print Spooler service, workstations included, are vulnerable to the PrintNightmare vulnerability and therefore Microsoft's approach is to block all non-administrative users from installing printer drivers. Or stop printing altogether (no joke, see more about it further down).

As at now there are two realistic options:

1 - Whenever the warning appears, call the admin to input administrative credentials to install the driver. Depending on your environment you may have hundreds or thousands of workstations, each with multiple printers, each requiring administrative attention.

2 - Roll out the following Registry value to practically undo Microsoft's security measures and revert back to the original behavior. Beware, this way you'll expose your network to the PrintNightmare threat:

Registry location: HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows NT\Printers\PointAndPrint
Name: RestrictDriverInstallationToAdministrators
Type: DWORD
Value: 0

More details in Microsoft's MSRC team's blog and in the KB5005652 (CVE-2021-34481) article.

Microsoft touts a 3rd option, disabling the Print Spooler service, practically going back to pre-printer era of making hard copies (a.k.a. pen and paper with your own two little hands). From the article:


Now that you know your risks and options, you can start working out your long-term corporate printing strategy.

Enjoy :-)

Friday, 5 March 2021

Stuck in Pending Reboot Cycle

Hello again,


Microsoft released a bunch of security updates on March 2, 2021 (KB5000871) addressing a number of Exchange server vulnerabilities. Details here. But that's not the point of this post.

Exchange admins, myself included, started rolling out the update. However in one instance a server was stuck in a "pending reboot" state:


The information for pendingreboot is stored in the Registry. Not wanting to rediscover the wheel, searched for an easy way out: a script which looks for entries that control pending reboots.

Came across Adam Bertram's article. He not only has a good list of Registry entries to check, but provided a PowerShell script also to make it easy.

Using his script I quickly found that the RebootPendinig Registry key was present. The script in its original form only shows whether it is pending reboot or not, but it doesn't show which key or value it is. I altered the script to show this detail also:


Checking in Registry Editor confirmed it:


Please note that it is an empty key. Its sheer presence will trigger the pending reboot condition.

For more on this key see this Microsoft Scripting Guy article.

Having rebooted the computer, it was safe to delete the key. But...:


The fix:

  1. Took ownership of the key. The original owner is System.
  2. Added myself with Full Access permissions.
  3. Delete the key.

Once the key was deleted, the patch installed just fine.

Until next time.



Wednesday, 21 August 2019

"Important" Update Bound to Break Your Exchange Server. Again.

Hi There,

I've done a routine manual patching of one of the Windows 2012 R2 servers, and, instead of hitting the Install button, as many of us do (they are all "Important" updates after all so why not just install them all, right?), I looked at what is going to be installed.

To my surprise I saw .Net Framework 4.8 on the list:



WHAAAAT??? .Net version upgrade as "Important"?

Yes, Microsoft is doing it again: they are shoving it down the throat without thinking of the consequences. They ruined a couple of Exchange servers about a year ago - more details here.

A word of advice:

  • Don't just blindly accept all updates just because they are listed as "Important".
  • Have your Exchange patched to the latest CU.
  • Consult the Exchange .Net supportability matrix.

The Exchange team has put up this warning on its .Net supportability matrix:


Specific for hybrid deployments, if you want to stay supported, you must run the latest, or the immediately previous release of Cumulative Updates / Update Rollups - see here. If you have, for instance, a Hybrid Exchange 2016 on CU12, hence supported (at the time of this writing), and don't want to update to CU13 just yet, then think again: a routine Windows Update exercise may bring your messaging system to its knees:


Thank you .Net team, yet another not-so-well-done upgrade.