How to concatenate a value to Select-Object's output - powershell

I have a script which finds snapshots that are older than 3 days and below are my code and output. However I want to add a new column for each VM displaying the actual age of that snapshots, say for example 5 days or 4 days. I have tried getting age by subtracting created date from today's date. But I am not sure how to add it as a column to my output.
I used this to calculate age:
$StartDate = Get-Date
$created = Get-VM |
Get-Snapshot |
Where {$_.Created -lt (Get-Date).AddDays(-1)} |
Select-Object Created
$age = New-Timespan -Start $StartDate -End $created
Full code:
Add-PSSnapin VMware.VimAutomation.Core
# HTML formatting
$a = "<style>"
$a = $a + "BODY{background-color:white;}"
$a = $a + "TABLE{border-width: 1px;border-style: solid;border-color: black;border-collapse: collapse;}"
$a = $a + "TH{border-width: 1px;padding: 5px;border-style: solid;border-color: black;foreground-color: black;background-color: LightBlue}"
$a = $a + "TD{border-width: 1px;padding: 5px;border-style: solid;border-color: black;foreground-color: black;background-color: white}"
$a = $a + "</style>"
Connect-VIServer -Server ***** -User ****** -Password ******
# Main section of check
Write-Host "Checking VMs for for snapshots"
$date = Get-Date
$datefile = Get-Date -UFormat '%m-%d-%Y-%H%M%S'
$filename = "C:\Temp\snaps_older_than_3\" + $datefile + ".htm"
$created = Get-VM |
Get-Snapshot |
Where {$_.Created -lt (Get-Date).AddDays(-1)} |
Select-Object Created
$age = New-Timespan -Start $StartDate -End $created
$ss = Get-VM |
Get-Snapshot |
Where {$_.Created -lt (Get-Date).AddDays(-1)} |
Select-Object vm, name, SizeGB, SizeMB, Created, powerstate + $age |
ConvertTo-HTML -Head $a -Body "<H2>VM Snapshot Report </H2>"|
Out-File $filename
Write-Host " Complete " -ForegroundColor Green
Write-Host "Your snapshot report has been saved to:" $filename
$SMTPServer = "*******"
$SMTPPort = 25
$username = "vcenter#mmmm.com"
#Define the receiver of the report
$to = "mmmmm#hcl.com"
$subject = "VM Snapshot Report"
$body = "VM Snapshot Report"
$attachment = New-Object Net.Mail.Attachment($filename)
$message = New-Object System.Net.Mail.MailMessage
$message.Subject = $subject
$message.Body = $body
$message.To.Add($to)
$message.From = $username
$message.Attachments.Add($attachment)
$smtp = New-Object System.Net.Mail.SmtpClient($SMTPServer, $SMTPPort);
$smtp.EnableSSL = $false
$smtp.Send($message)
Write-Host "Mail Sent"
Output:
I want to add a new column named "age".

Use a calculated property:
Get-VM |Select-Object VM,Name,SizeGB,SizeMB,Created,PowerState,#{Name='Age';Expression={New-TimeSpan -Start $StartDate -End $_.Created}}
From the help text for Select-Object:
-Property
Specifies the properties to select. Wildcards are permitted.
The value of the Property parameter can be a new calculated property.
To create a calculated property, use a hash table. Valid keys are:
Name (or Label) <string>
Expression <string> or <script block>

Related

Need to append this powershell script, not sure what to do

I need some help expanding on this script. Basically, I need to add when the $inputFileName = 'Report.txt' is not in its default dir when the script runs every morning the job spits out an e-mail saying no file to process, and then the job stops. What I am seeing is when there is no file in the source dir every now and then, the job runs attaching a blank .xls file that is of no use. I appreciate ANY help in advance!
$ErrorActionPreference="SilentlyContinue"
Stop-Transcript | out-null
$ErrorActionPreference = "Continue"
Start-Transcript -path C:\PATH\Logoutput.txt -append
$emailFilePath = 'C:\PATH\PATH\'
$inputFilePath = 'C:\PATH\PATH\Upload'
$inputFileName = 'Report.txt'
$inputFile = Join-Path $inputFilePath $inputFileName
$outputFileName = 'Report.csv'
$outputFilePath = 'C:\PATH\PATH\Send'
$OutputFile = Join-Path $outputFilePath $outputFileName
$folder = 'C:\PATH\PATH\Upload'
$filter = 'Report.txt'
$destination = $outputFilePath
$dateTime1 = Get-Date -Format s
Write-Host "The file was received: $dateTime1"
Import-CSV $inputFile -Delimiter "`t" -Header "Value 1" , "Value 2" , "Value 3" , "Value 4" , "Value 5" | Tee-Object -Variable Report.txt | Export-CSV $OutputFile -Delimiter "," -NoTypeInformation
$xl = new-object -comobject excel.application
$xl.visible = $false
$Workbook = $xl.workbooks.open("$OutputFile")
$Worksheets = $Workbooks.worksheets
$Workbook.SaveAs("$outputFilePath\Report.xls",1)
$Workbook.Saved = $True
$xl.Quit()
$objExcel = new-object -comobject excel.application
$objExcel.Visible = $false
$objWorkbook = $objExcel.Workbooks.open("$outputFilePath\Report.xls")
$objWorksheet = $objWorkbook.Worksheets.Item(1)
$objRange = $objWorksheet.UsedRange
[void] $objRange.EntireColumn.Autofit()
$objWorkbook.SaveAs("$outputFilePath\Report.xlsx",51)
$objWorkbook.Saved = $True
$objExcel.Quit()
$fromaddress = "user#domain.com"
$toaddress = "user#domain.com"
$bccaddress = ""
$CCaddress = "user#domain.com"
$Subject = "Here Is The Report"
$body = get-content $emailFilePath\content.htm
$attachment = "$outputFilePath\Report.xlsx"
$smtpserver = "smtpdomain"
$message = new-object System.Net.Mail.MailMessage
$message.From = $fromaddress
$message.To.Add($toaddress)
$message.CC.Add($CCaddress)
#$message.Bcc.Add($bccaddress)
$message.IsBodyHtml = $True
$message.Subject = $Subject
$attach = new-object Net.Mail.Attachment($attachment)
$message.Attachments.Add($attach)
$message.body = $body
$smtp = new-object Net.Mail.SmtpClient($smtpserver)
$smtp.Send($message)
$dateTime2 = Get-Date -Format s
Write-Host "The file was parsed and emailed at $dateTime2"
Start-Sleep -Seconds 60
$message.Dispose()
Start-Sleep -Seconds 60
kill -processname Excel
Start-Sleep -Seconds 60
Remove-Item "C:\PATH\PATH\Send\*.*"
$filenameFormat = "Report" + "" + (Get-Date -Format "yyyy-MM-dd") + ".txt"
$updatedFile = "C:\PATH\PATH\Upload\" + $filenameFormat
Rename-Item -Path "C:\PATH\PATH\Upload\Report.txt" -NewName $filenameFormat
Move-Item -Path $updatedFile -Destination C:\PATH\PATH\ArchivedReportData
Stop-Transcript
exit
You need to test for the file before processing as follows:
If ( -not (Test-Path -Path "inputFile")) {
#Write your file not found logic/messages here
Exit
}
Import-CSV $inputFile -Delimiter "`t" -Header "Value 1" , "Value 2" , "Value 3" , "Value 4" , "Value 5" | Tee-Object -Variable Report.txt | Export-CSV $OutputFile -Delimiter "," -NoTypeInformation
$dateTime1 = Get-Date -Format s
Write-Host "The file was received: $dateTime1"
...
HTH

Display duration of outlook appointment?

I am unable to display the duration of each appointment in my list box. I'm trying to print in the listbox 11:30; (60) B/H or 11:30-12:30; B/H, however unsure of how to do this, please may someone help?
I have tried $Duration and $._Duration, putting them between "[...]Start.ToString('HH:mm'), $_.Subject } " 'HH:mm' and $_. subject however these haven't been successful
#listbox for calendar entry
$Listboxcal= New-Object System.Windows.Forms.ListBox
$Listboxcal.Location = New-Object System.Drawing.Size(10,55)
$Listboxcal.Size = New-Object System.Drawing.Size(80,270)
$Listboxcal.Height = 150
add-type -assembly “Microsoft.Office.Interop.Outlook” | out-null
$outlook = new-object -comobject outlook.application
$namespace = $outlook.GetNameSpace(“MAPI”)
# https://learn.microsoft.com/en-us/dotnet/api/microsoft.office.interop.outlook.oldefaultfolders?view=outlook-pia
# Calendar = olFolderCalendar = 9
$calendar = $namespace.GetDefaultFolder(9)
# get today's calendar items!
$cItems = $calendar.Items | Where-Object {$_.Start -ge $(Get-Date $StrCaldate) -and $_.Start -le $(Get-Date $StrCaldate).AddDays(1)} |Sort-Object -Property Start | foreach { "{0}; {1}" -f $_.Start.ToString('HH:mm'), $_.Subject }
ForEach ($calendars in $cItems) {[void]$Listboxcal.Items.Add($calendars)}
The calendar appointments have a duration property. You just need to add that to the $cItems variable
$cItems = $calendar.Items | Where-Object {$_.Start -ge $(Get-Date $StrCaldate) -and $_.Start -le $(Get-Date $StrCaldate).AddDays(1)} |Sort-Object -Property Start | foreach { "{0}; ({1}) {2}" -f $_.Start.ToString('HH:mm'), $_.Duration, $_.Subject }
When I run this on my own calendar, I get the following:
16:30; (60) Appointment 1
18:30; (120) Appointment 2
It is working for me with the Duration property:
$calendar.Items | Select -First 1 | %{ $_.StartUTC.Tostring("hh:mm") `
+ "; (" + $_.Duration + ") " + $_.Subject}

Powershell Event Log Reporting

I'm working on a PS script to collect on certain Event IDs and spit them back every hour or so. I'm doing this because I want to spit it out to email for ease of reading.
My problem right now is that the script will run up to a certain point and hang. If I remove the date filters, it runs well. As soon as I re-add them (either through variables or hard-coded) it does it's hanging thing again. I need the date filters, however, because otherwise I'm getting everything when I'm looking for hourly chunks.
Looking for advice as I'd like to use variables for the one-offs or modifications! I'd also like to use spinoffs for other side reporting as well.
$filedate = (get-date).ToString("MM_dd_yy-hh_mm")
$filename = "bad_logins_DC01 " + $filedate + "_log.txt"
$after = (get-date).addhours(-1)
$before = (get-date)
$eventlog = Get-EventLog -ComputerName DC01 -LogName Security -After $after -Before $before
$eventlog | ?{$_.EventID -eq 4771 -or $_.EventID -eq 4776 } | Select #{Name="Event ID";Expression={$_.InstanceID}},#{Name="UserName";Expression={$_.ReplacementStrings[0]}},#{Name="Failure Code";Expression={$_.ReplacementStrings[4]}},#{Name="Host";Expression={$_.ReplacementStrings[6]}},#{Name="Port";Expression={$_.ReplacementStrings[7]}}, #{Name="Time";Expression={$_.TimeGenerated}} | ft | Out-File $filename -append -noclobber
$to = itsupport#ourdomain.com
$from = itsupport#ourdomain.com
$subject = $filename
$smtp = exchange.ourdomain.com
$contents = cat $filename
$body = $contents
Send-MailMessage -SmtpServer $smtp -To $to -From $from -Subject $subject -Body $body -Attachments $filename
Got it!
Big thanks to TheMadTechnicial for the assist on Get-WinEvent instead of Get-EventLog
$query_sec = #"
<QueryList>
<Query Id="0" Path="Security">
<Select Path="Security">*`
[System[Provider[#Name='Microsoft-Windows-Security-Auditing'] and `
TimeCreated[timediff(#SystemTime) <= 7200000] and `
(EventID=4771 or EventID=4776)]]</Select>
</Query>
</QueryList>
"#
$time = (Get-Date).ToString("dd-MM_hh-mm")
$to = "itsupport#mydomain.com"
$from = "me#mydomain.com"
$smtpServer = "mxserver.mydomain.com"
Try
{
$domain_controller = "DC01","C02","DC03"
ForEach ($dc in $domain_controller)
{
$Events = Get-WinEvent -ComputerName $dc -FilterXml $query_sec -ErrorAction Stop
ForEach ($event in $Events)
{
$eventXML = [xml]$Event.ToXml()
For ($i=0; $i -lt $eventXML.Event.EventData.Data.Count; $i++)
{
Add-Member -InputObject $Event -MemberType NoteProperty -Force `
-Name $eventXML.Event.EventData.Data[$i].Name `
-Value $eventXML.Event.EventData.Data[$i].'#text'
}
}
$filename = "C:\temp\"+$dc+"_failed_logins_"+$time+".txt"
$Events | Select-Object #{Name="UID";Expression={$_.TargetUserName}},`
ServiceName,`
#{Name="Error";Expression={$_.Status}},`
#{Name="IP";Expression={$_.IpAddress}},`
#{Name="Port";Expression={$_.IpPort}},`
#{Name="Event ID";Expression={$_.ID}},`
#{Name="Source";Expression={$_.MachineName}}`
| FT `
| Out-File $filename
$subject = "Bad Logins on " + $dc + " at " + $time
$body = Get-Content -Path $filename -Raw
Send-MailMessage -To $to -Subject $subject -From $from -SmtpServer $smtpServer -Body $body
}
}
Catch [Exception]
{
Write-Output " "
Write-Output "$dc has no relevant event logs!"
}

PowerShell outtput to HTML

Using the following and would like to know how to output the results to HTML file
$Start = (Get-Date).AddMinutes(-5)
$Computername = gc C:\Temp\List.txt
$Events = gc C:\Temp\ErrorCodes.txt
Get-EventLog -AsString -ComputerName $Computername |
ForEach-Object {
# write status info
Write-Progress -Activity "Checking Eventlogs on \\$ComputerName" -Status $_
# get event entries and add the name of the log this came from
Get-EventLog -LogName $_ -EntryType Error, Warning -After $Start -ComputerName $ComputerName -ErrorAction SilentlyContinue |
Add-Member NoteProperty EventLog $_ -PassThru | Where-Object {$Events -contains $_.eventid}
} |
# select the properties for the report
Select-Object EventLog, EventID, TimeGenerated, EntryType, Source, Message
This will get it to print with pretty colors. You can tinker around with it and change whatever you want.
$a = "<style>"
$a = $a + "BODY{background-color:peachpuff;}"
$a = $a + "TABLE{border-width: 1px;border-style: solid;border-color:black;border-collapse: collapse;}"
$a = $a + "TH{border-width: 1px;padding: 0px;border-style: solid;border-color: black;background-color:thistle}"
$a = $a + "TD{border-width: 1px;padding: 0px;border-style: solid;border-color: black;background-color:palegoldenrod}"
$a = $a + "</style>"
$Variable = get-what_I_want
$Variable2 = get-what_I_want
$VariableHTML = $Variable | ConvertTo-HTML -head $a -body "<H2>Title I want</H2>"
$Variable2HTML = $Variable2 | ConvertTo-HTML -head $a -body "<H1>Header One</H1> <H2>Header Two</H2> <H3>Header Three</H3> <p>Paragraph<p/>"
$VariableHTML > C:\PoSH\My_Exported_HTML.html
I added a second variable. As you can see, you can add different levels of headers and a Paragraph. I found this helpful for single line items or if you want a better description.
If I would say: ConvertTo-Html is what you need, than probably that would be enough to add a comment.
Instead I will say: before asking questions outside PowerShell, ask them inside PowerShell first.
Get-Help *html*

Powershell HTML email formatting

The below script puts database backup details into a nicely formatted table with borders and saves as a .htm. It then emails the report, but when the report is emailed the 'table' has no borders and no gap between the 'LastBackupDate' column and the 'LastLogBackupDate' column - it basically looks the same as the results would on the powershell console. Can anyone tell me how to format the email so all the html is used from the file? P.s. I can't use send-mailmessage due to issues with gmail ssl. Thanks.
#HTML
$a = "<style>"
$a = $a + "TABLE{border-width: 1px;border-style: solid;border-color: black;border-collapse: collapse;}"
$a = $a + "TH{border-width: 1px;padding: 10px;border-style: solid;border-color: black;}"
$a = $a + "TD{border-width: 1px;padding: 10px;border-style: solid;border-color: black;}"
$a = $a + "</style>"
#Set Date
$date = ( get-date ).ToString('yyyyMMdd')
#Locate DB
[System.Reflection.Assembly]::LoadWithPartialName('Microsoft.SqlServer.SMO') | out-null
$s = New-Object ('Microsoft.SqlServer.Management.Smo.Server') "LOCALHOST\SQLX64"
#Retrieves the last backup dates - for full and log backups
$dbs=$s.Databases
$backups = $dbs | SELECT Name,LastBackupDate, LastLogBackupDate | Sort-Object LastBackupDate | ConvertTo-HTML -head $a -body "<H2>DB01 Database Backup Details $date </H2>" | Out-File $("D:\SQL_Backup_Log_Script\Logs\Backup_Log_Temp.htm")
#Email Report
$EmailFrom = "someone#domain.com"
$emailto = "me#gmail.com"
$Subject = "Database Backup Log $date"
$Body = Get-Content D:\SQL_Backup_Log_Script\Logs\Backup_Log_Temp.htm
$SMTPServer = "smtp.gmail.com"
$SMTPClient = New-Object Net.Mail.SmtpClient($SmtpServer, 587)
$SMTPClient.EnableSsl = $true
$SMTPClient.Credentials = New-Object System.Net.NetworkCredential("someone#domain.com", "password here");
$message = New-Object Net.Mail.MailMessage($EmailFrom, $EmailTo, $Subject, $Body)
$message.IsBodyHtml = $true;
$SMTPClient.Send($message)
#Rename file to include today's date
Rename-Item -path D:\SQL_Backup_Log_Script\Logs\Backup_Log_Temp.htm -newname ($date +"_DB01_Backup_Log.htm")
Try change this line (can't test if is this the problem):
$Body = [System.IO.File]::ReadAllText("D:\SQL_Backup_Log_Script\Logs\Backup_Log_Temp.htm")
the body property in Net.Mail.MailMessage accept [string], get-content return [string[]].