Thursday, January 26, 2017

Sending emails

Short one for my own recollection. Sending emails is easy from within PowerShell

Send-MailMessage -From "fromthevcenter@whatever.com" -To "first.email@someaddress.com", "second.email@someaddress.com" -SmtpServer "thesmtpaddress" -Subject "VM Expansion $VM Completed" -Body $body

This was one of my requirements of my other post about upgrading the vCPU's ;-)

Wednesday, January 25, 2017

Store credentials securely for later use

A command you use quite often is Get-Credential. For instance for creating a PSSession to a server:

$cred = Get-Credential "admin"
$s = New-PSSession -Computername myserver -Credential $cred

It's nice for on the spot use, but in a script that might not work. There are ways of doing that plaintext, but I saw a webpage that unfortunately I don't have the link for anymore, but if I find that reference I will add, but you can store those credentials securely too:

$Credential = Get-Credential
$Credential | Export-CliXml -Path "D:\akos\Myserver.Cred"

This small piece of code lets you store credentials in a directory that you can secure with NTFS rights, and also, it is encrypted, so you don't see the password in plain text in your script.

Now if you want to use those credentials again, you can just load in the file:

$cred = Import-CliXml -Path "D:\akos\Myserver.Cred"

Very nice!!

Waiting for a VM to come back

In my previous post, I wrote about upgrading vCPU's, and that I want to do several other things as well. If you upgrade a vCPU on a VM, it could very well be that the Windows guest wants a second reboot. I've found that simply rebooting and waiting for a while is inefficient. So I usually check if the VMware tools are back online.

I've made that into a function, to exactly that:

function WaitforVM($VM)
{
    while (((get-vm $VM ).ExtensionData.Guest.ToolsRunningStatus ) -ne "guestToolsRunning" )
        {
            Write-Host "Waiting for machine to come back....." -ForegroundColor Yellow
            Sleep 5
        }
}

Now all you have to do, is to start the VM after the CPU addition, wait, then restart and wait again:

Start-VM -VM $VM -Confirm:$False
WaitforVM -VM $VM
Restart-VMGuest -VM $VM -Confirm:$False
WaitforVM -VM $VM

Nice, right? Obviously this function can be used for other things, like being used in scripts when you create a new VM from template and boot it up to see if that VM is live already.

Automatically upgrade vCPU's

I am lazy. Well, not lazy, I just don't like working at ungodly hours. Here's the story: I got this request to upgrade 2 customer VM's from 3 vCPU's to 4 vcpu's. No biggy, I thought. But he wanted it done after 1 AM.. Wait, that's not during office hours!

OK, I could fix that with my trusty Powershell toolkit, and a scheduled task. But then I talked to the customer who went like: "Sure that's fine with me to script it, but make sure the sessions are drained from the webserver".. Hmm, F5 loadbalancers. I've not worked too much with those before, really. I get the general ideas within loadbalancing, but let's try and script against it.

So I had a number of things I wanted to happen:
  • Log in to the F5 loadbalancer, preferably not with a script filled with credentials hardcoded into it. 
  • Wait an X amount of time for connections to drop from the specific pool
  • Shut down the machine, and wait for it to be properly turned off.
  • Set the number of CPU's and memory. This had an extra challenge, namely that the person who built the VM put in 1 vCPU with 3 cores, instead of 3 vCPU's.
  • Send an email with the results, so I can see what happened from my phone.
I'll spend a few posts on those different things.

Firstly the vCPU upgrade, which is the basis of this entire story:

Normally, you can turn off a VM, upgrade vCPU's, then start a VM again, through this simple set of commands:

$VM=Get-VM -Name 'WEB01'

Stop-VMGuest –VM $VM –Confirm:$False
do {
        $status = (get-VM $VM).PowerState
    }until($status -eq "PoweredOff")

$VM | Set-VM -NumpCPU 4 –Confirm:$False | Start-VM

However, since someone used 1 vCPU with multiple cores instead of multiple vCPU sockets, things work a little differently. If you would try this command, the VM would be shut down, but no upgrade would happen, and start back up with the same amount as before.

Fortunately there's another trick for that:

$VMSpec = New-Object -Type VMware.Vim.VirtualMachineConfigSpec -Property @{"NumCoresPerSocket" = 4;"numCPUs" = 4}
$VM.ExtensionData.ReconfigVM_Task($VMSpec)

(That first line shouldn't be cut off like that, should be 1 line, but alas: blog template gets in the way)

Now the VM gets upgraded to 4 vCPU's, although you would think it'd be 4x4 cpu's looking at the syntax.

So now the final complete code would be:

Add-PSsnapin VMware.VimAutomation.Core
Connect-VIServer myVcenter -ErrorAction Stop


$VM=Get-VM -Name 'WEB01'


Stop-VMGuest –VM $VM –Confirm:$False
do {
        $status = (get-VM $VM).PowerState
    }until($status -eq "PoweredOff")


$VMSpec = New-Object -Type VMware.Vim.VirtualMachineConfigSpec -Property @{"NumCoresPerSocket" = 4;"numCPUs" = 4}


Start-VM $VM


Yeay, success! Now on to the next bit...

Friday, July 29, 2016

Selecting and removing old snapshots

Me: "Say Customer X, I see you still have some snapshots here and there. Can I remove them? It's not wise to keep them for a long time."
Customer X: "Oh yeah, I forgot about those. Well: those updates we did worked out fine, so anything from before 11-07-2016 can be deleted"

Get-VM | Get-Snapshot | Where {$_.Created -lt (Get-Date 11-07-2016) | Remove-Snapshot -confirm:$false

Me: "OK, done!"

Another possibility: "Can you give me a list of snapshots that are older than a week?"

Get-VM | Get-Snapshot | Where {$_.Created -lt ((Get-Date).AddDays(-7))} | Select VM, Name

Did I say how much I love Powershell/PowerCLI? ;-)

Wednesday, July 27, 2016

Get the serialnumber via Powershell

I quickly wanted to know a serial number for a certain HP Server, but didn't want to log on to the ILO card to get it from there. You don't have to, either:


gwmi win32_bios | fl SerialNumber

Works on most machines I've seen so far (HP and Dell).

Thursday, July 21, 2016

Decode AsSecureString into cleartext

I needed a way to enter a password from the console. This is done by typing:

$pwd = Read-Host

It works, but I didn't want this text to be visible on the screen while I'm typing it:

$pwd = Read-Host -AsSecureString

Success! Now let's see the password in action:

PS C:\Users\Akos> $pwd
System.Security.SecureString

.. Hmm, not quite what I had hoped for. But there is hope yet:

$cleartextpwd = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($pwd))

Decodes the secure string into cleartext! Now you can type a password securely and use it. Be sure to remove the variable once you're done ;-)