August 2011 - Posts

Windows firewall

I normally leave the Windows firewall enabled in my test environment. It ensures I don’t forget it when testing. My recent session for the TechEd:Australia PowerShell conference involved me disabling various firewall rules on the subject machine to set up part of the demo. I had to use the GUI tools to do this. I'’ve moaned to myself that I needed some PowerShell tools for working with the firewall especially as the netsh syntax has changed in Windows 2008 R2 – the session has prompted me to do something about it.

James O’Neill has written a very nice Configurator module for setting up servers. I’ve borrowed some of his ideas but as I’m just working with the firewall I thought I’d be a bit more verbose in the way I do things.

First off I want to know which network types are enabled on my machine. I need to consider them when working with  firewall rules.

I’m creating these functions as a module so I can define my networks (firewall profiles) in the .psm1 file

## types            
Add-type @"
public enum ProfileType {
 Domain   = 1,
 Private  = 2,
 Public   = 4,
 All      = 1073741824
} 
"@            
            
## functions            
. $psScriptRoot/Get-Profile.ps1

I can use this enum in the function to display the firewall profiles

function get-profile {             
[CmdletBinding()]             
param ()             
BEGIN{}#begin             
PROCESS{            
$fw = New-Object -ComObject HNetCfg.FwPolicy2            
$fwtypes = $fw.CurrentProfileTypes            
            
@(1,2,4) |             
foreach {            
 $cpt = New-Object -TypeName PSObject -Property @{            
     Enabled = $false            
     Profile = [ProfileType]($_)             
   }            
 $cpt.PSTypeNames[0] = "FirewallProfile"            
             
 if ($_ -band $fwtypes){$cpt.Enabled = $true}            
 $cpt             
}            
            
}#process             
END{}#end            
            
<# 
.SYNOPSIS
Determines active firewall profiles

.DESCRIPTION
Determines active firewall profiles.
Possible values are:
 Domain
 Private 
 Public

.EXAMPLE
get-profile

#>            
            
}

The function gets the firewall COM object. For the three network types we create an object that gives the name and that its disabled. We change the object type and then if test if the value and the firewall CurrentProfileTypes property can band. If they do we set the profile to enabled ($true). The object is displayed.

Output looks like this

PS> get-profile | ft -a

Profile Enabled
------- -------
Domain   False
Private    True
Public    True

Posted by RichardSiddaway | with no comments
Filed under: , ,

UK User Group sessions

This is the provisional list of meetings for the rest of the year

 

20 September Aleksandar Nikolic  7.30pm BST

25 October  WSMAN and WMI  - this is an extended version of the talk I gave over Live Meeting to the TechEd Australia PowerShell conference 7.30pm GMT

22 November Jonathan Medd “What’s new in PowerCLI 5?” 8.30pm GMT

15 December Hyper-V with PowerShell 7.30pm GMT

 

All sessions will be delivered by Live Meeting. Full details to follow

Posted by RichardSiddaway | with no comments

Webcast: Get the most from PowerShell and WMI

I will be presenting the above webcast next week.

Date: Wednesday, September 7, 2011

Time: 12:00 PM - 1:00 PM CST

 

Thats 6pm UK time

 

Register for the web cast at

http://powershell.com/cs/media/p/11256.aspx

Posted by RichardSiddaway | with no comments
Filed under:

Testing services

A forum question about testing services and if they weren’t running got me thinking. I created an function to solve the question

function test-service{             
[CmdletBinding(SupportsShouldProcess=$true)]             
param (             
[parameter(Position=0,            
   ValueFromPipeline=$true,             
   ValueFromPipelineByPropertyName=$true)]            
   [Alias("CN", "ComputerName")]              
   [string]$computer="." ,            
               
   [string]$service="BITS" ,            
               
[parameter(Mandatory=$true)]            
   [string]$file            
               
)             
BEGIN {            
 if (!(Test-Path -Path $file)){Throw "log file not found"}            
}            
PROCESS {            
$result =  Get-WmiObject -Class Win32_Service -ComputerName $computer -Filter "Name='$service'"            
            
Write-Verbose "$($result.State)"            
            
if ($($result.State) -eq "Running"){            
  $logdata = "{0,14} {1} {2}" -f $computer, $($result.State), (get-date -Format f )            
}            
else{             
 $start = $result.StartService()             
 if ($start.ReturnValue -eq 0){            
   $logdata = "{0,14} {1} {2}" -f $computer, "Service Started", (get-date -Format f )            
 }            
 else {            
  $logdata = "{0,14} {1} {2}" -f $computer, "Service FAILED to Start", (get-date -Format f )            
 }              
}            
Add-Content -Path $file -Value $logdata             
}            
} ## end function

But I don’t like the answer for a number of reasons:

  • end up out putting text
  • log files involve extra work in parsing
  • will other people know where the log file is

A better solution, in my mind, is to write the data to the event log.  In this case I would use the system log because we are testing services. The application log could be used or we could even create a specific event log for the purpose.

 

function test-service2{             
[CmdletBinding(SupportsShouldProcess=$true)]             
param (             
[parameter(Position=0,            
   ValueFromPipeline=$true,             
   ValueFromPipelineByPropertyName=$true)]            
   [Alias("CN", "ComputerName")]              
   [string]$computer="." ,            
               
   [string]$service="BITS"            
)             
PROCESS {            
$result =  Get-WmiObject -Class Win32_Service -ComputerName $computer -Filter "Name='$service'"            
            
Write-Verbose "$($result.State)"            
            
if ($($result.State) -eq "Running"){            
  $type = "Information"            
  $msg = "$computer - $service is $($result.State) "            
}            
else{             
 $start = $result.StartService()             
 if ($start.ReturnValue -eq 0){            
   $type = "Warning"            
   $msg = "$computer - $service  was started "            
 }            
 else {            
   $type = "Error"            
   $msg = "$computer - $service  FAILED to start"            
 }              
}            
Write-EventLog -LogName Application -Source ServiceTest -EntryType $type -Message $msg -EventId 9999            
            
}            
} ## end function

 

before using the function run this to create the event log source

New-EventLog -LogName Application -Source ServiceTest

The actions are all written to the event log as information, Warning or Error messages as appropriate.

Get-EventLog -LogName Application -Source ServiceTest

Shows the messages.

Enjoy

Posted by RichardSiddaway | with no comments
Filed under:

Testing computer existence in AD

Forum question wanted to take a list of computer names in a csv

Using the Quest cmdlets it becomes

Import-Csv computers2.csv |            
foreach {            
 $comp =  Get-QADComputer -Name $($_.Name)            
             
 if ($comp) {$location = $comp.DN}            
 else {$location = "Does NOT exist in AD"}            
             
 New-Object -TypeName Psobject -Property @{            
  Name = $_.Name            
  Location = $location            
 }            
            
} | Export-Csv complocs.csv -NoTypeInformation

 

Read the CSV and for each computer see if we can find it in AD.  I’m searching whole AD and assuming less than 1000 machines. Alter the search properties if these don’t match your needs. Put the name and distinguished name (DN) in an object and write to CSV

Its just as easy with the Microsoft cmdlets

Import-Csv computers2.csv |            
foreach {            
 $comp =  Get-ADComputer -LDAPFilter "(name=$($_.Name))"            
             
 if ($comp) {$location = $comp.DistinguishedName}            
 else {$location = "Does NOT exist in AD"}            
             
 New-Object -TypeName Psobject -Property @{            
  Name = $_.Name            
  Location = $location            
 }            
            
} | Export-Csv complocs2.csv -NoTypeInformation

Main difference is that we have to use an LDAP filter in Get-ADComputer. Also we pick up the DistinguishedName not DN property

Deal of the Day–PowerShell

PowerShell and WMI is Manning’s deal of the day – 50% off print or e-book.

 

The deal also extends to PowerShell in Practice and PowerShell in Action 2E

See www.manning.com for details

Posted by RichardSiddaway | with no comments
Filed under: ,

Reminder: TechEd Australia PowerShell conference

The TechEd Australia PowerShell conference starts tomorrow at midnight UK time (9am in Australia).  Details from

http://msmvps.com/blogs/richardsiddaway/archive/2011/08/22/teched-australia-powershell-conference.aspx

 

I will be presenting on WSMAN and WMI

Posted by RichardSiddaway | with no comments
Filed under:

Network Adapter vendors

The NDis WMI classes expose some information about the vendors that produce the various adapters in our systems

function get-adaptervendor {            
param(            
 [string]$computer="."            
)            
Get-WmiObject -Namespace root\wmi -Class MSNdis_CoVendorDescription `
-ComputerName $computer |            
foreach {            
                
  $id = Get-WmiObject -Namespace root\wmi  `
  -Class MSNdis_CoVendorId -ComputerName $computer `
  -Filter "InstanceName='$($_.InstanceName)'"            
            
  New-Object -TypeName PSobject -Property @{            
    Computer = $_.__SERVER            
    Adapter = $_.InstanceName            
    Active = $_.Active            
    Description = $_.NdisCoVendorDescription            
    Vendorid = $id.NdisCoVendorID            
  }            
}            
}
Posted by RichardSiddaway | with no comments

Msndis class

The MSNdis class from the root\wmi namespace calls the MSNdis_CoHardwareStatus and MSNdis_CoDriverVersion classes. On my Windows 7 system it tries to call something else but I get a “Get-WmiObject : Not supported” error. Neither of these classes seems to have much in the way of documentation available.

Rather than calling MSNdis and getting a lot of WMI objects it would be better to combine the output. There are a set of MSNdis-co* classes

gwmi -Namespace root\wmi -List *ndis_co* | sort name

MSNdis_CoDriverVersion
MSNdis_CoHardwareStatus
MSNdis_CoLinkSpeed
MSNdis_CoMacOptions
MSNdis_CoMediaConnectStatus
MSNdis_CoMediaInUse
MSNdis_CoMediaSupported
MSNdis_CoMinimumLinkSpeed
MSNdis_CoReceivePduErrors
MSNdis_CoReceivePdusNoBuffer
MSNdis_CoReceivePdusOk
MSNdis_CoTransmitPduErrors
MSNdis_CoTransmitPdusOk
MSNdis_CountedString
MSNdis_CoVendorDescription
MSNdis_CoVendorDriverVersion
MSNdis_CoVendorId

Lets see what we can find out about them

 

 

function get-adaptercoinfo {            
param(            
 [string]$computer="."            
)            
Get-WmiObject -Namespace root\wmi -Class MSNdis_CoHardwareStatus `
-ComputerName $computer |            
foreach {            
                
  $drv = Get-WmiObject -Namespace root\wmi  `
  -Class MSNdis_CoDriverVersion -ComputerName $computer `
  -Filter "InstanceName='$($_.InstanceName)'"            
            
  New-Object -TypeName PSobject -Property @{            
    Computer = $_.__SERVER            
    Adapter = $_.InstanceName            
    Active = $_.Active            
    HardwareStatus = $_.NdisCoHardwareStatus            
    DriverVersion = $drv.NdisCoDriverVersion             
  }            
}            
}

Start with the MSNdis_CoHardwareStatus and match to MSNdis_CoDriverVersion  on instance name (associators don’t seem to be created for these classes). Put the appropriate properties into an object and output.

The output is best displayed like this

get-adaptercoinfo | ft -a

Posted by RichardSiddaway | with no comments

European PowerShell Deep Dive–presenting

I was notified last night that my submission to the Deep Dive was successful and I will be presenting. There will be a good number of PowerShell MVPs attending. This will be the PowerShell event of the year in Europe. The one in April in the USA was brilliant – this will be at least as good.

Event details from http://blogs.msdn.com/b/powershell/archive/2011/08/02/extending-discounted-registration-amp-session-proposal-deadline.aspx

Posted by RichardSiddaway | with no comments
Filed under: ,

Outlook: removing calendar entries

We recently looked at dumping the Calendar entries

http://msmvps.com/blogs/richardsiddaway/archive/2011/08/23/outlook-viewing-calendar-entries.aspx

 

I usually leave entries to build up in the Calendar but a simple clean operation is to delete everything that occurred before a certain date

function remove-calendaritem {            
param (            
 [datetime]$date            
)            
$outlook = New-Object -ComObject Outlook.Application            
            
get-mailfolders |             
where {$_.Path -like "*calendar*" -and $_.Path -notlike "*birthday*"} |            
foreach {            
  $targetfolder = $outlook.Session.GetFolderFromID($_.EntryID, $_.StoreID)            
              
  $targetfolder.Items | foreach {            
    if ($_.StartTime -lt $date){$_.Delete()}            
  }             
}            
}

The date parameter defines the date for which we want to delete all earlier entries. Get the calendar folders and test the StartTime of each entry. If its before our date then delete it.

Posted by RichardSiddaway | with no comments
Filed under: ,

Network Adapter details

In this post - http://msmvps.com/blogs/richardsiddaway/archive/2011/07/09/linking-the-network-card-to-the-registry-settings.aspx – I showed how to get the NetLuidIndex by linking the network card to the matching registry settings.  There is another way to get some that same information.

function get-adapter {            
param(            
 [string]$computer="."            
)            
Get-WmiObject -Namespace root\wmi -Class MSNdis_EnumerateAdapter `
-ComputerName $computer |            
foreach {            
 $nic = Get-WmiObject -Namespace root\wmi -Class MSNdis_EnumerateAdapterEx `
-ComputerName $computer -Filter "InstanceName = '$($_.InstanceName)'"            
            
$header = $nic.EnumerateAdapter.Header            
            
 New-Object -TypeName PSobject -Property @{            
  Computer = $_.__SERVER            
  Adapter = $_.InstanceName            
  Device = $_.DeviceName            
  Active = $_.Active            
  Index = $($nic.EnumerateAdapter.IfIndex)            
  NetLuid = $($nic.EnumerateAdapter.NetLuid)            
  Revision = $header.Revision            
  Size = $header.Size            
  Type = $header.Type            
 }            
}            
}

Use the MSNdis_EnumerateAdapter  class to get the adapters and match to the MSNdis_EnumerateAdapterEx  class on the Instance name. Not sure what size and type signify but they are identical on all adapters on my Windows 7 machines.

 

NOTE: The Index property is NOT the same as the DeviceId/Index property on the Win32_NetworkAdapter\Win32_NetworkAdapterConfiguration classes.

Testing the network speed

In the last post I showed how to use the MSNdis_LinkSpeed class. Digging into the class information I found a suggestion that the speed returned was in Kbps. The answers didn’t look right especially when they suggested my wireless network was running at 540Mbps!

At bit of experimentation produced this

function test-linkspeed{            
param(            
 [string]$computer="."            
)            
            
Get-WmiObject -Namespace root\wmi -Class MSNdis_LinkSpeed `
-ComputerName $computer |             
foreach {            
 $nic = Get-WmiObject -Class Win32_NetworkAdapter `
 -ComputerName $computer -Filter "Name = '$($_.InstanceName)'"            
            
New-Object -TypeName PSObject -Property @{            
 Name = $_.InstanceName            
 NdisLinkSpeed = $_.NdisLinkSpeed            
 TestNdis = $_.NdisLinkSpeed / 10000            
 Speed = $nic.Speed            
 Test = $nic.Speed / 1000000            
} | select Name, NdisLinkSpeed, TestNdis, Test, Speed            
            
}            
            
}

Use the MSNdis_LinkSpeed class as before. Pipe into foreach and get the corresponding Win32_NetworkAdapter class. I know that the speed reported there is in bits per second. Create an object that shows the speeds reported by the two classes, convert Win32_NetworkAdapter speed to Mbps and play around with the divisor for Ndis speed until it matches. Turns out MSNdis_LinkSpeed reports in 100s of bits per second.

Odd but fun

Posted by RichardSiddaway | with no comments

Network Link Speed

The root\wmi Namespace contains a class that just returns the link speed of your network card. Quick and easy to use function.

function get-linkspeed{            
param(            
 [string]$computer="."            
)            
Get-WmiObject -Namespace root\wmi -Class MSNdis_LinkSpeed `
-ComputerName $computer |             
select InstanceName, @{N="Speed(Mbps)"; E={$_.NdisLinkSpeed/10000}}            
            
}

The documentation I could find suggested that the NdisLinkSpeed property returned Kbps but that gave some odd results. Experimentation and a bit more research suggested I needed to divide by 10000.

Posted by RichardSiddaway | with no comments

Mailbox database status

 

A recent forum post on mailbox database status in Exchange 2007  proved interesting.

If I do this

PS> Get-MailboxDatabase -Status | select Name, server, storagegroup, mounted

Name Server StorageGroup
---- ------ ------------
MailDatabase EXCH07 EXCH07\Test1
MDB01 EXCH07 EXCH07\SG1
MDB02 EXCH071 EXCH071\SG2

but if I do this

PS> Get-MailboxDatabase -Status | select Name, server, storagegroup, mounted | fl *

Name : MailDatabase
Server : EXCH07
StorageGroup : EXCH07\Test1
Mounted : True

I get the mounted property. The help file says you have to use the format cmdlets to see the results of the status property

So if you want to work with the Mounted property  (or the BackupInProgress or OnlineMaintenanceInProgress properties)

You need to do something like this

Get-MailboxDatabase -Status | foreach {
$status = $_ | select -ExpandProperty Mounted
if ($status) {Write-Host "$($_.Identity) is Mounted"}
else {Write-Host "$($_.Identity) is not Mounted"}

}

The value is only visible if you use the –status switch AND you have to either use the format cmdlets or   seelct -expandproperty to be able to work with the property.

Awkward but usable.

Outlook: Viewing Calendar Entries

We have seen how to view emails – this is how to view items in your calendar

function get-calendaritem {            
            
$outlook = New-Object -ComObject Outlook.Application            
            
get-mailfolders |             
where {$_.Path -like "*calendar*" -and $_.Path -notlike "*birthday*"} |            
foreach {            
  $targetfolder = $outlook.Session.GetFolderFromID($_.EntryID, $_.StoreID)            
              
  $targetfolder.Items | foreach {            
   New-Object -TypeName PSObject -Property @{            
    Folder = $targetfolder.FolderPath            
    StartTime = $_.Start            
    EndTime = $_.End            
    Organizer = $_.Organizer            
    Subject = $_.Subject            
    Location =$_.Location            
   }            
  }             
}            
}

Use the get-mailfolders function we developed earlier. Filter for the calendar folders. For each of them get the folder and strip the appropriate properties from the entry. Create an object and display

Posted by RichardSiddaway | 2 comment(s)
Filed under: ,

TechEd Australia PowerShell conference

Tuesday August 30th 2011 at 9am EST there is a PowerShell conference at TechEd Australia. 

Details from

http://powershelldownunder.com/featured/teched2011/

The sessions will be available via Live meeting please register at above URL

Posted by RichardSiddaway | 2 comment(s)
Filed under:

Ping a subnet

I recently needed to find which IP addresses were active on a subnet to track down a printer. Quickest way was to ping them.

 

function ping-subnet {            
param (            
 [parameter(Mandatory=$true)]            
 [ValidatePattern("\b\d{1,3}\.\d{1,3}\.\d{1,3}\b")]            
 [string]$subnet            
)            
            
0..255 | foreach {             
             
 $address = "$subnet.$_"            
            
 if (Test-Connection -ComputerName $address -Count 1 -Quiet){            
    Test-Connection -ComputerName $address -Count 1            
 }            
            
}            
}

 

Put the subnet in as a parameter. Then work through 0 – 255 building an address from the subnet. use test-connection in quiet mode and if it responds do a 1 count test-connection (ping) to get the result.

Not necessarily the quickest but it was quick to throw together and it works

Posted by RichardSiddaway | with no comments

Create a process on a remote machine

We cam use the [wmiclass] to create a process but it doesn’t allow us to set the credentials. We can get round that by using a bit of .NET code. [wmiclass] is as accelerator for System.Management.ManagementClass so we go back to basics

function new-process {            
param (            
 [string]$computer="localhost",            
 [string]$procpath="C:\Program Files\Internet Explorer\iexplore.exe"            
)            
            
$conopt = New-Object System.Management.ConnectionOptions             
            
switch ($computer ) {            
 "."         {break}            
 "localhost" {break}            
 "$env:COMPUTERNAME" {break}            
 default {            
           $cred = Get-Credential            
           $conopt.UserName = $cred.UserName            
           $conopt.SecurePassword = $cred.Password            
         }            
}            
$conopt.EnablePrivileges = $true            
            
$scope = New-Object System.Management.ManagementScope             
$scope.Path = "\\$computer\root\cimv2"             
$scope.Options = $conopt             
            
$path = New-Object System.Management.ManagementPath            
$path.ClassName = "Win32_Process"              
            
$proc = New-Object System.Management.ManagementClass($scope, $path, $null)             
            
$proc.Create($procpath)             
}

 

The computer name and path to the exe we want to run are given as parameters. We create the System.Management.ConnectionOptions. If we are  targeting a remote machine we can add the credentials (doesn’t work for local machine). The switch simplifies the coding of avoid local machine

 

The scope and management path (name space and class) are set and then we create a new instance of the class. We can then use the Create method to create the process.

Ethernet Errors

While we are looking at the MSNdis_Ethernet* classes we should consider these three that pick up potential problems

MSNdis_EthernetReceiveErrorAlignment
MSNdis_EthernetOneTransmitCollision
MSNdis_EthernetMoreTransmitCollisions

 

If all is well we will get an answer of zero for each of them – no errors and no collisions. Its a bit awkward working through each class in turn and we get a lot of “noise” returned so the following function concatenates the results.

function test-etherneterror {            
param(            
 [string]$computer="."            
)            
Get-WmiObject -Namespace root\wmi -Class MSNdis_EthernetReceiveErrorAlignment `
-ComputerName $computer |            
foreach {            
                
  $one = Get-WmiObject -Namespace root\wmi  `
  -Class MSNdis_EthernetOneTransmitCollision -ComputerName $computer `
  -Filter "InstanceName='$($_.InstanceName)'"            
            
  $more = Get-WmiObject -Namespace root\wmi  `
  -Class MSNdis_EthernetMoreTransmitCollisions -ComputerName $computer `
  -Filter "InstanceName='$($_.InstanceName)'"            
            
  New-Object -TypeName PSobject -Property @{            
  Computer = $_.__SERVER            
  Adapter = $_.InstanceName            
  ReceiveError = $_.NdisEthernetReceiveErrorAlignment            
  OneCollision = $one.NdisEthernetOneTransmitCollision            
  MoreCollision = $more.NdisEthernetMoreTransmitCollisions            
 }            
}            
}

Start by getting the members of the MSNdis_EthernetReceiveErrorAlignment  class. Loop through them and get the related MSNdis_EthernetOneTransmitCollision  and MSNdis_EthernetMoreTransmitCollisions classes.

 

Create an object for output

Posted by RichardSiddaway | with no comments
More Posts Next page »