Monday, 24 October 2016

Outlook - Mailbox Full Message after storage quota increased (or removed)

I recently experienced an issue where multiple users for a mailbox were getting a "mailbox full" message in Outlook. When the message first appeared, I removed the storage quota on the mailbox, but after a server restart (and of course restarting the outlook clients), they were still getting prompted with the same message.

The solution ended up being to remove the .ost file for this particular mailbox (default location is %localappdata\Microsoft\Outlook) and then restarting the Outlook client (you will need to close Outlook before it will let you delete the .ost file)

The .ost file will automatically be re-created when Outlook is opened, and mail will then be downloaded back into the .ost file from the server.

Wednesday, 19 October 2016

iPhone - Bottom Half of Screen Disappearing

For quite some time I experienced what I thought was a strange issue on my iPhone where the bottom half of the screen would suddenly disappear, or "scroll" down underneath the viewable area of the screen - just like in the picture below;

Original home screen
Home screen after "Reachabiliy" activated

After a little bit of research, I found out that is actually a feature within the iPhone software known as "reachability". The idea being that the top half of the screen scrolls or moves towards the bottom of the screen, to make items that were originally at the top of screen more accessible when using the device with one hand. Pretty clever, right?

Reachability is activated by double tapping (note: not double pressing) the home button. Ie. tap the home button twice rapidly, but don't actually press the button down so it 'clicks'

Press the home button or tap anywhere on the screen to return the screen to normal

Monday, 17 October 2016

Shutdown/Restart Mac from Windows - Command Line

Administrators may occasionally be required to perform maintenance on Mac devices/servers from a windows based operating system. The following utility and command can be used to remotely shutdown/restart/reboot a mac/linux device from the command line on a windows based system - eg. Windows 7, 8, 10, Server 2003, 2008, 2012 etc.

First of all, create a .txt file (in this case it will be placed in C:\ but it can be placed anywhere), and put the following line inside the text file. This is the actual shutdown command that will be sent to the Mac/Linux device

sudo shutdown -r now

Next we need to download the application plink.exe. Plink.exe is a free utility that can be download absolutely free from the website below;

Place the plink.exe file into a folder on the windows device, and then run the following command from a command line. Note that this command references the command.txt we created above, so adjust the path accordingly if you didn't place it in C:\ as per this example

plink.exe -ssh -t mac-ipaddress -l root -pw macrootpw -m c:\command.txt

mac-ipaddress = the IP address or hostname of the Mac/Linux device to be shutdown
macrootpw = the password for the "root" user account of the Mac/Linux device to be shutdown

If you do not have the "root" user account enabled, or do not know the password it can be enabled and reset by following the instructions in the following link;

Friday, 14 October 2016

Windows Server Health Check Script - Powershell

Here is a script that I have developed to run a "health check" on a windows server. The script can be run on demand, but I tend to run them from Windows Task Scheduler with a trigger to run on windows startup to automatically check some of the key things within a windows server. At a high level, here is what is contained within the script;
  • A report of all services with a start mode of "Automatic" but are not in a "running" state
  • Any events in the windows Application log from the past 24 hours that are not categorized as "informational"
  • Any events in the windows System log from the past 24 hours that are not categorized as "informational"
  • A size report of all logical disks in the server showing size, and free space in GB and as a percentage
  • Average CPU load on server
  • Current memory usage (as a percentage)
All this information is retrieved by the script and stored in a .html file. At the end of the script the .html file is saved to disk and sent as an email attachment.

A few other points to note;
  • The start-sleep command is used at the start of the script to delay the script running for 300 seconds (5 minutes). If the script runs as soon as it is triggered on windows startup, not all windows components are ready/loaded and the results of the script are incomplete
  • The log file is saved by default into C:\Admin\ServerHealthChecks with a filename based on the target IP/hostname and date/time the script runs. This can be changed using the $logfile variable. Make sure the path specified in $logfile exists otherwise the .html file will not save correctly
  • If a disk has 10-20% free space, it's text will be orange in colour. Less than 10% will be red. Otherwise it will be green
  • Likewise, if CPU usage is 80-90% it will be orange. 90-100% will be red
  • If free memory is 10-20%, it will be orange. Less than 10% will be red
  • Be sure to update the variables at the end of the script (under #Send Log File via Email) to work with your email system/environment
Powershell script/code is below;

#Server Health Checker
#Author: Peter Morrissey

start-sleep 300

$target = ""

#Get Last Bootup Time
$osprops = get-wmiobject -class win32_operatingsystem 
$lastboot = $osprops.ConvertToDateTime($osprops.LastBootUpTime)

#Log File
$fulldate = Get-Date
$logfile = "c:\" + "Admin\" + "ServerHealthChecks\" + $FullDate.ToString("yyyyMMddHHmm") + "-" + "$Target" + ".html"
$global:strname = $env:username
$global:html = @()
$html += "<html>"
$html += '<font face="courier">'
$html += "<title>Server Health Check - $Target</title>"
$html += "<h3>$FullDate</h3>"
$html += "<h4>Server Health Check Script - Run by $global:strname</h4>"
$html += "<h4>Target Server: $Target</h4>"
$html += "<h4>Hostname: $env:computername</h4>"
$html += "<h4>Last Boot: $lastboot </h4>"
$html += "<p>"
$html += "******************************************************************************************* <p>"

#Services Check
write-host "Getting Service Information"
$html += '<u>Service Report - Services with StartMode "Auto" and State not currently "Running" </u><p>'

$servicelist = invoke-command -computername $target {
        get-wmiobject -class Win32_Service | Where {$_.StartMode -eq "Auto" -and $_.State -ne "Running"} | Select DisplayName, Name, StartMode, State
if ($servicelist){$temphtml = $servicelist | Select DisplayName, Name, StartMode, State | ConvertTo-HTML -fragment
                    ForEach ($line in $temphtml){$html += "$Line"} }
ELSE {write-host "All automatic services are running";$html += "All automatic services are running <p>"}

$html += "<p> ******************************************************************************************* <p>"

#EventLog Checks
write-host "Querying Application Log on $Target"
$appeventlog = invoke-command -computername $target {
        $targetDate = Get-Date
        $targetdate = $targetdate.adddays(-1)
        get-eventlog -logname "Application" -after $targetdate | where-object {$_.entrytype -ne "Information" -and $_.Source -ne "Print" -and $_.Source -ne "TermServDevices"} 

if ($appeventlog){#write-host $AppEventLog
                  $html += "<u>Application Log Non-Information Events (Last 24 Hours)</u><p>" 
                  $temphtml = $appeventlog |  Select TimeGenerated, EntryType, Source, Message | ConvertTo-HTML -fragment
                  foreach ($line in $temphtml){$html += "$line"}
ELSE {$html += "No non-informational events found in application log in past 24 hours <p>"}

$html += "<p>*******************************************************************************************<p>"

write-host "Querying System Log on $Target"

$syseventlog = invoke-command -computername $Target {
        $targetdate = get-date
        $targetdate = $targetdate.adddays(-1)
        get-eventlog -logname "System" -after $targetdate | where-object {$_.entrytype -ne "Information" -and $_.source -ne "Print" -and $_.source -ne "TermServDevices"} 

if ($syseventlog){#write-host $syseventlog
                  $html += "<u>System Log Non-Information Events (Last 24 Hours)</u><p>"
                  $temphtml = $syseventlog | Select TimeGenerated, EntryType, Source, Message | ConvertTo-HTML -fragment
                  ForEach ($line in $temphtml){$html += "$Line"}
else {$html += "No non-informational events found in system log in past 24 hours<p>"}

$html += "<p>*******************************************************************************************<p>"

#Local Disk Health Check
write-host "Getting logical disk information"
$diskreport = invoke-command -computername $target {
    Get-WmiObject Win32_logicaldisk | Select DeviceID, MediaType, VolumeName, `
    @{Name="Size(GB)";Expression={[decimal]("{0:N0}" -f($_.size/1gb))}}, `
    @{Name="Free Space(GB)";Expression={[decimal]("{0:N0}" -f($_.freespace/1gb))}}, `
    @{Name="Free (%)";Expression={"{0,6:P0}" -f(($_.freespace/1gb) / ($_.size/1gb))}} `

$html += "<u>Logical Disk Report</u><p>"
$temphtml = $DiskReport | Select DeviceID, VolumeName, "Size(GB)", "Free Space(GB)", "Free (%)" | ConvertTo-HTML -fragment
foreach ($Line in $temphtml)
    if ($line -like "*%<*")
        $lineindex = [array]::IndexOf($temphtml, $line)
        $templine = $line -split "%"
        $templine = $templine -replace(" ","")
        $templine = $templine[0] -split "<td>"
        $templine = $templine[5]
        $templine = $templine.trim()
        $templine = [decimal]$templine
        if ($templine -le 20 -and $templine -ge 10){$temphtml[$lineindex] = $temphtml[$lineindex].Replace("<td>",'<td><font color="orange">')}
        if ($templine -lt 10 ){$temphtml[$lineindex] = $temphtml[$lineindex].Replace("<td>",'<td><font color="red">');
                                $smtpclient = new-object 
                                $mailmessage = New-Object 
                                $smtpclient.Host = "" 
                                $mailmessage.from = ("") 
                                $mailmessage.Subject = “Server Health Check Alert - Disk Space Low - $target"
                                $mailmessage.Body = "Low disk space found on $target -  $temphtml"
                                $mailmessage.IsBodyHtml = $true

foreach ($line in $temphtml){$html += "$line"}

$html += "<p>*******************************************************************************************<p>"

#Check CPU Load
write-host "Getting CPU Stats"
$cpudata = get-wmiobject win32_processor -computername $target | measure-object -property LoadPercentage -average | select Average
$html += "<u>CPU Load (Average)</u><p>"
$cpuusage = $($cpudata.average)
    if ($cpuusage -ge 80 -and $cpuusage -le 90){$html += '<font color="orange">' + "Average CPU Load: $cpuusage%" + '</font>'}
    elseif ($cpuusage -gt 90){$html += '<font color="red">' + "Average CPU Load: $cpuusage%" + '</font>'}
    elseif ($cpuusage -lt 80){$html += '<font color = "green">' + "Average CPU Load: $cpuusage%" + '</font>'}
$html += "<p>*******************************************************************************************<p>"

#Check Memory Usage
write-host "Getting Memory Usage"
$html += "<u>Memory Usage Report</u><p>"
$memdata = get-wmiobject win32_operatingsystem -computername $target | select FreePhysicalMemory, FreeVirtualMemory, TotalVirtualMemorySize, TotalVisibleMemorySize
$freephysicalmem = $($memdata.freephysicalmemory)
$freevirtualmem = $($memdata.freevirtualmemory)
$totalvirtualmem = $($memdata.totalvirtualmemorysize)
$totalvisiblemem = $($memdata.totalvisiblememorysize)
$memusage = ($totalvisiblemem - $freephysicalmem) / $totalvisiblemem * 100
$freemem = $freephysicalmem / $totalvisiblemem * 100
[decimal]$freemem = "{0:N0}" -f $freemem

if ($freemem -lt 10){$html += '<font color="red">' + "Free Memory (%): $freemem" + '</font>'}
elseif ($freemem -gt 10 -and $freemem -le 20){$html += '<font color="orange">' + "Free Memory (%): $freemem" + '</font>'}
elseif ($freemem -gt 20){$html += '<font color="green">' + "Free Memory (%): $freemem" + '</font>'}
$html += "<p>*******************************************************************************************<p>"

#Export Log File
$html | out-file $LogFile

#Open Log File in Internet Explorer
#Invoke-Item $Logfile

#Send Log File via Email
$smtpclient = new-object 
$mailmessage = New-Object 
$smtpclient.Host = "" 
$mailmessage.from = ("") 
$mailmessage.Subject = “Server Health Check Results - $target"
$mailmessage.Body = "Server Health Check Results for $target"
$mailmessage.IsBodyHtml = $true

Thursday, 13 October 2016

Automatically logoff sessions from windows server using Powershell

Windows server has the functionality through group policy to automatically log off users at a certain time of day, or once their set logon hours expire etc, but in my experience (and many other users based on internet research), it doesn't work very reliably.

Here is a script you  can use that will get a list of all current user sessions on a server, and log them off. A "safelist" is also included where you can specify usernames that should not be logged off automatically by this script - ie. administrator accounts etc. Usernames should be specified in inverted commas and separated by single commas.

I've also incorporated logging functionality, as it may be useful to know what users are staying logged onto the server (perhaps when they shouldn't be), and to be 100% certain about what the script is doing, or has done. Adjust the $logfile variable as required, or ensure the default folder (C:\Admin) exists for it to work correctly.

This does not require any additional modules to be installed either.

The script works by using the query session command, and then manipulating/formatting the results to obtain a list of current user sessions. Because the query session command is a DOS based command, the results aren't formatted nicely into variables/members that powershell can easily understand and work with, so formatting/manipulation is done using the .Substring and .Trim functions. The list of user sessions t hat is obtained is then compared against the safelist and if the user is not present in the safelist, is then logged off the server.

You will need to setup a scheduled task to run this powershell script - you can view my blog post here on setting up Powershell scripts to run via scheduled tasks in windows

$safelist = "administrator", "user1"
$date = get-date -f "ddMMyyyy"
$logfile = "C:\Admin\LogOffScript-$date.txt"

$sessions = query session |  where-object { $_ -notmatch '^ SESSIONNAME' } | %{
    $item = "" | Select "Active", "SessionName", "Username", "Id", "State", "Type", "Device"
    $item.Active = $_.Substring(0,1) -match '>'
    $item.SessionName = $_.Substring(1,18).Trim()
    $item.Username = $_.Substring(19,20).Trim()
    $item.Id = $_.Substring(39,9).Trim()
    $item.State = $_.Substring(48,8).Trim()
    $item.Type = $_.Substring(56,12).Trim()
    $item.Device = $_.Substring(68).Trim()

foreach ($session in $sessions)
if ($safelist -notcontains $($session.username))
$time = get-date
logoff $($
write-output "$time | Logged off $($session.username)" | out-file $logfile -append

Wednesday, 12 October 2016

Windows - Unable to remove printer driver - The specified printer driver is currently in use

Sometimes you may need to uninstall a printer driver from a computer (because of corruption, to re-install etc), and may get the below error message;

"Unable to remove printername. The specified printer driver is currently in use"

This may even occur AFTER you have removed the printer itself from your list in Devices & Printers.

Here are some steps I found that allowed me to remove the printer and printer driver without having to restart the computer;

  1. Open Devices and Printers
  2. Right click the device you need to remove and select Remove Device
  3. Open Services.msc and locate the Print Spooler service
  4. Right click the Print Spooler service and select Stop
  5. Open regedit
  6. Browse to the key HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Print\Environments\
  7. Depending on whether you are running a 32 or 64 bit windows, expand the key for Windows NT x86 (if you're running 32 bit windows), or Windows x64 (if you are running 64 bit windows)
  8. Expand the Print Processors key
  9. Rename any entries under Print Processors to have .old on the end. In the example below, there is one entry, winprint which I renamed to winprint.old

  10. Go back to services.msc and start the Print Spooler service
  11. Open the Print Server Properties and try to remove the driver pack - it should now remove successfully
  12. Once the driver pack is removed, stop the Print Spooler service again
  13. Go back to regedit and rename the key(s) you renamed to have .old on the end back to their original name(s) - as per my example, winprint.old will be renamed back to winprint
  14. Start the Print Spooler service from services.msc
  15. Re-install printer & drivers as required

Tuesday, 11 October 2016

Removing old Windows Updates - Windows Installer Directory

Windows updates can tend to take up a large number of space after some time on the system drive (C:\), and are not easily removed.

Updates are typically installed into the C:\Windows\Installer directory and hold the .msi and .msp files used to install (or uninstall) windows updates.

A company called "Homedev" have developed a product called "Patch Cleaner" that is clever enough to search this windows installer directory and detect which patches can safely be removed. Over time windows updates tend to replace, outdate or supersede each other - rendering them useless and taking up precious hard disk space on your hard disk!

How does it work? Well, as explained by Homedev, their application queries the operating system for a list of all the currently installed patches and updates. It then compares this list returned by the operating system against all the files in the C:\Windows\Installer directory. Anything that's found in the folder but not in the list provided by the operating system is flagged as able to be removed by the application.

The application also has the ability to relocate the files to another location first (such as another drive, like an external USB hdd) which reduces the risk involved in removing some of these files. If it turns out the files are required they can simply be copied back to the C:\Windows\Installer directory.

The latest version of the application can be downloaded and installed from the below website;

  1. Once you have downloaded the file, double click it to run/execute
  2. Click Next to begin the installation process

  3. Select I Agree on the license agreement then select Next

  4. It is recommended to leave the default installation path and set to Everyone to be able to access the application. Click Next

  5. Click Next to begin the installation

  6. Click Close to exit the wizard once installation has completed

  7. You can now run PatchCleaner from the shortcut placed on the desktop or from within the Start Menu

  8. Upon startup, the application will automatically scan for files that can be removed

  9. Once the scan is finished, you will be presented with a window like the one below. The screen details how many files are orphaned and can be removed (in this example, there are 32 files, totalling 2.17GB in size). You can click either the Delete button to permanently delete the files, or the Move button the move all these files to another location (as mentioned previously)

  10. After deleting or moving the files, the application will run another scan and present a window again like the one above.

Monday, 10 October 2016

iPod/iPhone/iPad not appearing in iTunes

I occasionally experience an issue with my iPod, where after connecting it to my laptop via USB, and having the iPod appear in Windows Explorer, it won't appear as a device in iTunes

iPod showing in Windows Explorer but not iTunes

Follow the steps below to fix the issue;

  1. Close iTunes if you already have it running
  2. Click on the Start button (bottom left corner of screen) and type services.msc and press Enter
  3. A new window will now open showing a list of all windows services. Sort the list by name and locate the Apple Mobile Device Service
  4. Right click on this service and select Restart

  5. Once the service has restarted, locate the iPod Service. Right click on this service and select Restart

  6. Open iTunes. Your iPod/iPhone should now appear within iTunes correctly

Friday, 7 October 2016

iOS 10 - How to undelete/restore/recover standard iPhone apps after deleting them

When Apple introduced iOS 10 for iPads and iPhones, they introduced a new feature that allows you to uninstall the standard (apple) apps that come pre-installed on the phone - eg. stocks, mail, newsstand etc.

The process to remove them is simple - just like removing any other app on your device, you press and hold on any of the icons on the home screen for a few seconds until they all start moving slightly, and have a little "x" in the top right corner above each icon. You then click the small "x" to remove the app

What isn't entirely clear or obvious at first is the process to get these apps back after you've removed them. Turns out the answer is very simple, you just need to download them again from the App Store!

For example, if you open the App Store and search for the "mail" app, the first result that appears is the default Apple Mail app. Click the download or "cloud" icon next to it to download it again, and away you go!

Optus - Sagemcom F@ST 3864 modem/router - admin username and password

The Sagemcom F@ST 3864 modem/router that is provided by Optus has an administrative interface that you can login to to access advanced features that aren't accessible via the the "standard" interface.

The standard interface is accessed via and allows access to basic settings such as wifi options without needing to enter a username/password

However, if you change the "loginuser=" value from a "1" to a "0" you get prompted for a username/password. Once you've entered the correct username/password you can then access more advanced features within the modem setup/config.

There are a number of forum posts stating some of the default usernames/passwords for this modem, but none of them worked for me, even after a factory reset. What I did stumble across though was how to definitively (and easily) retrieve the admin password for this modem;

  1. Open a web browser and go to
    You will be presented with a screen like the one pictured below;

  2. Right click in a blank area of the page, and select the option to "View source" or "View page source" (the wording might be slightly different depending on what browser you are using)

  3. This will load up all the html code used on this page. If you look towards the top of the page, you will see a line starting with "pwdAdmin = " - what is after this and contained within single quotes is the admin password that is set on the router

  4. You can then go to the URL and enter the username "admin" and the password from Step 3 above and you will be able to access the hidden/advanced menu options within the router

Fix Windows Update Error Code 80070003

I got this error code today on a Windows 7 PC after trying to install some windows updates

Code 8007003
Code 643

To fix it, follow the steps below;
  1. Click on the Start button (bottom left corner) and types services.msc and press enter (to open the Services control panel)
  2. Locate the Windows Update service. Right click it and select Stop

  3. Open Windows Explorer. Navigate to the folder C:\Windows\SoftwareDistribution\Download folder. Delete everything within this folder - (this is where the windows updates are downloaded to before being installed)
  4. Go back to your list of services from Step 2. Right click the Windows Update service and select Start
  5. Go back to your windows updates and click Check for updates again and proceed to install them as you normally would

Thursday, 6 October 2016

IIS - Make OWA the Default Website Page

After installing Microsoft Exchange, a "virtual directory" for Outlook Web Access (OWA) is created that is generally accessible via the URL

In some scenarios it may be preferable to configure to redirect automatically to the OWA virtual directory (as users may forget to include this part if they are manually typing the URL). This means as soon as they try to access the root domain website, they are automatically presented with a login page for OWA.

It is very easy to configure, as per the steps below;

  1. Open Internet Information Services (IIS) Manager (from Control Panel > Administrative Tools)
  2. Expand the tree from the left hand side and highlight/select Default Web Site

  3. Double click the HTTP Redirect icon from the main window

  4. Select the option to Redirect requests to this destination and enter /owa into the text box below
    Select the option to Only redirect requests to content in this directory (not subdirectories). Ensure the status code is set to Found (302)

  5. Click Apply in the top right corner to apply the changes
  6. Try accessing the base URL again and you should be automatically redirected to the OWA login page

Wednesday, 5 October 2016

Get Computer Serial Number & HP Product Number using Powershell

You can use powershell to quickly obtain the serial number/service tag for a computer/server

get-wmiobject win32_bios | select SerialNumber

Some computer manufacturers (such as HP) also have a product number that you can access with the following command;

get-wmiobject win32_computersystem | select-object OEMStringArray

This win32_computersystem class also contains other details/information such as the Manufacturer and Model number of the computer system - you can view all the details by removing the pipe and everything after it

get-wmiobject win32_computersystem

This information is also available through the registry via the key

Tuesday, 4 October 2016

Find and Change Read Only Files using Powershell

This script can be used to search for all files that are marked as "read only" on a windows file system. The script will search all files within the $targetdir variable (including all subfolders)

$targetdir = "D:\multimedia"

$readonlyfiles = get-childitem $targetdir -recurse | where {$_.isreadonly -eq $true}

If you wish to remove the read only property from any read only files that are found, we can adjust the script as per below;

$readonlyfiles = get-childitem $targetdir -recurse | foreach {if($_.isreadonly){$_.isreadonly = $false; write-host $_.fullname}}

The script will also display/echo back any files that it finds and changes from being read-only.