Cleaning up stale Entra ID app registrations

This time I’ll share another short, “vibing” script, which helped me make some room for new app registrations inside my Entra ID. 🙂

Script is rather simple – it collects information about apps that are registered in the tenant, status of their credentials and reports back in a clean, HTML… well, report. In case I’m satisfied with the reported state, I can run it with -Force and it will also delete all the stale app registrations it reported. Easy, efficient, cool. 😎

Report looks like this:

Execution like this:

And, as always, script is there in my GitHub.

Cheers!

Exporting the Managed Favorites from Edge

It’s time for another short “vibe story”.
Although, “vibe coding” part was not that short… oh, well. 😅

So, there is a feature in Microsoft Edge called Managed Favorites – basically, it’s a policy which adds some predefined (let’s say, work-related) favorites into your Edge browser. Which is pretty cool, if you’re using Microsoft Edge. If not, you would maybe also want to have the same favorites added to your other browser(s). With all other favorites, Export/Import would do the trick. But not with these – if you tried exporting them, you could have seen that they are not getting exported with all other favorites. 🤷‍♂️

What can be done then?

You could go to your admin and nicely ask him to provide you these favorites so that you can create/import them by yourself.

Or, you could go to your registry and read the list (it’s actually JSON… but saved as a single string) from HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Edge\ManagedFavorites and create these favorites/bookmarks in your other browser(s):

Or, and this is the option I was vibe coding with my AI companion, you can get the Export-ManagedFavorites.ps1 script and run it to export them (as HTML) for you! 🙂
With managed favorites exported by the script, the toughest part is done, and you can easily import them into your favorite (pun intended) browser(s):

Maybe there are other options (probably there are), but I wanted to have this little PowerShell script for when I need it.

For more info and the script itself, go and check out my GitHub.

Cheers!

P.S. If you think I forgot about the “not that short vibe coding part” – my AI companion didn’t seem to understand my desire to have the final HTML formatted in a certain way… so, it took some time (and a few trips down the rabbit hole) to persuade it have it done the right way. 😅😀

The Need for (Internet) Speed… graph

Another one of more or less useful “projects” that got my attention was enabling Zabbix (while monitoring everything else) to also keep track of my Internet speed. There are sources on the Internet that tell you how (easy it is) to do it, but I was not that lucky – had issues trying to set it up. 🤷‍♂️🙂

 

What I’m using:
– Zabbix 7 (installed on Ubuntu 24.04)
(https://www.zabbix.com/download?os_distribution=ubuntu)
– Speedtest CLI by Ookla
(https://www.speedtest.net/apps/cli)
– some scripts

 

So, Zabbix is installed and working, no big surprise there.

 

Next thing we need to install is Speedtest CLI by Ookla – it’s a simple installation… sort of.
Installing it directly on Zabbix server.

(copy/paste from Ookla’s site – https://www.speedtest.net/apps/cli):

This usually works, but didn’t work for me. 🙂

Something cannot be found… hmmm… maybe if we look for “jammy Release”? 🤔

That (= changing “noble” to “jammy” in the sources list file) fixed it! Yaay! And now we can install speedtest:

If all goes well, we can check the version:

And we can test it couple of times manually, to see if it’s working:

 

Cool! This works! 🙂
Now the tough part – how can I make Zabbix pick it up?!

 

Let’s just say that the “normal and direct way” didn’t work that well (Speedtest tool was probably hitting timeouts on the Zabbix side, and had issues in delivering results to Zabbix – seen the timeout errors).

 

So, another solution was necessary – to work around the timeout errors, I’m actually running the Speedtest tool, store/cache data temporarily, and then Zabbix picks it up when it’s in the mood to do so. As I’m doing measurements every 15 minutes or so, there is plenty of time to pick the numbers up and not run into timeouts.

 

Solution is (relatively) simple:

– script that runs and stores/caches measurements (speedtest-cache.sh)
– systemd service and timer that run the script in 15-minute intervals (zabbix-speedtest.service, zabbix-speedtest.timer)
– script that reads measurements from the Zabbix side (speedtest-read.sh)
– Zabbix items representing measured values (template-speedtest-cache.xml)
– widget/graph that shows data in Zabbix

 

And here it is:
/usr/lib/zabbix/externalscripts/speedtest-cache.sh:

/etc/systemd/system/zabbix-speedtest.service:

/etc/systemd/system/zabbix-speedtest.timer:

/usr/lib/zabbix/externalscripts/speedtest-read.sh:

(manually imported) template-speedtest-cache.xml:

Added all the scripts, timers and services, fixed all the permissions, checked that I have data, and now my Internet Speed Monitor widget looks like this (it’s not much, but hey! 🙂):

Cheers!

P.S. I’m not a Zabbix expert, and I’m not responsible if this “solution” causes you any troubles!

P.P.S. Don’t just copy everything from the Internet! It’s full of bad people (and code)! 😉

Vibe adding the Cloudflare records

One of the summer night “lab sessions” produced this one – I was testing something and was in need to add a couple of new DNS records in my Cloudflare account. Of course, “the normal way” would be to login to the beautiful web-page doing just that, but I wanted to do it differently. Of course – with PowerShell. And of course – with the help of my vibe coding AI companion, ChatGPT. 🙂

So, the idea was born – let’s vibe produce the PowerShell script which will  check and add some (A, CNAME and TXT) records to my Cloudflare-hosted domain, backup the state before and after for… purposes, and report to me what was done in a nice, readable way.

The same thing I could have done via the web-page even faster, but… 🤷‍♂️

The result is script called Add-CfDNSRecord.ps1, which is available on my GitHub, and does just that! 🙂

And for the script to work, you will need the API token, which you can create as following:

  1. Login to your account at https://dash.cloudflare.com/
  2. Go to Profile (top right “user” menu)
  3. Go to API Tokens (left menu)
  4. Create Token
  5. You can use the Edit zone DNS template
  6. Configure settings of your token (constrained as possible in terms of zone, duration, etc.)
  7. Use this token with the script

This can be improved, but it does the job (for me).

Use at your own risk (like with everything you find online)!

Cheers!

Organize pictures and videos… the “vibe” way

The idea for this one came to mind one summer evening, when I was searching for something on my disks, and realized – it’s a mess.

So, started figuring out this mess by first organizing images and videos backed up from my phone(s) into folders. Phone backups are a nice thing… and usually it’s all in a single folder.

OK, there are options… but it is what it is – now I have a folder called like “Mobile-Backup-XXX”, with all files in it… no subfolders. 🤷‍♂️

Of course, when I opened this folder with thousands of files, and started moving them manually to respective subfolders, it soon became clear that I need help (OK, maybe that was obvious from the start 😁).

A whom do you call for help these days? Ghostbusters? 🤔

Well, no – the answer is always “AI”. More precisely, I called (free) ChatGPT.

Long story short, it helped me to write a nice PowerShell script which will take my folder with thousands of files and slightly organize it by moving those files into (sub)folders named by the date they were taken or created.

After some time, we got the script working, some logging was added, and it was ready for testing – tested it on a few folders, and then realized that sometimes it has issues with reading the “right” metadata, so we reengineered that part.

Some time later, after some other tiny things were polished, script was ready and doing it’s work just as I expected it! Nice!

Now, instead of a folder with thousands of images and videos, I have a folder with hundreds of subfolders… 😅

And if you put stuff into folders, you don’t have to look at it, and it doesn’t bother you anymore, right?! 😁

But OK – it’s a first step in organizing stuff! 😊

Could it be improved?! Of course! But… 🤷‍♂️

The script (Organize-PicsAndVids.ps1) is, as always, available on my GitHub.

Cheers!

P.S. This was also somewhat inspired by an episode from “Scott and Mark Learn To…” series of podcasts by Scott Hanselman and Mark Russinovich – make sure you subscribe and watch them regularly! They rock! 😊

Checking certificate expiration with PowerShell

Had an idea to write some (PowerShell) script which will check and maybe notify me of certificates that are nearing expiration for a bunch of (public) sites that… somewhat matter to me. 😊

As it turns out, someone already had this idea and wrote very nice PowerShell script that does just that, available here – thank you!

While testing it, there were sites on which the script worked just fine, and there were sites on which I got errors like this one (Error: “String was not recognized as a valid DateTime.”):

Seems to be connected to my regional settings (I know… who would ever use hr-HR instead of en-US, but… 😊) and date/time formatting:

I’ve tried to fix it in a couple of ways, but the one that finally did it (for me) was explained on Dan Sheehan’s blog (thanks!), implemented on lines 25-26 below.

So, my adapted script looks like this (and works with my hr-HR culture):

It provides the following output (which can be further customized per your needs, of course… and I know – need to insert some line breaks, convert output to HTML, send it via e-mail, … it’s a start! 😊):

Note that I’m returning expiration date “the Croatian way”, by using the following formatting:

Hope it helps someone (and #kudos to original authors)!

Cheers!

Patch Tuesday with PowerShell

It’s actually Wednesday here, but yesterday was another “Patch Tuesday” and Microsoft released its update packages.

So – it’s time to patch! 😊

Not sure how you’re patching your machines, but just wanted to make you aware of the nice PowerShell module called PSWindowsUpdate.

You can read more about it on the official PowerShell Gallery page and also here.

In short – this module takes care of controlling Windows Update from within PowerShell on your local and also remote machines.

And… I know it’s not nice like the Windows Update screen, but it does its job! 😊

To make use of it, you’ll have to take care of some minor prerequisites and install it via PowerShell Gallery.

Once done, you can use it to control Windows Update:

To make it easier for you, here is the installation script which takes care of… everything:

And that’s it – we’re done!

Happy patching!

Cheers!

Yet another “Kubernetes with Raspberry Pi” post

There’s a ton of the tutorials on how to get Kubernetes installed onto your Raspberry Pi, so… let’s write another one. 😊

As mentioned in my last post, I’ve found my forgotten Raspberry Pi, and played around with installing and configuring Raspbian Buster on it.

Today, I wanted to check if it will be possible to install Kubernetes onto such small machine – they are many articles on the “widest of the world’s webs” that say “Yes, it can be done!“, so I’ve decided to give it a try! And I chose to follow one of them (seemed like a nice reference).

As you remember, I’m starting with a cleanly installed (and just slightly customized) Raspbian Buster and building it from there.

And I’ll be using kubeadm for installing my cluster.

So, once I had at least two machines (my Raspberry Pi for the “control plane” and Ubuntu 20.04 LTS Hyper-V virtual machine as the “node” – you can read more about it here), I prepared them like this:

  • install Docker (in my case)
  • change the default cgroups driver for Docker to systemd
  • add cgroups limit support (for my Raspberry Pi 3)
  • configure iptables
  • disable swap (this one was a bit challenging)
  • prepare for Kubernetes installation (source, keys, kubeadm)
  • install Kubernetes “control plane”
  • add flannel
  • add a node to the cluster
  • test with some workload

One thing that bothered me (on Buster) was disabling swap in a way that it also stays disabled after a reboot (I know, it’s the details that eventually get you) – after a while, I’ve stumbled on this forum post and the solution provided by powerpetedid the trick! Thank you, @powerpete! 😊

And finally, details about the each step are here (outputs are commented and somewhat redacted/condensed):

Seems to be working (😊):

Cheers!

P.S. I’ve read about some having issues with flannel and using other network options (didn’t have this one). Also, if you’ll have issues with iptables (v1.8+), maybe you’ll need to switch to legacy version (didn’t have this one either).

Found my forgotten Raspberry Pi

And, naturally, decided to put it to use (although, for exactly what… is currently unclear). 😊

So… how?

As there was already a micro SD card inside my Raspberry Pi, I was all set!

Basically, what I had to do:

  • download the OS image (Raspberry Pi OS Lite)
  • download imaging software (Etcher)
  • extract the OS onto micro SD card
  • enable SSH by adding an empty file called “ssh” (yes, without any extension) to the boot volume
  • boot it up
  • set it up as I like

Extracting the OS image onto micro SD card is a “breeze” with right tools – select OS image, select where do you want to put it and click Flash:

After it’s finished, don’t forget to enable yourself the SSH access (it’s easier that way):

Done.

Let’s put the card back into Raspberry Pi and boot it up.

Few seconds later, you can use (e.g.) Windows Terminal and included SSH client to access your Raspberry Pi (default networking option is DHCP, with default username of pi and password raspberry):

I wanted to “tweak” my installation a bit (with the provided raspi-config script), so I’ve used the following for disabling unnecessary devices, custom network settings, etc.:

# raspi-config script is located in /usr/bin/raspi-config
# settings (some of them) are located in /boot/config.txt

# update the raspi-config script (or you can use 'sudo raspi-config nonint do_update') and vim... is nice to have
sudo apt update
sudo apt install -y raspi-config vim

# set static ip address (configure in '/etc/dhcpcd.conf', can check interfaces with 'ip link' - can be done nicer, but... :))
echo 'interface eth0' | sudo tee -a /etc/dhcpcd.conf
echo 'static ip_address=192.168.12.101/24' | sudo tee -a /etc/dhcpcd.conf
echo 'static routers=192.168.12.1' | sudo tee -a /etc/dhcpcd.conf
echo 'static domain_name_servers=192.168.12.1' | sudo tee -a /etc/dhcpcd.conf

# set password (for user 'pi')
echo "pi:MyExtraSecretPass#123" | sudo chpasswd

# set boot options to my liking
sudo raspi-config nonint do_boot_behaviour B1
sudo raspi-config nonint do_boot_wait 1

# set/disable unnecessary interfaces
sudo raspi-config nonint do_camera 1
sudo raspi-config nonint do_ssh 0
sudo raspi-config nonint do_vnc 1
sudo raspi-config nonint do_spi 1
sudo raspi-config nonint do_i2c 1
sudo raspi-config nonint do_serial 1
sudo raspi-config nonint do_onewire 1
sudo raspi-config nonint do_rgpio 1
sudo raspi-config nonint do_memory_split 16
sudo raspi-config nonint do_expand_rootfs
sudo raspi-config nonint do_wifi_country HR
sudo raspi-config nonint do_change_timezone Europe/Zagreb

# upgrade packages and set hostname
sudo apt upgrade -y
sudo raspi-config nonint do_hostname pimaster
sudo reboot

# ssh back into your pimaster
ssh [email protected]

And after a while, my Raspberry Pi is finally ready:

Cheers!

Scheduling a PowerShell script… with arguments

Let’s say that you have a neat PowerShell script, which you want to run on some kind of a schedule (a script which will collect some data and send you an e-mail, every day in the same hour… ‘til the end of time – maybe this one) – how can you do it? Smile

The answer is simple. Yes, there is a tool included with Windows operating system, which can help you… and it’s called… well – Task Scheduler. Smile

And… if you never used the Task Scheduler in Windows, maybe this is the time to start.

It’s a rather simple tool – you click through a simple wizard, select what you need (a program) and when you need it, and you’ve created a scheduled task.

image

OK… so, I can run a program? What about a PowerShell script?

The real question here is “Who/what will run my PowerShell script?”. And then, the answer is simple – the PowerShell engine.

This means that your “program” is powershell.exe. This also means that in your scheduled task you should enter something like this:

image

(note the full path to powershell.exe – C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe)

Now we have a scheduled task which will start PowerShell in designated time, every single day. Usually, this is not enough, and we need to add some arguments to the command running (like the path to the script we want to execute).

image

(argument field in this case contains -Command “& C:\Scripts\Get-HyperVReport.ps1be really careful about the single/double quotes here!)

Configured like this, our scheduled task will execute the following command:

Two remaining things that we have to check is to have our Get-HyperVReport.ps1 script saved in C:\Scripts and that user, under whom this task is running, has the appropriate permissions to run it. Also, if task should be running unnatended (usually it should), make sure to configure it so.

One other thing that may be useful – with this script, we need to specify some additional parameters (like ClusterName or if it will send us an e-mail when completed). In this case, we can easily add the required parameters to the arguments field, like this:

image

(argument field in this case contains -Command “& C:\Scripts\Get-HyperVReport.ps1‘ -ClusterName MyCluster -SendMail $true -SMTPServer smtp.mail.com -MailFrom [email protected] -MailTo [email protected])

The whole command is then:

Hope this helps!

Cheers!

P.S. One other other thing (yes, it’s written twice… live with it Smile) that can be useful – you can also use PowerShell to create scheduled task which will run this PowerShell script (instead of using “the lame wizard”). Pssst… take a look at the New-ScheduledTask command. Winking smile

P.P.S. You can also make use of Adam’s function, which will make your life easier – https://github.com/adbertram/Random-PowerShell-Work/blob/master/Scheduled%20Tasks/New-ScheduledScript.ps1. Thanks, Adam!