So let's go into the PowerShell console,
and we'll look at how we digitally sign a custom PowerShell script.
Okay,
so let's talk about how we sign a PowerShell script so that we
can then pass it on and use it with other individuals and other
devices with a specific certificate.
Now, of course, for this I'm going to utilize a self‑signed certificate.
Now the first thing we have to do is I want to create the path to the script.
Now, I already have a script here,
so I'm going to say \Users\Trainer\ and then a Data folder.
And then, of course, the script itself.
Let's just modify that.
It should be called Script.ps1.
There we go.
So, to see what this looks like, we can just say Get‑Content ‑Path $script,
and then we can see.
So it's simply a function that just writes a message
saying this is a PowerShell script,
and it then calls that function to render the value.
So nothing spectacular, but it's our first PowerShell script.
Now,
the process for doing this is we first need to
define the self‑signed certificate, or if we have a public one,
what that certificate would be.
So to do this,
we can actually use an out‑of‑the‑box function called SelfSignedCertificate.
And then it has some various properties that are available.
So, if I New‑SelfSignedCertificate here, ‑DNSName, I can then give that a name.
I'll call it script.company.com.
I also have the ‑CertStore that I wish to locate as well,
so CertStoreLocation, which is going to be Cert,
and I want this to be \CurrentUser\My.
I then want to choose the type.
Let me just put that there, ‑Type,
like so, and I want it to be a CodeSigningCert.
And then, of course,
I've got the ‑Subject of the certificate that I want to create,
and I'm going to call it PS Code Signing like so.
And then I can press Enter.
Now, interestingly, notice what happens.
It let me kind of auto complete it, but it doesn't have anything else.
So this is a great opportunity to talk about importing modules,
and it says Import‑Module PKI.
Now, of course, it says, well, hold on a minute.
I can't import it.
Okay, so then we can change that and say Install‑Module PKI,
and then it comes back and says the Install‑Module command was found,
but the module couldn't be loaded.
So what does that mean?
Well,
this is where I want to have a quick 2 second chat about
PowerShell 7 and about other PowerShell versions.
And to show you this, I'm going to say Windows PowerShell.
So I have Windows PowerShell, and I also have PowerShell 7.
So I'm going to say New‑SelfSignedCertificate.
And notice this time, I can tap through various options that are available,
so I could say ‑DnsName, and it now resolves.
So I can say script.company.com like so.
I can then say, ‑CertStoreLocation because it now resolves.
I can say Cert, and then we'll say \CurrentUser\My.
I can then say the ‑Type.
I should've put the y there, ‑Type.
And then if I tab,
you can see that I can now loop through the different types of certificates.
And then my last one is ‑Subject,
and I'm going to say PSCode Signing like so, and then
we just get a space between PS Code.
And now, I can enter that.
And, of course, that generates my certificate.
So what happened?
Why did it not work in PowerShell 7 and why did it work in regular PowerShell?
And that's because some of the commands don't work fully in
PowerShell 7 or what would be the .NET Core.
They haven't been kind of transferred over yet.
So, of course,
what you need to do is either bring in the latest versions
of the DLLs or at least the modules that are available to
be utilized with PowerShell 7,
or you'll have to go back and flick to a previous version.
So for now,
I'm actually just going to use this version of
PowerShell to generate that for me.
Okay, so once we have that, I need to get a copy of the certificate,
certificate.
I'm going to say here's my variable, and I'm going to say Get‑ChildItem,
and we can actually open directly into the current
user and into the \My location.
And then I'm going to filter and just say get me the ‑CodeSigningCertificate,
close that off, and then I'm going to use my offset here to say get me the 0 one.
Now we can bring this back and say certificate.
We can then double check to make sure.
So PS Code Signing, I only have one.
Now, of course, if you had more than one, then you couldn't use 0.
You would have to identify which one was which.
So let me just clear this.
We can then go and call the other value, which is Set‑AuthenticodeSignature.
Now, if I try to call $Script,
it doesn't reference it because my script variable was in PowerShell 7.
So I need to go and create this new variable here in the Windows PowerShell,
so I can reference that.
So let me just do that, \Users\Trainer\,
then from here, we're going to say Data,
and then I'm going to say Script.
So there's my path.
So now, we can say Set‑AuthenticodeSignature to the $script path that
we've got and then the certificate that we've got,
which is my variable called certificate,
and I can say set that to it.
Now, that's been added.
You can see it's the right certificate, and now it's the right path.
So now, we can actually check and validate that it's actually right.
So we can say Get‑AuthenticodeSignature $script.
I'm then going to use the Format option to put that
into a table so it makes more sense.
And I'll just autosize that as well and choose Enter.
And then, of course, it says Status, Path.
Now notice, it comes back and says Status, I have an
UnknownError, and that's okay.
We will be able to fix that in a second.
But it obviously comes back and says,
there's an UnknownError. And at any point, I can come back and check.
Now what does that do to the specific file?
Well, let's open up the actual File Explorer here,
and what we'll do is go into that Data directory,
and you can see I have the script.
And if I say Open with Notepad,
you'll notice what it actually does to the script.
It lets the message and the code that was originally there work. And what it
does, it injects the signature for the specific certificate, so it adds it
to the file so that when we need to utilize that, it's written directly in
the signature of the script itself.
So when we sign something,
it's as simple as that, which means that I can then take that file,
put it somewhere else, and as long as somebody
understands and accepts that certificate,
so I would have to issue that to them in the first place,
then they're able to utilize that,
especially if their execution policy has been set to use signed scripts.
Then, of course, once they trust that certificate,
it will then be able to execute.
So let's go back to the UnknownError.
So, what's the issue here?
Well,
this one is generally caused just because the certificate itself
isn't supported or understood by the trusted store.
So I'm going to launch MMC so we can just kind of see. I'm going to say File,
Add/Remove Snap‑in, and we'll just go to Certificates here.
Just choose Add.
I'm going to say my current user, choose OK.
Expand this down, go into Personal. And sure enough,
you can see my PS coding, which has been added.
I can just simply copy that here,
and what you'll find is it doesn't exist as a trusted root.
So if I scroll through,
I don't see the PS one, so I can come in here and just say Paste, prompt Yes,
and that will add the PS coding certificate as a root certificate option that's
available. Now, I'm going to close that and get rid of it.
What I can then do is go back, and you'll say it's
been updated to say Valid now.
And it's purely because it doesn't support that certificate or
at least know about it in the root store.
So it's as simple as that.
We can secure a PowerShell script by generating a certificate,
making sure it's trusted, and then if we need to issue to other people,
we can pass that information on to them, and then they can trust it, too.