Summer project – PowerShell IoT – pt 3. Needles and Pins.

Disclaimer: Pictures and GIFs are crap here. Deal with it.

So, I finaly got my PI working as expected, and was ready to start testing stuff.
Looking at the examples of the PowerShell IoT Github page , Lighting a single led would be a good first test.

In the box of goodies  I initialy had purchased I had five LEDs, 10 different resistors, a breadboard and the cables needed.

Before coding however, there is some knowledge needed:

  1. What is this GPIO thing?
  2. How do I know where to connect the cables on my PI?
  3. What are resistors, how do they work, and which one out of the millions available should I use?

So lets answer them in order.
GPIO is, to put it simple, the easiest way to interact with any kind of external device.
Connect your thing with one cable to any GPIO pin, and the other end to ground (‘GND’).
a GPIO pin has two modes you can set it to: High or Low (‘On/Off’ and ‘Up/Down’ are other terms i’ve stumbled accross here, but thats not what Wikipedia says..)
You can actually read and write data to GPIO, but for our test thats not necessary.
There is much more to GPIO, but for now that is nothing we need to know.

A great command I discovered pretty early on was ‘pinout’
As I understand it, this comes as a part of the package gpiozero, but it seems to be installed by default on Raspbian.
It prints out basic info of your Pi, and the layout of the pins. Please note that they are not in order!
If you connect something the wrong way, bad things might happen.
To make things even more interesting, the WiringPi numbers (that PowerShell IoT uses) is not the same as the numbers on the PI pinout command..
A complete map of numbers can be found here.

So step one would be two cables to the PI. One GPIO and one Gnd.

Next up we need to connect the cables to the breadboard, and a resistor on one side of it.
I googled it, looked at resistor calculator apps and so on, but I dont want google to simply solve my problem, I want to know how to solve it myself.
Nothing made it click until i stumbled on a sign in the store where i bought my things that had the following on it (roughly translated from swedish):

Resistance (kΩ) = ( Source voltage (V) -Voltage drop (V) ) / Power (mA)
If my Source voltage is 12V and i want to connect a LED of 3,6V 20mA I need a resistance of 0,42kΩ

PS:> (12-3.6)/20

Awesome! Learning instead of just repeating what others told me.

Last lesson to learn was that a LED can be connected backwards. It doesn’t work.
After realizing this everything was connected:
Raspberry Pi GPIO18 pin -> Resistance (330Ω) -> LED -> Raspberry PI GND
(This is exactly the same as the example on GitHub)


Fire up pwsh, Import the example LED module and voila!

Once one led is working, connecting more and writing small blink script was as simple as 1-2-3,
And so, my first adventure in to PowerShell IoT ended like this:
Its pronounced 'hyyif'

Thats it for my first venture. Next up will be an accelerometer.
I dont have no code from this available on GitHub, as it is already available in the PowerShell IoT repo.
Lessons learned:
Invest in a real breadboard and a breakout cable / cobbler. Its well worth the few $ it costs and makes it so much easier to connect stuff.

Summer project – PowerShell IoT – pt 2. Installation and prereqs.

Disclaimer: This is just what I did. some of this might actually be unneccesary, irrelevant or just plain weird. If so, let me know, and Ill try and update next time I install Raspbian.

So, to get everything we need up and running,
This is what i ended up with doing.

Download Raspbian and install in using etcher.
A simple guide for this can be found here.

Insert the sd card in the Pi, and boot it up.

After initial setup, start bash (console),  and do the following

  • Expand disk to use all free space on sd card using the following command
sudo raspi-config --expand-rootfs
  • Configure network to use WLAN. This is espacialy needed if you, like me, have a hidden SSID which is not supported in the gui configuration.
sudo nano /etc/wpa_supplicant/wpa_supplicant.conf 

I found a guide here of how to configure it, and my conf file ended up looking like this


And after doing this, I did a reboot to get connected to my network.

sudo reboot
  • Next step, Install prereqs for PowerShell and PowerShell IoT.
    According to the PowerShell install instructions, we need libunwind8.
    It seems to be some kind of prereq for CoreCLR 2.0 to work properly as it can generate really weird errors if it is missing.
sudo apt-get install libunwind8
  • Install Powershell. Download the latest build from here
    the file you get is a gziped file, that you can install using the following command.
mkdir ~/powershell
tar -xvf ./Downloads/powershell-6.0.2-linux-arm32.tar.gz -C ~/powershell/

This will install powershell in the ~/powershell folder. Feel free to use any folder you like.

  • Install Mono framework. PowerShell-IoT is based on the unosquare raspberryio framework, and that in turn requires a Mono version greater than 4.6 installed. The following commands will upgrade your installed packages, and install mono for you.
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install mono-complete
sudo apt-get install dirmngr
# Verify mono version -gt 4.6
mono --version
  • Finaly we install the unosquare raspberyio framework that PowerShell-IoT is based on using nuget. First off, make sure we have nuget installed.
sudo apt-get install nuget
  • Because the nuget version distributed is old, you will get a really weird error when trying to install stuff. Update Nuget exacutable by running the following command.
sudo nuget update -self
  • And finally, we can install raspberryio.
nuget install Unosquare.Raspberry.IO
  • It’s time to enter the world of powershell. Start Powershell using the following command.
sudo WIRINGPI_CODES=1 ~/powershell/pwsh

What is this WIRINGPI_CODES? you ask. a well structured and good explanation can be found on the PowerShell IoT Github page.

Photo from terminal on Raspbian. I have no idea how to do screenshots on Linux. And I know i didnt use the wiringpi variable. Bad Bjompen.

In the next chapter we will finally start to look in to some code and the first project: lighting a Led. ’til then, stay cool in the heatwave.

Summer project – PowerShell IoT – pt 1. The prequel.

Disclaimer, This is jut a prequel, no code is here. If you are just curious about how to get going, read chapter two directly.

Summertime is upon us, and I am in the middle of vacation.
Swedish weather right now is pure terror with forest fires, no rain and I am spending most of the days in the couch just trying to cool down.
What could be a better way than some code?

This spring Microsoft released Powershell IoT,
And there was some presentations of it at PSConfEU.
Since I have a Raspberry Pi, I thought this would be an interesting project to check out, And so, the summer project was decided.

At first I decided something I wanted to automate at home:
I have a crock pot. A cheap one without temp controll and automatic turn off, but it does its job.
If I could get my Pi connected to a temp sensor, using a needle in the food beeing prepared,
My plan was first to set a temerature alarm, but soon I realized I could connect it to a powerswitch,
and automatically turn the Crock Pot to off when meat reaches $temp.
Project one was designed.

Before I started messing with the project itself, I realized I would have to check out how PowerShell IoT works,
so i bought some cheap sensors (temp/humidity and acceleration), a bunch of leds, resistors, cables and a breakout board for design and connections.
All of this added up to a sum of about 20$. IoT stuff is cheap! =)

Good to go, I hit my first hurdle:
I haven’t installed or ran Linux in years.. how do this work?

I started by installing Raspbian, the default Raspbery Pi Operating system.
You can find raspbian here:
I opted for the desktop version. Why? Easier was my guess.

Secondly, We need to put it on a SD card.
I had a 16Gb card spare, so I used that one, connected to my laptop, and installed the image downloaded using Etcher, found here:
All of this is documented fairly well on the Raspbian page, and was very simple.

Throw the SD card in to the Pi, and off we go. I thought.
I started by installing PowerShell for Raspbian. I picked the correct version from,
Downloaded it, followed the instructions, and… nothing worked any more.
I ran out of diskspace.
Turns out the default raspbian image only has a 4 gb partition, the rest of the sd card is left unused.

Reinstall, and try again in chapter two.

New work, new life, new blogpost.

Well.. as expected, my plan for once a week went south.
But I finally had something to write about, so here goes.

I was recently tasked with writing a integration for SalesForce at work
Just as any normal task I started with google, what had people done before and was it already solved.
Turns out SalesForce, atlhough it has a really well documented API, does not seem to have a powershell module.

Well, read on to see how awesome it turned out.

First of, i needed a test Salesforce account and settings. Fairly easy, and summarized here:

Data Creation and gathering

  • Create developer account, they are free from here: Salesforce developer account
  • Log in to account webpage
    Note the first letters in the url, eu12 in my case. You’ll need those later.
  • Go to Apps -> App Manager and create a new connected app.
    Note the Consumer key and the consumer secret

    • If you missed them, they can be found in Apps -> connected apps -> manage connected apps
  • Click the small button besides your created app and select ‘View’
    Go to Apps -> Connected Apps -> Manage Connected app -> Click to select your newly created app

    • Check settings for oauth policies. If they are wrong, click edit policies and change
  • Click your user avatar -> settings to go to user settings
  • Select ‘Reset my security token’ to receive user token

You should now have the following infomation:

  • Username (
  • Password (password)
  • Consumer Secret (1234567890123456789)
  • Consumer Key (ReallyLongStringFullOfNumbersLike1234567890AndEvenSomeCharacterrsLike_./ThrownInThere)
  • User Token (25RandomCharactersNumbers)
  • Domain for connection (eu01)

Powershell stuff
Connecting to Salesforce using Oauth password
For all of SalesForce API requests, we need to make sure we use TLS 1.2, but this is not default in Powershell.
To set the security protocol to TLS1.2

> [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12

In order to send requests to your SalesForce API you first need to get an access token.
You get this by creating a custom webrequest to the oauth endpoint.
Create a body that looks like this:

$authBody = @{
  grant_type = 'password' # This is a string, not your password, to tell the API we want to use Password authentication.
  client_id = $SalesForceClientID # This is your consumer key previously fetched
  client_secret = $SalesForceClientSecret # This is your consumer secret
  username = $SalesForceUsername # Your username
  password = $PassToken # This is a combination of your password and your token. See below.

$PassToken is your password and your user token combined in to one string without spaces. In my example above:

> $Password = 'password'
> $UserToken = '25RandomCharactersNumbers'

PassToken would then be ‘password25RandomCharactersNumbers’

> $PassToken = "$SalesForceServicePassword$SalesForceToken"

Now, remember those first letters in your url at the top? eu12?
You need those to know which host you should talk to.
To receive your token, send a POST request with your body to the URI

> https://<yourdomain>

In my case, it would be


If you are successfull, you should now get back something like this:

> access_token :
> instance_url :
> id :
> token_type : 'Bearer' # This is not user specific. For Oauth it is always bearer.
> issued_at :
> signature :

It is good to keep this one in a variable, since we need it for all requests in this session.

> $AccessToken = Invoke-RestMethod -Uri '' -Method POST -Body $authBody

Now on to the good stuff.

Sending requests to the SalesForce API
We will start of with something somewhat simple right?
Searching for a user!

SalesForce API is actually quite a mess of different endpoints, and not always easy to navigate.
Fortunately, there is a API browser available online, at
Log in there using your SalesForce account, and select ‘Utilities’ -> ‘Rest Explorer’ to get to the API browser.
Executing the default ‘Get’ will give us a long list of objects to browse,
One of them is ‘Search’.
Clicking that will however only show an error, as we need to input a query of some kind.

Instead of telling you how i know, lets just say i do know that SalesForce uses something called SOQL, Salesforce Object Query Language.
Read all about that here.
Using this link, and also this
We can now start to construct our query. (Yes, in my case that actually included reading loads of more pages. If you are serious about learning SOQL, you should do it to.)
In the end i get something like this:
Userproperties? Well, back to the workbench explorer.
Users, and a lot of other things, in Salesforce are called SObjects.
Entering the SObjects API we find a User, and under that a Describe. Describing users sounds good.
This endpoint contains a fields ‘folder’ showing the available properties,
And using this information we can now nomplete the query:


So using the error from the /search url, we can construct a full query URL


Paste it into the Workbench field and execute. Success!
But we are not here to browse stuff.

Using the $accessToken we have, we can create a complete search request.

> $Method = 'Get' # What was set in the workbench
> $URI = "$($AccessToken.instance_url)/services/data/v41.0/search/?q=FIND+{björn}+IN+name+FIELDS+RETURNING+USER(id,name,username)" # The URL from your token plus the relative path from workbench
> $Headers = @{
  'Authorization' = "Bearer $($AccessToken.access_token)"
  'Accept' = 'application/json'
} # See description below

We must alwas set the header in our requests, as that is how we show that we have the correct token.
Using Oauth username password it is always set as the string ‘Bearer access_token’
Also, we always want json offcourse 😉

So lets try it:

> Invoke-RestMethod -URI $URI -Method $Method -Headers $Headers


And you can now go ahead and start messing about in the SalesForce API.

But I started by saying it turned out awesome.
Just searching using powershell and variables isn’t that nice,
So I wrapped this, and a few more api calls in a module,
Alongside a ‘Invoke-APSalesForceRestMethod’ that automaticatly wraps the token and creates a valid request from it.

Then we managed to convince our employer to open source it.

So without further delay,
you can download / fork / clone our SalesForce module here:
And please help out, send bug reports, add functionality and use it!

And this is the awesome part.
We managed to get our company, Snow Software, to open source our software.
and there is more to come, so stay tuned!


Oh, and I still need to learn how to format things on my blog..


‘Til nex time, whenever that may be!

ping? pong!

Good morning internet!

If you don’t already do this,
you should start reading /r/PowerShell on Reddit.
Many good questions ranging from total beginner to extremely advanced,
and you get to see problems you never knew other people had.

I try to help out there every now and then,
but mostly someone else beats me to it.
No fake internet points for me.

Today, like many times before, someone asked for tips about ping or similar commands,
so I thought I’d do a blog post about different ways to do it, and do some measuring as well!

Let’s start by checking different methods to do this.
In PowerShell there is a well-known command, Test-Connection, that most of use and love.
Simply put, it is equivalent to CMD’s ping, but with added PowerShell glory.

Next up is a somewhat lesser known one, Test-NetConnection.
This command gives you a little bit of different possibilities and results,
like setting target port (for testing stuff like www, ftp..), tracerouting etc.
More info on MS website.

Third (and forth) will be the .net class System.Net.NetworkInformation.Ping

I set up a quick test environment using four external known hosts that reply to ping.
[string[]]$address = '','','',''

And just to make sure all of them are actually available, lets test it first.
$address | foreach {Test-Connection $_ -Count 1}
Well, looks good. Let’s see how much time this takes.
PS> Measure-Command -Expression {$address | foreach {Test-Connection $_ -Count 1}} | Select -ExpandProperty Milliseconds
95 milliseconds.
After doing this 10 times I get between 95 and 105ms.

Does Test-NetConnection beat it? let’s see!
PS> Measure-Command -Expression {$address | foreach {Test-NetConnection $_ }} | Select -ExpandProperty Milliseconds
Whoa! nope, no, njet!
Again, after 10 or so times, average is between 250 and 350ms.
If you are only interested in ping results, avoid this.

So let’s go all in.
We already know using classes are almost always faster,
but it´s not knowledge unless tested.
First up is using good old ping.
PS> Measure-Command -Expression {$address | foreach {[System.Net.NetworkInformation.Ping]::new().Send($_)}} | Select -ExpandProperty Milliseconds
Yupp. It’s faster.
average after 10 tests is 69 to 75ms.

So let’s test one more.
[System.Net.NetworkInformation.Ping]::new() contains a method called SendPingAsync()
Normally, you wait for one ping to return, before sending the next one,
but using async we can send them all at the same time, and just await the results.
This is blazingly fast, but it takes a bit of more code to handle.
As it sends the ping request to a background job,
you have to explicitly tell PowerShell to wait for it to finish.
Let’s try.
PS> Measure-Command -Expression {$a = $address | Foreach {[System.Net.NetworkInformation.Ping]::new().SendPingAsync($_)} ; [Threading.Tasks.Task]::WaitAll($a)} | Select -ExpandProperty Milliseconds
39ms. Again, 10 tries average 39 to 49ms.
After this, you can use your variable ($a in my case) to check the actual status of your servers.

Final result:
1. SendPingAsync() ~40ms
2. Ping() ~75ms
3. Test-Connection ~95ms
4. Test-NetConnection ~347ms

So, is there a point to all this?
Well, I only tested four servers and there was already a massive speed difference.
No go run this test on a park of thousands of servers.

I highly recommend you read Boe Prox blogpost on speedy ping!,
because we all know you can’t have too many tools in your toolbox.

As for me? I think I have to learn how to write code in a blog post.
I wonder if someone has written a blog post about it..

Silence is golden.

I bet you thought this was going to be a different song.

So, I have been of grid for a while now.. time to get going again.
I’ve had my summer vacation,
and decided that now was not the time to be a techie,
so I have not even started my computer once in over a month.
You should try that some time. It feels good.

But there has also been another reason for my silence.
Nervousness. Happiness. Random outbursts of feelings.
Why? Well, I´ll start you off with words from the man himself, @jsnover.
‘I love to hear stories about how people learn PowerShell,
And it makes their career go forward’
(Not exact quote, but he says that a lot).

In three weeks I am joining the ranks at Snow Software,
and it is not without pride I say that my new title is going to be PowerShell Developer.

When I told one of my friends about this, he asked
‘How come you ended up there?
You were supposed to be a musician, right?’
And as I told him the story of my life, Jeffrey’s quote above came to mind.
How did I end up here?
Well, if someone is interested in the full story, ask me.
I love talking about myself.
But I can give you the brief PowerShell history.

(And if you’re already bored, as I would think, go read @joshduffney ‘s post of Pester. Really. It’s good.)

After I finished school I was going to be a rock star.
But as this was the end of the IT boom,
people with computer skills was high in demand,
and I have been an avid computer user since I was six years old,
(You never forget your first C=64).
So I took a job as a hardware tester/builder at a distributor company until my rock star career would take off.

I first installed PowerShell way back.
I don’t even remember when.
But being a CMD scriptkiddie, I didn’t get it.

Until 2009 (2010? might have been..),
when I was tasked with improving a SQL/TFS creation script.
I rewrote it in PowerShell using google copy and paste,
and it was ugly but working.
If I find it, I will redo this post in script format.

Since the word was out that PowerShell was the thing,
I decided to replace my beloved CMD shortcut with a PS one instead,
and forced myself to use that instead,
replacing all my known commands with the PowerShell equivalent.

After a while I started using WMI,
and that was when the light bulb lit up.
I ran head first in to it,
and within a year or so
I had replaced all my CMD scripts with PowerShell instead.

Along came new PowerShell versions,
new tasks, and new discoveries (Remoting and modules in PS2!)

And here I am, almost ten years later.
Pester, DSC, the DevOps movement..
So much fun stuff to learn, use, test!

And with a new job.
As a Powershell Developer.
Until my rock star career takes of that is.

Monday Shorty – Note to self; select-string.

So.. another Monday shorty.
I promised a while ago to make a longer one soon,
and I will.. Big news ahead, but I am not ready to tell you yet.

Anyway, I keep finding that i always have to google or get-help on select-string,
so here´s my note to self:

PS: > gci *.* -Recurse | Select-String -Pattern 'function' | select Path,LineNumber,Line

Path LineNumber Line
---- ---------- ----
PS:\Function\functionTemplate.ps1 3 function $PLASTER_PARAM_FunctionName
PS:\Function\PlasterManifest.xml 5 KTHPlasterFunction
PS:\Function\PlasterManifest.xml 15

Also Todays useful link!

Now hopefully, this is enough to make me remember 🙂


And now for something completely different..

So, I named this blog ‘A blog about things and stuff.’
It´s time for something other than powershell.

Apart from Code I do have a lot of interests,
the biggest one being music.
I listen to it, play it (Guitar, bass and whatever else i can get my hands on) and even run my own home studio.

And today one of my bands released our new album!
Necrophor – Reborn
On this particular album I play the bass, background guitar, Keyboard, and some additional battery.
Was thinking of doing vocals as well, but I had to leave something for the rest of the band 🙂
Jokes aside, a huge thanks to my fellow musicians,
Henrik ‘Hempa’ Eriksson – Vocals
Mikael ‘Strampan’ Strandberg – Drums
Henrik ‘Henrock’ Larsén – Guitars
And of course, the magician behind the mixing desk,
the man, the myth, the legendary
Thomas Skogsberg, Sunlight Studio – recording and mixing.

So, it is with great pride I give you Reborn.

You can find the full album on

And as an added bonus, if you pay for it, I get rich!

Until next time!

Monday shorty – Whats in that string?

Happy Monday!

Yes, I know, it´s Wednesday, but yesterday was the national day of Sweden so this is, in fact, the first workday of the week.
Let´s just say ‘Monday shorty’ was probably not the most thought through topic I could have chosen.

How many times have you seen this?
PS:\> $string
PS:\> $string -eq 'abc'

Or maybe even this?
PS:\> '^C' -eq '^C'

I know I have run in to it a lot of times,
And I have also answered the question on both Facebook and Reddit,
so Here is my solution to the question:
‘What´s in that string?’

Simply convert it to a char array,
and pipe it to a foreach loop converting each char in the array to an int!
PS:\> $string.ToCharArray() | ForEach-Object -Process {[int][char]$_}

Ok, I understand if you don’t speak int fluently,
So Here is Wikipedia’s list of ASCII chars.
And lo and behold, a trailing space!

Oh, the other one? Those are, after all, the same characters, right?
PS:\> '^C'.ToCharArray() | ForEach-Object -Process {[int][char]$_}
PS:\> '^C'.ToCharArray() | ForEach-Object -Process {[int][char]$_}

Simple, but useful, just how I like it.

See you next “Monday”


Monday Shorty – The wonderful world of DateTime.

Regularity is a good thing, and much needed when starting a blog,
so I was hoping to, at least for now, post one thing every week at least.
I have some plans for a longer post, but it is still far from done,
so instead here is a reminder to myself.

-update: Yes, yes, it took me two weeks to do a monday shorty.. sometimes stuff happens 😀

I often get files in random formats that i have to parse and do things with,
Be it reports, statistics, or anything else.
One of the things constantly written in a million ways is dates.
(Dear world, please implement ISO8601)

I was recently given the date format ‘1705221410’, or more specifically ‘yymmddHHMMss’.
so, off course, first try is
PS:> $a = [string]'1705221410'
PS:> Get-Date $a
Get-Date : Cannot bind parameter 'Date'. Cannot convert value "1705221410" to type "System.DateTime". Error: "String was not recognized as a valid DateTime."

.. well that sucks.

Fortunately, there is, off course, a DateTime type. Lets explore it.
PS:\> [system.datetime] | gm -Static

Name MemberType Definition
---- ---------- ----------
Compare Method static int Compare(datetime t1, datetime t2)
DaysInMonth Method static int DaysInMonth(int year, int month)
Equals Method static bool Equals(datetime t1, datetime t2), static bool ...
FromBinary Method static datetime FromBinary(long dateData)
FromFileTime Method static datetime FromFileTime(long fileTime)
FromFileTimeUtc Method static datetime FromFileTimeUtc(long fileTime)
FromOADate Method static datetime FromOADate(double d)
IsLeapYear Method static bool IsLeapYear(int year)
new Method datetime new(long ticks), datetime new(long ticks, System. ...
Parse Method static datetime Parse(string s), static datetime Parse(str ...
ParseExact Method static datetime ParseExact(string s, string format, System ...
ReferenceEquals Method static bool ReferenceEquals(System.Object objA, System.Obj ...
SpecifyKind Method static datetime SpecifyKind(datetime value, System.DateTim ...
TryParse Method static bool TryParse(string s, [ref] datetime result), sta ...
TryParseExact Method static bool TryParseExact(string s, string format, System. ...
MaxValue Property static datetime MaxValue {get;}
MinValue Property static datetime MinValue {get;}
Now Property datetime Now {get;}
Today Property datetime Today {get;}
UtcNow Property datetime UtcNow {get;}

hmm.. looks promising.. A few parse methods to try.
I we look closer at the ParseExact Method we can see the following
(HINT: If you type a method, but remove the parenthesis, you get to see what that specific method requires you to put inside.. the Overload Definitions.)
PS:\> [system.datetime]::ParseExact

static datetime ParseExact(string s, string format, System.IFormatProvider provider)
static datetime ParseExact(string s, string format, System.IFormatProvider provider, System.Globalization.DateTimeStyles style)
static datetime ParseExact(string s, string[] formats, System.IFormatProvider provider, System.Globalization.DateTimeStyles style)

So lets break down what we see here:
There are three ways of using this class, requiring different inputs.
As i only want the conversion to be done, lets look at the first one.
The ParseExact method needs the following arguments in this order:
The string that we would like to parse, in our example ‘1705221410’.
The string to decide what value equals what, again, in our example ‘yyMMddHHmm’

The last one is somewhat more tricky.
System.IFormatProvider is, simply put, a way of saying ‘we need to know how to interpret this’.
Or, as MSDN says it: Provides a mechanism for retrieving an object to control formatting..
Most common I find that what you need here is some kind of cultural info (how to show numbers, dates, separators and such), but the best way to be sure is, as always, search MSDN.

So now we can see that we need one of the following:
A CultureInfo Object
A DateTimeFormatInfo Object
A custom IFormatProvider
‘If provider is null, the CultureInfo object that corresponds to the current culture is used.’
That last one looks good. we do, after all, want to see dates the way we normally do.
So lets try it:
PS:\> [System.DateTime]::ParseExact('1705221410','yyMMddHHmm',$null)

Monday, 22 May, 2017 14:10:00

Success! but you are never satisfied until you know the details, so lets try with different ways of using it as well:
PS:\> [System.DateTime]::ParseExact('1705221410','yyMMddHHmm',[System.Globalization.DateTimeFormatInfo]::CurrentInfo)

Monday, 22 May, 2017 14:10:00

PS:\> [System.DateTime]::ParseExact('1705221410','yyMMddHHmm',[System.Globalization.CultureInfo]::GetCultureInfo('en-US'))

Monday, 22 May, 2017 14:10:00

Both seems to work fine!

So, now that we can do this, lets try it with even stranger strings.
PS:\> [string]$today = 'year 2017 and date 30 and month may and time 9 00'
PS:\> [string]$pattern = '\year yyyy an\d \da\te dd an\d \mon\t\h MMM an\d \ti\me H mm'
PS:\> [DateTime]::ParseExact($today, $pattern, $null)

Tuesday, 30 May, 2017 09:00:00
Awesome. Quite a long Monday shorty, but at least i posted something.
Next time i hope to present a project i am working on.
Nothing fancy, but it is a fun little home project.
Until then, keep coding, and remember:
If you´ve done it twice, it should be automated.

Todays readworthy links:
DateTime.ParseExact Method
DateTimeFormatInfo Class
IFormatProvider Interface