PowerShell for Windows Admins


March 1, 2016  1:56 PM

Comparing lists

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
Powershell

An interesting question on the forum regarding how you compare the contents of 2 collections.  The question revolved around comparing the contents of the Machine property of

HKLM:\System\CurrentControlSet\Control\SecurePipeServers\Winreg\AllowedExactPaths

with

$Machine = @(
‘System\CurrentControlSet\Control\ProductOptions’,
‘System\CurrentControlSet\Control\Server Applications’,
‘Software\Microsoft\Windows NT\CurrentVersion’
)

Start by getting the data from the registry

$p = Get-ItemProperty -Path ‘HKLM:\System\CurrentControlSet\Control\SecurePipeServers\Winreg\AllowedExactpaths’ -Name Machine

$p.Machine
System\CurrentControlSet\Control\ProductOptions
System\CurrentControlSet\Control\Server Applications
Software\Microsoft\Windows NT\CurrentVersion

So the 2 look identical but how do we do that programmatically.

You can’t do

$machine -eq $p.machine

you get nothing back.

You have to use Compare-Object:

Compare-Object $machine $p.machine

You’ll get nothing back so check  everything is equal:

PS> Compare-Object $machine $p.machine -IncludeEqual

InputObject                                                                     SideIndicator
———–                                                                         ————-
System\CurrentControlSet\Control\ProductOptions        ==
System\CurrentControlSet\Control\Server Applications ==
Software\Microsoft\Windows NT\CurrentVersion            ==

Compare-Object returns nothing if the 2 objects match so your comparison ends up as

PS> if ( -not (Compare-Object $machine $p.machine)){‘yay’}else{‘nay’}
yay

You can test it works

$m2 = ‘item1’, ‘item2’, ‘item3’

PS> Compare-Object $machine $m2

InputObject                                          SideIndicator
———–                                          ————-
item1                                                =>
item2                                                =>
item3                                                =>
System\CurrentControlSet\Control\ProductOptions      <=
System\CurrentControlSet\Control\Server Applications <=
Software\Microsoft\Windows NT\CurrentVersion         <=

PS> if ( -not (Compare-Object $machine $m2)){‘yay’}else{‘nay’}
nay

February 29, 2016  6:30 AM

CSV file with [] in headers

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
Powershell

With the PowerShell Summit registration deadline rapidly approaching I wanted to see how registrations were going. I can down load a CSV file from the event website that lists attendees.

Great. Just need to do some sorting and grouping and I’m golden.

I’m running PowerShell 5.0 on Windows 10 Insider build 14271

First off I discovered that the headers of the CSV file contain [] i.e. they look like this for example:

[UserName]
[REGISTRATIONSTATUS]
[AttendeeType]
[ConfirmationCode]

Sorting by attendee type

Import-Csv -Path C:\test1\AttendeeReport.csv |
Sort-Object -Property [AttendeeType]

works but if I add a check for complete registrations

Import-Csv -Path C:\test1\AttendeeReport.csv |
Where-Object [REGISTRATIONSTATUS] -eq ‘Complete’|
Sort-Object -Property [AttendeeType]

I get nothing back.

Import-Csv -Path C:\test1\AttendeeReport.csv |
Where-Object ‘[REGISTRATIONSTATUS]’ -eq ‘Complete’|
Sort-Object -Property [AttendeeType]

Is no better. You need to revert to old style where-object syntax

Import-Csv -Path C:\test1\AttendeeReport.csv |
Where-Object {$_.'[REGISTRATIONSTATUS]’ -eq ‘Complete’}|
Sort-Object -Property [AttendeeType]

Now I want to group on attendee type

PS> Import-Csv -Path C:\test1\AttendeeReport.csv |
>> Where-Object {$_.'[REGISTRATIONSTATUS]’ -eq ‘Complete’}|
>> Sort-Object -Property [AttendeeType] |
>> Group-Object -Property [AttendeeType] -NoElement
Group-Object : Wildcard characters are not allowed in “[AttendeeType]”.
At line:4 char:1
+ Group-Object -Property [AttendeeType] -NoElement
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : InvalidArgument: (:) [Group-Object], NotSupportedException
+ FullyQualifiedErrorId : ExpressionGlobbing2,Microsoft.PowerShell.Commands.GroupObjectCommand

This partially works

Import-Csv -Path C:\test1\AttendeeReport.csv |
Where-Object {$_.'[REGISTRATIONSTATUS]’ -eq ‘Complete’}|
Sort-Object -Property [AttendeeType] |
Group-Object -Property ‘`[AttendeeType`]’ -NoElement

But just gives me a count of the total number of attendees.

I tried a number of ways of dealing with the [] in the headers and therefore in the property names. In the end I decided it was going to be easier to completely reset the headers in the csv file:

Import-Csv -Path C:\test1\AttendeeReport.csv -Header  ‘UserName’, ‘REGISTRATIONSTATUS’, ‘AttendeeType’, ‘ConfirmationCode’, ‘PaymentAuthorization’, ‘RegisteredByEmail’, ‘PromotionCode’, ‘BioName’, ‘BioTitle’, ‘BioEmail’, ‘Created’, ‘Updated’, ‘LastName’, ‘Dietary’, ‘Alumni’, ‘FirstName’, ‘Twitter’, ‘BestEmail’

This means I have to skip the first record because it looks like this:

UserName             : [UserName]
REGISTRATIONSTATUS   : [REGISTRATIONSTATUS]
AttendeeType         : [AttendeeType]
ConfirmationCode     : [ConfirmationCode]
PaymentAuthorization : [PaymentAuthorization]
RegisteredByEmail    : [RegisteredByEmail]
PromotionCode        : [PromotionCode]
BioName              : [BioName]
BioTitle             : [BioTitle]
BioEmail             : [BioEmail]
Created              : [Created]
Updated              : [Updated]
LastName             : [LastName]
Dietary              : [Dietary]
Alumni               : [Alumni]
FirstName            : [FirstName]
Twitter              : [Twitter]
BestEmail            : [BestEmail]

My grouping script is now much simpler

Import-Csv -Path C:\test1\AttendeeReport.csv -Header  ‘UserName’, ‘REGISTRATIONSTATUS’, ‘AttendeeType’, ‘ConfirmationCode’, ‘PaymentAuthorization’, ‘RegisteredByEmail’, ‘PromotionCode’, ‘BioName’, ‘BioTitle’, ‘BioEmail’, ‘Created’, ‘Updated’, ‘LastName’, ‘Dietary’, ‘Alumni’, ‘FirstName’, ‘Twitter’, ‘BestEmail’ |
Select-Object -Skip 1 |
Where-Object REGISTRATIONSTATUS -eq ‘Complete’|
Sort-Object -Property AttendeeType |
Group-Object -Property AttendeeType –NoElement

If I come across other CSV files with [] in the headers I’m going to go for immediate replacement of the headers as the way to get the job done.


February 27, 2016  6:45 AM

PowerShell Summit–Registration closing soon

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
Powershell

Registration for the PowerShell and DevOps Global Summit will be closing in the next few days – http://powershell.org/wp/2016/02/18/last-chance-for-powershellsummit-org-registration/

We still have a few places left but you’ll have to hurry


February 24, 2016  3:22 PM

WMF 5.0 RTM has been republished

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
Powershell

A post on the PowerShell Team blog – https://blogs.msdn.microsoft.com/powershell/2016/02/24/windows-management-framework-wmf-5-0-rtm-packages-has-been-republished/ – reports that WMF 5.0 RTM has been republished.

You’ll have to uninstall the original RTM package before installing the new one.


February 24, 2016  1:14 PM

Get-ADUser quirk

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
Active Directory, Powershell

Came across an interesting quirk of the way Get-ADUser works.

If you use the –Identity parameter and tell it to find a specific user

PS> Get-ADUser -Identity dontexist
Get-ADUser : Cannot find an object with identity: ‘dontexist’ under: ‘DC=Manticore,DC=org’.
At line:1 char:1
+ Get-ADUser -Identity dontexist
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : ObjectNotFound: (dontexist:ADUser) [Get-ADUser], ADIdentityNotFoundException
+ FullyQualifiedErrorId : ActiveDirectoryCmdlet:Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException,Microsoft.ActiveDirectory.Management.Commands.GetADUser

You get an error if the user can’t be found

If you use a –Filter to perform the same search – its quite OK for nothing to be returned

PS> Get-ADUser -Filter {SamAccountName -eq ‘dontexist’}
PS>

Something to be aware of when error handling. When using the filter you can’t use try-catch because there’s no error if there’s no result


February 22, 2016  11:18 AM

IP Default Gateways by cmdlet

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
Network Adapter, Powershell

Following my recent post on setting the default gateway by using the Win32_NetworkAdapterConfiguration CIM class here’s how you do it using the networking cmdlets

Discover your adapters

Get-NetAdapter

Check the default gateway for an adapter

Get-NetIPConfiguration -InterfaceIndex 12 | select InterfaceIndex, IPv4Address, IPv4DefaultGateway

Set the default gateway

New-NetRoute -InterfaceIndex 12  -DestinationPrefix ‘0.0.0.0/0’ -NextHop ‘10.10.54.1’

This isn’t as intuitive as using the CIM class

Check the setting

£> Get-NetIPConfiguration -InterfaceIndex 12
InterfaceAlias       : Ethernet
InterfaceIndex       : 12
InterfaceDescription : Microsoft Hyper-V Network Adapter
NetProfile.Name      : Manticore.org
IPv4Address          : 10.10.54.100
IPv6DefaultGateway   :
IPv4DefaultGateway   : 10.10.54.1
DNSServer            : 10.10.54.201

To remove the default gateway

Remove-NetRoute -InterfaceIndex 12 -NextHop ‘10.10.54.1’ -Confirm:$false

If you leave off –Confirm you’ll be prompted to confirm the action on the active and persistent stores i.e. twice.

All of the above cmdlets are part of the NetTCPIP module available on Windows 8/Server 2012 and later.


February 22, 2016  9:34 AM

Quick test for updates that aren’t installed

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

I want a quick test to determine if any of the updates I’d approved hadn’t been installed on all of the relevant machines.

Get-WsusUpdate -Approval Approved | where InstalledOrNotApplicablePercentage -ne 100

Get the list of approved updates and filter on the InstalledOrNotApplicablePercentage

If anything does show up you can dig further to determine what hasn’t installed where


February 21, 2016  7:39 AM

IP Default Gateways

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
CIM, Network Adapter, Powershell

When you configure the IP Address on a network adapter you also have to set the default gateway if you want the machine to communicate with machines on other subnets.

One way you can do this is through the SetGateways method of Win32_NetworkAdapterConfiguration

$class = Get-CimClass -ClassName Win32_NetworkAdapterConfiguration $class.CimClassMethods[‘SetGateWays’].Parameters

Name                  CimType Qualifiers                         ReferenceClassName
—-                  ——- ———-                         ——————
DefaultIPGateway  StringArray {ID, In, MappingStrings}
GatewayCostMetric UInt16Array {ID, In, MappingStrings, Optional}

Notice you need to supply the information as arrays so:

$dgw = @(‘10.10.54.1’)
$gcm = @([uint16]2)

The default for the metric is 1. The metric is supplied as an unsigned 16 bit integer

Get-CimInstance -ClassName Win32_NetworkAdapterConfiguration -Filter “Index=2”  | Invoke-CimMethod –MethodName  SetGateWays -Arguments @{DefaultIPGateway = $dgw; GatewayCostMetric = $gcm}

To change the gateway simply overwrite the values via another call to SetGateways()

To completely remove the gateway information you need to set the value of the gateway to be the same as the IP address on the adapter

$dgw = @(‘10.10.54.200’)
$gcm = @([uint16]1)
Get-CimInstance -ClassName Win32_NetworkAdapterConfiguration -Filter “Index=2”  | Invoke-CimMethod –MethodName  SetGateWays -Arguments @{DefaultIPGateway = $dgw; GatewayCostMetric = $gcm}

Leaving the metric as 1 will cause no harm

Next time I’ll show how to perform the same actions with the networking cmdlets


February 15, 2016  10:50 AM

PowerShell Conference EU 2016–things to look forward to

Richard Siddaway Richard Siddaway Profile: Richard Siddaway

With 64 days to the European PowerShell conference (and less to the PowerShell Summit) I’m busy getting my sessions prepared.

At the European conference I’m presenting pre-conference workshops on DSC and CIM and then two sessions on managing the new Container feature in Server 2016 with PowerShell.

As i’m not organising this one I get to enjoy the conference.

There’s a number of sessions I’m really lookign forward to:

The sessions by Jeffery Snover and Bruce Payette haven’t been announced yet but they are bound to be good. Jeffery is a great speaker and Bruce knows so much about the inner workings of PowerShell that you always learn something new.

other sessions I’m lookign forward to include:

DSC resource creation by Ben Gelens

PowerShell and SQL Server: Journey to 200,000 rows per second by Chrissie LeMaire. if you ever wanted to discover how really optimise a process this session is for you

Test-driven developement with Pester by June Blender

If you’re looking for a PowerShell conference in Europe – this is the one where you’ll find great content. There’ll be a bunch of PowerShell MVPs there including

Tobias Weltner

Ravikanth Chaganti

Jeff Wouters

Steven Murawski

and the speakers of the sessions I mentioned earlier.  if you can’t get your PowerShell questions answered at the conference then there isn’t an answer


February 10, 2016  8:59 AM

PowerShell articles – – February 2016

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
Powershell

I’ve had 2 articles published this week.

The first one is on the Scripting Guy blog

https://blogs.technet.microsoft.com/heyscriptingguy/2016/02/08/should-i-use-cim-or-wmi-with-windows-powershell/

And looks at the WMI and CIM cmdlets showing why 99.99% you should be using the CIM cmdlets.

The second article is on the UK TechNet blog

http://blogs.technet.com/b/uktechnet/archive/2016/02/10/powershell-and-server-core.aspx

and discusses how to configure and administer a Windows Server Core instance. All of the techniques in the article use built in cmdlets – no scripting required


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: