Archive

Archive for the ‘Toolbox’ Category

Script of the Day – import all VMs from a Datastore to VMWare ESX / ESXi

February 3rd, 2011 No comments

So your DC fell over . . but you have a copy of all your vmdks etc and would like to import them to a new ESX host . .

The following script will run you through a series of prompt and then import all VMs from a DS to the specified ESX cluster


# Code by Alan van Wyk
# This script prompts for a Cluster and a Datastore and imports all VMs from the DS to the Cluster (to be used in DR emergencies etc)

# Simple function to tidy display at prompt screen
Function Selections () # Refresh screen at top of page, shows user selections
{
cls
cls
Write-Host ("Virtual Center: ") -ForegroundColor Blue -NoNewLine; Write-Host (" " + $vc)
Write-Host ("Destination Data Center: ") -ForegroundColor Blue -NoNewLine; Write-Host (" "  + $DC2)
Write-Host ("Destination Cluster: ") -ForegroundColor Blue -NoNewLine; Write-Host (" "  + $Cluster2)
Write-Host ("Destination Datastore: ") -ForegroundColor Blue -NoNewline; Write-Host (" "  + $Datastore2)
Write-Host
}
Function quit #quits script
{
exit
}
Function Pause ($Message="Press any key to continue...") #pause and wait for user to hit key to continue
{
Write-Host -NoNewLine $Message
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
Write-Host ""
}

$vc = Read-Host "Please specify your Virtual Center"
Write-Host "Connecting to Virtual Center... "
 Connect-VIServer $vc

selections
#Select DC
 $x = @(0) * 20 # initialize the array
 $i=0 # intialize the indexer
 Get-Datacenter `
 | select -first 20 `
 | % { $x[$i]=$_.Name; "{0} {1}" -f $i++, $_.Name } # store the DCs into an array and display the array
 Write-Host ("`n Please select Destination DataCenter from index above:`n") -ForegroundColor Yellow -BackgroundColor Red
 $index = read-host index # ask for an index
 $dc2 = $x[$index] # select index

 Selections
 # Select cluster
 $x = @(0) * 20 # initialize the array
 $i=0 # intialize the indexer
 Get-Datacenter $dc2    | Get-Cluster `
 | select -first 20 `
 | % { $x[$i]=$_.Name; "{0} {1}" -f $i++, $_.Name } # store the Clusters into an array and display the array
 Write-Host ("`n Please select Destination Cluster from index above:`n")    -ForegroundColor Yellow -BackgroundColor Red

 $index = read-host index # ask for an index
 $Cluster2 = $x[$index] # select index
 Selections

 $x = @(0) * 20 # initialize the array
 $i=0 # intialize the indexer
 get-cluster $cluster2 | get-vmhost | Get-Datastore `
 | select -first 20 `
 | % { $x[$i]=$_.Name; "{0} {1}" -f $i++, $_.Name } # store the Datastores into an array and display the array
 Write-Host ("`n Please select Destination Datastore from index above:`n")    -ForegroundColor Yellow -BackgroundColor Red
 $index = read-host index # ask for an index
 $Datastore2 = $x[$index] # select index
 Selections

 #Prompt for confirmation

 $confirmation = Read-Host "Type CONTINUE to confirm that you would like to import all VMs from $Datastore2 to $cluster2"
 If ($confirmation -cne "CONTINUE")
 {
 Write-Host ("Settings not confirmed - disconnecting from Virtual Center") -BackgroundColor Red -ForegroundColor Yellow
 disconnect-viserver -confirm:$false
 Pause
 Quit
 }

 $dsname = $Datastore2
 $datacenter = $dc2
 $cluster = $cluster2

#####################################################################################################
# Code below by LucD

$ESXname = Get-Cluster $cluster | Get-VMHost | select -First 1
$dsBrowser = Get-View (Get-View (Get-VMHost -Name $ESXname).ID).DatastoreBrowser
$folder = Get-View (Get-Datacenter -Name $datacenter | Get-Folder -Name "vm").ID
$pool = Get-View (Get-Cluster -Name $cluster | Get-ResourcePool -Name "Resources").ID
cls

foreach($dsImpl in $dsBrowser.Datastore){
 $ds = Get-View $dsImpl
 if($ds.Summary.Name -ne $dsname){continue}

 $datastorepath = "[" + $ds.Summary.Name + "]"

 $searchspec = New-Object VMware.Vim.HostDatastoreBrowserSearchSpec
 $searchSpec.matchpattern = "*.vmx"

 Write-Host "Searching in path" $datastorepath

 $task = Get-View ($dsBrowser.SearchDatastoreSubFolders_Task($datastorePath, $searchSpec))
 while ($task.Info.State -eq "running" -or $task.Info.State -eq "queued"){
 $task.UpdateViewData()
 sleep 5
 }
 if($task.info.result -ne $null){
 foreach ($file in $task.info.Result){

 if($file.FolderPath -match ".snapshot"){continue}
 $found = $FALSE
 foreach($vmx in $vms){
 if(($file.FolderPath + $file.File[0].Path) -eq $vmx){
 Write-Host "`tVM is registered"
 $found = $TRUE
 }
 }
 if (-not $found -and $task.Info.Result[0].File -ne $null){
 $vmx = $file.FolderPath + $file.File[0].Path
 $params = @($vmx,$null,$FALSE,$pool.MoRef,$null)
 Write-Host "Registering" $vmx
 $folder.GetType().GetMethod("RegisterVM_Task").Invoke($folder, $params)
 }

 }
 }
}

Script of the Day – changing ESX NTP servers

February 2nd, 2011 No comments

The following script will amend the NTP server settings for all ESX hosts in your VC

$ntp1 = <ipaddress>"
$ntp2 = "<ipaddress>"
$oldntp = "<ipaddress>"
$oldntp2 = "<ipaddress>"

Add-PSSnapin VMware.VimAutomation.Core
connect-viserver -server <vcentername> -credential (Get-Credential)

$vmhosts = Get-VMHost

foreach ($element in $vmhosts)
{
Remove-VMHostNtpServer -NtpServer $oldntp -VMHost $element
Remove-VMHostNtpServer -NtpServer $oldntp2 -VMHost $element
Add-VmHostNtpServer -NtpServer $ntp1 -VMHost $element
Add-VmHostNtpServer -NtpServer $ntp2 -vmhost $element

$ntpd = Get-Vmhostservice -VMHost $element | where {$_.key -eq 'ntpd'}
Restart-VMHostService $ntpd -Confirm:$false
}

Useful websites . . searching for Microsoft / Mac / Linux / BSD related results

February 1st, 2011 No comments

As a techie . . I heavily rely on google for answers to questions that relate to various IT systems (seeing as most people know more than me)

Well, the majority of my queries are related to Windows / Microsoft and supporting tools.

some of you may know this (and some of you may not), but Google has actually built a tool just for techies like us.

If you browse to http://www.google.com/microsoft.html you’ll be able to run a search that only queries websites that are specifically related to Microsoft support etc.

but this is not all . .there are a few others..

Apple Macintoshwww.google.com/mac Search for Mac & Apple things
BSDwww.google.com/bsd Search for the BSD operating systems
Linuxwww.google.com/linux Search for the Linux operating system
Microsoftwww.google.com/microsoft Search Microsoft-related pages
U.S. Government and state governmentswww.google.com/unclesam Search .gov, .mil and state sites
Universitieswww.google.com/options/universities.html Narrow your search to a specific institution’s website

Definitely worth a look (methinks)

Categories: Toolbox Tags: , ,

Script of the day – writing to a cell in Excel

January 31st, 2011 No comments

Ever needed to inject info to a cell in an Excel spreadsheet – repeatedly . . . you can do so from Powershell . . like so:

Function write-excel ($ExcelFile, $WorkSheet, $Column, $Row, $Value)
{
<#
	.SYNOPSIS
	 Write value(s) to Excel cells
	.DESCRIPTION
	 No return - Updates an Excel Cell
	.PARAMETER
		e.g. Specify the requested parameter, if not specified this will be prompted
	.EXAMPLE
		PS C:\> write-excel $ExcelFile $WorkSheet $Column $Row $Value
#>
	$File = (ls $ExcelFile).FullName
	# Open Excel
	$Excel = New-Object -Com Excel.Application

	# Prevent Overwrite and Macro Prompt
	$Excel.displayalerts=$False

	# Open Template File

	$WorkBook = $Excel.Workbooks.Open($File)
	$WorkSheet = $WorkBook.Worksheets.Item("$WorkSheet")
	$Worksheet.Cells.Item($Row,$Column) = $Value

	# Setting All Variables to Null

	$WorkBook.SaveAs($ExcelFile,1)
	$Excel.Quit()
 	$WorkBook = $Null
	$WorkSheet = $Null
	$Excel = $Null

	# Releasing Object Wrapper

	[GC]::Collect()
}

Script of the day – ping a range of IP addresses

January 28th, 2011 No comments

Friday today, so just a quick and easy script . . nothing clever

In PowerShell, ping functionality can be handled by using the ‘test-connection’ cmdlet, or simply using .Net

A ping using test-connection is just:

$object = New-Object system.Net.NetworkInformation.Ping
$object.Send('127.0.0.1')

You can wrap it as function to get even more out of this:

function ping-ip {
param( $ip )
trap {$false; continue}
$timeout = 1000
$object = New-Object system.Net.NetworkInformation.Ping
(($object.Send($ip, $timeout)).Status -eq 'Success')
}
ping-ip 127.0.0.1
ping-ip "news.bbc.com"

You can use this function to ping IP addresses or hostnames and will get either TRUE or FALSE as a return . . so you can use this in an if statement or similar

e.g.

If (Ping-IP "labserver001.local"){write-host "Lab domain appears to be online"}

You can add a loop to create your own network segment scan:

0..255 | % { $ip = "192.168.2.$_"; "$ip = $(ping-ip $ip)" }

Importing a VM from VM Workstation to ESX / ESXi

January 28th, 2011 No comments

Importing and exporting virtual machine from a VMWare ESX Server host requires converting that virtual machine’s .vmdk file(s) from one format to another.
Although the underlying technologies work the same, the formatting of the VMDKs differ.

You have 2 options:
1) If you have a running copy of workstation, simply use VMware Converter as you would for any normal conversion, treating the VM as you normally would a physical host in a P2V
2) If you have no working Workstation, you can clone / convert the vmdk at the command line – as I have a fully ESXi lab to play in, I don’t have Workstation running on any machines in my office – as such, when IBM recently supplied a VM for a demo . . that had been created on VM workstation, I had to import it. I used the following process.

Firstly, get hold of an SSH tool ( I use putty)

Next, open a connection to any host that has the storage containing the vmdk presented

In ESX / ESXi, this will be in /vmfs/volumes/<datastorename>

Note: the destination path /dest/folder/vmserver1.vmdk should not contain any existing files with the name ‘vmserver1.vmdk’. If it does the file will be overwritten.

Importing Virtual Disks from GSX Server and Workstation to ESX Server

Before an ESX Server can run a virtual machine created on a different version of VMWare, the virtual disks must first be converted to a format that can be read by the VMFS file system. This is done by running the following vmkfstools command:

vmkfstools -i <folder>/<filename>.vmdk <vmhba number>:<filename>.dsk

<folder> is the name of the folder from which you are importing from

<filename> is the name of the virtual machine file(s) to be imported

<vmhba number> is the name of the VMFS partition you are importing to

An example of a complete command would be:

vmkfstools -i /vmfs/volumes/CLRLAB001T1/vmserver1.vmdk /vmfs/volumes/CLRLAB001T1/vmserver1_new.vmdk

Additional information regarding the vmkfstools command can be found in the ESX Server documentation.

Categories: Toolbox, VMWare Tags: , ,

Powershell – Script of the Day – Menu-Plus

January 27th, 2011 No comments

Yesterday, we created a simple Powershell menu

http://www.get-virtual.info/2011/01/26/script-of-the-day-powershell-menu-select-list/

Today’s script is a feeder for the menu, that allows you use any filed of an object as your menu source and return a different field of it as your return value.

For Example:
the following query will give you a list of the filenames in the current directory, once you select an item, it will return that ‘LastWriteTime’ of that file. – Simple

PS:8 &amp;gt;menu-plus -object (gci) -displayfield &quot;name&quot; -menuTitle Please select a file -returnfield &quot;LastWriteTime&quot;
Function menu-plus ($object, $displayfield, $menuTitle, $returnfield)

{
&amp;lt;#
.SYNOPSIS
Feeder object to Menu Function to Enable return of different field in Object

.DESCRIPTION
Requires:Menu Function
Creates a menu that allows return of a different object field.

.PARAMETER
$object - the array that we're sselecting from
$Displayfield : Name of the field that will be displayed for selection
$MenuTitle : The prompt to included at top of menu
$Returnfield : Field to be returned - defauilts to all fields

.EXAMPLE

PS: &amp;gt;$a = gci
PS: &amp;gt;$b=menu-plus -object $a -displayfield &quot;name&quot; -menuTitle Please select a file -returnfield &quot;LastWriteTime&quot;
¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦
¦ Please select a file ¦
¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦
CDB

Compare
Decom
edit-table
temp.csv
PS:87 &amp;gt;$b.LastWriteTime
25 March 2010 15:20:53
#&amp;gt;
$menulist = @()
ForEach ($item in $object){$menulist += $item.$displayfield}
$returnval = menu $menulist $menuTitle $returnfield
$output = $object | where {$_.$displayfield -eq $returnval} | Select $returnfield
return $output
}

Script of the Day – Powershell Menu Select list

January 26th, 2011 No comments

Sometimes you’d like to prompt a user to select an option from a list in Powershell . .

try this:


Function menu
{
&lt;#
	.SYNOPSIS
	 Generate a small &quot;DOS-like&quot; menu.
	.DESCRIPTION
	  Allows you to pick  a menuitem using up and down arrows, select by pressing ENTER
  	.PARAMETER
		e.g. Specify the requested parameter, if not specified this will be prompted
	.EXAMPLE
		C:\&gt; $Options = &quot;Option1&quot;, &quot;Option2&quot;, &quot;Option3&quot;, &quot;Option4&quot;, &quot;Option5&quot;
		C:\&gt; $selection = Menu $Options &quot;Please select an Option?&quot;

		****************************
		* Please select an Option? *
		****************************

		Option1
		Option2
		Option3
		Option4
		Option5

		write-host $selection
		Option1

#&gt;
    param ([array]$menuItems, $menuTitle = &quot;MENU&quot;, [switch]$quit)
    $vkeycode = 0
    $pos = 0
	If ($quit){$menuItems += &quot;Quit&quot;}
    DrawMenu $menuItems $pos $menuTitle
    While ($vkeycode -ne 13) {
        $press = $host.ui.rawui.readkey(&quot;NoEcho,IncludeKeyDown&quot;)
        $vkeycode = $press.virtualkeycode
        Write-host &quot;$($press.character)&quot; -NoNewLine
        If ($vkeycode -eq 38) {$pos--}
        If ($vkeycode -eq 40) {$pos++}
        if ($pos -lt 0) {$pos = 0}
        if ($pos -ge $menuItems.length) {$pos = $menuItems.length -1}
        DrawMenu $menuItems $pos $menuTitl
    }
	If ($($menuItems[$pos]) -eq 'Quit'){return}
	Else
	{Write-Output $($menuItems[$pos])}
}



function DrawMenu {
    ## supportfunction to the Menu function above
    param ($menuItems, $menuPosition, $menutitle)
    $fcolor = $host.UI.RawUI.ForegroundColor
    $bcolor = $host.UI.RawUI.BackgroundColor
    $l = $menuItems.length + 1
    cls
    $menuwidth = $menutitle.length + 4
    Write-Host &quot;`t&quot; -NoNewLine
    Write-Host (&quot;#&quot; * $menuwidth) -fore $fcolor -back $bcolor
    Write-Host &quot;`t&quot; -NoNewLine
    Write-Host &quot;# $menutitle #&quot; -fore $fcolor -back $bcolor
    Write-Host &quot;`t&quot; -NoNewLine
    Write-Host (&quot;#&quot; * $menuwidth) -fore $fcolor -back $bcolor
    Write-Host &quot;&quot;
    Write-debug &quot;L: $l MenuItems: $menuItems MenuPosition: $menuposition&quot;
    for ($i = 0; $i -le $l;$i++) {
        Write-Host &quot;`t&quot; -NoNewLine
        if ($i -eq $menuPosition) {
            Write-Host &quot;$($menuItems[$i])&quot; -fore $bcolor -back $fcolor
        } else {
            Write-Host &quot;$($menuItems[$i])&quot; -fore $fcolor -back $bcolor
        }
    }
}

Extending a Windows C:\ Dell EXTPart

January 26th, 2011 No comments

I get many requests to extend the C:\ (or any other drive)
Most times these are for VMs – so it is pretty easy right? Extend the amount of disk allocated to the virtual machine, then extend in Computer Management – or using diskpart?

Well this does not always work – see, Windows does not really like you messing with system drive.

Well, Dell have come up with a brilliant tool called EXTPart
http://support.dell.com/support/downloads/download.aspx?c=us&cs=19&l=en&s=dhs&releaseid=R64398&formatcnt=2&fileid=83929

All you need to do now is provision the extra space to the VM, then run the tool at the command line and follow the wizard:

C:\>extpart.exe
ExtPart - Utility to extend basic disks (Build 1.0.4)
(c) Dell Computer Corporation 2003

Volume to extend (drive letter or mount point): c:
Current volume size : 66285 MB (69504860160 bytes)
Current partition size : 76285 MB (79990815744 bytes)
Size to expand the volume (MB): 76285

that’s it – job done . . zero downtime (watch out of course . . this works differently if you have a clustered disk to extend – see:  http://www.get-virtual.info/2011/01/25/replacing-clustered-storage-for-a-sql-cluster-emc-ce-ms-clustering/ )

Categories: Toolbox Tags: , , , ,

Replacing clustered storage for a SQL cluster (EMC CE / MS Clustering)

January 25th, 2011 5 comments

So we had a client running a SQL database . . and they ran out of space.
Normally, you’d just expand disks and we’re good . . but in this instance, the SQL server was clustered – and the cluster was Geo-spanned using EMC Cluster Enabler.

The way disk access is handled is as per following diagram
#################
#               #
#   EMC CE      # (Uses Lun / Device ID to identify disks) failover)
#               #(Allows failover of GeoSpan clusters i.e. remote site
#################
       ||
       \/ (Creates a Cluster Resource to handle GeoSpan replication)
##################
#                #
# MS Cluster     # (Uses Signature ID of disk to identify disk)
#   Service      #(Provides ability to failover between 2 Servers seemlessly)
##################
        ||
        \/
#################
#               #
# DiskMgr       # (Uses Disk ID to identify disk)
#               #
#################

So in order for us to expand the disk, we need to at a DiskMgr level, simply replace the disk with a new one containing the same data . . which also happens to carry the same Disk ID, Signature ID and Device / Lun ID. Of course . . the Lun ID will change when your storage guys present new storage and the signature and disk ID can’t change while the resource is in use.

In Simple Terms, what we need to do (once shutting down your SQL services etc)is:
1) Deconfigure Cluster resource (removes the cluster
2) Stop Clustering
3) Present Disk to OS
4) Disk Offset for SQL (format / drive letter etc)
5) Copy data
4) Swap Signatures for Clustering
6) Swap Drive Letters
7) Enable Clustering
8) Configure EMC CE Group

But for those of you who need a little more info (I blog this so I too have a copy) – here is what we do:

Provision new disk(s) and replicate these at a Storage level (clariion / symmetrix etc)

Shut down SQL services (and any other apps that write to this disk)

* EMC CE
Launch EMC Cluster Enabler (screen grab config for reference)
Select Manage cluster
Under storage, make sure disk that has been presented is available to both ends (rescan if needed)
Select Groups -> <Name of Group containing disk to be replaced. -> right click -> Deconfigure Group ** this removes the resource, stopping the EMC replication for all objects in that group – Your disk is still available in the cluster and at this point your Server could in theory continue to operate . . though without the ability to failover to the other cluster Node

Check that both servers see new disks at compmgmt level
Shut down B-Node
In Device Manager, disable ‘cluster Disk driver’ (You’ll have to first right click and select ‘show hidden devices’) * This Driver is the tool that allows the Clustering service to ‘own’ a disk and manage failover etc of whole disks.
Set cluster service to Manual (Services.msc)
Bounce A-Node
At cmd use Diskpar (this is an EMC tool for managing EMC disks)
Run a DumpCfg and capture the output (again an EMC tool)
diskpar (this will list disks – provide Device IDs etc)
* recheck disk IDs and write down disk ID and signature numbers!
diskpar -S<New Disk’s Number> *follow prompts – select offset of 1920 (SQL server) – We are setting the offset of the disk to 1920 as this is for a SQL server (best practice)
Compmgmgt – Assign disk a new drive letter and format **Allocation size must be 64k!! (SQL)
Robocopy old drive to new drive
View registry to capture disk signatures (hklm\system\currentcontrolset\services\clusdisk\parameters\signatures) – new disk will be in ‘available’, old one in ‘signatures’
Dumpcfg (will display signature mappings)
{Now swap signatures} as follows:
Dumpcfg -s<New random signature to allocate old disks> <Old disk number from DeviceMgr> >> Gives new sig to old disk
Dumpcfg -s<Original disk’s old signature ID> <New Disks Device ID>

Swap drive letters in Compmgmt

Enable Cluster disk Driver in Device Manager

At this point, we have reset all identifiers according to above diagram and we need to bring everything back up (so we reverse the process)

Bounce A-Node
Start clustering (If OK, Set Service to Auto)
Verify that your drive is accesible etc.
Start B-Node

EMC CE
NodeNameLevel, right-click -> ‘configure CE cluster’ -> follow wizard