Why you as a Sys Admin might be hesitant to script!

Scripting is addictive, it is the tool of the lazy and the weapon of the efficient. While some like me are hooked onto scripting, most do not share this passion. In my few years in the industry, I have noticed that while most Systems Engineer’s do leverage scripts, they do not truly take to it. Some would be hesitant to develop a script, some are happy picking up some one liner from the web and being done, while some would opt not to script at all.

In this post I thought to list out some of the reasons I have seen why people don’t script and dispel some of the myths :

1) But මචං (pal) I am not a programmer

This is the most common answer I get when I ask “why don’t you make a script for it?”. While I do come from a background of Software Engineering, in my opinion System’s Engineers do the hardest part of coding – debugging someone else’s code!

If you think about it systems and datacenters today are all software based. Troubleshooting system/infrastructure errors is actually troubleshooting issues in code that someone else has made – which is the toughest thing possible!

If you are able to troubleshoot logically the issues of a code, that means you can definitely write a small piece of code that simplifies your work! It’s just a matter of mindset.

2) Not using coding elements that make life a lot easier

Scripting can get cumbersome and not save as much time as advertised if you’re not using coding elements. I’ll admit, here is where some coding background would come useful, but they are not difficult to pick up.

Here’s a little example, say you have to power down a bunch of virtual machines in your vCenter, you can do it like this:

Get-VM VM1 | Shutdown-VMGuest
Get-VM VM2 | Shutdown-VMGuest
Get-VM VM3 | Shutdown-VMGuest

This does get the job done, but its terribly inefficient. Say this list is 100s of VMs, you would be writing 100s of lines to get this done. Would be easier to go to the vCenter and do it manually at that point! And if your application team says “Oops, sorry guys that was the wrong list of virtual machines” well all that effort is down the drain!
Here’s another, more simple way of doing the same thing :

$vmList = "VM1", "VM2", "VM3"

ForEach ($vm in $vmList){
    Get-VM $vm | Shutdown-VMGuest
}

This is a much more efficient piece of script. If you need to edit the list of VMs all you have to do is edit that one array variable. Your script is only a few lines long and the application team can edit this as much as they want and you don’t have to sweat about it. Also now you have a ready made script that you can use whenever another request like this comes along!

3) Not making scripts for the long term

Okay, this point also directly relates to the last point. One thing we’ve all done when we get a problem we need a script for is find a script/one-liner, execute and be done. But for scripts to be truly time-saving and effective they need to be applicable in the long term. For that you have to be mindful of concepts like code extend-ability and efficiency.

Now they might sound like boring, complex terms but the concepts are really simple. When making a script, make sure that if you have to re-use it the parts you have to change are minimal and what you have to change is clear. This is where the use of variables with names that make sense and comments come in to play.
Let’s take an example about increasing the Memory of a virtual machine:

Connect-VIServer vCenter1
Get-VM VM1 | Set-VM -MemoryGB 8 

This is perfectly fine and gets the job done… for this Virtual Machine.
Now take a look at this script:

#Set the parameters
$vcenter_name = "vCenter1"
$vm_name = "VM1" #for multiple VMs go as "VM1", "VM2" ...
$memory_amount = 8 

Connect-VIServer $vcenter

ForEach($vm in $vm_name){

    Get-VM $vm | Set-VM -MemoryGB $memory_amount 
}

With few lines of code added we have created a clear, extensible script that you can share with your colleagues and be a hero. We went from a script focused on a particular virtual machine to one that we can easily choose a different vCenter, have multiple VMs, and change the memory amounts easily. By using comments we have ensured that even if you dig this script up a year later, you can easily pick up what to do!

4) Uhh… I had a script for this, but I can’t find it now

Remember when you got that one problem, and you searched the web for a script/one-liner, got it done then forgot about it? Well now it has come up again and now you have to do the same thing again? Or your friend is asking for the script and now you’re the dumdum who can’t find it? Yes, we’ve all been there.

Programmers use a code repository or repo to keep the code, and you as a Sys Admin can do the same thing. It doesn’t have to be as fancy as a GitHub repo (even though it makes life easier with version controls and all), it could very well be a Google drive or even just a well organized folder in your PC! Just ensure that your scripts are stored somewhere which is easily accessible and searchable in the long term.

Your future-self will thank you for it!

In Summation

Just follow these simple tips to make your life easier with scripting:

  • Believe that you are able to script – don’t just dispel it thinking its something that only “some people” can do. All you need is a little practice.
  • Learn a few coding tips and tricks to make a more versatile script.
  • When you’re making a script keep in mind to make a script that you can dig up years later and use it easily. Think of your future-self!
  • Most importantly make sure you have saved your script somewhere that you can easily find!

And that is it! Hope you’ve enjoyed this post and feel like making more scripts that you’ll be proud of!

If you liked/hated this post, want me to share some detailed tips and tricks or elaborate more, please do hit me up in the comments, or on my social media linked below!

Thanks for reading and happy scripting!!!

System.Data.DataRow issue when querying MySQL with PowerShell Solved!

Has this happened to you – you’re doing a SELECT query from powershell doing your thang, but when you’re trying to output the fruits of your query labour all it says is System.Data.DataRow? You’re sure you did the query right, while the issue seems to be common the internet is not helping you out either and you feel like the scripting world is against you! Don’t worry the Scriptigator got yo’ back brotha/sista!

Okay in all seriousness, the issue does seem fairly widespread and weirdly did not happen to me before except this one time. Output is just “System.Data.DataRow” without outputting the contents of the query. The issue is that PowerShell seems to encapsulate the entire row in an object.

<query_result>.Item to the rescue!!! *this is only needed if the query returns just 1 row.

<query_result>.Item("<item_name>")

The item name is the column name that you want to output. As an example the code would look like this

#printing out the query results
Write-Host $query_result.Item("column_name")

And there it is, a fairly simple answer to a frustrating issue.

Checking for empty returns from MySQL queries in Powershell

Recently during a project I had to some DB queries using powershell. While that is straightforward and easy enough (I will create a post on querying DBs with powershell later on), the problem I ran in to was checking for an empty return.

I wouldn’t blame you for thinking “but scriptigator this should be simple right?” – because I thought the same. Query the DB, check if its null, presto manifesto yes? Well… sort of – IF you’re using Invoke-MysqlQuery this will work

$query_result = Invoke-Mysql -Query "SELECT * FROM table_name"

if($query_result -eq $null){
    Write-Host "This will work if you're using invoke-mysql"
}

else{
    Write-Host "need to try something else"
}

The problem with this approach is that empty or the $null global variable in Powershell is not exactly the same as an SQL null value. So we will have to use a workaround to get around the issue. There are a couple of ways to do this :

1. Checking the row count of a query

If the query does not match any records, how many rows would it output? Should be 0 right? Let’s use that logic here

$query_result = Invoke-MysqlQuery "SELECT * FROM table_name"
$query_row_count = ($query_result).count
if($query_row_count -eq 0){
    Write-Host "This WILL work!"
}

And yes this will work!

2. Using DBNull

If you’re using SQL reader method to query the Database you can use the system provided value of DBNull or System.DBNull that makes life a little easier. ( I had trouble with this when using Invoke-MySQL – script life can’t get too easy now can it? )

//DBNull and System.DBNull are interchangeable

if($query_result -eq [DBNull]::Value){
    Write-Host "This will work if you're using sqlreader"
}


if(([DBNull]::Value).Equals($query_result)){
    Write-Host "This will work if you're using sqlreader"
}

Conclusion time…

So there it is – all the methods I found to check for empty returns in Powershell/PowerCLI. As you know I do not claim to be an all-knowing demigod in scripting so if you find any alternative methods to these please feel free to share!

Till the next time – happy scripting!

Storing Passwords securely with Powershell

Security is paramount in our line of work, a breach would mean a catastrophe of epic proportions for a sys admin – I mean what can’t you do if you’re the administrator right? So we set our passwords T0b3imp055ibleT0Guess and lock them up in keypasses.

But we sys admins are lazy, when it comes to scripts – we leave it to ask for our password every time we execute the script, but what if we need to automate the script – schedule it to run automatically? we can’t leave them in plain sight, plain text! Not to worry – as always powershell has a module to save our skins. Here’s how you store your passwords securely and retrieve them when needed:

Storing passwords securely

Powershell thankfully has the ConvertFrom-SecureString module to convert any text to a secure string. Save the following script separately and it will prompt you to enter a new password and will save it in the location with the file name you have specified

$password_file_location = "D:\test\credentials.txt"
\\location and filename can be anything you want it to be

Read-Host "Enter New Password" -AsSecureString |  ConvertFrom-SecureString | Out-File $password_file_location

Retrieving the saved password

Use the following lines in your script (that does the automation job) to retrieve the saved password

$password_file_location = "D:\test\credentials.txt"

$password = Get-Content $password_file_location | ConvertTo-SecureString

Now the $password variable contains the password you have saved previously. Use it in the part of the code you use to connect to the server and viola you’re through without having to type your password all the time or using a plain text password!

Note: This doesn’t guarantee security, but it’s definitely a step in the right direction!

Error handling in Powershell : Try / Catch blocks in Powershell

Recently I had a project to develop a web portal that would trigger a powerCLI script. The problem was that if anything except the required JSON output popped up, especially any errors, the whole thing would crash. The only work around was to error handle the sh#t out of the code!!!

The best and easiest way to error handle / catch exceptions is to use try / catch blocks – if you’re familiar with Java (or any kind of) programming, powershell try catch blocks work exactly the same way. If you’re not – don’t worry I got your back.

What is a try catch block?

Try catch block is a way to structure your code to handle errors and catch any exceptions that your code might throw. There is also a “Finally” block that is also a part of the whole thing.

Try block – This is where you place the code which you need to check for exceptions
Catch block – This is where you specify what you need the code to do IF an exception is caught
Finally block – This is where you specify the code that you need to run regardless of whether an exception was caught or not

try{

	//The code that needs checking for exceptions
}

catch{

	//What should happen if an exception is caught
}

Finally{

	//What should run regardless of what happens above
}

Code Example

try{

	Connect-VIServer $vcenter -Credential $credentials -ErrorAction Stop
	Write-host "This will not run if an exception is caught"
}

catch{

	Write-host "Oops something is wrong with the credentials"
}

Finally{

	Write-host "This runs regardless of what happens above"
}

The above code is a PowerCLI script which will try to connect to a vCenter with the given credentials and if an exception is caught it will display the text in the catch block.

IMPORTANT: DONT FORGET THE -ERRORACTION The -ErrorAction stop is extremely important for the code to function as expected. This is will stop powershell from executing the next lines and divert the code to the catch block. If ErrorAction was not there it will continue executing everything regardless of an exception.