Monday, April 20, 2020

Chrome: Disabling Auto Update using PowerShell

In a previous post (Chrome: Disabling Auto Update using RegEdit), it was shown how to prevent Chrome from auto updating by editing registry using RegEdit. The point of this series of posts is to automate administrative tasks. In this post it will be shown how to disable Chrome from auto updating using PowerShell to update the registry.

To recap the steps required to disable Chrome auto updating are as follows:

1) Insure the following registry key exists and if it does not exist, create it:
HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Google

2) Insure the following registry key exists and if it does not exist, create it:
HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Google\Update

3) Insure the AutoUpdateCheckPeriodMinutes registry value exists with a value of zero under the  previous key:
HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Google\Update

The code to perform this is as follows:

[string] $softwarePolicyPath = 'HKLM:\SOFTWARE\Policies'
[string] $googleKey = 'Google'
[string] $googleUpdateKey = 'Update'

[string] $autoUpdateCheckPeriodMinutesValueName = 
             'AutoUpdateCheckPeriodMinutes'
[int] $autoUpdateCheckPeriodMinutesValue = 0
# If you are using pre-PowerShell 6.0 use this line of code instead

# [string] $softwarePolicyGoogleUpdatePath = 
#     Join-Path `
#         -Path $softwarePolicyPath `
#         -ChildPath $googleKey
[string] $softwarePolicyGooglePath = Join-Path $softwarePolicyPath $googleKey


if (-not (Test-Path $softwarePolicyGooglePath)) {
    Write-Host "Creating: $SoftwarePolicyGooglePath"

    New-Item `
        -Path $softwarePolicyPath `
        -Name $googleKey | Out-Null
}

# If you are using pre-PowerShell 6.0 use this line of code instead
# [string] $softwarePolicyGoogleUpdatePath = 
#     Join-Path `
#         -Path $SoftwarePolicyGooglePath `
#         -ChildPath $googleUpdateKey
[string] $softwarePolicyGoogleUpdatePath = Join-Path $softwarePolicyGooglePath $googleUpdateKey

if (-not (Test-Path $softwarePolicyGoogleUpdatePath)) {
    Write-Host "Creating: $softwarePolicyGoogleUpdatePath"

    New-Item `
        -Path $softwarePolicyGooglePath `
        -Name $googleUpdateKey | Out-Null
}

# create or update
Set-ItemProperty `
    -Path $softwarePolicyGoogleUpdatePath `
    -Name $autoUpdateCheckPeriodMinutesValueName `
    -Value $autoUpdateCheckPeriodMinutesValue


The Join-Path cmdlet shown above was reviewed in the previous post, PowerShell: Join-Path Joining Multiple Children.

The following cmdlets were used to access the registry and create the appropriate entities required to disable Chrome's auto update feature:
  • Test-Path: tests is a registry key exists
  • New-Item: creates a registry key
  • Set-ItemProperty: update a registry value if the value already exists or creates a registry value of the value does not exist

Sunday, April 19, 2020

PowerShell: Join-Path Joining Multiple Children

PowerShell's Join-Path cmdlet allows file paths, registry paths, etc. to be combined. Using Join-Path does not take a PhD in quantum physics to understand but prior to PowerShell 6.0 joining multiple paths was tedious. PowerShell 6.x, 7.x and later versions support joining paths as follows (excerpt from Microsoft's documentation for Join-Path):


To understand the elegance of the documentations "Example 7" consider a registry key that needs to be created programmatically:
HKLM:\SOFTWARE\Policies\Google\Update

The following code works for PowerShell 6.0 or later and can generate the aforementioned path programmatically in the style of Example 7:

[string] $hive = 'HKLM:'
[string] $softwareKey = 'SOFTWARE'
[string] $policiesKey = 'Policies'
[string] $googleKey = 'Google'
[string] $updateKey = 'Update'


[string] $path = Join-Path `
                    $hive `
                    $softwareKey `
                    $policiesKey `
                    $googleKey `
                    $updateKey

$path

The output from the above script is as follows:


PowerShell 5.x and Earlier

The previous code will fail if run under PowerShell 5.x or earlier. These versions of PowerShell do not support the command-line option allowing the combination of an indefinite number of paths. A more verbose usage of Join-Path is required to create the equivalent path (see below):

[string] $hive = 'HKLM:'
[string] $softwareKey = 'SOFTWARE'
[string] $policiesKey = 'Policies'
[string] $googleKey = 'Google'
[string] $updateKey = 'Update'
[string] $path =
        Join-Path -Path $hive -ChildPath $softwareKey |
        Join-Path -ChildPath $policiesKey |
        Join-Path -ChildPath $googleKey |
        Join-Path -ChildPath $updateKey

$path

The previous PowerShell code make use of the -Path and -ChildPath command-line options to create the desired registry path.


Saturday, April 18, 2020

Chrome: Disabling Auto Update using RegEdit

The latest series of blog postings have been focused on automating Chrome with PowerShell and Selenium. When working with Selenium the underling libraries (DLLs) must match the version of Chrome installed. Corporate environments do not always update Chrome to the latest version. The virtual machines used to run automation tasks often restrict auto updating software applications including Chrome. As part of automating Chrome using PowerShell and Selenium it is sometimes necessary to prevent Chrome from automatically updating so that an earlier version of Chromes can be automated.

On Windows the steps to disable Chrome auto update are as follows:

In the search box on the taskbar enter RegEdit which should allow the Registry Editor app (regedit) to be invoke:


From the RegEdit application, navigate to the following key:
HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Google\Update\

The path HKEY_LOCAL_MACHINE\SOFTWARE\Policies will exist but the Google and Update keys may not exist and will have to be created manually (see below):


To create the missing Google key:

Right click on the Polices folder to display the context menu and from this menu select New | Key:


When the Key menu item is invoked a new key named "New Key #1" will be created:


Rename "New Key #1" to Google:


Follow the same steps to add the Update key under the Google key. With the Update key selected:

Right click on values panel to the right and select New | DWORD (32-bit) Value:


When the DWORD (32-bit) Value menu item is invoked a new key named "New Value #1" will be created:


Rename "New Value #1" to AutoUpdateCheckPeriodMinutes and leave the value set to 0:


This disable Chrome auto updating on Windows

Wednesday, April 15, 2020

PowerShell: Chrome Automation with Selenium

Selenium is most often associated with QA and testing web sites. DevOps can also make use Selenium in order to automate health checks and a varaiety of administrative tasks. DevOps engineers have numerous logging consolidators, packages and application at their disposal: AppDynamics, SolarWinds, Splunk, etc. There are just times especially with legacy infrastructure or third party sites/applications that browser automation is helpful. A QA engineer would be concerned with Edge, Safari, Firefox, and Chrome. As a DevOps engineer, the focus of this post will be on automation using Selenium and Chrome. There is no reason to test all browser flavors when it is more practical for a DevOps team to standard on a single type of browser such as Chrome.

In a previous post, PowerShell: Install-Module and Uninstall-Module, it was shown how to install the Selenium module for PowerShell and with respect to installation using the all users scope. The Selenium module for PowerShell is an open source project hosted on Git Hub: https://github.com/adamdriscoll/selenium-powershell.

The https://github.com/adamdriscoll/selenium-powershell Git Hub home page includes a Readme.md page which contains a usage section describing how to use the PowerShell module to automate browsers with Selenium:


The URL used to demonstrate browser automation is https://www.google.com. A previous blog post showed how to inspect the element on this page in which the search term is entered, Chrome: Fundamentals of Browser Automation.

The PowerShell code to enter a search term and invoke search via the Enter key is straightforward. The term searched for will be "The Wedding Present Dalliance" which of course refers to the song "Daliance" but the band, The Wedding Present.

The browser automation code is as follows:

$driver = $null
try {
    $driver = Start-SeChrome
    Enter-SeUrl 'https://www.google.com' -Driver $driver

    # The name of the input element is q (name="q")
    # <input class="gLFyf gsfi" maxlength="2048" name="q"     

    $element = Find-SeElement -Driver $driver -Name 'q'
    Send-SeKeys -Element $element `
                -Keys "the wedding present dalliance`n"
}

catch {
    Write-Host $PSItem.Exception
}

finally {
    if ($null -ne $driver) {
        Stop-SeDriver $driver
        $driver = $null
    }
}

Chrome is launched and terminated using the Start-SeChrome and Stop-SeDriver functions which utilize PowerShells try/finally construct to insure that the Chrome is closed even if the script generates an error:

$driver = $null
try {
    $driver = Start-SeChrome
# ... additional code here ....
}
finally {
    if ($null -ne $driver) {
        Stop-SeDriver $driver
        $driver = $null
    }
}

Each browser supported by Selenium has it own start function:
  • Start-SeChrome: starts Chrome
  • Start-SeEdge: starts the version of Edge that is not implemented with Chromium
  • Start-SeNewEdge: starts the version of Edge that is implemented with Chromium
  • Start-SeFirefoxL starts Firefox
  • Start-SeInternetExplorer: starts Internet Explorer

The URL is assigned using the function, Enter-SeUrl:
    Enter-SeUrl 'https://www.google.com' -Driver $driver

The input element is selected by name using the fuction, Find-SeElement:
    # The name of the input element is q (name="q")
    # <input class="gLFyf gsfi" maxlength="2048" name="q"     
    $element = Find-SeElement -Driver $driver -Name 'q'

The text to search on and the Enter key to invoke search is invoked using function, Send-SeKeys:
    Send-SeKeys -Element $element `
                -Keys "the wedding present dalliance`n"

The result of running the script is the as anticipated search results:






Chrome: Fundamentals of Browser Automation

The page that will be automated as an example is https://www.google.com/ as it is displayed in Chrome. PowerShell and Selenium will be the technology the facilitates browser autoamtion.  Before coding the automation in PowerShell the elements on the page must be inspected so that a strategy for automation can be devised.

In Chrome,  https://www.google.com/ is displayed as follows:


Right clicking inside the search box displays a context menu and selecting the Inspect menu option allows the underlying HTML element of the search box to be inspected:


Selecting the Inspect menu item will display the Chrome Inspector with the HTML for the selected elemetnt lightlight.


Right clicking on the highlight element in Chrome Inspector allows the element to be copied:


Using Copy | Copy Element, the element associated with the search text field is:

<input class="gLFyf gsfi" maxlength="2048" name="q" type="text" jsaction="paste:puy29d" aria-autocomplete="both" aria-haspopup="false" autocapitalize="off" autocomplete="off" autocorrect="off" autofocus="" role="combobox" spellcheck="false" title="Search" value="" aria-label="Search" data-ved="0ahUKEwjVteiQn-ToAhVDEawKHcycBJoQ39UDCAY">

The Selnium API's Find-SeElement function can fine elements by name, class, name, etc. so the following are potential components by  which to automate the search text box:
  •  element type:input
  •  class: gLFyf gsfi
  • name: q
The class name has a space in it which is not supported. The page has multiple elements of type input. The unique component is the name, "q", which can be used by Find-SeElement to look up the underlying element.







Saturday, April 11, 2020

PowerShell: Install-Module and Uninstall-Module

In order to automate Chrome-based DevOps tasks, Selenium and PowerShell will be used. The site, PowerShellGallery, contains a variety of PowerShell modules that can be installed including Selenium for PowerShell, https://www.powershellgallery.com/packages/Selenium. The cmdlets used to install and uninstall PowerShell modules are Install-Module and Uninstall-Module respectively.

Clicking on the abo e link displays the following (note; the version number will change depending on the current version number where at the time of this blog entry being written is 3.0.0):


Install-Module: User Scope

The installation instructions shown on PowerShellGallary.com's Selenium page make use of Install-Module cmdlet which can be run from PowerShell:

Install-Module -Name Selenium

Another way to run the Install-Module cmdlet is from a Visual Studio Code Terminal window set to PowerShell versus BASH:


Running Install-Module defaults to user scope meaning the Selenium module for PowerShell (Selenium.psm1) will be installed at the following location:

C:\Users\<user name>\Documents\PowerShell\Modules\Selenium\3.0.0

To import this module (Selenium.psm1) into a PowerShell script, the following code could be used:

[string] $UserModules = 
             "$HOME\Documents\WindowsPowerShell\Modules"
Import-Module "$UserModules\Selenium\3.0.0\Selenium.psm1"


In the previous code, $HOME is an automatic variable in PowerShell defined on How-to: Automatic Variables as containing:


The Import-Module cmdlet imports the Selenium.psm1 module into the current session so that functions and classes exposed by the module can be used.

Install-Module: All Users

The environment where I develop automation scripts for uses multiple "Bot" accounts each corresponding to a different user on Windows. Installing a module with per-User scope (the default scope) would be problematic. To install PowerShell module (such as Selenium) for use by the all user scope, use the -Scope AllUsers parameter as follows:

Install-Module -Name Selenium -Scope AllUsers

An example of Visual Studio Code's Terminal window during the install of Selenium for all users is a follows:


When the Selenium or any module is installed at all users scope, there is no need to use the Import-Module cmdlet in order to access the installed module.

An example of using the Selenium.psm1 module is as follows and notice that the Import-Module cmdlet is not required due to Selenium being installed at under the all user scope:

$Driver = Start-SeChrome
Enter-SeUrl https://www.google.com -Driver $Driver


The previous PowerShell code launches an instance of Chrome and navigates the Chrome browser to the URL: https://www.google.com.

Uninstall-Module

Uninstalling a module is performed using the Uninstall-Module cmdlet. An example of the  Uninstall-Module cmdlet being used to uninstall the Selenium PowerShell module is follows:

Uninstall-Module -Name Selenium




Thursday, April 9, 2020

.NET Core: Determing which SDK and Runtime are Installed

1) Run Visual Studio Code:


2) From the View Menu select Terminal:



3) In the Terminal windows run the following command to see the currently installed .NET Core runtimes: dotnet --list-runtimes


4) In the Terminal windows run the following command to see the currently installed .NET Core SDKs: dotnet --list-sdks


Tuesday, April 7, 2020

PowerShell: Use Single Quotes Where Possible

As a general rule, PowerShell scripts should use strings marked by single quotes rather than double quotes. Using single quotes tells anyone reading the code, "This string will not contain variable substitution." Strings demarcated by double quotes support variable substitution.

In a previous posting, I declared a variable $key1 and deliberately used single quotes:

[string] $key1 =
            'HKLM:\SOFTWARE\Microsoft\Windows\' +
            'CurrentVersion\App Paths\chrome.exe'


The message to any developing reading the above code is that there would be parameters injected into the string because of the single quotes. I have seen example after example online of PowerShell where double quotes are used and there are no variable specified for substitution:

[string] $key2 =
            "HKLM:\SOFTWARE\Microsoft\Windows\" +
            "CurrentVersion\App Paths\chrome.exe"

Exception to the Rule: Variable Substitution

A double quoted string should be used when a variable to be replaced is specified. The previous string is technically correct but it contains no variable inside the double quotes so there is no point in using double quotes over single quotes. A string such as the following (variable $key3) takes advantage of variable substitution and is therefor surrounded by double quotes:

[string] $chromeExecutable = 'chrome.exe'
[string] $key3 =
            'HKLM:\SOFTWARE\Microsoft\Windows\' +
            "CurrentVersion\App Paths\$chromeExecutable"

The variable $key1 and $key3 will both have the same value where $key3 is assigned this value by substituting the parameter $chromeExecutable.

Exception to the Rule: Escape Sequences


The blog entry "PowerhShell: Escape Sequences (NewLine, Tab, BackSpace, etc)" demonstrated escape sequences. Consider a scenario where PowerShell and Selenium are being used to automate a web page and the term 'Wedding Present' is being searched for. One way to trigger the search button would be to invoke the Enter key. The text to pass to the Selenium API invoke the search button would be "Wedding Present`n" which requires double quotes so that the text 'Wedding Present' is passed including the escape sequence for the Enter key, `n.

Exception to the Rule: SQL Queries


There are other times when a double quoted string is useful in PowerShell. T-SQL uses single quotes for strings so a double quoted string PowerShell can contain single quotes. An example of T-SQL where single quotes are used inside a double quoted PowerShell string is as follows:

"SELECT * FROM Employee WHERE LastName LIKE 'S%' ORDER BY LastName"

The previous T-SQL select will select all employees where the last name starts with the letter S (WHERE LastName LIKE 'S%') and nested within the query are the single quotes used for the look up starts with the letter S, 'S%'.

Monday, April 6, 2020

PowerhShell: Escape Sequences (NewLine, Tab, BackSpace, etc)

The ultimately goal in this series of blog posts is to demonstrate PowerhSell being used with Selenium to automate Chrome. When automating a browser, invoking an Enter key is handy. This posts discusses PowerShell escape sequenecde which includes `n which is the escape sequence for the Enter key.  The character before the n key in the previous sentence is the back quote. The back quote character (`) shares the same key as the tilde on standard English keyboards. The back quote character is called by many names such as acute, backtick, left quote, or a open quote, and or backquote. In PowerShell the back quote is used to indicate an escape sequence in a string.

In a previous post (PowerShell: Comparing Version Numbers) the following code snippet was show which shows a back quote being used to esape the $ so that the variable is not injected into the double quoted string (`$versionCurrent and `$versionPrevious contain the escaped $ character):
    Write-Host
        "Correct: `$versionCurrent ($versionCurrent) -gt" +
        "`$versionPrevious ($versionPrevious)"


As was discussed above, the `n escape sequence corresponds to the Enter key. The following escape sequences are defined in my Microsoft's PowerShell documentation, About Special Characters:


The `t escape sequence is useufl in creating tab-seperated-value files (TSV's). The rest of the escape sequences have their uses but for our taget purpose is to automate Chrome using PowerShell and Selenium, they might not serve much of a use in that endeavor.



Sunday, April 5, 2020

PowerShell: Comparing Version Numbers

Comparing applciation version number in PowerShell would come in handy when Selenium is used to automate Chrome. The version of Selenium which allows Chrome to be automated is dependent on the version of Chrome installed on a give host (see PowerShell: Geting Chrome's Version Number). By using Chrome's version number, it would be possible for PowerShell to load at runtime the correct version of Selenium to allow the particular version of Chrome to be automated.

Comparing Versions

When thought of as version numbers 1.0.100 is a newer version than 1.0.99 but below the are compared as strings:

[string] $versionPrevious = '1.0.99'
[string] $versionCurrent = '1.0.100'


if ($versionCurrent -gt $versionPrevious) {
    Write-Host 
      "Correct: `$versionCurrent ($versionCurrent) -gt" + 
      "`$versionPrevious ($versionPrevious)"
}

else {
    Write-Host 
      "Incorrect: `$versionPrevious ($versionPrevious) -gt" +
      " `$versionCurrent ($versionCurrent)"
}

The output from the previous code is as expected the result of a string compare using the -gt operator which is not the same a comparison between version numbers:

Incorrect: $versionPrevious (1.0.99) -gt $versionCurrent (1.0.100)
.NET provides a class System.Version for representing version numbers. In PowerShell this calls is presented by the type [version]. The System.NET version type is described by Microsoft in https://docs.microsoft.com/ as follows:



Changing the variable type from [string] to [version] results in the version numbers be compared correctly:

[version] $versionPrevious = '1.0.99'
[version] $versionCurrent = '1.0.100'

if ($versionCurrent -gt $versionPrevious) {
    Write-Host 
      "Correct: `$versionCurrent ($versionCurrent) -gt" + 
      "`$versionPrevious ($versionPrevious)"
}


else {
    Write-Host 
      "Incorrect: `$versionPrevious ($versionPrevious) -gt" +
      " `$versionCurrent ($versionCurrent)"
}


The output from the previous code is as expected the result of a version using the -gt operator:

Correct: $versionCurrent (1.0.100) -gt $versionPrevious (1.0.99)

A final note, the Escape Character

The previous code snippet contained two instance of the back quote character being used to suppress the $ character's use in a double quoted string `$versionCurrent and `$versionCurrent. A PowerShell variable inside of a double quoted string is results in the value of the variable being replaced inside the string. The back quote before $ suppresses this substitution








Saturday, April 4, 2020

PowerShell: Getting Chrome's Version Number

As part of some DevOps work I have been performing automations using Selenium driven by PowerShell (more on that later). In order to automate a browser such as Chrome is it is handy to know what version Chrome is installed on a give machine.

The code required is fairly straight forward as shown by ChromeSupport.psm1:

class ChromeSupport {
    hidden static [string] $Key =
        'HKLM:\SOFTWARE\Microsoft\Windows\' +
        'CurrentVersion\App Paths\chrome.exe'


    static [System.Diagnostics.FileVersionInfo] GetVersionInfo() {
        [string] $path = 

          (Get-ItemProperty ([ChromeSupport]::Key)).'(Default)'

        return (Get-Item $path).VersionInfo
    }

}


The moduel is invoked from Powershell script, AutomationDriver.ps1:

using module '.\ChromeSupport.psm1'

[ChromeSupport]::GetVersionInfo()

The output from the above script is as follows:


Getting the product version is as matter of invoking the code as follows:

using module '.\ChromeSupport.psm1'

[ChromeSupport]::GetVersionInfo().ProductVersion

The previous code displays: