Use PowerShell Invoke-WebRequest to login on a website

To automate some tasks with PowerShell on a website you sometimes need to log in. Today I tried some curl and postman tricks but it isn’t hard if you know what to script with PowerShell and bypass all other tools.

First, find a website to log in to, then check the page source and what the submit button does. In this example, it is β€œInloggen” (dutch for login).

Then start the developer tools (F12), select the network tab, enter the credentials and login.

Now check the POST request in the developer tools.

The important things on this login form are:

  • Gebruikersnaam (username)
  • Wachtwoord (password)
  • __RequestVerificationToken

Now we can write a simple script

$LoginUri = ""
$BackendUri = ""
# ==========================================
$LoginResponse = Invoke-WebRequest -Uri $LoginUri -SessionVariable "Session" 
$LoginBody = @{
    __RequestVerificationToken = $LoginResponse.InputFields[1].value
    Gebruikersnaam             = "EnterUsername"
    Wachtwoord                 = "EnterPassword"
    Submit                     = "Inloggen"
$LoginResponse = Invoke-WebRequest -Uri $LoginUri -WebSession $Session -Body $LoginBody -Method "POST"

Invoke-WebRequest -Uri $BackendUri -WebSession $Session 

Explanation of the script:

  1. Open the website and find out what the __RequestVerificationToken must be
  2. Create a body with the credentials, the login form submit and the __RequestVerificationToken
  3. Do the actual login and save the web session (cookies and stuff).
  4. Now we can use the previous web session to check all the backend stuff

Happy Scripting πŸ™‚

Update Windows Server with powershell

This is for 2016 server. But it will work for other versions of Windows

[Net.ServicePointManager]::SecurityProtocol += [Net.SecurityProtocolType]::Tls12
Install-PackageProvider -Name NuGet -MinimumVersion -Force
Set-PSRepository -Name "PSGallery" -InstallationPolicy Trusted
Install-Module PSWindowsUpdate -Confirm:$false
Set-PSRepository -Name "PSGallery" -InstallationPolicy Untrusted
Get-WindowsUpdate -AcceptAll -Install -AutoReboot

Happy Patching πŸ™‚

Configure WSUS client with Powershell and Regedit

My use case for a customer was to configure WSUS for a couple of DMZ servers. The DMZ servers are not domain-joined. So I create a PowerShell script to configure the registry so I can easily deploy the settings to the servers.

You can use this script also for non domain-joined servers

# Script for WSUS configuration on non-domain joined servers

# First stop the Windows service
Get-Service -name wuauserv | stop-service

# Variables
$registryPath = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate"
$name1 = "TargetGroup"
$value1 = "Production"
$name2 = "WUServer"
$value2 = "http://wsus.domain.local:8530"
$name3 = "WUStatusServer"
$value3 = "http://wsus.domain.local:8530"
$name4 = "DoNotConnectToWindowsUpdateInternetLocations"
$value4 = "1"
$name5 = "TargetGroupEnabled"
$value5 = "1"
$registryPathAU = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU"
$nameAU1 = "AUOptions"
$valueAU1 = "3"
$nameAU2 = "UseWUServer"
$valueAU2 = "1"

# Inject registry
IF(!(Test-Path $registryPath))
    New-Item -Path $registryPath -Force | Out-Null
    New-ItemProperty -Path $registryPath -Name $name1 -Value $value1 -Force | Out-Null
    New-ItemProperty -Path $registryPath -Name $name2 -Value $value2 -Force | Out-Null
    New-ItemProperty -Path $registryPath -Name $name3 -Value $value3 -Force | Out-Null
    New-ItemProperty -Path $registryPath -Name $name4 -Value $value4 -PropertyType DWORD -Force | Out-Null
    New-ItemProperty -Path $registryPath -Name $name5 -Value $value5 -PropertyType DWORD -Force | Out-Null
    New-ItemProperty -Path $registryPath -Name $name1 -Value $value1 -Force | Out-Null
    New-ItemProperty -Path $registryPath -Name $name2 -Value $value2 -Force | Out-Null
    New-ItemProperty -Path $registryPath -Name $name3 -Value $value3 -Force | Out-Null
    New-ItemProperty -Path $registryPath -Name $name4 -Value $value4 -PropertyType DWORD -Force | Out-Null
    New-ItemProperty -Path $registryPath -Name $name5 -Value $value5 -PropertyType DWORD -Force | Out-Null
IF(!(Test-Path $registryPathAU))
    New-Item -Path $registryPathAU -Force | Out-Null
    New-ItemProperty -Path $registryPathAU -Name $nameAU1 -Value $valueAU1 -PropertyType DWORD -Force | Out-Null
    New-ItemProperty -Path $registryPathAU -Name $nameAU2 -Value $valueAU2 -PropertyType DWORD -Force | Out-Null
    New-ItemProperty -Path $registryPathAU -Name $nameAU1 -Value $valueAU1 -PropertyType DWORD -Force | Out-Null
    New-ItemProperty -Path $registryPathAU -Name $nameAU2 -Value $valueAU2 -PropertyType DWORD -Force | Out-Null

# Start the Windows service
Get-Service -name wuauserv | start-service

# Find updates and report to the WSUS server
$updateSession = new-object -com "Microsoft.Update.Session"; $updates=$updateSession.CreateupdateSearcher().Search($criteria).Updates
Start-sleep -seconds 10
wuauclt /detectnow
wuauclt /reportnow
c:\windows\system32\UsoClient.exe startscan

I save this file on the WSUS server itself at http://wsus.domain.local:8530/script.txt so I can download and run it from the DMZ environment.

invoke-webrequest -uri http://wsus.domain.local:8530/script.txt -outfile script.ps1

Happy updating πŸ™‚

Powershell better tab autocomplete

With Powershell ISE you can use CTRL + SPACE for auto completion.

Powershell ISE Completion

But when you work in a native Powershell window you don’t have this option. And many often you cycle with tab completion trough the powershell and because you press the TAB button too soon you have to remove characters and cycle again trough all the commands.

Unit now πŸ˜‰

There is an easy fix you can implement so the Powershell have the same auto completion like bash.

  • Type notepad $profile for Windows or gedit $profile for Linux
  • Add the line Set-PSReadlineKeyHandler -Key Tab -Function MenuComplete
Add line in $profile
  • Save the file and restart Powershell
  • And now you have a much better working tab completion
Linux Example
Windows Example

Happy coding πŸ™‚

Add Powershell 7 to your Powershell ISE

I find this code snippet somewhere on the internet and I like it πŸ™‚

Swtich Powershell version in ISE

Just open ISE and paste these code and you are ready to rock!

$ErrorActionPreference= 'silentlycontinue'
$psISE.CurrentPowerShellTab.AddOnsMenu.Submenus.Add("Switch to PowerShell 7", { 
        function New-OutOfProcRunspace {
            $ConnInfo = New-Object -TypeName System.Management.Automation.Runspaces.NamedPipeConnectionInfo -ArgumentList @($ProcessId)
            $DefaultType = [System.Management.Automation.Runspaces.TypeTable]::LoadDefaultTypeFiles()
            $Runspace = [System.Management.Automation.Runspaces.RunspaceFactory]::CreateRunspace($ConnInfo, $Host, $Default)
        $PowerShell = Start-Process PWSH -ArgumentList @("-NoExit") -PassThru -WindowStyle Hidden
        $Runspace = New-OutOfProcRunspace -ProcessId $PowerShell.Id
}, "ALT+F5") | Out-Null
$psISE.CurrentPowerShellTab.AddOnsMenu.Submenus.Add("Switch to PowerShell 5", { 
    $ChildProc = Get-CimInstance -ClassName win32_process | where {$_.ParentProcessId -eq $Pid}
    $ChildProc | ForEach-Object { Stop-Process -Id $_.ProcessId }
}, "ALT+F6") | Out-Null

Happy coding!

Create Azure Linux VM with worpress pre-installed

This is my first completed automated Linux Azure VM deployment. I like to share it with you.

There are 3 parts

  1. Create a keygen for ssh
  2. Powershell script
  3. Bash script

First start powershell and create a keypair with passphase

ssh-keygen -m PEM -t rsa -b 4096

Then place the bash script somewhere on your local computer

#! /bin/bash
apt-get update
apt-get install -y wordpress php libapache2-mod-php mysql-server php-mysql

echo "Alias /blog /usr/share/wordpress" >>/etc/apache2/sites-available/wordpress.conf
echo "<Directory /usr/share/wordpress>" >>/etc/apache2/sites-available/wordpress.conf
echo "    Options FollowSymLinks" >>/etc/apache2/sites-available/wordpress.conf
echo "    AllowOverride Limit Options FileInfo" >>/etc/apache2/sites-available/wordpress.conf
echo "    DirectoryIndex index.php" >>/etc/apache2/sites-available/wordpress.conf
echo "    Order allow,deny" >>/etc/apache2/sites-available/wordpress.conf
echo "    Allow from all" >>/etc/apache2/sites-available/wordpress.conf
echo "</Directory>" >>/etc/apache2/sites-available/wordpress.conf
echo "<Directory /usr/share/wordpress/wp-content>" >>/etc/apache2/sites-available/wordpress.conf
echo "    Options FollowSymLinks" >>/etc/apache2/sites-available/wordpress.conf
echo "    Order allow,deny" >>/etc/apache2/sites-available/wordpress.conf
echo "    Allow from all" >>/etc/apache2/sites-available/wordpress.conf
echo "</Directory>" >>/etc/apache2/sites-available/wordpress.conf

a2ensite wordpress
a2enmod rewrite 
reload apache2 
service apache2 reload
systemctl restart apache2

mysql -e "CREATE DATABASE wordpress;"
mysql -e "CREATE USER wordpress@localhost IDENTIFIED BY 'Secret@Pass1';"
mysql -e "GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP,ALTER ON wordpress.* TO wordpress@localhost;"

echo "<?php" >>/etc/wordpress/config-localhost.php
echo "define('DB_NAME', 'wordpress');">>/etc/wordpress/config-localhost.php
echo "define('DB_USER', 'wordpress');">>/etc/wordpress/config-localhost.php
echo "define('DB_PASSWORD', 'Secret@Pass1');">>/etc/wordpress/config-localhost.php
echo "define('DB_HOST', 'localhost');">>/etc/wordpress/config-localhost.php
echo "define('DB_COLLATE', 'utf8_general_ci');">>/etc/wordpress/config-localhost.php
echo "define('WP_CONTENT_DIR', '/usr/share/wordpress/wp-content');">>/etc/wordpress/config-localhost.php
echo "?>">>/etc/wordpress/config-localhost.php

service mysql start

publicip=$(dig +short && mv /etc/wordpress/config-localhost.php /etc/wordpress/config-$publicip.php

Then put the code in the Powershell ISE, change some variables and kickoff the script.

The things you may need to change:

  • location

New-AzResourceGroup -Name lxautodeploy -Location westeurope

# Create a subnet configuration
$subnetConfig = New-AzVirtualNetworkSubnetConfig `
  -Name "mySubnet" `

# Create a virtual network
$vnet = New-AzVirtualNetwork `
  -ResourceGroupName "lxautodeploy" `
  -Location "westeurope" `
  -Name "myVNET" `
  -AddressPrefix `
  -Subnet $subnetConfig

# Create a public IP address and specify a DNS name
$pip = New-AzPublicIpAddress `
  -ResourceGroupName "lxautodeploy" `
  -Location "westeurope" `
  -AllocationMethod Static `
  -IdleTimeoutInMinutes 4 `
  -Name "mypublicdns$(Get-Random)"

# Create an inbound network security group rule for port 22
$nsgRuleSSH = New-AzNetworkSecurityRuleConfig `
  -Name "myNetworkSecurityGroupRuleSSH"  `
  -Protocol "Tcp" `
  -Direction "Inbound" `
  -Priority 1000 `
  -SourceAddressPrefix * `
  -SourcePortRange * `
  -DestinationAddressPrefix * `
  -DestinationPortRange 22 `
  -Access "Allow"

# Create an inbound network security group rule for port 80
$nsgRuleWeb = New-AzNetworkSecurityRuleConfig `
  -Name "myNetworkSecurityGroupRuleWWW"  `
  -Protocol "Tcp" `
  -Direction "Inbound" `
  -Priority 1001 `
  -SourceAddressPrefix * `
  -SourcePortRange * `
  -DestinationAddressPrefix * `
  -DestinationPortRange 80 `
  -Access "Allow"

# Create a network security group
$nsg = New-AzNetworkSecurityGroup `
  -ResourceGroupName "lxautodeploy" `
  -Location "westeurope" `
  -Name "myNetworkSecurityGroup" `
  -SecurityRules $nsgRuleSSH,$nsgRuleWeb

  # Create a virtual network card and associate with public IP address and NSG
$nic = New-AzNetworkInterface `
  -Name "myNic" `
  -ResourceGroupName "lxautodeploy" `
  -Location "westeurope" `
  -SubnetId $vnet.Subnets[0].Id `
  -PublicIpAddressId $pip.Id `
  -NetworkSecurityGroupId $nsg.Id

  # Define a credential object
$securePassword = ConvertTo-SecureString ' ' -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential ("azureuser", $securePassword)

# Create a virtual machine configuration
$vmConfig = New-AzVMConfig `
  -VMName "myLXVM" `
  -VMSize "Standard_D2s_v3" | `
Set-AzVMOperatingSystem `
  -Linux `
  -ComputerName "myLXVM" `
  -Credential $cred `
  -DisablePasswordAuthentication | `
Set-AzVMSourceImage `
  -PublisherName "Canonical" `
  -Offer "UbuntuServer" `
  -Skus "18.04-LTS" `
  -Version "latest" | `
Add-AzVMNetworkInterface `
  -Id $nic.Id

# Configure the SSH key
$sshPublicKey = cat ~/.ssh/
Add-AzVMSshPublicKey `
  -VM $vmconfig `
  -KeyData $sshPublicKey `
  -Path "/home/azureuser/.ssh/authorized_keys"

New-AzVM `
  -ResourceGroupName "lxautodeploy" `
  -Location westeurope -VM $vmConfig

Get-AzPublicIpAddress -ResourceGroupName "lxautodeploy" | Select "IpAddress"

Invoke-AzVMRunCommand -ResourceGroupName "lxautodeploy" -Name 'myLXVM' -CommandId 'RunShellScript' -ScriptPath "" -Verbose

Now you can go to http://<publicip>/blog to access the new blog

You can access the server with ssh azureuser@<publicip>

Have fun with it!