1
00:00:00,940 --> 00:00:03,140
So let's put all of these things together.

2
00:00:03,140 --> 00:00:07,180
Some of these examples are variations on other things

3
00:00:07,180 --> 00:00:08,760
I've shown you earlier in the course,

4
00:00:08,760 --> 00:00:12,320
but let's revisit them and make sure we really understand the

5
00:00:12,320 --> 00:00:15,740
PowerShell language and how to put it all together.

6
00:00:15,740 --> 00:00:17,870
So let's create a variable, $os,

7
00:00:17,870 --> 00:00:20,830
and we'll run Get‑CimInstance and get the operating

8
00:00:20,830 --> 00:00:25,030
system class for the computer, Prospero,

9
00:00:25,030 --> 00:00:30,980
and I'm going to get the TotalVisibleMemorySize and

10
00:00:30,980 --> 00:00:36,520
subtract the FreePhysicalMemorySize times 1 KB because I

11
00:00:36,520 --> 00:00:39,240
want to turn this value into bytes.

12
00:00:39,240 --> 00:00:43,840
So $inuse is the total number of bytes of memory that is in

13
00:00:43,840 --> 00:00:47,200
use on Prospero because I want to get some information about

14
00:00:47,200 --> 00:00:50,040
processes running on that computer.

15
00:00:50,040 --> 00:00:53,190
So I'm going to build a hash table of parameters that

16
00:00:53,190 --> 00:00:55,260
I'm going to splat to Get‑CimInstance,

17
00:00:55,260 --> 00:01:02,540
so let's do the ClassName and my ComputerName.

18
00:01:02,540 --> 00:01:06,500
Now I'm going to filter for only processes where the

19
00:01:06,500 --> 00:01:11,180
WorkingSetSize is greater or equal to 250 MB.

20
00:01:11,180 --> 00:01:14,690
When you create a filter, the filter is using legacy syntax,

21
00:01:14,690 --> 00:01:17,940
but it is expecting that value to be in bytes.

22
00:01:17,940 --> 00:01:21,640
By using a subexpression and the 250MB,

23
00:01:21,640 --> 00:01:25,370
I don't have to try to figure out what's the numeric value of 250 MB.

24
00:01:25,370 --> 00:01:29,560
I can just use 250MB, put it as a subexpression,

25
00:01:29,560 --> 00:01:32,450
and PowerShell will fill it out, and expand it,

26
00:01:32,450 --> 00:01:36,340
and plug it into the filter.

27
00:01:36,340 --> 00:01:40,740
With that hash table, I can now splat that to Get‑CimInstance,

28
00:01:40,740 --> 00:01:44,620
so I'm going to @cim, remember, when we splat,

29
00:01:44,620 --> 00:01:47,510
we don't use the dollar sign, we're using the at

30
00:01:47,510 --> 00:01:50,240
symbol, and then select some properties,

31
00:01:50,240 --> 00:01:52,680
and I'm going to actually create some properties here.

32
00:01:52,680 --> 00:02:00,630
So I'm going to grab ProcessID and Name, I'm going to take the WorkingSetSize.

33
00:02:00,630 --> 00:02:03,080
The WorkingSetSize of each property is in bytes,

34
00:02:03,080 --> 00:02:05,310
so I'm going to divide by 1 MB,

35
00:02:05,310 --> 00:02:09,390
and I'm going around that value using the math class and the

36
00:02:09,390 --> 00:02:13,990
round method to 2 decimal points and use that value for a

37
00:02:13,990 --> 00:02:18,840
property I'm going to be calling WorkingMB.

38
00:02:18,840 --> 00:02:25,700
And we do something similar where I'm going to take the WorkingSetSize/$Inuse,

39
00:02:25,700 --> 00:02:29,090
that I created earlier, and create a PctMemory.

40
00:02:29,090 --> 00:02:30,570
In other words, I want to know,

41
00:02:30,570 --> 00:02:34,150
given the processes, what percentage of memory is being used by

42
00:02:34,150 --> 00:02:38,660
each of these processes? And there's my results.

43
00:02:38,660 --> 00:02:43,340
Now, I limited the output to processes greater than 250 MB.

44
00:02:43,340 --> 00:02:46,710
So the PctMemory is a little more meaningful.

45
00:02:46,710 --> 00:02:47,760
If I wanted to,

46
00:02:47,760 --> 00:02:52,580
I could have sorted that output on WorkingMB because that is a number,

47
00:02:52,580 --> 00:02:54,340
and that would have sorted properly.

48
00:02:54,340 --> 00:02:58,920
If I tried to sort on PctMemory, that will sort it as a string,

49
00:02:58,920 --> 00:03:01,540
which in this particular case, would probably work.

50
00:03:01,540 --> 00:03:02,970
But keep that in mind.

51
00:03:02,970 --> 00:03:07,580
When you're using the ‑f operator, you're getting strings not numeric values,

52
00:03:07,580 --> 00:03:12,940
even though it may look like it on the screen.

53
00:03:12,940 --> 00:03:14,520
Let's do something else.

54
00:03:14,520 --> 00:03:17,790
And we get a list of computers from computers.txt,

55
00:03:17,790 --> 00:03:21,400
which is in my work folder,

56
00:03:21,400 --> 00:03:27,990
and this file too has a listing of computers that are misformatted,

57
00:03:27,990 --> 00:03:31,040
so I've got extra spaces and blank lines.

58
00:03:31,040 --> 00:03:36,460
I'm going to use the AND logical operator to say, only take strings

59
00:03:36,460 --> 00:03:40,730
from computers.txt where the length is greater than 0,

60
00:03:40,730 --> 00:03:48,360
we saw that earlier, and Test‑WSMan using the trimmed version of each string,

61
00:03:48,360 --> 00:03:51,040
if that runs successfully,

62
00:03:51,040 --> 00:03:54,880
then I want to keep that name and write to the pipeline,

63
00:03:54,880 --> 00:03:58,440
and that will be saved $n.

64
00:03:58,440 --> 00:04:01,890
So $n right now looks a little funky still, right?

65
00:04:01,890 --> 00:04:04,420
I still have whitespace, but that's fine.

66
00:04:04,420 --> 00:04:07,840
I'm going to clean that up, like this.

67
00:04:07,840 --> 00:04:10,650
I'm going to run Get‑CimInstance, and in this case,

68
00:04:10,650 --> 00:04:15,030
I want the Win32_OperatingSystem, and I'm going to trim,

69
00:04:15,030 --> 00:04:16,370
for the ComputerName,

70
00:04:16,370 --> 00:04:18,960
I'm going to take $n because ComputerName will take

71
00:04:18,960 --> 00:04:22,280
multiple computers and trim each one.

72
00:04:22,280 --> 00:04:25,150
Get‑CimInstance will connect to every computer that's in the list,

73
00:04:25,150 --> 00:04:28,250
and I'm going to repeat myself here in the list because I have

74
00:04:28,250 --> 00:04:31,640
localhosts a couple times and Prospero a couple times.

75
00:04:31,640 --> 00:04:35,130
The Win32_OperatingSystem class has a property,

76
00:04:35,130 --> 00:04:38,790
CSName, which reflects the ComputerName of the object,

77
00:04:38,790 --> 00:04:44,740
so I'm going to make that a property and basically rename it to ComputerName.

78
00:04:44,740 --> 00:04:50,040
I'm going to create another property called OS.

79
00:04:50,040 --> 00:04:51,150
Now, in this particular case,

80
00:04:51,150 --> 00:04:54,800
I'm going to take the Caption property because that has

81
00:04:54,800 --> 00:04:57,550
the value for the operating system,

82
00:04:57,550 --> 00:05:01,690
and I'm going to replace Microsoft with nothing.

83
00:05:01,690 --> 00:05:02,330
Basically,

84
00:05:02,330 --> 00:05:04,720
I'm going to strip off Microsoft so it doesn't say Microsoft

85
00:05:04,720 --> 00:05:07,740
Windows 10, it'll just say Windows 10, for example,

86
00:05:07,740 --> 00:05:12,140
and I'm going to trim any whitespaces that might be left.

87
00:05:12,140 --> 00:05:16,240
I'll then get the Version property as well.

88
00:05:16,240 --> 00:05:22,010
I am now going to create a Timespan that is going to take the

89
00:05:22,010 --> 00:05:26,640
LastBootUpTime from Win32_OperatingSystem instance that I get,

90
00:05:26,640 --> 00:05:31,840
subtracting the current date, and that will become the uptime.

91
00:05:31,840 --> 00:05:35,060
Let's create a property called Installed,

92
00:05:35,060 --> 00:05:37,930
and I'm going to take the InstallDate,

93
00:05:37,930 --> 00:05:40,780
which would normally be just a standard datetime object,

94
00:05:40,780 --> 00:05:45,840
but I'm going to format this using a custom format string,

95
00:05:45,840 --> 00:05:50,090
which will be MMM and then the year.

96
00:05:50,090 --> 00:05:53,240
So the MMM is actually going to give me the month,

97
00:05:53,240 --> 00:05:54,930
or an abbreviation of the month.

98
00:05:54,930 --> 00:05:58,040
You'll see this here in just a second.

99
00:05:58,040 --> 00:06:03,040
Let's create another property called InstallAge.

100
00:06:03,040 --> 00:06:04,420
Instead of using New‑Timespan,

101
00:06:04,420 --> 00:06:07,960
I'm just subtracting. I'll still end up with a Timespan for the

102
00:06:07,960 --> 00:06:13,840
value. And then let's take the TotalVisibleMemory,

103
00:06:13,840 --> 00:06:16,230
divide by 1 MB as an integer,

104
00:06:16,230 --> 00:06:21,840
and you could also do this as an int32. They're really the same thing.

105
00:06:21,840 --> 00:06:24,610
And just to make things a little bit more interesting,

106
00:06:24,610 --> 00:06:27,970
I'm going to send this to a command called Out‑ConsoleGridView.

107
00:06:27,970 --> 00:06:30,410
I have a note in the demo file on what module you need

108
00:06:30,410 --> 00:06:32,940
to install in order to get that.

109
00:06:32,940 --> 00:06:33,670
And there we go.

110
00:06:33,670 --> 00:06:36,160
So that runs absolutely pretty quickly because I'm just querying,

111
00:06:36,160 --> 00:06:38,140
you know, local computer.

112
00:06:38,140 --> 00:06:44,000
So there is Prospero and the localhost, the OS has Microsoft stripped off,

113
00:06:44,000 --> 00:06:48,040
I have the Version, I have my Uptime, I have the install date,

114
00:06:48,040 --> 00:06:50,970
you can see the month abbreviation and the year,

115
00:06:50,970 --> 00:06:54,940
and my InstallAge, and the total memory as an integer.

116
00:06:54,940 --> 00:06:57,100
That looks like a lot of work,

117
00:06:57,100 --> 00:07:01,640
and it took me longer to explain than it probably did to write this.

118
00:07:01,640 --> 00:07:05,230
Once you understand how this all works, it's really not that difficult.

119
00:07:05,230 --> 00:07:05,690
And again,

120
00:07:05,690 --> 00:07:08,070
this is something that you probably would build into

121
00:07:08,070 --> 00:07:10,030
a PowerShell function or script,

122
00:07:10,030 --> 00:07:14,640
but you need to know that it works from the command line first.

123
00:07:14,640 --> 00:07:17,140
Finally, let's try this example.

124
00:07:17,140 --> 00:07:23,440
I'm going to create a Credential object for myself,

125
00:07:23,440 --> 00:07:29,940
put in the password, hopefully I don't mess it up,

126
00:07:29,940 --> 00:07:32,830
and the computer name I want to connect to is Prospero,

127
00:07:32,830 --> 00:07:36,480
which is a remote computer from this session that I'm in,

128
00:07:36,480 --> 00:07:45,140
and I'm going to run Get‑WinEvent, and I'm going to save the result to $data.

129
00:07:45,140 --> 00:07:49,040
So I'm going to do Get‑WinEvent, I'm going to search the system event log,

130
00:07:49,040 --> 00:07:50,550
on the remote computer,

131
00:07:50,550 --> 00:07:55,540
I'm going to pass my Credential object so I can authenticate to Prospero.

132
00:07:55,540 --> 00:07:59,640
The results of Get‑WinEvent, I'm also going to save to a variable,

133
00:07:59,640 --> 00:08:05,740
$all, because in a moment, I'm going to also use that variable.

134
00:08:05,740 --> 00:08:10,240
The results of Get‑WinEvent, I'm then going to group on the providername.

135
00:08:10,240 --> 00:08:12,050
I don't care about what gets grouped.

136
00:08:12,050 --> 00:08:15,940
I just want the count and the providername.

137
00:08:15,940 --> 00:08:21,940
The providername, in this case, will be the source of the event.

138
00:08:21,940 --> 00:08:27,440
I further only care about providers or sources that have created or

139
00:08:27,440 --> 00:08:34,440
generated more than 250 entries in the system event log.

140
00:08:34,440 --> 00:08:42,240
So this may take a moment to run depending on the size of the event log.

141
00:08:42,240 --> 00:08:44,340
So here's $data.

142
00:08:44,340 --> 00:08:47,610
So these are all of the sources and all of the counts.

143
00:08:47,610 --> 00:08:49,310
Now, it doesn't format very well,

144
00:08:49,310 --> 00:08:53,040
but that's fine because I want more information from

145
00:08:53,040 --> 00:08:55,720
Get‑WinEvent than what it can give me.

146
00:08:55,720 --> 00:08:58,540
So I'm going to tell PowerShell, this is what I want,

147
00:08:58,540 --> 00:09:02,440
give it to me, show me what I need to know.

148
00:09:02,440 --> 00:09:08,940
So if we take $data, and for each element that is in that group,

149
00:09:08,940 --> 00:09:11,160
I'm going to create a custom object.

150
00:09:11,160 --> 00:09:15,280
So the source, and just for the sake of demonstration,

151
00:09:15,280 --> 00:09:20,040
I'm going to take that name and make it all lowercase,

152
00:09:20,040 --> 00:09:26,140
I have the count, and I'm going to save that as a custom property,

153
00:09:26,140 --> 00:09:28,310
and now I'm going to create another percentage,

154
00:09:28,310 --> 00:09:33,640
so I'm going to take the count property and divided by $all.count.

155
00:09:33,640 --> 00:09:33,960
Remember,

156
00:09:33,960 --> 00:09:38,650
$all is the variable I created with the Out variable for Get‑WinEvent

157
00:09:38,650 --> 00:09:42,230
because I want to know what percentage of the events are being

158
00:09:42,230 --> 00:09:48,020
generated by each source, and let's include the ComputerName in all

159
00:09:48,020 --> 00:09:53,680
uppercase since I saved it as variable, and let's also create a

160
00:09:53,680 --> 00:09:57,250
property called Report, and I'm just going to get the current date

161
00:09:57,250 --> 00:10:02,240
formatted as a day.

162
00:10:02,240 --> 00:10:07,130
All of that custom output will be sorted on the count property in

163
00:10:07,130 --> 00:10:10,440
descending order, and then to make it easier,

164
00:10:10,440 --> 00:10:14,410
I'm just going to format it as a table. Now, I have a report that

165
00:10:14,410 --> 00:10:18,320
shows me the source of entries in the system event log on Prospero.

166
00:10:18,320 --> 00:10:22,460
If I wanted to, I could save this then to some type of file, I

167
00:10:22,460 --> 00:10:26,240
would strip off the format table, and replace it with the export or

168
00:10:26,240 --> 00:10:27,640
convert command.

169
00:10:27,640 --> 00:10:32,150
But the bottom line is, I got what I needed from PowerShell. Yes,

170
00:10:32,150 --> 00:10:34,160
I had to do a little bit of work.

171
00:10:34,160 --> 00:10:37,720
I had to take advantage of the PowerShell language and syntax,

172
00:10:37,720 --> 00:10:40,810
but because I know it, and eventually, you will know it,

173
00:10:40,810 --> 00:10:43,640
you can do things like this as well.

174
00:10:43,640 --> 00:10:46,930
Almost all of the examples I've shown you in this course,

175
00:10:46,930 --> 00:10:51,000
especially these longer ones, can all become good source material for

176
00:10:51,000 --> 00:10:59,000
your own PowerShell scripts and functions, but again, you need to make sure that they work first properly from the console.

