Friday, February 7, 2014

Powershell 2.0

Warnings And Alerts
I've put this at the top- of the post so you see it first. Please continue reading but have a look at the alerts in case it impacts anything you are doing.





Start of the post

A Good Place to Start
Is with the Microsoft's own Hey Scripting Guy Blog I can find him annoying when he talks Bravo Sierra about what he is doing, but try and see past that and get to the relevant info. To be fair he has written some good books that are available for Kindle as well as hardback versions. There should be a VBScript blog in there too somewhere I'll check that out later as I'm always arguing with my mate as he is VBScript and I'm Powershell...hey ho pick a side, tribe or clan and fight to the death!!

Windows Powershell Script Centre

Windows Powershell Owners Manual
Use the above manual to set quick edit mode and configure the memory buffers on the X & Y axis so you have enough columns and rows to scroll through large retrievals to the shell.


Forums & URLs

sapien.com/forums     Sapien self paced training   Primal Script
Powershell.org
Concentratedtech.com

Win32 Classes pay attention you'll be using tonnes of queries based on these.



Hardware - Query USB Devices

 gwmi Win32_USBControllerDevice |%{[wmi]($_.Dependent)} | Sort Description,DeviceID | ft manufacturer,Description,DeviceID -auto

Printer Shares- Query print servers

get-wmiobject -class win32_printer | select name,portname,shared,sharename

Windows Management Instrumentation
Why am I putting a large section in this post for WMI? I hear you say...the answer is really quite simple. The most commonly used piece of powershell that I have used...in my experience anyway is......

Get-WMIObject -class Win32_selectaclass <set parameters and output options>

Also if you look back to powershell basics, the shell provides an object orientated C# shell. Which means that if you are not using CMDLETS you can use C# and VBScript and you can certainly use the POWERSHELL INTEGRATED SOFTWARE ENVIRONMENT to do this. I have also developed powershell scripts with a C++ er and that all just worked nicely too. Now if you think of GPOs in AD....a Powershell script may not be directly executable but can be called from a VBScript....also some of the WMI queries that are used in the book I was reading can also be directly scripted with WSH on GPO in AD....so it's pretty important to understand the capabilities of the Powershell shell and the ISE too. So there you go...and I hope you have some fun....just extends some capabilities that I never thought of when I started reading a few tech books and suddenly the stars aligned.....

Good link from Mcrosoft regarding command line WMI
MS-WMI

WMI = Microsoft's implementation Web Based Enterprise Management (WBEM) Protocol.

Industry initiative for standardized technology for accessing management information in an enterprise environment. WMI uses the Common Information Model (CIM) industry standard to represent systems,applications,networks,devices and other managed components. CIM is developed and maintained by the Distributed Management Task Force (DMTF). We can run WMI scripts in Powershell on local or remote resources!! So full automation can be achieved with Powershell and WMI!!!

Powershell CMDlets that can use WMI management data can be found with the following command


get-command -noun wmi*


should return something like this


CommandType     Name                                                Definition

-----------     ----                                                ----------
Cmdlet          Get-WmiObject                                       Get-WmiObject [-Class] <String> [[-Property] <St...
Cmdlet          Invoke-WmiMethod                                    Invoke-WmiMethod [-Class] <String> [-Name] <Stri...
Cmdlet          Register-WmiEvent                                   Register-WmiEvent [-Class] <String> [[-SourceIde...
Cmdlet          Remove-WmiObject                                    Remove-WmiObject [-Class] <String> [-AsJob] [-Im...

Cmdlet          Set-WmiInstance                                     Set-WmiInstance [-Class] <String> [[-Arguments] ...


WMI Query Language 

Notes from this book WMI-Query-Language-via-PowerShell-Kindle

Yes WMI has it's own query language and can be faster than traditional Powershell queries. WQL is a subset of the American National Standards Institute Structured Query Language aka ANSI SQL or SQL. There are some symantec differences but WQL has a set  of keywords & operators and supports three types of queries

DATA

Simple/Common form of querying WMI data. Data Queries, used in retrieval class instances and data associations. 

get-wmiobject -class win32_product (example of a data query)


WQL keywords, select,associators of,references of, and ISA all used in data queries.



EVENT
Used to create WMI event subscriptions, such as create an event subscription when a USB device is connected. The WQL keywords Group, Having and Within are used when creating event queries

SCHEMA 
Used to retrieve class definitions and schema associations. They get information about WMI and it's structure. Schema queries return a result set of class definition objects rather than instances of classes. WQL keywords Select, Associations Of, and ISA are used when creating schema queries.

Microsoft WQL keywords
Ravi Chaganti WQL Keywords

WBEMTEST

Handy wee util wbemtest.exe just run from the CLI or Run command field.

Technet WBEMtest.exe

The root name space that WBEMtest connects to sounds pretty strange at first. Root\cimV2 the way I'm thinking about it is ROOT of the Common Information Management Version 2 name space. Where ROOT is the top level like a Root Folder in Unix...as if that makes any sense???? Right !!!

WMI Administrative Tools
WMI CIM Studio (NB can be used to execute data/schema queries. WMI Tools do not support WMI event query execution)
WMI Object Browser
WMI Event Registration
WMI Event Viewer

Download WMI Admin Tools  I use the CHROME browser, The WMI CIM Studio uses Internet Explorer so just copy and paste the address in to IE and you should be fine.

Address for CIM Studio = C:\Program Files\WMI Tools\studio.htm
You may have to allow blocked content.



A couple of Simple Queries
By launching wbemtest.exe from the run command or CLI....click the Connect button 




The QUERY button can be used for WMI data and schema queries and the Notification Query button used for WMI event queries

 Test query select * from win32_process

Should result in (it will fail if there are typos!!)


Which are processes from your PC currently running

Using the same test query but this time with CIM Stucio!!!
Make sure you are using Internet Explorer!!


Press the WQL Queries button (first row of buttons above the output columns, move the cursor until the button bubble shows WQL QUERIES and click the button)
everything in BLUE in the above screenshot is an active process....SO same query same result different WMI tool used!! YYYYYeeee HHHAAA

TYPE ACCELERATORS
AAAHHH now something really does become clear...always wondered why things were in square brackets....they are accelerators

Powershell provides shortcuts to allow direct access to .NET namespaces. THESE are Type Accelerators the WMI Namespace has three!!!

[WMI] retrieves single instance of a WMI class
[WMICLASS] accesses static properties and methods of a WMI class.
[WMISEARCHER] search for WMI objects

ALL of the above can be piped through the get-member command...this give you the members of theses accelerators see Using get-member

[wmisearcher] | get-member
[wmi] | get-member
[wmiclass] | get-member

So give it a try....

[WMISEARCHER] = Shortcut -> System.Management.ManagementObjectSearcher.NET

So how the heck do we use this? Looking at the book, it looks like we have to store information in a variable then execute actions on the variable so open Powershell and try this.

$svcs = [wmisearcher]"select * from win32_service where state='running'"

$svcs.get()

should return a rather large list of running services on the Server/PC, so make sure your shell session has the buffer setting increased for horizontal and vertical output, or redirect the output to a text file.

So what have I done here? $svcs is an array variable that will hold the query from [wmisearcher]"select * from win32_service where state='running'"
This query will return services that are in a "runnung" state

Kinda see it as two sides

set variable = command string to execute query

So now we have information in a variable we done it all through WQL how the hell do we get the useful stuff?

$svcs.get()

The .get() is interesting if you run this command without the () you return very little useful information it's almost like the command string says execute information retrieval and group it together so it makes sense. I've tried to figure this out to explain it easier, instead I've found this from the WMI & WQL The Scripting Guy not had time to read it all either for myself!! So anyway play around for yourself and get comfy with the Powershell Shell.


Changing Scope???
according to the book these commands

$objsearch = [wmisearcher]"select * from MSPower_DeviceEnable"
$objsearch.Scope = "rootWMI"
$objsearch.get()

should change the SCOPE of the default name space which is Rootcimv2.
 In first line your are storing a query, like before, in a variable.
In the second line you are using the SCOPE method to switch from the default name space, stored in the variable $objsearch to rootWMI.
In the third line you are using the .get() method to retrieve and group the results stored in the variable $objsearch...that is the way this layman is taking it....anyhoo it never worked on my PC even when I ran the shell as administrator....so give it a try, see if it works for you!!
And now you see how quickly WQL becomes verbose and puts you at risk of huge typos.

Here is another section of code to try, again from the book and again no worky on my Win7 PC.
Proves the point for the need of powershell commandlets though

register-wmievent -query "select * from _InstanceCreationEvent within 10 where targetinstance ISA 'win32_process'" -action {write-host "new process created"}

Read on to see why the above is no worky!!!

every time a new process is started the phrase new process created should pop up on the powershell shell....from now on Powershell = PoSh

Other tools for querying WMI are....
Sapien WMIExplorer 
Codeplex WMIExplorer
Lo4d.com WMIexplorer
SolarWunds WMImonitor

WMI Data Queries
Used to retrieve class instances and associations. Several keywords and operators are used in WMI queries. Select, From, Where, Associators of, References of, NOT, LIKE, Is, Null, to give just a few.

Select,from,where
General syntax

SELECT [* | PROPERTY NAMES] FROM ClassName

How to use? want to retrieve all the Win32_service class and properties

$query = "select * from win32_service"
get-wmiobject -query $query

and that brings back shed loads of information, all the instances and properties of win32_service!!

NB you can only execute queries on one class at a time

We can limit the instances to one particular service

$query = "select * from win32_service where name= 'audiosrv'"
get-wmiobject -query $query

returns

ExitCode  : 0
Name      : Audiosrv
ProcessId : 944
StartMode : Auto
State     : Running

Status    : OK

So WHERE narrows the scope of the data retrieved. This can be used in all three query types.
Generally when using SELECT and WHERE there are two forms

SELECT * FROM class WHERE property operator constant
or
SELECT * FROM class WHERE constant operator property

property = denotes a valid property of a WMI instance
operator = any valid WQL operator
constant = must be correct type for the property


WHERE = a CLAUSE see also Querying with WQL

Lets replace the
To see what happens when this is entered

$query = "select name, state from win32_service where 'audiosrv' like name"
get-wmiobject -query $query

Resulktant output 

__GENUS          : 2
__CLASS          : Win32_Service
__SUPERCLASS     :
__DYNASTY        :
__RELPATH        : Win32_Service.Name="Audiosrv"
__PROPERTY_COUNT : 2
__DERIVATION     : {}
__SERVER         :
__NAMESPACE      :
__PATH           :
Name             : Audiosrv
State            : Running

We now used name and state and this limits the number of properties returned to output. Also by using  where 'audiosrv' like name gives an instance of a win32_service with a name "Audiosrv" and lists only the name and state properties for that services..so...we are pairing down the info using more accuracy from WQL and PoSh. In the case of remote query execution we reduced the bandwidth and the amount of data to return so something else to think on!!

LIKE Operator

By using the LIKE we can search or query things we dont have the exact name for.

$query = "select * from win32_service where name like '%audio%'"
get-wmiobject -query $query

Pay attention to the %audio%. Since DOS the Asterisk * has been the wildcard character, in WQL because it's a subset of SQL the Wildcard is %

$query = "select * from win32_service where name like '[af]%'"
get-wmiobject -query $query

[af]% gives us a query that retrieves services that start with an a or a f 
The way the brackets [ ] are used is similar to Regular Expressions,used to define a range of characters..... so before moving on here is a link to some RegEX stuff , regular-expressions.info and Posix-Wikipedia

Here is another example and this time we are setting a range using [a=f]%

$query = "select * from win32_service where name like '[a=f]%'"
get-wmiobject -query $query

The result is a  RANGE from A through to F of services. So anything starting with A B C D E F is retrieved, the % is again the wildcard and retrieves the remaining string characters in the name that start with the range A through to F. NB [a-f]% can also be used to set a range MSDN documentation only specifies the = but - can also be used. Under my testing though each returns different results. The'[a=f]%'" produces a shorter output than '[a-f]%'". So play with it I guess I stopped and started shell sessions so that variables were new, still get different output.

NB Powershell recovers OBJECTS. Not just lines of text, these objects have lots and lots of attributes and methods.

$query = "select * from win32_service where name like '[^afgh]%'"
get-wmiobject -query $query

[^afgh]% so this means do NOT return service starting with A F G H

$query = "select * from win32_service where name like '%a_diosrv%'"
get-wmiobject -query $query

%a_diosrv% and this means that _ one character is matched in the position the _ is used in during the query and therfore it can be moved about!!! so play with it. The wildcard % is there to complete the retrieval of all the services that match the string segment you are querying on.

AND OR NOT operators are used for testing multiple conditions inside a WHERE clause.

$query = "select * from win32_service where state='running' and startmode='manual'"


get-wmiobject -query $query

Here we have queried for services that are in a 'running' state with the startmode set to 'manual' so the AND tests for both conditions to be TRUE!
This can be combined with the [af]% query we were using earlier.

$query = "select * from win32_service where (state='running') and (startmode='manual') and (name like '[af]%')"

get-wmiobject -query $query

Using parentheses is good practice and becomes necessary. 

Using OR we query for information whenever ONE or MORE conditions are TRUE.

$query = "select * from win32_service where (state='stopped') or (state='paused')"
get-wmiobject -query $query 

So we have retrieved all the services from Win32_Service that is either STOPPED or PAUSED.

Again we can combine this query with the [af]% 

$query = "select * from win32_service where (state='stopped') or (state='paused') and (name like '[af]%')"

get-wmiobject -query $query

Now....this where things went a bit weird because I noticed this query gave me results with names of services outside the range....I changed the order to

$query = "select * from win32_service where name like '[af]%' and state='running' or state='paused'"

get-wmiobject -query $query

I think I got more accurate results and no, no parentheses used but I got the same results with this query

$query = "select * from win32_service where (name like '[af]%') and (state='running') or (state='paused')"

get-wmiobject -query $query

So kind of thinking that position is important...I'll just keep working through the book and taking my notes....AAANNNDDD surprise surprise the book explains these results...OR is just enough to evaluate any one condition to TRUE. When it hit a true condition it just returned those true results. We fix that by using PARENTHESES.

$query = "select * from win32_service where (state='stopped' or state='paused') and name like '[af]%'"
get-wmiobject -query $query 

I guess if using OR stick the conditions you are testing for in parentheses all time and make that a rule!!

To be OR NOT to be....that is the question....

Now using NOT we can run a query like this....

$query = "select * from win32_service where not (state='running')"
get-wmiobject -query $query 

No need for any explanations I suppose??? Alternatives....

$query = "select * from win32_service where (state<>'running')"

$query = "select * from win32_service where (state!='running')"

NB <> and != are alternative methods to use NOT.


IS,,,,IS Not are another two operators that can be used.

$query = "select * from win32_logicaldisk where filesystem is null"

get-wmiobject -query $query

The above query is only valid with the constant NULL It also brings back the DVD player object.

NB sometimes the properties of WMI classes may not be displayed, so use the pipe command with Format-List (can be abbreviated to fl) appended to the query | format-list * (astrix is the wildcard, brings back all the properties).

$query = "select * from win32_logicaldisk where drivetype is 5"

The above query brings back an invalid query since the constant is not NULL.

If we use 

$query = "select * from win32_logicaldisk where filesystem is not null"

We get a listing of all the local disks.....thanks to using IS NOT

SELECT queries are used to retrieve instances of a WMI class.
SELECT queries are not the only way to retrieve instances of a WMI class.
SELECT queries always return a collection of instances of a WMI class.

ASSOCIATORS OF keyword can do the same. The difference is ASSOCIATORS OF returns a collection of WMI objects that belong to different WMI classes or associated WMI Classes.

Things are going to get trippy here because the book example does not match my work PC and indeed on my home PC CIM Studio just will not work as intended, methinks there are OS variations at play here.

Start CIM Studio, the book advises connect root\cimv2, then click on win32_service , my PC does not have this in root\cimv2, I just found an instance of it under cim_service.







In the top picture we have the WMI Root tree and in the second picture we have the ASSOCIATIONS tab. So if you move your mouse over the grey squares inside the red lined rectangle you will see WMI Class names pop up.




Excuse my freehand editing...been a long time with out using PAINT!!! As I've said before the book does not match my PC so I'm making assumptions here...I'll need to get an old XP up see what CIM Studio displays.....the book uses the following as a query sample

$query = "associators of {win32_service.name='netlogon'}"

This will bring back all associated class instances!!!!!

Notice the use of {}  brackets, they are part of the syntax {objectpath} to match the book I used their example and got these results...

Domain              : Company.Domain.uk
Manufacturer        : Hewlett-Packard
Model               : HP Compaq Elite 8300 USDT
Name                : MyPCHostName
PrimaryOwnerName    : Authorised User
TotalPhysicalMemory : 3644895232

ExitCode  : 0
Name      : LanmanWorkstation
ProcessId : 1328
StartMode : Auto
State     : Running
Status    : OK

GroupOrder : 64

Name       : MS_WindowsRemoteValidation

If the object path is just 


$query = "associators of {win32_service}"

Then nothing is returned, we need to have 

{win32_service.name= 'servicename'}

with a valid service name for the query to work.

It's confusing stuff and I've said before...need to get an old XP box fired up to see if that matches the book. Anyhoo, things to remember here are 

One Source Class = Win32_service name
gets split 3 ways and passed to associate WMI Classes
end up at the END POINT classes
All of which can be queried...the whole point!!


Notice the KEY symbol...by looking at the properties tab in CIM Studio, this uniquely IDs the WMI instance.

Playing around, I typed in this command 

get-wmiobject -class Win32_service | fl -property name

this lists all the Win32_service names, I picked WebClient and ran the following

$query = "associators of {win32_service.name='WebClient'}"
get-wmiobject -query $query

gave this output

Domain              : WORKGROUP
Manufacturer        : TOSHIBA
Model               : Satellite L650
Name                : PHOENIX
PrimaryOwnerName    : John
TotalPhysicalMemory : 4083007488

DisplayName : WebDav Client Redirector Driver
Name        : MRxDAV
State       : Stopped
Status      : OK
Started     : False

GroupOrder : 65
Name       : NetworkProvider

for extra info try this

 get-wmiobject -query $query | format-list *

NB Get-wmiobject and the format-list cmdlets can be abbreviated to

Get-Wmiobject = gwmi
Format-list = fl

SSSSOOOOO after a lot of flaffing about you can find the associate classes that are used during a WQL/WMI query. IF you look at my section Powershell screen dumps/results it will show you commands to retrieve all the service names in Win7. I needed a list so I could have a service name to query, so look at Win7 Service Names. Now that we have discovered this Source->Associate Classes->End Point combination I thought I would play and see what query would give that type of result, so look at the advanced query testing page see the results, and how I got there. It will save room on this page.

NB the query

 gwmi -query $query | fl __class,path

The __class property has actually two underscore characters and the result from this query will show the class, the class will also be named in the Root\cimV2 path.


Associator of keyword can also use the where clause for data queries. The usage of the where clause is different when compared to the select keyword queries. There are predefined keywords that you can use with the where clause

ASSOCIATORS OF {object path} WHERE

AssocClass = AssocClassNmae
ClassDefsOnly
RequiredAssocQualifier= QualifierName
RequiredQualifier= QualifierName
ResultClass= ClassName
ResultRole= PropertyName
Role= PropertyName


ASSOCIATORS OF cannot use the logical operators AND,NOT OR, within the WHERE clause. You can use multiple keywords using a space as a separator.



ClassDefsOnly

$query = "associators of {win32_service.name='netlogon'} where classdefsonly"

gwmi -query $query

For a screen output have a look at the ClassDefsOnly page in the Powershell Screen Dumps/Results section at the foot of the blog...double click the pic to enlarge. ClassDefsOnly = Associated Class Names that should be viewable from CIM STUDIO but as previously stated my Book and PC do not match.

AssocClass

$query = "associators of {win32_service.name='netlogon'} where assocclass=win32_dependentservice"

gwmi -query $query

For a screen output have a look at the AssocClass page in the Powershell Screen Dumps/Results section at the foot of the blog...double click the pic to enlarge. AssocClass= End Point associated with the Source through the specified class or one of the derived classes. This query gets the endpoint which is associated through Win32_DependentService association class.

ResultClass

$query = "associators of {win32_service.name='netlogon'} where resultclass=win32_loadordergroup"

gwmi -query $query

For a screen output have a look at the ResultClass page in the Powershell Screen Dumps/Results section at the foot of the blog. Surprisingly, I never got a return, I had to use 
gwmi -query $query | fl * to get an actual screen output, anyway according to the book this will retrieve End Points associated ONLY with a specified ResultClass.

ResultRole

$query = "associators of {win32_service.name='lanmanworkstation'} where resultrole=dependent"

gwmi -query $query | fl *

For a screen output have a look at the ResultRole page in the Powershell Screen Dumps/Results section at the foot of the blog. I played with the output as you can see.

ResultRole retrieves endpoints that must play a particular role in their association with the source object. So if the get-service cmdlet did not exist we can still query services  by using a similar query. See below screen output, and you get more information by using Fomat-List * 
Essentially the query is returning services that depend on the LanmanWorkstation service.

ExitCode  : 0
Name      : Browser
ProcessId : 1076
StartMode : Manual
State     : Running
Status    : OK

ExitCode  : 0
Name      : Netlogon
ProcessId : 660
StartMode : Auto
State     : Running
Status    : OK

ExitCode  : 0
Name      : SessionEnv
ProcessId : 1076
StartMode : Manual
State     : Running

Status    : OK

So try this...

get-service -name "lanmanworkstation" -dependentservices

Have a look at the bottom of the ResultRole results page...bet it matches??!!

To get a list of services that a specific service depends on....

$query = "associators of {win32_service.name='netlogon'} where resultrole=antecedent"

gwmi -query $query | fl *

Should give you 

ExitCode  : 0
Name      : LanmanWorkstation
ProcessId : 1328
StartMode : Auto
State     : Running
Status    : OK

LanmanWorkstation is listed as a service needed for the  NetLogon service to start and we can check this by

get-service -name "netlogon" -requiredservices

with the below screen output.

Status              Name               DisplayName
------                    ----                        -----------

Running  LanmanWorkstation  Workstation

WMI Relationships

Relationships   =   Dependency                             DEC
                             =   Element Setting
                             =   Component

Dependency.......one object is dependent on another object = antecedent 
see the definition antecedent 

The association class "win32_dependentservice"  defines a dependency relationship between two windows services win32_service.name='netlogon' is dependent on win32_service.name='lanmanworkstation" which is the antecedent.

The book states that the Win32_DiskDrive is another example of how to find a dependency relationship, since a partition is dependent on a disk drive, so win32_diskdrive = antecedent role and win32_diskpartition = dependent role. By specifying one of the antcedent or dependent roles we can get either of the class instances win32_diskdrive or win32_diskpartition.

The book gives this example

$query = "ASSOCIATOR OF {Win32_DiskDrive.DeviceID='.PHYSICALDRIVE0'} WHERE ResultRole=Dependent"

It errored out on my PC, see the Win32_diskdrive results page in the Powershell screen Dumps/results section for the screen out.

I ran

gwmi -class win32_diskdrive | fl *

Again for the Win32_diskdrive results page you can see that the DeviceID is 

DeviceID                    : \\.\PHYSICALDRIVE0

So I changed the books query to 

$query = "ASSOCIATOR OF {Win32_DiskDrive.DeviceID='\\.\PHYSICALDRIVE0'} WHERE ResultRole=Dependent"

And it worked....

Element Setting Relationship

The Association between an element = NIC
The settings for the NIC

The association classes have proerties named ELEMENT and SETTING.

Using CIM Studio...find Win32_NetworkAdapterSetting association class and it will define the relation ship between 
Win32_NetworkAdapter (element)
Win32_NetworkAdapterConfiguration (setting)

The book and my PC go their separate ways again...
The book uses

$query = "ASSOCIATOR OF {Win32_NetworkAdapterConfiguration.Index=12} WHERE ResultRole=element"

It just never worked on my PC, so I tried listing the NIC indexes by using this


gwmi -class Win32_NetworkAdapter | fl -property index

And for the indexes listed, nothing worked as I rotated them in....so here is the CIM Studio output to give you something to look at!!






~~~~~~~~~~~~~~Side Line~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Here is an after thought.....so many discrepancies between my PCs and the book I thought I'd check the MSIexec...so from PoSh

msiexec /?

So I have Windows ® Installer. V 5.0.7601.17514 in the office.

How to give your Administrators group WMI access 
  1. Run compmgmt.msc
  2. Click Services & Applications
  3. Click WMI Control
  4. Right Click Properties
  5. Select Security tab
  6. Select Root
  7. Select Security button at the bottom
  8. Verify your username or group is allowed permission
So if you have got to here you may have had some errors too....well....here is the thing I do a load of typos!!!!!! Yes commands that the PC cannot understand....so... You figured it out yet?? Its ASSOCIATORS OF...NOT.......... ASSOCIATOR OF

So try these again

$query = "ASSOCIATORS OF {Win32_DiskDrive.DeviceID='\\.\PHYSICALDRIVE0'} WHERE ResultRole=Dependent"

$query = "ASSOCIATORS OF {Win32_NetworkAdapterConfiguration.Index=12} WHERE ResultRole=element"

Yes one wee typo can scupper ye...nuff said!!!!!!

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Component Relationship

Contains two or more classes as groupcomponent and partcomponent 
Using Win32_GroupUser WMI class associates Win32_Group = GroupComponent and Win32_Account = PartComponent classes. Win32_GroupUser defines a relationship between a group and a member user account.

And I'm gonna have to set up some test groups and accounts....so be back in a bit!!!

So I've created a test group and a couple test users

Group = Test1
Users = Test_User1, Test_User2

Typed in the following query

$query = "associators of {win32_account.name='Test_User1',domain='PCHostname'} where ResultRole=GroupComponent ResultClass=Win32_account"

gwmi -query $query

And I got the following Output

Caption                        Domain            Name       SID
-------                             ------                 ----          ---
PCHostname\Users    PCHostname    Users      S-1-5-32-545
PCHostname\Test1    PCHostname    Test1       S-1-5-21-237238598-2245275001-                                                                                            265878481-1000


So the query lists all the groups that Test_User1 a member of. The NAME and DOMAIN are used because if you look through CIM Studio (see the Win32_Account results page) you will see these are KEYS or KEY properties in the Win32_Account class, if one of those is missing or incorrect then that will generate an invalid ObjectPath error when the query is ran. The Domain property value can be a DOMAIN name or a LOCAL COMPUTER name.

The 

ResultClass=Win32_account

Should help in getting only the group details and should prevent computer info being displayed.

So IF we want all members in a GROUP........

$query = "associators of {win32_account.name='test1',domain='PCHostname'} where ResultRole=PartComponent ResultClass=Win32_Account"

gwmi -query $query

results in 

AccountType : 512
Caption          : PCHostname\Test_User1
Domain          : PCHostname
SID                : S-1-5-21-237238598-2245275001-265878481-1001
FullName       : Test User 1
Name             : Test_User1
I thought I would query the USERS local group as well just to see the result..and..

$query = "associators of {win32_account.name='users',domain='PCHostname'} where ResultRole=PartComponent ResultClass=Win32_Account"

gwmi -query $query

gets you 

Caption                                              Domain           Name
-------                                                  ------                 ----
PCHostname\INTERACTIVE            PCHostname  INTERACTIVE
PCHostname\Authenticated Users   PCHostname  Authenticated Users
DomainName\Domain Users            DomainName  Domain Users
PCHostname\Test_User1                 PCHostname  Test_User1
PCHostname\Test_User2                 PCHostname  Test_User2

According to the book that is WMI/WQL relationships covered!!!

ROLE

Means Returned endpoints play a part in the association with the source object where the source object has a particular role.

The difference between ROLE and RESULTROLE is the ENDPOINT must have a particular association with the source.....getting like the MATRIX take the blue pill go on I dare you!!

SO the ROLE is used when the SOURCE has a particular role to play and not the endpoints, well so much!!

So by recycling a previous query

$query = "associators of {win32_account.name='test1',domain='PCHostname'} where Role=GroupComponent ResultClass=Win32_account"

results in 

AccountType : 512
Caption          : PCHostname\Test_User1
Domain          : PCHostname
SID                : S-1-5-21-237238598-2245275001-265878481-1001
FullName       : Test User 1
Name             : Test_User1

Which is the same result. lists the users of the TEST1 local group.

Using Role=GroupComponent we queried for all instances of win32_account.name='test1'  <----- is a group name and Role=GroupComponent.

RequiredQualifier RequiredAssocQualifier

RequiredQaulifier = this keyword is for EndPoints (associated with a Source) and they have to include the specified qualifier.

RequiredAssocQualifier = Endpoints must be associated (with Source) through an association class that includes the specific qualifier.

WMI Qualifiers = value that provides additional information and are used to narrow the result of a WMI/WQL query. The information returned can be for, Class, Associations, Triggers, Instances, Properties, or References.

REFERENCES OF

Similar to ASSOCIATORS OF statement, this keyword retrieves all association instances that refer to a particular SOURCE. So keep in mind SOURCE->ASSOCIATION->ENDPOINT holy trinity (no blasphemy intended!!)

REFERENCES OF {objectpath} is the syntax.

So it's the bit in the middle of the sandwich we are after...the JAM if you will, or the ASSOCIATION CLASS.


NB Keep in mind ASSOCIATORS CLASS retrieves results from the ENDPOINT ONLY.
Hopefully this pic will help....excuse the bad use of Paint!!


So it gets trippy again......

REFERENCES OF = used to query  Association Classes
ASSOCIATORS OF = used to query EndPoints (Target) Classes 

I'll switch back to the book examples and some side by side comparisons....

Results are posted in the page  Source->Associator->Endpoint in the 

Powershell Screen Dumps/Results section.

So hopefully you see the difference and realise the different levels in WMI that are being queried. By using the classdefsonly keyword we have limited the output.

Similar to the ASSOCIATORS OF  the WHERE clause can be used the general syntax being

REFERENCES OF {ObjectPath} where ClassDefsOnly, RequiredQualifier=QualifierName,ResultClass-ClassName, Role=PropertyName

Usage of which is pretty much the same as ASSOCIATORS OF...........

Onwards and Upwards.....

WMI EVENT QUERIES

So WMI has classes that represent system resources. Each of these system resources can be managed by WMI. Same is true for a system EVENT...when something HAPPENS..When a monitorable event occurs an instance of the corresponding WMI event class is created = WMI EVENT.

Powershell has a cmdlet 

Register-WMIEvent 

Microsoft Receiving a WMI Event    Microsoft Monitoring Events

So how do we find the WMI Event Classes?

I have to have a chuckle here I could not get the query the author had working....then I realised the fullstop(period) character I was reading was a bit of gunk on my tablet screen...superb...keep a clean tablet screen when reading manuals!!!

Here is the code

gwmi -query "select * from meta_class where (__this isa '__event') and (__class like 'win32%')"

NB the __this, __event __class could be tricky as the __ is actually 2x _ (underscore) characters...

Have a look at the Getting WMI Event Classes page in the Powershell Screen Dumps/Results section.

Again carefull of typos I missed a "-" and this code failed...so this is an example straight from the book again

register-wmievent -class win32_processStartTrace -SourceIdentifier "Process Started" -Action { Write-Host"$($event.SorceEventArgs.NewEvent.ProcessName) Just Started"}

Cut and paste it as I know it works.............. you'll get something like this 



NB The -Action parameter can be used to specify a scriptblock used to take some action when the event is triggered. You have to RUN PoSh as ADMINISTRATOR or ELEVATED MODE or you will get an access denied message when using Register-WMIEvent

So the command will apparently register an event consumer and display a message with the freshly started process name. It will result in process start messages...all the time. We can filter out unwanted processes before displaying anything to the shell and we should be able to use -Query parameter for the events we are interested in.

Run this.....

 register-wmievent -query "select * from Win32_ProcessStartTrace where processname='notepad.exe'" -action {write-host "newnotepad process created"}

You should get something like


I started a new notepad session and......got this


NOTICE the typo...LOL...point proved though a fresh launch of notepad.exe kicked off a write-host to the shell's output file. So there ya go!!

So we can list WMI event classes and we can use Register-WMIEvent to subscribe to the events from a WMI class.

The WMI Event Class provides events. We can use this to create a subscriber.

For Non-Event classes WMI does all the monitoring of the class instances and provisioning of creations,deletions and mods. So we need to subscribe to NON-Event classes....in other words Event Queries!

Event Query Types

There are three (another Holy Trinity!!??)

Intrinsic, Extrinsic and Timer

Intrinsic Events

Monitor a resource represented by a class in the CIM (Common Information Model) Repository.  Intrinsic Events occur in the response to change in the STANDARD WMI data model. So WMI creates Intrinsic Events for objects stored in the WMI Repository. A provider generates Intrinsic Events for dynamic classes but WMI can create an instance for a dynamic class if no provider is available. Having a WMI provider is not mandatory. Intrinsic Events are mostly defined within the standard WMI Model and WMI can handle Intrinsic events if they have no provider for a given resource within the standard WMI model.

WMI uses polling to detect change.
There are tonnes of WMI classes that are used to report intrinsic events.The interesting and useful ones are

__InstanceCreationEvent
__InstanceModificationEvent                        double underscores mind!!!
__InstanceDeletionEvent

So monitoring system resources?...use the above classes

Extrinsic Events

Are events that do not link directly to the standard WMI model.
Extrinsic Events are outside the standard WMI model. The means having a WMI provider is mandatory.

The Windows REGISTRY!!
The Registry defines extrinsic events for all registry change events.

NB...I'll need to reread the extrinsic and Intrinsic events as the author kinda sorta mixed these around by starting to explain Extrinsic Events then in that section explain more about Intrinsic Events...I think I see what he is saying but I'll go over these 2 sections again later.

Timer Events

Specialized Intrinsic Event.

WMI uses uses preconfigured event timers within the repository to generate event timers.

Win32_LocalTime  class

WQL Queries...The Syntax

The SELECT staement is used for Event Queries too. The general syntax is......

Event-WQL = "Select" "From" / Optional-Within = ["Within" Interval = 1*Digit Event-Where = ["Where"] Event-Expr = (("ISA")) ["Group Within"(['By[Dot]] ["Having"]]) Instance-State = "TargetInstance"/"PreviousInstance"

So we know..."Select" "From" Where.......Lets look at the new keywords.

Within

Specifies the polling interval or grouping interval (when used with the GROUP clause) for events.

Polling Interval = Interval used by WMI as the maximun amount of time that can pass before notification of an event must be delivered,

SELECT * From EventClass Within Interval Where Property = Value

The polling interval value is specified in seconds and is a floating point number.We can specify fractions of seconds. Keep in mind Event Queries are resource intensive and choosing fractions of a second as a polling time may cause system, slow down. Recommended values depend on the event class. Just dont use fractions of a second unless you really have to...I guess!!

Anyway check these screen shots

Setting the events for triggering and as I launched the Snip tool etc etc ...


You can see the event triggers being displayed to the shell output file.

Group

Causes WMI to generate a single notification to represent a group of events.
This returns an instance of __AggregateEvent that contains an embedded object of one of the instances received during the grouping interval and the number of events received.

Grouping Interval = Representative 
number of events = NumberOfEvents

The grouping interval is the time from the initial event which WMI should collect similar events. The Group clause must contain the WITIHIN clause to set the grouping interval and can contain either or both the BY or HAVING keywords. The Group clause is always after the WHERE clause, if WHERE is being used in the query.

Example of Grouping

 select * from EventClass [Where property=value] Group Within Interval

Useful if you dont want a notification every time there is an event. We may not want a notification if for say...every time an event log is written to. so use the GROUP clause to setup one notification when several events are triggered in relation to one event occurring.

Full example

$query = "select * From __instanceCreationEvent where targetInstance ISA 'win32_NTLogEvent'"

register-wmievent -query $query -action {write-host "New Evemtlog has arrived"}

watch out for the typos.............look at the screen shot


This is different from how polling works. When using polling intervals, there is a wait state until a specified time has elapsed and then the events generated, during the polling interval or wait state, has elapsed and sends all the events that were generated in a lump.

With the grouping interval one event will be received by the subscriber and the number of events occurred during the grouping interval will be known.

After doing some examples and going back to my PoSh session...look at this output



Having

Lets us be more selective, if we have large return from the event monitoring.

So 

$query = "select * From __instanceCreationEvent where targetInstance ISA 'win32_NTLogEvent' AND TargetInstance.eventCode=1980 Group Within 300 Having NumberOfEvents > 10"

register-wmievent -query $query -action {write-host "New 1980 Evemtlog has arrived"}

No hits yet but the other events sre being monitored!

So...previously on Do It Yourself WMI/WQL....using GROUP returns a property called NumberOfEvents this contains the number of events recieved during the grouping interval. So by using this property and the HAVING keyword we can filter event notifications...

The syntax

SELECT * From EventClass [Where Property = Value] Group Within interval Having NumberOfEvents Operator Constant

So event notifications are delivered only when WMI receives more than 10 events in the GROUP interval of 300 seconds or 5 minutes.

BY

Keyword can be used along with the GROUP clause to group events by one or more properties of the event class.

General Syntax

SELECT * fROM EventClas [WHERE property = Value] GROUP WITHIN Interval [BY Property_List]

Shell example.....

$query = "SELECT * FROM __instanceCreationEvent Where TargetInstance ISA 'Win32_NTLogEvent' Group Within 300by TargetInstance.SorceName Having NumberofEvents > 10"

Register-WMIEvent -query $query -action{write-host"eventlog entered using BY"}


The events are grouped by the Target.SourceName property and an event notification is delivered only if the number of events received during  the grouping  interval exceeds 10

(Keep in mind that you may have to go through the pain of entering typos in to the shell, to get round this the examples can be scripted, and just the necessary sections tweeked...mind GIGO!!! Garbage in =Garbage Out)

Intrinsic Event Queries

Lets not over think this too much and just keep in mind a few facts.

INTRINSIC EVENTS are used to monitor a resource represented by a class in the CIM repository.

INTRINSIC EVENTS occur in response to a change in the standard WMI data model.

WMI creates INTRINSIC EVENTS for objects stored in the WMI repository.

A provider generates INTRINSIC EVENTS for dynamic classes.

WMI can create an instance for a dynamic class if no provider is available.

Changes are detected using polling.

Clear as MUD!!!!

WMI System Classes there are quite a few!!
The ones that are most useful are



.
Use all of the above for monitoring resources on a system.

The Hierarchy

Me and the book will part our ways here, I think my PC matches the book but it could be misunderstood as the picture used in the book does n't really show the full tree hierarchy of the CIM/WMI...so I'll make my own......oh yeah while I was using the snipping tool my PC nose dived in performance so I closed off my PoSh to stop the monitoring scripts I was playing around with....they are system intensive.


So you can see under Root\CIMV2 path is __SystemClass\__IndicationRelated\__Event\__InstanceOperationEvent

No the PC and book do not match so dive in to CIM Studio yourself and see the paths.... for your computer.

General Syntax

SELECT Property_List From EventClass WITHIN PollingInterval Where TargetInstance | previousInstance ISA WMIClassName AND TargetInstance.WMIClassPropertyName = Value

The EventClass can be any of the system classes such as

__InstanceCreationEvent
__InstanceModificationEvent **
__InstanceInvocationEvent
__InstanceDeletionEvent

In the book it had a different class called __InstanceOperationEvent..See, from my snip of that WMI repository section, I do not have that class, I have __InstanceInvocationEvent.

So,, definite differences between the book and my PC OS install.

PreviousInstance = object state prior the EVENT **NB only available when using the __InstanceModificationEvent**
TargetInstance = object state after the EVENT


How are the classes used?

__InstanceCreationEvent 

Used when we want to receive a notification upon creation of an instance. So say, for every time a new process starts.

Recycling previously used commands/code

$query = "SELECT * FROM __instanceCreationEvent Where TargetInstance ISA 'Win32_NTLogEvent' 

Register-WMIEvent -query $query -action{write-host"eventlog entered using BY"}
                                                                       We are asking for a response/action to be                                                                            performed when the event occurs.

__InstanceDeletionEvent

Used when we want notification upon a deletion of an instance. In other words when a process is stopped.

$query = "SELECT * FROM __InstanceDeletionEvent WITHIN 5 WHERE TargetInstance ISA "Win32_Process'"


Register-WMIEvent -query $query -action{write-host"eventlog entered using BY"}
In the -action section We are asking for a response/action to be performed when the event occurs.

__InstanceModificationEvent

Used when we want to monitor changes to an existing instance or resource.
So, resources liek Memory, Paged,Memory, CPU can be monitored incase they exceed certain thresholds

$query = "select * from __instanceModificationEvent within 5 where TargetInstance ISA 'Win32_processor' and TargetInstance.LoadPercentage > 80"

register-wmievent -query $query -action {write-host "MPU is being used above 80%, you better do something quick!!!"}


So if the Micro Processor Unit is being used higher than 80% up pops a notification.

So if we want to play around with RANGES of percentage utilization....we need to use PreviousInstance as well as TagetInstance....both are embedded in the __InstanceModificationEvent.

$query = "select * from __instancemodificationevent within 5 where targetinstance isa 'win32_processor' and (targetinstance.loadpercentage >= 80 and previousinstance.loadpercenatge >= 70)"

register-wmievent -query $query -action {write-host "MPU is being used above 80%, you better do something quick!!!"} 


Instead of just displaying warnings to the shell output we can do more usefull stuff in the script block.

Powershell has Automatic Variables (and I know these are for PoSh 4 but it looks like the PoSh 2.0 stuff has been removed. I have some books I'll see what they say and type up something later)

SO looking at the list of variables we have an automatic variable called $event and it is used to store the last event received. It can also be accessed by the -Action scriptblock.

$query = "select * from __instancecreationevent within 10 where targetinstance isa 'win32_process'"

Nothing new here....but watch this......
                                                                           ***
register-wmievent -query $query -action {$global:myevent=$event} | out-null

Set $event variable to a variable in the global scope = $myevent. ***the automatic variable $event cannot be accessed otherwise***

Powershell 4.0 Scopes just a reminder as to why the variables were set global.



Open an application to fire the __InstanceCreationEvent...
So now you have to do a couple of things...remember that with PoSh you are dealing with objects and each object has properties or members that can be further queried...GET-Member cmdlet explained....

$myevent | get.member

This will bring back the members of the object conatined in $myevent

$myevent.sourceeventargs.newevent.targetinstance.name

Brings back the process caught. As you can see I have Chrome and Notepad cause I was playing around.

The three classes are derived from __InstanceOperationEvent class. It can be used for event subscriptions too!!

Example from the book...which does n't quite work on my PC so still debugging it


$query = "select * from __instanceOperationEvent within 10 where targetinstance isa 'win32_process'"


Register-WMIEvent -query $query -action {$processname = $event.sourceEventArgs.NewEvent.TargetInstance.Name} switch ($event.SourceEventArgs.NewEvent.__CLASS){
                                         __InstanceCreationEvent
                                         {
                                         write-host "a new process started:
                                         $($processname)"
                                         }
                                         __InstanceDeletionevent
                                         {
                                         write-host "a process terminated:
                                         $($processname)"
                                         }
                                         {
                                         __InstanceModificationEvent {
                                         write-host "Process was modified:
                                         $($processname)"
                                         }
                                         }
                                         }
                                         
                                      Still debugging the above commands...below is what should happen.............   
                                         
                                      
The -action script block is checking for the actual instance class type.
To do this we use the Switch statement.

This is required because __InstanceOperationEvent can be any of the three types. It does not have an instance of its own.

So every time a process working set is changed it triggers __InstanceModificationEvent which results in a torrent of output.

Extrinsic Event Queries

Are events that do not directly link to to the standard WMI model.
Since extrinsic events are outside of the standard WMI model, having a WMI provider is mandatory.

So we need the __ExtrinsicEventClass


Since the Windows Registry defines extrinsic events for all registry change events we can use that as an example...and the book uses it too!!!

First hurdle is that the registry entries between my PC and the one used in the book are more than likely way different!!




Monitoring Registry Value Change Events

We use RegistryValueChangeEvent to monitor registry value changes.

The book wants to use the following code....which wont work on my PC.

$query = "select * from RegistryValueChangeEvent where Hive='HKEY_LOCAL_MACHINE' and keypath='SoftwareTemp' and ValueName='Name'"

Register-WMIEvent -query $query -action {write-host "value changed"}

So any registry change we should see "value changed" in the PoSh. A couple of drawbacks!!! A deletion is registered as a change and it wont return the new value.of any new configuration that has updated the value.

The -action script block can be used to verify the registry value

$query = "select * from RegistryValueChangeEvent where Hive='HKEY_LOCAL_MACHINE' and keypath='SoftwareTemp' and ValueName='Name'"

Register-WMIEvent -query $query -action {

if (get-item HKLM:SOFTWARETemp).GetValue("Name")){Write-Host(Get-Item HKLM:SOFTWARETemp).GetValue("Name")
                                                                        }else{
                                write-host "The registry value was deleted"
                                                                                 }
                                                                             }

Monitoring registry key change events

RegistryKeyChangeEvent is used to monitor changes to a registry sub key. It will not give you any info on the value of the sub key after the modification.

$query = "select * from RegistryKeyChangeEvent  where Hive='HKEY_LOCAL_MACHINE' and keypath='SoftwareTemp' and ValueName='Name'"

Register-WMIEvent -query $query -action {write-host "value changed"}

Again the -action script block can be used to verify the registry value

Monitoring registry tree change events

RegistryTreeChangeEvent used to monitor sub-tree level modifications.It will not give you any info on the sub-tree modification, just that one occurred. 

$query = "select * from RegistryKeyChangeEvent  where Hive='HKEY_LOCAL_MACHINE' and RootPath='''"

Register-WMIEvent -query $query -action {write-host "value changed"}

External Vendors can provide their own Extrinsic event classes...below is a link to the Authors Chapter and to Intel's WMI docs




Goverlan WMI Explorer Apparently this util can remote query systems and export to VBS and Powershell
























































































































Modules & Snapins

Codeplex

Remote Desktop

Hewlett Packard
HP ILO (Inside Lights Out CMDlets)

MIcrosoft

Add Exchange Snapin to Powershell ISE in case of emergency check this from Stackoverflow Exchange Snapin Doc
Trouble_Shooting_Pack Not convinced with these utils but they might be handy. Another one from the Scripting Guy!!



Server Disc Space

Always a hot topic! No you cannot have music files or Ereader books on our servers thank you very much!!! Unless they are work related...but see that file that's titled "50 Shades of Gray" tut tut...

Probably the best Util for determining folder sizes is Treesize Pro but then why the Powershell page...well the Scripting Guy has made something that budding PoSh scripters might like...


Folder Sizes (MS Scripting Guy)


And from the Microsoft Script Centre....


Folder Stats


Just in case you work for a fud who is against using Treesize Pro...


1 comment: