Count property

Its frequently said that PowerShell is so big that no one can know everything about it.  I proved that today when I “discovered” a change in PowerShell of which I wasn’t aware.

 

If you create an array:

£> $a = 1,2,3

You can then get the number of members of that array i.e. its length

 

£> $a.count
3

 

£> $a[0]
1

 

In PowerShell 1.0 and 2.0 if you tried that on a variable that only held a single value you would get an error when you tried to access the first value:

£> $b = 1

£> $b.count

The count property returns nothing

 

£> $b[0]
Unable to index into an object of type System.Int32.
At line:1 char:4
+ $b[ <<<< 0]
    + CategoryInfo          : InvalidOperation: (0:Int32) [], RuntimeException
    + FullyQualifiedErrorId : CannotIndex

 

This changed in PowerShell 3.0 and later

£> $b = 1
£> $b.count
1

£> $b[0]
1

 

You can even try other indices
£> $b[1]
£>

 

And just get nothing back rather than an error.

 

This is really useful as you can now safely test on the Count property and if the value is greater than 1 to determine if its a collection.  Alternatively always treat it as a collection and iterate over the number of elements.  I can see this simplifying things for me in quite a few situations

Posted in Powershell Basics | Leave a comment

Split-Path serendipity

I’ve used Split-Path and its associated cmdlet Join-Path a lot when working with file system paths. Something I read today started me asking if it would work with URLs

 

It does:

 

£> Split-Path -Path ‘http://powershell.org/wp/forums/forum/windows-powershell-qa/’ -Leaf
windows-powershell-qa

£> Split-Path -Path ‘http://powershell.org/wp/forums/forum/windows-powershell-qa/’ -Parent
http:\\powershell.org\wp\forums\forum

 

£> Split-Path -Path ‘http://powershell.org/wp/forums/forum/windows-powershell-qa/’ -NoQualifier
//powershell.org/wp/forums/forum/windows-powershell-qa/

£> Split-Path -Path ‘http://powershell.org/wp/forums/forum/windows-powershell-qa/’ -Qualifier
http:

 

The –Resolve parameter won’t work because its not a file system path but if you need to play with URLs then could be useful.

 

Just for completeness Join-Path won’t work with URLs because its attempting to resolve the file path

Posted in Powershell | Leave a comment

European Summit countdown #1

There are four weeks left to register for the Summit if you are going to attend. Our numbers are moving in the right direction but we still need more registrations to make a 2015 Summit feasible.

Posted in Powershell, Summit | Leave a comment

DNS client settings

Following yesterdays post there are a couple of other cmdlets worth looking at if you want to dig into the DNS settings on your client machines.

Get-DnsClient wil show you the DNS relsted settings for all of your network interfaces by default.  To investigate a single interface

 

£> Get-DnsClient -InterfaceAlias vEthernet* | fl

InterfaceAlias                     : vEthernet (External01)
InterfaceIndex                     : 20
ConnectionSpecificSuffix           :
ConnectionSpecificSuffixSearchList : {}
RegisterThisConnectionsAddress     : True
UseSuffixWhenRegistering           : False

InterfaceAlias                     : vEthernet (Internal01)
InterfaceIndex                     : 16
ConnectionSpecificSuffix           :
ConnectionSpecificSuffixSearchList : {}
RegisterThisConnectionsAddress     : True
UseSuffixWhenRegistering           : False

 

You can also see the DNS servers a particular interface will use:

£> Get-DnsClientServerAddress -InterfaceAlias vEthernet*

InterfaceAlias               Interface Address ServerAddresses
                             Index     Family
————–               ——— ——- —————
vEthernet (External01)              20 IPv4    {192.168.0.1}
vEthernet (External01)              20 IPv6    {}
vEthernet (Internal01)              16 IPv4    {}
vEthernet (Internal01)              16 IPv6    {fec0:0:0:ffff::1, fec0:0:0:ffff::2, fec0:0:0:ffff::3}

Posted in DNS, Networking | Leave a comment

Have you been talking to strangers?

Want to know the machines to which your machine has been connecting?

 

Try looking in the client DNS cache:

 

Get-DnsClientCache

 

will show a wealth of useful data.  All in the form:

£> Get-DnsClientCache | where Entry -like ‘*www.intelliweather.net*’ | fl *

TTL                   : 39
Caption               :
Description           :
ElementName           :
InstanceID            :
Data                  : cache1.intelliweather.net
DataLength            : 8
Entry                 : http://www.intelliweather.net
Name                  : http://www.intelliweather.net
Section               : 1
Status                : 0
TimeToLive            : 39
Type                  : 5
PSComputerName        :
CimClass              : ROOT/StandardCimv2:MSFT_DNSClientCache
CimInstanceProperties : {Caption, Description, ElementName, InstanceID…}
CimSystemProperties   : Microsoft.Management.Infrastructure.CimSystemProperties

TTL                   : 39
Caption               :
Description           :
ElementName           :
InstanceID            :
Data                  : 38.114.169.29
DataLength            : 4
Entry                 : http://www.intelliweather.net
Name                  : cache1.intelliweather.net
Section               : 1
Status                : 0
TimeToLive            : 39
Type                  : 1
PSComputerName        :
CimClass              : ROOT/StandardCimv2:MSFT_DNSClientCache
CimInstanceProperties : {Caption, Description, ElementName, InstanceID…}
CimSystemProperties   : Microsoft.Management.Infrastructure.CimSystemProperties

 

 

What is interesting is the Time To Live settings on some of the records:

£> Get-DnsClientCache | sort TTL -Descending | group TTL -NoElement

Count Name
—– —-
    7 74538
    1 70203
    1 64639
    1 53300
    1 53299
    1 16441
    2 9308
    1 2579
    1 2573
    3 2475
    6 2469
    2 2327
    2 1986
    1 1890
    1 1089
    1 999
    2 899
    2 891
    2 878
    3 728
    1 724
    6 711
    1 631
    1 458
    1 412
    1 363
    1 133
   15 0

 

Some of those records will be around for a long time!

Posted in DNS, Networking, Powershell | Leave a comment

foreach

I was asked about foreach today and responded with a description of who foreach-object works. Thinking about it I should have realised that part of the issue with foreach is the confusion that arises between foreach and foreach – –  that is the difference between the foreach PowerShell statement and the foreach alias of the foreach-object cmdlet.

 

To unravel the confusion there are two different things referred to as foreach. The confusion is that they do very similar things but are used in different ways.

 

The first is the PowerShell statement which is used to step through each value in a collection of values:

 

$procs = Get-Process

foreach ($proc in $procs) {

New-Object -TypeName PSObject -Property @{
   Name = $proc.Name
   SysMen =  $proc.NonpagedSystemMemorySize + $proc.PagedSystemMemorySize64
}

}

 

You create your collection of objects and then use foreach to step through them. It is convention to make the collection plural and the individual member of the collection its singular.  Within the script block you can define what happens to the object.

 

I know I could have a performed this action is a simpler way but I wanted to demonstrate how foreach works. The simpler way would be:

Get-Process |
select Name,
@{Name = ‘SysMen';
Expression = {$_.NonpagedSystemMemorySize + $_.PagedSystemMemorySize64}}

 

Now we’ve got that out of the way what about the other foreach which is the alias of foreach-object.  This can be use to iterate over a collection of objects. The main difference is that the objects are usually piped into foreach:

 

Get-Process |
foreach {

New-Object -TypeName PSObject -Property @{
   Name = $_.Name
   SysMen =  $_.NonpagedSystemMemorySize + $_.PagedSystemMemorySize64
}

}

 

If you don’t like using $_ to represent the object on the pipeline try

Get-Process |
foreach {

New-Object -TypeName PSObject -Property @{
   Name = $psitem.Name
   SysMen =  $psitem.NonpagedSystemMemorySize + $psitem.PagedSystemMemorySize64
}

}

 

which is exactly equivalent to

Get-Process |
ForEach-Object {

New-Object -TypeName PSObject -Property @{
   Name = $psitem.Name
   SysMen =  $psitem.NonpagedSystemMemorySize + $psitem.PagedSystemMemorySize64
}

}

 

Using the cmdlet or its alias you can set up script blocks to process once when the first object reaches foreach (BEGIN), once per object on the pipeline (PROCESS) and once when the last object has been processed (END)

Get-Process |
ForEach-Object `
-BEGIN {
  Write-Host “First object about to be processed”
} `
-PROCESS {
New-Object -TypeName PSObject -Property @{
   Name = $psitem.Name
   SysMen =  $psitem.NonpagedSystemMemorySize + $psitem.PagedSystemMemorySize64
}
}`
-END {
Write-Host “Last object processed”
}

 

Your ouput looks like this

 

First object about to be processed

Name                                                                      SysMen
—-                                                                      ——
armsvc                                                                    164096
concentr                                                                  200400
conhost                                                                   119104
csrss                                                                     153664
csrss                                                                     407760
           <truncated>

WUDFHost                                                                  103696
WWAHost                                                                   778816
WWAHost                                                                   785120
Yammer.Notifier                                                           566304
Last object processed

 

More info is available in the help files for foreach-object and about_foreach

Posted in Powershell Basics | Leave a comment

Can it -whatif

One of the nice things about PowerShell is that it can help you prevent mistakes. Many of the cmdlets that make changes to you system have a –whatif parameter that allows you to test your actions:

 

£> Get-Process | Stop-Process -WhatIf
What if: Performing the operation “Stop-Process” on target “armsvc (1564)”.
What if: Performing the operation “Stop-Process” on target “audiodg (3004)”.
What if: Performing the operation “Stop-Process” on target “concentr (7080)”.
What if: Performing the operation “Stop-Process” on target “conhost (3628)”.

etc

 

The –whatif parameter is only present on cmdlets that make changes and then only if the team writing the cmdlet implemented it – they should but you can’t guarantee it happened. So how can you find out which cmdlets implement –whatif?

Use Get-Command

Compare these 2 commands.

£> Get-Command -Module CimCmdlets | select Name

Name
—-
Export-BinaryMiLog
Get-CimAssociatedInstance
Get-CimClass
Get-CimInstance
Get-CimSession
Import-BinaryMiLog
Invoke-CimMethod
New-CimInstance
New-CimSession
New-CimSessionOption
Register-CimIndicationEvent
Remove-CimInstance
Remove-CimSession
Set-CimInstance

 

shows the cmdlets in a module

 

£> Get-Command -Module CimCmdlets -ParameterName Whatif | select Name

Name
—-
Invoke-CimMethod
New-CimInstance
Remove-CimInstance
Remove-CimSession
Set-CimInstance

 

Now you can test a module to see which cmdlets have –whatif enabled.  You can also test at just the cmdlet level:

£> Get-Command *process -ParameterName Whatif  -CommandType cmdlet | select Name

Name
—-
Debug-Process
Stop-Process

£> Get-Command *wmi* -ParameterName Whatif  -CommandType cmdlet | select Name

Name
—-
Invoke-WmiMethod
Remove-WmiObject
Set-WmiInstance

Posted in Powershell Basics | Leave a comment