Monthly Archive

Creating Registry Key

I had a question left on the blog asking how to create a registry key. My preferred method is to use the CIM class = StdRegProv. Its a static class so you don’t need to create an object


[uint32]$hklm = 2147483650
$newkey = 'SOFTWARE\NewKey'

Invoke-CimMethod -ClassName StdRegProv -MethodName CreateKey -Arguments @{hDefKey = $hklm; sSubKeyName = $newkey}


Define the variables for the HIVE in this case HKLM – local machine .  Notice that the value has to be an unsigned integer.


The key you want to create is just the path to the key. if you need to create multiple levels of subkeys they will all create from a single path.


Then use Invoke-CimMethod to call the CreateKey method on StdRegProv. The hash table in Arguments parameter has the method parameter names and appropriate  values.


If everything works you’ll get a return value of 0.


How did I know which parameters the method took?


I used Get-CimClass but that’s a story for another post.

PowerShell column

The first in a regular(ish) series of articles has been published on the TechNet UK Blog.


Covering all things PowerShell related the articles will be appearing every 3-4 weeks.

Windows Server 2016 TP4

A new technology preview for Windows Server 2016 has just been released. Available from all good Microsoft download sites.

Splatting and Default parameters

One thing you don’t hear much about is default parameters.

Consider this

Get-CimInstance -ClassName Win32_LogicalDisk -Filter "DeviceId = 'C:'"


A pretty standard use of CIM.


Now think if you have to do this across a number of machines on a regular basis.  Typing could get a bit tedious.

You could use splatting:

$params = @{
  ClassName = 'Win32_LogicalDisk'
  Filter = "DeviceId = 'C:'"

Get-CimInstance @params


Create a hash table of parameter names and values and use that to reduce your typing. Because its a hash table you can modify as required to use other classes or Filters


An alternative is to use default parameters

$PSDefaultParameterValues = @{
'Get-CimInstance:ClassName' = 'Win32_LogicalDisk'
'Get-CimInstance:Filter' = "DeviceId = 'C:'"



Use the $PSDefaultParameterValues variable to hold your default values. Note how the cmdlet and parameter are defined. You can then call the cmdlet and the default parameters and their values are applied.


If you want to override the default values you may have to do it for all of the default values for a cmdlet – in the above case the Filter is nonsensical if applied to Win32_OperatingSystem so you’d have to do this

Get-CimInstance -ClassName Win32_OperatingSystem -Filter "Manufacturer LIKE '%'"


Used with a bit of care splatting and default parameters are a good way to save typing

Out of Process

One thing I’ve been seeing come up a lot recently is the problem of modules and cmdlets cot being available when jobs and workflows are executed even though the module has been specifically loaded into PowerShell.


This is because workflows and Jobs run in a separate process when you execute them – NOT your current PowerShell process.  The worflow or job process doesn’t run your profile and doesn’t auto load modules.  


You need to specifically perform the module import. Remember you can’t use Import-Module in a workflow so you have to wrap that part in  an InlineScript block.

Accessing WMI

There are 3 sets of cmdlets for working with WMI classes – the WMI cmdlets, the WSMAN cmdlets and the CIM cmdlets.  The protocols used by these 3 sets are different.


The WMI cmdlets introduced in PowerShell 1 & 2 use DCOM for local and remote access under all circumstances


The WSMAN cmdlets introduced in PowerShell 2 use WSMAN (WinRm)

The CIM cmdlets introduced in PowerShell 3 use:

- DCOM for local access if ComputerName parameter NOT used

- WSMAN for local access IF –ComputerName parameter is used

- WSMAN (WinRM) for remote access 

- WSMAN if a default CIM session is used for remote access

- DCOM if a CIM session is created using DCOM as the protocol option


The CIM cmdlets are easier to use than the WSMAN cmdlets and are the recommended way to access WMI classes.

PowerShell + DevOps Global Summit 2016 – the agenda

We've finalised the agenda and we're starting to publish session information on the web site at


There are a handful of sessions on the site at present. The rest will be added over the next week or so.


Keep checking back to see who's been added.


Registration opens 1 December 2015

WMI wildcards and filtering

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 = {
    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

PowerShell in Action, 3e MEAP 2

Another chapter of PowerShell in Action third edition has been released into the MEAP process. – see

WMI cmdlets and credentials

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.