Click an Ad

If you find this blog helpful, please support me by clicking an ad!

Tuesday, June 18, 2013

Windows Updates for Labs Without an Internet Connection

I'm often building lab environments that have no ability to get online. This is usually because some of the VMs I build have the same name as actual production systems. Some of them are even restores of production VMs in a lab environment. Naming conflicts suck, especially in the middle of the day.

I found a great tool called WSUS Offline Update that lets me put all of the WSUS updates I want onto a virtual DVD and update my OS from it. I wish I had it back in the day when I was updating remote offices on a slow and shared internet connection! It's well-built and fairly granular - you can pick and choose OS, Architecture, etc. It will even do Office and .NET!


Friday, June 14, 2013

Running Scheduled Reports in Spiceworks

We love Spiceworks! BUT it's still missing some things. One of which is the ability to set up reports to run automatically and email them to you. Well, it's not missing per se, it's just kind of complicated. The ability is there, and this is how to use it.

The post here within the Spiceworks Community got me started, but I wanted to show the whole picture.

  1. On your Spiceworks server, go to c:\Program Files (x86)\Spiceworks and create a new folder called 'rpt'.
  2. Now go into c:\Program Files (x86)\Spiceworks\pkg\gems\spiceworks-X.X.XXXXX (where the X's represent your version number), and copy the file run_report.rb into the rpt folder you created in step 1.
  3. Open a command prompt and navigate to c:\Program Files (x86)\Spiceworks\rpt and execute the following command to see how to use this ruby script:
    ..\bin\ruby run_report.rb -?
  4. Now, you need to find the report number that corresponds to the report you want to run. In my case, I used the following command:
    ..\bin\ruby run_report.rb -e user@contoso.com -p password -l 
  5. Your Spiceworks login credentials are used in the above command, as well as -l, which lists all reports, along with their report numbers. Write down the report numbers you want.
  6. In a batch file, write a line for each report. Here is an altered copy of my batch file:

    cd "C:\Program Files (x86)\Spiceworks\rpt"

    REM To get a list of tickets run this command:
    REM ..\bin\ruby run_report.rb -e user@contoso.com -p password -f pdf -l

    REM Run Report #72
    ..\bin\ruby run_report.rb -e user@contoso.com -p password -f pdf 72

    REM Run Report #73
    ..\bin\ruby run_report.rb -e user@contoso.com -p password -f pdf 73

    REM Run Report #74
    ..\bin\ruby run_report.rb -e user@contoso.com -p password -f pdf 74

    powershell.exe -NoProfile -File C:\ps\SpiceworksReporting.ps1


  7. Pay attention to the last line, which calls a powershell script that will email you the reports! Here's that file:

    #This file is run at the tail-end of SpiceworksReporting.bat

    $To = "admin@contoso.com"
    $From = "spiceworks@contoso.com"
    $Subject = "Spiceworks Reports"
    $SMTPServer = "smtpserver.contoso.com"
    $Body = "See Attached File(s)"

    #Report 1: 
    $file1 = "C:\Program Files (x86)\Spiceworks\rpt\report-72.pdf"

    #Report 2:
    $file2 = "C:\Program Files (x86)\Spiceworks\rpt\report-73.pdf"

    #Report 3:
    $file3 = "C:\Program Files (x86)\Spiceworks\rpt\report-78.pdf"

    #Send Email
    Send-MailMessage -To $To -From $From -SMTPServer $SMTPServer -Subject $Subject -Body $Body -Attachments $file1,$file2, $file3

    Remove-Item $file1
    Remove-Item $file2
    Remove-Item $file3


  8. Now, go into Task Scheduler and create a task to run the batch file. The batch file creates the reports, which output into pdf and are stored in the rpt folder we create. Then, the batch file calls the Powershell script which emails these files as attachments and then deletes the PDF files that were created.
Voila! You have automated Spiceworks reports!

Monday, June 10, 2013

Working with Windows Defender Updates in WSUS

We don't auto-approve anything besides the Windows Defender updates. We do this using a custom Auto-Approve rule within WSUS like so:

So, updates are being approved, and now I would like to auto-decline superseded updates to keep things tidy. Why keep things tidy? I have a third-party patch management system that also let's me pull some pretty nifty reports on client patching progress, and if I don't remove these they sort of pollute my output by not being installed.

So I made a powershell script by adapting my old "Decline Itanium Patches" script.
Here's the script for declining superseded Definitions for Windows Defender updates:

$WsusServer = "WsusServer.contoso.com"
$UseSSL = $false
$PortNumber = 80
$TrialRun = $true

#E-mail Configuration
$SMTPServer = "SMTPServer.contoso.com"
$FromAddress = "administrator@contoso.com"
$Recipients = "me@contoso.com"
$MessageSubject = "PS Report - Declining Superceded Defender Updates"

Function SendEmailStatus($MessageSubject, $MessageBody)
{
$SMTPMessage = New-Object System.Net.Mail.MailMessage $FromAddress, $Recipients, $MessageSubject, $MessageBody
$SMTPMessage.IsBodyHTML = $true
#Send the message via the local SMTP Server
$SMTPClient = New-Object System.Net.Mail.SMTPClient $SMTPServer
$SMTPClient.Send($SMTPMessage)
$SMTPMessage.Dispose()
rv SMTPClient
rv SMTPMessage
}

#Connect to the WSUS 3.0 interface.
[reflection.assembly]::LoadWithPartialName("Microsoft.UpdateServices.Administration") | out-null
$WsusServerAdminProxy = [Microsoft.UpdateServices.Administration.AdminProxy]::GetUpdateServer($WsusServer,$UseSSL,$PortNumber);

$defender = $WsusServerAdminProxy.GetUpdates() | ?{-not $_.IsDeclined -and $_.Title -match "defender" -and $_.IsSuperseded -eq $true}

If ($TrialRun)
{$MessageSubject += " Trial Run"}
Else
{$defender | %{$_.Decline()}}

$Style = "<Style>BODY{font-size:11px;font-family:verdana,sans-serif;color:navy;font-weight:normal;}" + `
"TABLE{border-width:1px;cellpadding=10;border-style:solid;border-color:navy;border-collapse:collapse;}" + `
"TH{font-size:12px;border-width:1px;padding:10px;border-style:solid;border-color:navy;}" + `
"TD{font-size:10px;border-width:1px;padding:10px;border-style:solid;border-color:navy;}</Style>"

If ($defender.Count -gt 0)
{
$MessageBody = $defender | Select `
@{Name="Title";Expression={[string]$_.Title}},`
@{Name="KB Article";Expression={[string]::join(' | ',$_.KnowledgebaseArticles)}},`
@{Name="Classification";Expression={[string]$_.UpdateClassificationTitle}},`
@{Name="Product Title";Expression={[string]::join(' | ',$_.ProductTitles)}},`
@{Name="Product Family";Expression={[string]::join(' | ',$_.ProductFamilyTitles)}},`
@{Name="Uninstallation Supported";Expression={[string]$_.UninstallationBehavior.IsSupported}} | ConvertTo-HTML -head $Style
SendEmailStatus $MessageSubject $MessageBody
}

Running this script with $TrialRun set to $true (as it is initially) will simply email you what the script plans to do; it won't decline anything. Changing the $TrialRun variable to $false will actually decline things.

I set this script to run daily about an hour after my scheduled WSUS Synchronization.

In case you're wondering, the patch management system I'm running is Dameware Third Party Patching by Solarwinds. I'm still learning it and the curve is a bit steeper than I would like. At this time, I can't recommend it, but only because I need to learn more to use it effectively and not because it's a poor product (that I've found). I DO really like the reports it generates and I am successfully patching all Adobe Flash installs through my WSUS Server.

Friday, June 7, 2013

Finding Files Over a Certain Length

So one thing that I've put into place following my Veeam restoration issue with long filenames is a script that runs daily on my fileservers that emails me when it finds any filename+filepath that's over 240 characters. The limit for an NTFS file is 256 characters, and a Veeam restore will choke if it tries to restore a file that exceeds this length.

Before I get into the script, I'd like to thank Ben for writing the actual action part of the script.
I have made modifications so that it runs where I want it to run and emails me if there are any results. Here it is:

#Let's find some long filenames
$files=Get-Childitem F:\ -Recurse 

#Change Outpath to where you want log.
$Outpath = "C:\Temp\LongFiles.txt"

#MAIN SCRIPT
foreach ($file in $files)
{
if ($file.pspath.substring(38).length -gt 240)
{
if($File.Attributes -like "Directory*")
{
Write-Output ($File.PSPath.substring(38) + " is " + $File.Name.Length + " Characters Long, and it is a directory! The total path length is " + ($File.PSPath.Substring(38).length) + ".") >> $Outpath
} #End If
else
{
Write-Output ($File.PSPath.substring(38) + " is " + $File.Name.Length + " Characters Long, and it is a file! The total path length is " + ($File.PSPath.Substring(38).length) + ".") >> $Outpath
} #End Else
} #End If
} #End Foreach

#Email Parameters
$smtpserver = "mailserver.contoso.com"
$From = "administrator@contoso.com"
$To = "me@contoso.com"
$Subject = "PS Report - Long Filenames from <servername>"
$body = (Get-content $outpath | out-string)

#Sending the email
If ((Test-Path $outpath) -eq $True){
Send-Mailmessage -from $From -to $To -subject $Subject -smtpserver $smtpserver -body $body
} #End If

#Delete the log file
Remove-Item $outpath

So, a couple of things to mention about this:

  • Change the get-childitem path to the one you wish to scour.
  • Make sure you have a c:\temp path for the log file or change the output logfile's path.
  • Change the email parameters.
  • In the first 'If' statement, I changed his script to output anything over 240 characters in length, because that's all I really care about.
  • Make sure you have access to the files or the script won't search those files/folders.

I then set up a scheduled task to run the script every morning. The "Sending the email" portion tests to see if a logfile exists. If there is no logfile, then there are no files that meet the criteria (over 240 chars).

As is good practice, if there is nothing to say, the script does not email me. I have enough emails to dig through every day....