PowerCLI

PowerCLI – Get-Screenshot Function

Posted on 03 August 2010

I have created a cool PowerShell Function that will get you the Screenshot of a VM’s Console. You can either import this into a script (probably tidier to remove all the help info first) or save it as a .psm1 file and import it as a powershell module. If you are not sure how to import a powershell module here is a breif explanation.

 

Run the Following Command

dir env:psmodulepath

This should give you an output like the following

 

Name                                          Value
—-                                                  —–
PSMODULEPATH                   C:\Documents and Settings\username\My Documents\WindowsPowerShell\Modules;
 
Now once you have saved the below function as a .psm1 file place it inside a folder with the same name as the psm1 file. For example Create a Folder in the above directory called “Get-Screenshot” and then save the function as “Get-Screenshot.psm1″ inside that folder.

 

Go back to your PowerShell Window and then type the following command.

 

Import-Module Get-Screenshot

 

You should then be able to run the Function using the following Syntax.

PS>Get-Screenshot -VMName “server01″ -Destination “C:\Temp\Screenshots\”

Function Get-Screenshot
{
<#
.Synopsis
 Takes a Screenshot of a selected VM and places it into a specified Location on your Local Computer.
.Description
 Provide a VM Name and a Destination and you will be able to take a screenshot of the Virtual Machines Current Console.`
 The cmdlet then copies all existing screenshots into the specified location.
.Parameter VMName
 The Name of the VM that you would like to screenshot.
.Parameter Destination
 The Location that you would like to save teh screenshots to.

.Example
 PS> Get-Screenshot -VMName "server01" -Destination "C:\Temp\Screenshots\"
.Link
    about_functions
    about_functions_advanced
    about_functions_advanced_methods
    about_functions_advanced_parameters
.Notes
NAME:      Get-Screenshot
AUTHOR:    Steven Bryen
LASTEDIT:  03/08/2010

#>

[CmdletBinding()]
PARAM($VMName,$Destination)

		$vm = Get-VM -Name $VMName
		$vmView = $vm | Get-View
		$vmh = Get-VMHost -Name $vm.VMhost
		$vmView.CreateScreenshot_Task() | Out-Null
		sleep -Seconds 10
		$driveName = "ScreenshotDS"
		$vmxPath = $vmView.Config.Files.VmPathName
		$pngPath2 = $vmxPath | % { $_.Split(' ')[1]; }
		$pngPath3 = $pngPath2 | % { $_.Split('/')[0]; }
		$pngPath4 = $driveName + ":\" + $pngPath3 + "\" + ($vm.Name) + "-screenshot"
		$ds = Get-Datastore -VM $vm
		New-PSDrive -Name $driveName -PSProvider ViMdatastore -Root '\' -location $ds
		Copy-DatastoreItem -Item $pngPath4* -Destination $Destination
}

Post to Twitter

Comments (0)

PowerCLI

PowerCLI – Using PowerShell Jobs

Posted on 02 August 2010

Today I learnt about jobs in PowerShell. I was quite interested in the idea of running jobs in the background and speeding up all of my scripts. Although I had all these great ideas of how I was going to use jobs I soon found that it was going to get really complex.

The main reason for this is that PowerShell jobs run in their own runspace, meaning that by default you cannot use any global variables inside the job. So this meant that the job was unaware of the connection to and even unaware of the VIM PSSnapin.

Ok so them two are pretty easy, you just do something like below.

Start-Job -ScriptBlock
{
Add-PSSnapin *vmware*;
connect-viserver vc01;
get-vm;
disconnect-viserver vc01 -Confirm:$false -Force:$true
}

So that looks clever but say for example you want to change vc01 to vc02 and you have 10 jobs then there is lots of space for human error.

So then we can use -InputObject to pass a variable into the job. Interesting… So for example:

$vi_server = "vc01.domain.com"
Start-Job -InputObject $vi_server -ScriptBlock
{
	Add-PSSnapin *vmware*;
	connect-viserver $input;
	get-vm;
	disconnect-viserver $input -Confirm:$false -Force:$true
}
This worked fine When I was playing around but what if you want to pass more than one global variable into the job? Well this is when it became a bit complex. Say for example I wanted to run a job which did the following:
$vi_server = "vc01.domain.com"
$vi_user = admin
$vi_pass = password
$name = "inf"

Add-PSSnapin *vmware*;
connect-viserver -Server $vi_server -User $vi_user -Password $vi_pass;
get-vm | where {$_.Name -like $name};
disconnect-viserver $vi_server -Confirm:$false -Force:$true

There are now four variables that i would like to use within my job. This is where custom objects come into play. So you can do the following.

$vi_server = "vc01.domain.com"
$vi_user = admin
$vi_pass = password
$name = "inf"

$jobcmd =
	{
	$in = $input.'<>4__this'.read();
	Add-PSSnapin *vmware*;
	$connection = Connect-VIServer $in[1] -User $in[2] -Password $in[3];
	get-vm | where {$_.Name -like $in[4]};
	Disconnect-VIServer $connection -Confirm:$false -Force:$true;
	}

$jobSpec=@()
$jobSpec += $jobcmd
$jobSpec += $vi_server
$jobSpec += $vi_user
$jobSpec += $vi_pass
$jobSpec += $name

Start-Job -InputObject $jobSpec -ScriptBlock $jobSpec[0]
So let me just explain what we did there. I will start from the bottom, We had too many variables to pass through with the -InputObject option so we created an empty array $jobSpec we then added all of the global variables into this array so that the input object would now be this array.

Now moving further up the script to line 8, we created a variable called $in this got hold of all of the objects in the array and then in lines 10 and 11 we used each object in the array.

Note that all the lines between 7 and 13 are all within the scriptblock which is held in the variable $jobCmd  we added this to the empty array first and used it as our scriptblock within the Start-Job cmdlet.

This is a very cool way of passing global variables into Powershell Jobs. One example of how I used this to a huge effect was to deploy a Virtual Storage Appliance to each of my physical ESX hosts. This came in the vApp form and I was able to run Powershell jobs within a foreach ($vmh in Get-VMHost) which meant that I could deploy the vApps simultaneously without waiting for the previous deployment to start.

Finally I want to briefly talk through how we can then wait for the jobs to all finish before we move on in the script. The Get-Job cmdlet is useful for this and it returns the state of the job amonst other things. The  state can be Running, Failed or Completed. On the vApp deploy script I added a nice while loop that would output a Job in Progress to the screen until all jobs were completed. This was added to the script straight after the foreach loop and looked like this.

while ((Get-Job | where {$_.State -eq "Running"}).getType -ne $null)
	{
	echo "Jobs In Progress"
	Sleep -Seconds 10
	}

Post to Twitter

Comments (0)

How To Guides, PowerCLI, Problems Solved

PowerCLI – Change Text Case of all VM Names

Posted on 19 April 2010

I was asked by a colleague today if I was able to create a script to change the case of all the VMnames to Lowercase. I know that many people are pretty strict on text casing for Server Names to keep things nice and tidy. And I don’t blame them, it does make things look a lot neater.

If you are the sole admin in your environment then this will probably not be an issue for you, however if you have some people who have previously made things look messy then this is a good way to tidy it up in a flash.

So I set about working this out and It turns out there is a pretty easy way to do this. There is a way in Powershell to change the case of a variable. So here is the process flow of the script. Pretty basic stuff, but can be very effective on a large deployment.

UPDATE: I have updated the script to eliminate the use of an external CSV file.

- you can now chose which Case you would like the VM Names to be at the top of the script.
- It then gathers the VM Names into a variable called $vmlist
- call the variable and then for each VM in the list and use the Set-VM cmdlet to change the case dependent on the above set case.
- Disconnect from VC(s)

Here is the script:

##Change VM Name Case to Lower or Upper Case
##Created by Steven Bryen
##This Script will change the text case of all VM Names to Lower Case or Upper Case
## Please use the “case” variable to set whether you require uppercase (upper) or lowercase (lower) VM names.
#–Set Virtual Center(s)
$vcenter= “localhost”
#Would you like the case to be upper or lower?
$case= upper
#–Connect to Virtual Center or ESX
connect-viserver $vcenter
#–Get List of VMs
$vmlist = get-vm | select Name
if
{
($case -eq “upper”)
foreach ($vmname in $vmlist)
{
$upper = $vmname.ToUpper()
get-vm -Name $vmname | set-vm -Name $upper -Confirm:$false
}
}
elseif
{
($case -eq “lower”)
foreach ($vmname in $vmlist)
{
$lower = $vmname.ToLower()
get-vm -Name $vmname | set-vm -Name $lower -Confirm:$false
}
}
else
{
Write-Host “Please ensure that the Case Variable is set to either lower or upper.
}
#–Disconnect Virtual Center
Disconnect-VIServer -Server * -Confirm:$false -Force:$true

 Hope this helps you keep things tidy :-)

Post to Twitter

Comments (0)

General Posts

Chinwag with Mike Laverick

Posted on 31 March 2010

Today I had the opportunity to feature in Mike Laverick’s Chinwag series.

Firstly let me apologise for my common London Accent and I have a slight cold/flu coming on so sound a bit more common than normal :-P

It was a great chat and I spoke about My introduction into Virtualisation, My visit to an “IceCube” Datacenter, Troubles Automating Deployments and Some of my personal views including a few on “Cloud” Computing.

You can Catch the Info on Mikes Blog here:

Chinwag with Mike Laverick

You can also grab the media from the following sources too:

Video
MP3 Audio
Subscribe on iTunes

I hope you enjoy the listen and once again apologise for my common accent/oncoming cold voice..:-P

Steve :-)

Post to Twitter

Comments (0)

General Posts, PowerCLI

New Page – PowerCLI One Liners

Posted on 29 March 2010

I have started to create a  list of all the one liners that I am using in PowerCLI to complete of the usual admin tasks that I comple on a day-to-day basis.

I started building the list last weekand have got 9 that I found really useful so far. I will be keeping this post upto date and it is going to be shown as a page at the Links on the top of my blog.

Click here to be forwarded to my new page:  PowerCLI One Liners

Steve

Post to Twitter

Comments (0)

How To Guides, PowerCLI, Problems Solved

PowerCLI – Using Import-CSV to Populate VC (v2)

Posted on 08 March 2010

Ok, so I rushed a bit into getting the last post about this online as I hadn’t blogged in a while. However nearly as soon as I finished I started getting more ideas about how I could improve the script. The next day I started improving the script and done some testing and now It allows you to use 4 CSV Files to add Datacenters, Folders, Clusters and Hosts intou your VC Environment.

I am already having ideas about the next version, I am thinking about the possibilities of having one script that exports Inventory information using export-csv and then another script that uses them same exported CSVs. This will be really useful for rebuilding a VC, and could possibly be done as a scheduled job on a daily basis so that you always have the files there incase it crashes. Anyways That probably won’t be here anytime soon unfortunately (very busy next few months) but it is on my list of things to work on.

This Script works for environments that need to be populated using the Datacenter > Folder > Cluster > Hosts Heirachy in the inventory.

The Four CSV Files

This script uses 4 CSV Files to populate the inventory from. One for each inventory item. The CSV Files are:

data.csv – A List of Datacenters that Need Adding.

Datacenter, Location
DC01, Datacenters
DC02, Datacenters

Note: Leave the location field as “Datacenters” if you add your Datacenters into the root Folder Like we do. This is the default root folder for new Datacenters.

folder.csv – Folders to be added into Datacenters.

Folder, Location
Development, DC01
Production, DC01
Staging, DC02

clu.csv – Clusters to be added into Folders

Cluster, Location, DRS, DRSMode, HA
clu01, Production, Yes, FullyAutomated, Yes
clu02, Production, Yes, FullyAutomated, No
clu03, Production, No, n/a, Yes
clu04, Staging, No, n/a, No

Note: DRS and HA Values must be “Yes” or “No”. If DRS is “No” then DRSMode must hold the “n/a” Value.

hosts.csv – List of Hosts to be added into Clusters

Hostname, Password, User, Folder, Cluster
host1.domain.com, MyPass, root, Development, n/a
host2.domain.com, MyPass, root, Development, n/a
host3.domain.com, MyPass, root, Development, n/a
host4.domain.com, MyPass, root, Production, clu01
host5.domain.com, MyPass, root, Production, clu01

Note: Hosts that are not in clusters and just sit under folders must have the “n/a” value in the Cluster column.

 

The PowerCLI Script – Broken Down.

First things First – Set Variables

## —-Set Variables—-
$vcenter = 192.168.1.5
$hostscsv = Import-Csv “C:\PowerCLI\hosts.csv”
$datacsv = Import-Csv “C:\PowerCLI\data.csv”
$foldercsv = Import-Csv “C:\PowerCLI\folder.csv”
$clucsv = Import-Csv “C:\PowerCLI\clu.csv”

Here we add the paths to the CSV Files and the vCenter IP Address/Hostname etc.

Keeping it Simple – Connect to vCenter

## —-Connect to VirtualCenter—-

Connect-VIserver $vcenter

Add Datacenters from data.csv

## —-Add Datacenters From CSV—-

$datacsv | % {
$Name = $_.Datacenter
$Location = Get-Folder -Name $_.Location

New-Datacenter -Location $Location -Name $Name
}

Add Folders from folder.csv

## —-Add Folders From CSV—-

$foldercsv | % {
$Name = $_.Folder
$Location = Get-Datacenter -Name $_.Location

New-Folder -Location $Location -Name $Name
}

Add Clusters from clu.csv

## —-Add Clusters From CSV—-

$clucsv | % {
$Name = $_.Cluster
$Location = Get-Folder -Name $_.Location
$DRS = $_.DRS
$DRSMode = $_.DRSMode
$HA = $_.HA

if ($DRS -eq “No” -AND $HA -eq “No”)
{
New-Cluster -Location $Location -Name $Name
}
elseif ($DRS -eq “No” -AND $HA -eq “Yes”)
{
New-Cluster -Location $Location -Name $Name -HAenabled:$true
}
elseif ($DRS -eq “Yes” -AND $HA -eq “Yes”)
{
New-Cluster -Location $Location -Name $Name -DRSEnabled -DRSMode $DRSMode -HAenabled:$true
}
elseif ($DRS -eq “Yes” -AND $HA -eq “No”)
{
New-Cluster -Location $Location -Name $Name -DRSEnabled -DRSMode $DRSMode
}
}

You can see this uses various If and Elseif statements to decide how to configure HA and DRS. The example CSV above has one of each possible selection.

Nearly there – Add Hosts from host.csv

## —-Add Hosts From CSV—-

$hostscsv | % {
$PW = $_.Password
$HN = $_.Hostname
$Cluster = $_.Cluster
$User = $_.User
$Folder = $_.Folder
$getfolder = Get-Folder -Name $_.Folder
if ($Cluster -ne “n/a”)
{
$getcluster = Get-Cluster -Name $_.Cluster
}
if ($Cluster -eq “n/a”)
{
Add-VMhost -Name $HN -User $User -Password $PW -Location $getfolder -Force
}
else
{
Add-VMhost -Name $HN -User $User -Password $PW -Location $getcluster -Force
}
}

This is one of the main improvements from my first post about this script. The original was kicking out errors, now I have added in If statements to make sure that this was stopped.

And Finally – Disconnect from vCenter

## —-Disconnect From VirtualCenter—-

Disconnect-VIServer -Server * -Confirm:$false -Force:$true

All of the files that I used for this script can be downloaded below:

data.csv

folder.csv

clu.csv

hosts.csv

populatevc.ps1

Zip Bundle

I hope that this helped

Steve

Post to Twitter

Comments (0)

SEE MORE ARTICLES IN THE ARCHIVE