ความสนุกวันศุกร์: สร้างหน้าต่างติดตาม PowerShell
การใช้วัตถุ COM คุณสามารถสร้างอินสแตนซ์ของ Internet Explorer จากนั้นใช้วิธีการและคุณสมบัติ DOM เพื่อกำหนดค่าหน้าต่างและเขียนข้อความลงไป นี่คือเวอร์ชัน PowerShell ของสิ่งที่ฉันเคยทำใน VBScript
#requires -version 2.0
Function Trace-Message {
<#
.Synopsis
Display script trace messages
.Description
This command will launch an instance of Internet Explorer and display user
defined trace messages. The trace message will automatically include a time
stamp. After your script has completed, the window will remain open until you
manually close it. If you use this command in the PowerShell ISE, you can use
the -Terminate parameter to close it and clean up the COM object.
The function has parameters to adjust the positioning, size and format of the
Internet Explorer window. You can't change the position or window size once the
window is first created, although you can manually reposition and resize. But
it is possible to specify different values for these settings on a per message
basis:
Title
Background Color
Font
FontSize
The beginning of every trace window will include information about the user and
computer running the script. This can be useful when troubleshooting a script
that someone else is running.
IMPORTANT: The trace window will only be created if the function detects a
variable in the current scope, usually the script, called TraceEnabled with a
value of $True. This means your script can have trace commands but they won't
do anything unless $TraceEnabled is set to $True.
.Notes
Last Updated: October 30, 2013
Version : 0.9
.Link
Friday Fun: Create a PowerShell Trace Window
#>
[cmdletbinding(DefaultParameterSetName="Trace")]
Param (
[Parameter(Position=0,Mandatory=$True,HelpMessage="Enter a trace message",
ParameterSetName="Trace")]
[string]$Message,
[Parameter(ParameterSetName="Trace")]
[int]$Top=10,
[Parameter(ParameterSetName="Trace")]
[int]$Left=10,
[Parameter(ParameterSetName="Trace")]
[int]$Width=600,
[Parameter(ParameterSetName="Trace")]
[int]$Height=600,
[Parameter(ParameterSetName="Trace")]
[string]$BGColor="#ffff00",
[Parameter(ParameterSetName="Trace")]
[string]$Title="Trace Messages",
[Parameter(ParameterSetName="Trace")]
[string]$Font="Verdana",
[Parameter(ParameterSetName="Trace")]
[int]$FontSize=2,
[Parameter(ParameterSetName="Kill")]
[alias("kill")]
[switch]$Terminate
)
if ($Terminate) {
$script:IEWindow.Quit()
if ($IEWindow) {
Remove-Variable -name IEWindow -Scope Script
}
return
}
#only run if $TraceEnabled is True
if ($script:TraceEnabled) {
#if there isn't an IE window object, create it
If (-NOT $script:IEWindow) {
$script:IEWindow = New-Object -ComObject "InternetExplorer.Application"
$script:IEWindow.navigate("about:blank")
$script:IEWindow.ToolBar = $False
$script:IEWindow.AddressBar = $False
$script:IEWindow.Top = $Top
$script:IEWindow.Left = $Left
$script:IEWindow.Width = $Width
$script:IEWindow.Height = $Height
$script:IEWindow.Visible = $True
$script:IEWindow.menubar = $False
$script:IEWindow.StatusBar = $False
$script:IEWindow.Document.IHTMLDocument2_Title = $Title
$script:IEWindow.document.IHTMLDocument2_bgColor= $BGColor
#include some default information
$script:IEWindow.Document.IHTMLDocument2_writeln("<font face=$Font size=$FontSize> $(Get-Date) - User: $($env:USERDOMAIN)\$($env:USERName) <br>")
$elevated = ([security.principal.windowsprincipal]([security.principal.windowsidentity]::Getcurrent())).IsInRole([system.security.principal.securityidentifier]"S-1-5-32-544")
$script:IEWindow.Document.IHTMLDocument2_writeln("<font face=$Font size=$FontSize> $(Get-Date) - Elevated: $Elevated <br>")
$script:IEWindow.Document.IHTMLDocument2_writeln("<font face=$Font size=$FontSize> $(Get-Date) - Computer: $env:Computername <br>")
$os = Get-WmiObject win32_operatingsystem
$script:IEWindow.Document.IHTMLDocument2_writeln("<font face=$Font size=$FontSize> $(Get-Date) - OS: $($os.caption) <br>")
$script:IEWindow.Document.IHTMLDocument2_writeln("<font face=$Font size=$FontSize> $(Get-Date) - Ver.: $($os.version) <br>")
$script:IEWindow.Document.IHTMLDocument2_writeln("<font face=$Font size=$FontSize> $(Get-Date) - Service Pack: $($os.ServicePackMajorVersion).$($os.ServicePackMinorVersion) <br>")
$script:IEWindow.Document.IHTMLDocument2_writeln("<font face=$Font size=$FontSize> $(Get-Date) - Architecture: $($os.OSArchitecture) <br>")
$script:IEWindow.Document.IHTMLDocument2_writeln("<font face=$Font size=$FontSize> $(Get-Date) - ******************************<br>")
}
#write the message to the window
$script:IEWindow.Document.IHTMLDocument2_writeln("<font face=$Font size=$FontSize> $(Get-Date) - $Message <br>")
$script:IEWindow.Document.IHTMLDocument2_Title = $Title
$script:IEWindow.document.IHTMLDocument2_bgColor= $BGColor
} #if $TraceEnabled
} #close Trace-Message function
Set-Alias -Name Trace -Value Trace-Messageฟังก์ชันนี้เขียนโดยสมมุติว่าคุณจะใช้ฟังก์ชันนี้ภายในสคริปต์ ฉันจะมีตัวอย่างในอีกสักครู่ ขั้นแรกฟังก์ชันจะตรวจสอบตัวแปร ซึ่งน่าจะอยู่ในขอบเขตสคริปต์ที่เรียกว่า TraceEnabled หากตั้งค่าเป็น True ฟังก์ชันจะดำเนินต่อไป จากนั้นจะตรวจสอบว่าหน้าต่างการติดตามที่มีอยู่ได้ถูกสร้างขึ้นแล้วหรือไม่ ถ้าไม่เช่นนั้น ระบบจะสร้างมันขึ้นมาโดยใช้คุณสมบัติเริ่มต้นบางอย่างสำหรับขนาด ตำแหน่ง และสี ซึ่งทั้งหมดนี้คุณสามารถเปลี่ยนแปลงได้ผ่านพารามิเตอร์ เมื่อสร้างหน้าต่างแล้ว สตริงข้อความของคุณจะถูกเขียนลงในหน้าต่าง Internet Explorer ฉันใส่วันที่และเวลาปัจจุบันไว้หน้าข้อความ ฉันยังรวมข้อมูลผู้ใช้และระบบเริ่มต้นไว้ด้วยเมื่อสร้างหน้าต่าง IE เป็นครั้งแรก ในอดีตสิ่งนี้มักจะมีประโยชน์ โดยเฉพาะอย่างยิ่งเมื่อต้องรับมือกับผู้ใช้ที่ไม่เชี่ยวชาญด้านเทคโนโลยี
เมื่อคุณรวมฟังก์ชันนี้ไว้ในสคริปต์ ทุกอย่างควรได้รับการล้างข้อมูลเมื่อคุณปิดหน้าต่าง หน้าต่าง IE จะยังคงอยู่แม้ว่าสคริปต์จะสิ้นสุดแล้วก็ตาม สิ่งนี้มีประโยชน์เพราะคุณสามารถพิมพ์จากมัน คัดลอกและวางหรืออะไรก็ได้ หากคุณเรียกใช้สคริปต์จาก PowerShell ISE สิ่งต่างๆ อาจไม่ได้รับการทำความสะอาดอย่างดีเสมอไป ดังนั้นฉันจึงเพิ่มพารามิเตอร์ -Terminate (ด้วยนามแฝงว่า -Kill) เมื่อคุณใช้สิ่งนี้ใน ISE ให้รัน Trace -Kill เพื่อปิดหน้าต่างและล้างข้อมูล
แล้วคุณจะใช้สิ่งนี้อย่างไร?
นี่คือเวอร์ชันของสคริปต์ (ซึ่งฉันไม่คิดว่าจะเผยแพร่มาก่อน ดังนั้นคุณจะได้รับโบนัสในวันนี้) ที่จะรับข้อมูลสุขภาพเซิร์ฟเวอร์พื้นฐานและสร้างรายงาน HTML
#requires -version 3.0
<#
ServerHealth.ps1
A script to do a quick health check and create an HTML report.
This version includes my trace function.
****************************************************************
* DO NOT USE IN A PRODUCTION ENVIRONMENT UNTIL YOU HAVE TESTED *
* THOROUGHLY IN A LAB ENVIRONMENT. USE AT YOUR OWN RISK. IF *
* YOU DO NOT UNDERSTAND WHAT THIS SCRIPT DOES OR HOW IT WORKS, *
* DO NOT USE IT OUTSIDE OF A SECURE, TEST SETTING. *
****************************************************************
#>
[cmdletbinding()]
Param(
[Parameter(Position=0,HelpMessage="Enter the computer name for the report")]
[ValidateNotNullorEmpty()]
[Alias("name","cn")]
[string]$Computername=$env:computername,
[Parameter(Position=1,HelpMessage="Enter the path for the html report")]
[ValidateNotNullorEmpty()]
[string]$Path="ServerHealth.htm",
[Alias("RunAs")]
[System.Management.Automation.Credential()]$Credential = [System.Management.Automation.PSCredential]::Empty,
[switch]$Trace
)
#dot source the Trace function
. C:\scripts\Trace.ps1
if ($trace) {
$script:TraceEnabled = $True
}
# !!!!!!
#dot source the Trace function
. C:\scripts\Trace.ps1
if ($trace) {
#set the variable to turn tracing on
$script:TraceEnabled = $True
}
#!!!!!!!
#the trace commands will only work if $TraceEnabled = $True
Trace "Starting $($MyInvocation.MyCommand)"
Write-Verbose "Starting $($MyInvocation.MyCommand)"
#initialize an array for HTML fragments
Trace "initializing fragments"
$fragments=@()
$ReportTitle = "Server Health Report: $($Computername.toUpper())"
Trace $ReportTitle
Trace "Defining head"
#this must be left justified
$head = @"
<Title>$ReportTitle</Title>
<style>
body { background-color:#FFFFFF;
font-family:Tahoma;
font-size:12pt; }
td, th { border:1px solid black;
border-collapse:collapse; }
th { color:white;
background-color:black; }
table, tr, td, th { padding: 2px; margin: 0px }
tr:nth-child(odd) {background-color: lightgray}
table { width:95%;margin-left:5px; margin-bottom:20px;}
.alert {background-color: red ! important}
.warn {background-color: yellow ! important}
</style>
<br>
<H1>$ReportTitle</H1>
"@
#build a hashtable of parameters for New-CimSession
$cimParams=@{
ErrorAction="Stop"
ErrorVariable="myErr"
Computername=$Computername
}
Trace "Reporting on computer $Computername"
if ($credential.username) {
Write-Verbose "Adding a PSCredential for $($Credential.username)"
Trace "Adding a PSCredential for $($Credential.username)"
$cimParams.Add("Credential",$Credential)
}
Try {
#verify if computer is running PowerShell 2 or 3
Write-Verbose "Test-WSMan $Computername"
Trace "Test-WSMan $Computername"
$wsman = Test-WSMan -ComputerName $Computername -ErrorAction Stop -ErrorVariable myErr
Trace ($wsman | out-string)
}
Catch {
Write-Warning "Failed to test WSMan for $Computername"
Write-Warning $myErr.ErrorRecord
Trace "Oops"
Trace "Failed to test WSMan for $Computername"
Trace "Breaking out"
Break
}
if ([int]($wsman.ProductVersion.Substring(25)) -lt 3) {
#running less than PowerShell 3 so create a DCOM option
Write-Verbose "$Computername running PowerShell 2.0"
Trace "$Computername running PowerShell 2.0"
Trace "Creating new CimSessionOption"
$cimOption = New-CimSessionOption -Protocol Dcom
$cimParams.Add("SessionOption",$cimOption)
}
#create a CIM Session
Write-Verbose "Creating a CIM Session"
Trace "Creating a CIM Session"
Try {
$cs = New-CimSession @cimParams
}
Catch {
Write-Warning "Failed to create CIM session for $Computername"
Write-Warning $myErr.ErrorRecord
Trace "Oops"
Trace "Failed to create CIM session for $Computername"
Trace "Breaking"
Break
}
#get OS data and uptime
Write-Verbose "Getting OS and uptime"
Trace "Getting OS and uptime"
$os = $cs | Get-CimInstance -ClassName Win32_OperatingSystem
$fragments+="<h2>Operating System</h2>"
Trace "Converting OS data to HTML fragment"
$fragments+= $os | select @{Name="Computername";Expression={$_.CSName}},
@{Name="Operating System";Expression={$_.Caption}},
@{Name="Service Pack";Expression={$_.CSDVersion}},LastBootUpTime,
@{Name="Uptime";Expression={(Get-Date) - $_.LastBootUpTime}} |
ConvertTo-HTML -Fragment
Write-Verbose "Getting memory usage"
Trace "Converting memory usage to HTML fragment"
$fragments+="<h2>Memory Usage</h2>"
[xml]$html= $os |
Select @{Name="TotalMemoryMB";Expression={[int]($_.TotalVisibleMemorySize/1mb)}},
@{Name="FreeMemoryMB";Expression={[math]::Round($_.FreePhysicalMemory/1MB,2)}},
@{Name="PercentFreeMemory";Expression={[math]::Round(($_.FreePhysicalMemory/$_.TotalVisibleMemorySize)*100,2)}},
@{Name="TotalVirtualMemoryMB";Expression={[int]($_.TotalVirtualMemorySize/1mb)}},
@{Name="FreeVirtualMemoryMB";Expression={[math]::Round($_.FreeVirtualMemory/1MB,2)}},
@{Name="PercentFreeVirtualMemory";Expression={[math]::Round(($_.FreeVirtualMemory/$_.TotalVirtualMemorySize)*100,2)}} |
ConvertTo-Html -Fragment
#parse html to add color attributes
Trace "Parsing memory fragment"
for ($i=1;$i -le $html.table.tr.count-1;$i++) {
$class = $html.CreateAttribute("class")
#check the value of the percent free memory column and assign a class to the row
if (($html.table.tr[$i].td[2] -as [double]) -le 10) {
$class.value = "alert"
$html.table.tr[$i].ChildNodes[2].Attributes.Append($class) | Out-Null
}
elseif (($html.table.tr[$i].td[2] -as [double]) -le 20) {
$class.value = "warn"
$html.table.tr[$i].ChildNodes[2].Attributes.Append($class) | Out-Null
}
}
#add the new HTML to the fragment
Trace "adding fragment"
$fragments+= $html.innerXML
#get disk drive status
Write-Verbose "Getting drive status"
Trace "Getting drive status"
$drives = $cs | Get-CimInstance -ClassName Win32_Logicaldisk -filter "DriveType=3"
$fragments+="<h2>Disk Usage</h2>"
Trace "Converting disk usage to HTML fragment"
[xml]$html= $drives | Select DeviceID,
@{Name="SizeGB";Expression={[int]($_.Size/1GB)}},
@{Name="FreeGB";Expression={[math]::Round($_.Freespace/1GB,4)}},
@{Name="PercentFree";Expression={[math]::Round(($_.freespace/$_.size)*100,2)}} |
ConvertTo-Html -Fragment
#parse html to add color attributes
Trace "Parsing memory fragment"
for ($i=1;$i -le $html.table.tr.count-1;$i++) {
$class = $html.CreateAttribute("class")
#check the value of the percent free column and assign a class to the row
if (($html.table.tr[$i].td[3] -as [double]) -le 10) {
$class.value = "alert"
$html.table.tr[$i].ChildNodes[3].Attributes.Append($class) | Out-Null
}
elseif (($html.table.tr[$i].td[3] -as [double]) -le 20) {
$class.value = "warn"
$html.table.tr[$i].ChildNodes[3].Attributes.Append($class) | Out-Null
}
}
Trace "adding disk fragment"
$fragments+=$html.InnerXml
Clear-Variable html
#get recent errors and warning in all logs
Write-Verbose "Getting recent eventlog errors and warnings"
Trace "Getting recent eventlog errors and warnings"
#any errors or audit failures in the last 24 hours will be displayed in red
#warnings in last 24 hours will be displayed in yellow
$Yesterday = (Get-Date).Date.AddDays(-1)
Trace "Yesterday is $yesterday"
$after = [System.Management.ManagementDateTimeConverter]::ToDmtfDateTime($yesterday)
Trace "Converted $yesterday to $after"
#get all event logs with entries
Trace "get all event logs with entries"
$logs = $cs | Get-CimInstance win32_ntEventlogFile -filter "NumberOfRecords > 0"
#exclude security log
$fragments+="<h2>Event Logs</h2>"
#process security event log for Audit Failures
$fragments+="<h3>Security</h3>"
Trace "Getting security event log data and converting to HTML fragment"
[xml]$html = $cs |
Get-CimInstance Win32_NTLogEvent -filter "Logfile = 'Security' AND Type = 'FailureAudit' AND TimeGenerated >= ""$after""" |
Select -property TimeGenerated,Type,EventCode,SourceName,Message |
ConvertTo-Html -Fragment
Trace "Parsing event log fragment"
if ($html.table) {
#if a failure in the last day, display in red
if (($html.table.tr[$i].td[1] -eq 'FailureAudit') -AND ([datetime]($html.table.tr[$i].td[0]) -gt $yesterday)) {
$class.value = "alert"
$html.table.tr[$i].Attributes.Append($class) | Out-Null
}
Trace "Adding event log fragment"
$fragments+=$html.InnerXml
}
Else {
#no recent audit failures
Write-Verbose "No recent audit failures"
$fragments+="<p style='color:green;'>No recent audit failures</p>"
}
Clear-Variable html
Trace "Getting all other event logs"
foreach ($log in ($logs | where logfilename -ne 'Security')) {
Write-Verbose "Processing event log $($log.LogfileName)"
$fragments+="<h3>$($log.LogfileName)</h3>"
Trace "Converting event log data to HTML fragment"
[xml]$html = $cs |
Get-CimInstance Win32_NTLogEvent -filter "Logfile = ""$($log.logfilename)"" AND Type <> 'Information' AND TimeGenerated >= ""$after""" |
Select -property TimeGenerated,Type,EventCode,SourceName,Message |
ConvertTo-Html -Fragment
Trace "Parsing fragment"
if ($html.table) {
#color errors in red
for ($i=1;$i -le $html.table.tr.count-1;$i++) {
$class = $html.CreateAttribute("class")
#check the value of the entry type column and assign a class to the row if within the last day
if (($html.table.tr[$i].td[1] -eq 'Error') -AND ([datetime]($html.table.tr[$i].td[0]) -gt $yesterday)) {
$class.value = "alert"
$html.table.tr[$i].Attributes.Append($class) | Out-Null
}
elseif (($html.table.tr[$i].td[1] -eq 'Warning') -AND ([datetime]($html.table.tr[$i].td[0]) -gt $yesterday)) {
$class.value = "warn"
$html.table.tr[$i].Attributes.Append($class) | Out-Null
}
} #for
$fragments+=$html.InnerXml
}
else {
#no errors or warnings
Write-Verbose "No recent errors or warnings for $($log.logfilename)"
Trace "No recent errors or warnings for $($log.logfilename)"
$fragments+="<p style='color:green;'>No recent errors or warnings</p>"
}
Clear-Variable html
} #foreach
#get services that should be running but aren't
Write-Verbose "Getting services that should be running but aren't"
Trace "Getting services that should be running but aren't"
$services = $cs | Get-CimInstance -ClassName win32_service -filter "startmode='Auto' AND state <> 'Running'"
$fragments+="<h2>Services</h2>"
Trace "Converting service data to HTML fragment"
$fragments+= $services | Select Name,Displayname,Description,State |
ConvertTo-Html -Fragment
$fragments+="<br><i>Created $(Get-Date)</i>"
#create the HTML report
Write-Verbose "Creating an HTML report"
Trace "Creating an HTML report"
Trace "Writing to $path"
ConvertTo-Html -Head $head -Title $reportTitle -body $Fragments | Out-File -FilePath $path -Encoding ascii
Trace (get-item $path | out-string)
Write-Verbose "Saving the HTML report to $Path"
Write-Verbose "Ending $($MyInvocation.MyCommand)"
Trace "Ending $($MyInvocation.MyCommand)"
Write-Host "Report saved to $path" -ForegroundColor Greenเมื่อคุณดูสิ่งนี้ คุณจะเห็นคำสั่งติดตามจำนวนหนึ่ง สคริปต์การติดตามซึ่งมีที่มาแบบจุดในสคริปต์นี้ จะสร้างนามแฝงของการติดตาม คำสั่งเหล่านี้จะไม่ทำอะไรนอกจาก $TraceEnabled จะตั้งค่าเป็น $True สคริปต์เวอร์ชันนี้มีสวิตช์ -Trace ซึ่งทำหน้าที่ดังกล่าว จากนั้นสคริปต์จะทำงานและข้อความติดตามทั้งหมดของฉันถูกเขียนไปยังหน้าต่าง IE
S:\ServerHealth-Trace.ps1 -Computername CHI-HVR2.GLOBOMANTICS.LOCAL -Credential globomantics\administrator -Trace -Path c:\work\hvr2-health.htmหากมีปัญหา ฉันสามารถดูว่าสคริปต์เสียหายหรือล้มเหลวตรงไหน หากทุกอย่างเป็นไปด้วยดี ฉันจะได้รายงานดังนี้:
สคริปต์สถานภาพเซิร์ฟเวอร์รับข้อมูลบางอย่างโดยใช้ Get-CIIMinstance บนหน่วยความจำ การใช้งานดิสก์ และบันทึกเหตุการณ์จากวันสุดท้ายนั้น สคริปต์จะสร้างตัวเลือก DCOM แบบไดนามิกหากตรวจพบว่าคอมพิวเตอร์ระยะไกลไม่ได้ใช้งาน PowerShell 3
คุณสามารถใช้ฟังก์ชัน Trace-Message ของฉันร่วมกับ Write-Verbose คุณสามารถแสดงข้อมูลเดียวกันหรือแตกต่างกันได้ มันขึ้นอยู่กับคุณ. คุณอาจบรรลุผลลัพธ์เดียวกันได้โดยใช้แบบฟอร์ม Windows หรือ WPF ผ่าน ShowUI แต่ทุกคนมี Internet Explorer และนี่ค่อนข้างง่ายที่จะรวมเข้าด้วยกัน
อย่างไรก็ตาม หากคุณเพียงต้องการสำเนาของสคริปต์สถานภาพเซิร์ฟเวอร์โดยไม่มีคำสั่ง Trace คุณก็ทำได้:
#requires -version 3.0
<#
ServerHealth.ps1
A script to do a quick health check and create an HTML report
****************************************************************
* DO NOT USE IN A PRODUCTION ENVIRONMENT UNTIL YOU HAVE TESTED *
* THOROUGHLY IN A LAB ENVIRONMENT. USE AT YOUR OWN RISK. IF *
* YOU DO NOT UNDERSTAND WHAT THIS SCRIPT DOES OR HOW IT WORKS, *
* DO NOT USE IT OUTSIDE OF A SECURE, TEST SETTING. *
****************************************************************
#>
[cmdletbinding()]
Param(
[Parameter(Position=0,HelpMessage="Enter the computer name for the report")]
[ValidateNotNullorEmpty()]
[Alias("name","cn")]
[string]$Computername=$env:computername,
[Parameter(Position=1,HelpMessage="Enter the path for the html report")]
[ValidateNotNullorEmpty()]
[string]$Path="ServerHealth.htm",
[Alias("RunAs")]
[System.Management.Automation.Credential()]$Credential = [System.Management.Automation.PSCredential]::Empty
)
Write-Verbose "Starting $($MyInvocation.MyCommand)"
#initialize an array for HTML fragments
$fragments=@()
$ReportTitle = "Server Health Report: $($Computername.toUpper())"
#this must be left justified
$head = @"
<Title>$ReportTitle</Title>
<style>
body { background-color:#FFFFFF;
font-family:Tahoma;
font-size:12pt; }
td, th { border:1px solid black;
border-collapse:collapse; }
th { color:white;
background-color:black; }
table, tr, td, th { padding: 2px; margin: 0px }
tr:nth-child(odd) {background-color: lightgray}
table { width:95%;margin-left:5px; margin-bottom:20px;}
.alert {background-color: red ! important}
.warn {background-color: yellow ! important}
</style>
<br>
<H1>$ReportTitle</H1>
"@
#build a hashtable of parameters for New-CimSession
$cimParams=@{
ErrorAction="Stop"
ErrorVariable="myErr"
Computername=$Computername
}
if ($credential.username) {
Write-Verbose "Adding a PSCredential for $($Credential.username)"
$cimParams.Add("Credential",$Credential)
}
Try {
#verify if computer is running PowerShell 2 or 3
Write-Verbose "Test-WSMan $Computername"
$wsman = Test-WSMan -ComputerName $Computername -ErrorAction Stop -ErrorVariable myErr
}
Catch {
Write-Warning "Failed to test WSMan for $Computername"
Write-Warning $myErr.ErrorRecord
Break
}
if ([int]($wsman.ProductVersion.Substring(25)) -lt 3) {
#running less than PowerShell 3 so create a DCOM option
Write-Verbose "$Computername running PowerShell 2.0"
$cimOption = New-CimSessionOption -Protocol Dcom
$cimParams.Add("SessionOption",$cimOption)
}
#create a CIM Session
Write-Verbose "Creating a CIM Session"
Try {
$cs = New-CimSession @cimParams
}
Catch {
Write-Warning "Failed to create CIM session for $Computername"
Write-Warning $myErr.ErrorRecord
Break
}
#get OS data and uptime
Write-Verbose "Getting OS and uptime"
$os = $cs | Get-CimInstance -ClassName Win32_OperatingSystem
$fragments+="<h2>Operating System</h2>"
$fragments+= $os | select @{Name="Computername";Expression={$_.CSName}},
@{Name="Operating System";Expression={$_.Caption}},
@{Name="Service Pack";Expression={$_.CSDVersion}},LastBootUpTime,
@{Name="Uptime";Expression={(Get-Date) - $_.LastBootUpTime}} |
ConvertTo-HTML -Fragment
Write-Verbose "Getting memory usage"
$fragments+="<h2>Memory Usage</h2>"
[xml]$html= $os |
Select @{Name="TotalMemoryMB";Expression={[int]($_.TotalVisibleMemorySize/1mb)}},
@{Name="FreeMemoryMB";Expression={[math]::Round($_.FreePhysicalMemory/1MB,2)}},
@{Name="PercentFreeMemory";Expression={[math]::Round(($_.FreePhysicalMemory/$_.TotalVisibleMemorySize)*100,2)}},
@{Name="TotalVirtualMemoryMB";Expression={[int]($_.TotalVirtualMemorySize/1mb)}},
@{Name="FreeVirtualMemoryMB";Expression={[math]::Round($_.FreeVirtualMemory/1MB,2)}},
@{Name="PercentFreeVirtualMemory";Expression={[math]::Round(($_.FreeVirtualMemory/$_.TotalVirtualMemorySize)*100,2)}} |
ConvertTo-Html -Fragment
#parse html to add color attributes
for ($i=1;$i -le $html.table.tr.count-1;$i++) {
$class = $html.CreateAttribute("class")
#check the value of the percent free memory column and assign a class to the row
if (($html.table.tr[$i].td[2] -as [double]) -le 10) {
$class.value = "alert"
$html.table.tr[$i].ChildNodes[2].Attributes.Append($class) | Out-Null
}
elseif (($html.table.tr[$i].td[2] -as [double]) -le 20) {
$class.value = "warn"
$html.table.tr[$i].ChildNodes[2].Attributes.Append($class) | Out-Null
}
}
#add the new HTML to the fragment
$fragments+= $html.innerXML
#get disk drive status
Write-Verbose "Getting drive status"
$drives = $cs | Get-CimInstance -ClassName Win32_Logicaldisk -filter "DriveType=3"
$fragments+="<h2>Disk Usage</h2>"
[xml]$html= $drives | Select DeviceID,
@{Name="SizeGB";Expression={[int]($_.Size/1GB)}},
@{Name="FreeGB";Expression={[math]::Round($_.Freespace/1GB,4)}},
@{Name="PercentFree";Expression={[math]::Round(($_.freespace/$_.size)*100,2)}} |
ConvertTo-Html -Fragment
#parse html to add color attributes
for ($i=1;$i -le $html.table.tr.count-1;$i++) {
$class = $html.CreateAttribute("class")
#check the value of the percent free column and assign a class to the row
if (($html.table.tr[$i].td[3] -as [double]) -le 10) {
$class.value = "alert"
$html.table.tr[$i].ChildNodes[3].Attributes.Append($class) | Out-Null
}
elseif (($html.table.tr[$i].td[3] -as [double]) -le 20) {
$class.value = "warn"
$html.table.tr[$i].ChildNodes[3].Attributes.Append($class) | Out-Null
}
}
$fragments+=$html.InnerXml
Clear-Variable html
#get recent errors and warning in all logs
Write-Verbose "Getting recent eventlog errors and warnings"
#any errors or audit failures in the last 24 hours will be displayed in red
#warnings in last 24 hours will be displayed in yellow
$Yesterday = (Get-Date).Date.AddDays(-1)
$after = [System.Management.ManagementDateTimeConverter]::ToDmtfDateTime($yesterday)
#get all event logs with entries
$logs = $cs | Get-CimInstance win32_ntEventlogFile -filter "NumberOfRecords > 0"
#exclude security log
$fragments+="<h2>Event Logs</h2>"
#process security event log for Audit Failures
$fragments+="<h3>Security</h3>"
[xml]$html = $cs |
Get-CimInstance Win32_NTLogEvent -filter "Logfile = 'Security' AND Type = 'FailureAudit' AND TimeGenerated >= ""$after""" |
Select -property TimeGenerated,Type,EventCode,SourceName,Message |
ConvertTo-Html -Fragment
if ($html.table) {
#if a failure in the last day, display in red
if (($html.table.tr[$i].td[1] -eq 'FailureAudit') -AND ([datetime]($html.table.tr[$i].td[0]) -gt $yesterday)) {
$class.value = "alert"
$html.table.tr[$i].Attributes.Append($class) | Out-Null
}
$fragments+=$html.InnerXml
}
Else {
#no recent audit failures
Write-Verbose "No recent audit failures"
$fragments+="<p style='color:green;'>No recent audit failures</p>"
}
Clear-Variable html
#process all the other logs
foreach ($log in ($logs | where logfilename -ne 'Security')) {
Write-Verbose "Processing event log $($log.LogfileName)"
$fragments+="<h3>$($log.LogfileName)</h3>"
[xml]$html = $cs |
Get-CimInstance Win32_NTLogEvent -filter "Logfile = ""$($log.logfilename)"" AND Type <> 'Information' AND TimeGenerated >= ""$after""" |
Select -property TimeGenerated,Type,EventCode,SourceName,Message |
ConvertTo-Html -Fragment
if ($html.table) {
#color errors in red
for ($i=1;$i -le $html.table.tr.count-1;$i++) {
$class = $html.CreateAttribute("class")
#check the value of the entry type column and assign a class to the row if within the last day
if (($html.table.tr[$i].td[1] -eq 'Error') -AND ([datetime]($html.table.tr[$i].td[0]) -gt $yesterday)) {
$class.value = "alert"
$html.table.tr[$i].Attributes.Append($class) | Out-Null
}
elseif (($html.table.tr[$i].td[1] -eq 'Warning') -AND ([datetime]($html.table.tr[$i].td[0]) -gt $yesterday)) {
$class.value = "warn"
$html.table.tr[$i].Attributes.Append($class) | Out-Null
}
} #for
$fragments+=$html.InnerXml
}
else {
#no errors or warnings
Write-Verbose "No recent errors or warnings for $($log.logfilename)"
$fragments+="<p style='color:green;'>No recent errors or warnings</p>"
}
Clear-Variable html
} #foreach
#get services that should be running but aren't
Write-Verbose "Getting services that should be running but aren't"
$services = $cs | Get-CimInstance -ClassName win32_service -filter "startmode='Auto' AND state <> 'Running'"
$fragments+="<h2>Services</h2>"
$fragments+= $services | Select Name,Displayname,Description,State |
ConvertTo-Html -Fragment
$fragments+="<br><i>Created $(Get-Date)</i>"
#create the HTML report
Write-Verbose "Creating an HTML report"
ConvertTo-Html -Head $head -Title $reportTitle -body $Fragments | Out-File -FilePath $path -Encoding ascii
Write-Verbose "Saving the HTML report to $Path"
Write-Verbose "Ending $($MyInvocation.MyCommand)"
Write-Host "Report saved to $path" -ForegroundColor Greenวันนี้คุณจะได้รับความสนุกเป็นสองเท่า คุณคิดอย่างไรเกี่ยวกับเรื่องทั้งหมดนี้? เช่นเคย ฉันหวังว่าจะได้ยินสิ่งที่คุณคิด


