Monitor Print Server Activity

I was recently approached by management and asked to monitor an older print server to see who was still using it.  They wanted a report that would show which users and machines were still using this print server so they could correct old printer mappings.  Well of course Microsoft gives us no easy way to do this out of the box so it was time to get creative.  Here is the method I used to enable logging and generate a nice pretty TPS report from the data.

Enable Print service logging on the print server
1. Open the event viewer
2. Expand application and service logs > Microsoft > Windows > PrintService
3. Right-click the operational log, click enable log.

Now that logging is enabled you will begin to see the logs fill up with print jobs (Event 307). I let this run for about a week so we could get plenty of data. You may need to adjust the size of the log because I found it filled up way too quickly. The default is 1MB which is stupid low.
Now on to generate a pretty report for these guys. As it turns out this sounds so easy but in fact is a PITA. You can export the log to CSV but there are several issues with this, the biggest one is it exports the users SID instead of username, which of course makes sense because we all know the SID for each user right? There are also several formatting issues with exporting to CSV and long story short, it just didn’t work, you’re welcome to try that on your own if you think I am crazy. What I really needed was a way to pull the XML params out of the detail section of each event and export that to CSV. To accomplish this we turn to our friend, Powershell.

$PrinterList = @()
$StartTime = "04/10/2014 12:00:01 PM"
$EndTime = "04/18/2014 6:00:01 PM"
$Results = Get-WinEvent -FilterHashTable @{LogName="Microsoft-Windows-PrintService/Operational"; ID=307; StartTime=$StartTime; EndTime=$EndTime;} -ComputerName "localhost"

ForEach($Result in $Results){
$ProperyData = [xml][/xml]$Result.ToXml()
$PrinterName = $ProperyData.Event.UserData.DocumentPrinted.Param5
$hItemDetails = New-Object -TypeName psobject -Property @{
DocName = $ProperyData.Event.UserData.DocumentPrinted.Param2
UserName = $ProperyData.Event.UserData.DocumentPrinted.Param3
MachineName = $ProperyData.Event.UserData.DocumentPrinted.Param4
PrinterName = $PrinterName
PageCount = $ProperyData.Event.UserData.DocumentPrinted.Param8
TimeCreated = $Result.TimeCreated
}

$PrinterList += $hItemDetails
}

#Output results to CSV file
$PrinterList | Export-Csv -Path "C:PrintAudit.csv"

 

This script runs locally on the print server and pulls all the info I needed and dumps into a CSV that can then be fondled within excel.  Optionally, you can run this remotely by changing the –ComputerName param at the end of line 4.  Of course, you do need to modify the start and end times to your needs.

VSS System Writer Missing

We recently upgraded our active directory controller from 2003 to 2008 R2.  After the upgrade the backup team came to me and said backups were failing on the new DCs.  Running a “vssadmin list writers” would show that the system writer was missing.  I tried running the usual repair process for VSS (permissions and reregister DLLs) but nothing was working.  Additionally, every time you restart the volume shadow service the following event would show in the application log.

Log Name: Application
Source: Microsoft-Windows-CAPI2A
Event ID: 512
Task Category: None
Level: Error
Description:
The Cryptographic Services service failed to initialize the VSS backup “System Writer” object.

Details:
Could not open the EventSystem service for query.

System Error:
Access is denied.

 

After some troubleshooting and Googling I found the answer.  The problem was with a GPO that was being applied to the DCs.  The GPO was put in place years ago by someone in the backup team to give their service account access to some of the services on the machine.  The problem was with the service EventSystem (COM+ Event System).  The SERVICE account needs read permission to that service for VSS to function properly, this permission was missing from the GPO.  I added the NT AUTHORITY/SERVICE account with read permission to the GPO and ran a GPUPDATE /force on the DCs.  Restart the Cryptography service and the volume shadow service and the system writer is now back and happy.

XenDesktop 7 BrowserName attribute incorrect

A user found this issue because on his mobile device (IPad) it said he was connected to an app that he did not open. Here is the scenario:

1. copy an existing app named “Calculator1″
2. Rename the copied app to “Calculator2″
3. The web interface and receivers will now show the new name. But when the user connects to calculator2 from an Ipad, goes to “switch apps” button on receiver, it will show connected to calculator1.

Looking into the problem further, I ran a Get-BrokerApplication -name calculator2.

ApplicationType : HostedOnDesktop
BrowserName : Calculator1
CommandLineExecutable : c:windowssystem32calc.exe
Name : Calculator2
PublishedName : Calculator2

This appears to be a bug in XenDesktop 7.  Whenever you copy or rename an app it does not update the BrowserName attribute to the new name.  To fix this you can run the below PowerShell script from a DDC.  This script will make the BrowserName match what is set for PublishedName for all apps in your farm/site.

 

Import-Module Citrix.XenDesktop.Admin
Add-PSSnapin Citrix.*
$apps = get-brokerapplication
foreach ($app in $apps){
$appname = $app.Name
Set-BrokerApplication -Name $appname -BrowserName $appname
}

 

Set DNS and Hostname on all ESXi Hosts in a Cluster

This script can be used to configure DNS settings on each host in the cluster.  It will set the DNS Server addresses and will also set the hostname to match what was used when adding it to vcenter.  If you added the host to vcenter by IP then you will want to comment that section out.

As with any VMWare script, you will need the latest version of VMWare PowerCLI installed to run this.

 
Connect-VIServer vcenter.domain.com
$Cluster = "Clustername"
$ESXHosts = Get-Cluster $Cluster | Get-VMHost

ForEach ($ESXHost in $ESXHosts){

#Set DNS Servers
Get-VMHost | Get-VMHostNetwork | Set-VMHostNetwork -DnsAddress [8.8.8.8],[9.9.9.9]

#Set DNS domain and search domains
Get-VMHost | Get-VMHostNetwork | Set-VMHostNetwork -Domain domain -SearchDomain domain.com, child1.domain.com, child2.domain.com

#Get hostname from vcenter, set Hostname
$hostnamearray = $ESXHost.name.split(".")
$hostname = $hostnamearray[0]
Get-VMHostNetwork -VMHost $ESXHost | Set-VMHostNetwork -HostName $hostname 
}