Powershell script design write message body to log - email

I'm trying to parse through my Outlook inbox and match certain messages and then, for each of those matches, write the email message body to my Application log. My code so far is below but I'm finding that the script is writing the same message for each match. Meaning, the last message body that the script stores, gets written X number of times for each of the matches that the filter catches.
Add-type -assembly "Microsoft.Office.Interop.Outlook" | out-null
$olFolders = "Microsoft.Office.Interop.Outlook.olDefaultFolders" -as [type]
$outlook = new-object -comobject outlook.application
$namespace = $outlook.GetNameSpace("MAPI")
$inbox = $namespace.getDefaultFolder($olFolders::olFolderInBox)
$filter = (%{$inbox.items | Where {$_.SenderName -match ‘TestUser’ -and $_.UnRead -eq $true}})
$filter.count
foreach ($msg in $filter)
{
$MsgBody = $filter | select-object Body | format-table -HideTableHeaders -Wrap | Out-String
}
for ($i = $filter.count; $i -gt 0 ; $i --) {
Write-eventlog -logname Application -source "TestAlerts" -eventID 100 -entrytype Information -message "$MsgBody"
#$($msg)[$i].UnRead -eq $false - this still isn't working either.
}

Try this:
for ($i = $filter.count; $i -gt 0 ; $i --) {
$msg = $filter[$i]
$MsgBody = $msg | select-object Body | format-table -HideTableHeaders -Wrap | Out-String
Write-eventlog -logname Application -source "TestAlerts" -eventID 100 -entrytype Information -message "$MsgBody"
}

Related

Export 365 Users Mailboxes Size and Unit in separate columns

I have good script that export 365 Users Mailboxes Size to csv file.
The results looks like that:
Today it display the Total Size with the Unit (KB/MB/GB) inside the same column.
As for the Total Size (Bytes)- i dont really need that column.
So, i want to separate the Total Size column into 2 separate columns of Size and Unit columns.
Like that:
So at the end, the results will be:
Here's the code:
Param(
[Parameter(Mandatory = $false)]
[switch]$MFA,
[switch]$SharedMBOnly,
[switch]$UserMBOnly,
[string]$MBNamesFile,
[string]$UserName,
[string]$Password
)
Function Get_MailboxSize{
$Stats=Get-MailboxStatistics -Identity $UPN
$IsArchieved=$Stats.IsArchiveMailbox
$ItemCount=$Stats.ItemCount
$TotalItemSize=$Stats.TotalItemSize
$TotalItemSizeinBytes= $TotalItemSize –replace “(.*\()|,| [a-z]*\)”, “”
$TotalSize=$stats.TotalItemSize.value -replace "\(.*",""
$DeletedItemCount=$Stats.DeletedItemCount
$TotalDeletedItemSize=$Stats.TotalDeletedItemSize
#Export result to csv
$Result=#{'Display Name'=$DisplayName;'User Principal Name'=$upn;'Mailbox Type'=$MailboxType;'Primary SMTP Address'=$PrimarySMTPAddress;'IsArchieved'=$IsArchieved;'Item Count'=$ItemCount;'Total Size'=$TotalSize;'Total Size (Bytes)'=$TotalItemSizeinBytes;'Deleted Item Count'=$DeletedItemCount;'Deleted Item Size'=$TotalDeletedItemSize;'Issue Warning Quota'=$IssueWarningQuota;'Prohibit Send Quota'=$ProhibitSendQuota;'Prohibit send Receive Quota'=$ProhibitSendReceiveQuota}
$Results= New-Object PSObject -Property $Result
$Results | Select-Object 'Display Name','User Principal Name','Mailbox Type','Primary SMTP Address','Item Count','Total Size','Total Size (Bytes)','IsArchieved','Deleted Item Count','Deleted Item Size','Issue Warning Quota','Prohibit Send Quota','Prohibit Send Receive Quota' | Export-Csv -Path $ExportCSV -Notype -Append
}
Function main(){
#Check for EXO v2 module inatallation
$Module = Get-Module ExchangeOnlineManagement -ListAvailable
if($Module.count -eq 0){
Write-Host Exchange Online PowerShell V2 module is not available -ForegroundColor yellow
$Confirm= Read-Host Are you sure you want to install module? [Y] Yes [N] No
if($Confirm -match "[yY]") {
Write-host "Installing Exchange Online PowerShell module"
Install-Module ExchangeOnlineManagement -Repository PSGallery -AllowClobber -Force
}
else {
Write-Host EXO V2 module is required to connect Exchange Online.Please install module using Install-Module ExchangeOnlineManagement cmdlet.
Exit
}
}
#Connect Exchange Online with MFA
if($MFA.IsPresent){
Connect-ExchangeOnline
}
#Authentication using non-MFA
else{
#Storing credential in script for scheduling purpose/ Passing credential as parameter
if(($UserName -ne "") -and ($Password -ne "")){
$SecuredPassword = ConvertTo-SecureString -AsPlainText $Password -Force
$Credential = New-Object System.Management.Automation.PSCredential $UserName,$SecuredPassword
}
else{
$Credential=Get-Credential -Credential $null
}
Connect-ExchangeOnline -Credential $Credential
}
#Output file declaration
$ExportCSV=".\MailboxSizeReport_$((Get-Date -format yyyy-MMM-dd-ddd` hh-mm` tt).ToString()).csv"
$Result=""
$Results=#()
$MBCount=0
$PrintedMBCount=0
Write-Host Generating mailbox size report...
#Check for input file
if([string]$MBNamesFile -ne "") {
#We have an input file, read it into memory
$Mailboxes=#()
$Mailboxes=Import-Csv -Header "MBIdentity" $MBNamesFile
foreach($item in $Mailboxes){
$MBDetails=Get-Mailbox -Identity $item.MBIdentity
$UPN=$MBDetails.UserPrincipalName
$MailboxType=$MBDetails.RecipientTypeDetails
$DisplayName=$MBDetails.DisplayName
$PrimarySMTPAddress=$MBDetails.PrimarySMTPAddress
$IssueWarningQuota=$MBDetails.IssueWarningQuota -replace "\(.*",""
$ProhibitSendQuota=$MBDetails.ProhibitSendQuota -replace "\(.*",""
$ProhibitSendReceiveQuota=$MBDetails.ProhibitSendReceiveQuota -replace "\(.*",""
$MBCount++
Write-Progress -Activity "`n Processed mailbox count: $MBCount "`n" Currently Processing: $DisplayName"
Get_MailboxSize
$PrintedMBCount++
}
}
#Get all mailboxes from Office 365
else{
Get-Mailbox -ResultSize Unlimited | foreach {
$UPN=$_.UserPrincipalName
$Mailboxtype=$_.RecipientTypeDetails
$DisplayName=$_.DisplayName
$PrimarySMTPAddress=$_.PrimarySMTPAddress
$IssueWarningQuota=$_.IssueWarningQuota -replace "\(.*",""
$ProhibitSendQuota=$_.ProhibitSendQuota -replace "\(.*",""
$ProhibitSendReceiveQuota=$_.ProhibitSendReceiveQuota -replace "\(.*",""
$MBCount++
Write-Progress -Activity "`n Processed mailbox count: $MBCount "`n" Currently Processing: $DisplayName"
if($SharedMBOnly.IsPresent -and ($Mailboxtype -ne "SharedMailbox")){
return
}
if($UserMBOnly.IsPresent -and ($MailboxType -ne "UserMailbox")){
return
}
Get_MailboxSize
$PrintedMBCount++
}
}
#Open output file after execution
If($PrintedMBCount -eq 0){
Write-Host No mailbox found
}
else{
Write-Host `nThe output file contains $PrintedMBCount mailboxes.
if((Test-Path -Path $ExportCSV) -eq "True"){
Write-Host `nThe Output file available in $ExportCSV -ForegroundColor Green
$Prompt = New-Object -ComObject wscript.shell
$UserInput = $Prompt.popup("Do you want to open output file?",0,"Open Output File",4)
If ($UserInput -eq 6){
Invoke-Item "$ExportCSV"
}
}
}
#Disconnect Exchange Online session
Disconnect-ExchangeOnline -Confirm:$false | Out-Null
}
. main
Replace line:
$Results | Select-Object 'Display Name','User Principal Name','Mailbox Type','Primary SMTP Address','Item Count','Total Size','Total Size (Bytes)','IsArchieved','Deleted Item Count','Deleted Item Size','Issue Warning Quota','Prohibit Send Quota','Prohibit Send Receive Quota' | Export-Csv -Path $ExportCSV -Notype -Append
With:
$Results | Select-Object 'Display Name','User Principal Name','Mailbox Type','Primary SMTP Address','Item Count',#{Name = 'Total Size'; Expression = {($_."Total Size").Split(" ")[0]}},#{Name = 'Unit'; Expression = {($_."Total Size").Split(" ")[1]}},'Total Size (Bytes)','IsArchieved','Deleted Item Count','Deleted Item Size','Issue Warning Quota','Prohibit Send Quota','Prohibit Send Receive Quota' | Export-Csv -Path $ExportCSV -Notype -Append
I have replaced 'total size' with the 2 following calculated properties:
#{Name = 'Total Size'; Expression = {($_."Total Size").Split(" ")[0]}}
#{Name = 'Unit'; Expression = {($_."Total Size").Split(" ")[1]}}
This splits the value into an array and will put them into the specified properties of "Total Size" & "Unit"
You can use -csplit (case-sensitive -split) to split the TotalItemSize value by the unit. This will create an array of three items. The third item will be the (# bytes) value that you are replacing anyway.
$Stats=Get-MailboxStatistics -Identity $UPN
$TotalItemSize,$Unit = $Stats.TotalItemSize.Value -csplit '(\b[A-Z]+\b)').Trim()[0,1]
$Unit will now have the unit and $TotalItemSize will contain the size without the unit. Trim() is to remove surrounding spaces from the formatting.
You could technically do all of your size manipulations with one line:
$TotalItemSize,$Unit,$TotalSizeInBytes = ($Stats.TotalItemSize.Value -split ' ' -replace '\(|,')[0,1,2]

How to read input through a csv file and write the output in an output file in power shell script?

[This is the powershell script to get the selected services status of servers,where list of servers are given through input csv file and the status of those server should be stored in an output file.
-----------Below is the script----------
$Servers = Get-Content "C:\temp\input.csv"
$Log = #()
foreach($Server in $Servers)
{
$Services = Get-Service *HRRA*, "SQL Server Reporting Services" -ComputerName $COMPUTERNAME
foreach ($Service in $Services)
{
$properties = #(
#{n='ServiceName';e={$Service.Name}}
#{n='Status';e={$Service.Status}}
#{n='ServerName';e={$Server}}
)
$Log += "" | select $properties
}
}
$Log | Format-Table -AutoSize | Out-File "D:\temp\test.txt" -Force
------------------------------------New Script----------------------------------
$Computers = Import-Csv "C:\Temp\Input.csv"
#$mailboxdata = Get-Service *HRRA*,"SQL Server Reporting Services" -ComputerName $ComputerName| select machinename,name, status | sort machinename |
#format-table -AutoSize |Out-File "D:\Temp\RRR.txt"
#LogWrite "$ComputerName"
foreach($row in $computers)
{
{
Add-Content -Path D:\Temp\SSRS.txt -Value $mailboxdata }
Get-Content -Path D:\Temp\SSRS.txt
$ComputerName= $row.ComputerName;
$mailboxdata = Get-Service *HRRA*,"SQL Server Reporting Services" -ComputerName $ComputerName| select machinename,name, status | sort machinename |
format-table -AutoSize |Out-File "D:\Temp\SSR.txt"
$fromaddress = "Reporting.Services#accenture.com"
$toaddress = "aditi.m.singh#accenture.Com"
#$toaddress1 = "s.ab.balakrishnan#accenture.com"
$Subject = "SSRS Services Status"
$body = "Please find attached - test"
$attachment = "D:\Temp\SSR.txt"
$smtpserver = "AMRINT.SMTP.ACCENTURE.COM"
$message = new-object System.Net.Mail.MailMessage
$message.From = $fromaddress
$message.To.Add($toaddress)
#$message.To.Add($toaddress1)
$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)
}
If i am running the script with static value its giving me output for both the servers---Below is the script----
Get-Service *HRRA*,"SQL Server Reporting Services" -ComputerName VW118627, VW118623 | select name, status, machinename | sort machinename | format-table -AutoSize |
Out-File "D:\Temp\Report.txt"
Looking at the screenshot, I can see the input csv is really a Comma Separated Values file. For these, you use the Import-Csv cmdlet to retrieve an array of computer names from the file.
$outputFile = "D:\temp\test.csv"
# make sure the field name matches what is in the CSV header
$Servers = (Import-Csv -Path "C:\temp\input.csv").ComputerName
$Log = foreach($Server in $Servers) {
# add a test to see if we can reach the server
if (Test-Connection -ComputerName $Server -Count 1 -Quiet -ErrorAction SilentlyContinue) {
Get-Service -Name *HRRA*, "SQL Server Reporting Services" -ComputerName $Server |
Select-Object #{Name = 'MachineName'; Expression = {$Server}},
#{Name = 'ServiceName'; Expression = {$_.Name}},
#{Name = 'Status'; Expression = {$_.Status}}
}
else {
Write-Warning "Server '$Server' is unreachable"
}
}
# if you want the log sorted, do
$Log = $Log | Sort-Object MachineName
# output on screen
$Log | Format-Table -AutoSize
# output to CSV file
$Log | Export-Csv -Path $outputFile -Force -NoTypeInformation
# mail the output csv file using Send-MailMessage
# collect the parameters in a hashtable
$mailParams = #{
SmtpServer = "AMRINT.SMTP.ACCENTURE.COM"
From = "Reporting.Services#accenture.com"
To = "aditi.m.singh#accenture.com"
Subject = "SSRS Services Status"
Body = "Please find attached - test"
BodyAsHtml = $true
Attachments = $outputFile
# add other parameters if needed
# see https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/send-mailmessage
}
# use 'splatting' to send the email
# see https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_splatting
Send-MailMessage #mailParams
P.S. The Format-Table cmdlet is for displaying the object(s) on screen only.

Having trouble writing Powershell output to csv file

I'm a PowerShell newbie trying to write a simple script to look up the number of times a specific user has logged into a workstation, and export that information in a useful way to a CSV file so it can be easily manipulated. The CSV file only really needs to contain the time of login and the username mentioned in the "Message" section of the Security log entry.
My problem is it seems I can either get a CSV file with a truncated "Message" no containing the username, or I get all the information I want printed to host instead of exporting to CSV. I'm sure the solution is probably very basic, but like I said I'm a newbie.
In the code posted here I get everything I need printed to host, but I can't seem to get it into a CSV file. Any help would be appreciated.
New-Item -Name "UserLoginHistory" -Path C:\ -ItemType Directory -Force | Out-Null
$UserName = Read-Host -Prompt 'Which user are you searching for?'
$a =Get-EventLog -LogName Security -Message "*$UserName*" | Where-Object {$_.EventID -eq 4624}
foreach($item in $a)
{
$timeLog = $item.TimeGenerated
$item = $item.Message.Split(":")
$subject = $item[3].split()
#$subject[2]
$NewLogin = $item[14].split()
#$NewLogin[2]
$WorkstationName = $item[26].split()
#$WorkstationName[1]
$SourceNetworkAddress = $item[27].split()
#$SourceNetworkAddress[1]
"Time: $timeLog Subject: $($subject[2]) NewLogin: $($NewLogin[2]) WorkstationName $($WorkstationName[1]) SourceNetworkAddress $($SourceNetworkAddress[1])"
}
Export-Csv -Path C:\UserLoginHistory\LoginHistory.csv
Don't reuse the variable $item of the foreach inside the {scrript block} for other purposes.
create a [PSCustomObject] and emit it to a gathering variable for the whole foreach
Untested template:
New-Item -Name "UserLoginHistory" -Path C:\ -ItemType Directory -Force | Out-Null
$UserName = Read-Host -Prompt 'Which user are you searching for?'
$Events = Get-EventLog -LogName Security -Message "*$UserName*" | Where-Object {$_.EventID -eq 4624}
$Data = foreach($Event in $Events){
$item = $Event.Message.Split(":")
[PSCustomObject]#{
Time = $Event.TimeGenerated
Subject = $item[3].split()[2]
NewLogin = $item[14].split()[2]
WorkstationName = $item[26].split()[1]
SourceNetworkAddress = $item[27].split()[1]
}
}
$Data | Format-Table -Autosize *
$Data | Out-Gridview
$Data | Export-Csv -Path C:\UserLoginHistory\LoginHistory.csv -NoTypeInformation
Try stuffing your results into an array like this untested code.
New-Item -Name "UserLoginHistory" -Path C:\ -ItemType Directory -Force | Out-Null
$UserName = Read-Host -Prompt 'Which user are you searching for?'
$a =Get-EventLog -LogName Security -Message "*$UserName*" | Where-Object {$_.EventID -eq 4624}
$ReportOutPut = #() # An array to hold your output.
foreach($item in $a)
{
$timeLog = $item.TimeGenerated
$item = $item.Message.Split(":")
$subject = $item[3].split()
#$subject[2]
$NewLogin = $item[14].split()
#$NewLogin[2]
$WorkstationName = $item[26].split()
#$WorkstationName[1]
$SourceNetworkAddress = $item[27].split()
#$SourceNetworkAddress[1]
"Time: $timeLog Subject: $($subject[2]) NewLogin: $($NewLogin[2]) WorkstationName $($WorkstationName[1]) SourceNetworkAddress $($SourceNetworkAddress[1])"
$ReportOutput += [pscustomobject] #{
Time = $timeLog;
Subject = $subject[2];
NewLogin = $NewLogin[2];
WorkstationName = $WorkstationName[1];
SourceNetworkAddress = $SourceNetworkAddress[1]
} # Custom objec to be exported via csv
}
Export-Csv -InputObject $ReportOutPut -NoTypeInformation -Path C:\UserLoginHistory\LoginHistory.csv

Unable to generate HTML table from Powershell function

I have got a powershell function that gets all errors and warnings from the event logs, counts the occurance of each Event ID and returns a Powershell table. THe code that does this is as follows -
function Get-EventLogs {
[System.Collections.ArrayList]$results = #()
#Do you want to enable transcript for logging all output to file?
$enableLogging = $FALSE
$ExportEnabled = $FALSE
# logging
# if you need detailed logging for troubleshooting this script, you can enable the transcript
# get the script location path and use it as default location for storing logs and results
$log = $MyInvocation.MyCommand.Definition -replace 'ps1','log'
$resultPath = $PSScriptRoot + '\'
Push-Location $resultPath
if ($enableLogging)
{
Start-Transcript -Path $log -ErrorAction SilentlyContinue
Write-Host "Logging enabled..."
Write-Host
Write-Host "Powershell version"
$PSVersionTable.PSVersion
$Host.Version
(Get-Host).Version
Write-host
}
$currentCulture = [System.Threading.Thread]::CurrentThread.CurrentCulture
# Configuration
# selected Event log sources
# limit the feedback only to the following logs
$EventLogList = 'System','Application'
#for FIM Health Check the Security log has less signification value and is skipped
#add it to the eventlog list when you need it
#,'Security'
# if the event logs are containing too much data,
#collect x years of logs
$startdate = ((Get-Date).AddDays(-7))
$Count = 0
$Activity = "Checking log properties"
$allEvents = New-Object System.Collections.Hashtable
$Count = 0
$Activity = "Checking log detaills"
foreach ($eventlog in $EventLogList)
{
#$Count += 1
$pct = ($Count / $EventLogList.Count * 100)
$status = $EventLog + " (" + $Count + "/" + $EventLogList.Count +")"
Write-Progress -Activity $Activity -Status $status -PercentComplete $pct
write-host $count"." $eventlog
[System.Threading.Thread]::CurrentThread.CurrentCulture = New-Object "System.Globalization.CultureInfo" "en-US"
# query the event log
# store the data in a hashtable, to avoid new queries
$allEvents = $Null
$allEvents = Get-WinEvent -FilterHashtable #{logname=$eventlog;StartTime=$startdate;level=0,1,2,3,4,5} -ErrorAction SilentlyContinue
#DEBUG if ($eventlog -eq "Application") { $allevents}
if ($allEvents.count -eq 0)
{
$message = "No events for " + $eventlog + "log since "+ $startdate + "."
Write-Host $message
Write-Host
# no data to process, skip processing for current loop
Continue
}
#For events detailed reporting we're only interested in error events
#not interested in informational events (level 0 and 4)
$evtStats = $allEvents | where -Property level -Notin -Value 0,4 | Group-Object id | Sort-Object Count -Descending
$allevents = $Null
#prep export
$exportfile = $resultPath + "_EventIDStats"+ $eventlog + ".csv.txt"
if ($exportEnabled) {$export | Export-Csv $exportfile -NoTypeInformation}
# evtStats has number and ID attribute
# other attributes must be added:
# - errortype name
# - Source
# - errortype name
# for each event id in the event statistics
# display the most recent event
$Activity = "Looking up last event occurrence..."
$i= 0
foreach ($item in $evtStats)
{
$i += 1
$pct = ($i / $evtStats.Count * 100)
$eventID = $item.Name
$status = "EventID: "+ $item.Name
Write-Progress -Activity $Activity -Status $status -PercentComplete $pct
$customobj = "" | select Count,ErrorID,ErrorType,Message
$customobj.Count = $item.Count
$customobj.ErrorID = $item.Name
#get most recent event from the eventID
$id = $item.Name.ToInt32($Null)
[System.Threading.Thread]::CurrentThread.CurrentCulture = New-Object "System.Globalization.CultureInfo" "en-US"
$lastevent = get-winevent -FilterHashtable #{LogName=$eventlog;Id=$id} -MaxEvents 1 -ErrorAction SilentlyContinue
#depending on local settings, query might fail, if it fails reset to local culture
if ($lastevent.LevelDisplayName.Length -eq 0)
{
[System.Threading.Thread]::CurrentThread.CurrentCulture = $currentCulture
$lastevent = get-winevent -FilterHashtable #{LogName=$eventlog;Id=$id} -MaxEvents 1
}
$customobj.ErrorType = $lastevent.LevelDisplayName
$customobj.Message = $lastevent.Message
#prep EventID export
$exportfile = $resultPath + $eventlog +'_EventID_' + $customobj.ErrorID + ".csv.txt"
if ($exportEnabled)
{
$customobj | Export-Csv $exportfile -NoTypeInformation
}
$results += $customobj
}
#display with format
$results | Format-Table -AutoSize
return ,$results
if ($exportEnabled)
{
$exportfile = $resultPath + "_lastEvents_short_" + $eventlog + ".txt"
$results| Format-Table -AutoSize | out-file $exportfile
$exportfile = $resultPath + "_lastEvents_detail_" + $eventlog + ".txt"
$results | out-file $exportfile
}
}
#Write-Output $results | Format-Table -AutoSize
}
I then need to format the output of this function as a HTML table, so I can show it in my report.
$elogs = (Get-EventLogs) | Out-String
The code above outputs it as a long string (to be expected). But I cannot figure out how to format it as a HTML table. THe code that finally generates the report is as follows -
$Report = ConvertTo-Html -Title "$Computername" `
-Head "<center><h1>Server Report for <br><br>$Computername</h1></center><br /><br />" `
-Body "$Heading $Hardware $elogs $PercentFree $Output $Restarted $Services $Stopped $Css" }
Is there a way to output this as a table?
ConvertTo-Html is able to take an object and render that object as a HTML table. For simplicity's sake, I'll include the -Fragment switch that will ONLY return a HTML table (not all the HTML header, etc.).
Take a simple object, such as some basic process data, and you can create a HTML table:
[PS] $p = Get-Process | Select -First 3 -Property Name,ID
[PS] $p | ConvertTo-Html -Fragment
<table>
<colgroup><col/><col/></colgroup>
<tr><th>Name</th><th>Id</th></tr>
<tr><td>Process1</td><td>1888</td></tr>
<tr><td>Process2</td><td>1536</td></tr>
<tr><td>Process3</td><td>13920</td></tr>
</table>
Note that we don't need to specify a -Body with all the variables; we just need to make sure that we have all the data collected in an object (with the appropriate property names) and the cmdlet does the rest.
Going back to your script, there are a few things to look at:
Don't use Write-Host. If you want debug messages, consider using Write-verbose and Write-Debug. You'll need to set the $VerbosePreference and $DebugPreference variables to "Continue" to make this output visible.
Similarly, avoid using Format-Table
Your script returns an object ,$results. You should be able to pipe this into ConvertTo-Html with additional header and body content.
Note finally that the -Body switch doesn't format your object; it just includes extra HTML in front of the HTML table.

Server reboot script with timed loop

I'm putting together a reboot script used for scheduling server reboots.
My goal is to improve functionality and error handling by using a loop with counter to break/exit the script if the server:
1) Does not restart. For example While (Test-path "\\$server\c$")
2) Does not come online. For example While (-not(Test-path "\\$server\c$"))
In addition, I'm trying to add logging to a CSV file if any of the above conditions are TRUE. Otherwise the script continues and creates the CSV with the previous reboot time stamp along with current reboot time stamp.
My current attempt does not seem to correctly exit the script and log the failure and honestly I'm a little unsure of how to test this before rebooting servers.
Param([Parameter(Mandatory=$true)][string]$server)
$ErrorActionPreference = "SilentlyContinue"
Try{
$LastReboot = Get-EventLog -ComputerName $server -LogName system | Where-Object {$_.EventID -eq '6005'} | Select -ExpandProperty TimeGenerated | select -first 1
(Invoke-WmiMethod -ComputerName $server -Path "Win32_Service.Name='HealthService'" -Name PauseService).ReturnValue | Out-Null
Restart-Computer -ComputerName $server -Force
#New loop with counter, exit script if server did not reboot.
$max = 20;$i = 0
DO{
IF($i -gt $max){
$hash = #{
"Server" = $server
"Status" = "FailedToReboot!"
"LastRebootTime" = $LastReboot
}
$newRow = New-Object PsObject -Property $hash
Export-Csv c:\Scripts\RebootCheck.csv -InputObject $newrow -Append -Force
;exit}#exit script and log failed to reboot.
$i++
"Wait for server to reboot"
Start-Sleep -Seconds 30
}#end DO
While (Test-path "\\$server\c$")
$max = 15;$i = 0
DO{
IF($i -gt $max){
$hash = #{
"Server" = $server
"Status" = "FailedToComeOnline!"
"LastRebootTime" = $LastReboot
}
$newRow = New-Object PsObject -Property $hash
Export-Csv c:\Scripts\RebootCheck.csv -InputObject $newrow -Append -Force
;exit}#exit script and log failed to reboot.
$i++
"Wait for [$server] to come online"
Start-Sleep -Seconds 30
}#end DO
While (-not(Test-path "\\$server\c$"))
$CurrentReboot = Get-EventLog -ComputerName $server -LogName system | Where-Object {$_.EventID -eq '6005'} | Select -ExpandProperty TimeGenerated | select -first 1
$hash = #{
"Server" = $server
"Status" = "RebootSuccessful"
"LastRebootTime" = $LastReboot
"CurrentRebootTime" = $CurrentReboot
}
$newRow = New-Object PsObject -Property $hash
Export-Csv c:\Scripts\RebootCheck.csv -InputObject $newrow -Append -Force
}#End Try.
Catch{
$errMsg = $_.Exception
"Failed with $errMsg"
}
In order to break out of a loop, use the break keyword, not return.
Assign $true to $test inside the if block immediately before break:
$test = false
while ($limit -lt $max){
Write-Host "Reboot Request Sent, waiting for server to reboot"
if(Test-Path \\Server1\C$){
Write-Host "Reboot Successful, continue script"
$test = $true
break
}
$limit++
Start-Sleep -Seconds 10
}
The switch statement you've shown is syntactically valid, but kinda weird, since it's the exact equivalent of a standard if/else:
if($test)
{
Write-Host "Reboot succeeded!"
}
else
{
Write-Host "Reboot failed!"
}
After trial and error I believe I have something working.
This example will exit the script after two seconds
#restart-computer $server
$max = 2;$i = 0
DO{
IF($i -gt $max){"Server failed to reboot!";exit}#exit script and log failed to reboot.
$i++
"Wait for server to reboot"
Start-Sleep -Seconds 1
}#end DO
While (Test-path "\\$server\c$")
"Server rebooted, continue script"