1
00:00:00,140 --> 00:00:02,960
So let's go into the PowerShell console,

2
00:00:02,960 --> 00:00:08,240
and we'll look at how we digitally sign a custom PowerShell script.

3
00:00:08,240 --> 00:00:08,600
Okay,

4
00:00:08,600 --> 00:00:12,990
so let's talk about how we sign a PowerShell script so that we

5
00:00:12,990 --> 00:00:16,320
can then pass it on and use it with other individuals and other

6
00:00:16,320 --> 00:00:19,500
devices with a specific certificate.

7
00:00:19,500 --> 00:00:23,040
Now, of course, for this I'm going to utilize a self‑signed certificate.

8
00:00:23,040 --> 00:00:27,540
Now the first thing we have to do is I want to create the path to the script.

9
00:00:27,540 --> 00:00:30,870
Now, I already have a script here,

10
00:00:30,870 --> 00:00:38,610
so I'm going to say \Users\Trainer\ and then a Data folder.

11
00:00:38,610 --> 00:00:42,440
And then, of course, the script itself.

12
00:00:42,440 --> 00:00:44,140
Let's just modify that.

13
00:00:44,140 --> 00:00:46,440
It should be called Script.ps1.

14
00:00:46,440 --> 00:00:47,060
There we go.

15
00:00:47,060 --> 00:00:53,590
So, to see what this looks like, we can just say Get‑Content ‑Path $script,

16
00:00:53,590 --> 00:00:55,010
and then we can see.

17
00:00:55,010 --> 00:00:57,690
So it's simply a function that just writes a message

18
00:00:57,690 --> 00:00:59,430
saying this is a PowerShell script,

19
00:00:59,430 --> 00:01:03,010
and it then calls that function to render the value.

20
00:01:03,010 --> 00:01:07,040
So nothing spectacular, but it's our first PowerShell script.

21
00:01:07,040 --> 00:01:07,290
Now,

22
00:01:07,290 --> 00:01:09,900
the process for doing this is we first need to

23
00:01:09,900 --> 00:01:14,500
define the self‑signed certificate, or if we have a public one,

24
00:01:14,500 --> 00:01:16,440
what that certificate would be.

25
00:01:16,440 --> 00:01:17,270
So to do this,

26
00:01:17,270 --> 00:01:24,040
we can actually use an out‑of‑the‑box function called SelfSignedCertificate.

27
00:01:24,040 --> 00:01:29,040
And then it has some various properties that are available.

28
00:01:29,040 --> 00:01:40,650
So, if I New‑SelfSignedCertificate here, ‑DNSName, I can then give that a name.

29
00:01:40,650 --> 00:01:45,540
I'll call it script.company.com.

30
00:01:45,540 --> 00:01:50,640
I also have the ‑CertStore that I wish to locate as well,

31
00:01:50,640 --> 00:01:54,810
so CertStoreLocation, which is going to be Cert,

32
00:01:54,810 --> 00:02:01,440
and I want this to be \CurrentUser\My.

33
00:02:01,440 --> 00:02:03,560
I then want to choose the type.

34
00:02:03,560 --> 00:02:05,200
Let me just put that there, ‑Type,

35
00:02:05,200 --> 00:02:11,440
like so, and I want it to be a CodeSigningCert.

36
00:02:11,440 --> 00:02:12,410
And then, of course,

37
00:02:12,410 --> 00:02:16,240
I've got the ‑Subject of the certificate that I want to create,

38
00:02:16,240 --> 00:02:22,240
and I'm going to call it PS Code Signing like so.

39
00:02:22,240 --> 00:02:24,040
And then I can press Enter.

40
00:02:24,040 --> 00:02:26,780
Now, interestingly, notice what happens.

41
00:02:26,780 --> 00:02:31,940
It let me kind of auto complete it, but it doesn't have anything else.

42
00:02:31,940 --> 00:02:36,610
So this is a great opportunity to talk about importing modules,

43
00:02:36,610 --> 00:02:39,640
and it says Import‑Module PKI.

44
00:02:39,640 --> 00:02:41,510
Now, of course, it says, well, hold on a minute.

45
00:02:41,510 --> 00:02:43,060
I can't import it.

46
00:02:43,060 --> 00:02:47,390
Okay, so then we can change that and say Install‑Module PKI,

47
00:02:47,390 --> 00:02:51,520
and then it comes back and says the Install‑Module command was found,

48
00:02:51,520 --> 00:02:55,040
but the module couldn't be loaded.

49
00:02:55,040 --> 00:02:56,240
So what does that mean?

50
00:02:56,240 --> 00:02:56,740
Well,

51
00:02:56,740 --> 00:02:59,210
this is where I want to have a quick 2 second chat about

52
00:02:59,210 --> 00:03:02,520
PowerShell 7 and about other PowerShell versions.

53
00:03:02,520 --> 00:03:06,640
And to show you this, I'm going to say Windows PowerShell.

54
00:03:06,640 --> 00:03:10,670
So I have Windows PowerShell, and I also have PowerShell 7.

55
00:03:10,670 --> 00:03:13,970
So I'm going to say New‑SelfSignedCertificate.

56
00:03:13,970 --> 00:03:20,510
And notice this time, I can tap through various options that are available,

57
00:03:20,510 --> 00:03:23,760
so I could say ‑DnsName, and it now resolves.

58
00:03:23,760 --> 00:03:34,420
So I can say script.company.com like so.

59
00:03:34,420 --> 00:03:38,410
I can then say, ‑CertStoreLocation because it now resolves.

60
00:03:38,410 --> 00:03:46,540
I can say Cert, and then we'll say \CurrentUser\My.

61
00:03:46,540 --> 00:03:49,250
I can then say the ‑Type.

62
00:03:49,250 --> 00:03:52,060
I should've put the y there, ‑Type.

63
00:03:52,060 --> 00:03:53,330
And then if I tab,

64
00:03:53,330 --> 00:03:57,160
you can see that I can now loop through the different types of certificates.

65
00:03:57,160 --> 00:04:00,030
And then my last one is ‑Subject,

66
00:04:00,030 --> 00:04:05,260
and I'm going to say PSCode Signing like so, and then

67
00:04:05,260 --> 00:04:07,740
we just get a space between PS Code.

68
00:04:07,740 --> 00:04:10,020
And now, I can enter that.

69
00:04:10,020 --> 00:04:12,790
And, of course, that generates my certificate.

70
00:04:12,790 --> 00:04:13,870
So what happened?

71
00:04:13,870 --> 00:04:19,330
Why did it not work in PowerShell 7 and why did it work in regular PowerShell?

72
00:04:19,330 --> 00:04:24,480
And that's because some of the commands don't work fully in

73
00:04:24,480 --> 00:04:28,740
PowerShell 7 or what would be the .NET Core.

74
00:04:28,740 --> 00:04:31,590
They haven't been kind of transferred over yet.

75
00:04:31,590 --> 00:04:32,490
So, of course,

76
00:04:32,490 --> 00:04:36,220
what you need to do is either bring in the latest versions

77
00:04:36,220 --> 00:04:41,660
of the DLLs or at least the modules that are available to

78
00:04:41,660 --> 00:04:44,090
be utilized with PowerShell 7,

79
00:04:44,090 --> 00:04:47,370
or you'll have to go back and flick to a previous version.

80
00:04:47,370 --> 00:04:48,360
So for now,

81
00:04:48,360 --> 00:04:50,690
I'm actually just going to use this version of

82
00:04:50,690 --> 00:04:53,840
PowerShell to generate that for me.

83
00:04:53,840 --> 00:04:59,120
Okay, so once we have that, I need to get a copy of the certificate,

84
00:04:59,120 --> 00:05:01,630
certificate.

85
00:05:01,630 --> 00:05:08,440
I'm going to say here's my variable, and I'm going to say Get‑ChildItem,

86
00:05:08,440 --> 00:05:12,530
and we can actually open directly into the current

87
00:05:12,530 --> 00:05:15,240
user and into the \My location.

88
00:05:15,240 --> 00:05:19,640
And then I'm going to filter and just say get me the ‑CodeSigningCertificate,

89
00:05:19,640 --> 00:05:24,740
close that off, and then I'm going to use my offset here to say get me the 0 one.

90
00:05:24,740 --> 00:05:27,010
Now we can bring this back and say certificate.

91
00:05:27,010 --> 00:05:28,830
We can then double check to make sure.

92
00:05:28,830 --> 00:05:30,870
So PS Code Signing, I only have one.

93
00:05:30,870 --> 00:05:34,340
Now, of course, if you had more than one, then you couldn't use 0.

94
00:05:34,340 --> 00:05:37,540
You would have to identify which one was which.

95
00:05:37,540 --> 00:05:39,240
So let me just clear this.

96
00:05:39,240 --> 00:05:45,140
We can then go and call the other value, which is Set‑AuthenticodeSignature.

97
00:05:45,140 --> 00:05:48,740
Now, if I try to call $Script,

98
00:05:48,740 --> 00:05:53,960
it doesn't reference it because my script variable was in PowerShell 7.

99
00:05:53,960 --> 00:05:59,240
So I need to go and create this new variable here in the Windows PowerShell,

100
00:05:59,240 --> 00:06:00,580
so I can reference that.

101
00:06:00,580 --> 00:06:06,210
So let me just do that, \Users\Trainer\,

102
00:06:06,210 --> 00:06:10,130
then from here, we're going to say Data,

103
00:06:10,130 --> 00:06:11,910
and then I'm going to say Script.

104
00:06:11,910 --> 00:06:13,320
So there's my path.

105
00:06:13,320 --> 00:06:19,990
So now, we can say Set‑AuthenticodeSignature to the $script path that

106
00:06:19,990 --> 00:06:22,820
we've got and then the certificate that we've got,

107
00:06:22,820 --> 00:06:24,760
which is my variable called certificate,

108
00:06:24,760 --> 00:06:27,540
and I can say set that to it.

109
00:06:27,540 --> 00:06:29,190
Now, that's been added.

110
00:06:29,190 --> 00:06:32,840
You can see it's the right certificate, and now it's the right path.

111
00:06:32,840 --> 00:06:37,040
So now, we can actually check and validate that it's actually right.

112
00:06:37,040 --> 00:06:43,940
So we can say Get‑AuthenticodeSignature $script.

113
00:06:43,940 --> 00:06:47,060
I'm then going to use the Format option to put that

114
00:06:47,060 --> 00:06:49,130
into a table so it makes more sense.

115
00:06:49,130 --> 00:06:53,040
And I'll just autosize that as well and choose Enter.

116
00:06:53,040 --> 00:06:55,770
And then, of course, it says Status, Path.

117
00:06:55,770 --> 00:06:57,910
Now notice, it comes back and says Status, I have an

118
00:06:57,910 --> 00:06:59,950
UnknownError, and that's okay.

119
00:06:59,950 --> 00:07:02,540
We will be able to fix that in a second.

120
00:07:02,540 --> 00:07:04,390
But it obviously comes back and says,

121
00:07:04,390 --> 00:07:08,340
there's an UnknownError. And at any point, I can come back and check.

122
00:07:08,340 --> 00:07:11,740
Now what does that do to the specific file?

123
00:07:11,740 --> 00:07:15,130
Well, let's open up the actual File Explorer here,

124
00:07:15,130 --> 00:07:18,050
and what we'll do is go into that Data directory,

125
00:07:18,050 --> 00:07:20,130
and you can see I have the script.

126
00:07:20,130 --> 00:07:22,840
And if I say Open with Notepad,

127
00:07:22,840 --> 00:07:26,440
you'll notice what it actually does to the script.

128
00:07:26,440 --> 00:07:31,320
It lets the message and the code that was originally there work. And what it

129
00:07:31,320 --> 00:07:37,390
does, it injects the signature for the specific certificate, so it adds it

130
00:07:37,390 --> 00:07:42,350
to the file so that when we need to utilize that, it's written directly in

131
00:07:42,350 --> 00:07:45,460
the signature of the script itself.

132
00:07:45,460 --> 00:07:47,010
So when we sign something,

133
00:07:47,010 --> 00:07:50,610
it's as simple as that, which means that I can then take that file,

134
00:07:50,610 --> 00:07:52,950
put it somewhere else, and as long as somebody

135
00:07:52,950 --> 00:07:56,540
understands and accepts that certificate,

136
00:07:56,540 --> 00:07:59,320
so I would have to issue that to them in the first place,

137
00:07:59,320 --> 00:08:02,220
then they're able to utilize that,

138
00:08:02,220 --> 00:08:07,960
especially if their execution policy has been set to use signed scripts.

139
00:08:07,960 --> 00:08:10,220
Then, of course, once they trust that certificate,

140
00:08:10,220 --> 00:08:12,840
it will then be able to execute.

141
00:08:12,840 --> 00:08:15,840
So let's go back to the UnknownError.

142
00:08:15,840 --> 00:08:18,310
So, what's the issue here?

143
00:08:18,310 --> 00:08:18,610
Well,

144
00:08:18,610 --> 00:08:22,100
this one is generally caused just because the certificate itself

145
00:08:22,100 --> 00:08:29,080
isn't supported or understood by the trusted store.

146
00:08:29,080 --> 00:08:33,240
So I'm going to launch MMC so we can just kind of see. I'm going to say File,

147
00:08:33,240 --> 00:08:37,050
Add/Remove Snap‑in, and we'll just go to Certificates here.

148
00:08:37,050 --> 00:08:37,960
Just choose Add.

149
00:08:37,960 --> 00:08:41,140
I'm going to say my current user, choose OK.

150
00:08:41,140 --> 00:08:43,900
Expand this down, go into Personal. And sure enough,

151
00:08:43,900 --> 00:08:47,110
you can see my PS coding, which has been added.

152
00:08:47,110 --> 00:08:49,000
I can just simply copy that here,

153
00:08:49,000 --> 00:08:52,250
and what you'll find is it doesn't exist as a trusted root.

154
00:08:52,250 --> 00:08:53,430
So if I scroll through,

155
00:08:53,430 --> 00:08:58,520
I don't see the PS one, so I can come in here and just say Paste, prompt Yes,

156
00:08:58,520 --> 00:09:04,070
and that will add the PS coding certificate as a root certificate option that's

157
00:09:04,070 --> 00:09:07,640
available. Now, I'm going to close that and get rid of it.

158
00:09:07,640 --> 00:09:10,570
What I can then do is go back, and you'll say it's

159
00:09:10,570 --> 00:09:12,300
been updated to say Valid now.

160
00:09:12,300 --> 00:09:14,900
And it's purely because it doesn't support that certificate or

161
00:09:14,900 --> 00:09:17,140
at least know about it in the root store.

162
00:09:17,140 --> 00:09:18,490
So it's as simple as that.

163
00:09:18,490 --> 00:09:22,760
We can secure a PowerShell script by generating a certificate,

164
00:09:22,760 --> 00:09:26,260
making sure it's trusted, and then if we need to issue to other people,

165
00:09:26,260 --> 00:09:30,000
we can pass that information on to them, and then they can trust it, too.

