PowerShell for Windows Admins


November 11, 2015  2:00 PM

WMI wildcards and filtering

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
CIM, Powershell, WMI

A question on the forum asking about filtering WMI results raises a number of interesting points.

The user wanted to pass a computername and a filter term to pull product information from remote machines. I ended up with this

$computername = $env:COMPUTERNAME
$filter = ‘Live’

$scriptblock = {
param($filter)
Get-WmiObject -Class Win32_product -Filter “Name LIKE ‘%$filter%'” |
Select  IdentifyingNumber, Name, LocalPackage }

Invoke-Command -ComputerName $computername -ScriptBlock $scriptblock -ArgumentList $filter

You can pass an argument into the scriptblock you use with invoke-command by using the –Argumentlist parameter.

More interesting is the –Filter parameter on Get-Wmi-Object

-Filter “Name LIKE ‘%$filter%'”

Notice that % is the wildcard not * as you’d use for a string.  Its always better to filter the results from Get-WmiObject using –Filter rather than a where-object after the call.

Of course you can just use the wmi or cim cmdlets directly for this problem which is even better

Get-WmiObject -Class Win32_Product -ComputerName $computername -Filter “Name LIKE ‘%$filter%'” | Select  IdentifyingNumber, Name, LocalPackage

Get-CimInstance -ClassName Win32_Product -ComputerName $computername -Filter “Name LIKE ‘%$filter%'” | Select  IdentifyingNumber, Name, LocalPackage

November 6, 2015  1:48 PM

PowerShell in Action, 3e MEAP 2

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
Books, Powershell

Another chapter of PowerShell in Action third edition has been released into the MEAP process. – see https://manning.com/books/windows-powershell-in-action-third-edition


November 4, 2015  5:13 AM

WMI cmdlets and credentials

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
Powershell, WMI

If you’re working with the WMI cmdlets and need to pass credentials you’ll end up with a statement something like this

Get-WmiObject -Class Win32_ComputerSystem -ComputerName $computer -Credential $cred

If the computer name defaults to the local host or you use . or ‘localhost’ as the computer name you’ll get an error

PS> Get-WmiObject -Class Win32_ComputerSystem -ComputerName $env:COMPUTERNAME  -Credential $cred
Get-WmiObject : User credentials cannot be used for local connections
At line:1 char:1
+ Get-WmiObject -Class Win32_ComputerSystem -ComputerName $env:COMPUTER …
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : InvalidOperation: (:) [Get-WmiObject], ManagementException
+ FullyQualifiedErrorId : GetWMIManagementException,Microsoft.PowerShell.Commands.GetWmiObjectCommand

You need to build in some logic to prevent credentials being used ig you’re working against the local machine.  One way to this is to create a bunch of Get-WmiObject statements and use if statements to decide which to use.

I think there’s a neater way if you use splatting

#$computer = $env:COMPUTERNAME
#$computer = ‘localhost’
#$computer = ‘.’
$computer = ‘server02’

$params = @{
‘Class’ =  ‘Win32_ComputerSystem ‘
‘ComputerName’ = $computer
}

switch ($computer){
“$env:COMPUTERNAME” {break}
‘localhost’ {break}
‘.’   {break}
default {$params += @{‘Credential’ = $cred}}
}

Get-WmiObject @params

Splatting involves creating a hash table of the parameters and their values. You can then use a switch statement to decide if computer matches any of the local name variants. If it doesn’t then add the credential

You could extend this slightly to cope with not having a computer name  in the initial set of params and only add it if required

$params = @{
‘Class’ =  ‘Win32_ComputerSystem’
}

if ($computer) {
$params += @{‘ComputerName’ = $computer}

switch ($computer){
“$env:COMPUTERNAME” {break}
‘localhost’ {break}
‘.’   {break}
default {$params += @{‘Credential’ = $cred}}
}
}

Get-WmiObject @params

Then you only test the computer name if you need to.


October 30, 2015  11:37 AM

Creating DNS records

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
DNS, Powershell

Following on from my previous post about creating a reverse lookup zone in DNS here’s a function to create records in that zone.

The function takes an IP address and name (of host) and uses Add-DnsServerResourceRecordA  to add the record to the forward lookup zone – I use my default AD zone.

The function then splits the IP address. Uses the last octet for the name in the reverse record. Creates the reverse lookup zone from the first 3 octets – notice how the range parameter is used in a decreasing way to specify the order of the octets – to create the reverse lookup zone. The host name and zone are used to create the FQDN of the host.

Add-DnsServerResourceRecordPtr  is used to create the reverse (PTR) record.

function new-dnsrecord {
[CmdletBinding()]
param (
[string]$name,
[string]$ipaddress,
[string]$zone = ‘Manticore.org’
)

Add-DnsServerResourceRecordA -Name $name -ZoneName $zone -AllowUpdateAny -IPv4Address $ipaddress

$octs = $ipaddress -split ‘\.’

$revname = “$($octs[3])”
$revzone = “$($octs[2..0] -join ‘.’).in-addr.arpa”
$fqdn = “$name.$zone”

Add-DnsServerResourceRecordPtr -Name $revname -ZoneName $revzone -AllowUpdateAny -PtrDomainName $fqdn

}


October 30, 2015  11:36 AM

Create a reverse lookup zone

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
DNS, Powershell

I needed to create a DNS reverse lookup zone for my test environment. With Windows Server 2012 R2 I’ve got cmdlets available for managing DNS servers – the DnsServer module. You need to install the DNS role or the DNS RSAT tools to get access to the module.

 

To create a new reverse lookup zone

Add-DnsServerPrimaryZone -DynamicUpdate Secure -NetworkId ‘10.10.54.0/24’ -ReplicationScope Domain

 

Use the netorkId to define the subnet the zone spans. Setting DynamicUpdate to Secure ensures I have an AD integrated zone and I’ve set the replication scope to the domain.

 

Doesn’t get any easier


October 29, 2015  12:31 PM

Win free entry to the PowerShell Summit

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
Powershell

Want to go to the PowerShell Summit? Want to go for free?

You can win free entry to the Summit (need to pay your own travel & hotel) through the competition at http://powershell.org/wp/2015/10/28/win-a-free-4-day-pass-to-powershell-and-devops-summit-2016/


October 26, 2015  9:07 AM

-in operator

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
Powershell

As an alternative to the –contains operator you can use the –in operator

Repeating the tests from the previous post on –contains

PS> $primes = 1,3,5,7,11,13,17,19,23,29,31,37,41,43,47
PS> $candidate = 7
PS> $candidate -in $primes
True
PS> $candidate = 4
PS> $candidate -in $primes
False

The –in operator can be used in the simplified where syntax but –contains can’t


October 26, 2015  8:57 AM

-contains operator

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
Powershell

Sometimes you may want to test if a value is in a collection of values

For instance

$primes = 1,3,5,7,11,13,17,19,23,29,31,37,41,43,47

if you want to test if 7 is a member of the collection

$candidate = 7
$primes -contains $candidate
True

Likewise testing 4

$candidate = 4
$primes -contains $candidate
False


October 26, 2015  8:44 AM

DSC resource kit update–October 2015

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
Powershell

The DSC resource kit is the primary place to look for DSC resources beyond those baked into Windows.

An update to the resources in the kit has been announced. Some new resources and lots of bug fixes.

see http://blogs.msdn.com/b/powershell/archive/2015/10/23/dsc-resource-kit-updates-are-here.aspx

for details


October 24, 2015  7:48 AM

Testing connectivity before Invoke-Command

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
Powershell

A question on the forum asked about testing if a remote machine could be reached before using Invoke-Command against it.

The usual way to test if you can reach a remote machine is to ping it

PS> Test-Connection -ComputerName $env:COMPUTERNAME -Quiet
True

That shows you can reach the machine but it doesn’t mean that you can use Invoke-Command to send a request.

I think a better test is to use Test-WSMan

It will test if the WinRm service is running (won’t test if remoting is enabled)

$computers = “$env:COMPUTERNAME”, ‘NotFound’

foreach ($computer in $computers){
$target = $computer
if (Test-WSMan -ComputerName $computer -ErrorAction Ignore) {
Invoke-Command -ComputerName $computer -ScriptBlock {Get-Service}
}
else {
Write-Warning -Message “Couldn’t connect to $computer”
}

}

You can push the output to file or put the unreachable machine names into a file if you need to record them.

 


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: