1. Introduction
Website automation health check typically refers to proactively monitoring and testing a website or web application to identify issues before they impact customers. Today I will show you how to monitor the website uptime and auto login the website for checking.
2. Why Powershell
Why would I use Powershell for auto health checking? Powershell is the native application in Windows, so don’t need to install other software or environment and just can use it, this will be very convenient for some companies’ servers, maybe for some security reasons that do not allow to installation of any 3 party software in the server, and it also needs to handle the auto health check service on schedule, in this time, the powershell is the best choice!
3. Preparation
1) Create an empty folder for your project, e.g. AutoHealthCheck
2) Create a libs
folder, we will put the preparation libraries in it
3) Download the Selenium
We bill based on Selenium
for the auto testing, so the first thing we need to download the Selenium
web driver. We just need the WebDriver.dll
, so go to Nuget and download the Selenium.WebDriver
package (the latest version is 4.12.4 this time)
https://www.nuget.org/api/v2/package/Selenium.WebDriver/4.12.4
Rename the selenium.webdriver.4.12.4.nupkg
to selenium.webdriver.4.12.4.zip
and unzip it, copy the below file to your project libs
folder
selenium.webdriver.4.12.4\lib\netstandard2.0\WebDriver.dll
4) Download the latest chrome driver below, it must be based on your chrome version
https://chromedriver.chromium.org/downloads
put the chromedriver.exe
file into your project libs
folder
4. Start Coding
Even just a simple program and only a single file will be ok, but I think we still need to design the flow and some helper functions:
4.1. Workflow
1) We will create a PowerShell script file and put it into Windows’s schedule for auto-run
2) There should be a setting file for controlling which website we need to check
3) For security reasons, if we need to check the login page it needs to encrypt the password in the settings file
4) The script will auto-call Chrome access the URL and check the element whether exists based on the setting value
5) It needs to write a log for checking the result
Okay, we need to accomplish the above function, we can create some helper functions first.
4.2. Write Log Function
The log is very important and can help us to find the issue, and we can easily write log in PowerShell with below
function WriteLog {
Param ([string]Logfile, [string]LogString)
Stamp = (Get-Date).toString("yyyy/MM/dd HH:mm:ss")LogMessage = "StampLogString"
Add-content LogFile -valueLogMessage
}
and define the log file name and path
$LogFileName = (Get-Date).toString("yyyyMMdd-HHmmss")
$Logfile = "$RootFloder\logs\$LogFileName.log"
4.3. Read INI File Function
We will use the ini
file for a setting file, the structure will be as below
;Config for website helath check
[Base]
;The base config
IsDebug=true
SMTP=localhost
SendFrom=Tester@abc.com
SendTo=winsonet@gmail.com
[Localhost]
;Test for auto login function
Delay=5
IsLoginPage=true
UserXPath=//*[@id="mat-input-0"]
PwdXPath=//*[@id="mat-input-1"]
SubmitForm=//*[@id="wrapper"]/app-login/div/form/div[3]/button
LoginInfo=login_info.dat
Url=http://localhost:4810/login
[Localhost_user-management]
;Test for auto login function
Delay=5
XPath=//*[@id="wrapper"]/app-user-management/h1
Url=http://localhost:4810/user-management
I will explain these later, for now, if we want to read this file, we can create the below function
function Get-IniFile {
param(
[parameter(Mandatory = true)] [string]filePath
)
anonymous = "NoSection"ini = @{}
switch -regex -file filePath { "^\[(.+)\]" {
# Section
section =matches[1]
ini[section] = @{}
CommentCount = 0 }
"^(;.*)" {
# Comment
if (!(section)) {section = anonymousini[section] = @{} }value = matches[1]CommentCount = CommentCount + 1name = "Comment" + CommentCountini[section][name] = value }
"(.+?)\s*=\s*(.*)" {
# Key if (!(section)) {
section =anonymous
ini[section] = @{}
}
name,value = matches[1..2]ini[section][name] = value } }
returnini
}
and usage as below
$CheckItems = Get-IniFile "$RootFloder\config.ini"
# Get Base settings
$IsDebug = $CheckItems.Base["IsDebug"] -eq "true"
4.4. Send Email Function
This is an auto-schedule task so we should send an email for notification after done, we can create the below send email function, and it will attach the log file
function SendEmail {
param(
[parameter(Mandatory = true)] [string]EmailSubject,
[Parameter(Mandatory = true, HelpMessage = "Email attachments.")]
[string[]]Attachments
)
try {
BaseConfig = Get-IniFile "RootFloder\config.ini"
EmailFrom =BaseConfig.Base.SendFrom
EmailTo =BaseConfig.Base.SendTo.split(';')
SMTPserver =BaseConfig.Base.SMTP
#EmailSubject = "Auto Health Checked Result on " + (Get-Date).toString("yyyyMMdd")EmailBody = "Dear Admin, <br><br>Please find the below attachment for the health check result!<br><br><br><br>"
#Write-Output "EmailTo SMTP:SMTPserver"
#Send-MailMessage CmdLet
Send-MailMessage -ErrorAction Stop -from "EmailFrom" -to "EmailTo" -subject "EmailSubject" -body "EmailBody" -BodyAsHtml -SmtpServer "SMTPserver" -AttachmentsAttachments
}
catch {
Write-Output "There was a problem with sending email, check error log. Value of error is: _"ErrorLogFileName = (Get-Date).toString("yyyyMMdd-HHmmss")
ErrorLogfile = "RootFloder\logs\Errors_ErrorLogFileName.log"
WriteLogErrorLogfile $_.ToString()
}
}
4.5. Use the Selenium in Powershell
There is a Selenium PowerShell Module for help to use Selenium in PowerShell. But I think the module it’s too complex(there are many functions unnecessary to use in this case) and maybe some companies would not allow to installation any 3 party PowerShell module, so I will write the logic by myself 🙂
1) Import the Selenium
There are 3 options to import the Selenium
library
# OPTION 1: Import Selenium to PowerShell using the Add-Type cmdlet.
Add-Type -Path "(RootFloder)\libs\WebDriver.dll"
# OPTION 2: Import Selenium to PowerShell using the Import-Module cmdlet.
Import-Module "(RootFloder)\libs\WebDriver.dll"
# OPTION 3: Import Selenium to PowerShell using the .NET assembly class.
[System.Reflection.Assembly]::LoadFrom("(RootFloder)\libs\WebDriver.dll")
2) Create the Chrome option
We can create the chrome option to set how the chromedriver
works, for example, set the maximize window or use the chrome extensions
$ChromeOption = New-Object OpenQA.Selenium.Chrome.ChromeOptions
$ChromeOption.AddExcludedArgument("enable-automation")
$ChromeOption.AddArguments("--start-maximized")
#$ChromeOption.AddArguments('--headless') #don't open the browser
# Ignore the SSL non secure issue
$ChromeOption.AcceptInsecureCertificates = $true
# Create a new ChromeDriver Object instance.
$ChromeDriver = New-Object OpenQA.Selenium.Chrome.ChromeDriver($ChromeOption)
If the checking website does not support SSL, it needs to ignore it, so we need to use the Chrome option for that
4.6. Get the Settings from Ini
We need to get the settings from ini
file as below
$CheckItems = Get-IniFile "$RootFloder\config.ini"
foreach the result
Foreach (key inCheckItems.keys ) {
if (key -ne "NoSection" -andkey -ne "Base") {
if (IsDebug) {
Write-Output "=====key===Start===Checking========="
Write-Output CheckItems.key
}
Item =CheckItems.key
if (null -ne Item["Url"]) {
# Launch a browser and go to URL if the Url is not nullChromeDriver.Navigate().GoToURL(Item["Url"])
# Wait for x seconds for loading the website contentChromeDriver.Manage().Timeouts().ImplicitWait = [TimeSpan]::FromSeconds(Item["Delay"])
Start-Sleep -sItem["Delay"]
}
#...
}
}
4.7. Get the Element
We can get the website element with XPath
with Selenium
in PowerShell, so there are some settings in out ini
, we define what element should be found
[Localhost_user-management]
;Test for auto login function
Delay=5
XPath=//*[@id="wrapper"]/app-user-management/h1
Url=http://localhost:4810/user-management
The about testing site is my previous article’s demo project.
And we can find the XPath
in chrome like below
1) Right click the element and inspect it
2) Right click the HTML code with the element and Copy
=> Copy XPath
, then just copy into your ini
file
We can use the below code to get the element by XPath
in PowerShell
Element =ChromeDriver.FindElement([OpenQA.Selenium.By]::XPath(Item[subSection + "XPath"]))
and you also can execute the Javascript
in this element
$ChromeDriver.ExecuteScript("arguments[0].click()", $Element)
4.8. Encrypt and Decrypt the Password
When we want to auto login to a website for testing, we need to put the password in the setting file, but that’s a security issue if we just set the password directly, so we need to encrypt it.
We can put the password into an encrypted file (e.g. login_info.dat) and decrypt it when we need to use it.
Create another PowerShell
script file, put the below codes
# param(fileName)fileName = "login_info.dat"
User = Read-Host -Prompt 'Input your login name' -AsSecureStringPasword = Read-Host -Prompt 'Input your password' -AsSecureString
User =User | ConvertFrom-SecureString
Pasword =Pasword | ConvertFrom-SecureString
info = "User|Pasword"
Set-contentfileName -value $info
After executing it, it will prompt you to input the user name and password and encrypt into a login_info.data
file, and we can use the below to decrypt it
# Get the encrypted user name and password
UserInfo = Get-Content 'login_info.data'UserName = UserInfo.Split("|")[0] | ConvertTo-SecureStringPassword = UserInfo.Split("|")[1] | ConvertTo-SecureString
# decrypt the username and password and send to web pageUserName = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR(UserName))Password = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($Password))
4.8. Auto Login to the Website
I will show you how to automate login to a website. We still use the demo project :
1) Get the username and password from the encrypted file
# Get the encrypt user name and password
UserInfo = Get-ContentItem.LoginInfo
UserName =UserInfo.Split("|")[0] | ConvertTo-SecureString
Password =UserInfo.Split("|")[1] | ConvertTo-SecureString
# decrypt the username and password and send to web page
UserName = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR(UserName))
Password = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR(Password))
2) Find the user name and password element with their XPath and set the value
# Pass the user and password and set the value with SendKeys method
ChromeDriver.FindElement([OpenQA.Selenium.By]::XPath(Item["UserXPath"])).SendKeys(UserName)ChromeDriver.FindElement([OpenQA.Selenium.By]::XPath(Item["PwdXPath"])).SendKeys(Password)
# Find the submit button and submit
ChromeDriver.FindElement([OpenQA.Selenium.By]::XPath(Item["SubmitForm"])).Submit()
4.9. Find the Element by Tag Name
We also can find the element by tag name, for example below structure
we want to find the User Management
element by tag name (here is h1
), We can find its parent by XPath
Element =ChromeDriver.FindElement([OpenQA.Selenium.By]::XPath(//*[@id="wrapper"]))
and then get the element by tag name, because there will be multiple elements with a tag, so if you want to get the first one, just get the index 0 as below
Element =Element.FindElements([OpenQA.Selenium.By]::TagName('h1'))[0]
```
of course, you can find the tag name directly, but there are many tags on a page, so if you find the tag based on the parent will be easy to find it
```powershell
Element =ChromeDriver.FindElements([OpenQA.Selenium.By]::TagName('h1'))[0]
In the end, we can create a batch file to execute the Powershell script so that it can be easy to use
@REM start.bat
powershell.exe -ExecutionPolicy Bypass -Command .\demo.ps1
5. Conclusion
PowerShell is a powerful script for handling many server-side problems, it very suitable for use in some servers that’s require a lot of security restrictions. You can find the full source code in github.