We started the year off great with the U.S. apparently shooting down a Chinese Spy Balloon which after being in the news for a few weeks went completely silent, Donald Trump having more court cases ongoing than Pete Davidson has had girlfriends, the 2023 Writers Guild of America Strike and the Killing of Brianna Ghey.
The United Kingdom Governement deciding that the Scottish Paliament cannot introduce a bill by blocking it with Section 35 for Gender Recognition Reform, the first time it has ever been used because every single tory in United Kingdom is a homophobic cunt.
The Death of TV Legends Matthew Perry, Andrew Braugher and David McCallum.
The absolute cluster-fuck which was 2023 in the UK, as well as the new First Minister of Scotland Humza Yousaf.
TLDR; 2023 was a shit storm.
I’ve done less in 2023 than last year. I’ve spent a lot of time doing DIY around the house and in the Garden and haven’t done much else of anything. I went to a few gigs, played a lot of games and watched some TV and Movies. It’s been a pretty peaceful year to say the least.
I watched 42 different shows this year with a total watch time of 152 hours, which is about 12.7 hours per month with my most watched show being Young Sheldon. My most-watched Week was Week 16 (10 Apr - 16 Apr) with 25 plays and my most-watched Month was October with 44 plays. I watched 335 episodes this year, which is down from 443 in 2023, 530 in 2021 and 922 in 2020. My first watch of the year was Young Sheldon, my last was Home Improvement.
My most played TV Shows in 2023, in order of total plays, were:
Show | Plays | Time Watched |
---|---|---|
Young Sheldon | 58 | 00D 18H 52M |
Home Improvement | 46 | 00D 18H 24M |
Mrs. Brown’s Boys | 32 | 00D 15H 52M |
Ghosts (US) | 24 | 00D 08H 41M |
South Park | 20 | 00D 07H 26M |
After Life | 19 | 00D 08H 50M |
Paw Patrol | 16 | 00D 03H 12M |
NCIS | 14 | 00D 10H 18M |
Firebuds | 14 | 00D 02H 48M |
The Big Bang Theory | 12 | 00D 04H 11M |
My most popular genre was Comedy with 22 shows, most popular network was CBS with 6 shows.
My highest rated Shows of 2023 were The Last of Us, Mrs. Brown’s Boys and South Park.
I watched 68 different movies this year with a total watch time of 136 hours, which is about 11.3 hours per month with my most watched movie being Everybody’s Everything. My most-watched Week was Week 51 (Dec 11 - Dec 17) with 6 plays and my most-watched Month was October and December with 16 plays each. I watched movies 77 times this year, which is up from 57 in 2023, but down from 111 in 2021 and 140 in 2020.
My most played Movies in 2023, in order of total hours, were:
Movie | Plays | Hours |
---|---|---|
Everybody’s Everything | 3 | 00D 05H 48M |
Paw Patrol: The Movie | 3 | 00D 04H 18M |
Jurassic World | 2 | 00D 04H 08M |
Saw V | 2 | 00D 03H 10M |
The Green Mile | 1 | 00D 03H 09M |
Oppenheimer | 1 | 00D 03H 01M |
Braveheart | 1 | 00D 02H 57M |
Scary Movie | 2 | 00D 02H 56M |
The Godfather | 1 | 00D 02H 55M |
Elvis | 1 | 00D 02H 39M |
My most popular genre was Horror with 29 movies, most popular Studio was Universal Pictures with 11 movies.
My highest rated Movies of 2023 were Braveheart, Oppenheimer, Street Trash.
In 2023 I scrobbled 18,405 times with a daily average of 50 plays, down from 27,799 and 76 respectively in 2022. I scrobbled 5,187 unique songs down from 7,893 in 2022. My top five songs for the year were:
Song | Artist | Scrobbles |
---|---|---|
WASTE | Kxllswitch | 141 |
Iris | Lil Bo Weep | 112 |
(pls) set me on fire | Enter Shikari | 99 |
You Make Me Sick! | Ashnikko | 87 |
Take on the World | You Me At Six | 84 |
I scrobbled 3,665 unique albums. My top five albums for the year were:
Album | Artist | Scrobbles |
---|---|---|
crybaby | Lil Peep | 353 |
HELLBOY | Lil Peep | 315 |
Happier Than Ever | Billie Eilish | 243 |
Everybody’s Everything | Lil Peep | 219 |
Come Over When You’re Sober, Pt. 2 | Lil Peep | 217 |
I scrobbled 1,783 unique artists, and for the 7th year in a row Lil Peep was top of the list, no surprise. My top five artists for the year were:
Artist | Scrobbles |
---|---|
Lil Peep | 2,413 |
You Me At Six | 1,009 |
Billie Eilish | 785 |
surrenderdorothy | 407 |
Enter Shikari | 397 |
I played 131 different games this year, with a total play time of 1,042.6 hours, which is about 86.9 hours per month and 2.9 hours per day with my most played game being Call of Duty[1]. My most-played week was Week 33 (Aug 14 - Aug 20) with 41.6 hours and my most-played Month was November with 125.7 hours.
My most played Games in 2023 by month, in order of total hours, were:
Game | Month | Playtime |
---|---|---|
Call of Duty: Modern Warfare II | January | 02D 07H 34M |
Call of Duty: Modern Warfare II | February | 01D 13H 34M |
Hogwarts Legacy | March | 01D 02H 03M |
Call of Duty: Modern Warfare II | April | 00D 17H 22M |
NCIS | May | 00D 17H 40M |
Call of Duty: Modern Warfare II | June | 02D 03H 02M |
Call of Duty: Modern Warfare II | July | 00D 20H 27M |
The Texas Chain Saw Massacre | August | 01D 10H 55M |
Call of Duty[1] | September | 02D 00H 48M |
Call of Duty[1] | October | 02D 23H 26M |
Call of Duty[1] | November | 04D 19H 14M |
Call of Duty[1] | December | 02D 17H 46M |
I completed the following games in 2023, in order of total hours:
Game | Playtime |
---|---|
Saints Row | 25.4 Hours |
Hogwarts Legacy | 43.7 Hours |
The Last of Us Part I | 31.1 Hours |
South Park: The Stick of Truth | 13.5 Hours |
Paw Patrol: World | 13.2 Hours |
Suicide of Rachel Foster | 5.2 Hours |
Paw Patrol: Grand Prix | 1.6 Hours |
My Little Pony: A Maretime Bay Adventure | 1.4 Hours |
Pineapple on Pizza | 9.8 Minutes |
Call of Duty: Modern Warfare III[2] | XXXXXXXXXX |
I’ve created 4 projects this year. The below table is in no particular order.
Project | Language | Type |
---|---|---|
Snap2HTML-NG | C# | WinForms, Console |
Der Toten Alptraum (Cancelled) | C# | Game |
cum.zip | PHP | Website |
AssetCore | C# | Mobile App |
2023 has been very quiet project wise as I’ve been spending a lot more time doing work around the house.
At the time of writing there have about 83 git commits this year, this includes a complete re-write for v3.0.
These are my ‘tops’ of the year, things that I really loved entertainment wise.
The below areas were used as data sources for the information within this post.
This data is from 00:00 01 January 2023 to 23:59 31 December 2023.
[1] Activision turned Call of Duty MWII (2022) into DLC in September for 'Call of Duty HQ', so I can no longer split out the time between MWII and MWIII playtime.
[2] Playtime not included as I cannot split Multiplayer time and Single-Player time.
I don’t fall into the requirement. Although The Lonely Helmet did have pretty good results (> 25k) it’s no where near the $200,000 USD or more in the last 12 months AND have at least 200,000 lifetime game installs required for me to pay per install, however.
This sets a horrible path that Unity is going down. They no longer care about Developers or Gamers, they care about lining their pockets and nothing else.
The last few days there has been many opinions on this and why it’s a terrible idea. Installation tracking is messy, tricky and in a lot of cases inaccurate. Unity won’t even explain how they’re tracking it, they’re claiming propriety software - which is even worse. Why? Because Unity acquired ironSource in 2022, the owners of installCore - an SDK that allows charging for installations and allowed making installations invisible to users and anti-virus.
An unbelievable amount of games have been made in the Unity Engine. Some absolute massive games, such as Cuphead, Beat Saber, Fall Guys, Rust and Pokémon GO. I was working on a new game using it called Der Toten Alptraum, which I’ve now decided to scrap. I can’t support Unity, nor can I knowningly let people install Unity games that I made knowing that ironSource is involved.
There are some really good engines out there that you might want to try instead, such as; Godot, Unreal Engine, GameMaker, CryEngine 3, etc. But the overall conclusion?
Fuck Unity.
]]>This post refers to SSE/OVO but if you somehow have THTC under another provider it should work the same way, you’d just need to find their complaints email address yourself.
You must complain to SSE directly. They have 8 weeks to resolve the issue by either having the meter replaced or booking you an appointment for the meter to be replaced, as far as I’m aware they must change the meter within those 8 weeks else you can request a deadlock letter. Even if you don’t receive a deadlock letter (I didn’t) you can still go to the Ombudsman.
Make sure you do the complaint through email. Do not use the forms on their website because it doesn’t send you a confirmation email so you can’t follow up on it or provide it as proof to the Ombudsman.
They will be absolute helmets (to be polite about it) but just fight through it for the 8 weeks. They’ll try and say you can change to another supplier even with THTC (you can’t. I tried). I sent them something along the lines of the below so feel free to reuse it:
“Hello,
I have been trying to switch from THTC to a single meter (Eco7) since insert date. Unfortunately, I have had no success in doing so and I am unable to change to another supplier as SSE/OVO are the only supplier that supports THTC still.
Include something about how expensive your electricity is vs. quotes received from another supplier; I recommend Octopus
Can you please arrange for my meter to be changed to an Eco7 (I have storage heaters)?”
If you don’t have storage heaters mention a Standard meter instead of Eco7.
I chased them weekly.
DO NOT TALK TO THEM ON THE PHONE. YOU NEED EMAILS AS EVIDENCE.
After you’ve gone through the worst 8 weeks of your living existence, you’ll need to now raise the complaint with the Ombudsman. When you raise the complaint include every single email you sent and received from SSE, including copies of your last few bills and how much you paid.
I would also recommend going onto the SSE website and registering interest for a Smart Meter and including a screenshot when it says you can’t get one. Do not ask SSE for a Smart Meter in your complaint, make sure you are asking for a standard or eco7 meter.
If you have any emails or letters about Tariff changes include those as well. More the better even if it seems irrelevant.
When you search for the provider on the Ombudsman Website, search for ‘SSE’ and select ‘SSE (Energy)’ because they have like 80 different names.
Wait. I think I had to respond to the Ombudsman once potentially twice, you can arrange for them to call you if you’re not comfortable doing Emails, but Emails are better because you have a track record of everything. This part took the longest time between them reviewing the case, awaiting responses from SSE (They won’t respond, don’t worry) etc.
The Ombudsman will eventually come back with a Decision, once the decision has been issued and you accept the decision, SSE then have a month from the date to issue the Remedies (replacing the meter and anything else)
Component | Value |
---|---|
First Complaint to SSE | 09-Dec-2022 |
Ombudsman Case Opened | 02-Feb-2023 |
Ombudsman Decision | 20-Apr-2023 |
Remedies Due By | 07-Jun-2023 |
Meter Change Txt/Email | 23-May-2023 |
Meter Changed | 24-May-2023 |
SSE Complaints Email: complaints@sseenergyservices.com
Ombudsman: https://www.ombudsman-services.org/complain-now
//
Good luck.
]]>After not touching anything for a while, I recently started it again and realized that although I wanted to create something again, I didn’t want to touch that project yet. So I started looking into new things that Microsoft had brought out recently and came across .NET MAUI – a cross-platform framework for building native mobile (and desktop) apps within C# and XAML.
I wanted to start somewhere simple to prevent myself getting burned out immediately because I decided to build the next Snapchat or TikTok like the silly billy I am. I learned during this that no matter how simple the application you are making is, doing cross-platform for Windows, iOS, and Android however perfect the framework – is going to be a pain in the ass. Accordingly, I scrapped the iOS app for my starter project and stuck with Android and Windows only.
The simplest application I could think of at the time was a non-persistent To Do app that let you track things that you need to complete in the future without putting a due data on it – because I hate due dates. It allowed me to add tasks, update them, mark them as complete and used native system specific gestures to allow quick deletion on right swipe.
It doesn’t look pretty nor was I aiming for it at the time. I purely wanted the functionality of the application to work so I could use what I learned in the app I want to make. It uses the MVVM Community Toolkit which if you are using .NET MAUI, .NET Core – whatever – I highly recommend using it because it is without a doubt the easiest to use MVVM package I’ve ever used in my life.
Obviously non-persistent apps have their purpose in the world but anything I make in the future I am going to want to save the data somewhere, whether that is a server somewhere in the cloud or to a local device. I started working on that immediately after which turned out to be a horrendous task as the documentation for SQLite on cross-platform applications still doesn’t exist for .NET MAUI, or at least substantial in-depth documentation. I got it working though. 😊
What next? I’m currently working on an idea that I’ve had for about 5 years that I’ve never been able to execute because the pre-existing cross-platform frameworks haven’t suited my needs, or I’ve not had time to learn them. I previously started learning Swift UI and quickly realized that although functional, the absolute grasp that Apple has on it’s developers (which also causes issues with .NET MAUI sadly) isn’t worth the time or money to learn Swift UI – even if .NET MAUI has it’s own flaws.
I don’t know when my app will come out or if I’ll even ever finish it. It could very easily end up in the archive of started but never finished ideas, but we’ll see.
//
Song Recommendation: BEXEY - Laugh Later Cry Now
Catch. 😊x
]]>Year 3 of making one of these posts, accidentally forced myself into a tradition of writing about my life over the last year without writing anything down during the year, so I just spend the month of November December trying to remember what’s happened. I’ve been pretty quiet on here this year as I’ve been putting a lot of time into GameTrakr that I’m planning to go live with early 2023 hopefully, including having my friend tustin do a complete re-write of the backend to migrate it to Laravel. There will be more about that in the future though. 😊
I called this section Year News Highlights last year, but it doesn’t feel right using that name this year. I might change the name again next year if I decide I hate News of The Year, but it’s what we’ll use for now.
Vladimir Putin signed a decree declaring the Luhansk People’s Republic and Donetsk People’s Republic as independent from Ukraine, even though no one on planet earth agreed, at the end of February, beginning the full-scale invasion of Ukraine on the 26th February starting the largest armed conflict in Europe since World War II.
Winona (Lil Bo Weep) died in March at the age of 22. Love you bo. ♥
The UK, specifically London, caused an ongoing outbreak of monkeypox in May which luckily hasn’t turned out to be COVID-19v2. Former Japanense Prime Minister Shinzo Abe was assassinated in July. Liz Truss was appointed Prime Minister of the UK on September 6th, then stepped down as Prime Minister on October 25th after realizing she was an absolute idiot, she was outlasted by a Lettuce. She also may or may not have killed Queen Elizabeth II, who died 2 days after Truss was appointed Prime Minister.
Elon Musk decided to buy Twitter for $44B for some reason then proceeded to fire nearly everyone, as well as trying to sue a guy that tracked his plane through public information.
I didn’t really do much in 2022. I started a new job in April, moving from Softcat over to SoftwareONE which has been great. I didn’t travel much, however I did travel to Germany in September and spent the whole month which was great - sprechen sie englisch?
I released my first game The Lonely Helmet in June, then proceeded to make it free in December so you should check it out (please).
Trakt was down from December 12 until December 20 as well as some data corruption between November 7 and December 11. Some of this data may be incorrect.
I watched 46 different shows this year with a total watch time of 235 hours, which is about 19.6 hours per month with my most watched show being Young Sheldon. My most-watched Week was Week 41 (Oct 3 - Oct 9) with 30 plays and my most-watched Month was March with 65 plays. I watched 443 episodes this year, which is down from 530 in 2021 and 922 in 2020. My first watch of the year was NCIS, my last was Rick and Morty.
My most played TV Shows in 2022, in order of total plays, were:
Show | Plays | Time Watched |
---|---|---|
Young Sheldon | 69 | 00D 22H 26M |
Archer | 50 | 00D 18H 20M |
When Calls the Heart | 24 | 00D 17H 12M |
Pushing Daises | 22 | 00D 15H 24M |
Reaper | 22 | 00D 14H 39M |
Rick and Morty | 22 | 00D 08H 15M |
NCIS | 20 | 00D 14H 44M |
Jurassic World Camp Cretaceous | 19 | 00D 07H 36M |
Ghosts (US) | 16 | 00D 05H 42M |
Boston Legal | 11 | 00D 07H 42M |
My most popular genre was Comedy with 28 shows, most popular network was Netflix with 12 shows.
My highest rated Shows of 2022 were Kleo, Inside the World’s Toughest Prisons and Young Sheldon.
Trakt was down from December 12 until December 20 as well as some data corruption between November 7 and December 11. Some of this data may be incorrect.
I watched 53 different movies this year with a total watch time of 93 hours, which is about 7.8 hours per month with my most watched movie being 101 Dalmatians (1996). My most-watched Week was Week 29 (Jul 11 - Jul 17) with 12 plays and my most-watched Month was July with 12 plays. I watched movies 57 times this year, which is down from 111 in 2021 and 140 in 2020.
My most played Movies in 2022, in order of total hours, were:
Movie | Plays | Hours |
101 Dalmatians (1996) | 2 | 00D 03H 26M |
Titanic (1997) | 1 | 00D 03H 14M |
Paw Patrol: The Movie (2021) | 2 | 00D 02H 52M |
Meet the Spartans (2008) | 2 | 00D 02H 48M |
Idiocracy (2006) | 2 | 00D 02H 48M |
All Quiet on the Western Front (2022) | 1 | 00D 02H 27M |
Hacksaw Ridge (2016) | 1 | 00D 02H 19M |
Terrifier 2 (2022) | 1 | 00D 02H 18M |
Bohemian Rhapsody (2018) | 1 | 00D 02H 15M |
Moonfall (2022) | 1 | 00D 02H 10M |
My most popular genre was Comedy with 31 movies, most popular Studio was Walt Disney Pictures with 9 movies.
My highest rated Movies of 2022 were Grease (1978), Bohemian Rhapsody (2018), South Park: Post COVID: The Return of COVID (2021).
In 2022 I scrobbled 27,799 times with a daily average of 76 plays, up from 22,856 and 62 respectively in 2021. I scrobbled 7,893 unique songs up from 5,757 in 2021. My top five songs for the year were:
Song | Artist | Scrobbles |
nineteen | Lil Peep | 200 |
Angry | Mars Argo | 149 |
I'm Used to That | Horse Head | 147 |
sTraNgeRs | Bring Me the Horizon | 119 |
all i can see | Guardin | 104 |
I scrobbled 5,577 unique albums. My top five albums for the year were:
Album | Artist | Scrobbles |
crybaby | Lil Peep | 592 |
HELLBOY | Lil Peep | 357 |
Permanence | No Devotion | 295 |
The Two of Us Are Dying | Killstation | 251 |
Solos | Lil Bo Weep | 202 |
I scrobbled 2,492 unique artists, and for the 6th year in a row Lil Peep was top of the list, no surprise. My top five artists for the year were:
Artist | Scrobbles |
Lil Peep | 1,917 |
No Devotion | 552 |
Lil Bo Weep | 546 |
Killstation | 545 |
yxngxr1 | 483 |
I played 134 different gmaes this year, with a total play time of 513.6 hours, which is about 42.8 hours per month and 1.4 hours per day with my most played game being Call of Duty: Modern Warfare II (2022). My most-played week was Week 48 (Nov 28 - Dec 4) with 36.4 hours and my most-played Month was December with 92.6 hours.
My most played Games in 2022 by month, in order of total hours, were:
Game | Month | Playtime |
---|---|---|
Mafia: Definitive Edition | January | 00D 08H 23M |
Cuphead | February | 00D 04H 00M |
Call of Duty: Vanguard | March | 00D 02H 02M |
Family Guy: Back to the Multiverse | April | 00D 06H 31M |
The Walking Dead: Telltale Definitive | May | 00D 08H 13M |
Call of Duty: WWII | June | 00D 07H 17M |
Cyberpunk 2077 | July | 01D 05H 05M |
Grand Theft Auto IV | August | 00D 11H 55M |
Hot Wheels Unleashed | September | 00D 14H 39M |
Back 4 Blood | October | 00D 16H 40M |
Call of Duty: Modern Warfare II | November | 02D 08H 08M |
Call of Duty: Modern Warfare II | December | 02D 21H 26M |
I completed the following games in 2022, in order of total hours:
Game | Playtime |
---|---|
Cyberpunk 2077 | 31.8 Hours |
Hot Wheels Unleashed | 20.2 Hours |
PowerWash Simulator | 19.9 Hours |
Stray | 11.6 Hours |
Mafia: Definitive Edition | 10.6 Hours |
Max Payne 3 [1] | 9.3 Hours |
Crysis: Remastered | 6.2 Hours |
The Walking Dead: Survival Instinct | 5.5 Hours |
Cuphead [1] | 4 Hours |
Fast & Furious: Spy Racers Rise of Sh1ft3r | 2.9 Hours |
I’ve created 6 projects this year. The below table is in no particular order.
Project | Language | Type |
---|---|---|
Snow.NET | C# | .NET Library |
Snow Log Collector (v2) | C# | Winforms |
Snow Document Downloader | C# | Winforms |
Snow Administration Toolkit | C# | WPF |
System Scanner | C# | .NET Core |
GameTrakr Rewrite | Laravel | Laravel |
2022 has been a lot quieter project wise than 2021 because I’ve been putting a lot of time into GameTrakr and some closed source things.
At the time of writing there have about 127 git commits this year, this includes a complete re-write for v2.0. Other than that, nothing super special happened this year. I did finally migrate all my non-jekyll infrastructure from Shared Hosting to a VPS though, only took … years.
I’ve put a lot of work into GameTrakr this year getting it ready for release. Even more work is going into it at the moment as my friend Tustin is helping migrate the project from frameworkless PHP over to Laravel to make it more stable for mass use before I hopefully ship it out of BETA this year.
The following things were added in v3.0 and will be migrated over to v4.0, with a bit more added too…
Hopefully come the 2023 year in review, v4.0 will have shipped and I can give more info then. 😊
These are my ‘tops’ of the year, things that I really loved entertainment wise.
This is just a silly little list of things I hope to do in 2023, will update you next year if they happy. 😉
The below areas were used as data sources for the information within this post.
This data is from 00:00 01 January 2022 to 23:02 31 December 2022.
[1] Playtime does not include time spent playing before GameTrakr was made in January 2021.
* Tweet Mirror for Tweet of The Year.
Something I’ve noticed during this learning period is that the documentation (and Stack Overflow answers) still aren’t quite there yet like it is for .NET Framework, but obviously, Framework is a lot older and has years of questions and answers over the internet. It’s been a bit of a blind-eyed experience trying to work things out, but I’ve managed to get to a point where I’ve got a prototype working of what I’m wanting to create. I’m also going to be nice and explain how I’ve done it, in case someone else needs to in the future.
I’d like to first point out though, that my Linux knowledge is that of a five-year-old. So I apologise in advance if someone looks at this and goes “good lord”, it’s not the prettiest but it is the good base for something.
When you’re working with Cross-platform, you unfortunately can’t just use the same methods of extracting data on both systems. In some cases you can but in most cases you cannot, for instance on Windows you can use WMI or the Registry to get the Operating System ‘friendly name’, such as “Windows 10 Pro”. This won’t work on Linux because Linux has neither WMI or a registry that is readable in this method, so you have to go around it a different way.
1
2
3
4
5
// Get the Operating System in C# for Windows
var name = (from x in new ManagementObjectSearcher("SELECT Caption FROM Win32_OperatingSystem").Get().Cast<ManagementObject>()
select x.GetPropertyValue("Caption")).FirstOrDefault();
Console.WriteLine($"Operating System: {name.ToString()}");
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// Get the Operating System in C# for Linux
internal string RunShell(string cmd)
{
var process = new Process()
{
StartInfo = new ProcessStartInfo
{
FileName = "/bin/sh",
Arguments = $"-c \"{cmd}\"",
RedirectStandardOutput = true,
UseShellExecute = false,
CreateNoWindow = true,
}
};
process.Start();
string result = process.StandardOutput.ReadToEnd();
process.WaitForExit();
return result;
}
Console.WriteLine($"Operating System: {RunShell(". /etc/os-release; echo \"$PRETTY_NAME\"")}");
So it does beg the question of how do you build for each platform under the same project, without needing to worry about Linux somehow running Windows Code and vice versa? Ah well, Microsoft (or something) thought about that and created a handy little class called RuntimeInformation
which includes IsOsPlatform()
which lets you do a boolean check on whether you are running Windows, Linux, Unix etc. So all you need to do is wrap your above code in this to allow the application to know what to run on which operating system, example below.
1
2
3
4
5
6
7
8
9
using System.Runtime.InteropServices;
If(RuntimeInformation.IsOsPlatform(OSPlatform.Windows)) {
// Run your Windows Method here...
}
If(RuntimeInformation.IsOsPlatform(OSPlatform.Linux)) {
// Run your Linux Method here...
}
Pulling Software Information is equally painful, when working with Linux you ideally want to work on an exclusion basis of file extensions, whereas with Windows you want to work on an inclusion basis. Windows is simple, if it’s an .exe
file it’s a runnable application in some form or another, MacOS is simple, if it’s an .app
file it’s a runnable application in some form or another, with some slight variance. Linux on the other hand is nomans land, everything is technically an executable but you don’t care about maybe 90% of files on it from an Application Gathering perspective, so you can’t really refuse the same method across both Operating Systems.
The source code to what I’m working on is currently available on GitHub, although I’d only recommend looking at it to get an idea of how it works rather than using it for anything as it’s similar to that of an old fashioned banks online system, horrific spaghetti.
GitHub: Laim/SystemScanner
//
Song Addiction at he moment: Bring Me The Horizon - sTraNgeRs (Explicit)
Catch. 😊x
]]>I was recently having a conversation with a few people about exporting data from Snow and importing it into a custom CMDB solution that snow doesn’t support via the Snow Integration Manager, which if you don’t know what that is, it basically links up to external systems and pulls the data from things like vSphere and inventories it into Snow, or imports the data into the another system like ServiceNow. The connectors are created by Snow directly and integration outside of that is entirely up to you if you have the time, effort and resource to actually do it.
Snow does have a connector within the Snow Integration Manager called Snow License Manager Data Exporter but it’s pretty limited on what it can pull out and you can add or remove any columns, it’s all or nothing in CSV, XML or JSON only - what if I just want every Microsoft application in XLSX 🤔, for example.
Therefore, I introduce you to Snow.NET, a (kind of) API wrapper that allows you to query any part of the Snow API in a few lines of code and do what you want with the data. It uses RestSharp as it’s client library because why re-invent the wheel, eh?, so authentication and accessing data is super easy. Below is an example of authenticating and getting a list of all Customers the current account has access to.
1
2
3
4
5
6
7
8
9
10
11
12
Authenticate auth = new Authenticate("http://snow.domain.scot/api/", "Administrator", "SnowNET2022!");
if(auth.Client != null) {
PlatformData platform = new PlatformData(auth.Client);
Customers customers = platform.Customers();
for (int i = 0; i < customers.Body.Count; i++)
{
Console.WriteLine($"{customers.Body[i].Body.Name} - {customers.Body[i].Body.Id}");
}
}
Pulling computers with as many or little columns as you want is even easier, for example if you want to export a list of computers on a daily basis automatically via the API that contains the ID, Name, Manufacturer, Operating System, Client Version and Last Scan Date and import it into some custom CMDB solution you can do the below.
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
Authenticate auth = new Authenticate("http://snow.domain.scot/api/", "Administrator", "SnowNET2022!");
int loadedComputers = 0;
private void LoadComputers(int _skipCount = 0) {
ComputerData cd = new ComputerData(auth.Client);
Computers computers = cd.Computers(cid: 1, skipCount: _skipCount);
for (int i = 0; i < computers.Body.Count; i++) {
Computer computer = cd.Computer(cid: 1, computers.Body[i].Body.Id);
dataGridComputers.Rows.Add(
computer.Body.Id,
computer.Body.Name,
computer.Body.Manufacturer,
computer.Body.OperatingSystem,
computer.Body.ClientVersion,
computer.Body.LastScanDate
);
loadedComputers++;
}
if(loadedComputers < computers.Body.Count) {
LoadComputers(_skipCount: loadedComputers);
}
}
It also supports filtering, so if you only wanted to pull the above for computers that have Windows 10 Professional installed, you’d simply add in an additional parameter and you’ll only pull back Windows 10 Professional machines and nothing else.
1
2
3
4
private void LoadComputers(int _skipCount = 0) {
ComputerData cd = new ComputerData(auth.Client);
Computers computers = cd.Computers(cid: 1, skipCount: _skipCount, additionalParameters: "&$filter=OperatingSystem eq 'Microsoft Windows 10 Pro'");
}
Like everything, it’s Open Source over on GitHub, there’s also an Examples repo to get you started. If it’s not on there already, it’ll also be available via NuGet soon.
//
Song Addiction at he moment: Mars Argo - Angry
Catch. 😊x
]]>This post was updated 02/08/2023 to correct an error in relation to CID usage on SPE platforms.
Snow License Manager is great. It has an insane amount of Inventory data from desktops, servers and mobile devices to SaaS providers like Zoom. It has a lot of reports built in that have been created by the development team but you’ll probably find something you want isn’t there. This isn’t just a Snow thing, this is common to all products and unlike some other products, you can actually create custom reports in T-SQL and have them within your Web GUI and allow your system users to run them like any other report.
So, what is a custom report? By assumption most people refer to Saved User Reports as Custom Reports and technically they’re not wrong. A Saved User Report is a customized version of a default report in Snow License Manager which usually has extra or less columns and pre-set criteria like Organisation = Department A
which can then be scheduled or viewed without setting your columns and criteria every time you run the report. A Custom Report on the other hand is created in T-SQL within your SnowLicenseManager database and then inserted into the tblReport
and tblReportSecurity
tables. That’s a very simple explanation of what they are but hopefully you get the gist.
Before you can create a custom report there are a few things you’ll need or would benefit having.
I’ll be providing scripts that can be copy and pasted into SSMS but ideally you should never randomly copy and paste scripts from the internet that you’re not entirely sure what they do, especially if you’re doing this directly into a production environment. If you’ve never used T-SQL before, I recommend looking through one of these resources and getting to grips with the basics.
Note that at the time of writing the above external websites are suitable for a basic understanding of T-SQL. I cannot guarantee that in two weeks or two years that the content will still be useful, appropriate or relevant. I would recommend further research if required and finding your own resources.
Before creating your Custom Report, you first need to create a normal script that returns the data that you’re looking to get. For this example I’ll be creating a report that provides all of the uploaded documents per an inventoried device, this report would be useful if you had an internal requirement to upload purchase or warranty documents to all devices in the system.
1
2
3
4
5
6
7
8
9
SELECT
c.ComputerID
,c.HostName
,d.Title AS [Document Title]
,d.FileName
,d.ContentType AS [Document Type]
FROM [SnowLicenseManager].[dbo].[tblDocuments] d
INNER JOIN [SnowLicenseManager].[dbo].[tblComputer] c ON d.ParentID = c.ComputerID
WHERE DocumentType = 3 AND c.CID = 1
In the above example we are doing our initial SELECT
from the tblDocuments
table with the alias d
. We’re then joining it to our tblComputer
table with the alias c
, based on the ParentID
in tblDocuments being the same as the ComputerID
in tblComputer. We’re then finishing the script off with a WHERE
statement ensuring that we’re only returning Computer Documents with DocumentType = 3
and limiting the data to the Customer with CID = 1
.
You can find the CID for each customer in the platform within the SnowLicenseManager.dbo.tblCID
table, if you’re running an enterprise platform with only one customer in it then the CID will always be 1.
If you are creating a custom report on an SPE platform, ensure that you use
CID = {0}
instead of directly referencing a CID number as you may accidentally leak customer data otherwise.
On Lines 2 - 6, these are the columns that we are wanting to appear in our output. It’s currently configured to return the ComputerID
, HostName
, Title
of the document, FileName
of the document, and the ContentType
of the uploaded document. I’ve added the alias to the start of each column name to ensure that if both tables have an identical column name that the correct column is being returned.
Assuming that you have documents assigned to some computers in Snow License Manager, when you run the below in SSMS you should see the below, although your data will be different naming wise.
Here’s the fun part, creating and adding the report to Snow License Manager. Just a few things to point out
I’m going to split this out into four different sections, however I’ll include the finished script at the bottom. As mentioned in the Prerequisites section, I highly recommend doing this on a test environment before pushing anything into PROD as the Script I use for creating Custom Reports does contain DELETE statements and I’m trusting you not to accidentally delete default reports, I do mention below a way of not accidentally doing that though.
For ease of use there are seven variables at the top of the script. Six of them need to be filled out for the report to go into the system correctly and function correctly.
1
2
3
4
5
6
7
8
9
USE [SnowLicenseManager]
DECLARE @ReportName NVARCHAR(MAX) = 'Custom Report for Documents per Inventoried Asset'
DECLARE @ReportID uniqueidentifier = (SELECT NEWID())
DECLARE @ReportDescription NVARCHAR(MAX) = 'Shows all documents for each asset in the system'
DECLARE @ColumnList NVARCHAR(MAX) = 'ComputerID,HostName,Document Title,FileName,Document Type'
DECLARE @ColVis NVARCHAR(MAX) = '-1,1,1,1,1'
DECLARE @KeyFieldName NVARCHAR(MAX) = 'ComputerID'
DECLARE @RowTargetLink NVARCHAR(MAX) = 'Computer.aspx?='
Hopefully the above is pretty self explanatory but just in case. @ReportName
is the name that appears in the Snow License Manager report list and throughout the system, such as All Computers
. I include Custom Report for
at the start of all of my Custom Reports to prevent me accidentally overwriting or deleting a default report from the system. @ReportID
is automatically generated and is a random UUID/GUID, don’t change this.
@ReportDescription
is the description of the report that appears under it’s name when viewing the report or when in the All Reports page. The @ColumnList
is a list of the columns that are in your script created in Creating your Initial Script. @ColVis
is whether or not you want the column to be visible, 1 for true and 0 for false. When a column is set to 0
it does not appear by default but can be selected via the Column Selector. If you want to have the column used for something else but not usable to the End User you can use a -1. The values match up with the columns in Column List, so in this case ComputerID
is not usable or selectable but everything else is visible by default.
@KeyFieldName
and @RowTarget
are useful but depending on the type of reports you’re creating, you might not use all that often. The RowTargetLink refers to the page of the object you’re viewing, so for Computers it’s Computer.aspx?id=
, for Users it’s User.aspx?id=
, etc. The KeyFieldName refers to the actual ID of said object, which in this case is ComputerID. This means that when you click on a row in the report it will take you to that physical object in the system, they’re not actually required and can be left blank, but I thought I’d include it.
If you’re like me you’ll probably find yourself updating Custom Reports every so often. To make this easier, I started to include DELETE statements at the top of my report script when executing so I wouldn’t end up with duplicate reports in the system that return different results, or just don’t appear at all because of identical names.
1
2
3
4
DELETE FROM [tblReportSecurity] WHERE ReportID = (SELECT ReportID FROM [tblReport] WHERE Name = @ReportName)
DELETE FROM [tblReportExportSchedule] WHERE ReportID = (SELECT ReportID FROM [tblReport] WHERE Name = @ReportName)
DELETE FROM [tblSystemUserReports] WHERE BaseReportID = (SELECT ReportID FROM [tblReport] WHERE Name = @ReportName)
DELETE FROM [tblReport] WHERE Name = @ReportName
There are four major tables involved when adding a report to Snow License Manager, tblReportSecurity
, tblReportExportSchedule
, tblReport
. Each serves it’s own purpose but as there is no ‘procedure’ for deleting reports from the system, if you simply add the report in again or delete it from one table you’ll be left with stale data in the database that may or may not become a pain in the future.
The first two delete statements are removing the report information from tblReportSecurity
which determines who can actually view the report (Administrator, Viewer, etc.). The second delete statement is reporting data from tblReportExportSchedule
so that there is no left over schedule data assigned to users. Both of these do this based off of the ReportID which is generated when the original report was created, which we are able to do by searching tblReport
for a report with the same name as the one we’re adding.
The third statement removes the report information from tblSystemUserReports
, this will delete any ‘user saved’ reports which are based on the Custom Report. Once the Custom Report is removed from the system these reports will not work, thus we want to remove the left behind data.
The forth delete statement is deleting the actual report itself and everything assigned to it, so if you find that your new report has a bug in it and need to revert back, make sure you have a backup of the original report.
This section is pretty simple, it’s simple a variable that has the script you created early in it.
1
2
3
4
5
6
7
8
9
10
11
12
DECLARE @sql NVARCHAR(MAX) =
'
SELECT
c.ComputerID
,c.HostName
,d.Title AS [Document Title]
,d.FileName
,d.ContentType AS [Document Type]
FROM [SnowLicenseManager].[dbo].[tblDocuments] d
INNER JOIN [SnowLicenseManager].[dbo].[tblComputer] c ON d.ParentID = c.ComputerID
WHERE DocumentType = 3 AND c.CID = 1
'
If you’re using a Service Provider Edition platform, you’ll want to replace c.CID = 1
with c.CID = {0}
. This means when Customer A views the report they see their data, and when Customer B views the report they see their data - it’s a wildcard I guess?.
Another honorble mention is that if you have a report that contains single quotes, such as WHERE OperatingSystem LIKE '%Windows%'
you want to wrap it in single quotes twice, like ''%Windows%''
- these ARE NOT DOUBLE QUOTES.
Finally, this section adds the report to the actual system and the relevant tables.
1
2
3
4
5
INSERT INTO [tblReport] (ReportID, StockReport, IsCustomReport, ReportType, ViewName, Name, Description, SQLQuery, ColumnList, ColumnVisibility, KeyFieldName, RowTargetLink, UsesCustomFields, CustomFieldCategoryID)
VALUES (@ReportID, 0, 1, 3 , 'QUERYBUILDER', @ReportName, @ReportDescription, @sql, @ColumnList, @ColVis, @KeyFieldName, @RowTargetLink, 0, 0)
INSERT INTO [tblReportSecurity]
SELECT ReportID, 0 FROM [tblReport] WHERE ReportID = @ReportID
In the first INSERT
statement we’re inserting the report into the tblReport
table and making it available to users in the system. The INSERT INTO
should be pretty self explanatory for most of the values as they match up with the previously explained variables, however for the ones that aren’t:
Column | Value | Description |
StockReport | 0 | Tags it as a Stock Report, 1 = true, 0 = false |
IsCustomReport | 1 | Tags it as a Custom Report, 1 = true, 0 = false |
ReportType | 3 | Not relevant - leave as |
ViewName | QUERYBUILDER | Tells snow what view to use for the report - leave as |
UsesCustomFields | 0 | Only relevant with Report Criteria - leave as |
CustomFieldCategoryID | 0 | Only relevant with Report Criteria - leave as |
The second INSERT
statement is inserting the Report ID into the tblReportSecurity
table. @ReportID
is as defined previously, 0
is the ID of the System User Group that can view the report which in this case would be Administrator only.
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
30
31
32
33
USE [SnowLicenseManager]
DECLARE @ReportName NVARCHAR(MAX) = 'Custom Report for Documents per Inventoried Asset'
DECLARE @ReportID uniqueidentifier = (SELECT NEWID())
DECLARE @ReportDescription NVARCHAR(MAX) = 'Shows all documents for each asset in the system'
DECLARE @ColumnList NVARCHAR(MAX) = 'ComputerID,HostName,Document Title,FileName,Document Type'
DECLARE @ColVis NVARCHAR(MAX) = '-1,1,1,1,1'
DECLARE @KeyFieldName NVARCHAR(MAX) = 'ComputerID'
DECLARE @RowTargetLink NVARCHAR(MAX) = 'Computer.aspx?id='
DELETE FROM [tblReportSecurity] WHERE ReportID = (SELECT ReportID FROM [tblReport] WHERE Name = @ReportName)
DELETE FROM [tblReportExportSchedule] WHERE ReportID = (SELECT ReportID FROM [tblReport] WHERE Name = @ReportName)
DELETE FROM [tblSystemUserReports] WHERE BaseReportID = (SELECT ReportID FROM [tblReport] WHERE Name = @ReportName)
DELETE FROM [tblReport] WHERE Name = @ReportName
DECLARE @sql NVARCHAR(MAX) =
'
SELECT
c.ComputerID
,c.HostName
,d.Title AS [Document Title]
,d.FileName
,d.ContentType AS [Document Type]
FROM [SnowLicenseManager].[dbo].[tblDocuments] d
INNER JOIN [SnowLicenseManager].[dbo].[tblComputer] c ON d.ParentID = c.ComputerID
WHERE DocumentType = 3 AND c.CID = 1
'
INSERT INTO [tblReport] (ReportID, StockReport, IsCustomReport, ReportType, ViewName, Name, Description, SQLQuery, ColumnList, ColumnVisibility, KeyFieldName, RowTargetLink, UsesCustomFields, CustomFieldCategoryID)
VALUES (@ReportID, 0, 1, 3 , 'QUERYBUILDER', @ReportName, @ReportDescription, @sql, @ColumnList, @ColVis, @KeyFieldName, @RowTargetLink, 0, 0)
INSERT INTO [tblReportSecurity]
SELECT ReportID, 0 FROM [tblReport] WHERE ReportID = @ReportID
If you paste the above (after reviewing it) into SQL Server Management Studio in yourt Development Environment and execute, then login to Snow License Manager, you should now be able to see and run the report within the portal and see something similar to the below
As mentioned at the start, this is a very simple report. It should give you a general idea of what you’re doing when creating custom reports in Snow License Manager, however if you have any issues feel free to reach out to me via email - otherwise have fun. 😀
//
Song Addiction at he moment: Modern Baseball - I Think You Were in My Profile Picture Once 2012 is calling me
Catch. 😊x
]]>Feel free to use this section as a TL;DR.
/api/v2/
now returns a list of API options, /api/v2/version
for latest releases/api/v2/vulnerability
api_key
?format=
to a header called api_format
There is documentation over at snwapi.com/#documentation and I’ll be posting some examples over on the Examples Repo on GitHub in the next few days. You can request a key for Version 2.0 now.
For people like myself who like to see things visually though, enjoy some screenshots from PostMan below of how you should now authenticate with snwapi v2.0.
Version 1.0 will continue to get updates until July 1st 2022 at which point it will be disabled and users will be required to use Version 2.0. The switch over shouldn’t be too much work as the only real major difference is the required headers, the formatting of the data and naming conventions within the actual data is the same as Version 1.0.
//
Song Addiction at he moment: CORPSE - POLTERGEIST!
Catch. 😊x
]]>Back in July 2020 I released a fancy little tool called Snow Log Collector to try and make it a bit faster and easier to pull log files and data update job information in Snow Software environments. I haven’t touched it since then and there’s been a good few changes to Snow since then, and because of how (badly) I made version 1 none of those changes have been reflected. Basically, any new services that have been added since July 2020, haven’t been picked up by Snow Log Collector. GG, well done Laim. ♥
I’ve spent the last few weeks rewriting the tool from the ground up so I hopefully never have to touch it again unless there is a major overhaul. The scripts that are used for exporting data from the database are written to an .xml
file in the Resources directory meaning that they’re easily customizable and changeable if Snow were to change any table or column names. An example from the DataUpdateJob.xml
file below.
1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="utf-8"?>
<Resource version="9.19.00" defaultSize="11" isCustom="false" fileVersion="1.0.0">
<tblSystemCustomProcedures>
SELECT * FROM [SnowLicenseManager].[dbo].[tblSystemCustomProcedures]
</tblSystemCustomProcedures>
</Resource>
The logging directories are now stored in the Snow Log Collector.exe.config
configuration file, by default these should suit all environments but if you’ve installed Snow somewhere that isn’t in Program Files it does mean it’s easily changeable also and should mean all environments are supported, unless you have a really weird installation.
I also created an installer package and portable version of the tool, so if you don’t like installing things or can run a portable application without going through CAB, it should hopefully suit all needs. It’s entirely open source over on GitHub so feel free to raise a pull request or fork it and make it your own, it’s licensed under MIT so just bare that in mind.
There is also a SaaS tab included now. This allows you to pull all data from the Database for Microsoft 365, Adobe Creative Cloud and any SaaS Generic Connectors that you have in place. These export out the system the same way as the Data Update Job exports so should be easily readable in Microsoft Excel for troubleshooting or for sending to support teams at a Partner, Snow Support or yourself.
You can download it on GitHub.
//
Song Addiction at he moment: yung van, SpaceMan Zack - Sunshine Hotel
Catch. 😊x
]]>