Powershell Review Script

Hi,

I've amended a script from here there and everywhere basically lol - I just been playing around and adding bits and testing but just want to see if anyone can recommend anything on the script i could change or improve on.

Any suggestions will be appreciated.

########################################################################################################################
# SMTP Settings - Config Part
########################################################################################################################
# Define settings objects (No need to touch these)

$smtp = New-Object -type PSObject -Property @{sender = $null;recipients = $null;server = $null;}
$settings = New-Object -TypeName PSObject -Property @{NumberEvents=$null;ProcessNumToFetch=$null}

# Script Options:
# How many recent event log events will we show?
$settings.NumberEvents = 3
# ProcessNumToFetch
$settings.ProcessNumToFetch = 3
                                            ########################################################################################################################
                                                        #      !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!ONLY CHANGE THESE SETTINGS!!!!!!!!!!!!!!!!!!!
                                            ########################################################################################################################

                                                                                                         $smtp.sender = "Server Health Reporting -  <>"
                                                                        $smtp.recipients = @("")
                                                                        $smtp.server = ""
                                            ########################################################################################################################

########################################################################################################################
# Import Exchange 2010 Cmdlets
########################################################################################################################
function LoadExchangeTools {

if (!(Get-pssnapin | ? {$_.name -like 'Microsoft.Exchange*'})) {
		$Reg = Get-PSSnapin -Registered | ? {$_.name -like 'Microsoft.Exchange*'}
		IF ($Reg | ? {$_.name -like '*e2010'}){
			Add-PSSnapin Microsoft.Exchange.Management.PowerShell.e2010
			}
		ElseIf($Reg | ? {$_.name -like '*Admin'}){
			Add-PSSnapin Microsoft.Exchange.Management.PowerShell.Admin
		}
	}
Else{
		"Exchange modules not found"
	}
}

LoadExchangeTools
########################################################################################################################
# Begin Header Report
########################################################################################################################

$ListOfAttachments = @()
$Report = @()
$CurrentTime = Get-Date


# Assemble the HTML Header and CSS for our Report
$HTMLHeader = @"
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">
<html><head><title>My Systems Report</title>
<style type="text/css">
<!--
body {
font-family : Tahoma;
}
#report {
width : 900px;
}
table {
border-collapse : collapse;
border : none;
font : 10pt Tahoma;
color : black;
margin-bottom : 10px;
}
table td {
font-size : 10px;
padding-left : 0;
padding-right : 20px;
text-align : center;
border-top : 1.2px solid #aabcfe;
border-bottom : 2px solid #aabcfe;
color : black;
}
table th {
font-size : 10px;
font-weight : bold;
background : #b9c9fe;
padding-left : 0;
padding-right : 20px;
text-align : center;
color : #039;
}
#container {
position : relative;
}
#left {
width : 50%;
top : 0;
left : 0;
bottom : 0;
}
#right {
position : absolute;
top : 0;
right : 0;
bottom : 0;
width : 50%;
}
h2 {
clear : both;
font-size : 130%;
font-family : Tahoma;
color : #039;
text-align : center;
}
h3 {
clear : both;
font-size : 115%;
margin-left : 20px;
margin-top : 30px;
border-bottom : 1px solid #fff;
color : black;
}
p {
margin-left : 20px;
font-size : 12px;
border-bottom : 1px solid #fff;
color : black;
}
table.list td:nth-child(1) {
font-weight : bold;
border-right : 1px solid grey;
text-align : center;
}
-->
</style>
</head>
<body>

"@


########################################################################################################################
# WMI Queries
########################################################################################################################

$DiskSpace = Get-WmiObject Win32_LogicalDisk -filter "DriveType=3" | Select SystemName,DeviceID,VolumeName,@{Name="Size (GB)";Expression={"{0:N1}" -f($_.size/1gb)}},@{Name="Free Space (GB)";Expression={"{0:N1}" -f($_.freespace/1gb)}},@{Name="Free Space (%)";Expression={"{0:P2}" -f(($_.freespace/1gb) / ($_.size/1gb))}} | ConvertTo-Html -Fragment
            
$OS = (Get-WmiObject Win32_OperatingSystem | Select @{name="OSDescription";Expression={$_.Caption + " (" + $_.Version + ")"}}).OSDescription

$SystemInfo = Get-WmiObject -Class Win32_OperatingSystem | Select-Object Name, TotalVisibleMemorySize, FreePhysicalMemory



########################################################################################################################
# Report System Memory
########################################################################################################################

$TotalRAM = $SystemInfo.TotalVisibleMemorySize/1MB
$FreeRAM = $SystemInfo.FreePhysicalMemory/1MB
$UsedRAM = $TotalRAM - $FreeRAM
$TotalRAM = [Math]::Round($TotalRAM, 2)
$FreeRAM = [Math]::Round($FreeRAM, 2)
$UsedRAM = [Math]::Round($UsedRAM, 2)

$TopProcesses = Get-Process | Sort WS -Descending | Select ProcessName, Id, @{label="WS (MB)";expression={[int]($_.WS/1mb)}} -First $Settings.ProcessNumToFetch | ConvertTo-Html -Fragment

########################################################################################################################
# Report Services That Are Stopped
########################################################################################################################

$ServicesReport = @()
foreach ($Service in $(Get-WmiObject -Class Win32_Service | Where {($_.StartMode -eq "Auto") -and ($_.State -eq "Stopped")})) {
	$row = New-Object -Type PSObject -Property @{
	   	Name = $Service.Name
		Status = $Service.State
		StartMode = $Service.StartMode
	}
$ServicesReport += $row
}

$ServicesReport = $ServicesReport | ConvertTo-Html -Fragment


########################################################################################################################
# Symantec BackupExec Report
########################################################################################################################

$BackupReport = @()
$BackupEvent = Get-EventLog -LogName Application -Newest 3 | Where-Object {$_.EventID -eq 57755 -or $_.EventID -eq 34114 -or $_.EventID -eq 34112}
foreach ($event in $BackupEvent) {
	$row = New-Object -Type PSObject -Property @{
		TimeGenerated = $event.TimeGenerated
		EntryType = $event.EntryType
		Source = $event.Source
		Message = $event.Message
	}
	$BackupReport += $row
}

$BackupReport = $BackupReport | ConvertTo-Html -Fragment

########################################################################################################################
# Exchange 2010 Report - Top 5 Mailboxes (GB In Size)
########################################################################################################################

$ExchangeReport = @()
$ExchangeEvent = Get-Mailbox -ResultSize Unlimited | Get-MailboxStatistics | Sort-Object TotalItemSize -Descending | Select-Object DisplayName,TotalItemSize -First 5
foreach ($event in $ExchangeEvent) {
	$row = New-Object -Type PSObject -Property @{
		DisplayName = $event.DisplayName
		TotalItemSize = $event.TotalItemSize
	}
	$ExchangeReport += $row
}

$ExchangeReport = $ExchangeReport | ConvertTo-Html -Fragment

########################################################################################################################
# Temperature Sensor
########################################################################################################################

$TemperatureReport = @()
$TemperatureEvent = gwmi -Namespace root\hpq -Class HP_NumericSensor | ForEach {
    $sensor = $_
    Switch ($_.Name) {
        "Temperature Sensor 1" {
       $row = New-Object PSObject -Property @{
                Sensor = "Ambient"
                Temperature = $sensor.CurrentReading
            }
        $TemperatureReport += $row
        }
        "Temperature Sensor 2" {
        $row = New-Object PSObject -Property @{
                Sensor = "CPU"
                Temperature = $sensor.CurrentReading
            }
        $TemperatureReport += $row
        }
    }
}

$TemperatureReport = $TemperatureReport | ConvertTo-Html -Fragment
	
########################################################################################################################
# RAID Report
########################################################################################################################
$RAIDReport = @()
$RAIDEvent = gwmi -Namespace root\hpq -Class HPSA_StorageExtent | Select-Object ElementName,@{N="OperationalStatus";E={$_.OperationalStatus}}
foreach ($event in $RAIDEvent) {
	$row = New-Object -Type PSObject -Property @{
		ElementName = $Event.ElementName
		OperationalStatus = Switch ($Event.OperationalStatus){"2"{"OK"};"3"{"NotOK"};"4"{"Warning"}}
	}
	$RAIDReport += $row
}

$RAIDReport = $RAIDReport | ConvertTo-html -Fragment

########################################################################################################################
# Uptime of PC
########################################################################################################################

$Uptime = Get-WmiObject -Class Win32_OperatingSystem
$LastBootUpTime = $Uptime.ConvertToDateTime($Uptime.LastBootUpTime)
$Time = (Get-Date) - $LastBootUpTime
$SystemUptime = '{0:00} Days, {1:00} Hours, {2:00} Minutes, {3:00} Seconds' -f $Time.Days, $Time.Hours, $Time.Minutes, $Time.Seconds

########################################################################################################################
# Add the current System HTML Report into the final HTML Report body
########################################################################################################################

$HTMLMiddle = @"

	<div id="report">
	<h2>$($env:computername) Report</h2>
	<h3>General System Info</h3>
	<table class="list">
	<tr>
	<th>System Uptime</th>
	<td>$SystemUptime</td>
	</tr>
	<tr>
	<th>OS</th>
	<td>$OS</td>
	</tr>
	<tr>
	<th>Total RAM (GB)</th>
	<td>$TotalRAM</td>
	</tr>
	<tr>
	<th>Free RAM (GB)</th>
	<td>$FreeRAM</td>
	</tr>
	</table>
	</div>
	

    <h3>Disk Space</h3>
    <table class="normal">$DiskSpace</table>

<div id="container">
<div id="left">
	<h3>System Processes - Top $ProccessNumToFetch Highest Memory Usage</h3>
	<table class="normal">$TopProcesses</table>
</div>

<div id="right">
	<h3>System Services - Automatic Startup but not Running</h3>
	<table class="normal">
	$ServicesReport
	</table>
</div>
</div>


    <h3>Top 5 Largest Mailboxes</h3>
    <p> Exchange 2010 Mailboxes - Top 5 Largest Mailboxes </p>
    <table class="normal">
    $ExchangeReport
	</table>


    <h2>Backup Report</h2>
    <table=class"normal">$BackupReport</table>	


<H3>RAID Report</H3>
<table class="normal">$RAIDReport</table>

<H3>Temperature Sensor</H3>
<table class="normal">$TemperatureReport</table>

"@

########################################################################################################################
# Assemble the closing HTML for our report.
########################################################################################################################

$HTMLEnd = @"
</div>
</body>
</html>
"@

########################################################################################################################
# Send Email + Out Report.html 
########################################################################################################################


# Assemble the final report from all our HTML sections
$HTMLmessage = $HTMLHeader + $HTMLMiddle + $HTMLEnd
# Save the report out to a file in the current path
$HTMLmessage | Out-File ((Get-Location).Path + "\report.html")
# Email our report out
send-mailmessage -from $smtp.sender -to $smtp.recipients -subject "Systems Report" -BodyAsHTML -body $HTMLmessage -priority Normal -smtpServer $smtp.server

Open in new window

LVL 1
Alex YoungAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

footechCommented:
Glad to see you using Here-strings for the headers!  I think that's much better than 147 Add-Content commands.  :)
I'm not really seeing anything that would make a huge difference, but there are some minor points that might help.
 - I almost always think of a query as taking longer than building an object (though I'm sure someone could point out an exception to this).  Because of this, if I have to make a query like gwmi win32_operatingsystem I believe it's quicker to store the results of this query to a variable and then construct objects from that variable, than it is to perform the query multiple times and each time storing a specific property to a variable.  So on that basis you could store the results of gwmi win32_operatingsystem to a variable, then modify lines 145, 147, 261 to derive from that.
 - I think you could optimize a bit in each of your foreach statements by not using the $row variable but instead adding the results directly to the output variable.  For example
$ServicesReport = @()
foreach ($Service in $(Get-WmiObject -Class Win32_Service | Where {($_.StartMode -eq "Auto") -and ($_.State -eq "Stopped")})) {
	$ServicesReport += New-Object -Type PSObject -Property @{
	   	Name = $Service.Name
		Status = $Service.State
		StartMode = $Service.StartMode
	}
}

Open in new window

- Lastly, assuming you followed the advice in my first point (storing the results to a variable named OSInfo), you could then modify the code for line 263 (261 and 262 wouldn't be needed) to:
$Time = $CurrentTime - $OSInfo.ConvertToDateTime($OSInfo.LastBootUpTime)

Open in new window

It doesn't get much more minor than that!  :)
0
Alex YoungAuthor Commented:
The only thing I would like to improve on is formatting on the email cause Instead of a big list on a email I would like to move the reports side by side - works on HTML but dunno about email
0
SubsunCommented:
As footech said the changes may not make a huge difference as you are running script against single computer..

You can avoid some foreach loops and use pipeline to save data to variable..
For example.. $ServicesReport can be
$ServicesReport = Get-WmiObject -Class Win32_Service | 
Where {($_.StartMode -eq "Auto") -and ($_.State -eq "Stopped")} |
Select Name,StartMode,State | ConvertTo-Html -Fragment

Open in new window

Similarly you can convert $BackupReport, $RAIDReport etc..
0
Webinar: Miercom Evaluates Wi-Fi Security

It's not just about Wi-Fi connectivity anymore. A wireless security breach can cost your business large amounts of time, trouble, and expense. Plus, hear first-hand from Miercom how WatchGuard's Wi-Fi security stacks up against the competition in our upcoming webinar!

footechCommented:
Not sure I know exactly what you're picturing for the formatting, but for email (especially if you want it to look correct in Outlook) your options are pretty much limited by the use of tables.  So if you can work out the placement of inner and outer tables you might be able to do what you want.  One thing I remember is that Outlook doesn't support divs.  It's been a couple of years now since I last had to compose an HTML email report like that so probably couldn't give you any more details.  Back then I remember finding sites that listed what HTML was supported by Outlook.
0
Alex YoungAuthor Commented:
Ah ok yh and there's me trying divs lol - it's not a problem just wanted shorter page of email
0
footechCommented:
If I remember right I tried the same thing and wondered why my email didn't look at all like my WYSIWYG.  It may actually support divs in some fashion, just not the properties that I cared about.  I find it ridiculous that Outlook/Word's HTML and CSS support has hardly changed since 2007 was released.
0
Alex YoungAuthor Commented:
Yh I know it does suck lol - has anyone good ideas I know it's ambitious but this is obviously coming into a mailbox yeh but to read all the emails in the mailbox and put the data from all these servers into a single database or something. It's something that is a bit of a big project or might not be.

So...

Server A (Client A)
Server B (Client B)

Sends email report 9am to monitoring mailbox

A script runs to collect these emails and puts the info into a database or just puts it into a HTML file.

Does that make sense? Let me know if you think I'm being crazy but be cool to get done and learn
0
footechCommented:
I'm sure that you could take all the data and pipe it into a database, but to do that I would treat that as a completely separate task from sending an email, meaning I would never try to take the results from an email message (or messages) and then try to reconstitute it into a form to put back in a database.  Better to work straight from the source, though I suppose you could use .CSV files as intermediates, such that you would use the data in the .CSV to populate both the email and database.  But this isn't something I would care to attempt here as I've never worked with databases and PowerShell.
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Powershell

From novice to tech pro — start learning today.