Website Automation Health Check with Powershell

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

Do you want to be a good trading in cTrader?   >> TRY IT! <<

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.

Loading

Views: 40
Total Views: 516 ,

Leave a Reply

Your email address will not be published. Required fields are marked *