Clean Up Unused Printer Drivers

Working on a printer migration project, and one of the first steps was to clean up the existing print servers so that when running the migration. I wanted a way to contact remote print servers too. This script, once imported allows cleanup of remote print servers.

Requires Powershell 4, so run off a Windows 8/Windows Server 2012.

If targeting a Windows 2003 print server, it cannot perform the actual removal and will just list a number of errors. It does atleast highlight all of the drivers which are not in use though.

# ----------------------------------------------------------------------------------------------------------
# PURPOSE: Remove Printer Drivers which do not have any printers
#
# VERSION DATE USER DETAILS
# 1 28/08/2014 Craig Tolley First version
# 1.1 29/08/2014 Craig Tolley Moved getting printers into variable to improve performance.
#
# ----------------------------------------------------------------------------------------------------------

#Define the print server names.
Function Remove-UnusedPrinterDrivers
{

Param
(
#The name of the print server to clean up.
[Parameter(Mandatory=$true)]
[string]$PrintServerName
)

#Get all of the printer drivers
$Drivers = Get-PrinterDriver -ComputerName $PrintServerName
$Printers = Get-Printer -ComputerName $PrintServerName

ForEach($Driver in $Drivers)
{
$PrintersUsingDriver = ($Printers | Where {$_.DriverName -eq $Driver.Name} | Measure).Count
Write-Host "Driver: $($Driver.Name) has $PrintersUsingDriver printers using it."

If ($PrintersUsingDriver -eq 0)
{
Try
{
Remove-PrinterDriver -Name $Driver.Name -ComputerName $PrintServerName -ErrorAction Stop
Write-Host " $($Driver.Name) has been removed." -ForegroundColor Green
}
Catch
{
Write-Host " Failed to remove driver: $($Driver.Name)" -ForegroundColor Red
}
}
Write-Host ""
}
}

Be the first to like.
Posted in Powershell, Server 2003, Server 2008, Server 2012 | Leave a comment

WhatsUp Gold Raspberry Pi Monitor

I have worked out a way to get a full screen display of a specific dashboard for use with a digital signage display using a Raspberry Pi, using only a web browser.

The Dashboard client was ok, but required a Windows machine, and although we could use the existing web page with automatic login (http://community.whatsupgold.com/forums/whatsupgoldeditionsstandardandpremiumeditions/automatic-login-by-url) too much space was lost using the menu and title bars.

So, here it is:

  1. On your WUG server, browse to the installation directory: C:\Program Files (x86)\Ipswitch\WhatsUp\HTML\NmConsole\Workspace\HomeWorkspace
  2. Take a copy of HomeWorkspace.asp and call it HomeWorkspaceMonitor.asp
  3. Open the file in your favourite editor and remove the following sections:
    1. AddNavigation();
    2.  <% AddWorkspaceViewTabs(WT_UNIVERSAL); %>
    3.  <div id=”titlebar”>
      ‘ <h2><%= $.tr(“Home”) %></h2>
      ‘ <% AddWorkspaceToolbarButtons($.tr(“Home Dashboard”), WT_UNIVERSAL) %>
      </div>
  4. Save the file.
  5. Open up your browser and enter the URL, substituting your server name, the ID of the workspace you want to view and a valid username and password: http://localhost/NmConsole/Workspace/HomeWorkspace/HomeWorkspaceMonitor.asp?HomeWorkspace.nWorkspaceID=10025&sUsername=DisplayRead&sPassword=DisplayRead

This gave us a page with only the actual content of the dashboard. We set the user account to have very limited access, and then set a Raspberry Pi to autoload Firefox, full screen and browse to this page.

WUG.png

Hopefully this will be useful to others

Be the first to like.
Posted in Monitoring, Raspberry Pi | Leave a comment

Renaming NetApp SnapMirror Destinations

We have a collection of NetApp devices hosting a large number of volumes, and utilise SnapMirrors extensively for backup and DR, as well as moving information between departments

As the storage has grown, and different people have added new volumes, new SnapMirrors have been created, with a wide variety of naming formats to match the mood of the creator on that particular day. This makes managing volumes, when you are not exactly sure what they do, a little challenging.

A standard for the naming of these volumes was decided on, and all new SnapMirror destinations must be in the format of the original volume name with _SnapMirror appended to the end. This is similar to what the OnCommand System centre uses, just without the date.

Whilst this was all good for new volumes, the 200 existing volumes and mirrors would likely not be changed for a long time. So, I set about looking for a way to update all of our SnapMirror destinations. With there being a lot of volumes, scripting was the only way to be looking at this.

So, here is a module containing two functions. The first, Get-NonStandardSnapMirrorNames looks through all of the specified NetApp Filers for SnapMirrors do not fall into the format specified. The second function, Repair-NonStandardSnapMirrorNames, runs through a procedure which can correct them.

I have been good and even included PowerShell help inside the function, so once you have imported the module you can run Get-Help with the relevant function in order to find out the exact syntax.

If you use this and have some suggestions on how it could be improved then please let me know. I am relatively new to NetApp storage devices and still working out some of the peculiarities. There are probably a number of ways that this could be improved, but it worked well for me in the environment that I have,

You will need to have the DataOnTap PowerShell kit available from NetApp to use this script, as everything is performed using the PowerShell commands rather than using any SSH sessions.

So, here it is. Copy into your favourite editor, save, import to PowerShell and off you go.

# ----------------------------------------------------------------------------------------------------------
# PURPOSE:    Check all SnapMirrors on Filers to ensure that they are named correctly. 
#
# VERSION     DATE         USER                DETAILS
# 1           09/07/2014   Craig Tolley        First version
# 1.1         15/07/2014   Craig Tolley        Moved Disables/Enables Snapmirrors into a batch to stop failed transfers
#                                              Made Common Credentials a parameter that then asks for details. 
#
# ----------------------------------------------------------------------------------------------------------

<# .Synopsis    Find all SnapMirrors where the destination volume name does not match the specified convention. Returns a collection of SnapMirrors.  .EXAMPLE    Get-NonStandardSnapMirrorNames -FilersToCheck "filer1", "filer2"    Provide a list of the filers to check using the default suffix of _SnapMirror.    e.g This would be considered a valid destination.          Source:       vol1         Destination:  vol1_SnapMirror    e.g This would be considered invalid.          Source:       vol1         Destination:  vol1_SM .EXAMPLE    Get-NonStandardSnapMirrorNames -FilersToCheck "filer1", "filer2" -SnapMirrorSuffix "_Snap"        Provide a list of the filers to check. Also specify what the SnapMirror suffix should be.     In this case it would check to see if the destination was the name of the source with _Snap appended to the end.  .EXAMPLE    Get-NonStandardSnapMirrorNames -FilersToCheck "filer1", "filer2" -CommonCredentials        Provide a list of the filers to check and that all filers use the same credentials. You will only be prompted once for credentials      #>
function Get-NonStandardSnapMirrorNames
{
    [CmdletBinding()]
    Param
    (
        # A collection of the filers that we want to check.
        [Parameter(Mandatory=$true,
                   ValueFromPipelineByPropertyName=$true,
                   Position=0)]
        [string[]]$FilersToCheck,

        # The suffix that you would expect to have found in a properly named SnapMirror relationship. By default it expects _SnapMirror, this can be overridden. 
        # e.g If the source volume is called 'MyVol', would mean that we expect the destination volume to be 'MyVol_SnapMirror'
        [string]$SnapMirrorSuffix = "_SnapMirror",

        #Credentials to be used for every filer that you are connecting to. If each filer requires different credentials then leave this option out. 
        [Switch]$CommonCredentials

    )

    Begin
    {
        #Check that that DataOnTap Module is available, check it is loaded. 
        Write-Host "Checking for DataONTAP Module..."
        if ((Get-Module -ListAvailable | Where {$_.Name -eq "DataONTAP"}).Count -ne 1) {
            Write-Error "DataONTAP not installed on targeted machine"
            Exit 1
            }
        if ((Get-Module | Where {$_.Name -eq "DataONTAP"}).Count -ne 1) {
            Write-Host "Importing DataONTAP Module..."
            Import-Module -Name "DataONTAP" | Out-Null
            }

        #Create a new collection of Snapmirrors
        $SnapmirrorsToFix = @()

        #Get credentials for all of the filers - to save constantly asking for them later
        if ($CommonCredentials) {$Credentials = Get-Credential}
        foreach($Filer in $FilersToCheck)
            {
            if ($CommonCredentials)
                {Add-NaCredential -Controller $Filer -Credential $Credentials | Out-Host}
            else
                {Add-NaCredential -Controller $Filer -Credential (Get-Credential -Message "Please supply credentials for $filer") | Out-Host}
            }
    }

    Process
    {
        Write-Host "Getting all SnapMirrors that do not match the specified convention"
        Write-Host "Set SnapMirror Suffix is: $SnapMirrorSuffix"
        Write-Host " " 

        #Go through each of the filers in turn and look at all of the volumes and all of the SnapMirrors
        foreach($Filer in $FilersToCheck)
            {
            #Connect to the filer and get all of the volumes
            Write-Host " "
            Write-Host "Connecting to $Filer..."
            Connect-NaController $Filer | Out-Host
            $VolCount = 0
            
            $Volumes = Get-NaVol

            foreach($Volume in $Volumes)
                {
                #Get the snapmirrors for the volume where it is the source of the mirror
                $SnapMirrors = Get-NaSnapmirror -Location $Volume | Where {$_.State -eq "source"}

                foreach($SnapMirror in $SnapMirrors)
                    {
                        [string]$DestinationFilerString = $SnapMirror.Destination.Split(":")[0]
                        [string]$DestinationVolumeString = $SnapMirror.Destination.Split(":")[1]
                        [string]$SourceVolumeName = -Join  ("$($Volume.Name)","$SnapMirrorSuffix")

                        If($DestinationVolumeString -ne $SourceVolumeName)
                            {
                                $SnapmirrorsToFix += $SnapMirror
                                $VolCount += 1
                            }
                    }
                }
                Write-Host " "
                Write-Host "$VolCount volumes found on $Filer that do not match the specified convention"
            }

    }
    
    End
    {
    Write-Output $SnapmirrorsToFix
    Write-Host " "
    Write-Host "  --  Completed finding SnapMirrors that do not match the convention  -- "
    }
}


<# .Synopsis    Re-configures all of the provided Snapmirrors to match the conventions. Pass in a Snapmirror object.    Updates the volume name, the SnapMirror schedule on the destination filer, the SnapMirror relationship on the source filer    Forces a re-sync to ensure that everything is working.     Requires an initial baseline to exist before the operation will complete. Also the SnapMirror must be Idle.  .EXAMPLE    Repair-NonStandardSnapMirrorNames -SnapMirrorsToFix $SnapMirror .EXAMPLE    Repair-NonStandardSnapMirrorNames -SnapMirrorsToFix $SnapMirror -SnapMirrorSuffix "_Snap" .EXAMPLE    Repair-NonStandardSnapMirrorNames -SnapMirrorsToFix $SnapMirror -CommonCredentials    Supply one set of credentials for use with all the filers that will be connected to. If the filers require different credentials, then this parameter should be omitted.     If omitted you will be prompted for credentials for each of the filers that are required to be connected to.  #>
function Repair-NonStandardSnapMirrorNames
{
    [CmdletBinding()]
    Param
    (
        # A collection of the filers that we want to check.
        [Parameter(Mandatory=$true,
                   ValueFromPipeline=$false,
                   Position=0)]
        [DataONTAP.Types.Snapmirror.SnapmirrorStatusInfo[]]$SnapMirrorsToFix,

        # The suffix that you would expect to have found in a properly named SnapMirror relationship. By default it expects _SnapMirror, this can be overridden. 
        # e.g If the source volume is called 'MyVol', would mean that we expect the destination volume to be 'MyVol_SnapMirror'
        [string]$SnapMirrorSuffix = "_SnapMirror",

        #Credentials to be used for every filer that you are connecting to. If each filer requires different credentials then leave this option out. 
        [Switch]$CommonCredentials
    )

    Begin
    {
        #Check that that DataOnTap Module is available, check it is loaded. 
        Write-Host "Checking for DataONTAP Module..."
        if ((Get-Module -ListAvailable | Where {$_.Name -eq "DataONTAP"}).Count -ne 1) {
            Write-Error "DataONTAP not installed on targeted machine"
            Exit 1
            }
        if ((Get-Module | Where {$_.Name -eq "DataONTAP"}).Count -ne 1) {
            Write-Host "Importing DataONTAP Module..."
            Import-Module -Name "DataONTAP" | Out-Null
            }
            
            [DataONTAP.Types.Snapmirror.SnapmirrorStatusInfo[]]$Snapmirror

            #Connect to all of the necessary filers in advance. Controllers are then explicitly defined for each operation. 
            $Filers = @()
            foreach ($Snapmirror in $SnapMirrorsToFix)
                {
                $Filers += $SnapMirror.Source.Split(":")[0]
                $Filers += $Snapmirror.Destination.Split(":")[0]
                }
            $Filers = $Filers | Select -Unique

            #Get credentials for all of the filers - to save constantly asking for them later
            if ($CommonCredentials) {$Credentials = Get-Credential}
            foreach($Filer in $Filers)
            {
                if ($CommonCredentials)
                    {Add-NaCredential -Controller $Filer -Credential $Credentials | Out-Host}
                else
                    {Add-NaCredential -Controller $Filer -Credential (Get-Credential -Message "Please supply credentials for $filer") | Out-Host}
                }
    }

    Process
    {

        #Disable SnapMirrors on all Destination Filers
        $Filers = @()
        foreach ($Snapmirror in $SnapMirrorsToFix)
            {$Filers += $Snapmirror.Destination.Split(":")[0]}
        $Filers = $Filers | Select -Unique
        Write-Host "Disabling SnapMirrors on the destination so that they are not updated during the rename"
        foreach($Filer in $Filers)
        {
            Write-Host $Filer
            Connect-NaController $Filer | Out-Null
            Disable-NASnapMirror  | Out-Null
        }
   

        #Perform the actual repair operation. 
        foreach($Snapmirror in $SnapmirrorsToFix)
            {   
                Write-Host "Fixing SnapMirror destination name"    
                Write-Host $Snapmirror

                #Set all of the names for the sources and the destinations. Easier than keeping calculating them on the fly. 
                $SourceFiler = $Snapmirror.Source.Split(":")[0]
                $SourceVolName = $Snapmirror.Source.Split(":")[1]
                $DestinationFiler = $Snapmirror.Destination.Split(":")[0]
                $OriginalDestinationVolName = $Snapmirror.Destination.Split(":")[1]
                $NewDestinationVolName = -Join ($Snapmirror.Source.Split(":")[1],"$SnapMirrorSuffix")
                
                #Connect to the Source
                Write-Host "Connecting to the source filer"
                Connect-NaController $SourceFiler
                $Snapmirror = Get-NaSnapmirror $Snapmirror.Destination.Split(":")[1]

                #Check that the source volume is attached to vfiler0. If not, editing becomes a lot harder and not implemented here! :-)
                If ((Get-NAVol $SourceVolName).OwningVfiler -ne "vfiler0")
                    {
                    Write-Error "The source volume is not owned by the default vFiler. Cannot edit SnapMirrors that are owned by non-default vFilers. Stopping change for this SnapMirror"
                    Break
                    }

                #Check that the snapmirror is not actually running. If it is, then break. 
                If ($Snapmirror.Status -ne "idle")
                    {
                    Write-Error "The snapmirror is not idle. Cancelling operation"
                    Break
                    }

                #We must have at least one base snapshot, else the release and the update will fail as no common baseline exists. 
                If (($Snapmirror.BaseSnapshot).ToString -eq "")
                    {
                    Write-Error "The snapmirror relationship does not have a common base snapshot. Operation would break the current relationship"
                    Break
                    }

                #Check whether the destination is already in the correct format. 
                If ($NewDestinationVolName -eq $OriginalDestinationVolName)
                    {
                    Write-Host "Snapmirror Destination is already in the correct format. Not going to change anything"
                    Break
                    }
                
                #Release the Snapmirror - which removes it from the Source Filer
                Write-Host "Releasing the SnapMirror source connection"
                Connect-NaController $SourceFiler | Out-Null
                Get-NASnapMirror $OriginalDestinationVolName | Invoke-NaSnapmirrorRelease -Confirm:$false | Out-Null
                          
                Try
                    {
                    Connect-NaController $DestinationFiler | Out-Null
                    #Rename the destination Vol
                    Write-Host "Renaming the destination volume"
                    Get-NaVol -Name $OriginalDestinationVolName | Rename-NaVol -NewName $NewDestinationVolName | Out-Null
      
                    #Update the Destination of the Snapmirror on the Destination Filer
                    Write-Host "Updating the SnapMirror Schedule with the new destination volume name"
                    $SMSched = Get-NaSnapmirrorSchedule $OriginalDestinationVolName
                    $SMSched.Destination = "$DestinationFiler`:$NewDestinationVolName"
                    $SMSched | Set-NaSnapmirrorSchedule

                    #Remove the Old SnapMirror Schedule
                    Write-Host "Removing the SnapMirror schedule for the old destination"
                    Get-NaSnapmirrorSchedule $OriginalDestinationVolName | Remove-NaSnapmirrorSchedule | Out-Null          
                    }
                
                Catch
                    {   
                    Write-Error "Failed to update the volume"
                    Break
                    }
            }

        #Re-enable SnapMirrors on all Destination Filers
        Write-Host "Re-enabling SnapMirrors on the destination..."
        foreach($Filer in $Filers)
        {
            Write-Host $Filer
            Connect-NaController $Filer | Out-Null
            Enable-NASnapMirror  | Out-Null
        }

        #Update all Snapmirrors so that they re-register on the Source Filer
        foreach($Snapmirror in $SnapmirrorsToFix)
            {
            Write-Host "Registering the SnapMirror on the Source filer and reconnecting the SnapMirror"
            $NewDestinationVolName = -Join ($Snapmirror.Source.Split(":")[1],"$SnapMirrorSuffix")
            $DestinationFiler = $Snapmirror.Destination.Split(":")[0]
            Connect-NaController $DestinationFiler | Out-Null
            Do {Write-Host "."} Until ((Get-NASnapMirror $NewDestinationVolName).Count)
            Get-NASnapMirror $NewDestinationVolName | Invoke-NaSnapmirrorBreak -Confirm:$false | Out-Null
            Get-NASnapMirror $NewDestinationVolName | Invoke-NaSnapmirrorResync -Confirm:$false | Out-Host
            }

        #Update any Snapmirrors that might be in a failed State. The Disable above does not check for any that were already running.
        Write-Host "Resuming any SnapMirrors that might have failed due to SnapMirror being Disabled. "
        foreach($Filer in $Filers)
        {
            Connect-NaController $Filer | Out-Null
            Get-NaSnapmirror | Where {$_.CurrentTransferError -ne $null -and $_.Status -eq "idle"} | Invoke-NaSnapmirrorUpdate
        }

    }
    
    End
    {
        Write-Host "  --  Completed repairing SnapMirrors that do not match the convention  -- "
    }
}

Be the first to like.
Posted in General Stuff, Powershell | Leave a comment

Setting Max Concurrent Mailbox Moves on all CAS Servers

Have been working on a migration of a whole load of mailboxes. One of the first things I came across is the pre-defined limit on the number of concurrent mailbox moves that can be completed on a CAS server in an Exchange environment.

I knew that our environment could handle a few more moves than the limit of 2, particularly out of hours. I wanted to ensure that if anyone started any moves within business hours though that a limit was still applied.

So, I went and wrote this little script below. It goes through and updates all of the CAS servers in your Exchange environment and sets the value of the concurrent moves to whatever you specify. I then scheduled this to run each day at the end of the day to allow more scheduled moves overnight, and ran it again in the morning with the original limit of 2 moves just before we opened.

It uses Invoked Sessiosn too, so as long as remoting has been enabled on your CAS servers, then you don’t need Exchange installed on the box that you are going to run from.

# ----------------------------------------------------------------------------------------------------------
# PURPOSE:    Set the Max Concurrent Mailbox Moves on all CAS Servers
#
# VERSION     DATE         USER                DETAILS
# 1           24/06/2014   Craig Tolley        First version
#
#
# ----------------------------------------------------------------------------------------------------------
#Script Block to Run on Each Host
$ScriptBlock = {
    
    #Parameters
    $MaxMovesValue = 50
    #Start of Script
    Write-Output $("-"*50)
    Write-Output "Connected to: $(hostname)"
    #Get the Exchange Install Path, check it has been returned. Exit if not found.     
    [string]$ExInstallPath = $env:exchangeinstallpath 
    If ($ExInstallPath.Length -eq 0)
        {
        Write-Error "CAS Server $hostname did not return the Install Path."
        Exit
        }
    Else
        {
        Write-Output "Exchange is installed at: $ExInstallPath"
        }
        #Look up the location of the configuration file and check that it exists
    $ConfigFileName = $ExInstallPath + "bin\MSExchangeMailboxReplication.exe.config"
    If ((Test-Path $ConfigFileName) -eq $false)
        {
        Write-Error "Cannot find the MRS configuration file"
        Exit
        }
    #Create a backup of the configuration file. 
    Write-Output "Config Backup: $ConfigFileName.$(Get-Date -Format yyyyMMdd_HHmm).backup"
    Copy-Item $ConfigFileName -Destination ($ConfigFileName + "." + (Get-Date -Format yyyyMMdd_HHmm) + ".backup")
    #Configure the file with the specified values and save the changes. 
    Write-Output "Configuring XML File"
    [System.Xml.XmlDocument]$config = Get-Content ($ConfigFileName)
    $config.configuration.MRSConfiguration.MaxActiveMovesPerSourceMDB = [string]$MaxMovesValue
    $config.configuration.MRSConfiguration.MaxActiveMovesPerTargetMDB = [string]$MaxMovesValue
    $config.configuration.MRSConfiguration.MaxActiveMovesPerSourceServer = [string]$MaxMovesValue
    $config.configuration.MRSConfiguration.MaxActiveMovesPerTargetServer = [string]$MaxMovesValue
    $config.Save($ConfigFileName)
    
    #Restart the MRS to activate the changes. 
    Write-Output "Restarting Mailbox Replication Service"
    Get-Service MSExchangeMailboxReplication | Restart-Service -WhatIf
    
    Write-Output "Configuration Complete!"
    Write-Output $("-"*50)
    Write-Output ""
}
#Get all of the CAS Servers
$CAS = Get-ClientAccessServer
#Loop through all changing the setting. 
foreach($srv in $CAS)
    {
     Write-Output "Configuring CAS Server: $srv"
     Invoke-Command -ComputerName $srv -ScriptBlock $ScriptBlock
    }

Be the first to like.
Posted in Exchange, Powershell | Leave a comment

I’m back!

Now back in to doing some proper geeky stuff, which is what I love doing. So, here marks the start of a new set of posts which actually provide useful (at least in my opinion) tools, fixes, and scripts.

Kicking off with a little bit of Exchange, got a couple of NetApp PowerShell tools in the pipeline (no pun intended) and some VMware bits and pieces.

Be the first to like.
Posted in General Stuff | Leave a comment

Converting RTF-HTML – Not possible in a thread?

Been working on an application that needed to convert some RTF to HTML. Initially I thought this would be a reasonably simple requirement, and hoped that .Net might even include such a function to do this. Alas, I was being too optimistic.

So, trusting Google, ended up on this post from Matthew Manela – http://code.msdn.microsoft.com/Converting-between-RTF-and-aaa02a6e

Put that it, built the project, and ran on my UI thread, all works fine.

Put the same code in a background worker process or thread, and you will get an error: The calling thread must be STA, because many UI components require this.

The converter above unfortunately uses the built in RichTextBox component to perform a RTF-XAML conversion as the first step in the whole conversion process.

So, if anyone knows of a way that I can go from RTF-HTML in a separate thread from the UI, I would love to hear from you.

Be the first to like.
Posted in VB.net | Leave a comment

Ping Host with a Log File

Another potentially useful script here. It pings a host and records the output in a log file. The ping continues until you press Ctrl+C to stop it. This is useful for running in a background monitoring connectivity response times to a host and seeing if there is any network dropout.

Ping is no guarantee of performance, but it does give some idea if you have some underlying network problem over an extended period.

Run from the command line using the following format:

Ping_With_Log.vbs www.google.co.uk C:\GooglePing.txt
'Script to ping a host and record the output to a log file. 
'Craig Tolley
'Version 1.0 - 09/10/2013 - Initial Release
'Version 2.0 - 10/01/2014 - Complete rewrite to make significantly more usable and readable. 

'-------------------  START SCRIPT -------------------

'Check the provided arguments
If WScript.Arguments.Count = 2 Then
	HostToPing = WScript.Arguments(0)
	LogFileName = WScript.Arguments(1)
Else
	Wscript.Echo "Invalid number of arguments detected. " & Chr(13) & Chr(13) & _
				 "Usage: Ping_With_Log.vbs HostToPing LogFileName" & Chr(13) & Chr(13) & _
				 "The host to ping can either be an IP address or resolvable host name" & Chr(13) & Chr(13) & _
				 "The LogFile can either be just a filename, in which case it will be created in the current directory, or a full folder path and file name" & Chr(13) & Chr(13) & _
				 "e.g Ping_With_Log.vbs www.google.co.uk C:\GooglePing.txt"
	Wscript.Quit
End If

'Definitions
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objShell   = CreateObject("Wscript.Shell")
Set objLogFile = objFSO.OpenTextFile(logfilename, 8, True)

'Run the command
strCommand = "%comspec% /c ping -t " & HostToPing
Set objExec   = objShell.Exec(strCommand)

Wscript.Echo "Ping with Error Log has started. To stop collecting Ping data press Ctrl+C"

'Keep writing the output of the application until Ctrl+C is pressed to cancel the ping
Do While objExec.StdOut.AtEndOfStream <> True
	objLogFile.WriteLine(Date & " " & Time & " " & objExec.StdOut.ReadLine)
Loop

'Open the log file for viewing
strCommand = "notepad.exe " & LogFileName
objShell.Exec(strCommand)

Be the first to like.
Posted in General Stuff | Leave a comment

Using Enum with ComboBox and setting Combobox value – VB.net

This is my take on setting a combobox to use an enum which has both a description and key value set. It also shows how this works when trying to assign a value to the combobox.


Enum MyLogEnum
Error = 1
Warning = 2
Information = 3
End Enum

ComboBox_LogLevel.DataSource = System.Enum.GetValues(GetType(MyLogEnum))

And to assign a numeric value to the Combobox and make it display correctly:

ComboBox_LogLevel.SelectedItem = DirectCast(SourceIntValue, MyLogEnum)

Unfortunately, I could not find an equally as elegant way of doing the same thing using a ComboBox that was part of a Datagrid View, so ended up rewriting the Enum as a Dictionary like this:


Dim LoggingLevelsList As New Dictionary(Of String, Integer)
For Each enumValue As Integer In [Enum].GetValues(GetType(MyLogEnum))
LoggingLevelsList.Add([Enum].GetName(GetType(MyLogEnum), enumValue), enumValue)
Next
DataGridCombo.DataSource = New Windows.Forms.BindingSource(LoggingLevelsList, Nothing)
DataGridCombo.DisplayMember = "Key"
DataGridCombo.ValueMember = "Value"

With this in the Datagridview Combobox, you do not need to do any casting from the source integer.

If someone has a better way for Enums on a DataGridView ComboBox, I would really like to hear them.

Be the first to like.
Posted in Programming, VB.net | Leave a comment

Recursively Delete Empty Folders – VBScript

Ok, if you use your favourite search engine to look up a recursive deletion of empty folders, you will more than likely come up with a lot of results. I did. However by the end of the first page, I hadn’t found what I needed, so made up my own.

The special bits about this script:

  1. It forces you to use cscript and the command line, meaning that you won’t have to keep clicking OK to the prompts.
  2. It checks if there are any thumbs.db or desktop.ini files in the folders first, as these would otherwise stop the deletion.
  3. It tells you at the end if there were any errors.

Nothing particularly ground breaking, just more useful to me.

So, here it is. My advice – when running the script run it and pipe the results to a file – that way you can quickly search the file for the word ‘Error’ to see what didn’t work. For example:

cscript C:\Scripts\DeleteEmptyFolders.vbs > C:\Scripts\Results.txt

And here is the script:

'Script to delete all empty folders within a given directory. 
'Recursively searches through to make sure that folders that just contain empty folders are also removed.
'Also removed desktop.ini and thumbs.db files if they exist to accurately remove empty folders.  
'Craig Tolley
'Version 1.0 - 27/12/2013 - Initial Release

'-------------------  START SCRIPT -------------------
Option Explicit
On Error Resume Next

'Check we are running from the command line and using cscript. 
If Not LCase( Right( WScript.FullName, 12 ) ) = "\cscript.exe" Then
	WScript.Echo("You must use cscript and run this script from the command line." & Chr(13) & "e.g cscript.exe DeleteEmptyFolders.vbs")
	WScript.Quit
End If

'Define some variables and bits. 
Dim objFSO, strFolderPath, intErrorCount
Set objFSO = CreateObject("Scripting.FileSystemObject")
intErrorCount = 0

'Ask user for the folder to tidy up. Check they entered something and that what they entered is actually a valid folder. 
strFolderPath = InputBox("Enter the path of the directory to clean up")
strFolderPath = Trim(strFolderPath)
If Len(strFolderPath) = 0 Then 
	WScript.Echo "No path entered. Exiting"
	WScript.Quit
End If
If (objFSO.FolderExists(strFolderPath)) = False Then
	WScript.Echo "The path entered is either invalid or cannot be found. Please check and try again."
	WScript.Quit
End If

'Run the recursive cleanup
RecursiveDeleteEmptyFolders strFolderPath

'Give the user back some information. 
WScript.Echo "--------------------------------------------------------------------"
WScript.Echo "Finished Cleanup of " & strFolderPath
If intErrorCount > 0 Then WScript.Echo "There were " & intErrorCount & " errors during the operation"
WScript.Echo "--------------------------------------------------------------------"


'Sub to recursively delete all empty folders. 
Sub RecursiveDeleteEmptyFolders(ByVal strDirectory)
	On Error Resume Next
	Dim objFolder, objSubFolder
	Set objFolder = objFSO.GetFolder(strDirectory)
 
	WScript.Echo "Checking Folder: " & strDirectory & ". Contains " & objFolder.Files.Count & " files and " & objFolder.SubFolders.Count & " folders."

	'If the RemoveDesktopIni or RemoveThumbsDB Flag is set to True then remove any files called Desktop.ini or thumbs.db
	If objFSO.FileExists(strDirectory & "\desktop.ini") Then 
		objFSO.DeleteFile(strDirectory & "\desktop.ini")
		If Err Then
			WScript.Echo "Error deleting:" & strDirectory & "\desktop.ini" & " - " & Err.Description
			intErrorCount = intErrorCount + 1
			Err.Clear
		End If
   	End If
	If objFSO.FileExists(strDirectory & "\thumbs.db") Then 
		objFSO.DeleteFile(strDirectory & "\thumbs.db")
			If Err Then 
				WScript.Echo "Error deleting:" & strDirectory & "\thumbs.db" & " - " & Err.Description
				intErrorCount = intErrorCount + 1
				Err.Clear
		End If
   	End If
	
	'Now check if the folder contains any files. 
	If objFolder.Files.Count = 0 Then
	
		'Then check if there are any subfolders. 
		If objFolder.SubFolders.Count = 0 Then
		
			'Check that the subfolders do not begin with a tilde, and if they do not, delete the folder. 
			If Left(objFolder.Name,1) <> "~" Then
				WScript.Echo "Deleting: " & objFolder.Path
				objFolder.Delete
				If Err Then 
					WScript.Echo "Error deleting:" & objFolder.Name & " - " & Err.Description
					intErrorCount = intErrorCount + 1
					Err.Clear
				End If
			End If
			
		Else
			'Subfolders found, so go through each of those. 
			For Each objSubFolder in objFolder.SubFolders
				RecursiveDeleteEmptyFolders objSubFolder.Path
			Next
		End If
	Else
							
		'Files have been found in the folder, but check any subfolders anyway
		For Each objSubFolder in objFolder.SubFolders
			RecursiveDeleteEmptyFolders objSubFolder.Path
		Next
	End If
End Sub

3 people found this post useful.
Posted in VBScript | Leave a comment

MagicISO with Intel ICH10R RAID Array

Was having trouble getting MagicISO to install on my Windows 7 x64 Professional machine that I had just rebuilt. It worked fine before I installed new hard disks, but not now.

My new HDD have been installed in a RAID1 configuration using the built in Intel ICH10R RAID controller. This involved giving Windows a driver when installing (the built in one on the RTM CD does not load correctly and causes setup failures).

My CD drive is also on the same ICH10R bus, so a filter had been set on the drivers in the registry. This was stopping the successful installation of virtual CD drives which did not use the Intel bus.

The solution in this case is to remove the filters.

  1. Open regedit.
  2. Browse to HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Class\{4D36E965-E325-11CE-BFC1-08002BE10318}
  3. Rename UpperFilters to UpperFilters.old
  4. Rename LowerFilters to LowerFilters.old
  5. Reboot your machine.

MagicISO should then install successfully and be able to create virtual drives.

The values that I had in my registry entries were: LowerFilters:iaStorF, UpperFilters: GEARAspiWDM. The first is created by the Intel RAID controller card, and the second is created when iTunes is installed.

After you have rebooted and installed MagicISO, you may need to rename UpperFilters1 back to the original name so that iTunes will load without an error.

 

Be the first to like.
Posted in Windows 7 | Leave a comment
  • Tags

  • Categories

  • My LinkedIn Profile

    To see my LinkedIn profile, click here:

    Craig Tolley
  • September 2014
    M T W T F S S
    « Aug    
    1234567
    891011121314
    15161718192021
    22232425262728
    2930  
  • Meta

  • Top Liked Posts

    Powered by WP Likes

Swedish Greys - a WordPress theme from Nordic Themepark.