Monthly Archive

Categories

Monthly Archives: January 2017

More on Foreach

My post on foreach seems to haver generated a bit of confusion. I was trying to use the calculations as examples not a statement that you should do things that way – there were statements to that effect in the post but they seem to have been missed.

 

Any way, to try and resolve the confusion here’s another couple of examples. This time getting network adapters and finding the matching IP address.

 

First using Foreach-Object on a pipeline

Get-CimInstance -ClassName Win32_NetworkAdapter -Filter "NetEnabled = $true" |
ForEach-Object {
$ip = Get-CimInstance -ClassName Win32_NetworkAdapterConfiguration -Filter "Index = $($psitem.DeviceId)"
$props = @{
Name = $psitem.NetConnectionId
Product = $psitem.ProductName
DHCP = $ip.DHCPEnabled
IP   = $ip.IPAddress
}
New-Object -TypeName PSObject -Property $props
} | Format-List

 

You can’t pipe Get-CimInstance into another call to the same cmdlet so you need to solve the problem using foreach.

Now the same problem solved using a foreach loop

$nics = Get-CimInstance -ClassName Win32_NetworkAdapter -Filter "NetEnabled = $true"
$data = foreach ($nic in $nics) {
$ip = Get-CimInstance -ClassName Win32_NetworkAdapterConfiguration -Filter "Index = $($nic.DeviceId)"
$props = @{
Name = $nic.NetConnectionId
Product = $nic.ProductName
DHCP = $ip.DHCPEnabled
IP   = $ip.IPAddress
}
New-Object -TypeName PSObject -Property $props
}
$data |Format-List

Is PowerShell just for administration?

Two related questions were left on my blog recently.

 

Is PowerShell just for administration?

Should I learn PowerShell, VBScript or cmd tools?

 

PowerShell was introduced as Microsoft’s automation engine for the Windows platform. It includes a scripting language, a shell and  the Integrated Scripting Environment (ISE). Other additions over the years have included Powershell workflows and Desired State Configuration.

The extension of PowerShell to Linux and Mac extends the administrative capabilities.

 

I would say that PowerShell  is primarily about the administration of Windows machines. This will be extended in time but at the moment its a Windows based administration tool.

 

Does that mean that its all you can do with it - Very definitely Not for example I recently wrote a script that would look at a large set of photos and move them into the correct folder based on the month they were created. Doing this by hand for a few photos is easy – for hundreds you need a script.

 

Over the years I’ve seen PowerShell code to do many non-administrator based things – for instance:

- manage and modify photos and videos

- play space invaders

- calculate the cooking time of a chicken given its weight

- work out the apparent temperature using air temperature, wind speed and altitude

- create web sites

 

PowerShell is .NET based which means you can work with just about the whole of the .NET framework in your PowerShell code. You can even write GUI applications in PowerShell if you want.

 

If you have a task that you perform on a Windows machine its very probable that a script could be written to perform that task. Creating the script may be very easy or very difficult but it should be possible.

 

If you want to do this sort of thing you need to:

- work out how to do the task manually

- break that down into a number of steps

- create the code to perform each step

- join it all together and test

 

If any one has suggestions for tasks they’d like to do leave a comment and I’ll see if I can suggest how you could do it

 

PowerShell or VBScript or cmd tools is fairly easy decision for me.  VBScript will receive no further development as far as I’m aware. The cmd tools are OK for specific jobs but don’t have the breadth that PowerShell does. CMD batch files are no where as caapble asa PowerShell script.

 

Learn PowerShell and use it as you want to make your computer use easier

foreach confusion

One of the biggest sources of confusion to people learning PowerShell is foreach.

 

Don’t worry – it is confusing. Having just read the help file about_foreach its doubly confusing. That help file desperately needs a re-write

 

Foreach is used in two separate ways with two separate meanings

 

Firstly there is the foreach language statement or foreach loop. This is used to iterate over a collection of items

$disks = Get-CimInstance -ClassName Win32_LogicalDisk -Filter "DriveType=3"
foreach ($disk in $disks){
$fp = [math]::Round(($disk.FreeSpace / $disk.Size) * 100, 2)
if ($fp -lt 60){
Write-Warning -Message "$($disk.DeviceId) has $fp % free space"
}
else {
Write-Information -MessageData "$($disk.DeviceId) has $fp % free space" -InformationAction Continue
}
}

 

In this case the Win32_LogicalDisk CIM class is used to create a collection of disk information. The foreach language statement (loop) is used to work through that collection. For each disk in the disks collection we calculate the percentage free space. If that percentage is less than 60 a warnign message is displayed otherwise an information message is displayed – for versions of PowerShell before 5.0 use Write-Host instead of Write-Information.

 

PLEASE DON’T COMMENT THAT YOU WOULD DO THIS ANOTHER WAY – SO WOULD I. I’M USING IT TO ILLUSTRATE FOREACH!

 

Alternatively you could do this

Get-CimInstance -ClassName Win32_LogicalDisk -Filter "DriveType=3" |
foreach {
$fp = [math]::Round(($psitem.FreeSpace / $psitem.Size) * 100, 2)
if ($fp -lt 60){
Write-Warning -Message "$($psitem.DeviceId) has $fp % free space"
}
else {
Write-Information -MessageData "$($psitem.DeviceId) has $fp % free space" -InformationAction Continue
}
}

 

Get the disk information but this time pass it into foreach on the pipeline

 

AGAIN PLEASE DON’T COMMENT THAT YOU WOULD DO THIS ANOTHER WAY – SO WOULD I. I’M USING IT TO ILLUSTRATE FOREACH!

 

This is where the confusion arises – foreach is used in two different ways.

 

In the second set of code – foreach is actually an alias for Foreach-object so the code could be written

Get-CimInstance -ClassName Win32_LogicalDisk -Filter "DriveType=3" |
ForEach-Object -Process {
$fp = [math]::Round(($psitem.FreeSpace / $psitem.Size) * 100, 2)
if ($fp -lt 60){
Write-Warning -Message "$($psitem.DeviceId) has $fp % free space"
}
else {
Write-Information -MessageData "$($psitem.DeviceId) has $fp % free space" -InformationAction Continue
}
}

 

which makes more sense and is less confusing

 

Couple of tips:

 

Foreach in the pipeleine is an alias for foreach object and foreach on its own is the language statement

When writing code use Foreach-Object rather than foreach to reduce confusion

New Year book offer

The New Year starts very nicely with POwerShell in Action, 3e being Mannings deal of the day for 3 January 2017

 

Half off my book Windows PowerShell in Action, Third Edition. Use code dotd010317au at http://bit.ly/2iw7MD2

 

Links should be directed to the DOTD's page at https://www.manning.com/dotd