1
00:00:00,940 --> 00:00:03,130
All of this capability to discover and

2
00:00:03,130 --> 00:00:05,390
install modules from the online PowerShell

3
00:00:05,390 --> 00:00:08,750
Gallery is absolutely fantastic, but what

4
00:00:08,750 --> 00:00:10,320
if you have a scenario where there's a

5
00:00:10,320 --> 00:00:12,350
machine that doesn't have connectivity to

6
00:00:12,350 --> 00:00:14,870
the PowerShell Gallery or no internet

7
00:00:14,870 --> 00:00:16,620
connectivity at all, and you want to

8
00:00:16,620 --> 00:00:18,600
install a PowerShell module on that

9
00:00:18,600 --> 00:00:21,200
machine? This can also happen in dark

10
00:00:21,200 --> 00:00:23,960
sites or offline environments such as

11
00:00:23,960 --> 00:00:27,140
ships, oil rigs, secure locations, there's

12
00:00:27,140 --> 00:00:29,570
plenty of examples. There's a command

13
00:00:29,570 --> 00:00:31,760
included in the PowerShell Get module

14
00:00:31,760 --> 00:00:34,450
named Save‑Module, and you can use this on

15
00:00:34,450 --> 00:00:36,360
a computer that is connected to a

16
00:00:36,360 --> 00:00:39,210
repository such as the PowerShell Gallery,

17
00:00:39,210 --> 00:00:41,200
to save the module without actually

18
00:00:41,200 --> 00:00:43,480
installing it. For me, this command

19
00:00:43,480 --> 00:00:46,360
actually has two primary use cases. The

20
00:00:46,360 --> 00:00:48,510
first one is that because Save‑Module

21
00:00:48,510 --> 00:00:50,840
doesn't actually install the module, this

22
00:00:50,840 --> 00:00:52,900
gives you the capability to pull down the

23
00:00:52,900 --> 00:00:55,180
code for that module in question. You can

24
00:00:55,180 --> 00:00:57,180
then inspect the code within the module to

25
00:00:57,180 --> 00:00:59,400
see how it's been written to get a feel

26
00:00:59,400 --> 00:01:00,920
for whether you are happy to actually

27
00:01:00,920 --> 00:01:04,010
install this module or not. Publishing to

28
00:01:04,010 --> 00:01:06,260
a repository like the PowerShell Gallery

29
00:01:06,260 --> 00:01:08,230
does have guidelines, and they are

30
00:01:08,230 --> 00:01:10,550
scanning it for malicious code, but it can

31
00:01:10,550 --> 00:01:12,330
never hurt to check it for yourself to

32
00:01:12,330 --> 00:01:14,440
ensure that you are comfortable with it.

33
00:01:14,440 --> 00:01:16,940
The second use case for Save‑Module is to

34
00:01:16,940 --> 00:01:19,200
download a copy of the module in question

35
00:01:19,200 --> 00:01:21,410
without installing it, providing you with

36
00:01:21,410 --> 00:01:23,540
the package that you can then transfer to

37
00:01:23,540 --> 00:01:26,450
that offline machine using, well,

38
00:01:26,450 --> 00:01:28,780
basically any method you can to move

39
00:01:28,780 --> 00:01:31,180
files. It might be across a network share

40
00:01:31,180 --> 00:01:34,060
or on a USB drive. When that package has

41
00:01:34,060 --> 00:01:35,970
been copied to the destination computer,

42
00:01:35,970 --> 00:01:38,160
you can then literally copy and paste the

43
00:01:38,160 --> 00:01:40,920
folder into one of the PS module paths on

44
00:01:40,920 --> 00:01:42,860
that offline machine, and then you can

45
00:01:42,860 --> 00:01:45,130
start using that module. Let's go through

46
00:01:45,130 --> 00:01:48,750
that process now. The help here shows us

47
00:01:48,750 --> 00:01:50,490
that we have the same parameters as other

48
00:01:50,490 --> 00:01:52,210
commands to be specific about the

49
00:01:52,210 --> 00:01:54,360
versioning, but this time we've got two

50
00:01:54,360 --> 00:01:57,120
required parameters, which are ‑name for

51
00:01:57,120 --> 00:01:58,520
the name of the module we want to save,

52
00:01:58,520 --> 00:02:02,070
and ‑path to specify which path we want to

53
00:02:02,070 --> 00:02:05,200
save the module to. On this computer, the

54
00:02:05,200 --> 00:02:07,020
one that we've been using for the duration

55
00:02:07,020 --> 00:02:09,440
of this course so far, I'm going to create

56
00:02:09,440 --> 00:02:11,720
a new directory in the C:\ drive called

57
00:02:11,720 --> 00:02:14,980
offlinepsmodule, and I'll use the

58
00:02:14,980 --> 00:02:16,480
‑ItemType parameter to ensure it gets

59
00:02:16,480 --> 00:02:19,440
created as a directory. I can then use

60
00:02:19,440 --> 00:02:21,690
Save‑Module and specify the name of the

61
00:02:21,690 --> 00:02:23,940
module, which for this demo we'll just use

62
00:02:23,940 --> 00:02:26,850
the PSSlack module again and also provide

63
00:02:26,850 --> 00:02:28,860
the path in which I want to save it to,

64
00:02:28,860 --> 00:02:31,540
which is the folder that I just created.

65
00:02:31,540 --> 00:02:33,380
Let's check the contents of that folder by

66
00:02:33,380 --> 00:02:35,800
using Get‑ChildItem, and you'll note that

67
00:02:35,800 --> 00:02:37,640
there's now a single folder there named

68
00:02:37,640 --> 00:02:40,730
PSSlack. Let's look inside of that folder

69
00:02:40,730 --> 00:02:43,110
and there's a subfolder with the version

70
00:02:43,110 --> 00:02:46,780
of the module 1.0.5, being the latest that

71
00:02:46,780 --> 00:02:49,240
it saved from the PowerShell Gallery.

72
00:02:49,240 --> 00:02:50,840
Let's check out the contents of that

73
00:02:50,840 --> 00:02:53,310
folder, and this is the underlying code

74
00:02:53,310 --> 00:02:55,120
and components that form the PowerShell

75
00:02:55,120 --> 00:02:57,540
module. I'm going to flick across to

76
00:02:57,540 --> 00:02:59,700
another machine that I have here, which

77
00:02:59,700 --> 00:03:01,540
I've got set up with a blue PowerShell

78
00:03:01,540 --> 00:03:03,100
console so you can tell that we've

79
00:03:03,100 --> 00:03:05,960
switched across. This machine is an exact

80
00:03:05,960 --> 00:03:07,440
clone of the machine that we've been

81
00:03:07,440 --> 00:03:10,140
working on throughout this course so far,

82
00:03:10,140 --> 00:03:12,280
with the exception that this one does not

83
00:03:12,280 --> 00:03:14,420
have a network card at all, and it's got

84
00:03:14,420 --> 00:03:17,470
no connectivity to any network, let alone

85
00:03:17,470 --> 00:03:20,040
the internet and the PowerShell Gallery.

86
00:03:20,040 --> 00:03:22,810
Let me do an ipconfig here, and you'll see

87
00:03:22,810 --> 00:03:25,100
that there's no data returned. And if I

88
00:03:25,100 --> 00:03:27,250
try and ping a popular address like

89
00:03:27,250 --> 00:03:31,080
1.1.1.1, it'll fail. Let me try and

90
00:03:31,080 --> 00:03:34,150
perform a Find‑Module for PSSlack, and

91
00:03:34,150 --> 00:03:35,950
you'll see we get this warning at the top,

92
00:03:35,950 --> 00:03:37,660
telling me that it's unable to resolve the

93
00:03:37,660 --> 00:03:40,260
PowerShell Gallery. There's no way I'm

94
00:03:40,260 --> 00:03:41,910
going to be able to install anything from

95
00:03:41,910 --> 00:03:43,900
the PowerShell Gallery if I can't even

96
00:03:43,900 --> 00:03:46,490
resolve the DNS entry. Just so you know

97
00:03:46,490 --> 00:03:48,260
that there's no smoke and mirrors here,

98
00:03:48,260 --> 00:03:50,610
I'll also run Get‑Module PSSlack

99
00:03:50,610 --> 00:03:52,920
‑ListAvailable to show that it is not

100
00:03:52,920 --> 00:03:55,140
found in any of the PS module path

101
00:03:55,140 --> 00:03:58,410
folders. Now all I have done here is

102
00:03:58,410 --> 00:04:01,590
copied that folder, offlinepsmodule, from

103
00:04:01,590 --> 00:04:03,220
the first computer we were on a few

104
00:04:03,220 --> 00:04:05,270
moments ago, and I've copied it to this

105
00:04:05,270 --> 00:04:08,070
computer in the same location. Now you

106
00:04:08,070 --> 00:04:09,240
might be thinking we can use

107
00:04:09,240 --> 00:04:11,830
Install‑Module, but Install‑Module is a

108
00:04:11,830 --> 00:04:14,310
part of PowerShell Get, which interfaces

109
00:04:14,310 --> 00:04:16,230
with repositories, and we don't have

110
00:04:16,230 --> 00:04:18,930
access to any repository. So to get this

111
00:04:18,930 --> 00:04:21,080
module working on this computer, I'm going

112
00:04:21,080 --> 00:04:23,470
to simply use Copy‑Item to copy the

113
00:04:23,470 --> 00:04:26,660
PSSlack folder from C:\offlinepsmodule,

114
00:04:26,660 --> 00:04:30,210
and I'm going to copy it to one of the

115
00:04:30,210 --> 00:04:33,370
default PS module paths. So I'll pick the

116
00:04:33,370 --> 00:04:35,930
one down in my user profile, which is at

117
00:04:35,930 --> 00:04:40,370
C:\Users\Matt\Documents\PowerShell\ and

118
00:04:40,370 --> 00:04:43,410
then Modules. Because we want to ensure

119
00:04:43,410 --> 00:04:45,210
that everything is copied, I'll use the

120
00:04:45,210 --> 00:04:47,390
‑recurse parameter and then let that copy

121
00:04:47,390 --> 00:04:51,010
across. If I run Get‑Module again to see

122
00:04:51,010 --> 00:04:53,740
if it finds the PSSlack module, this time

123
00:04:53,740 --> 00:04:56,270
we get a result back, which is great. From

124
00:04:56,270 --> 00:04:58,130
there, I could import the module into this

125
00:04:58,130 --> 00:05:00,840
session, and I can use Get‑Command to list

126
00:05:00,840 --> 00:05:02,920
the commands inside of this module and

127
00:05:02,920 --> 00:05:05,080
start using it on this computer that has

128
00:05:05,080 --> 00:05:09,000
no network connectivity to the PowerShell Gallery.

