Function: Get-Documentation

March 18, 2011 Leave a comment

Righto – As mentioned here in Get-Screenshot we can easily capture our working screen. Now more than just the novelty of having a .png file filling up a random folder…. think this concept through to automatically documenting a script / build / app install.

Function Get-Documentation ($cmd,$filename="screenshot",$fold="C:\wiki\Get-Documentation",[switch]$PAUSE,[switch]$CLS,[switch]$DISPLAY)
	# note use of script block $cmd =  {gf get-screenshot -de}
	# syntax Get-Documentation -cmd {gf get-screenshot -de} -PAUSE -CLS -DISPLAY

	if ($CLS) {clear}
	"`nRunning command ""$cmd""`n" | Write-Host -ForegroundColor Green
	. $cmd

	sleep 1
	if ($PAUSE) {pause}
	if ($display) {get-screenshot $filename -fold $fold  -DISPLAY} else {get-screenshot $filename -fold $fold}

Talking through the various param options:
$cmd……………… the script block to execute
$filename……………name of the file, with a default of “screenshot”, but will also have datestamp appended
$fold…………………folder, default is “C:\wiki\Documentation”
[switch]$PAUSE……wait for user input before continuing
[switch]$CLS……….clear the powershell window before executing the script block
[switch]$DISPLAY….invoke the screengrab (for review purposes)

sample output from running command:
Get-Documentation {gf get-screenshot -de} SampleScreenShot -PAUSE -CLS -DISPLAY


Categories: Powershell

Function: Get-Screenshot

March 17, 2011 1 comment

Function: Get-Screenshot

Just as I was leaving for the day… From across the room came a granade:

I wish there was a way to grab a screenshot from the command line

Somewhere in the back of my mind I have a vague memory of catching this in a mail / post, and true enough, had the sample I was after. I messed with it a few minutes, and refined it adding my usual variables. Then stripping out the taskbar (thanks to Shay Levi) and getting the screen size dynamically (thanks Keith Hill). The result is the Function below.

Function Get-Screenshot ($filename="PrintScreen",$ext="png",$fold="C:\temp",[switch]$DISPLAY,[switch]$FULL)
	$date = Get-Date -Format yyyyMMdd_HHmm
	if (!(Test-Path $fold)) {md $fold}
	$repfile = "$fold\$filename`_$date.$ext"
	if ($FULL) 
		$screen = gwmi Win32_DesktopMonitor
		[int32]$height = $screen[0].screenHeight
		[int32]$width = $screen[0].screenWidth
	} else {
		$workarea = [System.Reflection.Assembly]::LoadWithPartialName('PresentationFramework')
		[int32]$height = [System.Windows.SystemParameters]::FullPrimaryScreenHeight
		[int32]$width = [System.Windows.SystemParameters]::FullPrimaryScreenWidth
	[reflection.assembly]::LoadWithPartialName("System.Drawing") > $null
	$Bitmap = New-Object System.Drawing.Bitmap $width,$height
	$Size = New-object System.Drawing.Size $width,$height
	$FromImage = [System.Drawing.Graphics]::FromImage($Bitmap)
	$FromImage.copyfromscreen(0,0,0,0, $Size,([System.Drawing.CopyPixelOperation]::SourceCopy))
	$Bitmap.Save($repfile,([system.drawing.imaging.imageformat]::png)); # the acceptable values: png, jpeg, bmp, gif...
	if ($DISPLAY) {
		Invoke-Item $repfile
	} else {
		return "PrintScreen saved to: $repfile"


  • The $DISPLAY switch is a simple way to flag the output to screen
  • The mix of WMI and .NET is here to show that both can be used
  • There’s a few ideas spawned off from here, tbc

    Categories: Powershell

    Identifying SAN disk usage using WMI – Powershell – Script of the Day

    March 11, 2011 Leave a comment

    So I was commissioned with identifying the amount of actual disk space used by a bunch of Microsoft Servers that were attached to various SANs on our network. Unfortunately, despite us having a rather expensive vendoir supplied product for doing this reporting, the vendor product(s) is/are dependent on agents running on the servers to actually report back what the performance stats look like.

    I fugured that the information must be accessible via WMI so I set about trying to identify something that identified disks as being remote / SAN attached.

    I had a crack using several different WMI classes, thinking that I may need to tie the results from a hardware based query to identify physical disks, against the results of something like the win32_logicaldisk class – but was drawing a blank.

    to identify similarities / differences betwen hosts I decided to just spit our the results of the Disk / Volume classes for a handful of hosts

    I tried the following classes:

    After interrogating a few hosts (some SAN attached, some not . I noticed a similarity in the device IDs returned in the following class win32_Volume.

    you see all of our servers are set to have local disk for the C: and CDROM for the Z: (so I had a control group)
    Executing the following however . . against a LONG list of server seemed to always return C: and Z: with device IDs in the format:


    Now I have looked around for an explanation as to why all the Local Disks and Local CD Roms appear with tat number at the end, but I can find no confirmation – but I figured I’d simply create a PowerShell script using this snippet of info to generate the report I require.

    First of all, the wmi query that I would need :
    gwmi -ComputerName <servername> -class win32_volume | select deviceid, driveletter

    Now all I need to do is contruct a method to repeat the above and churn out a nice Excel style report to show disk utilisation . .

    Here is the result

    Function get-sandisks ([string]$InputFilename,[string]$OutputFilename)
    $servers = gc $InputFilename
    $MyObj = @()
    # Cycle through the servers in the file
    foreach ($server in $servers)
    {Write-Host $server -ForegroundColor Green
    # first test if we can ping the server (quicker than trying WMI straight away)
    If (Test-Connection $server -Count 1)
    if (Get-WmiObject -ComputerName $server Win32_LogicalDisk -ea 0)
    {$disks = gwmi -ComputerName $server -class win32_volume | ?{$_.driveletter} #| ?{$_.deviceid -notmatch "806e6f6e6963"} #| select deviceid, driveletter
    If ($disks)
    {foreach ($disk in $disks)
    $rep = "" | select "Server Name", "Drive Letter", "Disk Space", "Used Space", "Free Space", "DeviceID", "Type"
    $Rep."Server Name" = $server
    $Rep."Drive Letter" = $disk."driveletter"
    $Rep."Disk Space" = $disk | %{$_.Capacity}
    $Rep."Free Space" = $disk | %{$_.Freespace}
    $Rep."Used Space" = $Rep."Disk Space" - $Rep."Free Space"
    If ($disk.deviceid -notmatch "806e6f6e6963"){$rep.Type = "SAN"}
    {$Rep.Type = "Local"}
    $Rep."DeviceID" = $disk | %{$_.deviceID}
    Write-Host $rep
    $MyObj += $Rep
    $rep = $null
    $rep = "" | select "Server Name", "Drive Letter", "Disk Space", "Used Space", "Free Space", "DeviceID", "Type"
    $Rep."Server Name" = $server
    $Rep."Drive Letter" = "WMI"
    Write-Host $rep "WMI" -ForegroundColor Yellow
    $MyObj += $Rep
    $rep = $null
    {              $rep = "" | select "Server Name", "Drive Letter", "Disk Space", "Used Space", "Free Space", "DeviceID", "Type"
    $Rep."Server Name" = $server
    $Rep."Drive Letter" = "PING"
    Write-Host $rep "PING" -ForegroundColor Yellow
    $MyObj += $Rep
    $rep = $null
    $MyObj | sort | Export-Csv -Path $OutputFilename -NoTypeInformation

    While I appreciate that this is  not 100% accurate, I simply wanted to report on space that is in use by the SAN and is no local disk, so the result is fit for my purpose.

    Copying data to a VM datastore using PowerCli – Script of the Day

    March 8, 2011 Leave a comment

    Ever needed to copy data from your local machine to a VMware datastore . .and not felt like messing around with winSCP / FastSCP, the Datastore browser etc?

    PowerCli / PowerShell lets you create a new PSProvider item for your datastore, which in turn lets you copy data using the normal Copy-Item syntax. (though using Copy-DatastoreItem instead)

    So, if you have a Datastore in your ESX environment called ‘Datatstore1’ and you want to copy an iso from your C:\ISO directory, it would be as simple as

    PS: >new-PSDrive -location (get-datastore 7523_local) -name myds -PSProvider VimDatastore -Root '\'
    Name           Used (GB)     Free (GB) Provider      Root                                               CurrentLocation
    ----           ---------     --------- --------      ----                                               ---------------
    myds                                   VimDatastore  \lonlab001@443\Prod\7523_local
    PS: >Copy-DatastoreItem -item C:\ISO\install.iso -Destination myds:\ISOS\Myiso.iso -force

    Also, as the drive is now a normal PSProvider path, normal commands like get-childitem work like they do on a local drive

    PS: >gci myds:
       Datastore path: [7523_local]
                LastWriteTime            Type       Length Name
                -------------            ----       ------ ----
         21/04/2010     07:40          Folder              esxconsole-4bcdbd...
         08/03/2011     16:31          Folder              ISOS


    Of course this gives you full access to all of the datat on your datastores directly form a PowerCli session, so you can run any sort of reports / inventories etc that you may need. Happy days . .

    Categories: Powershell, Scripting, VMWare

    ‘Upgrading’ from ESX to ESXi – a multipart series – Tools

    March 2, 2011 Leave a comment

    Setting up the test environment

    In order to get this whole build tested, we need a repeatable and accessible Lab environment.

    If you are unfortunate enough to not have an ESX lab environment that you can play on, you could build a workstation and emulate your production environment right on your desktop using VMware workstation.

    Tools that we’ll require (so need to download if you do not have them already) are as follows:


    · Installation guide

    · Download : (you’ll need a free logon)

    You favourite script editor

    · I use PowerGui : – but you can use anything you like

    A VMware ESXi Server, or VMware workstation to run tests on, along with a copy of the ESXi Installable media

    · – you can get trials of both from here

    Copies of the various tools we’ll be testing

    · UDA (Ultimate Deployment Appliance) –

    · EDA (ESX Deployment appliance) –

    · VMware’s own ‘Auto Deploy’ –

    · SD / USB duplication – WinImage –

    · V-PXEServer –

    · Manual installation – Just the Install ISO above

    Assuming that not everyone has spare hardware at their disposal, I guess it would be useful to create VMs to act as ESXi hardware on which to test our installations.

    If you’re using VMWare workstation as your lab – Full guide at:

    Quick Video:

    If you are using an ESX(i) host to run your test ESXi VMs on, follow the guide at :

    For each appliance based deployment method, we’ll create a new VM – these will be detailed as we test each appliance

    Categories: Virtualisation, VMWare

    ‘Upgrading’ from ESX to ESXi – a multipart series – Intro

    March 2, 2011 Leave a comment

    ‘Upgrading’ from VMWare ESX 4.0 to ESXi 4.1(u1) – with as few button clicks as possible.

    Anyone reading the official docs from VMware at : is likely to be annoyed and frustrated at the lack of actual information as to how to manage the ‘upgrade’ (migration) from ESX to ESXi.

    There is no direct way to upgrade directly as the 2 products are effectively 2 different operating systems that behave in exactly the same way. (well not really, but they are installed totally differently and are managed slightly differently)

    Anyway, we have about 80 ESX hosts to migrate to ESXi, so I decided to find the easiest method to do so.

    A scour of the web found several great resources. – and some valuable information. It seems that nobody has yet delivered a full ‘upgrade’ solution, but several people have provided automated deployments of the core installation and several other people have created configuration scripts for the newly installed ESX. So I have decided to add an additional ‘information gathering’ step, then ‘borrow’ some of the work done elsewhere and put together an ‘upgrade’ solution.

    Scratching my head, I have been working on a simpler way to manage the deployment / upgrade.

    The way I see it, the ‘upgrade’ needs 3 parts:

    1) Capture configuration from the existing ESX host that we will be replacing (we may need to interpret and reformat it for our new ESXi Host

    2) Deploy new ESXi instance on the hardware

    3) Deploy captured config to our new ESXi host.

    Whilst I realise that this probably will not be enough to make it a full ‘upgrade’ the idea is to get as much done as quickly as possible.

    Coming up will be several posts, documenting comparisons of 5 methods of deployment, as well as some PowerCli code and a look into Host Profiles for easing this process.

    On the off chance that one of the vendors that do ‘migration’ tools feel like offering me a free license to trial their tool and write up a process doc, I may even be inclined to review that for people with $$$ – but it is important that it is noted that I promise no allegiance to any tools, as would like this review to be fair and open to all. The end product of the series should provide a decision as to my preferred FREE method for doing the migration.

    At the end of the series, I’ll create a comparison table comparing the various products, as a springboard for anyone who’ll soon be in the same situation as me.

    For environments where there are only 2 or 3 ESX hosts, I’d consider building a solution like this going overboard, so I will make the assumption that readers of the series are people who have large numbers of hosts to upgrade and therefore will be wanting to work on ESX / ESXi rather than VMware workstation. As such, I will endeavour to get all tools working on ESXi and will highlight tweaks required (several of the tools I have tested so far were created on VMware workstation and therefore do not import directly to ESX hosts)

    Products that I will be including in my review for the deployment include:

    1. UDA (Ultimate Deployment Appliance) –

    2. EDA (ESX Deployment appliance) – (0.90 in VMware appliance Marketplace, but 0.94 available at: )

    3. VMware’s own ‘Auto Deploy’ –

    4. SD / USB duplication

    5. Manual installation (I will include this as a benchmark – remember ESXi requires very few clicks as is to get running, so manual may still be the way to go)

    I will go through the options for the deployment of ESXi, before doing the capture and deploy steps above (I need a deployment workframe to work on, so it makes sense in this case)

    All tests for now will be run in my isolated lab, with the convenient luxury of the deployment servers being located on the same subnets etc as the Hosts I’ll be deploying to, but once I have selected a solution and start the migration of 80 ESX hosts to ESXi, I will of course post details of any further tweaks required for deployment.


    Categories: Virtualisation, VMWare Tags:

    Script of the Day – Scripted start of Virtual Center when hosted as a VM

    February 25, 2011 Leave a comment

    There are many threads on the VM communities, debating whether it is better to run a VC on a physical host, or a VMWare host.

    My answer is always that running it as a VM is better, but the arguement always comes back that if I have catastrophic faiilure and don’t know where my VC last lived . . I will be in trouble.

    Of course, plan a is to simply set the restart policy on the VM to start with the host, but people tell me they have had mixed results with this approach.

    The alternative is a quick PowerCli script that quickly connects to each ESX host in the cluster, checks if it owns the VM, then starts the VM.

    $vCenters = "ESXHost1", "ESXhost2", "ESXHost3"
    $VCServer = "VCServer"
    $userName = "username"
    $passwd = Read-Host ("Password for " + $userName) -AsSecureString:$true
    $cred = New-Object System.Management.Automation.PSCredential -ArgumentList $userName,$passwd

    One catch to be aware of though is that if you are using AD for DNS and all AD servers are VMs, you will be unable to resolve the ESX host names for the script to work, so you’ll need to specify IP addresses to the ESX hosts.

    You do not however need to specify the DNS server IP for the VM, as the script look s as VM Names and

    You could extend the above script then to start a series of VMs with a set wait time between VMs (e.g. start the DC for DNS etc, then start the SQL server, then start the VC, wait 60 seconds between each start)

    <pre>Disconnect-VIServer * -Confirm:$false
    $vCenters = "", "", ""
    $vms = "DNSServer", "SQLServer", "VCServerName"
    $userName = "root"
    $passwd = Read-Host ("Password for " + $userName) -AsSecureString:$true
    $cred = New-Object System.Management.Automation.PSCredential -ArgumentList $userName,$passwd
    # time to wait before starting next VM
    $waittime = 60
    Foreach ($vm in $vms){
     ForEach ($vCenter in $vCenters) {
     connect-VIServer -Server $vCenter -Credential $cred
     If (get-vm $VCServer -ea 0)
     Start-VM $vm
     Write-Host "VM $VM Starting on $vCenter" -ForegroundColor Green
     Write-Host "Sleeping for $waittime to allow $vm to start up"
     sleep $waittime
     disconnect-VIserver -confirm:$false

    And if you are feeling really flash, you could get each VM start, then monitor that VM for a particular services on thon that VM to run, before starting the next VM (if you have relevant access rights etc)

    Prime example here is where I need a VM running my AD/DNS to start, before I can start the SQL server. Then, I want te SQL server to start and the service running, before I can start the Virtual Center.

    # remove any VI connections that you may create in your PS Profile
    Disconnect-VIServer * -Confirm:$false
    # List of ESX hosts (by IP here as we are assuming DNS lives on a VM)
    $ESXHosts = "", "", ""
    # 2 dimensional array, each row reflecting the VM to start and the service that I need to monitor
    $vms = ("ADDNSServerName", "DNS"), ("SQLServerName","MSSQLSERVER"),("VCServerName","vpxd")
    $userName = "root"
    $passwd = Read-Host ("Password for " + $userName) -AsSecureString:$true
    $cred = New-Object System.Management.Automation.PSCredential -ArgumentList $userName,$passwd
    # Connect to all ESX hosts in array $ESXHosts
    ForEach ($ESXHost in $ESXHosts) {connect-VIServer -Server $ESXHost -Credential $cred}
    Foreach ($vm in $vms){
     Write-Host "Searching for $vm[0]" -ForegroundColor Blue
     ForEach ($ESXHost in $ESXHosts) {
     If (get-vm -Name $vm[0] -server $ESXHost -ea 0)
     Start-VM -VM $vm[0] -Server $ESXHost
     Write-Host "VM $VM Starting on $ESXHost" -ForegroundColor Green
     $i = 0
     $running = "no"
     do {$running = Get-Service -ComputerName $vm[0] -Name $vm[1] -ea 0 | % {$_.status}; sleep 1; $i++; Write-Host "Waiting for $vm[1] service to start on $vm[0]- $i seconds elapsed" -ForegroundColor Yellow}
     while ($running -ne "Running")
     Write-Host "$vm[1] service started on $vm[0]" -ForegroundColor Green
    Write-Host "VC should now be up and running" -ForegroundColor Red