Posted On July 10, 2020

PowerShell: Use Selenium Drivers to Automate Logins

kimconnect 0 comments
blog.KimConnect.com >> Codes >> PowerShell: Use Selenium Drivers to Automate Logins

Set Variables:

$username='testrobot'
$password='password'
$url='https://blog.kimconnect.com'

# Version 0.0.2 - return true or false, while keeping IE Open for further use
# This iteration also handles IE Protected mode errors

# Usage:
# 1. $ie=autologinSe "$url" "$username" "$password"
# 2. autologinSe $someUrlNoLogin
# 3. autologinSe "$url" "$username" "$password" -exitIeWhenDone $true

Run the Function:

function autologinSe{
    param(
        $url,
        $username,
        $password,
        $usernameElementId='userNameInput',
        $passwordElementId='passwordInput',
        $submitButtonId='submitButton',
        $exitIeWhenDone=$false
    )
    $ErrorActionPreference = 'continue'

    # Initial validation
    if(!$url){write-warning "No URL specified.";return $false}

    function killInternetExplorer{
        $ieInstances=(New-Object -COM 'Shell.Application').Windows()|?{$_.Name -like '*Internet Explorer*'} 
        $ieInstances|%{$_.Quit()
        [Runtime.Interopservices.Marshal]::ReleaseComObject($_)
        }
        [GC]::Collect()
        [GC]::WaitForPendingFinalizers()
        }

    function enableIeProtectedMode{
        # $hives = 0..4|%{"HKLM:\Software\Microsoft\Windows\CurrentVersion\Internet Settings\Zones\$_"}
        $hives = 0..4|%{"HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings\Zones\$_"}
        $keyName='2500' # Key Name '2500' corresponds to 'Protected Mode' in IE
        
        #Skipping zone 0 as that is the default local machine zone
        $hives[1..4]|%{Set-ItemProperty -Path $_ -Name $keyName -Value 0}
        $keys=$hives|%{Get-ItemProperty -Path $_}|select DisplayName, `
                                                        @{name='status';e={
                                                                        if($_.$keyName -eq 0){'enabled'}
                                                                        elseif($_.$keyName -eq 3){'disabled'}
                                                                        else{'n/a'}                                                                                        
                                                                        }}
        write-host "IE Protected Mode Standardized Values:`r`n$($keys|out-string)" 
    }

    function disableIeProtectedMode{
        # $hives = 0..4|%{"HKLM:\Software\Microsoft\Windows\CurrentVersion\Internet Settings\Zones\$_"}
        $hives = 0..4|%{"HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings\Zones\$_"}
        $keyName='2500' # Key Name '2500' corresponds to 'Protected Mode' in IE
        
        #Skipping zone 0 as that is the default local machine zone
        $hives[1..4]|%{Set-ItemProperty -Path $_ -Name $keyName -Value 3}
        $keys=$hives|%{Get-ItemProperty -Path $_}|select DisplayName, `
                                                        @{name='status';e={
                                                                        if($_.$keyName -eq 0){'enabled'}
                                                                        elseif($_.$keyName -eq 3){'disabled'}
                                                                        else{'n/a'}                                                                                        
                                                                        }}
        write-host "IE Protected Mode Standardized Values:`r`n$($keys|out-string)" 
    }

    function allowActiveX($zone='Trusted'){
        #Source: https://learn.microsoft.com/en-us/previous-versions/troubleshoot/browsers/security-privacy/ie-security-zones-registry-entries
        $zoneCode=switch($zone){
            'My Computer'{0;break}
            'Local Intranet'{1;break}
            'Trusted'{2;break}
            'Internet'{3;break}
            'Restricted Sites'{4;break}
            default{2}
            }
        #Reference table:
        #Value    Setting
        #------------------------------
        #0        My Computer
        #1        Local Intranet Zone
        #2        Trusted sites Zone
        #3        Internet Zone
        #4        Restricted Sites Zone
        $hashMap=@{
            '2702'=0 #ActiveX controls and plug-ins: Allow ActiveX Filtering = Enable (2702)
            '1208'=0 #ActiveX controls and plug-ins: Allow previously unused ActiveX controls to run without prompt = Enable (1208)
            '1209'=0 #ActiveX controls and plug-ins: Allow Scriptlets = Enable (1209)
            '2201'=3 #ActiveX controls and plug-ins: Automatic prompting for ActiveX controls = Disable (2201)
            '2000'=0 #ActiveX controls and plug-ins: Binary and script behaviors = Enable (2000)
            '120A'=0 #Display video and animation on a webpage that does not use external media player = Enable (120A)
            '1001'=0 #ActiveX controls and plug-ins: Download signed ActiveX controls = Enable (1001)
            '1004'=0 #ActiveX controls and plug-ins: Download unsigned ActiveX controls = Enable (1004)
            '1201'=0 #ActiveX controls and plug-ins: Initialize and script ActiveX controls not marked as safe for scripting = Enable (1201)
            '120B'=3 #Only allow approved domains to use ActiveX without prompt = Disable (120B)
            '1200'=0 #ActiveX controls and plug-ins: Run ActiveX controls and plug-ins = Enable (1200)
            '1405'=0 #ActiveX controls and plug-ins: Script ActiveX controls marked as safe for scripting = Enable (1405)
            }        
        
        $trustedDomains="HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings\zones\$zoneCode"
        $currentValues=Get-ItemProperty $trustedDomains
        foreach ($item in $hashMap.GetEnumerator()) {
            $key = $item.Key
            $value = $item.Value
            if($currentValues.$key -ne $value){
                    New-ItemProperty -Path $trustedDomains -Name $key -Value $value -PropertyType DWORD -Force
                }
        }
    }

    function addDomainToTrustedSites($url){
        $httpType=.{[void]($url -match '^(https{0,1})');$matches[1]}
        $domain=([uri]$url).Host
        #$rootDomain=$domain.split('.')[-2..-1] -join '.' # This is assuming that the TLD is one-dotted (e.g. .com) not two-dotted (e.g. co.uk)
        $rootDomain=.{$fragments=$domain.split('.')
                    $fragments[1..$($fragments.count)] -join '.'
                    }
        write-host "Root domain detected`t: $rootDomain"        
        # The more advanced function to retrieve this value is at https://blog.kimconnect.com/powershell-extract-root-domain-from-url/
        if ($rootDomain -notmatch '\.' -or $rootDomain -eq $env:USERDNSDOMAIN){
            write-host "There's no need to add $url to the Trusted zone as it is local to this domain."
            return $true
            }
        $dwordValue=2 # value of true correlates to 'enable'
        $domainRegistryPath='HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\Domains'
        $domainRegistryPath2='HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\EscDomains' #EscDomains key applies to those protocols that are affected by the Enhanced Security Configuration (ESC)
        $null=New-Item -Path 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap' -ItemType File -Name 'EscDomains' -Force
        $null=New-Item -Path "$domainRegistryPath" -ItemType File -Name "$rootDomain" -Force
        $null=New-Item -Path "$domainRegistryPath2" -ItemType File -Name "$rootDomain" -Force
        $null=Set-ItemProperty -Path "$domainRegistryPath\$rootDomain" -Name $httpType -Value $dwordValue
        $null=Set-ItemProperty -Path "$domainRegistryPath2\$rootDomain" -Name $httpType -Value $dwordValue

        # Also add {about:blank} record as that doesn't seem to have been added by default
        if (!(test-path "$domainRegistryPath\blank")){
            #New-ItemProperty -Path $trustedDomains -Name $key -Value $value -PropertyType DWORD -Force
            $null=New-Item -Path "$domainRegistryPath" -ItemType File -Name 'blank'
            $null=Set-ItemProperty -Path "$domainRegistryPath\blank" -Name 'about' -Value $dwordValue
            }
        if (!(test-path "$domainRegistryPath2\blank")){
            $null=New-Item -Path "$domainRegistryPath2" -ItemType File -Name 'blank'
            $null=Set-ItemProperty -Path "$domainRegistryPath2\blank" -Name 'about' -Value $dwordValue
            }                     

        # Also add {about:internet} record since it will stop a login when missing
        if (!(test-path "$domainRegistryPath\internet")){
            $null=New-Item -Path "$domainRegistryPath" -ItemType File -Name 'internet'
            $null=Set-ItemProperty -Path "$domainRegistryPath\internet" -Name 'about' -Value $dwordValue
            }
        if (!(test-path "$domainRegistryPath2\internet")){
            $null=New-Item -Path "$domainRegistryPath2" -ItemType File -Name 'internet'
            $null=Set-ItemProperty -Path "$domainRegistryPath2\internet" -Name 'about' -Value $dwordValue
            } 
            
        $valueAfterChanged=(Get-ItemProperty "$domainRegistryPath\$rootDomain")."$httpType"
        $value2AfterChanged=(Get-ItemProperty "$domainRegistryPath2\$rootDomain")."$httpType"
        if ($valueAfterChanged -eq 2 -and $value2AfterChanged -eq 2 ){
            write-host "$rootDomain has been added to Internet Explorer"
            return $true
            }
        else{
            write-warning "$rootDomain has NOT been added to Internet Explorer."
            return $false
            }
    }

    function includeSelenium{
        Import-Module Selenium -ea SilentlyContinue
        if (!(get-module selenium -EA SilentlyContinue)){
            Start-job {
                [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
                if(!(Get-PackageProvider Nuget -ea SilentlyContinue)){Install-PackageProvider -Name NuGet -Force}
                # Defining $ENV:ChocotaleyInstall so that it would be called by refreshenv
                $ENV:ChocolateyInstall = Convert-Path "$((Get-Command choco).Path)\..\.."   
                Import-Module "$env:ChocolateyInstall\helpers\chocolateyProfile.psm1"
                Install-Module Selenium -Force -Confirm:$False
                } |Receive-Job -Wait
            Update-SessionEnvironment
            Import-Module Selenium
            }
        }

    function invokeSelenium($url,$userName,$password,$usernameElementId,$passwordElementId,$submitButtonId){
        $ErrorActionPreference = "Stop"
        function closeSelenium($selenium){
            if($selenium){
                $selenium.close()
                $selenium.quit()
                }
            }
        
        function noLogin($url){
            $seleniumIe = New-Object "OpenQA.Selenium.IE.InternetExplorerDriver"
            $seleniumIe.Navigate().GoToURL($url)
            $title=$seleniumIe.Title
            write-host "Page reached: '$title'"
            $trustedSiteError=$title -match '^Error'
            if($trustedSiteError){
                write-host "An site trust issue has been detected. Adding root domain to the trusted sites list to resolve this issue."
                addDomainToTrustedSites $url              
                closeSelenium $seleniumIe                
                return $false
                }
            else{
                return $seleniumIe                
                }
            }

        function login($url,$username,$password,$usernameElementId,$passwordElementId,$submitButtonId){
            $seleniumIe = New-Object "OpenQA.Selenium.IE.InternetExplorerDriver"
            $seleniumIe.Navigate().GoToURL($url)
            $userField=$seleniumIe.FindElementById($usernameElementId)
            $userField.clear()
            $userField.SendKeys($username)
            $passwordField=$seleniumIe.FindElementById($passwordElementId)
            $passwordField.SendKeys('')
            $passwordField.clear()           
            $passwordField.SendKeys($password)
            $submitButton=$seleniumIe.FindElementById($submitButtonId)
            $submitButton.Click()
            $title=$seleniumIe.Title
            write-host "Page reached: '$title'"
            $trustedSiteError=$title -match '^Error'
            if($trustedSiteError){
                write-warning "A site trust issue has been detected."                
                closeSelenium $seleniumIe                
                return $false
            }else{
                return $seleniumIe                
                }
            }
        
        try{
            $null=allowActiveX
            $isLogin=$userName,$password,$usernameElementId,$passwordElementId,$submitButtonId|?{!(!$_)}
            if($isLogin){
                write-host "Login to $url as $userName..."
                $ie=login $url $userName $password $usernameElementId $passwordElementId $submitButtonId
            }else{
                write-host "Accesing $url without login..."
                $ie=nologin $url
                }
            return $ie
            }
        catch{            
            Write-Warning $Error[0].Exception.Message
            return $false
            }
        }

    try{
        write-host "Username`t: $username`r`nPassword`t: $(!(!$password))`r`nusernameElementId`t: $usernameElementId`r`npasswordElementId`t: $passwordElementId`r`nsubmitButtonId`t: $submitButtonId"
        $null=includeSelenium
        $null=disableIeProtectedMode
        $null=addDomainToTrustedSites $url                   
        if(get-module selenium -ea SilentlyContinue){
            $isLogin=$userName,$password,$usernameElementId,$passwordElementId,$submitButtonId|?{!(!$_)}
            if($isLogin){                
                $selenium=invokeSelenium $url $userName $password $usernameElementId $passwordElementId $submitButtonId
            }else{
                write-host "No username or password are given. Proceeding to access only the provided URL."
                $selenium=invokeSelenium $url
                }
        }else{
            write-warning "Please manually verify that the Selenium module is installed before retrying this function."
            }
        if($selenium){            
            if($exitIeWhenDone){
                $null=killInternetExplorer
                return $true
            }else{
                return $selenium
                }
        }else{
            write-warning "There were errors preventing a successful login."
            return $false
            }
        }
    catch {
        write-warning "$_"        
        return $false
        }
    
    # Note on a common error:
    #New-Object : Exception calling ".ctor" with "0" argument(s): "Unexpected error launching Internet Explorer. Protected
    #Mode settings are not the same for all zones. Enable Protected Mode must be set to the same value (enabled or
    #disabled) for all zones. (SessionNotCreated)"
    #At line:1 char:15
    #+ $seleniumIe = New-Object "OpenQA.Selenium.IE.InternetExplorerDriver"
    #+               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    #    + CategoryInfo          : InvalidOperation: (:) [New-Object], MethodInvocationException
    #    + FullyQualifiedErrorId : ConstructorInvokedThrowException,Microsoft.PowerShell.Commands.NewObjectCommand
    # Solution: either DISABLE or ENABLE Protected mode for ALL ZONES
}

$ie=autoLoginSe $url $username $password

Deprecated version:

# Version 0.0.1 - function to return true or false, and close IE afterward
function autologinSe{
    param(
        $url,
        $username,
        $password,
        $usernameElementId='userNameInput',
        $passwordElementId='passwordInput',
        $submitButtonId='submitButton'
    )
    $ErrorActionPreference = "Stop"

    function killInternetExplorer{
        $ieInstances=(New-Object -COM 'Shell.Application').Windows()|?{$_.Name -like '*Internet Explorer*'} 
        $ieInstances|%{$_.Quit()
        [Runtime.Interopservices.Marshal]::ReleaseComObject($_)
        }
        [GC]::Collect()
        [GC]::WaitForPendingFinalizers()
        }

    try{
        killInternetExplorer|out-null
        if (!(get-module selenium -EA SilentlyContinue)){
            [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
            Install-Module Selenium -Force
            }
        Import-Module Selenium
        $seleniumIe = New-Object "OpenQA.Selenium.IE.InternetExplorerDriver"
        $seleniumIe.Navigate().GoToURL($url)
        $userField=$seleniumIe.FindElementById($usernameElementId)
        $userField.SendKeys($username)
        $passwordField=$seleniumIe.FindElementById($passwordElementId)
        $passwordField.SendKeys($password)
        $submitButton=$seleniumIe.FindElementById($submitButtonId)
        $submitButton.Click()
        $title=$seleniumIe.Title
        write-host "Page reached: '$title'"
        $seleniumIe.close()
        $seleniumIe.quit()
        $not404=$title -notmatch '^404|^Error'
        if($not404){return $true}
        else{return $false}
        }
    catch{
        write-warning "$($error[0])"
        return $false
        }
    # Troubleshooting:
    #New-Object : Exception calling ".ctor" with "0" argument(s): "Unexpected error launching Internet Explorer. Protected
    #Mode settings are not the same for all zones. Enable Protected Mode must be set to the same value (enabled or
    #disabled) for all zones. (SessionNotCreated)"
    #At line:1 char:15
    #+ $seleniumIe = New-Object "OpenQA.Selenium.IE.InternetExplorerDriver"
    #+               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    #    + CategoryInfo          : InvalidOperation: (:) [New-Object], MethodInvocationException
    #    + FullyQualifiedErrorId : ConstructorInvokedThrowException,Microsoft.PowerShell.Commands.NewObjectCommand
    # Solution: either DISABLE or ENABLE Protected mode for ALL ZONES
}
autoLoginSe $url $username $password
# Troubleshooting:
#New-Object : Exception calling ".ctor" with "0" argument(s): "Unexpected error launching Internet Explorer. Protected
#Mode settings are not the same for all zones. Enable Protected Mode must be set to the same value (enabled or
#disabled) for all zones. (SessionNotCreated)"
#At line:1 char:15
#+ $seleniumIe = New-Object "OpenQA.Selenium.IE.InternetExplorerDriver"
#+               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#    + CategoryInfo          : InvalidOperation: (:) [New-Object], MethodInvocationException
#    + FullyQualifiedErrorId : ConstructorInvokedThrowException,Microsoft.PowerShell.Commands.NewObjectCommand
# Solution: either DISABLE or ENABLE Protected mode for ALL ZONES

Leave a Reply

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

Related Post

PowerShell: Windows Automated Disk Cleanup

##################################################################################     <#      This script is created to automate the cleanup activity. Doing so will benefit to reduce the size of disk.     This script will perform the following   1. Clear windows temp and user temp folder   2. Empty recycle bin   3. Disk Cleanup   4. Clear CBS cabinet log files   5. Clear downloaded patches   6. Clear downloaded driver   7. Clean download folder      Note:  …

Random Notes about WSUS

#Install the PowerShell Windows Update module $checkModule=Get-Module -ListAvailable -Name PSWindowsUpdate if(!($checkModule)){ [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 #…

PowerShell: Setting Windows Pagefile

# setPageFile.ps1 # Source: # Reposting here as such code seems to be open source…