Monthly Archives: October 2011

Reading the hosts file–revised

Quick revision to the post on reading the hosts file http://msmvps.com/blogs/richardsiddaway/archive/2011/10/23/reading-the-hosts-file.aspx.

I wanted to be able to display the whole file

function get-hostfilecontent {            
 param ([switch]$all)            
 $file = Join-Path -Path $($env:windir) -ChildPath "system32\drivers\etc\hosts"            
 if (-not (Test-Path -Path $file)){            
   Throw "Hosts file not found"            
 }            
 $cont = Get-Content -Path $file             
 if ($all) {            
   $cont            
 }            
 else {            
   $cont |             
   where {!$_.StartsWith("#")} |            
   foreach {            
     if ($_ -ne ""){            
       $data = $_ -split " ",2            
       New-Object -TypeName PSObject -Property @{            
         Server = $data[1].Trim()            
         IPAddress = $data[0].Trim()            
       }            
     }            
   }            
 }            
}


so added an $all switch.  If this is selected the full contents of the file are displayed otherwise just the IP address entries are displayed as before

Multiple value query in WQL

A simple query that demonstrates how to query for multiple values. We want to stop the running services that are running where the names a like BITS and WinRm

Get-WmiObject -Class Win32_Service -Filter "State='Running' AND Name LIKE '%BITS%' OR Name LIKE '%WinRM%'" |
Invoke-WmiMethod -Name StopService

 

Define the service state and use AND to link to the names and then OR to say you want name A or name B.  If it is easier to visualise use the syntax like this

Get-WmiObject -Class Win32_Service -Filter "State='Running' AND (Name LIKE '%BITS%' OR Name LIKE '%WinRM%')"

 

It does work!

 

To restart the services

Get-WmiObject -Class Win32_Service -Filter "State='Stopped' AND Name LIKE '%BITS%' OR Name LIKE '%WinRM%'" |
Invoke-WmiMethod -Name StartService

Logging non-contactable systems

In this post - http://msmvps.com/blogs/richardsiddaway/archive/2011/10/23/1760058.aspx – I showed how to get the date of the last update applied to a system.  A comment was posted asking how to log machines that can’t be contacted

".", "rslaptop01", "200.0.0.1" | foreach {              
    if (Test-Path -Path hotfix.log){Remove-Item -Path hotfix.log -Force}            
                
    if(-not(Test-Connection -ComputerName $_ -Count 1 -Quiet)){            
      Add-content -Path hotfix.log -Value "Could not contact $($_) at $(get-date)" -Encoding ASCII            
    }            
    else {            
      Get-HotFix -ComputerName $_  |              
      Where {$_.InstalledOn} |              
      sort InstalledOn -Descending |              
      select CSname, @{Name="Installed";              
      Expression={"{0:dd MMMM yyyy}" -f [datetime]$_.InstalledOn.Tostring()}} -First 1             
    }            
}


Simply add a couple of lines to run Test-Connection and if you don’t get an answer then write out to a log file.

Clearing hosts file

We seen how to delete a single entry from the hosts file – this is how we clear all entries

function clear-hostfilecontent {            
 [CmdletBinding()]            
 param ()            
 $file = Join-Path -Path $($env:windir) -ChildPath "system32\drivers\etc\hosts"            
 if (-not (Test-Path -Path $file)){            
   Throw "Hosts file not found"            
 }            
 Write-Verbose "Remove IP Addresses"            
 $data = ((Get-Content -Path $file) -notmatch "^\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b")             
             
 $data             
              
 Set-Content -Value $data -Path $file -Force -Encoding ASCII             
}


 



Don’t bother with parameters and change the regex to pick off any lines that don’t start with an IP address (or at least the pattern that represents an IP address).  Write the data back to the file.  I’ve used ASCII encoding on these because the default is Unicode which uses 2 bytes per character and isn’t really usable.

PowerShell, Storage, WMI and Windows Server 8

A must read if you are interested in any of these

http://blogs.technet.com/b/server-cloud/archive/2011/10/14/windows-server-8-standards-based-storage-management.aspx

 

WMI is getting everywhere these days – better learn it quick

Remove a host file record

Next up is removing a record from a hosts file

function remove-hostfilecontent {            
 [CmdletBinding()]            
 param (            
  [parameter(Mandatory=$true)]            
  [ValidatePattern("\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b")]            
  [string]$IPAddress,            
              
  [parameter(Mandatory=$true)]            
  [string]$computer            
 )            
 $file = Join-Path -Path $($env:windir) -ChildPath "system32\drivers\etc\hosts"            
 if (-not (Test-Path -Path $file)){            
   Throw "Hosts file not found"            
 }            
 Write-Verbose "Remove IP Address"            
 $data = ((Get-Content -Path $file) -notmatch "$ip\s+$computer")            
              
 $data             
              
 Set-Content -Value $data -Path $file -Force -Encoding ASCII             
}


 



Get an IP Address and computer as before. Create the path to the hosts file.



Read the files contents and perform a –notmatch using the IP Address and computername in the regular expression.  \s+ means one or more white spaces. This removes the record we don’t want.



I managed to create a regular expression that works Smile



Then write the data back.  normally I wouldn’t look at completely re-writing a file like this but the hosts file is small so its probably as quick and it makes the code really simple.

Minor rant

Why do software suppliers – Adobe with Acrobat Reader & Oracle with Java are the worst culprits – insist on trying to install their browser toolbar & change my default search engine??

What’s worse is that they make the default action to install it & I have to remember each and every time their products update – at least once a week! – to untick the box so it doesn’t install.

 

I really hate this behaviour – please stop.

I know you won’t but I had to ask

PowerShell and WMI – new MEAP release

Four new chapters have been added to the MEAP  (early access) for PowerShell and WMI

Chapter 14 - Users and security

Chapter 15 - Logs, jobs, and performance

Chapter 16  - Hyper-V

Chapter 17 - Windows Remote Management

 

Chapter 17 deals with using WMI over the WSMAN cmdlets

 

The MEAP is available from http://www.manning.com/siddaway2/

 

The last two chapters (18&19) deal exclusively with the  CIM cmdlets and other new features in PowerShell v3

Hosts file – add a record

We’ve seen how to read the Hosts file – this is how we add a record

function add-hostfilecontent {            
 [CmdletBinding(SupportsShouldProcess=$true)]            
 param (            
  [parameter(Mandatory=$true)]            
  [ValidatePattern("\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b")]            
  [string]$IPAddress,            
              
  [parameter(Mandatory=$true)]            
  [string]$computer            
 )            
 $file = Join-Path -Path $($env:windir) -ChildPath "system32\drivers\etc\hosts"            
 if (-not (Test-Path -Path $file)){            
   Throw "Hosts file not found"            
 }            
 $data = Get-Content -Path $file             
 $data += "$IPAddress  $computer"            
 Set-Content -Value $data -Path $file -Force -Encoding ASCII             
}


 



Take an IP address and computer as parameters.  Test if the hosts file exists



Read the contents, add the new record and write back.



This ensures that the new record is actually on a new line all by itself

Reading the hosts file

Normally I ignore the Hosts file but my development laptop isn’t a member of my test domain – a number of reasons for this which I won’t go into.

This means that when I want to RDP to a machine in the test domain I have to use the IP address. A bit awkward but not too bad until I start changing the machines and I need to remember more IP addresses. Time to use the Hosts file then I can just refer to machine name.  First off need to be able to read the hosts file.

Could just use

Get-Content -Path C:\Windows\system32\drivers\etc\hosts

but that’s no fun.  Lets identify the bits of the file we need and junk the rest.

function get-hostfilecontent {            
 $file = Join-Path -Path $($env:windir) -ChildPath "system32\drivers\etc\hosts"            
 if (-not (Test-Path -Path $file)){            
   Throw "Hosts file not found"            
 }            
 Get-Content -Path $file |             
 where {!$_.StartsWith("#")} |            
 foreach {            
  if ($_ -ne ""){            
  $data = $_ -split " ",2            
   New-Object -TypeName PSObject -Property @{            
     Server = $data[1].Trim()            
     IPAddress = $data[0].Trim()            
   }            
  }            
 }            
}


Create the path to the file and test it exists.  I’ve used the windir environmental variable just to be sure I can find it.



Run get-content on the file and filter out the comments (start with #). For each remaining record split it in 2 based on the first space. Only allow two substrings from the split in case multiple spaces were used. Take the resultant data and output as an object with 2 properties – server name and IPAddress.