PowerShell Core 6.0 and Raspberry Pi
TL;DR – Start PowerShell as the root user, install the module for All Users and then set up your cron job to run the script in the root user’s crontab.
If, like me, you have a Raspberry Pi that you are already using to do awesome home automation things with and you’re a big fan of PowerShell, you’re probably as excited as I was hearing that it was now possible to install (I say that loosely) and run PowerShell Core on a Raspberry Pi 2 or 3.
That we have a low power IoT type device capable of running PowerShell opens up some amazing opportunities for PowerShell enthusiasts who might not have a lot of exposure to Python. Python has great compatibility with a Raspberry PI, allowing you to control GPIO pins but PowerShell Core 6 doesn’t have that level of capability…yet but I’m sure it will come in time. That said, if you want to schedule PowerShell scripts to run and don’t want to have your computer running all the time, a Raspberry Pi is now an option. You should be aware of its limits – limited memory, disk storage and CPU power being the most obvious.
The purpose of this post is to demonstrate how to use a Raspberry Pi to run a PowerShell script that requires access to parts of the OS it wouldn’t normally have. It will be using a module and running on a schedule using cron
.
First things first, you’ll need to install PowerShell Core 6.0. I’ve decided not to repeat the instructions since they’re as clear and concise as they need to be at that link. Here’s the script we’re going to run which checks if today is the last day of the month, if it is, it imports a module, creates an HTML file from my temperature trend history from my Hive home heating and then copies the file to a system folder:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
function IsFinalDayOfMonth() { $FinalDay = (Get-Date -Day 1 -Month ([int](Get-Date -Format "MM") + 1)).AddDays(-1).Date $Today = (Get-Date).Date if ($Today -eq $FinalDay) { Return $true } Else {Return $false} } If (IsFinalDayOfMonth) { Import-Module -Name PoSHive $HiveUsername = 'user@hive' $HivePassword = 'thepassword' $Hive = [Hive]::new($HiveUsername, $HivePassword) $Hive.Login() $Start = (Get-Date -Day 1).Date $End = Get-Date $FileLocation = $Hive.GetHeatingHistory($Start, $End, 'Main', '/home/pi/temperature-trends/') $Hive.Logout() | Out-Null Move-Item -Path $FileLocation -Destination '/var/www/html/temperature-trends/' } Else {Write-Output "Not quite the end of the month yet..."} |
A few things to note about this script:
- It requires a module called PoSHive.
- It’s meant to run on a schedule.
- It copies a file to a web server hosting area which requires super user (sudo).
It’s number 3 that drives our decisions from here. If we tried to run this script in our own crontab
(Linux task scheduler), we’d get our output file but it would never be copied to /var/www/html/temperature-trends
as we want because that’s a special folder owned by root. We’ll ignore the fact that I could technically make myself the owner of the folder for the purposes of this demonstration. Similarly, if we just added the PowerShell command as a cron job to the root user’s crontab, it wouldn’t have the module we need and would fail.
The solution then is to run PowerShell as the root user and install the module for all users.
- Get PowerShell running as root.
- sudo ~/powershell/pwsh
- Install the module for All Users
- Install-Module -Name PoSHive -Scope AllUsers
- Exit PowerShell
- Exit
Now the module is available in any session that starts PowerShell and we need to create the cron job that will execute our script that we’ve saved to /home/pi/scripts
and it’s called Get-HeatingHistoryWebsitePush.ps1
We need to set the cron job up in the root user’s crontab so that it has permissions when it runs to copy the file to that system folder /var/www/html/temperature-trends
so:
- Open the root user’s crontab
sudo crontab -e
- Enter the details for the cron job using the appropriate settings. Cron scheduling is easy to work out when you use something like Crontab guru. I want my script to run every day, just before midnight. The important bit to take away from this is that you need to specify full path locations to PowerShell itself and the script’s location.
59 23 * * * /home/pi/powershell/pwsh -File /home/pi/scripts/Get-HeatingHistoryWebsitePush.ps1
- If you’re using nano,
Ctrl+X
exits with a prompt to save. I think vim is:wq
That is pretty much all there is to it. Your script should now run on the schedule you’ve set, with the root user’s privileges, properly import the module (since it’s installed for all users) and be allowed to perform other root user level activities within the PowerShell script such as copy a file to a system folder, as we do in our script. Here’s a screenshot of the output from my script, running on a Raspberry Pi, which is the temperature trend of my home heating system in January 2018 produced by my module PoSHive, using data from the Hive API and created using Google Charts.
Have fun with PowerShell on your Raspberry Pi!
-Lewis
Install link is broken
And wouldn’t it be easier to run the script every first day of the month a minute after midnight (it’s possible to write in cron 1 0 1 * *)? The script will not run 30 times a month unnecessarily and it will be faster if you do not have to use the complex function to find out the last day of the month. In addition, data for the last minute of the month will no longer be missing.
And wouldn’t it be easier to run the script every first day of the month a minute after midnight (it’s possible to write in cron 1 0 1 * *)? The script will not run 30 times a month unnecessarily and it will be faster if you do not have to use the complex function to find out the last day of the month. In addition, data for the last minute of the month will no longer be missing.
And the function is really bad – what about December? [int](12 + 1)?
When you add the months, please: (Get-Date -Day 1).AddMonths (1)
Or isn’t this easier?
$today = Get-Date
$lastDay = [DateTime] :: DaysInMonth ($today.Year, $today.Month)
@NightHunter – thanks for the critique. I’m not going to suggest for a minute that every script I produce is a production ready masterpiece without any bugs, but then, neither is anyone else’s code – even as simple as this error might be. That said, the point of this article wasn’t to demonstrate the script, merely how to run them on a Raspberry Pi…since the concept was very new when I wrote this article 2 years ago.