a little deviation never hurt anyone

Backup Cisco Devices with SSH .NET

Backups are…boring.  As boring as they are, there’s nothing like having to reconfigure an entire switch or firewall because you didn’t do them.

I recently put together a simple command line application in c# to backup Cisco switches (IOS and NXOS) and firewalls (ASA).  I used the (really) awesome, open source SSH.NET library to accomplish this.  Hopefully this will help some other admins out.  Feedback is always welcome.


sshbackup.exe device_address backup_user backup_password backups_location device_type


Can be the DNS name or the IP address of your Cisco device






Path to store the backup. Can be local or UNC.


IOS, ASA, or NXOS (Nexus devices)


sshbackup.exe switch01 ibackup SuperSecretPa$$word \\ServerA\Configs ios


[2014-11-18 07:25:35.7779] *** switch01 ***
[2014-11-18 07:25:35.8248] Ping successful for swith01
[2014-11-18 07:25:35.9186] Destination \\ServerA\Configs ok
[2014-11-18 07:25:38.2467] Setting terminal length...
[2014-11-18 07:25:38.2467] Snatching config...
[2014-11-18 07:25:42.9030] Writing \\ServerA\Configs\switch01_20141118.config
[2014-11-18 07:25:42.9186] Successfully wrote \\ServerA\Configs\switch01_20141118.config


Microsoft .NET 4.5

SSH.NET 4.0 Binary –



Rotate Logs in Use with Powershell

Log rotation is a task every admin has to deal with at some point.  It’s relatively trivial if the files aren’t in use at the time of rotation.  But occasionally you will come across logs that are opened by a process that can’t simply be renamed (e.g. PHP logs files in IIS).

Below is a simple Powershell script I wrote to rotate log files that are in use and optionally send an email.

Usage: powershell .\RotateLocalLogsTruncate.ps1 -TargetFolder c:\inetpub\logs\PHPLogs\ -LogFile php.log


Rotates logs by copying the file and truncating the original
Updated: 2014.11.14

Param (
		[boolean]$Recurse = $True,
		[Boolean]$SendEmail = $false,
		[string]$MailTo = "",
		[string]$MailFrom = "",
		[string]$MailServer = ""

# generates a nicely formatted time stamp for logging
function StampTime() {
	return "[" + (Get-Date -Format u) + "]"

# record the script name
$scriptName = ($MyInvocation.MyCommand).Name
# record the path
$scriptPath = $MyInvocation.MyCommand.Path
$scriptDir = Split-Path $scriptPath
# set the event source
New-EventLog -LogName "Application" -Source "CustomScripts" -ErrorAction SilentlyContinue
Write-EventLog -LogName Application -Source "CustomScripts" -EventId 1000 -EntryType Information -Message "$scriptName Started"

try {
	# if there's no trailing slash add it
	if ( !$TargetFolder.EndsWith("\") ) {
		$TargetFolder += "\"

	# date to append
	$date = Get-Date -Format "yyyy-MM-dd-hhmmss"

	# log
	$log = ""
	# check the path
	if ( (Test-Path -Path $TargetFolder) -eq $false ) {
		# path is bad
		$log = (StampTime) + (" $TargetFolder appears to be unreachable or invalid`n")
	} else {
		# find log files
		$log += (StampTime) + (" Searching $LogPath...`n")
		$LogFiles = $null
		if ( $Recurse -eq $True ) {
			$LogFiles = Get-Childitem -Path $TargetFolder -Include $LogFile -Recurse
		} else {
			$LogFiles = Get-Childitem -Path $TargetFolder -Include $LogFile
		# do we have any?
		if ( $LogFiles -eq $null ) {
			# none
			$log += (StampTime) + ("Found 0 log files`n")
		} else {
			# got some
			if ( $LogFiles.Count -eq $null ) {
				$log += (StampTime) + ("Found 1 log file`n")
			} else {
				$log += (StampTime) + (" Found " + $LogFiles.Count + " log files`n")
			# loop through the logs
			foreach ( $f in $LogFiles ) {
				if ( $f -ne $null ) {
					# copy & truncate the log file
					$newFile = $f.BaseName + "-" + $date + $f.Extension
					$newPath = $f.DirectoryName + "\" + $newFile
					$log += (StampTime) + (" Rotating " + $f.Name + " to $newFile`n")
					Copy-Item -Path $f.FullName -Destination $newPath -Force | Out-Null
					if ( Test-Path -Path $newPath ) {
						# copy OK, truncate file
						$log += (StampTime) + (" Copy OK`n")
						Clear-Content -Path $f.FullName -Force
					} else {
						# copy failed
						$log +=  (StampTime) + ("Copy FAILED`n")
				$log += (StampTime) + (" Complete")
			# done output details to the console
			Write-Host $log
			if ( $SendEmail -eq $true ) {
				$MailSubject = "[SUCCESS] Rotate Logs - " + $s.Name + " (" + $LogFile + ")"
				Send-MailMessage -To $MailTo -From $MailFrom -Subject $MailSubject -Body $log -SmtpServer $MailServer -Priority Low
	# write the details to the event log
	Write-EventLog -LogName "Application" -Source "CustomScripts" -EventId 1000 -EntryType Information -Message $log
} catch [System.Exception] {
	# something went wrong
	Write-Host (StampTime) "[ERROR] "$Error[0] -ForegroundColor Red
	if ( $SendEmail -eq $true ) {
		$MailSubject = "[ERROR] Rotate Logs"
		Send-MailMessage -To $MailTo -From $MailFrom -Subject $MailSubject -Body $Error[0] -SmtpServer $MailServer -Priority High
	Write-EventLog -LogName Application -Source "CustomScripts" -EventId 1000 -EntryType Error -Message $Error[0]

Windows Update Error Code 8024402C

When attempting to install updates from WSUS, you might receive the follow error:

Windows Update encountered an unknown error. Code 8024402C

Windows Update Error Code 8024402c

Windows Update Error Code 8024402c

Typically this would point to connectivity.  After you’ve verified network connectivity to your WSUS server, you can follow these steps:

  1. Stop the Windows Update Service
    net stop wuauserv
  2. Delete the contents of C:\Windows\SoftwareDistribution
    rmdir C:\Windows\SoftwareDistribution /s /q
  3. Start the Windows Update Service
    net start wuauserv
  4. Check for updates
    wuauclt /detectnow /reportnow

You can string all of this together in a batch like so:

net stop wuauserv
rmdir %windir%\softwaredistribution /s /q
net start wuauserv

Outlook 2010 Shared Exchange Mailboxes

Outlook 2010 Shared Exchange Mailboxes

Handling Sent & Deleted Items

Microsoft Outlook 2010 introduced several new features. Unfortunately, it removed one feature that many organizations utilize: sent items & deleted items support for shared mailboxes. By default, Outlook 2010 will place all sent items and deleted items in the user’s mailbox. The issue with this is that users of a shared mailbox cannot see what emails have been sent out or deleted. In Outlook 2007, you could manually enable this feature by adding a registry key. This doesn’t work the same way in Outlook 2010. There is a fix though.

  1. Obtain the hotfix from Microsoft found at You need will need to fill out the information to have Microsoft send you a link to the hotfixes. There is one for x64 and x86.
  2. Install the provided hotfix.
  3. On the client computer logged in as the user, add the following registry key (based on
    "DelegateSentItemsStyle "=dword:00000001
  4. In the mail profile, add each shared mailbox as an account.
  5. Reboot the computer.

Eject a CD/DVD Drive with Powershell

Here’s a quick Powershell script to eject all CD/DVD drives on a computer.  This uses the WMPlayer COM object.

$wm = New-Object -ComObject "WMPlayer.ocx"

$drives = $wm.cdromCollection<a href="">All Posts</a>

for($i = 0; $i -lt $drives.Count; $i++) {

Great for playing jokes on co-workers or locating a PC.

Change DNS Servers Remotely with Powershell

At some point most admins will need to change a DNS server (or two) on their network.  This is an easy change for DHCP clients, but can be a real pain for statically assigned clients.  Below is a simple Powershell script that runs through a list a computer names and updates the DNS servers on the clients.

$servers = "SERVERA","SERVERB","CLIENT1"

foreach($server in $servers) {
Write-Host "Connect to $server..."
$nics = Get-WmiObject Win32_NetworkAdapterConfiguration -ComputerName $server -ErrorAction Inquire | Where{$_.IPEnabled -eq "TRUE"}
$newDNS = "",""

foreach($nic in $nics) {
Write-Host "`tExisting DNS Servers " $nic.DNSServerSearchOrder
$x = $nic.SetDNSServerSearchOrder($newDNS)

if($x.ReturnValue -eq 0) {
Write-Host "`tSuccessfully Changed DNS Servers on " $server
} else {
Write-Host "`tFailed to Change DNS Servers on " $server

Simply change $servers to match your list of computers.  What’s that you say?  Don’t feel like typing out a comma separated list of computers?  Change line 1 to $servers = Get-Content C:\PathToFile\computers.txt to feed in a list of computers from a text file.

This has been tested on Windows Server 2003, Windows Server 2008, Windows Vista, Windows 7, and Windows XP.  The script does requires WMI access to the computers so be sure to add an exception to the firewall if needed.

Netdiag [FATAL] Could not open file C:\WINDOWS\system32\config\netlogon.dns for reading

When you run the netdiag command on a Windows Server 2003 server, you may encounter the following errors:

[FATAL] Could not open file C:\WINDOWS\system32\config\netlogon.dns for reading.
[FATAL] Could not open file C:\WINDOWS\system32\config\netlogon.dns for reading.
[FATAL] No DNS servers have the DNS records for this DC registered.

This is because the 32-bit version of netdiag, while supported by Microsoft, isn’t able to locate the DNS file in a 64-bit installation.  To fix this issue, copy netdiag.exe from the Windows Server 2003 64-bit installation CD (SUPPORT\TOOLS\ to C:\Program Files (x86)\Support Tools.

McAfee Agent & AntiVirus Uninstall – Completely remove McAfee via command line/script

If you’re like most admins out there, you’ve had a need to completely remove McAfee components whether it’s troubleshooting or getting rid of the product.

McAfee is a stubborn product to remove.  They offer a tool to assist with removing their consumer products.  This won’t work on managed installations (ePO) unfortunately.  So I’ve assembled a batch file to handle the dirty work.  As always, use at your own risk.


REM McAfee Removal Script
REM Last Update: 11/01/2010

ECHO Removing AntiSpyware
"C:\Program Files\McAfee\VirusScan Enterprise\scan32.exe" /UninstallMAS
"C:\Program Files (x86)\McAfee\VirusScan Enterprise\scan32.exe" /UninstallMAS

REM Kill McTray &amp; Trusted Validation
ECHO Killing processes
taskkill.exe /f /t /im mctray.exe
taskkill.exe /f /t /im mfevtps.exe

ECHO Removing VirusScan 8.0
msiexec.exe /x {5DF3D1BB-894E-4DCD-8275-159AC9829B43} REMOVE=ALL REBOOT=R /q

ECHO Removing VirusScan 8.5
msiexec.exe /x {35C03C04-3F1F-42C2-A989-A757EE691F65} REMOVE=ALL REBOOT=R /q

ECHO Removing VirusScan 8.7
msiexec.exe /x {147BCE03-C0F1-4C9F-8157-6A89B6D2D973} REMOVE=ALL REBOOT=R /q

ECHO Remove McAfee Agent
"C:\Program Files\McAfee\Common Framework\frminst.exe" /forceuninstall /silent
"C:\Program Files (x86)\McAfee\Common Framework\frminst.exe" /forceuninstall /silent</code></strong>
<span style="font-size: 12px;"><code><span style="font-family: courier new,courier,monospace;">"c:\Program Files\Network Associates\Common Framework\frminst.exe" /forceuninstall /silent</span></code></span>

REM Remove McAfee Registry Keys
ECHO Removing Registry Keys
REG DELETE HKLM\SYSTEM\CurrentControlSet\services\McShield /f
REG DELETE HKLM\SYSTEM\CurrentControlSet\services\McTaskManager /f
REG DELETE HKLM\SYSTEM\CurrentControlSet\Services\mfeapfk /f
REG DELETE HKLM\SYSTEM\CurrentControlSet\Services\mfeavfk /f
REG DELETE HKLM\SYSTEM\CurrentControlSet\Services\mfebopk /f
REG DELETE HKLM\SYSTEM\CurrentControlSet\Services\mfehidk /f
REG DELETE HKLM\SYSTEM\CurrentControlSet\Services\mferkdet /f
REG DELETE HKLM\SYSTEM\CurrentControlSet\Services\mfetdik /f
REG DELETE HKLM\SYSTEM\CurrentControlSet\Services\mfevtp /f

If you have suggestions, problems, etc. please post below.  Happy hunting!

Indexing Adobe Arobat PDF files with SharePoint Server 2007

So you have a snazzy new SharePoint site?  It works wonderfully with Office documents.  Now you need to index all those PDF files that are floating around the office.  Fortunately, this is an easy fix.


  • Windows Server 2008 R2 Standard
  • Microsoft Office SharePoint Server (MOSS) 2007
  • Adobe IFilter 9.0 for 64-bit platforms – Download
  • Adobe Acrobat Reader (to view documents)
  • A GIF to use for the Acrobat file icon – Download


  1. Extract and run PDFiFilter64installer.  Follow the prompts.
  2. Add C:\Program Files\Adobe\Adobe PDF iFilter 9 for 64-bit platforms\bin to your PATH variable.  (Right click on Computer –> Properties –>Advanced system settings.  Click the Advanced tab and click on the Environment Variables button)
  3. Open SharePoint Search Administration. (Central Administration->Shared Services Administration)
  4. Click on File Types
  5. Click on New file type.  Type in pdf for the file extension and click OK.
  6. Open regedit and navigate to \\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Office Server\12.0\Search\Setup\ContentIndexCommon\Filters\Extension\.pdf
    Change the (Default) key to {E8978DA6-047F-4E3D-9C78-CDBE46041603}.
  7. Copy your PDF GIF icon to C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\IMAGES.
  8. Open C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\XML\DOCICON.xml in Notepad.
  9. Under the <ByExtension> section add:
    <Mapping Key=”pdf” Value=”youricon.gif”/>
    Save the file.
  10. Restart the server.

There you have it.  Searchable PDF files with the proper icon.  You can initiate a full crawl again just to be sure everything already existing gets indexed.  Bear in mind that scanned PDF files (those generated from multi-function scanner/printer/fax units) are often images embedded in the PDF document and aren’t searchable.


Hash Large Files with .Net SHA1/MD5

I’ve been working on an application that checks for duplicate files.  One of the better ways to test whether files are identical is to hash them.  MD5 hashing is common, but it has been known to cause collisions.  I elected to use the SHA1 algorithm instead.

In my testing, I’ve found that I can has a ~1GB file within about 7 seconds without consuming an equal share of memory.

You will need the following namespaces:

  • System.Security.Cryptography
  • System.IO

SHA1 Hash Example Code:

public string SHA1HashFile(string sPath) {
	string sHash = "";

	using (StreamReader sr = new StreamReader(sPath)) {

		SHA1CryptoServiceProvider sha1h = new SHA1CryptoServiceProvider();
		sHash = BitConverter.ToString(sha1h.ComputeHash(sr.BaseStream));

	return sHash;

Usage: SHA1HashFile(“C:\\Path\\File.iso”);

MD5 Hash Example Code:

public string MD5HashFile(string sPath) {
	string sHash = "";
	using (StreamReader sr = new StreamReader(sPath)) {
		MD5CryptoServiceProvider md5h = new MD5CryptoServiceProvider();
		sHash = BitConverter.ToString(md5h.ComputeHash(sr.BaseStream));

	return sHash;

Usage: MD5HashFile(“C:\\Path\\File.iso”);

« Older posts

© 2015 DigitalDeviation

Theme by Anders NorenUp ↑