Posts Tagged ‘Powershell’

Using regular expressions to parse files in PowerShell – Script of the Day

March 28th, 2011 No comments

How often do you find yourself needing to identify a string in a file somewhere.

For example, you have a log file, or a config file and you know it contains an IP address, but you do not want to manually trawl through this file (or even worse . . these files)

Regular expressions are pretty handy, as you can use them to identify (and edit) strings of text pretty simply. thik of it as a Replace function on steroids.

Here are some examples:

Anyway, back to our original question – we’d like to find an IP address in a file.

The first thing of course is to get hold of the text in our file – we’ll drop it into an array, so we can do a line by line comparison..

$var = @(Get-Content .\Access*.log)

Next, we need to create a Regex string pattern, which we will use as reference when we query out text – there are plenty examples available on the web (e.g. – but we just need one to find IP addresses:

$regex = [regex] "\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}"

Lastly, we simply need to return a list of elements in our array, where the array matches the REGEX search string – again simple:

$regex.matches($var) | Select-Object -unique -property "Value"

so the full bit of code:

$var = @()
$var = Get-Content .\Access*.log
$regex = [regex] "\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}"
$regex.matches($var) | `Select-Object -unique -property "Value"


Finding VMs with disks on multiple different datastores – Script of the Day

March 23rd, 2011 No comments

I was looking at a VM on one of our hosts and noticed the rather odd configuration showed that the VM had 2 disks provisioned (not unusual), and that the 2 disks had been presented on different storage (very unusual for non clustered VMs in our environment)

I figured, the easiest way to identify all of the VMs that are using VMDKs on multiple different datastores was PowerCli.

The result – just a one liner.

PS:7 >get-vm | ?{$_.DatastoreIdList.count -gt 1}

Name                 PowerState Num CPUs Memory (MB)
----                 ---------- -------- -----------
labserver001     PoweredOn  1        8192
labserver 17a         PoweredOn  2        1280
labserver21        PoweredOn  1        8192
labserver17b         PoweredOn  2        1152

Powershell – (Get-virtual).info – RSS Capture with Powershell through a proxy

March 22nd, 2011 No comments

a little geekery . . .

As the blog is called ‘Get-Virtual’  . .I figure we may as well have a cmdlet / function to allow us to actually get the content of get-virtual . . . so I quickly put together an RSS reader to capture the RSS feed for the blog and export it to a GridView

The function is not entirely useless, as it will demonstrate 6 new things
1 – Using Powershell to get info from the web
2 – Accessing the web from Powershell through a proxy
3 – Authenticating through the proxy using Powershell
4 – Reading an RSS feed using Powershell
5 – Exporting a Powershell object to a GridView
6 – Reading / Parsing XML using Powershell

Exporting the info captured into a GridView makes it easy to filter the data and view what the latest posts etc are.

I have hashed a little ‘replace’ code out in the script as several of the older posts had special characters that get misinterpreted . . so you could remove the hashes to clean this up if you really wanted.

here is the code:

function get-virtual 
	([string]$proxyserver = (Get-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings"  | %{$_.ProxyServer}),
	{	$proxy = new-object System.Net.WebProxy $proxyserver
		If ($auth)
			{if (!$proxycred) 
			{$proxycred = Get-Credential}
			$proxy.credentials = $proxycred.GetNetworkCredential()
		$WebClient = New-Object System.Net.WebClient
		$webclient.proxy = $proxy
		$WebClient = Get-WebClient
        $blog =  1$Webclient.DownloadString("")
		$obj = @() # New-Object psobject
		for ($i=1; $i -le $; $i = $i + 1)
		$rep = "" | select "Title", "Link", "Creator", "Date"
		$rep."Title" = ($[$i].title)#.toString().replace("`â`€`“","-").replace("`â`€`˜","`"").replace("`â`€`™","`"")
		$rep."Link" = ($[$i].Link)#.toString().replace("`%e2`%80`%98","`'").replace("`%e2`%80`%99","`'").replace("","")
		$rep."Creator" = $[$i].Creator
		$rep."Date" = $[$i].PubDate
		$Obj += $Rep
		$obj | Out-GridView -Title " Fat(ish) client"
		return $obj


and here is the result:

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

March 11th, 2011 No comments

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 vendor 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.

Script of the Day – Scripted start of Virtual Center (and supporting servers) when hosted as a VM

February 25th, 2011 No comments

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)

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 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

so all you now need to do is keep a copy of the above script and make sure the few fields in the first few rows remain up to date with your ESX hostnames and the Servers / Services that you require to run your VC.

It is kind of a vApp in a script . .
have a great weekend

Script of the day – Powercli one liner to get ESX host versions

February 24th, 2011 No comments

So I was looking at an ESX estate that is managed by someone else and was hoping to do a few ‘Get-EsxCli’ queries.
Of course Get-EsxCli only works properly from 4u2, so I needed to find a host that was patched up to date.

The easy way? PowerCli of course.

get-view -ViewType HostSystem -Property Name,Config.Product | select Name,@{N="Build";E={$_.Config.Product.FullName}} | sort build,name

Script of the day – testing if 2 IP addresses are on the same subnet

February 21st, 2011 No comments

Ever needed to script around IP addressing issues on hosts and needed to determine whether 2 hosts are in fact on the same subnet or not?

Try the following Function

Function Compare-Subnets {
param (


$mask =""

if (($ip1.address -band $mask.address) -eq ($ip2.address -band $mask.address)) {$true}
else {$false}


The code simply does a binary comparison of the 2 IP addresses.

– much like you used to do when you first did TCPIP subnetting (some of you may remember this)

To use it, the syntax is simply as follows

Compare-Subnets -IP1 $IP1 -IP2 $IP2 -mask $SubnetMask

and the return is simply a boolean True or False. – Simple

e.g.PS:115 >Compare-Subnets -ip1 -ip2 -mask

Script of the Day – new(ish) Powercli cmdlets Get-ESXTop – part 1

February 18th, 2011 No comments

Ignore this post – found it written up far better than I could ever manage:

When I have some time, I’ll write a wrapper for get-ESXTOP and get-esxcli to make these easier to use. In the mean time, head over to for a decent guide!

Yes I know, some of you noticed these a while ago, but I have not been paying attention.

Back in December, the PowerCli guys released a new version of the Cli for us : Of course, I installed straight away, but did not go through the release notes.

Anyway, long story short, I noticed 2 particularly useful little cmdlets have appeared:

Get-Esxtop (no more SSH access required) –

and Get-ESXCli -

Of course, this is very exciting news. As a rule, I try user PowerCli as my first port of call for everything – SSH / Console access is a distant second as far as I am concerned (call me lazy)

Anyway, generally, when I need to view counters for a VM, I go to and use those values as a guide as to what I should be tracking.

We run (we have to connect direct to an ESX host to use these tools – so connect using the normalsyntax first)

 connect-viserver &lt;hostname&gt;

Well first things first, using get-esxtop we may not know what exactly we’d like to query, so to return the set of cuonters available to us,

PS:6 &gt;get-esxtop -Counter
Name                 Fields
----                 ------
Server               {MinFetchIntervalInUsec:U64, IsVMVisor:B, TimeStampInUsec:U64, Time:S64}
COS                  {UserTimeInUsec:U32, NiceTimeInUsec:U32, SysTimeInUsec:U32, IdleTimeInUsec:U3...
PCPU                 {NumOfLCPUs:U32, NumOfCores:U32, NumOfPackages:U32}
LCPU                 {LCPUID:U32, CPUHz:U64, UsedTimeInUsec:U64, HaltTimeInUsec:U64...}
PMem                 {PhysicalMemInKB:U32, COSMemInKB:U32, KernelManagedInKB:U32, NonkernelUsedInK...
NUMANode             {NodeID:U32, TotalInPages:U32, FreeInPages:U32}
Sched                {HostCPUInPct1Min:U32, HostCPUInPct5Min:U32, HostCPUInPct15Min:U32, NumOfSche...
SchedGroup           {GroupID:U32, GroupName:STR, IsValid:B, IsVM:B...}
CPUClient            {CPUClientID:U32, IsValid:B, NumOfVCPUs:U32}
HiddenWorld          {HiddenWorldID:U32, HiddenWorldName:STR}
VCPU                 {VCPUID:U32, WorldName:STR, IsValid:B, Affinity:U64...}
VMem                 {MemClientID:U32, IsValid:B, CurrentSwapInKB:U32, ToBeSwappedInKB:U32...}
VMNUMANodeMem        {NodeID:U32, IsValid:B, GuestMemInKB:U32, OverheadMemInKB:U32}
SCSI                 {NumOfReservations:U64, DurationInUsec:U64, NumOfConflicts:U64, ConfigNumOfOu...
Adapter              {AdapterName:STR, IsValid:B, QueueDepth:U32, NumOfChannels:U32}
Channel              {ChannelID:U32, IsValid:B, NumOfTargets:U32}
Target               {TargetID:U32, IsValid:B, NumOfLuns:U32}
Lun                  {LunID:U32, IsValid:B}
Path                 {PathName:STR, DeviceName:STR, IsValid:B, NumOfCommands:U64...}
WorldPerDev          {WorldID:U32, IsValid:B, NumOfActiveCmds:U32, NumOfQueuedCmds:U32...}
Partition            {PartitionID:U32, IsValid:B, NumOfCommands:U64, NumOfBlocksRead:U64...}
SCSIDevice           {DeviceName:STR, IsValid:B, QueueDepth:U32, BlockSizeInBytes:U32...}
Nfs                  {NumOfNfsClients:U32}
NfsClient            {MountName:STR, NumOfReads:U64, ReadByte:U64, ReadTimeInUsec:U64...}
Net                  {NumOfPortsets:U32, NumOfPNICs:U32}
NetPortset           {PortsetName:STR, IsValid:B, NumOfPorts:U32}
NetPort              {PortID:U32, IsValid:B, IsUplink:B, ClientName:STR...}
PNIC                 {PNICName:STR, UplinkPort:U32, IsValid:B, IsLinkUp:B...}
Interrupt            {NumOfInterruptVectors:U32}
InterruptVector      {VectorID:S64, Devices:STR, NumOfCPUs:U32}
InterruptPerCPU      {CPUID:U32, Count:U64, SysTimeInUsec:S64}
Power                {NumOfLCPUs:U32}
CStateInfo           {StateID:S32}
PStateInfo           {StateID:S32}
TStateInfo           {StateID:S32}
LCPUPower            {LCPUID:U32, NumOfCStates:U32, NumOfPStates:U32, NumOfTStates:U32}
CState               {StateID:S32, ResidentTimeInUsec:S64}
PState               {StateID:S32, ResidentTimeInUsec:S64}
TState               {StateID:S32, ResidentTimeInUsec:S64}

hmm, seems to provide a long list (more than 200 once you go into each of the branches) – but most importantly, they are nicely distributed by what they monitor.

to get a slightly easier to read output of this, we can run

$out = @()
foreach($counter in (Get-EsxTop -Counter)){
 foreach($field in $counter.Fields){
 $row = &quot;&quot; | Select Counter,Field,Type
 $row.Counter = $counter.Name
 $row.Field = $field.Name
 $row.Type = $field.Type
 $out += $row
$out | Export-Csv &quot;C:\counters.csv&quot; -NoTypeInformation -UseCulture

OK, so now we have a list of counters – and looking at ESXTOp these seem to align directly with the normal column headers. We know what we have, we have a list of counters in the doc above from VMware, to help us know what to view . . so how do we view these counters?

Well pretty simple really – let’s say we want to read all VCPU related counters, it is as simple as

Get-EsxTop -CounterName  VCPU | select * | ft -AutoSize

Right, this is about where I started scratching my head – no number of select statements or cleverness seems toreturn info for just the one VM, so what do we do?

well….with a little help from our other new cmdlet we’ll soon be churning out pretty live stats. …. Watch this space….I’ll post the rest of the solution early next week.

Categories: Powershell, VMWare Tags: ,

Script of the Day – Creating AD groups without QAD cmdlets

February 10th, 2011 No comments

We’re automating some server builds and need to create AD groups to manage resource access to each Server (company policy)
We use SCCM for deployment and I wanted to automate the groups (at build time)
Also, I did not want to have any dependencies on external Modules (so I want to do this without the quest tools)

I found a few documents online for creating AD groups that went without the quest tools, but found that most did not work.

You see, our key problem was that we wwanted to create Domain Local Security Groups.
In VBScript, this was pretty simple, as on the ‘put’ portion of group creation, you just told the script to apply both Group type constants, using an or statement.
The theory was that this would work in Powershell too (and many online script seemed to indicate that it would) – but the group types being created were inconsistent.

Below are the constants for the different group types:

Value GroupType
2 Global distribution group
4 Domain local distribution group
8 Universal distribution group
-2147483646 Global security group
-2147483644 Domain local security group
-2147483640 Universal security group

So creating a Domain Local Security group is as simple as:

$groupType = -2147483644
$objOU = [ADSI]&quot;LDAP://localhost:389/OU=YourOUName,DC=Example,DC=com&quot;
$GroupName = &quot;MyNewGroup&quot;
$objGroup = $objOU.Create(&quot;group&quot;, &quot;CN=&quot; + $GroupName)
$objGroup.Put(&quot;groupType&quot;, $groupType )
$objGroup.Put(&quot;sAMAccountName&quot;, $GroupName )

Of course you can change the LDAP binding to a DC (rather than localhost) and you can change the GroupType by amending the value of $GroupType
Even better, you could wrap it into a Function, with a switch statement to take care of Group type selection.

Happy days.

Monitoring VM Logs – Nearly real time monitoring – Script of the day

February 9th, 2011 No comments

Today’s Script of the day is not one of my own, but one I have used a few times in the past few weeks – and I figured I should post here as a reminder for when I next need it.

Written by the scripting wizard LucD, it is a tool that basicall ymonitors and displays VM logs . . almost as they happen.

A great and very effective script for troubleshooting realtime VM issues.