The following script allows you to modify PuTTY sessions in a batch.
Category: PowerShell
-
Prevent explorer from automatically restarting
For certain actions it is required that the Windows Explorer is stopped in order to avoid open file handles or other actions that can be done while the Explorer is running. Windows is configured to restart the Explorer automatically when its process is terminated. I wrote a small PowerShell script that checks the current setting, disables it if necessary, kills the process and then restarts it and optionally restores the setting if it was set in the first place. You can find it here:
This script has to be executed with administrator privileges as it changes values in the system wide part of the registry.
-
Automated Eclipse downloader
I work with Eclipse a lot and to download a new version, which comes out 4 times a year, I use the following script. It can be executed with PowerShell and does not require Java to be installed on the system because it downloads the OpenJDK version itself. Eclipse can then be found in the folder “eclipse_out” and Java in “java_out”.
Why this script? Because it also installs all the plugins I need. For example “Spring tool suite”, “SonarLint”, “Buildship” and many more.
-
Automate with ssh
Scenario
I have a bunch of Linux hosts to perform actions on. Updates, certificates, cleanup, you name it. I do all my work over “ssh” but for that to work the hosts must be trusted. Of course I can use “ssh-keyscan” to get the keys but my own “known_hosts” file gets pretty messed up when I add all the keys there. I would like to use a temporary solution. The best would be a parallel temporary solution so that I can handle a lot of hosts at once. Fortunately PowerShell allows such a thing. In this example the host has the name “4ab586fc-9a23-49eb-8d81-f2ca021203aa” (I really love GUIDs) and the full domain name would be “4ab586fc-9a23-49eb-8d81-f2ca021203aa.example.com”. Keeping this in mind the script that gets the key, performs the action (a simple “ls”) and deletes the key would look like this:
Start-Job -ScriptBlock { $Uuid = "4ab586fc-9a23-49eb-8d81-f2ca021203aa" $Domain = "$Uuid.example.com" ssh-keyscan "$Domain" >> "$Uuid.known_host" ssh -o UserKnownHostsFile="$Uuid.known_host" root@"$Domain" "ls" >> "$Uuid.output" Remove-Item -Path "$Uuid.known_host" }
The catch here is, that the servers public key is temporary stored in a local file instead of the users “known_hosts” file and then referenced with the parameter “-o UserKnownHostsFile=$Uuid.known_host” in the ssh command. After completion the file is then removed and the access to the server was a success. Running this in a loop allows the execution of tasks on multiple servers at the same time.
-
Escaping in shells
First things first: A string with spaces is enclosed in either single quotes ‘ or double quotes “. The difference you ask? Single quotes are treated “as is”: No variable replacement, no parsing, just a string. If you want to embed a variable value, you have to concatenate the string. Period. Double quotes allow dynamic values via variables:
NAME="Andreas" echo "The name is $NAME" # Output: The name is Andreas
This would print my name in the echo line.
Okay, so now what if you need a quote in a echo line? Exactly, the same that is used to initiate and terminate the string? Well, you have to escape it. Let me make this clear: We are still working on a default Linux Bash now. Double quotes are relatively easy:
echo "A string with a \" is fine." # Output: A string with a " is fine.
Same goes for variables:
NAME="Name with a \" character." echo "Value: $NAME" # Output: Value: Name with a " character.
Single quotes are a little more tricky:
echo $'String with a \' in it.' # Output: String with a ' in it.
And as a variable:
NAME=$'Name with a \' in it.' echo 'Value: '$NAME # Output: Value: Name with a ' in it.
Okay, so now you can have quotes in strings that are framed by the same quotes. This is the beginning and I’d start practicing this for bash. I will continue this tutorial with PowerShell embedding:
Write-Host "A string containing a `" character." # Output: A string containing a " character.
As you can see, the escaping character is different from bash: PowerShell uses a ` to escape newline (`n) or quotes (`”).
As we all know, MS is known for their consistency. Single quotes are treated differently:
Write-Host 'A string containing a '' character.' # Output: A string containing a ' character.
Isn’t that awesome?
So why am I explaining this?
Try to imagine the following scenario: You are working on a Windows-Machine (with PowerShell) and would like to run a command via SSH (basically a Linux tool) on a remote Linux server that runs BaSH. I’d suggest working from bottom (the command on the Linux server) to top (the command being written in the PowerShell environment). First execute it on Bash, then via SSH and finally embed it in the PowerShell command. This way you always know on which level you are and which escapes you are going to need.
I will continue this tutorials because this always gave me a headache. Especially considering variables parsed on the executing host, the remote machine or coming from a command line. One has to work very concentrated here and always visualize where a certain part of a command is executed.
-
Check if remote database exists
Escaping in PowerShell or in any other scripting language is not that much fun to begin with. So if you have quotes in quotes on different shells in different systems it becomes really funny. So trust me, I am more than surprised that I just found a neat way to check, if a database exists on a remote host with PowerShell (on Windows) and SSH (to a Linux machine):
[string]::IsNullOrEmpty((ssh root@your.hostname.com 'mysql -N -e $''SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = \''databasename\'';'''))
Execute this with a replaced host- and database name in PowerShell and it tells you “False” if your database exists or “True” if not because it is checked if the string is null or empty. Maybe just flip the boolean value in the end đŸ™‚đŸ™ƒ
-
Eclipse bundle creator
For development of Spring Boot applications, designing Jasper reports, writing regular Java applications and libraries build with Gradle, development of database scripts and DB management in general with DBeaver and development of C/C++ applications I use Eclipse with a few plugins. Now eclipse releases a new version every three month and I was always annoyed by the time consuming process of downloading and creating a new distribution that would fit my needs. Fortunately Eclipse offers a command to automate this process on the command line.
The theoretical part
For this script to work Java has to installed and available in the global path.
This chapter shows the command line options:
-application org.eclipse.equinox.p2.director
This parameter takes two more arguments.
-repository $RepoListStr -installIU $FeatureListStr
$RepoListStr is a list of repository urls separated by “,”.
$FeatureListStr is a list of features to install separated by “,”.
$FeatureList = "org.eclipse.epp.mpc.feature.group,org.eclipse.buildship.feature.group,..."
$Repos = "https://download.eclipse.org/releases/2021-12,https://download.eclipse.org/eclipse/updates/4.22,..."
In the end the full command looks like this:
eclipse.exe -application org.eclipse.equinox.p2.director -repository $RepoListStr -installIU $FeatureListStr
The script
I have published the full installer in my GitHub repository. The script can be altered and features can be added and removed if needed. I tried to document the features I need the most.
Feature IDs
Now how do you get the feature ids for your desired components? The easiest way is on a already installed environment following this path:
Repositories
And how do you get the corresponding repositories for the repository array? Again on a already installed system:
Additional configuration
The script also alters the memory configuration to a initial size of 1GB and a maximum consumption of 4GB in “eclipse.ini”. Without this I ran in a “OutOfMemory” exception a few times. Further more automatic updates are enabled. This should be removed if the IDE is installed under “%ProgramFiles%” and UAC is enabled.
Troubleshooting
Sometimes a repository is missing or something goes wrong. Then features are missing. This can be detected in a certain log file. In the temporary directory Eclipse is extracted in and which is opened when the script has finished there is a folder “configuration” that contains files in the form of “<timestamp>.log”. For example:
1640808421484.log
This file then shows a message like the following:
This means that a certain dependency could not be found. I’ll show one way to fix this. Search for the problem causing library:
Open the hit that leads to the eclipse page and copy the link:
Paste the copied link into the address bar and remove the highlighted part:
Open the page:
This is the eclipse update page. Copy the URL and add it the “Repos” array:
Rerun the script. Now the library should be found. This can be repeated if more errors occur.
-
Setup Msys2 automatically
Some time ago I wrote a short post on “How to develop a 64bit C application on Windows 10 with Visual Studio Code“.
To be honest´it is a little bit tricky setting up the development environment, with gcc, gdb, make and other required tools. So I have extended my automated installation script.
This script will:
- Install Msys2 in “%LocalAppData%\Programs\Msys2” (Under your user directory. Thus, no admin privileges are required.
- Install all the required tools for development like compiler, linker, debugger, etc.
- Update everything to the latest version.
If you download the file from the repository it is possible that PowerShell will ask you if you really want to run the file. You can prevent this from happening with the following command:
Unblock-File -Path install.ps1 Are you sure you want to perform this action? Performing the operation "Unblock-File" on target "C:\Users\Path\to\download\directory\install.ps1". [Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help (default is "Y"):
There will be a console windows flashing up a few times. When everything is done the regular prompt of PowerShell is shown.
-
Get full path of executable in PATH variable
Ever wanted to get the full path of an executable that is located in the global PATH variable? Maybe for configuration purposes? Take a look at the following snippet. It may help you:
(Get-Command -Name @("code.cmd")).Path | ForEach-Object { Write-Host "$(([System.IO.DirectoryInfo]$_).Parent.FullName)" }
This will show the full path of the parent folder containing “code.cmd”. The term “code.cmd” could be replaced with “java”, “cmd”, “powershell” or whatever is configured in the global path. It could be useful to find out what version of a certain framework or program is used for example.
-
Debugging with PowerShell
I see a huge demand for automation even in areas that are not primarily associated with software development or IT in general. And I also see people getting more and more interested in scripting and coding to get annoying, repetitive and boring tasks done more easily and robust. There is only one drawback: Code that automates tasks wants to be written first and debugging is a big aid on the way to get things done. That is why I wrote this text: Because I think PowerShell is a powerful scripting tool and it should not be restricted to software developers only. So let’s get started.
First download and install Visual Studio Code. User Installer with 64 bit is probably the best choice if you are not sure about permissions and architecture. Just make sure to select the following two options during the installation process.
Now create a folder somewhere on your computer. In a workspace, in the documents folder, on your desktop, wherever you will find it again. Make a right click in this folder and choose “Open with Code”.
The next thing that should open right now is the following screen.
Click on the “New File” icon and create a file called “example.ps1”. Open the file and add the following code. You can copy and paste it from here, if you want. The variable in “Round …” is written in this strange way to show you a way of embedding variables in strings. This comes in handy a lot of times and I think it is good to show it right from the start. Don’t forget to save the file.
for ($i = 0; $i -lt 10; $i++) { Write-Host -Object "Round $(${i})" }
If “VS Code” asks you to install the PowerShell extensions, say “Install”. Maybe you have to wait a few moments for everything to load.
Now set a break point on the left side of the code (1). A red dot should appear. Select the “Run and Debug” icon (2) on the left or press “Crtl+Shift+D” on your keyboard. Then choose “Run and Debug” (3) in the sidebar.
Now the PowerShell code should run and stop at the break point:
To continue running the code select (1). To go over the code step by step choose (2). You can inspect the variables used in the code (in this case it is “$i”) on the left side or by hovering with the mouse over it in the code. The console output is on the bottom (4).
Small addition: If you have a big script with a lot of code and you loose track of all your break points, meaning your code stops a lot of time and this gets annoying, you can see a list of breakpoints on the bottom left of the window.
I hope this helps some people. It sure helped me a lot and made my life much easier. Especially when I remember back writing scripts with the old CMD/Batch syntax. This feels like stone age compared to PowerShell đŸ™‚