Quantcast
Channel: CIM – PowerShell for Windows Admins
Viewing all 117 articles
Browse latest View live

PowerShell DSC for Linux

$
0
0

PowerShell DSC for Linux has moved out of CTP and v1 is available for download from http://www.microsoft.com/en-us/download/details.aspx?id=46919

You will find more details at http://blogs.msdn.com/b/powershell/archive/2015/05/06/powershell-dsc-for-linux-is-now-available.aspx

You will need to download OMI version 1.0.8-1 which is available from https://collaboration.opengroup.org/omi/documents.php?action=show&dcat=&gdid=32721

OMI has to be installed on the Linux box before the DSC package

A useful getting started guide is available https://technet.microsoft.com/en-us/library/mt126211.aspx

I demonstrated DSC for Linux at the recent PowerShell Summit NA 2015

https://www.youtube.com/watch?v=X5igUenOJiU&index=30&list=PLfeA8kIs7CochwcgX9zOWxh4IL3GoG05P

though things have changed a bit since I built that demo environment using the DSC for Linux CTP. I’m going to rebuild my Linux box with the new bits and give it a whirl.

Being able to manage Windows and Linux environments through the same techniques, and in some cases the same DSC configurations is a big step forward


Service startup type

$
0
0

Get-Service has been part of PowerShell since version 1. One thing it doesn’t do though is display the service startup type:

£> Get-Service | select -f 1 | fl *
Name                : 7f11b722
RequiredServices    : {}
CanPauseAndContinue : False
CanShutdown         : False
CanStop             : True
DisplayName         : AppendRunner
DependentServices   : {}
MachineName         : .
ServiceName         : 7f11b722
ServicesDependedOn  : {}
ServiceHandle       : SafeServiceHandle
Status              : Running
ServiceType         : Win32OwnProcess
Site                :
Container           :

You need to use the Win32_Service CIM class to get that information:

£> Get-CimInstance -ClassName Win32_Service -Filter “DisplayName = ‘AppendRunner'” | fl *
Name                    : 7f11b722
Status                  : Degraded
ExitCode                : 0
DesktopInteract         : False
ErrorControl            : Ignore
PathName                : “C:\windows\system32\rundll32.exe” “c:\Program Files
(x86)\AppendRunner\AppendRunner.dll”,serv
ServiceType             : Own Process
StartMode               : Auto
Caption                 : AppendRunner
Description             :
InstallDate             :
CreationClassName       : Win32_Service
Started                 : True
SystemCreationClassName : Win32_ComputerSystem
SystemName              : RSSURFACEPRO2
AcceptPause             : False
AcceptStop              : True
DisplayName             : AppendRunner
ServiceSpecificExitCode : 0
StartName               : LocalSystem
State                   : Running
TagId                   : 0
CheckPoint              : 0
ProcessId               : 1568
WaitHint                : 0
PSComputerName          :
CimClass                : root/cimv2:Win32_Service
CimInstanceProperties   : {Caption, Description, InstallDate, Name…}
CimSystemProperties     : Microsoft.Management.Infrastructure.CimSystemProperties

 

If you want to see the startup type for all services

Get-CimInstance -ClassName Win32_Service | Format-Table Name, DisplayName, State, StartMode –AutoSize

If you wan to group by start mode:

£> Get-CimInstance -ClassName Win32_Service | sort StartMode | Format-Table Name, DisplayName, State, StartMode -GroupBy
StartMode –AutoSize

The sort is essential otherwise a new group will be generated every time the start mode changes

 

CIM filters

$
0
0

I was looking up Win32_SystemDriver on the MSDN site and noticed there was some PowerShell example code

Get-WmiObject -Class Win32_SystemDriver |
Where-Object -FilterScript {$_.State -eq “Running”} |
Where-Object -FilterScript {$_.StartMode -eq “Manual”} |
Format-Table -Property Name,DisplayName

A better way to write this would be:

Get-WmiObject -Class Win32_SystemDriver -Filter “State=’Running’ AND StartMode=’Manual'” | Format-Table -Property Name, DisplayName –AutoSize

or

Get-CimInstance -ClassName Win32_SystemDriver -Filter “State=’Running’ AND StartMode=’Manual'” | Format-Table -Property Name, DisplayName -AutoSize

Do the filtering in the CIM call – especially if you’re running this against a number of remote machines. That way you limit the network traffic you’re returning

WMI dates

$
0
0

Dates as reported by WMI still seem to cause a lot of problems. If you use the WMI cmdlets

£> Get-WmiObject -Class Win32_OperatingSystem | select *date* | fl
InstallDate   : 20131205101649.000000+000
LocalDateTime : 20150728121320.002000+060

 

That format is year, month, day, hour, minute, second then fractions of a second after the decimal point with the final +nnn indicating an offset from Greenwich Mean Time  (UTC) for time zones and daylight saving time.

You can read the date presented by WMI but its not intuitive.

The PowerShell team added a ConvertToDateTime() to the object output by WMI so that you can easily perform date conversions

£> Get-WmiObject -Class Win32_OperatingSystem | select @{N=’Install'; E={$_.ConvertToDateTime($_.Installdate)}}, @{N=’Lo
calDate'; E={$_.ConvertToDateTime($_.LocalDateTime)}} | fl
Install   : 05/12/2013 10:16:49
LocalDate : 28/07/2015 12:16:26

 

Though my preferred solution these days is to use the CIM cmdlets as they convert the date for you without any extra effort

£> Get-CimInstance -ClassName Win32_OperatingSystem | select *date* | fl
InstallDate   : 05/12/2013 10:16:49
LocalDateTime : 28/07/2015 12:17:29

Win32_ReliabilityRecords Class

$
0
0

The Win32_ReliabilityRecords class was introduced with Windows 7. It contains information from the Windows Event Log related to system reliability.

The most interesting properties are the Message and the TimeGenerated

£> Get-WmiObject -class win32_reliabilityRecords | select -First 1 | fl Message, TimeGenerated
Message       : Installation Successful: Windows successfully installed the following update: Definition Update for  Windows Defender – KB2267602 (Definition 1.207.1367.0)
TimeGenerated : 20150929170914.620000-000

Notice the usual delightful date format on TimeGenerated

Easiest way to resolve this and get sensibly formatted date is to use the CIM cmdlets

£> Get-CimInstance -ClassName win32_reliabilityRecords | select -First 1 | fl Message, TimeGenerated
Message       : Installation Successful: Windows successfully installed the following update: Definition Update for  Windows Defender – KB2267602 (Definition 1.207.1367.0)
TimeGenerated : 29/09/2015 18:09:14

Now you have a date you can read easily.

NICs with IP addresses

$
0
0

A question on the forum asked about discovering those network adapters that had IP addresses configured. The user had tried

PS> Get-WmiObject -Class Win32_NetworkAdapterConfiguration -Filter “IPAddress IS NOT NULL”
Get-WmiObject : Invalid query “select * from Win32_NetworkAdapterConfiguration where IPAddress IS NOT NULL”
At line:1 char:1
+ Get-WmiObject -Class Win32_NetworkAdapterConfiguration -Filter “IPAdd …
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : InvalidArgument: (:) [Get-WmiObject], ManagementException
+ FullyQualifiedErrorId : GetWMIManagementException,Microsoft.PowerShell.Commands.GetWmiObjectCommand

Actually they’d tried the full WQL query. I don’t do that because its more typing than using the class name and a filter.

The problem is that IPAddress is a string array and WQL won’t let you query against an array of properties.

You have 2 choices

Get-WmiObject -Class Win32_NetworkAdapterConfiguration | where IPAddress

which is fine fro local machines but means you are filtering out results on the local machine when querying a remote machine – wasteful.

A better solution is to use the IPEnabled property. This is a boolean that is set to TRUE when an IP address (static or DHCP) has been set on a NIC. Your query then becomes

Get-WmiObject -Class Win32_NetworkAdapterConfiguration -Filter “IPEnabled = $true”

OR

Get-CimInstance -ClassName Win32_NetworkAdapterConfiguration -Filter “IPEnabled = $true”

WMI linked classes

$
0
0

You will find that many WMI classes have links – some are associations built in to WMI (a subject for another time) while other classes can be linked based on property values. An example of the latter is the Win32_NetworkAdapter and Win32_NetworkAdapterConfiguration classes. The DeviceId on Win32_NetworkAdapter  matches Index on Win32_NetworkAdapterConfiguration .

The follwoing function (adapted from a question on the forum) shows one way this link can be used

function Get-NetworkInfo{
[cmdletbinding()]
param( [string]$ComputerName )

$networkinfo = @()

$networks = Get-WmiObject Win32_Networkadapter -Filter ‘NetEnabled=True’ -ComputerName $ComputerName

$adapter = 0
foreach($network in $networks){

$id = $network.DeviceId

$IPinfo = Get-WmiObject win32_networkadapterconfiguration -Filter “Index = $id” -ComputerName $ComputerName
$winServers = 0
$winServers = ($IPinfo.WinsPrimaryServer -join ‘,’),($IPinfo.WinsSecondaryServer -join ‘,’)

$adapter += 1

$props = @{
‘Adapter’ = $adapter;
‘Manufacturer’ = $network.Manufacturer;
‘Description’ = $network.Description;
‘Connection’ = $network.NetConnectionID;
‘SpeedGB’ = [math]::Round($network.Speed / 1GB, 2)
‘IPAddress’ = $IPinfo.IPAddress -join ‘,’
‘Submask’ = $IPinfo.IPSubnet -join ‘,’
‘Gateway’ = $IPinfo.DefaultIPGateway -join ‘,’
‘DNSServers’ = $IPinfo.DnsServerSearchOrder-join ‘,’
‘WinServers’ = $winServers -join ‘,’
‘DomainSuffixes’ = $IPinfo.DNSDomainSuffixSearchOrder -join ‘,’
}

$networkinfo += New-Object -TypeName psobject -Property $props
}
$networkinfo
}
Get-NetworkInfo -ComputerName $env:COMPUTERNAME

WMI wildcards and filtering

$
0
0

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


Creating Registry Key

$
0
0

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.

New-CimInstance cmdlet and the–Key parameter

$
0
0

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.

 

The post New-CimInstance cmdlet and the–Key parameter appeared first on PowerShell for Windows Admins.

BinaryMiLog cmdlets

$
0
0

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

The post BinaryMiLog cmdlets appeared first on PowerShell for Windows Admins.

WMI discovery

$
0
0

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.

The post WMI discovery appeared first on PowerShell for Windows Admins.

CDXML filter parameters

$
0
0

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 CDXML – even if you never create a CDXML module – because 2/3 of the cmdlets in Windows Server 2012 and later are created this way.

The post CDXML filter parameters appeared first on PowerShell for Windows Admins.

Scripting Game puzzle –– January 2016

$
0
0

Here’s how I’d solve the puzzle

function get-starttime {
[CmdletBinding()]
param(
[parameter(
ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true)]
[Alias(‘CN’, ‘Computer’)]
[ValidateNotNullOrEmpty()]
[string[]]$computername = $env:COMPUTERNAME
)

PROCESS {

foreach ($computer in $computername){
$props = [ordered]@{
ComputerName = $computer
StartTime = ”
‘UpTime (Days)’ = 0.0
Status = ‘OFFLINE’
}

if (Test-WSMan -ComputerName $computer -ErrorAction SilentlyContinue) {
$lbt = Get-CimInstance -ClassName Win32_OperatingSystem -ComputerName $computer -ErrorAction SilentlyContinue

if ($lbt) {

$props[‘StartTime’] = $lbt.LastBootUpTime

$upt = [math]::round(((Get-Date) – $lbt.LastBootUpTime).TotalDays, 1)
$props[‘UpTime (Days)’] = $upt

$props[‘Status’] = ‘OK’
}
else {
$props[‘Status’] = ‘ERROR’
}

} ## endif

New-Object -TypeName PSObject -Property $props

} ## end foreach

} ## end PROCESS
}

Create an advanced function. Yes I know I’ve used lower case for the function name. I always do to visually separate my code from cmdlets and other functions.

Use the [parameter] decorator to enable pipeline input. Only a single parameter so don’t need to bother woth positional parameters. Function is supposed to default to local machien so can’t make parameter mandatory.

Requirement to process multiple computers at once presumably means the computername parameter has to take an array – sumultaneous processing implies a work flow which negates the initial requirement to create a function

Use the PROCESS block to run a foreach loop that iterates over the collection of computernames.

Create a hash table for the results – I’ve used an ordered hash table to preserve the property order. Set the values to a failed connection.

use Test-Wsman to see if can reach the computer. If can’t the output object is created. If you can reach the machine then run Get-CimInstance – preferred over Get-WmiObject because it returns the date ready formatted

Assuming that works set the start time and status properties. Calculate the uptime in days. I’d prefer to see  just an integer here – tenths of days doesn’t mean anything to most people

If the call to Get-CimInstance  fails then set the status to ERROR

Output the object.

The requirement to add a proeprty for patching is not clear but I’m assuming it means if the machine has been up for more than 30 days with the 1/10 month as a typo

if you want to add that then

Add a property

MightNeedPatching = $false

to the hash table when you create it

and add this line

if ($upt -ge 30){$props[‘MightNeedPatching’] = $true}

after

$upt = [math]::round(((Get-Date) – $lbt.LastBootUpTime).TotalDays, 1)
$props[‘UpTime (Days)’] = $upt

The post Scripting Game puzzle – – January 2016 appeared first on PowerShell for Windows Admins.

IP Default Gateways

$
0
0

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

The post IP Default Gateways appeared first on PowerShell for Windows Admins.


Breaking CIM sessions

$
0
0

A CIM session is analogous to a PowerShell remoting session but for CIM based cmdlets – the CIM cmdlets themselves and any CDXML based cmdlets e.g. the networking cmdlets

By default a CIM session uses WSMAN as its transport protocol – the same as remoting. You do have the choice to create a CIM session using DCOM for transport (same as the WMI cmdlets use)

I’ve always maintained that DCOM based sessions could be broken if the remote machine was re-started. This was based on the testing I did when writing PowerShell and WMI.

Some recent information cast doubt on that assertion though.  I’ve digging into CIM sessions recently and have what I think is a definitive statement on DCOM based CIM sessions.

If you create a DCOM based CIM session to a machine running PowerShell 2.0 from a machine running PowerShell 3.0 (or PowerShell 4.0 – I haven’t tested recently but remember doing this when writing the CIM section of PowerShell in Depth) access the remote machine and then restart and attempt to use the session – it will break like this:

$dopt = New-CimSessionOption -Protocol Dcom
$dcs = New-CimSession -ComputerName W8R2STD01 -SessionOption $dopt
Get-CimInstance -ClassName Win32_OperatingSystem -CimSession $dcs

SystemDirectory   Organization     BuildNumber      RegisteredUser   SerialNumber     Version          PSComputerName
—————   ————     ———–      ————–   ————     ——-          ————–
C:\Windows\sys…                  7601             Windows User     00477-179-000… 6.1.7601         W8R2STD01
Restart-Computer -ComputerName W8R2STD01
Get-CimInstance -ClassName Win32_OperatingSystem -CimSession $dcs
Get-CimInstance : Access is denied.
At line:1 char:1
+ Get-CimInstance -ClassName Win32_OperatingSystem -CimSession $dcs
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : PermissionDenied: (root\cimv2:Win32_OperatingSystem:String) [Get-CimInstance], CimExcept
ion
+ FullyQualifiedErrorId : HRESULT 0x80070005,Microsoft.Management.Infrastructure.CimCmdlets.GetCimInstanceCommand
+ PSComputerName        : W8R2STD01

The CIM session will usually become usable again after a period of time.

If you repeat the experiment using WSMAN or DCOM sessions to machines running PowerShell 3.0 or above the command to use the session is effectively paused until the session is responsive – this can take a little time

A machine running PowerShell 5.0 RTM can create a CIM session to PowerShell 2.0 (DCOM)  or later (DCOM or WSMAN) and the command is effectively paused until the remote machine is up.

The only time I can see the need to use a DCOM based CIM session is to access a PowerShell 2.0 machine – under any other circumstances I’d recommend using the default WSMAN based sessions.

Bottom line is that DCOM based sessions can be broken under specific circumstances that hopefully with time will disappear.

The post Breaking CIM sessions appeared first on PowerShell for Windows Admins.

IIS 6.0 server information

$
0
0

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

The post IIS 6.0 server information appeared first on PowerShell for Windows Admins.

IIS information

$
0
0

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

The post IIS information appeared first on PowerShell for Windows Admins.

Monitor Info

$
0
0

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

The post Monitor Info appeared first on PowerShell for Windows Admins.

Folder creation dates from WMI

$
0
0

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.

 

The post Folder creation dates from WMI appeared first on PowerShell for Windows Admins.

Viewing all 117 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>