I always talk about “objects in the pipeline” when writing or training about PowerShell. We shouldn’t be thinking about trying to parse text or even be too concerned about individual items. Most of the time we can simply let the PowerShell pipeline do all of the work for us. With that said, you can take control, too. One such situation might be when you want to look at the results of PowerShell expression, where it would help to see results grouped together. Taking this scenario a step further, you may want to create an HTML report using grouped output. If you look at help for Convertto-HTML, you won’t see a –Group parameter or anything that looks like it will help. As I’ll show you, it isn’t too difficult to achieve.

First, let’s look at creating a nice formatted group report in the console. We’ll begin with some data.

PowerShell

1

$data=dirc:\scripts-File-Recurse

The variable $data should contain all the files in my Scripts folder. Let’s say I want to create a formatted report that shows files grouped by directory.

PowerShell

1

$data|sortDirectory,Length|format-table-GroupByDirectory

With the Format-Table cmdlet, you can specify a property name to group by. I recommend you sort on that same property first as I’ve done.

This isn’t too difficult because PowerShell has built-in instructions that tell it how to format a table of file objects. What I want next is to duplicate this in an HTML file. To accomplish this, I’ll need an intermediate step to group the data accordingly.

PowerShell

1

$groups=$data|sortDirectory,Length|Group-Object-PropertyDirectory

Technically, I didn’t have to sort before grouping. But the result will be that each group of related files is now sorted first by directory and then length,

Each group of related files is now sorted first by directory and then length. (Image Credit: Jeff Hicks)

Sponsored

I now have a new set of objects. The file objects are in the Group property for each grouped entry. To create the HTML report, I will need to use fragments. Instead of piping directly to Convertto-HTML, I’m going to create my own body. I’ll start with a blank string.

PowerShell

1

$Body=""

Now for the fun part. I’m going to enumerate each grouped entry in $grouped. I’m going to use the Name property as my heading with an H2 HTML tag. Next, I’m going to send the collection of files and create an HTML table fragment. A table is the default, so I didn’t have specify the –As parameter, but I wanted to demonstrate it in case you needed a list instead.

PowerShell

1

2

3

4

5

6

7

foreach($itemin$groups){

$Body+="<H2>$($item.name)</H2>"

$body+=$item.Group|

SelectCreationTime,LastWriteTime,

@{Name="Size";Expression={$_.length}},Name|

Convertto-Html-Fragment-AsTable

}

You have to remember that Convertto-HTML will look at any incoming objects and convert all properties, not just the ones you see on the screen. That’s why I’m selecting a few objects first. With the body complete, I’m now ready to create the final document.

I’m adding style from an external CSS file and including a footer of sorts with –PostContent displaying the current date and time. This is what I end up with:

You could follow the same process for any type of object. Because this is likely to be a repeatable process, this is something you want to turn into a PowerShell tool. For those of you panicking thinking you can’t do it, relax. Here’s my version of a tool that I call Out-HTMLReport.

PowerShell

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

#requires -version 3.0

FunctionOut-HTMLReport{

<#

.SYNOPSIS

Send the output of a command to an HTML report.

.DESCRIPTION

Send output from a PowerShell expression to this command and create a formatted HTML report. For best results you should specify the properties to display or use Select-Object earlier in your expression. You can also group results by a property name.

.PARAMETER InputObject

The output from some PowerShell expression.

.PARAMETER Path

The filename and path for the HTML file.

.PARAMETER PreContent

Content to be used at the beginning of your HTML document. This can include HTML tags.

.PARAMETER CssUri

The path to a CSS file. See examples for how to embed a style sheet in the document.

.PARAMETER As

Data will be formatted as fragments. It can be either a Table (default) or a List. All data will be formatted the same.

.PARAMETER Group

The property to group data on. If you specify a grouping property, this property will not be displayed in the table or list output.

.PARAMETER Properties

The properties to display in the report. The default will be all properties.

.PARAMETER Title

The title for your HTML report.

.PARAMETER Head

Content to use for the Head section of the HTML document.

.PARAMETER PostContent

Content to be used at the end of your HTML document. This can include HTML tags.

Get all processes where a Company property is defined and create an HTML report grouping on the company property. Selected properties for each object will be displayed as a table. This example is using an external CSS file.

[Parameter(Position=0,Mandatory,HelpMessage="Enter the name of the report to create")]

[ValidateNotNullorEmpty()]

[string]$Path,

[string]$Group,

[ValidateNotNullorEmpty()]

[string[]]$Properties="*",

[string]$CssUri,

[ValidateSet("Table","List")]

[ValidateNotNullorEmpty()]

[string]$As="Table",

[string]$Title,

[string]$Head,

[string[]]$PreContent,

[string[]]$PostContent,

[Parameter(Position=1,Mandatory,ValueFromPipeline,

HelpMessage="Enter objects to format")]

[ValidateNotNullorEmpty()]

[object[]]$InputObject

)

Begin{

Write-Verbose"Starting $($myinvocation.mycommand)"

#copy most of the bound parameters since they will

#be passed to Convertto-HTML

Write-verbose"PSBoundParameters"

write-Verbose($PSBoundParameters|out-string)

#initialize an array to hold all the processed data

$data=@()

#iniatilize a variable for the HTML body

[string[]]$body=@()

$body+=$PreContent

}#begin

Process{

#add each input object to $data

foreach($itemin$Inputobject){

$data+=$item

}

}#process

End{

Write-Verbose"Processing $($data.count) objects"

#sort on grouping property if used

if($Group){

Write-Verbose"Grouping on $Group"

$data|Group-Object-Property$Group|

Sort-Object-PropertyName|

foreach{

$body+="<H2>$($_.Name)</H2>"

$body+=$_.Group|

Select-Object-property$Properties-ExcludeProperty$Group|

ConvertTo-HTML-As$As-Fragment

}#foreach

}

else{

Write-Verbose"No grouping"

$body+=$data|

Select-Object-property$Properties|

ConvertTo-HTML-As$As-Fragment

}

#create the HTML

$htmlParams=$PSBoundParameters

#remove conflicting or unused parameters

"InputObject","Path","Group","Properties",

"PreContent","WhatIf","Confirm"|

foreach{

$htmlparams.Remove($_)|out-null

}

#add body

$htmlParams.Add("Body",$body)

Write-Verbose"Using these Convertto-HTML parameters"

Write-Verbose($htmlParams|out-string)

#create the HTML

$html=ConvertTo-HTML@htmlParams

#create the file

$html|Out-File-filepath$Path-encodingASCII

Write-Verbose"Report created at $path"

Write-Verbose"Ending $($myinvocation.mycommand)"

}#end

}#end Out-Report function

#optional: define an alias

Set-Alias-Nameohr-ValueOut-HTMLReport

The function is intended to be used at the end of a PowerShell expression is the same way would you use Out-File or Out-Printer. If you look through the function, you’ll see that is a wrapper to Convertto-HTML and uses many of the same parameters. Here’s how you can use it. First, I need some new data.

You can use my function even if you don’t want to group output. I hope you’ve seen what you can accomplish with PowerShell and that it isn’t especially complicated, especially if you read full help and examples for commands like Format-Table and ConvertTo-HTML.