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 2.8.5.201 -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 🙂

Use TOR proxy with any linux command

There is an easy way to use the The Onion Router for any command under linux

First install TOR and proxychains4

$ sudo apt install tor proxychains4

You can configure proxychains.conf but the default config is good 🙂

$ sudo nano /etc/proxychains.conf

Then start the tor service

$ sudo systemctl start tor

And check your ip:

$ proxychains4 curl ifconfig.me

You can use any command you want. So if you want your firefox browser over tor:

$ proxychains4 firefox

To refresh your TOR IP simply restart the TOR service

Happy proxying 🙂

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
}
ELSE
{
    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
    }
ELSE
{
    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
.\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.Clear()
$psISE.CurrentPowerShellTab.AddOnsMenu.Submenus.Add("Switch to PowerShell 7", { 
        function New-OutOfProcRunspace {
            param($ProcessId)
  
            $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)
  
            $Runspace.Open()
            $Runspace
        }
  
        $PowerShell = Start-Process PWSH -ArgumentList @("-NoExit") -PassThru -WindowStyle Hidden
        $Runspace = New-OutOfProcRunspace -ProcessId $PowerShell.Id
        $Host.PushRunspace($Runspace)
}, "ALT+F5") | Out-Null
  
$psISE.CurrentPowerShellTab.AddOnsMenu.Submenus.Add("Switch to PowerShell 5", { 
    $Host.PopRunspace()
  
    $ChildProc = Get-CimInstance -ClassName win32_process | where {$_.ParentProcessId -eq $Pid}
    $ChildProc | ForEach-Object { Stop-Process -Id $_.ProcessId }
  
}, "ALT+F6") | Out-Null

Happy coding!

Repair Debian boot after Windows update

Today I update my dual boot system and unfortunately my Debian OS wasn’t booting anymore. The root cause was that Windows decide to reclaim the EFI boot.

The fix is quite easy.

Type mountvol P: /S

Check the EFI boot partition data

And fix your boot the this command:

bcdedit.exe /set {bootmgr} path \EFI\Debian\grubx64.efi

As you can see in the screenshot, this also work for EndeavourOS and Ubuntu and probably for a lot other Linux EFI boot systems.

Happy booting!

Corrupt SD Card Recovery

A friend of mine came back from vacation where he had taken a lot of pictures. When he got back home a large part of his Micro SD card (exFAT partition) was no longer accessible so he missed a couple of weeks of his photos and videos. His Windows Operating System froze completely when it hit a rotten cluster during a file copy action. So we had to find another solution to get his files back.

The first step I tried was to get the data from the SD card via Linux with ddrescue. With ddrecue, you create and complete dump of the SD card (or the sdb1 partition only). So you can do the data recovery on the image file (backup1.img) and not on the already corrupted SD Card.

The command you can use is:

ddrescue -d /dev/sdb1 /media/thomas/backup1.img /media/thomas/backup1.mapfile

But Linux also had also trouble reading when I hit a bad cluster. The only thing I could do during the read issues was a physical disconnect of the USB adapter, reconnect the adapter and restart the ddrescue process. The reason of was that a dual SD card adapter was used:

Micro SD > SD > SD > USB

(spoiler ALERT!: Never use multiple adapters for data recovery!!!)

Because ddrescue has a mapfile it goes further where he was stopped the last time.

While debugging I wrote a simple loop that forced a “physical” disconnection of the USB adapter wait one sec and reconnect the devices without touching anything.

Source of the USBReset (fork)

This works but is a very very slow process. This will takes months to recover so I had to find another way.

#!/bin/bash
## Steps to Prepare:
# lsusb check card reader and change the /dev/bus
# Start script in usbreset folder 
# Run as sudo
# mount disk (media / thomas)
while true
do
	echo "Let's try Again!"
	ddrescue -d /dev/sdb1 /media/thomas/4905eb31-1df4-49bb-bb75-ec4889641d20/backup1.img /media/thomas/4905eb31-1df4-49bb-bb75-ec4889641d20/backup1.mapfile
	sleep 1
	./usbreset /dev/bus/usb/001/004
	sleep 1
done

The funny thing is that it was Sinterklaas time and that my daughter had just received a vtech kiddy photo camera with a Micro SD to USB adapter included 😀

So I try new new adapter: Micro SD > USB and with success.

And after almost 15 hours the result 99.98% rescued rate 🙂

During my search for a solution I found some interesting articles:

Happy recovering!

Git SFTP

I was working for an elementary website of a friend of mine. I pushed the website to GitHub so it’s was way easier to maintain the site.

But I thought it must be easier than transferring all the changes every time by an FTP program. So I found git-ftp and of course FTPS didn’t work out of the box 😉

Windows

What you have to do to enable GIT FTP (on Windows)

First start an ssh sessions from powershell

ssh [email protected]

This will add the public key to you known host. Otherwise you will get this error later

fatal:  Can't access remote 'sftp://SOMEUSER:***@SOMEHOSTNAME'. Network down? Wrong URL? exiting...

You can see this with the -vv parameter

git ftp init -vv

Now it’s time to install git-ftp

  • First go to c:\program files\git
  • Then run git-bash as administrator

And install git-ftp (bin is an alias for program files)

$ curl https://raw.githubusercontent.com/git-ftp/git-ftp/master/git-ftp > /bin/git-ftp
$ chmod 755 /bin/git-ftp

No go to your project and enter these commands

git config git-ftp.user SOMEUSERNAME
git config git-ftp.url sftp://SOMEHOSTNAME/public/sites/SOMEWEBSITE/
git config git-ftp.password SOMEPASSWORD
git ftp init

And the next time you make a change you only have to do

git ftp push

Linux (Debian)

For linux the steps are much easier.

First start an ssh sessions from bash

ssh [email protected]

This will add the public key to you known host. Otherwise you will a error later.

Now install ftp-git

$ sudo apt install git-ftp

No go to your project and enter these commands

git config git-ftp.user SOMEUSERNAME
git config git-ftp.url sftp://SOMEHOSTNAME/public/sites/SOMEWEBSITE/
git config git-ftp.password SOMEPASSWORD
git ftp init

And the next time you make a change you only have to do

git ftp push

When you get an errors like these:

zo 19 dec 2021 23:11:50 CET: Retrieving last commit from sftp://******:***@s*******/public/sites/*********/.
*   Trying *********:22...
* Connected to ******* (********) port 22 (#0)
* Found host ******** in /home/******/.ssh/known_hosts
* Set "ecdsa-sha2-nistp256" as SSH hostkey type
* Closing connection 0
curl: (79) Error in the SSH layer

zo 19 dec 2021 23:11:50 CET: fatal: Could not get last commit. Use 'git ftp init' for the initial push. Can't access remote 'sftp://******:***@********'. Network down? Wrong URL? exiting..

Then try the --insecure parameter

git ftp push -vv --insecure

Happy uploading 🙂