Java keystore certificate missing after Jenkins upgrade

Java keystore certificate missing after Jenkins upgrade

Following a tricky upgrade to a Jenkins server it was found that the server was no longer able to communicate with the Git server, although SSH access with private keys was stil working correctly. On invrestigating the Jenkins logs (found at Logs at: http://YOUR-JENKINS-SERVER-URL/log/all) this error was found to be the problem:

Failed to login with creds MYCREDENTIALNAMEHERE
sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.provider.certpath.SunCertPathBuilder.build(Unknown Source)
at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(Unknown Source)
at java.security.cert.CertPathBuilder.build(Unknown Source)
Caused: sun.security.validator.ValidatorException: PKIX path building failed
at sun.security.validator.PKIXValidator.doBuild(Unknown Source)
at sun.security.validator.PKIXValidator.engineValidate(Unknown Source)
at sun.security.validator.Validator.validate(Unknown Source)
at sun.security.ssl.X509TrustManagerImpl.validate(Unknown Source)
at sun.security.ssl.X509TrustManagerImpl.checkTrusted(Unknown Source)
at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(Unknown Source)
Caused: javax.net.ssl.SSLHandshakeException

The problem here is that the Java runtime is not able to validate the connection as it doesnt have the relevant SSL certificate. To resolve I needed to download the certificate from the site and add it to the Java Keystore.

Photo by Chunlea Ju on Unsplash

On the server download the relevant web certificate for connecting to the relevant site (a GitHub server in my instance) that you are trying to access. Next find which Java JRE your Jenkins was using. This can be found in your Jenkins.xml file under the executable element. For example %BASE%\jre\bin\java means c:\Jenkins\JRE\bin\java if you have installed Jenkins to C:\Jenkins on Windows. Now find the cacerts file inside that Java runtime that it was using (for example C:\Jenkins\jre\lib\security\cacerts) where you will need to install the Certificate. To add the cert to the Java Keystore for that Java install run the below in a terminal:

keytool -import -alias INSERT_ALIAS_NAME_HERE -keystore PATH_TO_JRE_HERE\security\cacerts -file CERTIFICATE_FILE_NAME

for example…

keytool -import -alias ExampleName -keystore C:\Jenkins\jre\lib\security\cacerts -file exampleCertFile.cer

If you are asked for a password then it will be ‘changeit‘ by default.

Now the JRE Java runtime on the box that Jenkins is now using has the Certificate installed it will be able to make a SSL connection.

Free SSL encryption on Azure with Cloudflare

Free SSL encryption on Azure with Cloudflare

I have a small Web Application site (running ASP.net Core) hosted on Microsoft Azure under a shared plan. Azure shared plans are budget friendly whilst providing features like custom domain names. Until recently the site was HTTP only which was initially fine for my use case but as HTTPS is becoming increasingly a minimum standard on most sites and even browsers are now warning users when navigating to unsecure sites, it was time to move to HTTPS.

Photo by James Sutton on Unsplash

The Problem

Whilst setting up HTTPs certificates has got easier and cheaper there is still usually a trade off between effort and cost. I could have added SSL to my Azure subscription but I couldn’t justify that cost for the site in question. So I needed an easy and cheap solution – and I definitely found it with Cloudflare!

The Solution

I am amazed how easy it was to set up SSL fronting of my existing site using Cloudflare’s SSL.

  1. Create an account at Cloudflare.com
  2. Enter your domain name where the site is hosted.
  3. Confirm the pricing plan (choose FREE)
  4. Cloudflare scans the domain’s DNS entries and asks you to confirm which entries you want proxying. Once done you’ll be given the new NameServers which you’ll need to update on your domain registar’s site.
  5. Once the NameServers have synced (could take minutes to 48 hours) you are done!

There are a few configuration modes for their SSL offering, e.g. full SSL (i.e. SSL from end users to Cloudflare to origin server) or Flexible (i.e. where the SSL stops at Cloudflare and traffic is not encrypted from your origin server to Cloudflare). The options you choose will depend on your setup and your requirements. As my site is hosted on Azure I got Full SSL encryption by default (using Azure’s SSL keys to encrypt traffic from my web server to Cloudflare).

You don’t need an Azure hosted site for this SSL goodness to work as they will front your service wherever its hosted.

This process was so easy I should have done it months ago. For more info checkout these resources:

RunAs Issue? Check Secondary Logon Service.

RunAs Issue? Check Secondary Logon Service.

On Windows if you are having problems trying to perform an action as a different user via the RunAs command then it might be due to the ‘Secondary Logon Service’ not running. I recently had this problem on Windows Server and after some investigations found that the ‘Secondary Logon Service’ had been disabled, starting the service resolved the issue. By default it is set to ‘Manual’.

The error you get from the RunAs command may vary depending on OS version but will report a problem running a process or service. This is the error I get on Windows 10:

1058: The service cannot be started, either because it is disabled or because it has no enabled devices associated with it.

Linux Home Server Build

Linux Home Server Build

On this blog I have posted many times about my home server configuration and seeing as I’ve recently updated it I thought I’d give a quick overview of the changes made and provide some tips for setting up a Linux home server.

My home server (an HP MicroServer) is used for NAS file storage, running Plex Media server and a few other ativites including client backups. Previously my server was running Windows Home Server 2011 which was an excellent Home Server OS from Microsoft based on Windows Server 2008 R2. In additon to file sharing it also allowed for easy server administration and client PC backups. Client PCs would backup images to the server allowing for client files or whole systems to be restored. Unfortunately Microsoft discontinued Windows Home Server and it is no longer supportrd and Windows Server 2008 R2 updates will stop in July 2019. In terms of replacement options there were several, whilst all Windows offerings are too expensive and seem overkill for a home server, serious Linux and BSD options include Free NAS, Amahi, Ubuntu Server and numerous Linux desktop distros. I would also recommend looking at a Synology if you have the budget.

In the end I chose Lubuntu 18.04 (LTS) desktop distro for my needs. Why a desktop distro for a server? Well I dont need to squeeze every onunce of performance from the server and the Lubuntu desktop is so lightweight and efficient I can have a graphcial desktop enviroment as well as great server performance. It is handy to have the option to be able to RDP into the box and use the Lubuntu desktop as an alternative to SSH when required.

I installed the OS, and checked for updates:

sudo apt-get update
sudo apt-get dist-upgrade

After installing the OS I inserted the data drives and mounted them under a /mydata mount point so that I can easily access all the files on those drives. To make these mount points persistent I edited /etc/fstab to add each one using the UUID of the partition (which is found in Disks app or the GParted app)

sudo nano /etc/fstab

Then add an entry for each parition to mount …

 UUID=YOUR_OWN_PARTITION_UUID /mydata/d1/ ext4 defaults 0 0
UUID=YOUR_OWN_PARTITION_UUID /mydata/d2/ ext4 defaults 0 0

Configure The FireWall

The ufw (uncomplicated firewall) firewall is installed on Lubuntu by default but is turned off so turn it on and check its status:

sudo ufw status 

If inactive then activate it with:

sudo ufw enable

To see its status and current rules:

sudo ufw status verbose

Add new rules with:

sudo ufw allow PORTNUMBERHERE 

Install XRDP Remote Desktop Service

Next I set up XRDP for remote access to this headless server.

sudo apt-get -y install xrdp
sudo ufw allow 3389/tcp
sudo systemctl enable xrdp
sudo systemctl restart xrdp

At this point I hit may issues but this hack below seemed to be the one that led to a working XRDP session but using this command to create a .xsession in home directory of connecting user:

 echo "lxsession -s Lubuntu -e LXDE" > ~/.xsession 

For more information see this article.

Setup Cockpit Web Interface

For more remote administration and monitoring goodness I installed Cockpit which is a web based interface for servers with lots of useful features.

sudo apt-get install cockpit
sudo ufw allow 9090

Then browse to https://yourserverip:9090

For a useful Cockpit install guide check out this link.

Setup Samba for file sharing

The whole point of a file server is to share files and in order to support file sharing with Windows devices on the network you’ll need to setup Samba. A good link for setting up Samba can be found here.

sudo apt-get install samba

Set a password for your user in Samba.

sudo smbpasswd -a        

All the folder shares and their configuration are stored in the smb.conf file which can be edited by opening it up in a text editor like nano.

 sudo nano /etc/samba/smb.conf 

In the smb.conf file you may want to change the workgroup name to the same as that used by your window PCs and then add each of your folder shares.

[<folder_name>]
    path = /folder/path
    valid users = <user_name>
    read only = no

Once you have made the required changed restart the smb daemon service

sudo service smbd restart

You’ll also likely need to punch a hole in the ufw firewall for samba

sudo ufw allow Samba

Once Samba has restarted, use this command to check your smb.conf for any syntax errors with testparm

testparm

For a good guide on more complex permissions check out this guide here.

It’s worth noting that users need to have Unix perms on the underlying folders in order to be able to access them. Amend Linux file permissions as required.

Scheduled Tasks with Cron

For scheduled tasks (backup jobs etc) I have configured Cron jobs to run bash scripts (although I could have kept my existing PowerShell scripts as PowerShell now runs on Linux too) but they needed a rewrite anyway.

Open your cron job file with…

sudo crontab -e 

then add entries like this example:

# run test job at 11:15 every day 
15 11 * * * . /etc/profile; /bin/bash /home/me/testjob.sh > /tmp/cron.out

For more info on Cron check out this guide and for an awesome helper tool for building the Cron schedule times check out corntab.com.

Summary

So I’ve covered the basics of how I’ve set up my Home Server using Lubuntu which others may find useful. I’ve been running this setup for a few months and so far I am very pleased with its performance and stability.

Future steps are to install Plex Media Server and configure client PC backups. As I want to use the Snaps for Plex I am waiting for the offical Plex Snap Package to come out of BETA as I’m not in a rush. Alternatively I may use Docker to run Plex. To replace the client PC backup feature I previously had with Windows Home Server I will soon be moving to a client imaging tool such as CloneZilla, Acronis or Windows Backup and then copying the images to the server.

Vertical Monitors

Vertical Monitors

Whilst I’ve been using a multiple monitor setup at home and work for many years only for the past year have I been using one of the two in vertical/portrait mode, and I’m hooked.

The benefits for using multiple displays over a single display has been researched numerous times over the years. Estimates on the amount of productivity gain that can be made vary from 20% to 42% in the research I have seen, but even at 20% the second monitor soon pays for itself. Jon Peddie Research (JPR) in their 2017 research found a 42% gain in productivity based on the increased number of pixels available via multiple screens. And whilst some of this gain can be made from just larger screens as opposed to more screens there are certainly ease of use advatanges to multiple screens and several studies sponsored by Dell have found the user experience to be more pleasureable with multiple screens. I find using several screens an easier way of arranging windows than trying to arrange them on one large monitor.

“We found that users of multiple monitors have an average expected productivity increase of 42%,” said Dr. Jon Peddie, President of Jon Peddie Research.

University of Utah study showed that a second monitor can save an employee 2.5 hours a day if they use it all day for data entry.

“The more you can see, the more you can do.” Jon Peddie, 1998

But what about having monitors in portrait mode, well the Jon Peddie research also stated that additional benefit could be had by reducing scrolling for information.

“Having one of the monitors in portrait mode adds to productivity by eliminating the need to scroll.”

After taking a week or so to get used to the portrait mode I quickly found its benefits. It’s ideal for viewing anything that requires vertical scrolling, e.g. web pages, code, log files, Jira backlogs etc. In a quick test of a code file in VSCode I could see 62 lines of code on my 24inch hortizontal monitor, but 120 lines when the file was moved to the vertical monitor. Not only do you reduce scrolling but there are advantages in being able to see more of a document in one go, helping you visualise the problem.

On a side note the Xerox Alto, which was the first computer designed to support a GUI based OS, had a vertical screen to represent a document layout.

twomonitors_small

Over the past decade or more displays have moved to widescreen format and many applications have tailored their UIs to fit this trend. This means that having all portrait monitors can quickly lead to some frustrations and the need to horizontally scroll, thus reducing the additional productivity gains. This is why I have found that (for me) the ideal setup is one landscape display and one portrait display (as in the image above).

With this formation you can use the display that is best suited to the task at hand, and so you have the best of both worlds. Combine this with a few simple keyboard shortcuts to move things between monitors and you’ll find soon be loving the layout. In Windows using the Windows key and the cursor keys together can quickly move and dock windows. Linux distros vary.

Since I made the switch to one vertical at work I have had numerous colleagues see the benefits and be converted to this layout, so if you have a monitor that is capable of being turned vertically then I recommend you give it a go and see how you get on. You might get hooked!

 

Calculate a file hash without 3rd party tools on Windows & Linux.

Calculate a file hash without 3rd party tools on Windows & Linux.

If you need to generate a hash of a file (e.g. MD5, SHA256 etc) then there are numerous 3rd party tools that you can download but if you are restricted to only built in tools or don’t need to do this often enough to install something then there are built in OS tools for Windows and Linux that can be used.

Windows:

For Windows there is “certUtil” which can be used from the command prompt console with  the “-hashfile” option to generate a hash for a supplied file:

CertUtil [Options] -hashfile filePath [HashAlgorithm]

The [HashAlgorithm] options are MD2, MD4, MD5, SHA1 (default), SHA256, SHA384 and SHA512.

For example to get an MD5 hash of a file use:

CertUtil -hashfile C:\ExampleFile1.txt MD5

More documentation for CertUtil can be seen here.

For those with access to PowerShell v4  and above (Windows 8.1 & Win Server 2012 R2) you can use the built in commandlet called get-filehash like this:

Get-FileHash C:\ExampleFile1.txt  -Algorithm MD5 | Format-List

The algorithms supported are SHA1, SHA256 (default), SHA384, SHA512, MACTripleDES, MD5 & RIPEMD160.

For Powershell versions prior to V4 there are numerous scripts available on the web that will work out the hash for you using various methods.

Linux:

For Linux use the correct  hashalgorithmSUM command in the terminal for the algorithm you are looking for, i.e. for an MD5 hash use md5sum or for SHA512 hash use sha512sum.

For example:

md5sum /home/rich/Documents/ExampleFile1.txt 
sha1sum /home/rich/Documents/ExampleFile1.txt
sha512sum /home/rich/Documents/ExampleFile1.txt

 

 

Building a Python Flask Web UI For Raspberry Pi Sure Elec LCD

Building a Python Flask Web UI For Raspberry Pi Sure Elec LCD

In an earlier post I outlined how I setup a Sure Electronics LCD screen with my Raspberry Pi 3 using a Python driver. Whilst updating the LCD via command line is immensely useful I decided to build a UI to control the LCD send messages too it. By using a browser based UI I could update the LCD screen from anywhere. Essentially this was a chance to play with a Python web framework and write some code!

BlogFlaskUISureElecLCD2 

I’ve passed the UI’s URL round my family’s devices at home and they now send me messages whilst I’m in my study working/playing.

The end result can be found in my GitHub repo.

As my driver was in Python and I’m enjoying coding in Python at the moment I decided to use a Python Web framework to serve the HTML/JavaScript UI and host RESTful services on the server side to accept LCD commands. After some reading I went with Flask which  seemed perfect for my needs. I could have gone with Django but Flask seemed for appropriate for my needs. For a good comparison see this CodeMentor.io post. For a great tutorial on Flask checkout this series by Miguel Grinberg and this great post by Scotch.io.  

Building the server side web framework was easy and logical in Flask and I was able to get something setup in one file which served my needs. However after reading some Flask best practices I spread my solution out into a more appropriate structure. Flask will seem familiar to web developers with experience of ASP.net MVC, Web API, Node/Express etc. You define routes to handle incoming requests. The key aspects my solution are outlined below. I am running the Flask server directly on my Raspberry Pi and using it to serve the pages and host the services for commanding the LCD screen.

To install Flask (on a Pi) first install Python Pip (a popular Python Package Manager) via “apt-get install python-pip” or “apt-get install python3-pip” (for a Python v3 specific Pip) and then install Flask via “pip install flask”.

Flask comes with a small lightweight development server which runs your app in Dev mode and also auto restarts after code changes. I found this fast and robust enough for my needs. 

Lets check out the main parts of the code:

run.py:  This is the entry point for the app. When run it calls run in the app file and here I have optionally passed IP/Port I want the app to run on which enables the app to be exposed to the internal network so I can connect from other machines on the network. 

from app import app 
if __name__ == '__main__':
    app.run(host="192.100.100.100", port=5000)

app/__inti_.py & config.py: This is the app initialisation code and where it points to the config.py file where config settings can be set for the app.

app/views.py: This is the heart of the app. After importing the relevant python components and instantiating the Smartie LCD driver (from previous post), the routes for the app are defined.

@app.route("/")
def show_homepage():
    return "Home Page!"

@app.route("/lcd")
def show_lcdpage():
    name="Jeff"
    return render_template("lcd.html", name=name)

The route for root will just return the text “Home Page” whereas the route for /lcd will call render_template to return a templated HTML page (lcd.html) and passes any relevant data (e.g. “Jeff” which is irrelevant in this example”). Templates will be covered shortly below.

@app.route("/lcd/clear", methods=["POST","GET"])
def display_clear():
    smartie1.clear_screen()
    return "Success"

@app.route("/lcd/displaymessage", methods=["POST"])
def display_message():
    if not request.json:
        abort(400)
    smartie1.clear_screen()
    smartie1.backlight_on()
    smartie1.write_lines_scroll(request.json['Lines'])
    return "Success" 

Any POST or GET on http://SERVERADDRESS:PORT/lcd/clear will result in the smartie drivers clear screen method being called. A POST to “/lcd/displaymessage” will be validated to ensure that the request contains JSON data and then the data will be passed to the driver for display.

/app/templates/lcd.html: This is the main HTML page that enables the user to type the messages to display.

BlogFlaskUI2

The CSS and JavaScript used by this page is found in the static folder and referenced in the usual way………….

<!-- CSS for our app -->         
 <link rel="stylesheet" href="/static/lcd.css"/>

<!-- JS for our app --> 
<script type="text/javascript" src="/static/lcd.js" charset="utf-8"></script>

So we need to ensure that the flask server returns these static files, but we don’t want to have to define  a specific app.route for each one so instead we use this one in our views.py :

@app.route('/<path:filename>')  
def send_file(filename):  
      return send_from_directory('/static', filename)

This basically states that any requests for a file path are sourced from the /static folder directly. So we can just place any files in the static folder that we want to be served directly (the CSS and JavaScript files in our case).

/app/static/lcd.js:  From this JavaScript code we can consume the services hosted by Flask for our application. It’s using the XMLHttpRequest object to make AJAX requests to the Flask server. The SendCommand function takes callback methods which will be called on success or error.

function SendCommand(url, httpVerb, data, successCallback, errorCallback){
                
  var dataToSend;
  if(data!=null){
      var dataToSend = JSON.stringify(data);          
  }
   var request = new XMLHttpRequest();
  request.open(httpVerb, url, true);
  request.setRequestHeader('Content-Type', 'application/json; charset=UTF-8');
   request.onload = function() {
      if(this.status >= 200 && this.status < 400){
          // success here
          var returnedData; 
          if (this.response != null){
              successCallback(returnedData, this.status);
          }                                                                        
      }
      else{
          //error returned from server
          errorCallback("Error response returned from server", this.status);
      }
  }
   request.onerror = function() {
          errorCallback("Error contacting server", this.status);
  }

  if (dataToSend != null){
      request.send(dataToSend);
  }
  else{
      request.send();
  }
}

That’s mostly it. Run the app by running the run.py module (e.g in the Python IDLE or terminal) and direct your browser to http://SERVERADDRESS:5000/lcd.

The code for my Python driver and this web app is available on GitHub here https://github.com/RichHewlett/smartie and https://github.com/RichHewlett/LCD-Smartie-Web.

Using a Sure Electronics LCD with the Raspberry Pi using Python

Using a Sure Electronics LCD with the Raspberry Pi using Python

After receiving a new Raspberry Pi 3 at Christmas I quickly set off looking for uses for this wonderful machine, and quickly found myself hooking it up to an LCD display. This post covers the Python driver I used and modified, as well as some other useful resources.

RPi3

Firstly as an owner of the original Raspberry Pi model B I was pleasantly surprised how capable the Raspberry Pi version 3 is. The performance is much improved and the new built in wireless is a superb addition which makes this version of the Pi more  usable and reduces the friction caused by having too many USB devices hanging off it like a mutant spider. The Pi v3 is powerful enough to be used as a basic workstation and I found myself working on it directly (within Raspbian OS) making the coding workflow more enjoyable as a result than the previous models. Also the as VNC Server is now built into the Raspbian OS it makes setting up the Pi as headless very easy. In fact once you have installed Raspbian and setup VNC then you can run it with just the power supply connected which makes it use little space and you can locate it anywhere.

SureElecLCD1Once my Pi3 was up and running I decided to connect an old LCD matrix screen to it. This LCD is Sure Electronics 20×4 screen which I bought years ago to attach to my HomeServer but never got around to it. The LCD has a USB interface and was used on Windows via the LCD Smartie application. A quick google showed that LCDProc is an equivalent tool for using LCD screens with Linux, and I found some useful tutorials (e.g. here & here). You can install LCDProc via “apt-get install lcdproc”.

I only had limited success with LCDProc but soon realised what I really needed was a programmatic way of controlling the LCD as opposed to a general display tool, so after some more googling I found a few variations of python drivers were being used to control similar LCDs, and this “Smartie” driver by Steve Davis worked best for me, which in turn was inspired by this driver. These drivers use the “pyserial” Python module, easily installable via Python PIP package manager:

“apt-get install python-pip” or “apt-get install python3-pip” (for python v3 pip)
followed by “pip install pyserial==3.0”.

RaspberryPiWhilst the smartie driver initially worked I found that it failed to work after a reboot. After some serious head scratching I realised that it would always work after running LCDProc, meaning the initalisation code for LCDProc setup up the LCD successfully for the Python driver to communicate.  After digging into the Sure Electronics manual and digging into the source code for the SureElec driver for LCDProc (here & here) I was able to find the initisiation command codes for the LCD and add this to the smartie python driver. This enabled the Python driver to be used without relying at all on LCDproc or similar software.

 I have also added some new functionality to the driver which includes flashing, wrapping text and scrolling multiple lines etc. Also included is a demo function that runs through the various functions provided by the driver to show what’s possible and to help testing after making any modications. My updated driver can be found on my GitHub repo (https://github.com/RichHewlett/smartie). With this driver i was able to control my LCD backlight, display text and get a temperature reading. The fact that it was writen in Python was a bonus as I find Python a great langage for coding fun projects.

SureElecLCD2

If you have a Sure Electronics LCD you may be able to take this and use it, or modify it as required, although there are many variations of these devices. Once you have connected your LCD and rebooted the machine just check that the LCD is on the right USB port in Linux (e.g. /dev/ttyUSB0) and that the user has permissions on that port. If you have a Sure 16×4 screen then this will probably work by modifying the SCREEN_WIDTH constant to 16. If you have a different LCD Screen then you may need to modify the initalisation codes and command strings that get sent to the LCD by each method. A good source of refercence is to check out the LCDProc source code for their bundled drivers as they support many screens.

In the next post I’ll cover my next step of building Python Web App using Flask to control the LCD screen from a browser.

Archiving Adobe Lightroom Back Ups with PowerShell

Archiving Adobe Lightroom Back Ups with PowerShell

LightroomLogoIf you are an Adobe Lightroom user it is critical to have regular backups of your photo library catalogue. Luckily this is a simple task thanks to the fact that Lightroom has features built in to regularly taka a backup for you (which in effect means making a copy of your current catalogue file into a new location in the location you have specified in the user preferences of the application.

For information on how to configure the backup settings in Lightroom check out this Adobe link: https://helpx.adobe.com/lightroom/help/back-catalog.html

Lightroom unfortunately does nothing to clear out old backups and prior to Lightroom version 6 these backups were not even compressed, which together can mean the space required to store backups grows very quickly. It was always frustrating as the catalogue files can be compressed by a huge margin (80-90% in cases). Luckily newer versions of Lightroom now compress the backups into zip files which makes their size much less of an issue.

Anyway for those familiar with PowerShell I have a script that I use which after each backup to remove old backups, compress the new backups and move the backup to a new location (to a separate drive to guard against drive failure).

powershellLogo1The script is called LR_Zip_Tuck as it zips the backups and tucks them away. There are two versions of the script. V1 is for Lightroom versions before V6/CC as it includes the additional compression step which is no required since Lightroom V6. This still wo9rks with Lightroom V6 but is slower , and so V2 of the Script is recommended.

The script first waits until the Lightroom application is no longer running before proceeding. This means that you can run this script on exit of Lightroom as it is still backing up (if you have it set to backup on exit) and it will wait until Lightroom has finished (I run it from a desktop shortcut when I still in Lightroom or it is backing up on exit).

## check if Lightroom is running, and if so just wait for it to close
$target = "lightroom"

$process = Get-Process | Where-Object {$_.ProcessName -eq $target}

if($process)
{
	Write-Output "Waiting for Lightroom to exit..."
	$process.WaitForExit()
	start-sleep -s 2
}

It then loops each folder in the backup location looking for catalogue backups that Lightroom has created since the last time the script was run. It then copies it to the off drive backup location and then deletes local the file.

## loop each subfolder in backup location and process
foreach ($path in (Get-ChildItem -Path $LocalBkUpFolder -Directory))
{
	## find zip file in this folder and rename
	$path | Get-ChildItem | where {$_.extension -eq ".zip"} | Select-Object -first 1 | % { $_.FullName} | Rename-Item -NewName {$path.Name + ".zip"}

	## move file to parent folder (as dont need subfolders now)
	$SourceFilePath = $path.FullName + "\" + $path.Name + ".zip"
	Move-Item $SourceFilePath -Destination $LocalBkUpFolder

	## copy zip to remote share location
	Write-Output "Tucking backup away on remote share"
	Copy-Item $NewFileName -Destination $RemoteBkUpFolder

	## delete folder
	Remove-Item -Recurse -Force $path.FullName
}

It then does some house keeping ensuring that only the configured number of old backups exist in the local and remote locations (ensuring that the oldest are deleted first). This prevents the backups building up over time.

## cleanup zip files (local)
Remove-MostFiles $LocalBkUpFolder *.zip 8

## cleanup zip files (remote)
Remove-MostFiles $RemoteBkUpFolder *.zip 20

That’s about it. The scripts are available on my GitHub repo here (as LR_ZipTuck_V1.ps1 and LR_ZipTuck_V2.ps1).

Disable Start Menu Web Search in Windows 10

Disable Start Menu Web Search in Windows 10

If like me you like the Windows 10 “start” menu to only provide applications and Windows settings in the search results and not web search results you need to configure it using these steps.

Using the Start Menu find “Cortana & Search Settings” , then click the settings icon (the cog),  turn Cortana off, and then turn off “Searh Online and Include Web Results”.