PowerShell for Windows Admins


April 25, 2016  8:33 AM

Cim session oddity

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

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

April 14, 2016  8:27 AM

Folder creation dates from WMI

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
CIM, Powershell, 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.


April 14, 2016  4:50 AM

PowerShell Summit 2016 recordings

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
Powershell

The recordings from this years PowerShell Summit are now available:

http://powershell.org/wp/2016/04/13/powershell-devops-global-summit-videos-online/

https://www.youtube.com/playlist?list=PLfeA8kIs7Coc1Jn5hC4e_XgbFUaS5jY2i


April 13, 2016  3:49 AM

IT Ops Education program and Scholarship

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
DevOps, IT education, Powershell

Do you know a young person in the USA that is just starting their IT career and would benefit from an intensive training program and scholarship?

Point them to the DevOps Collective site (DevOps Collective is the parent organization for powershell.org)  https://devopscollective.org/2016/04/04/announcing-the-getgoing-it-ops-education-program-scholarship/

Initially this program is US only but we hope to make a global program in years to come


April 12, 2016  3:33 PM

Monitor Info

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

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


April 4, 2016  7:28 AM

PowerShell Summit: CIM Deep Dive

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
Powershell, Windows 10

A big thank you to everyone who attended my Summit pre-conference workshop. The interaction was great and I really enjoyed it even though I was feeling the efffects of my flight the previous day.

One thing we discovered was that good old dependable calc has changed. On a Windows 10 (build 14295 and last couple of builds) its now calculator.exe.

PS> Get-CimInstance -ClassName Win32_Process -Filter “Name LIKE ‘calc%'”

ProcessId Name           HandleCount WorkingSetSize VirtualSize
——— —-           ———– ————– ———–
1400      Calculator.exe 373         56770560       336953344

On Windows 2012 r2 its still calc.exe which caused a bit of confusion until we realised what was happening


April 1, 2016  8:53 AM

MVP renewal 2016

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
Powershell

Its April first and the email arrives mid-afternoon. My MVP award has been renewed for another year (9th consecutive year)

I still really appreciate the recognition this award bestows and hope to keep working to make the PowerShell community even better in the next 12 months


March 31, 2016  1:01 PM

IIS information

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

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


March 31, 2016  11:21 AM

European PowerShell Conference 2016–few places left

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
Powershell

There are still a few places left at the European PowerShell conference next month – http://www.psconf.eu/

There’s a terrific line up of speakers and I really recommend you get there if you can


March 30, 2016  10:44 AM

IIS 6.0 server information

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

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


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: