Monthly Archive

PowerShell and WMI

Cim session oddity

The CIM cmdlets were introduced with PowerShell 3.0.  You can use the –ComputerName parameter to access a remote machine or, if you need to run multiple commands to the remote machine, you can create a CIM session.

 

CIM sessions are analogous to PowerShell remoting sessions and use WSMAN by default to connect to the remote machine:

PS> $c12 = New-CimSession -ComputerName W12R2SUS

PS> Get-CimInstance -CimSession $c12 -ClassName Win32_OperatingSystem | fl

SystemDirectory : C:\Windows\system32
Organization    :
BuildNumber     : 9600
RegisteredUser  : Windows User
SerialNumber    : 00252-00107-57895-AA282
Version         : 6.3.9600
PSComputerName  : W12R2SUS

 

In this case I’m accessing a Windows 2012 R2 system

 

If you try to create a CIM session to a machine running PowerShell 2.0 it will appear to work but you’ll get an error when you try to access the session:

PS> $c8 = New-CimSession -ComputerName W8R2STD01
PS> Get-CimInstance -CimSession $c8 -ClassName Win32_OperatingSystem | fl
Get-CimInstance : The WS-Management service cannot process the request. A DMTF resource URI was used to access a non-DMTF class. Try again using a non-DMTF resource URI.
At line:1 char:1
+ Get-CimInstance -CimSession $c8 -ClassName Win32_OperatingSystem | fl
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (root\cimv2:Win32_OperatingSystem:String) [Get-CimInstance], CimException
    + FullyQualifiedErrorId : HRESULT 0x80338139,Microsoft.Management.Infrastructure.CimCmdlets.GetCimInstanceCommand
    + PSComputerName        : W8R2STD01

 

The reason is that the version of WSMAN installed with with PowerShell 2.0 (WSMAN 2.0) isn’t compatible with CIM sessions which expect WSMAN 3.0

 

One option is to use a DCOM based session:

PS> $opt = New-CimSessionOption -Protocol Dcom
PS> $c8D = New-CimSession -ComputerName W8R2STD01 -SessionOption $opt
PS> Get-CimInstance -CimSession $c8D -ClassName Win32_OperatingSystem | fl

SystemDirectory : C:\Windows\system32
Organization    :
BuildNumber     : 7601
RegisteredUser  : Windows User
SerialNumber    : 00477-179-0000007-84050
Version         : 6.1.7601
PSComputerName  : W8R2STD01

 

PowerShell MVP Jeff Hicks discovered that if you use a filter parameter with Get-CimInstance you can access PowerShell 2.0 machines using a WSMAN based CIM session

PS> Get-CimInstance -CimSession $c8 -ClassName Win32_OperatingSystem -Filter "Caption LIKE '%'"  | fl

SystemDirectory : C:\Windows\system32
Organization    :
BuildNumber     : 7601
RegisteredUser  : Windows User
SerialNumber    : 00477-179-0000007-84050
Version         : 6.1.7601
PSComputerName  : W8R2STD01

 

In this case you’re filtering on the Caption being like any characters

 

I stood in for a speaker who was ill at the recent European PowerShell conference and part of the session was on using CIM sessions. This issue came up and I decided to investigate a bit closer

Without a filter:

PS> Get-CimInstance -CimSession $c8 -ClassName Win32_OperatingSystem -Verbose
VERBOSE: Perform operation 'Enumerate CimInstances' with following parameters, ''namespaceName' =
root\cimv2,'className' = Win32_OperatingSystem'.
Get-CimInstance : The WS-Management service cannot process the request. A DMTF resource URI was used to access a
non-DMTF class. Try again using a non-DMTF resource URI.
At line:1 char:1
+ Get-CimInstance -CimSession $c8 -ClassName Win32_OperatingSystem -Ver ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (root\cimv2:Win32_OperatingSystem:String) [Get-CimInstance], CimException
    + FullyQualifiedErrorId : HRESULT 0x80338139,Microsoft.Management.Infrastructure.CimCmdlets.GetCimInstanceCommand
    + PSComputerName        : W8R2STD01

VERBOSE: Operation 'Enumerate CimInstances' complete.

 

An attempt is made to enumerate the instances of the Win32_OperatingSystem class

 

If you use a filter

PS> Get-CimInstance -CimSession $c8 -ClassName Win32_OperatingSystem -Filter "Caption LIKE '%'"  -Verbose | fl
VERBOSE: Perform operation 'Query CimInstances' with following parameters, ''queryExpression' = SELECT * FROM
Win32_OperatingSystem WHERE Caption LIKE '%','queryDialect' = WQL,'namespaceName' = root\cimv2'.

SystemDirectory : C:\Windows\system32
Organization    :
BuildNumber     : 7601
RegisteredUser  : Windows User
SerialNumber    : 00477-179-0000007-84050
Version         : 6.1.7601
PSComputerName  : W8R2STD01

VERBOSE: Operation 'Query CimInstances' complete.

 

You’re sending a WQL  query to the remote machine.

 

My current theory is that Get-CimInstance is trying to enumerate the instances of a particular class (in a similar way to Get-WSmnaInstance does) and that fails due to the WSMAN version mismatch.  Using the Filter bypasses the enumeration allowing it to work.

 

This is a totally undocumented feature and there is no guarantee it will continue to work in future versions. Until PowerShell 2.0 is gone from you environment be aware that its an option but be careful

Folder creation dates from WMI

A question on the powershell.org about finding the creation date of folders raises some interesting points

 

To find a folder’s creation date use:

Get-WmiObject -Class Win32_Directory -Filter "Drive='C:' AND Path = '\\users\\$user\\'" | select Name, @{N='Creation date'; E={$_.ConvertToDateTime($_.CreationDate)}}

 

OR

 

Get-CimInstance -ClassName Win32_Directory -Filter "Drive='C:' AND Path = '\\users\\$user\\'" | select Name, CreationDate

 

If you use Get-WmiObject the date is returned in the form

20160128110039.938756+000

 

Which is why you need to perform the conversion using the ConvetToDateTime method that PowerShell adds to every WMI object.

 

Get-CimInstance automatically performs the conversion for you.

 

The other interesting part is the filter

"Drive='C:' AND Path = '\\users\\$user\\'"

 

Note that it’s wrapped in double quotes. Each of the values is a string so HAS to be in single quotes. Also note that you need to double the \ characters as WMI treats a single \ as an escape character so you have to escape the escape character.

Monitor Info

A question on the forum about combining information from 2 CIM classes produced this:

 

function Get-MonitorInfo {
    [CmdletBinding()]
    param(
        $computername = $env:COMPUTERNAME
    )

    $cs = New-CimSession -ComputerName $computername
   
    $monitors =  Get-CimInstance -Namespace root\wmi -ClassName WmiMonitorId -Filter "Active = '$true'" -CimSession $cs
   
    foreach ($monitor in $monitors) {
       
        $in = ($monitor.InstanceName).Replace('\', '\\')
        Write-Verbose -Message $in
        $dp = Get-CimInstance -Namespace root\wmi -ClassName WmiMonitorBasicDisplayParams -Filter "InstanceName = '$in'" -CimSession $cs
       
        $name = ''

        foreach ($c in $monitor.UserFriendlyName){
            if ($c -ne '00'){$name += [char]$c}
        }

        $type = 'Unknown'
        switch ($dp.VideoInputType){
            0 {$type = 'Analog'}
            1 {$type = 'Digital'}
        }
       
        New-Object -TypeName PSObject -Property @{
            Name = $name
            Type = $type
        }
    }
   
    Remove-CimSession -CimSession $cs
}

 

Create a CIM session to the computer. Get the instances of the WmiMonitorId class. Iterate through them and find the matching WmiMonitorBasicDisplayParams class instance.

 

The InstanceName of the monitor will look like this:

DISPLAY\GSM598F\4&19086f00&0&UID200195_0

you need to replace \ by \\ to use the value in a CIM query because \ is treated as the escape character and you have to escape it to use it

 

Translate the UserFriendly name by converting the byte array to a string and determine the VideoInputType using the switch.

 

Create an object and output

IIS information

In my recent post about getting server information from a IIS web server I said I post about getting similar information from later machines.

 

You still have the root\MirosoftIISv2 namespace available if you install the IIS 6.0 tools but one question to keep in mind – how long will they continue to be available?

 

Your alternative is the root\webadministration names space. You can use the Site class to get the relevant information

 

$serverdata = @()
Get-CimInstance -Namespace root\webadministration -ClassName Site -ComputerName $env:COMPUTERNAME |
foreach {

$serverdata += New-Object -TypeName PSObject -Property @{
Port = [string]::Join(',', ($_.Bindings | select -ExpandProperty BindingInformation))
SiteName = $_.Name
SiteId = $_.id
PSComputerName = $_.PSComputerName
Status = Invoke-CimMethod -InputObject $_ -MethodName GetState | select -ExpandProperty ReturnValue
}

}
$serverdata

 

Remember that COM objects are inert so you can’t call the method directly on the object. otherwise the info is about the same

IIS 6.0 server information

A question of the forum asked about getting data from IIS 6.0 servers

 

One of the ways to access this data is to use CIM (WMI). IIS 6.0 has the root\MicrosoftIIsV2  namespace. Later versions of Windows server also have a root\webadministration namespace which is preferred.

 

The original question asked about IIS 6.0 – I’ll show the same functionality using the later namespace in the next post

 

This based on the original code in the question and isn’t necessarily how I would do it from scratch

$file = Get-Content "C:\Temp\PowerShellScripts\IISQuery\servers.txt"
$OutputDir = "C:\Temp\PowerShellScripts\IISQuery\Output"
$OutputFile = Join-Path $OutputDir "IIStest.csv"
$serverdata = @()

foreach ($computername in $file)
{
$IISWebServer = Get-WmiObject -Namespace root\MicrosoftIIsV2 -Class IISWEbServer -ComputerName $computername -Authentication 6
foreach ($webserver in $IISWebServer) {

$IISWebServerSet = Get-WmiObject -Namespace root\MicrosoftIISv2 -Class IISWebServerSetting -ComputerName $computername -Filter "Name='$($webserver.Name)'"  -Authentication 6

$serverdata += New-Object -TypeName PSObject -Property @{
PScomputername = $IISWebServerSet.PScomputername
ServerComment = $IISWebServerSet.ServerComment
SiteStatus = $webserver.ServerState
Bindings = [string]::join(';',($IISWebServerSet.ServerBindings | select -expand hostname))
Port = [string]::join(';',($IISWebServerSet.ServerBindings | select -expand Port))
SiteName = $IISWebServerSet.Name
}

} ## end of foreach ($webserver in $IISWebServer)

}  ## end of foreach ($computername in $file)
$serverdata | Export-Csv -Path $OutputFile –NoTypeInformation

 

Start by defining input and output files and an empty array

 

Loop through the servers and get the IISWebserver class instance. You’ll get one object per web site. Loop through the sites and get the IISWebServerSetting class for that site (using –Filter).

 

Create and output object and add to the array

Export the array to a csv file

 

There are a few improvements that could be made to this to make it more efficient that I’ll cover in a later post

Network adapter Index

A few years ago I wrote a post about setting the IP metric on a connection - https://richardspowershellblog.wordpress.com/2012/01/01/changing-ip-connection-metric/

 

I was recently asked if the Index’s associated with network adapters were consistent acros machines. The answer – unfortunately- is no they’re not as a rule.

 

I used the function from the original post

function Test-IPmetric {
    Get-WmiObject -Class Win32_NetworkAdapter -Filter "AdapterType = 'Ethernet 802.3'" |
    foreach {
        Get-WmiObject -Class Win32_NetworkAdapterConfiguration -Filter “Index=$($_.DeviceId)” |
        Select-Object Description, Index, IPEnabled, IPConnectionMetric
    }
}

to view the index

 

The Index property from Win32_NetworkAdapaterConfiguration is identical to the DeviceId from the Win32_NetworkAdapater class for a given network adapter.

 

if you try the function on a number of machines you’ll see that Index numbers assigned by Windows aren’t consistent.  My test VMs (Hyper-V) all seem to have the same index numbers assigned but I always create my VMs and add network adapters in the same way.

 

I wouldn’t rely on a particular index being assigned to a given network adapter – always pull the data and test

CDXML filter parameters

I was recently asked about adding a filter parameter to a cmdlet created through CDXML. If you’ve not seen it before (see PowerShell and WMI Chapters 18 & 19 from www.manning.com) CDXML allows you to creat ecmdlets by wrapping a WMI class in some simple XML.

 

The resultaing CDXML (Cmdlet Definition XML) is thn published as a module.  Here’s a simple example using the Win32_NetworkAdapterConfiguration class

<?xml version='1.0' encoding='utf-8'?>
<PowerShellMetadata xmlns='http://schemas.microsoft.com/cmdlets-over-objects/2009/11'>
  <Class ClassName='ROOT\cimv2\Win32_NetworkAdapterConfiguration'>
    <Version>1.0</Version>
    <DefaultNoun>NetworkAdapterConfiguration</DefaultNoun>
    <InstanceCmdlets>
      <GetCmdletParameters DefaultCmdletParameterSet='DefaultSet'>
      </GetCmdletParameters>
    </InstanceCmdlets> 
  </Class>
</PowerShellMetadata>

 

The first 2 lines are boilerplate. The NameSpace and WMI class are defined on line 3, follwoed by a version number (arbitary) and a default noun for you cmdlet to use.  Instance cmdlets defines how you’ll pull the data for existing instances of the class – in other words the Get-NetworkAdapterConfiguration cmdlet.

 

Save as a CDXML file and import as a module

Import-Module .\NetworkAdapterConfiguration.cdxml

 

Get-Module will sjow it as a Cim module with a single exported command.   Use it like any other cmdlet

PS> Get-NetworkAdapterConfiguration | ft -a

ServiceName  DHCPEnabled Index Description
-----------  ----------- ----- -----------
kdnic        True        0     Microsoft Kernel Debug Network Adapter
mwlu97w8     True        1     Marvell AVASTAR Wireless Composite Device
msu64w8      False       2     Surface Ethernet Adapter
mwlu97w8     True        3     Marvell AVASTAR 350N Wireless Network Controller
RFCOMM       False       4     Bluetooth Device (RFCOMM Protocol TDI)
BthPan       True        5     Bluetooth Device (Personal Area Network)
vwifimp      True        6     Microsoft Wi-Fi Direct Virtual Adapter
vwifimp      True        7     Microsoft Wi-Fi Direct Virtual Adapter
RasSstp      False       8     WAN Miniport (SSTP)
RasAgileVpn  False       9     WAN Miniport (IKEv2)
Rasl2tp      False       10    WAN Miniport (L2TP)
PptpMiniport False       11    WAN Miniport (PPTP)
RasPppoe     False       12    WAN Miniport (PPPOE)
NdisWan      False       13    WAN Miniport (IP)
NdisWan      False       14    WAN Miniport (IPv6)
NdisWan      False       15    WAN Miniport (Network Monitor)

 

Using the cmdlet is equivalent to

Get-CimInstance -ClassName Win32_NetworkAdapterConfiguration

 

but is easier and requires less typing.

Very often you’ll want to pick a specific adapter – for instance

 

Get-CimInstance -ClassName Win32_NetworkAdapterConfiguration -Filter 'Index=3'

 

You can implement the same kind of filters using CDXML. You add a queryable properties section as shown below:

<?xml version='1.0' encoding='utf-8'?>
<PowerShellMetadata xmlns='http://schemas.microsoft.com/cmdlets-over-objects/2009/11'>
  <Class ClassName='ROOT\cimv2\Win32_NetworkAdapterConfiguration'>
    <Version>1.0</Version>
    <DefaultNoun>NetworkAdapterConfiguration</DefaultNoun>
    <InstanceCmdlets>
      <GetCmdletParameters DefaultCmdletParameterSet='DefaultSet'>

        <QueryableProperties>
          <Property PropertyName='Index'>
            <Type PSType ='UInt32'/>
            <RegularQuery AllowGlobbing='true'>
              <CmdletParameterMetadata PSName='Index'  ValueFromPipelineByPropertyName='true' CmdletParameterSets='DefaultSet' />
            </RegularQuery>
          </Property>
        </QueryableProperties>       
             
      </GetCmdletParameters>
    </InstanceCmdlets> 
  </Class>
</PowerShellMetadata>

 

Set the paraemter name – same as property to use here – and the type (unsigned integer). Decide whether pipeline input and wildcards (globbing) are allowed and save the file.

 

Re-import the module (use the Force) and your new parameter is available

Get-NetworkAdapterConfiguration -Index 3

 

Its important to understand CDXMLMI – even if you never create a CDXML module – because 2/3 of the cmdlets in Windows Server 2012 and later are created this way.

WMI discovery

I’ve been working with System Center Configuration Manager this week. SCCM uses a lot of WMI. However, WMI discovery is still a bit of an art.

 

I needed to find the SMS_SCI_Component class.

 

If you know the namespace you can easily find the classes in that namespace but namespaces are hierarchical so you need to work down the tree.

The root namespace is at the top of the namespace tree so

C:\Scripts> Get-CimInstance -ClassName __NAMESPACE -Namespace root

Name
----
subscription
DEFAULT
SCCMDP
CIMV2
msdtc
Cli
nap
MicrosoftIISv2
SECURITY
CCMVDI
NetworkModel
RSOP
SMS
ccm
StandardCimv2
WMI
AccessLogging
directory
Policy
InventoryLogging
Interop
Hardware
ServiceModel
Microsoft
aspnet

 

After a bit of digging I found I needed the sms namespace

PS C:\Scripts> Get-CimInstance -ClassName __NAMESPACE -Namespace 'root\sms'

Name 
----    
site_PS1

 

which leads to:

Get-CimInstance -ClassName SMS_SCI_Component -Namespace 'root\sms\site_PS1'

 

What if you only know the class?

There’s a little trick using Get-WmiObject

Get-WmiObject -Namespace root -Recurse -List -Class SMS_SCI_Component

   NameSpace: ROOT\SMS\site_PS1

Name  
----      
SMS_SCI_Component      

 

The trick is to start with the root namespace and use the –Recurse (search through all child namespaces) and –List (just give class details) parameters.  You’ll see a listing by namespace for each instance of the class discovered.

BinaryMiLog cmdlets

It’s not often I come across soemthing brand new in PowerShell but yesterday when I was investigating New-CimInstance I discovered 2 cmdlets in the CimCmdlets module I hadn’t noticed before. These are:

Export-BinaryMiLog

Import-BinaryMiLog

 

The cmdlets are used to export, or import, CIM instances as a binary encoded file.  Think of them as  Export-Clixml and Import-Clixml but for CIM instances.

Their usage is very simple:

Get-CimInstance -ClassName Win32_OperatingSystem |
Export-BinaryMiLog -Path testfile.bmil

 

This creates a   30 KB binary file – its definitely not human readable!

You don’t need to use a bmil extension (its the one in the help file) and you can use a CIM instance object instead of the pipeline

$os = Get-CimInstance -ClassName Win32_OperatingSystem
Export-BinaryMiLog -InputObject $os -Path testfile2.stuff

 

Getting the data back is performed by Import-BinaryMiLog

$os1 = Import-BinaryMiLog -Path .\testfile.bmil
$os2 = Import-BinaryMiLog -Path .\testfile2.stuff

 

The results appear to be a standard CIM object

Compare-Object -ReferenceObject $os -DifferenceObject $os1 -IncludeEqual
Compare-Object -ReferenceObject $os -DifferenceObject $os2 -IncludeEqual
Compare-Object -ReferenceObject $os1 -DifferenceObject $os2 –IncludeEqual

 

These cmdlets give you way to persist CIM objects to disk so that they can be referenced at a later date. If you need to test for changes to a system this could be a useful technique

New-CimInstance cmdlet and the–Key parameter

I was asked a question about the –Key parameter on New-CimInstance today. I wasn’t sure of the answer so I’ve done some experimentation.

 

I tend to avoid New-CimInstance if I can preferring to use the Create method on the CIM class – however not all CIM classes have a create method so need to fall back on New-CimInstance.

 

I started by looking at the documentation. The help file for New-CimInstance says:

-Key<String[]>

Specifies the properties that are used as keys. CimSession and ComputerName cannot be used when Key is specified.

 

That then leads to the question how do I discover the Key or Keys of a CIM class.  You can’t use the –Qualifier parameter in Get-CimClass because that works at the class level and Key is a property qualifier.  Means you need to use some code

function Get-CimClassKey { 

    param (
   
        [string]$CIMnamespace = 'ROOT/cimv2',
       
        [string]$CIMclass
   
    )

    $class = Get-CimClass -Namespace $CIMnamespace -ClassName $CIMclass

    foreach ($property in $class.CimClassProperties) {
 
        $property | Select-Object -ExpandProperty Qualifiers |
        foreach {
            if ($_.Name -eq 'key'){
                $property
            }
        }

    }
}

 

The Key property of a class HAS to be given a value when a new instance of the class is created.

 

The New-CimInstance help file shows an example using Win32_Environment.  Adapring the example:

PS> New-CimInstance -ClassName Win32_Environment @{Name='RStest1'; VariableValue='test1'; UserName='RSSURFACEPRO2\Richard'}

Name             UserName                                            VariableValue
----             --------                                            -------------
RStest1          RSSURFACEPRO2\Richard                               test1

Using our function to discover the Keys of Win32_Environment

PS> Get-CimClassKey -CIMclass Win32_Environment

Name               : Name
Value              :
CimType            : String
Flags              : Property, Key, NullValue
Qualifiers         : {read, key, MappingStrings, Override...}
ReferenceClassName :

Name               : UserName
Value              :
CimType            : String
Flags              : Property, Key, ReadOnly, NullValue
Qualifiers         : {key, MappingStrings, MaxLen, read}
ReferenceClassName :

 

Adding the –Key parameter

PS> New-CimInstance -ClassName Win32_Environment @{Name='RStest2'; VariableValue='test2'; UserName='RSSURFACEPRO2\Richard'} -Key 'Name', 'UserName'

Name             UserName                                            VariableValue
----             --------                                            -------------
RStest2          RSSURFACEPRO2\Richard                               test2

 

Using Win32_Environment you can use the Key parameter, or not, as long as you define values for the Name and Username properties.

Another example in the New-CimInstance help file uses the Win32_Process class.  The key for that class is the Handle property

PS> Get-CimClassKey -CIMclass Win32_process

Name               : Handle
Value              :
CimType            : String
Flags              : Property, Key, ReadOnly, NullValue
Qualifiers         : {key, MaxLen, read}
ReferenceClassName :

 

the Handle is appears to be identical to the ProcessId in value as far as I can determine

 

This now gets  messy:

 

Just the Handle.  BTW exmple 3 in the documentation has an error as Handle is a string not an integer

PS> New-CimInstance -ClassName Win32_Process -Property @{Handle='0'}
New-CimInstance : Provider is not capable of the attempted operation
At line:1 char:1
+ New-CimInstance -ClassName Win32_Process -Property @{Handle='0'}
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (Win32_Process:CimInstance) [New-CimInstance], CimException
    + FullyQualifiedErrorId : HRESULT 0x80041024,Microsoft.Management.Infrastructure.CimCmdlets.NewCimInstanceCommand

 

Add the Key parameter

PS> New-CimInstance -ClassName Win32_Process -Property @{Handle='0'} -Key Handle
New-CimInstance : Provider is not capable of the attempted operation
At line:1 char:1
+ New-CimInstance -ClassName Win32_Process -Property @{Handle='0'} -Key ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (Win32_Process (Handle = "0"):CimInstance) [New-CimInstance], CimException
    + FullyQualifiedErrorId : HRESULT 0x80041024,Microsoft.Management.Infrastructure.CimCmdlets.NewCimInstanceCommand

 

The only way it works is if you use –ClientOnly to make an in memory CIM instance that only exists in your PowerShell session

PS> New-CimInstance -ClassName Win32_Process -Property @{Handle='0'} -Key Handle -ClientOnly

Handle PSComputerName
------ --------------
0

 

You can remove the –Key parameter

PS> New-CimInstance -ClassName Win32_Process -Property @{Handle='0'} -ClientOnly

Handle PSComputerName
------ --------------
0

 

Win32_Process has a Create method that takes these parameters

PS> $class.CimClassMethods['Create'].Parameters

Name                       CimType Qualifiers                                 ReferenceClassName
----                                 ------- ----------                                 ------------------
CommandLine                 String {ID, In, MappingStrings}
CurrentDirectory            String {ID, In, MappingStrings}
ProcessStartupInformation Instance {EmbeddedInstance, ID, In, MappingStrings}
ProcessId                   UInt32 {ID, MappingStrings, Out}

 

Using Invoke-CimMethod

PS> Invoke-CimMethod -ClassName Win32_Process -MethodName Create -Arguments @{CommandLine='notepad.exe'}

ProcessId ReturnValue PSComputerName
--------- ----------- --------------
     2648           0

 

Now trying New-CimInstance

PS> New-CimInstance -ClassName Win32_Process -Property @{Handle='0'; CommandLine='notepad.exe'} -Key Handle
New-CimInstance : Provider is not capable of the attempted operation
At line:1 char:1
+ New-CimInstance -ClassName Win32_Process -Property @{Handle='0'; Comm ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (Win32_Process (Handle = "0"):CimInstance) [New-CimInstance], CimException
    + FullyQualifiedErrorId : HRESULT 0x80041024,Microsoft.Management.Infrastructure.CimCmdlets.NewCimInstanceCommand

 

Other variants of not including the Handle property and changing the handle value all fail with same error

 

Botton line is that New-CimInstance is a bit of a mess to use – with or without the –Key parameter (which doesn’t seem to do much).

 

If the CIM class hasa create method Id recommend that you use that as a lot of CIm classes (or their providers) don’t work with New-cimInstance. In reality given that many of the CIM classes are effectively read only – you can’t create a new instance of Win32_ComputerSystem for example – it probably doesn’t matter.