PowerShell for Windows Admins


August 17, 2014  1:02 PM

Have you been talking to strangers?

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
DNS, PowerShell

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                 : www.intelliweather.net
Name                  : 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                 : 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!

August 14, 2014  2:01 PM

foreach

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
PowerShell

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


August 12, 2014  10:29 AM

Can it -whatif

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
PowerShell

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


August 11, 2014  1:44 PM

Select-Object or Where-Object

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
PowerShell

Both Select-Object and Where-Object (referred to by their aliases of select and where from now on) are both used to filter data.

 

It is important to know the way these 2 cmdlets are used.

 

Where is used to restrict the objects on the pipeline to those where one or more properties satisfy the filter criteria e.g.

Get-Process | where CPU -gt 20

 

You get a reminder of this if you you use the full syntax

Get-Process | where -FilterScript {$_.CPU -gt 20}

 

As a matter of style you very rarely see anyone using the parameter name –FilterScript.

 

Select is used to cut the number of properties on an object to just those you want to work with e.g.

Get-Process | select Name, Id, CPU

 

If you want just those properties for the processes where CPU time is greater than 20 seconds you need to combine them on the pipeline:

Get-Process | where CPU -gt 20 | select Name, Id, CPU

 

There isn’t a way to embed a where type filter in a select or vice versa. Keep it simple. Use the pipeline and let the cmdlets do the job for which they were designed.


August 10, 2014  6:07 AM

Installing Centos in Windows 2012 R2 Hyper-V

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
Hyper-V 2012 R2, Virtualization

I need to create a virtual machine with CentOS 6.5 as the guest OS.

I clicked through creating the VM and discovered that the install wouldn’t work. Eventually tracked down the issues.

Keep the following points in mind as you create your VM:

  1. Create the VM as a generation 1 virtual machine
  2. Ensure the virtual disk controller and disk are IDE
  3. Ensure a legacy network adapter is used – may need to create the VM without a network adapter and add the adapter before the install
  4. If asked to test the install media (iso image) be aware that it will be ejected after the test so you’ll need to open it again
  5. keep it simple and only have 1 network adapter
  6. Use the map to find the nearest city to get the time zone – scrolling though the list is boring


August 10, 2014  2:51 AM

WMI troubleshooting

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
CIM, PowerShell, WMI

A WMI troubleshooting series has been started on the Ask the Performance Team Blog.

The overview article is:

http://blogs.technet.com/b/askperf/archive/2014/08/07/troubleshooting-wmi-series-coming.aspx

 

The first article is about common symptoms and errors:

http://blogs.technet.com/b/askperf/archive/2014/08/08/wmi-common-symptoms-and-errors.aspx

 

followed by an article on dealing with WMI repository corruption:

http://blogs.technet.com/b/askperf/archive/2014/08/08/wmi-repository-corruption-or-not.aspx

 

Very useful information in both articles. If the rest of the series is at this level you’ll want to book mark these posts


August 10, 2014  2:34 AM

Euorpean PowerShell Summit 2014 registration details

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
PowerShell

The European PowerShell Summit, organised by PowerShell.org, will be in Amsterdam September 29 – October 1 2014 at the Park Hotel. Details at http://powershell.org/wp/community-events/summit/

 

The Summit will feature 3 days of PowerShell sessions from PowerShell team members, PowerShell MVPs and other PowerShell experts. It’s the in-person gathering place for PowerShell enthusiasts and PowerShell users. It’s a place to make new connections, learn new techniques, and offer something to your peers and colleagues.  If you can’t get your PowerShell questions answered at the PowerShell Summit you’ll never get an answer.

The Summit agenda is available to view at: http://eventmgr.azurewebsites.net/event/agenda/PSEU14

 

Registration is now open via http://eventmgr.azurewebsites.net/event/home/PSEU14.

 


August 6, 2014  2:18 PM

Invoke-Item tips

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
PowerShell

Invoke-Item is another cmdlet that you don’t see used that often but there is one place where its invaluable – opening files. If you give Invoke-Item the path to a file

Invoke-Item -Path .\procs.txt

The file will be opened with the default application associated with that extension. In this case Notepad.

If you use a PowerShell script file

Invoke-Item .\t1.ps1

It will be opened in Notepad for you to examine.  CSV files automatically open in Excel and other Office files are opened in the correct application.

Using the alias ii for Invoke-item makes it even easier.


August 5, 2014  12:42 PM

ServerManagerTasks module – - Get-SMServerFeature

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
CIM, PowerShell, WMI

Finding the Windows features installed on a remote machine can be an interesting task. You could use Get-WindowsFeature but that gives you a “graphical” display:

£> Get-WindowsFeature | where DisplayName -like ‘*DNS*’

Display Name         Name             Install State
————         —-             ————-
[X] DNS Server       DNS              Installed
[X] DNS Server Tools RSAT-DNS-Server  Installed

Or you could use Get-SMServerFeature from the ServerManagerTasks module:

£> Get-SMServerFeature -BatchSize 1000  | where DisplayName -like ‘*DNS*’ | sort Displayname | ft -a Displayname, State, Type, ConfigurationStatus

Displayname      State Type ConfigurationStatus
———–      —– —- ——————-
DNS Server           1    0                   3
DNS Server Tools     1    2                   3

Which is CIM based and uses a new class: root/microsoft/windows/servermanager/MSFT_ServerFeature

Following the tradition firmly established since the introduction of WMI the data from this class is represented by integer values AND just for giggles its not documented. To be fair most of the WMI classes aren’t documented.

<rant>

We need documentation for these classes

</rant>

In an effort to work out which are the important values I compared the outputs from

Get-SMServerFeature -BatchSize 1000  | where DisplayName -like ‘*PowerShell*’ | sort Displayname | ft -a Displayname, State, Type, ConfigurationStatus

AND

Get-WindowsFeature | where DisplayName -like ‘*PowerShell*’ | sort Displayname

The important property from  Get-SMServerFeature  seems to be State which takes a 0 or 1. O corresponds to Available in Get-WindowsFeature and 1 corresponds to Installed.

You can use the trick I show in PowerShell and WMI (www.manning.com/siddaway2)

$state = DATA {ConvertFrom-StringData -StringData @’
0 = Available
1 = Installed
‘@}

Get-SMServerFeature -BatchSize 1000  |
where DisplayName -like ‘*PowerShell*’ |
sort Displayname |
select DisplayName, UniqueName,
@{N=’State’; E={$state["$($_.State)"]}

$state = DATA {ConvertFrom-StringData -StringData @’
0 = Available
1 = Installed
‘@}

Create a hash table for the integer values and their meaning and use that hash table in a calculated field to get the meaning from the integer value.

The output will look like this:

DisplayName : Windows PowerShell Web Access
UniqueName  : WindowsPowerShellWebAccess
State       : Available

Its now easy to compare the data between different machines.  Get-SMServerFeature has a CimSession parameter for working with remote machines


August 4, 2014  2:09 PM

European Summit – - update 6

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
PowerShell

As pointed out on PowerShell.org – http://powershell.org/wp/2014/08/03/powershell-summit-europe-2014-status/ – we’re around the 50% of capacity for registrations at the moment.

We need at least 45 attendees to be able to afford to put on a European Summit in 2015. Its not that we don’t want to do a European Summit – its we can’t afford to unless we get the support needed to ensure the event is financially viable

There are about 6 weeks until registration closes in mid-September.

Now is the time to start pestering your boss about going. There’s a great speaker line up plus some excellent evening activities. Amsterdam is a wonderful city that’s well worth a visit.

If you want to hear top line PowerShell speakers, including the PowerShell team, at an annual PowerShell summit then we need your support and I’d urge you to attend.

Registration is via the link at http://powershell.org/wp/community-events/summit/

It would be a sad position if we can’t get enough attendees from across Europe to make this work


Forgot Password

No problem! Submit your e-mail address below. We'll send you an e-mail containing your password.

Your password has been sent to: