-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathSendEmail-3rdPartySoftware.ps1
333 lines (282 loc) · 13.6 KB
/
SendEmail-3rdPartySoftware.ps1
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
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
<#
.INFO
Script: SendEmail-3rdPartySoftware.ps1
Author: Richard Tracy
Email: [email protected]
Twitter: @rick2_1979
Website: www.powershellcrack.com
Last Update: 07/15/2019
Version: 1.0.0
.DISCLOSURE
THE SCRIPT IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. BY USING OR DISTRIBUTING THIS SCRIPT, YOU AGREE THAT IN NO EVENT
SHALL THE AUTHOR OR ANY AFFILATES BE HELD LIABLE FOR ANY DAMAGES WHATSOEVER RESULTING FROM USING OR DISTRIBUTION OF THIS SCRIPT, INCLUDING,
WITHOUT LIMITATION, ANY SPECIAL, CONSEQUENTIAL, INCIDENTAL OR OTHER DIRECT OR INDIRECT DAMAGES. BACKUP UP ALL DATA BEFORE PROCEEDING.
.SYNOPSIS
Sends an email of 3rd party Software and updates from list generated
.DESCRIPTION
Imports list generated by Get-3rdPartySoftware.ps1 and emails it and formats it as table
.PARAMETER SoftwareList
REQUIRED: Specified path to software list
.PARAMETER ConfigPath
Specified path to alternate config file. Defaults to relative path of script under Config folder
.PARAMETER SMTPServer
NAMED SMTP. Specify basic SMTP server (usally exchange). Use config for more detail
.PARAMETER From
NAMED SMTP Specify from receipent when using SMTPServer param
.PARAMETER To
NAMED SMTP. Specify to receipent when using SMTPServer param> Use array for mutlple. EG: @("user1@domain", "user2@domain")
.EXAMPLE
powershell.exe -file "SendEmail-3rdPartySoftware.ps1" -SoftwareList D:\3rdPartySoftware\softwarelist.xml
powershell.exe -file "SendEmail-3rdPartySoftware.ps1" -ConfigPath D:\Configs\email.xml -SoftwareList D:\3rdPartySoftware\softwarelist.xml
powershell.exe -file "SendEmail-3rdPartySoftware.ps1" -SoftwareList D:\3rdPartySoftware\softwarelist.xml -SMSTServer mail.mydomain.local -From [email protected] [email protected]
.NOTES
This script is meant to be scheduled or chained with Get-3rdPartySoftware.ps1 script. Use the Schedule exposrt to build a chain task schudule.
Using the config is more advanced than the params. Read the config comment sfor more info.
.LINK
.CHANGE LOG
1.0.0 - Jul 15, 2019 - initial
#>
##*===========================================================================
##* PARAMS
##*===========================================================================
[CmdletBinding(DefaultParameterSetName='Null')]
param (
[Parameter(ParameterSetName='Config', Mandatory=$true)]
[string]$ConfigPath,
[Parameter(Mandatory=$true)]
[string]$SoftwareList,
[Parameter(ParameterSetName='SMTP', Mandatory=$true)]
[string]$SMTPServer,
[Parameter(ParameterSetName='SMTP',Mandatory=$false)]
[string]$From = 'mdt@localhost',
[Parameter(ParameterSetName='SMTP',Mandatory=$true)]
[string[]]$To
)
#==================================================
# FUNCTIONS
#==================================================
Function Test-IsISE {
# try...catch accounts for:
# Set-StrictMode -Version latest
try {
return ($null -ne $psISE);
}
catch {
return $false;
}
}
Function Get-ScriptPath {
# Makes debugging from ISE easier.
if ($PSScriptRoot -eq "")
{
if (Test-IsISE)
{
$psISE.CurrentFile.FullPath
#$root = Split-Path -Parent $psISE.CurrentFile.FullPath
}
else
{
$context = $psEditor.GetEditorContext()
$context.CurrentFile.Path
#$root = Split-Path -Parent $context.CurrentFile.Path
}
}
else
{
#$PSScriptRoot
$PSCommandPath
#$MyInvocation.MyCommand.Path
}
}
Function Format-DatePrefix {
[string]$LogTime = (Get-Date -Format 'HH:mm:ss.fff').ToString()
[string]$LogDate = (Get-Date -Format 'MM-dd-yyyy').ToString()
return ($LogDate + " " + $LogTime)
}
Function Write-LogEntry {
param(
[Parameter(Mandatory=$true,Position=0,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
[ValidateNotNullOrEmpty()]
[string]$Message,
[Parameter(Mandatory=$false,Position=2)]
[string]$Source = '',
[parameter(Mandatory=$false)]
[ValidateSet(0,1,2,3,4)]
[int16]$Severity,
[parameter(Mandatory=$false, HelpMessage="Name of the log file that the entry will written to")]
[ValidateNotNullOrEmpty()]
[string]$OutputLogFile = $Global:LogFilePath,
[parameter(Mandatory=$false)]
[switch]$Outhost
)
Begin{
[string]$LogTime = (Get-Date -Format 'HH:mm:ss.fff').ToString()
[string]$LogDate = (Get-Date -Format 'MM-dd-yyyy').ToString()
[int32]$script:LogTimeZoneBias = [timezone]::CurrentTimeZone.GetUtcOffset([datetime]::Now).TotalMinutes
[string]$LogTimePlusBias = $LogTime + $script:LogTimeZoneBias
}
Process{
# Get the file name of the source script
Try {
If ($script:MyInvocation.Value.ScriptName) {
[string]$ScriptSource = Split-Path -Path $script:MyInvocation.Value.ScriptName -Leaf -ErrorAction 'Stop'
}
Else {
[string]$ScriptSource = Split-Path -Path $script:MyInvocation.MyCommand.Definition -Leaf -ErrorAction 'Stop'
}
}
Catch {
$ScriptSource = ''
}
If(!$Severity){$Severity = 1}
$LogFormat = "<![LOG[$Message]LOG]!>" + "<time=`"$LogTimePlusBias`" " + "date=`"$LogDate`" " + "component=`"$ScriptSource`" " + "context=`"$([Security.Principal.WindowsIdentity]::GetCurrent().Name)`" " + "type=`"$Severity`" " + "thread=`"$PID`" " + "file=`"$ScriptSource`">"
# Add value to log file
try {
Out-File -InputObject $LogFormat -Append -NoClobber -Encoding Default -FilePath $OutputLogFile -ErrorAction Stop
}
catch {
Write-Host ("[{0}] [{1}] :: Unable to append log entry to [{1}], error: {2}" -f $LogTimePlusBias,$ScriptSource,$OutputLogFile,$_.Exception.Message) -ForegroundColor Red
}
}
End{
If($Outhost -or $Global:OutTohost){
If($Source){
$OutputMsg = ("[{0}] [{1}] :: {2}" -f $LogTimePlusBias,$Source,$Message)
}
Else{
$OutputMsg = ("[{0}] [{1}] :: {2}" -f $LogTimePlusBias,$ScriptSource,$Message)
}
Switch($Severity){
0 {Write-Host $OutputMsg -ForegroundColor Green}
1 {Write-Host $OutputMsg -ForegroundColor Gray}
2 {Write-Warning $OutputMsg}
3 {Write-Host $OutputMsg -ForegroundColor Red}
4 {If($Global:Verbose){Write-Verbose $OutputMsg}}
default {Write-Host $OutputMsg}
}
}
}
}
##*===========================================================================
##* VARIABLES
##*===========================================================================
# Use function to get paths because Powershell ISE and other editors have differnt results
$scriptPath = Get-ScriptPath
[string]$scriptDirectory = Split-Path $scriptPath -Parent
[string]$scriptName = Split-Path $scriptPath -Leaf
[string]$scriptBaseName = [System.IO.Path]::GetFileNameWithoutExtension($scriptName)
#Get required folder and File paths
If($PsCmdlet.ParameterSetName -eq 'Config'){
[string]$EmailConfigPath = $Config
}
Else{
[string]$ConfigPath = Join-Path -Path $scriptDirectory -ChildPath 'Configs'
[string]$EmailConfigPath = Join-Path -Path $ConfigPath -ChildPath "email_configs.xml"
}
$RelativeLogPath = Join-Path -Path $scriptDirectory -ChildPath 'Logs'
#build log name
[string]$FileName = $scriptBaseName + '-' + (get-date -Format MM-dd-yyyy-hh-mm-ss) + '.log'
#build global log fullpath
$Global:LogFilePath = Join-Path $RelativeLogPath -ChildPath $FileName
#clean old log
if(Test-Path $Global:LogFilePath){remove-item -Path $Global:LogFilePath -ErrorAction SilentlyContinue | Out-Null}
Write-Host "Logging to file: $LogFilePath" -ForegroundColor Cyan
##* ==============================
##* MAIN - DO ACTION
##* ==============================
#import the Software list
If($SoftwareList){
$SoftwareObject = Import-Clixml $SoftwareList
}
Else{
Write-LogEntry ("No software repository path or xml file specified") -Severity 3 -Outhost
Exit
}
$EmailParams = @{}
# BUILD PATHS FROM XML
#=======================================================
If(Test-Path $EmailConfigPath){
[string]$EmailXMLFile = (Get-Content $EmailConfigPath -ReadCount 0) -replace '&','&'
[xml]$EmailConfigs = $EmailXMLFile
#get email settings
[boolean]$SendEmail = [boolean]::Parse($EmailConfigs.emailConfigs.enable)
[string]$EmailType = $EmailConfigs.emailConfigs.Type
[string]$Subject = $EmailConfigs.emailConfigs.Subject
switch($EmailType){
"internal" {
[string]$Server = $EmailConfigs.emailConfigs.internalEmail.SmtpServer
[string]$Port = $EmailConfigs.emailConfigs.internalEmail.Port
[boolean]$UseSSL = [boolean]::Parse($EmailConfigs.emailConfigs.internalEmail.UseSSL)
[string]$From = $EmailConfigs.emailConfigs.internalEmail.From
$Recipents = $EmailConfigs.emailConfigs.internalEmail.To -split ","
[string[]]$To = @($Recipents)
#build credentials
If(Get-ChildItem $EmailConfigs.emailConfigs.ExchCreds -Recurse -ErrorAction SilentlyContinue | Out-null){
[System.Management.Automation.PSCredential]$credentials = Get-credential (Import-Clixml $EmailConfigs.emailConfigs.internalEmail.ExchCreds)
$EmailParams.Add('Credentials',$credentials)
}
}
"external" {
[string]$Server = $EmailConfigs.emailConfigs.externalEmail.SmtpServer
[string]$Port = $EmailConfigs.emailConfigs.externalEmail.Port
[boolean]$UseSSL = [boolean]::Parse($EmailConfigs.externalEmail.UseSSL)
[string]$From = $EmailConfigs.emailConfigs.externalEmail.From
$Recipents = $EmailConfigs.emailConfigs.internalEmail.To -split ","
[string[]]$To = @($Recipents)
[string]$Username = $EmailConfigs.emailConfigs.externalEmail.Username
[string]$Password = $EmailConfigs.emailConfigs.externalEmail.Password
#build credentials
$credentials = new-object Management.Automation.PSCredential "$Username", ("$Password" | ConvertTo-SecureString -AsPlainText -Force)
If($credentials){$EmailParams.Add('Credentials',$credentials)}
}
}
Write-LogEntry ("Using {0} email type for: {1}" -f $EmailType,$Server) -Severity 1 -Outhost
}
Else{
Write-LogEntry ("Unable to find configuration settings: {0}" -f $EmailConfigPath) -Severity 3 -Outhost
Exit
}
$Attachment = Get-ChildItem $RelativeLogPath -Filter '*log' | Where-Object{$_.Name -match 'Get-3rdPartySoftware'} | sort LastWriteTime | select -last 1 -ExpandProperty FullName
If($Attachment){$EmailParams.Add('Attachment',$Attachment)}
#Set columns list
$columnsToSelect = @('DownloadDate','Publisher','Product','ProductType','File','Size','Version','Arch','Language')
#Grab MDTShare properties values (if exists)
$SoftwareObject | Foreach{
$ShareProperties = $_.PSObject.Properties -match 'MDTShare' | Select -ExpandProperty Name
}
#slat them to the columns list
If($ShareProperties){$columnsToSelect += $ShareProperties}
#Grab MDTStatus properties values (if exists)
$SoftwareObject | Foreach{
$StatusProperties = $_.PSObject.Properties -match 'MDTStatus' | Select -ExpandProperty Name
}
#slat them to the columns list
If($StatusProperties){$columnsToSelect += $StatusProperties}
#build style
$style = "<style>BODY{font-family: Arial; font-size: 10pt;}"
$style = $style + "TABLE{border: 1px solid black; border-collapse: collapse;}"
$style = $style + "TH{border: 1px solid black; background: #dddddd; padding: 5px; }"
$style = $style + "TD{border: 1px solid black; padding: 5px; }"
$style = $style + "</style>"
#[string]$message = $SoftwareObject | Where-Object{$_.Downloaded -eq "True"} | Select-Object Publisher,Product,@{Label='Product Type'; Expression={$_.ProductType}},File,Size,Version,Arch,Language,@{Label='Downloaded'; Expression={$_.DownloadDate}} | Sort-Object DownloadDate -Descending | ConvertTo-Html -Head $style
[string]$message = $SoftwareObject | Where-Object{$_.Downloaded -eq "True"} | Select-Object $columnsToSelect | Sort-Object DownloadDate -Descending | ConvertTo-Html -Head $style
Write-LogEntry ("Software columns identified: {0}" -f ($columnsToSelect -join ",")) -Severity 1 -Outhost
#format message as a html table
$message = $message + "SOFTWARE LOCATION: $(Split-path $SoftwareList -Parent)"
$message = $message + "<hr>"
$message = $message + "HOST: $env:Computername"
$message = $message + "<br>"
$message = $message + "SCRIPT: Get-3rdPartySoftware.ps1"
$message = $message + "<br>"
$message = $message + "DATE: $(Get-date)"
If($SendEmail){
Write-LogEntry ("Sending Email to: {0}" -f ($Recipents -join ",")) -Severity 1 -Outhost
Try{
Send-MailMessage -From $From -To $to -Subject $Subject -Body $message -BodyAsHtml -Priority High -DeliveryNotificationOption OnSuccess, OnFailure -SmtpServer $Server -UseSsl:$UseSSL @EmailParams
Write-LogEntry ("Email Sent, script completed") -Severity 1 -Outhost
}
Catch{
Write-LogEntry ("Unable to send email: {0}" -f $_.Exception.Message) -Severity 3 -Outhost
}
}