Archive

Archive for the ‘Powershell’ Category

Who fancies knowing when the rugby is on?

September 1st, 2015 No comments

Been messing around with some regex for some boring work related consumption of poorly constructed data – when I thought why not do something useful?

Rugby world Cup is around the corner – let’s make the schedule accessible from my Powershell session

(be warned, this was a quick and nasty – no comments, no instructions)

 

</pre>
Function Get-RugbySchedule
{
$fixturesXML = (invoke-webrequest -uri "http://www.ultimaterugby.com/match/list").ParsedHtml.body.innerHTML
$maincontent = $fixturesXML -split "main-content" | select -skip 1 -first 1

$items =  $maincontent | Select-String '(?s)(<DIV class=match-item.*?</SPAN></DIV></DIV>)' -AllMatches

$item = $items.matches[1].Value
$out = @()
foreach($item in $items.Matches.Value)
{
$ret = "" | select Detail, HomeTeam, AwayTeam, HomeScore, AwayScore, Status, Kickoff, Date, Venue, Tournament
$teams = ($item | Select-String '(?<=class=team-name>).*?(?=</SPAN>)' -AllMatches).Matches
if($teams.count -eq 2)
{
$ret.Hometeam = $teams[0].Value
$ret.AwayTeam = $teams[1].Value
$scores =  ($item | Select-String '(?<=(<SPAN class=score>|<SPAN class="score win">)).*?(?=</SPAN>)' -AllMatches).Matches
if($scores.Count -eq 2)
{
$ret.HomeScore =$scores[0].value
$ret.AwayScore = $scores[1].Value
}

}

$ret.Status = ($item | Select-String '(?<=<META content=)(.*?)(?=itemprop="eventStatus">)' -AllMatches).Matches[0].Value.Replace('"',"")
$ret.Detail = ($item | Select-String '(?<=<META content=)(.*?)(?=itemprop="name">)' -AllMatches).Matches[0].Value.Replace('"',"")

$kickoff = ($item | select-string '(?<=<DIV class=kickoff>).*?(?=</DIV>)').Matches.Value
$ret.Kickoff = ($kickoff | Select-String '([0-9]|0[0-9]|1[0-9]|2[0-3]):[0-5][0-9]').Matches.Value
$ret.Date = ($kickoff | select-string '(?<=<SPAN class=date>)(.*?)(?=</SPAN>)').Matches.Value

$locationInfo =  ($item | Select-String '(?s)(?<=itemprop="location").*?(?=</DIV>)' -AllMatches).Matches.Value
$ret.Venue = ($locationInfo | select-string '(?<=>)(([a-zA-Z0-9_ ])+?)(?=<)').Matches.Value

$details = ($item | select-string '(?<=<DIV class=tournament>).*?(?=</DIV>)').Matches.Value
$ret.Tournament = ($details | select-string '(?<=>)(([a-zA-Z0-9_ ])+?)(?=<)').Matches.Value
$out += $ret
}
return $out
}

Categories: Powershell Tags: ,

Powershell behind a Proxy server

June 30th, 2015 No comments

so there I was, living in my Powershell session, when I stumbled across a cmdlet that looked kinda useful.
I wanted a little more info, but when I ran “get-help ” – I discovered that my local help files were out of date.

That’s easy to fix -no?:

Update-Help : Failed to update Help for the module(s) 'Microsoft.PowerShell.Management, Microsoft.PowerShell.Security,
Microsoft.PowerShell.Utility, CimCmdlets, ISE, Microsoft.PowerShell.Diagnostics, Microsoft.PowerShell.Host, Microsoft.WSMan.Management,
PSDesiredStateConfiguration, PSScheduledJob, PSWorkflow, PSWorkflowUtility, Microsoft.PowerShell.Core' with UI culture(s) {en-US} : Unable
to connect to Help content. The server on which Help content is stored might not be available. Verify that the server is available, or
wait until the server is back online, and then try the command again.
At line:1 char:1
+ update-help
+ ~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [Update-Help], Exception
    + FullyQualifiedErrorId : UnableToConnect,Microsoft.PowerShell.Commands.UpdateHelpCommand

errr . . .no!

Of course, I was in the office – behind a corporate proxy, that needed authentication . . and I needed my Powershell session to use my corporate proxy.

As it goes, the ie proxy settings are managed by GPO, so I figured I’d just use these.

First step – let’s check what our Powershell environment is using for its proxy:

netsh winhttp show proxy


Current WinHTTP proxy settings:

    Direct access (no proxy server).

hmm – not great, let’s change it

netsh winhttp import proxy source=ie
netsh winhttp show proxy

cool – we have now told Powershell to use our ie proxy.
Now, in our environment, we need to authenticate against the proxy.

If you manually authenticate (Username, Password) take this approach:

$webclient=New-Object System.Net.WebClient
$creds=Get-Credential
$webclient.Proxy.Credentials=$creds

Alternatively, if you are in a Domain environment and your proxy accepts NTLM/AD Auth, here’s what to do:

$webClient = new-object System.Net.WebClient
$webClient.Headers.Add(“user-agent”, “PowerShell Script”)
$webClient.Proxy.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials

Magic.

Now all that’s left to do is run

Update-Help

And try remember what it was that you were trying to achieve in the first place.

Categories: Powershell Tags:

Invoking SSH commands using powershell (kinda)

June 30th, 2015 No comments

Sometimes, you need to fire SSH commands from a Powershell session.
This is quite quick and easy if you have the right tools.

First of all, get the Posh-SSH cmdlets off github:
https://github.com/darkoperator/Posh-SSH

Install this like any other module (Drop it in your PSModulePath – else amend the code below to import the module from wherever you would like to execute it)
Now simply fire away using the module.

clever work (none of the credit to me)

I’ve used this for invoking SSH commands against ESX hosts, Dell iDracs and other SSH devices. Simple and quite reliable. I find it far more consistent than plink.exe etc

# Quick and untested copy of what you need:

Import-Module Posh-SSH

# Create Pwd (this saves a file copy)
# read-host -assecurestring | convertfrom-securestring | out-file $env:userprofile\$env:username.txt

# Retrieve info from file previously created under user profile
$username = "username@domain.net.intra"
$password = get-content $env:userprofile\$env:username.txt | convertto-securestring
$credential = new-object -typename System.Management.Automation.PSCredential -argumentlist $username,$password

# Create SSH Session
$ssh = New-SSHSession -ComputerName $vmhost -Credential $credential -AcceptKey 1

# Invoke SSH command and capture output as string (you can return the full object if you like, I just needed the string Out)
$ret = $(Invoke-SSHCommand -SSHSession $ssh -Command "racadm getconfig -g cfgUserAdmin -i 2").Output

# return object is a String - if you want it as an array of strings for each row returned
$ret = $ret.split("`n")


# Clean up your mess
Remove-SSHSession -SSHSession $ssh
Remove-variable ssh

Categories: Powershell Tags:

Create ESXi Host firewall rules using PowerCli

February 13th, 2015 No comments

Recently, I needed to create some custom firewall rules on ESX hosts (lots of them) – for some Syslog servers that were in addition to our existing Syslog servers.

Here was my appraoach (note – Firewall rules will be lost at reboot unless you hack bootbank, or make the changes using custom VIBs)
http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=2007381

http://cormachogan.com/2014/03/28/adding-bespoke-firewall-rules-to-esxi/

The code has dependecnies on Posh-SSH (freely available, excellent automation tool)

# PowerCLI Script for enabling SSH, setting firewall and disable SSH alert in vCenter
# multiple dependencies 
# https://github.com/darkoperator/Posh-SSH 
# PowerCli


#Requires -Modules ActiveDirectory
#Requires -Version 4
#Requires -Modules Posh-SSH


# Sample update
import-module posh-ssh
add-pssnapin vm*
$vmhostname = read-host "Please provide target ESX hostname"
Connect-VIServer <viservname>
$Credential = Get-Credential -Message "Please provide root user password for $vmhostname" -UserName "root"

# enable SSH on ESX host (function below)
Set-SshOnVmHost -VMHostName $vmhostname -Status On

# Create firewall rule on ESX host
new-FireWallRuleonVmHost -VMHostName $vmhostname -direction outbound -protocol tcp -porttype dst -serviceID myServicename -port 1234 -enabled false -required false

# Display the change
$esxcli = Get-EsxCli -VMHost $vmhostname
$esxcli.network.firewall.ruleset.list()

# Disable SSH on the host
Set-SshOnVmHost -VMHostName $vmhostname -Status Off


function Set-SshOnVmHost
{
    Param(
        [String]
        $VMHostName,
        [ValidateSet('On','Off')]
        [String]
        $Status
        )

    	write-host "Configuring SSH on host: $($vmHost.Name) to $Status" -fore Yellow
        if((Get-VMHostService -VMHost $vmhostname | where {$_.Key -eq "TSM-SSH"}).Policy -ne "$Status"){
            Write-Host "Setting SSH service policy to automatic $status $($vmHost.Name)"
            Get-VMHostService -VMHost $vmhostname | where { $_.key -eq "TSM-SSH" } | Set-VMHostService -Policy "$Status" -Confirm:$false -ea 1 | Out-null
	    }
    
        $vmhost = get-vmhost $vmhostname
      
        $esxcli = Get-EsxCli -VMHost $vmhost
        if($Status -eq 'On'){
	        if((Get-VMHostService -VMHost $vmhost | where {$_.Key -eq "TSM-SSH"}).Running -ne $true){
                Write-Host "Starting SSH service on $($vmHost.Name)"
                Start-VMHostService -confirm:$false  -HostService (Get-VMHost $vmHost | Get-VMHostService | Where { $_.Key -eq "TSM-SSH"}) | Out-null
                $ip = (Get-WmiObject -class win32_NetworkAdapterConfiguration -Filter 'ipenabled = "true"').ipaddress[0]
	            if($esxcli -ne $null){
                    if($ip.count -ne 1){
                        $ip = read-host "Please provide the IP address that should be to access this host via SSH"
                    }
                    try{
                        test-ipaddress $ip
                        if(($esxcli.network.firewall.ruleset.allowedip.list("sshServer") | select AllowedIPAddresses).AllowedIPAddresses -eq "All"){
                            Write-Host "Changing the sshServer firewall configuration"        
                            $esxcli.network.firewall.ruleset.set($false, $true, "sshServer")
                             if(($esxcli.network.firewall.ruleset.allowedip.list("sshServer") | select AllowedIPAddresses).AllowedIPAddresses -notmatch "$ip"){
                                $esxcli.network.firewall.ruleset.allowedip.add("$ip", "sshServer")
                            }
                            $esxcli.network.firewall.refresh()
                        }
                    }
                    catch {
                        throw "Unable to configure IP restirctions on Firewall when enabling SSH $_"		        
                    }
		        }
            }
        }
        else{
	        if((Get-VMHostService -VMHost $vmhost | where {$_.Key -eq "TSM-SSH"}).Running -ne $false){
                Write-Host "Stopping SSH service on $($vmHost.Name)"
                Stop-VMHostService -confirm:$false -HostService (Get-VMHost $vmHost | Get-VMHostService | Where { $_.Key -eq "TSM-SSH"}) | Out-null
                write-host "Set Firewall rule too allow all IPs for SSH, but disable the service"
		        if(($esxcli.network.firewall.ruleset.allowedip.list("sshServer") | select AllowedIPAddresses).AllowedIPAddresses -ne "All"){
        	        Write-Host "Changing the sshServer firewall configuration"        
        		        $esxcli.network.firewall.ruleset.set($true, $true, "sshServer")
            	        $esxcli.network.firewall.refresh()
                }
            }
        }
            
	    # End Comment
	    if(($vmHost | Get-AdvancedSetting | Where {$_.Name -eq "UserVars.SuppressShellWarning"}).Value -ne "1"){
            Write-Host "Suppress the SSH warning message"
        	    $vmHost | Get-AdvancedSetting | Where {$_.Name -eq "UserVars.SuppressShellWarning"} | Set-AdvancedSetting -Value "1" -Confirm:$false | Out-null
        }
 }

 function Test-IPaddress
{
    [CmdletBinding()]
    Param
    (
        [Parameter(Mandatory=$true,
                   ValueFromPipelineByPropertyName=$true,
                   Position=0)]
        [ValidateScript({$_ -match [IPAddress]$_ })]  
        [string]
        $IPAddress
    )

        [ipaddress]$IPAddress
}


# function for creation of a new Firewall rulle on an ESX host

function new-FireWallRuleonVmHost {
 Param( [Parameter(Mandatory=$true)]
        [String]
        $VMHostName,
        [Parameter(Mandatory=$true)]
        [ValidateSet('inbound','outbound')]
        [String]
        $direction,
        [Parameter(Mandatory=$true)]
        [ValidateSet('tcp','udp')]
        [String]
        $protocol,
        [Parameter(Mandatory=$true)]
        [ValidateSet('dst','src')]
        [String]
        $porttype,
        [Parameter(Mandatory=$true)]
        [String]$serviceID,
        [ValidateRange(0,65536)]
        [int]$port,
        [Parameter(Mandatory=$true)]
        [ValidateSet('true','false')]
        [String]
        $enabled,
        [Parameter(Mandatory=$true)]
        [ValidateSet('true','false')]
        [String]
        $required
        )

    # Create an SSH Session to the target
    $ssh = New-SSHSession -ComputerName $VMHostName -Credential $credential
   
    # Get the SSH Session's ID
    $sessionId = $($ssh.Index)
    
    # Copy original service.xml to .bak
    Invoke-SSHCommand -Command  "cp /etc/vmware/firewall/service.xml /etc/vmware/firewall/service.xml.bak" -Index $sessionId

    # Allow write access over existing service.xml
    Invoke-SSHCommand -Command  "chmod 644 /etc/vmware/firewall/service.xml" -Index $sessionId

    # Change the sticky bit
    Invoke-SSHCommand -Command  "chmod +t /etc/vmware/firewall/service.xml" -Index $sessionId

    # Create a local copy of the service.xml file
    $out = %{Invoke-SSHCommand -Command  "cat /etc/vmware/firewall/service.xml" -Index $sessionId}
    $out.Output > c:\temp\services.xml
    1$xml = $out.Output

    # Sort through IDs to find the highest current value (assuming 
    $ids = @(); $list = $xml.ConfigRoot.service | %{$_.id}  | ?{$_ -match '0'} | %{$ids += [int]$_}
    [string]$id = "`'00" +  (($ids | sort-object -Descending | select-object -First 1) + 1).ToString() + "`'";

    # insert xml for new service custom xml before closing  the closing <`/ConfigRoot`>
    $newXml = (get-content C:\temp\servicestmp.xml | Select-String -Pattern "`<`/ConfigRoot`>" -NotMatch) + @"
    <service id=$id>
        <id>$serviceID</id>
        <rule>
            <direction>$direction</direction>
            <protocol>$protocol</protocol>
            <porttype>$porttype</porttype>
            <port>$port</port>
        </rule>
        <enabled>$enabled</enabled>
        <required>$required</required>
    </service>
</ConfigRoot>
"@ > "C:\temp\services.xml"

    # copy new xml to services.xml on vm host
    Set-SCPFile -ComputerName $VMHostName -Credential $credential -LocalFile C:\temp\services.xml -RemoteFile /etc/vmware/firewall/service.xml
    
     # Prevet write access over service.xml
    Invoke-SSHCommand -Command  "chmod 444 /etc/vmware/firewall/service.xml" -Index $sessionId

    # Change the sticky bit
    Invoke-SSHCommand -Command  "chmod -t /etc/vmware/firewall/service.xml" -Index $sessionId
    
    # Refresh Firewall Rules on ESX host
    Invoke-SSHCommand -Command  "esxcli network firewall refresh" -Index $sessionId
       
    # remove the SSH Session that you created
    remove-sshSession -index $sessionId

}
Categories: Powershell, VMWare Tags:

Last boot time with PowerShell

November 14th, 2012 No comments

Has to retrieve a bunch of boot times for a list of servers – quickly put together a function (I know there are many equally easy ways – but felt like retrieving info via PowerShell as part of a bigger report)

Function get-lastboot { 
 param($computername)
$date = Get-WmiObject Win32_OperatingSystem -ComputerName $computername | foreach{$_.LastBootUpTime}
$RebootTime = [System.DateTime]::ParseExact($date.split('.')[0],'yyyyMMddHHmmss',$null) 
$RebootTime

} #end function

Like so:

PS C:\scripts\Powershell> get-lastboot winhost7

20 October 2012 20:20:11
Categories: Powershell, Toolbox Tags:

Finding an unsused IP address on a subnet using Powershell

October 12th, 2012 No comments

I have been doing a bunch of P2Vs lately and sometimes when VMWare converter decides to not play along, I resort to offline conversions using Platespin convert.
Platespin likes to have about 4 IPs allocated for different reasons per conversion, so I decided to wroite a quick function to find unused IPs.

First of all, I alreday had some subnetting functions available (I found these online) – so all I had to do was write the extra bit of code.

Historically, I used to do this each time:

1..254 | %{$ip = "10.2.25.$_"; test-connection $ip -count 1 -ea 0}

This of course becomes a pain after a while, so this is where I went (the following all lives in my proifile, so is accesible each time I open a new Shell)

I have tried to track down the source of my original IP Subnetting function – I *think it was

function Get-UnusedIPAddress ($hostname, $subnet, $mask="255.255.255.0",$IPCount,[switch]$verbose,[switch]$all,$skip)
{
if ($verbose.IsPresent) {
  $VerbosePreference = 'Continue'
  Write-Verbose "Verbose Mode Enabled"
}
Else {
  $VerbosePreference = 'SilentlyContinue'
}

If ($hostname)
	{
	write-host "Attempting to access host NIC for accurate Subnet / Mask info" -fore green
	$hostdetails =  get-nics $hostname | ?{$_.DefaultIPGateway} |  select -first 1
	if ($hostdetails)
		{
		$subnet = $hostdetails | %{$_.IPAddress} | select -first 1
		$mask = $hostdetails | %{$_.IPsubnet} | select -first 1
		}
	else
		{
		write-host "No WMI access - will use NSLookup and simply scan the /24 address"
		}
	}
	if (!($subnet))
		{
		$subnet = [Net.Dns]::GetHostEntry("$hostname") | %{$_.Addresslist} | select -first 1 | %{$_.IPAddressToString}
		If (!($subnet)){return "Invalid request - please revise your query"}
		}
	$range = Get-NetworkSummary -IP $subnet -Mask $mask | %{$_.Range}
	write-host "Finding available IP(s) on $subnet/$mask - range $range" -fore green
	$range = Get-NetworkRange $subnet $mask
	$returnIPs = 1
	If ($skip){$range = $range | select -skip $skip}
	ForEach($rangeIP in $range)
		{
		If (!(test-connection $rangeIP -count 1 -ea 0))
			{
			write-host "Testing $rangeIP"
			If (($returnIPs -lt $IPcount) -OR ($all))
				{
				write-host $rangeIP -fore yellow
				$returnIPs++
				}
			Else
				{
				write-host $rangeIP -fore yellow
				return
				}
			}
		}
	return
}

The idea is that you can simply say

Get-UnusedIPAddress

The Function runs a WMI wuery against the specified hostname (or IP) and uses the IP and SM to find the first available IP after this.

Additional switches allow for the following:
$subnet – Specify the subnet to trawl (where you do not yet have a host in place) – Example : 10.2.1.0
$mask – If the function is unable to hit your specified host, it will defaul to a /24 Subnet mask – you may want to check a small / bigger range – Example 255.255.255.240
$IPCount – The Number of IPs that you would like returned
$all – Instructs the script to find all IPs in the range that are currently unused

I was surprised just how much I use this, once I had created it.

Supporting and useful functions that enable this script:


Function ConvertTo-BinaryIP {
  <#
    .Synopsis
      Converts a Decimal IP address into a binary format.
    .Description
      ConvertTo-BinaryIP uses System.Convert to switch between decimal and binary format. The output from this function is dotted binary.
    .Parameter IPAddress
      An IP Address to convert.
  #>
 
  [CmdLetBinding()]
  Param(
    [Parameter(Mandatory = $True, Position = 0, ValueFromPipeline = $True)]
    [Net.IPAddress]$IPAddress
  )
 
  Process {
    Return [String]::Join('.', $( $IPAddress.GetAddressBytes() |
      ForEach-Object { [Convert]::ToString($_, 2).PadLeft(8, '0') } ))
  }
}

Function ConvertTo-DecimalIP {
  <#
    .Synopsis
      Converts a Decimal IP address into a 32-bit unsigned integer.
    .Description
      ConvertTo-DecimalIP takes a decimal IP, uses a shift-like operation on each octet and returns a single UInt32 value.
    .Parameter IPAddress
      An IP Address to convert.
  #>
 
  [CmdLetBinding()]
  Param(
    [Parameter(Mandatory = $True, Position = 0, ValueFromPipeline = $True)]
    [Net.IPAddress]$IPAddress
  )
 
  Process {
    $i = 3; $DecimalIP = 0;
    $IPAddress.GetAddressBytes() | ForEach-Object { $DecimalIP += $_ * [Math]::Pow(256, $i); $i-- }
 
    Return [UInt32]$DecimalIP
  }
}

Function ConvertTo-DottedDecimalIP {
  <#
    .Synopsis
      Returns a dotted decimal IP address from either an unsigned 32-bit integer or a dotted binary string.
    .Description
      ConvertTo-DottedDecimalIP uses a regular expression match on the input string to convert to an IP address.
    .Parameter IPAddress
      A string representation of an IP address from either UInt32 or dotted binary.
  #>
 
  [CmdLetBinding()]
  Param(
    [Parameter(Mandatory = $True, Position = 0, ValueFromPipeline = $True)]
    [String]$IPAddress
  )
 
  Process {
    Switch -RegEx ($IPAddress) {
      "([01]{8}\.){3}[01]{8}" {
        Return [String]::Join('.', $( $IPAddress.Split('.') | ForEach-Object { [Convert]::ToUInt32($_, 2) } ))
      }
      "\d" {
        $IPAddress = [UInt32]$IPAddress
        $DottedIP = $( For ($i = 3; $i -gt -1; $i--) {
          $Remainder = $IPAddress % [Math]::Pow(256, $i)
          ($IPAddress - $Remainder) / [Math]::Pow(256, $i)
          $IPAddress = $Remainder
         } )
 
        Return [String]::Join('.', $DottedIP)
      }
      default {
        Write-Error "Cannot convert this format"
      }
    }
  }
}

Function ConvertTo-MaskLength {
  <#
    .Synopsis
      Returns the length of a subnet mask.
    .Description
      ConvertTo-MaskLength accepts any IPv4 address as input, however the output value
      only makes sense when using a subnet mask.
    .Parameter SubnetMask
      A subnet mask to convert into length
  #>
 
  [CmdLetBinding()]
  Param(
    [Parameter(Mandatory = $True, Position = 0, ValueFromPipeline = $True)]
    [Alias("Mask")]
    [Net.IPAddress]$SubnetMask
  )
 
  Process {
    $Bits = "$( $SubnetMask.GetAddressBytes() | ForEach-Object { [Convert]::ToString($_, 2) } )" -Replace '[\s0]'
 
    Return $Bits.Length
  }
}

Function ConvertTo-Mask {
  <#
    .Synopsis
      Returns a dotted decimal subnet mask from a mask length.
    .Description
      ConvertTo-Mask returns a subnet mask in dotted decimal format from an integer value ranging
      between 0 and 32. ConvertTo-Mask first creates a binary string from the length, converts
      that to an unsigned 32-bit integer then calls ConvertTo-DottedDecimalIP to complete the operation.
    .Parameter MaskLength
      The number of bits which must be masked.
  #>
 
  [CmdLetBinding()]
  Param(
    [Parameter(Mandatory = $True, Position = 0, ValueFromPipeline = $True)]
    [Alias("Length")]
    [ValidateRange(0, 32)]
    $MaskLength
  )
 
  Process {
    Return ConvertTo-DottedDecimalIP ([Convert]::ToUInt32($(("1" * $MaskLength).PadRight(32, "0")), 2))
  }
}

Function Get-NetworkAddress {
  <#
    .Synopsis
      Takes an IP address and subnet mask then calculates the network address for the range.
    .Description
      Get-NetworkAddress returns the network address for a subnet by performing a bitwise AND
      operation against the decimal forms of the IP address and subnet mask. Get-NetworkAddress
      expects both the IP address and subnet mask in dotted decimal format.
    .Parameter IPAddress
      Any IP address within the network range.
    .Parameter SubnetMask
      The subnet mask for the network.
  #>
 
  [CmdLetBinding()]
  Param(
    [Parameter(Mandatory = $True, Position = 0, ValueFromPipeline = $True)]
    [Net.IPAddress]$IPAddress,
 
    [Parameter(Mandatory = $True, Position = 1)]
    [Alias("Mask")]
    [Net.IPAddress]$SubnetMask
  )
 
  Process {
    Return ConvertTo-DottedDecimalIP ((ConvertTo-DecimalIP $IPAddress) -BAnd (ConvertTo-DecimalIP $SubnetMask))
  }
}


Function Get-BroadcastAddress {
  <#
    .Synopsis
      Takes an IP address and subnet mask then calculates the broadcast address for the range.
    .Description
      Get-BroadcastAddress returns the broadcast address for a subnet by performing a bitwise AND
      operation against the decimal forms of the IP address and inverted subnet mask.
      Get-BroadcastAddress expects both the IP address and subnet mask in dotted decimal format.
    .Parameter IPAddress
      Any IP address within the network range.
    .Parameter SubnetMask
      The subnet mask for the network.
  #>
 
  [CmdLetBinding()]
  Param(
    [Parameter(Mandatory = $True, Position = 0, ValueFromPipeline = $True)]
    [Net.IPAddress]$IPAddress,
 
    [Parameter(Mandatory = $True, Position = 1)]
    [Alias("Mask")]
    [Net.IPAddress]$SubnetMask
  )
 
  Process {
    Return ConvertTo-DottedDecimalIP $((ConvertTo-DecimalIP $IPAddress) -BOr `
      ((-BNot (ConvertTo-DecimalIP $SubnetMask)) -BAnd [UInt32]::MaxValue))
  }
}


Function Get-NetworkSummary ( [String]$IP, [String]$Mask ) {
  If ($IP.Contains("/"))
  {
    $Temp = $IP.Split("/")
    $IP = $Temp[0]
    $Mask = $Temp[1]
  }
 
  If (!$Mask.Contains("."))
  {
    $Mask = ConvertTo-Mask $Mask
  }
 
  $DecimalIP = ConvertTo-DecimalIP $IP
  $DecimalMask = ConvertTo-DecimalIP $Mask
 
  $Network = $DecimalIP -BAnd $DecimalMask
  $Broadcast = $DecimalIP -BOr
    ((-BNot $DecimalMask) -BAnd [UInt32]::MaxValue)
  $NetworkAddress = ConvertTo-DottedDecimalIP $Network
  $RangeStart = ConvertTo-DottedDecimalIP ($Network + 1)
  $RangeEnd = ConvertTo-DottedDecimalIP ($Broadcast - 1)
  $BroadcastAddress = ConvertTo-DottedDecimalIP $Broadcast
  $MaskLength = ConvertTo-MaskLength $Mask
 
  $BinaryIP = ConvertTo-BinaryIP $IP; $Private = $False
  Switch -RegEx ($BinaryIP)
  {
    "^1111"  { $Class = "E"; $SubnetBitMap = "1111" }
    "^1110"  { $Class = "D"; $SubnetBitMap = "1110" }
    "^110"   {
      $Class = "C"
      If ($BinaryIP -Match "^11000000.10101000") { $Private = $True } }
    "^10"    {
      $Class = "B"
      If ($BinaryIP -Match "^10101100.0001") { $Private = $True } }
    "^0"     {
      $Class = "A"
      If ($BinaryIP -Match "^00001010") { $Private = $True } }
   }  
 
  $NetInfo = New-Object Object
  Add-Member NoteProperty "Network" -Input $NetInfo -Value $NetworkAddress
  Add-Member NoteProperty "Broadcast" -Input $NetInfo -Value $BroadcastAddress
  Add-Member NoteProperty "Range" -Input $NetInfo `
    -Value "$RangeStart - $RangeEnd"
  Add-Member NoteProperty "Mask" -Input $NetInfo -Value $Mask
  Add-Member NoteProperty "MaskLength" -Input $NetInfo -Value $MaskLength
  Add-Member NoteProperty "Hosts" -Input $NetInfo `
    -Value $($Broadcast - $Network - 1)
  Add-Member NoteProperty "Class" -Input $NetInfo -Value $Class
  Add-Member NoteProperty "IsPrivate" -Input $NetInfo -Value $Private
 
  Return $NetInfo
}

Function Get-NetworkRange( [String]$IP, [String]$Mask ) {
  If ($IP.Contains("/"))
  {
    $Temp = $IP.Split("/")
    $IP = $Temp[0]
    $Mask = $Temp[1]
  }
 
  If (!$Mask.Contains("."))
  {
    $Mask = ConvertTo-Mask $Mask
  }
 
  $DecimalIP = ConvertTo-DecimalIP $IP
  $DecimalMask = ConvertTo-DecimalIP $Mask
 
  $Network = $DecimalIP -BAnd $DecimalMask
  $Broadcast = $DecimalIP -BOr ((-BNot $DecimalMask) -BAnd [UInt32]::MaxValue)
 
  For ($i = $($Network + 1); $i -lt $Broadcast; $i++) {
    ConvertTo-DottedDecimalIP $i
  }
}
Categories: Powershell, Toolbox Tags:

Useful scripts for amending the number of ports per vSwitch

May 1st, 2012 No comments

We have found that on many (most) of our ESX hosts, we run at risk of running our of vbSwitch ports when we run through our maintenance periods and reduce the number of hosts in a cluster.
Below are the scripts that I use to amend these settings:

# Calculating ports in use on each vSwitch: 
$myCol = @() 
ForEach ($VMHost in (get-cluster "prod Core" | Get-VMHost | Sort Name)) 
        { 
        ForEach ($VM in ($VMHost | Get-VM)) 
                { 
                ForEach ($NIC in (Get-NetworkAdapter -VM $VM)) 
                        { 
                        $myObj = "" | Select VMHost, VM, NIC, PortGroup, vSwitch 
                        $myObj.VMHost = $VMHost.Name 
                        $myObj.VM = $VM.Name 
                        $myObj.NIC = $NIC.Name 
                        $myObj.PortGroup = Get-VirtualPortGroup -VM $VM -Name $NIC.NetworkName 
                        $myObj.vSwitch = $myObj.PortGroup.VirtualSwitchName 
                        $myCol += $myObj 
                        } 
                } 
        } 
$myCol | Group-Object VMHost, vSwitch -NoElement | Sort Name | Select Name, Count 

“To upgrade the port numbers on vSwitch1 on myesxhost.intra to 120 ports , you need:”

# To increase number of ports on a vSwitch 
Get-VMHost "myserver1.intra" | % {Get-VirtualSwitch -VMHost $_ -Name vSwitch0 | where {$_.NumPorts -lt "128"}} | % { Set-VirtualSwitch -VirtualSwitch $_ -NumPorts "128" } 

“Note, the PowerCli says ‘128’ – the reason for this is that VMware reserves 8 ports for overhead on each vswitch.
(http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1008040)

You’ll also want to vMotion the Vms off each host – you can highlight multiple VMs and drag and drop, or right click, select ‘migrate’ and follow the wizard.
If you want to PowerCli it, you can try the following:”

# For a controlled migration. moving all VMs on myserver1 to myserver2 
get-vmhost myserver1.intra | get-vm | move-vm -destination (get-vmhost myserver2.intra) 

“The above will prompt you on each VM – you can ignore all prompts with :”

# to Ignore prompts 
get-vmhost myserver1.intra | get-vm | move-vm -destination (get-vmhost myserver2.intra) -Confirm:$false 

We previously had a bug that NICs lost the connection state(i.e. – the ‘Connected’ box got unchecked) – the solution was to move the VMs to a host that had available switch ports and then set the Nic’s to connected.”

#To find disconnected NICs in Prod Core cluster:" 
$vms = Get-Cluster "Prod Core" | Get-VM 
Get-NetworkAdapter ($vms | where {$_.powerstate -eq “poweredon”}) | Where { $_.connectionstate.connected -eq “$F” } | select parent, connectionstate 
#To repair change all disconnected NICs in a cluster to connected 
$vms = Get-NetworkAdapter ((Get-Cluster "Prod Core HA" | Get-VM) | where {$_.powerstate -eq “poweredon”}) | Where { $_.connectionstate.connected -eq “$F” } | select parent, connectionstate 
foreach ($a in $vms) 
{ 
$vm = get-vm $a.parent 
write-host $a.parent -back green 
if (!(test-connection $vm.name )) 
   { 
   $nics = $vm | get-networkadapter | Where {$_.ConnectionState.Connected -eq $false -and $_.ConnectionState.StartConnected -eq $true} 
   if ($nics -ne $null) 
   { 
           foreach ( $nic in $nics ) 
           { 
                     write-host $vm.Name 
                     write-host $nic 
                        If (test-connection  $vm.Guest.HostName -count 1 -ea 0){write-host "Returning Pings!!"; return}else{write-host "Not Returning Pings"} 
         } 
                $nic | Set-NetworkAdapter -Connected $true 
        } 
  
                        If (test-connection  $vm.Guest.HostName -count 3 -ea 0){write-host "Returning Pings!!"}else{write-host "Not Returning Pings"} 
        } 
} 
Categories: Powershell, Toolbox, VMWare Tags:

Querying BMC ADDM / Atrium from Powershell.

August 30th, 2011 No comments

We have a new discovery appliance at a client site – BMC atrium.

I was having a look at it and unfortunately it does not have a normal SQL backend . . so it is not as easy to collect information as I would like (well . . .it is if you do a little legwork)

Looking through the docs, I found they do have an API – and actually . . the API was incredibly simple to use – just need some web access.

Well. my weapon of choice is always PowerShell . . so all I need is a simple web query no?

there are a few tricks though.

I do not want to have to keep providing my password
I would not like any clear text passwords knocking about
I want to be able to pass Queries that contain special characters
I’d like a simply object returned that can easily be manipulated using normal PowerShell syntax.

Here’s what I came up with.

Note – you’ll need to specify a server and a proxy (or include these in your function by editing the values in the first line of the function

Remember – it would be best practice to create a read-only account and use these creds for queries.


Function get-Addm ([string]$query,$servername"myserver.lab.local", $username, $password, $proxy="myproxy.lab.local", [switch]$resetpwd)
	{
	# Use system reflection to convert string to URL.
	[System.Reflection.Assembly]::LoadWithPartialName("System.Web") | out-null
	$query = [System.Web.HttpUtility]::UrlEncode($query)
	
	# Check for password / gather password info
	If ($resetpwd)
		{del $env:userprofile\$username.txt}
	If (!$username)
		{
		write-host "No Username specified - using $env:username" -fore Green
		$username = $env:username
		}
	if (test-path $env:userprofile\$username.txt)
		{
		write-host "Stored creds found for $username" -fore Green
		}
		else
		{
		write-host "No Password saved for $username - please specify a valid pwd" -fore Green
		read-host -assecurestring | convertfrom-securestring | out-file $env:userprofile\$username.txt
		}
		$password = get-content $env:userprofile\$username.txt | convertto-securestring
		$credentials = new-object -typename System.Management.Automation.PSCredential -argumentlist $username,$password

	# Decrypt stored creds 
	$pw =  $credentials.GetNetworkCredential().password
	
	# Create Web request
	$proxy = new-object System.Net.WebProxy $proxy
	# $proxy.credentials = $proxycred.GetNetworkCredential()
	
	$WebClient = New-Object System.Net.WebClient
	$webclient.proxy = $proxy 
	$url = "https://$servername/ui/api/CsvApi?query=$query&username=$username&password=$pw"
	$Webclient.DownloadFile($url, "$env:temp\tmp.csv")
		#Import captured CSV
	$csv = import-csv "$env:temp\tmp.csv"
	return $csv
	}

So now I can simply generate a custom query in the GUI – then recycle this query for future searches, using Powershell – and get an opbject returned which I can edit as per normal Powershell queries.

so – for example, I’d like all windows servers and the DNS servers currently configured for these:

get-addm -query "SEARCH Host WHERE (os HAS SUBSTRING 'windows') SHOW name, os, vendor, virtual, partition, #InferredElement:Inference:Associate:DiscoveryAccess.endpoint, #DeviceWithInterface:DeviceInterface:InterfaceOfDevice:NetworkInterface.dns_servers AS 'DNS Servers'" -username "read_only" -servername "myappliance"

Categories: ADDM, Powershell Tags:

Powershell – Converting multiple return values to single strings for reports

June 24th, 2011 No comments

Sometimes, you’re writing a little Powercli / Powershell code to generate a report and the repotr you generate retuns multiple values for some lines.

for example, you want a report showing each ESX host in your environment’s mapped VLANs and Datastores – or you’d like to interrogate some servers and return their DNSServers – as single objects.

[string]::Join is your friend here.

for example:

Get-VirtualPortGroup -VMHost $vmhost | %{$_.VlanId}
2598
2599
553
552
638
637
104
119
2470
2460
2951
2465
19
17
50
633
634
635
636

Hmm – this has returned a nice list – but I don;t want a new line for each VLAN.

so let’s join that into a comma sepated string?

[string]::Join(',',(Get-VirtualPortGroup -VMHost $vmhost | %{$_.VlanId}))
2598,2599,553,552,638,637,104,119,2470,2460,2951,2465,19,17,50,633,634,635,636

Ahh – much better!

so now I can generate my original report to find VLANs and Datastores mapped to hosts in my cluster

get-cluster $cluster | Get-VMHost | Select Name,
    @{N="VLAN";E={[string]::Join(',',(Get-VirtualPortGroup -VMHost $_ | %{$_.VlanId}))}},
    @{N="Datastore";E={[string]::Join(',',(Get-Datastore -VMHost $_ | %{$_.Name}))}}
Name                                              VLAN                                              Datastore
----                                              ----                                              ---------
LABESX8.get-virtual.info                         3410,3415,3430,3435,3425,3420,0,0,2640           LABSTG112L055,LABSTG112L062,LABSTG112L012..
labesx17.get-virtual.info                         3410,3415,2640,3425,3435,3430,3420,0,0,0         LABSTG112L055,LABSTG112L062,LABSTG112L099..
labesx18.get-virtual.info                         3410,3415,3430,3435,3425,3420,0,0,2640           LABSTG112L055,LABSTG112L062,LABSTG112L099..
labesx21.get-virtual.info                         3410,3415,2640,3435,3430,3425,3420,0,0           LABSTG112L055,LABSTG919119,LABSTGHA919L116_FI,..
labesx40.get-virtual.info                         3410,3415,2640,3435,3430,3425,3420,0,0           LABSTG112L055,LABSTG112L062,LABSTG112L099..
labesx25.get-virtual.info                         3410,3415,2640,3435,3430,3420,3425,0,0           LABSTG112L055,LABSTG919119,LABSTGHA919L116_FI,..

the magic lies here:

[string]::Join(',',(

What this is saying is joing the response from the following queery – into 1 string . .seperated by ‘,’

job done – pretty reports here we come!

Categories: Powershell, VMWare Tags:

Opening a Port on a Windows machine using Powershell

May 23rd, 2011 No comments

Quick one today . .

Someone in the office asked me how to quickly open a TCP port on a Windows host in order to do some firewall / port testing across vlans.

I figured, let’s do it in Powershell – pretty simple, just open an http listener.

Like so:

function open-socket ($port)
	{
	($prefix="http://+:$port/")
	# create an httplistener listening on the specified prefix url
	$listener = new-object Net.HttpListener
	$listener.Prefixes.Add($prefix)
	$listener.Start()
	}
	

Simple, just change the port number as applicable and job’s a good’un.

Categories: Powershell Tags: