January 2014 - Posts

When did Windows update last run

A question came up on the forum regarding when Windows Update last run and when an update was last installed.  Get-Hotfix shows the date of installation for most BUT not all patches.

The registry holds values showing last successful detection and install:

$props = [ordered]@{
LastDetect = Get-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\Results\Detect' -Name LastSuccessTime |
select -ExpandProperty LastSuccessTime

LastInstall = Get-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\Results\Install' -Name LastSuccessTime |
select -ExpandProperty LastSuccessTime
}

New-Object -TypeName psobject -Property $props

Posted by RichardSiddaway | with no comments
Filed under: ,

Win32_OperatingSystem examples

The Win32_ComputerOperatingSystem class can provide a good deal of information about the OS installed on your machines. These examples are converted from those presented here: http://msdn.microsoft.com/en-us/library/aa394596%28v=vs.85%29.aspx

 

# ServicePack version
Get-CimInstance -ClassName Win32_OperatingSystem |
select ServicePackMajorVersion, ServicePackMinorVersion

# install date of OS
Get-CimInstance -ClassName Win32_OperatingSystem |
select Installdate

# Windows version
Get-CimInstance -ClassName Win32_OperatingSystem |
select Caption, Version

# windows folder
Get-CimInstance -ClassName Win32_OperatingSystem |
select WindowsDirectory

# all
Get-CimInstance -ClassName Win32_OperatingSystem |
select Caption, Version, ServicePackMajorVersion,
ServicePackMinorVersion, Installdate, WindowsDirectory

 

You could create a function:

function get-OS {
[CmdletBinding()]
param(
[string]$computername = $env:COMPUTERNAME
)

Get-CimInstance -ClassName Win32_OperatingSystem  -ComputerName $computername|
select Caption, Version, ServicePackMajorVersion,
ServicePackMinorVersion, Installdate, WindowsDirectory

}

 

and then choose properties if required:

£> get-OS | Format-Table Caption, Installdate

Caption                                    Installdate                              
-------                                    -----------                              
Microsoft Windows 8.1 Pro                  05/12/2013 10:16:49                      

£> get-OS


Caption                 : Microsoft Windows 8.1 Pro
Version                 : 6.3.9600
ServicePackMajorVersion : 0
ServicePackMinorVersion : 0
Installdate             : 05/12/2013 10:16:49
WindowsDirectory        : C:\windows


£> get-OS | Format-Table Caption, Service* -AutoSize

Caption                   ServicePackMajorVersion ServicePackMinorVersion
-------                   ----------------------- -----------------------
Microsoft Windows 8.1 Pro                       0                       0

£> get-OS | Format-Table Caption, Installdate -AutoSize

Caption                   Installdate       
-------                   -----------       
Microsoft Windows 8.1 Pro 05/12/2013 10:16:49

Posted by RichardSiddaway | with no comments

Win32_Process examples–running applications

You can see the running processes on a local or remote machine using Get-Process. Alternatively you can use Win32_Process:

Get-CimInstance -ClassName Win32_Process |
select Name, ProcessID, Threadcount, PageFileUsage, PageFaults, WorkingSetSize |
Format-Table –AutoSize

You can use the –ComputerName or –CimSession properties to access the processes on a remote machine.

Other properties are available:

Get-CimClass -ClassName Win32_Process |
select -ExpandProperty CimClassProperties |
Format-Table -AutoSize

Posted by RichardSiddaway | with no comments

Win32_Process examples–test command line

To see the command lines that have been used when processes are started is simple one liner:

Get-CimInstance -ClassName Win32_Process | select Name, CommandLine

If you want to investigate specific processes use the –Filter parameter to restrict the processes

Posted by RichardSiddaway | with no comments

Win32_Examples–start application in hidden window

This one is interesting as I’d tried doing this a while back and failed.  Starting a process with Win32_Process is straightforward but controlling the process – such as starting in a hidden window wasn’t working. This is how you do it:

function start-hiddenproc {
[CmdletBinding()]
param (
[string]$processname = 'notepad.exe'
)

$startclass = Get-CimClass -ClassName Win32_ProcessStartup
$startinfo = New-CimInstance -CimClass $startclass -Property @{ShowWindow = 0} -ClientOnly

$class = Get-CimClass -ClassName Win32_Process
Invoke-CimMethod -CimClass $class -MethodName Create -Arguments @{Commandline = $processname; ProcessStartupInformation = [CimInstance]$startinfo}
}

 

The function takes a path to the process executable as a parameter – would be a good place for a validation script parameter to test the path to the executable.

 

Get the Win32_ProcessStartup class and use it with New-CimInstance to create the start up information. The New-CimInstance parameter –ClientOnly can be aliased to –Local.  I always prefer to use the master parameter name rather than aliases – makes it easier for people to look things up in the documentation.

 

Get the Win32_Process class and use it with Invoke-CimMethod to invoke the Create method with the arguments passed as shown

Posted by RichardSiddaway | with no comments

Winter Scripting Games 2014–event 1 available

The event instructions for event 1 are available for download. Entries will be accepted starting tomorrow. Event will close 26 January 00:00:00 UTC

Posted by RichardSiddaway | with no comments

Win32_Process examples–running scripts

Back in the day when all we had was VBScript you could run scripts through the command line (cscript) or you would get a more graphical interface (wscript).  One of the examples at http://msdn.microsoft.com/en-us/library/aa394599(v=vs.85).aspx shows how to detect running scripts.

I don’t imagine much call for that technique but if you need it – here it is:

Get-CimInstance -ClassName Win32_Process -Filter "Name = 'cscript.exe' OR Name = 'wscript.exe'" |
Format-Table Name, Commandline

You could use a variation to test the command line input to other processes if you need to

Winter Scripting Games 2014–tips

Event 1 is available for download in just over 6 hours

In the mean time head over to powershell.org and look at the fantastic set of tips that the coaches are putting out

Posted by RichardSiddaway | with no comments

Kindle app for Windows 8

I’ve written unfavourably on the Kindle app in the past but I stumbled on an piece of functionality in the app that makes me take a lot of my comments back – search.

If you are in the Kindle app and bring up the charms you can get into search. This means you can search for books within your cloud store – this is especially useful fro me when I have hundreds of books most of which aren’t downloaded onto my Windows device at any one time.

Posted by RichardSiddaway | with no comments
Filed under:

Win32_Process examples

In case you were wondering where the examples came that inspired the code in this series from its here - http://msdn.microsoft.com/en-us/library/aa394599(v=vs.85).aspx

I’m providing PowerShell examples

In some cases it would be easier to use the *Process cmdlets but I want to demonstrate how to use the WMI class

Win32_Process examples–terminate process

Terminating a running process is simply a case of calling the Terminate method:

function remove-proc{
[CmdletBinding()]
param (
[string]$computername = $env:COMPUTERNAME,
[string]$processname
)

Get-CimInstance -ClassName Win32_Process -ComputerName $computername -Filter "Name = '$processname'" |
Invoke-CimMethod -MethodName Terminate
}

 

This will terminate all instances of a given process.  If you want to be more selective then change the function to use the process id rather than the process name

Win32_Process examples–set priority

Changing the priority of a process can give a processing boost to an application – but its not always a safe option.

You can modify the process like this:

function set-procpriority {
[CmdletBinding()]
param (
[string]$computername = $env:COMPUTERNAME,
[string]$processname,

[ValidateSet("Idle", "BelowNormal", "Normal", "AboveNormal", "HighPriority", "RealTime")]
[string]$priority
)

switch ($priority){
"Idle"         {[uint32]$priorityin =    64; break}
"BelowNormal"  {[uint32]$priorityin = 16384; break}
"Normal"       {[uint32]$priorityin =    32; break}
"AboveNormal"  {[uint32]$priorityin = 32768; break}
"HighPriority" {[uint32]$priorityin =   128; break}
"RealTime"     {[uint32]$priorityin =   256; break}
}

Get-CimInstance -ClassName Win32_Process -ComputerName $computername -Filter "Name = '$processname'" |
Invoke-CimMethod -MethodName SetPriority -Arguments @{Priority = $priorityin}
}

The advanced takes three parameters – computername (defaults to local machine), a process name and the priority that process should have.

A switch statement converts the priority name to an unsigned integer value

The process objects are retrieved by Get-CimInstance and Invoke-CimMethod is used to call the SetPriority method.

You can use it like this:

£> notepad

£> get-process notepad | Format-List Name, PriorityClass

Name          : notepad
PriorityClass : Normal

£> set-procpriority -processname 'notepad.exe' -priority HighPriority

                                              ReturnValue PSComputerName                                         
                                              ----------- --------------                                          
                                                           0 RSSURFACEPRO2                                          

£> get-process notepad | Format-List Name, PriorityClass

Name          : notepad
PriorityClass : High

The function will modify the priority of all instances of the process. If you want to modify just one instance then you need to remove the process name parameter and add a process id parameter

Winter Scripting Games 2014 –Event 1

The first event in the 2014 Winter Scripting Games kicks off in just over 2 days time.

The practice event is finished and we’re testing the judging system

Good luck to all participants

Win32_Process examples: get process owner

Moving on with examples of using Win32_Process you can find the process owner:

function get-procowner {
[CmdletBinding()]
param (
[string]$computername = $env:COMPUTERNAME
)

Get-CimInstance -ClassName Win32_Process -ComputerName $computername |
foreach {
  $owner = Invoke-CimMethod -InputObject $psitem -MethodName GetOwner

  $props = [ordered]@{
             Name = $psitem.Name
             Domain = $owner.Domain
             User = $owner.User
             ComputerName = $psitem.PSComputerName
          
           }
  New-Object -TypeName PSObject -Property $props
}
}

Use the same param block as before to pass a computername – defaulted to local machine.

For each of the Win32_Process objects get the corresponding owner using the GetOwner method.

Create an ordered hash table for the properties and output a PSObject using those properties

Win32_Process examples–processor time and memory usage

I saw some example code for using Win32_Process and didn’t like it so decided to create my own versions.  In this case the objective is to display the processor time and memory usage:

function get-proctimeandRAM {
[CmdletBinding()]
param (
[string]$computername = $env:COMPUTERNAME
)

Get-CimInstance -ClassName Win32_Process -ComputerName $computername |
foreach {
  $props = [ordered]@{
              Name =  $psitem.Name
              ProcessId = $psitem.ProcessId
              WorkingSetSize = $psitem.WorkingSetSize
              PageFileUsage = $psitem.PageFileUsage
              PageFaults = $psitem.PageFaults
              ProcessorTime = ($psitem.KernalModeTime + $psitem.UserModeTime) / 10000000
           }
 
  New-Object -TypeName PSObject -Property $props
}
}

Start by creating an advanced function that takes a computername as a parameter.  This is used to call Get-CimInstance to access the Win32_Process class on the machine.

I’m switching to the CIM cmdlets for everything as my test environment is, or soon will be, Windows 2012 R2 or Windows 8.1.

For each if the Win32_Process objects create a New-Object. I’ve chosen to use an ordered hash table (PS 3 and above) so that my properties remain in the order I want

The function produces a list by default as there 6 properties on the object. If you want  table output use Format-Table.

Examples of use:

get-proctimeandRAM
get-proctimeandRAM | ft -AutoSize

VM disk info

A question came into the forum about getting information on the virtual disks associated with particular Hyper-V virtual machines. Is a bit of a digging exercise but this gets the results:

Get-VM |
foreach {
$VMname = $psitem.Name
Get-VMHardDiskDrive -VMName $VMname  |
foreach {
   Get-VHD -Path $_.Path |
   select @{N='VMname'; e={$VMName}}, Path, Size, FileSize
}
}

Get the set of VMs and for each of them get the VMHardDisks associated with the machine. For each VMHardDisk get the VHD – this is where you find the data you need.

 

The size and file size are in bytes – its a simple matter to create calculated fields that divide by 1GB or percentages if you require

Finding a sequence

I saw a challenge to find the occurrences of the sequence 1759 in the larger sequence 11759171759.  It was originally presented as a SQL Server based challenge to be solved with TSQL but we can do this just as easily with PowerShell using Select-String

£> $data = '11759171759'
£> Select-String -InputObject $data -Pattern '1759' -AllMatches | foreach {$_.Matches.Index}

1
7

Create a variable to hold the big sequence and use that with the –InputObject parameter of Select-String. Supply the pattern to be tested and use –AllMatches to get all matches not just the first which is default. The resultant MatchInfo is piped to foreach-object where the Index of each match is retrieved.

if you want to see the full MatchInfo

£> $m = Select-String -InputObject $data -Pattern '1759' -AllMatches
£> $m.Matches


Groups   : {1759}
Success  : True
Captures : {1759}
Index    : 1
Length   : 4
Value    : 1759

Groups   : {1759}
Success  : True
Captures : {1759}
Index    : 7
Length   : 4
Value    : 1759

The indexes are zero based.  Add one if you want the position based on a starting index of 1

£> foreach ($match in (Select-String -InputObject $data -Pattern '1759' -AllMatches).Matches){$match.Index + 1}
2
8

Interesting puzzle that gives a good example of using Select-String

Posted by RichardSiddaway | with no comments
Filed under:

Cim cmdlet aliases

I don’t use aliases in scripts/functions and don’t use them much at the command line. One alias I do use reasonably often is gwmi for Get-WmiObject – mainly because I do a lot with WMI.  I’m using the CIM cmdlets much more these days and suddenly realised that I didn’t know if they had aliases.

One quick trip to Get-Alias and I had the answer:

£> Get-Alias | where Definition -like '*Cim*'

CommandType     Name
-----------     ----
Alias           gcai -> Get-CimAssociatedInstance
Alias           gcim -> Get-CimInstance
Alias           gcls -> Get-CimClass
Alias           gcms -> Get-CimSession
Alias           icim -> Invoke-CimMethod
Alias           ncim -> New-CimInstance
Alias           ncms -> New-CimSession
Alias           ncso -> New-CimSessionOption
Alias           rcie -> Register-CimIndicationEvent
Alias           rcim -> Remove-CimInstance
Alias           rcms -> Remove-CimSession
Alias           scim -> Set-CimInstance

Also note change in the way the data is presented compared to earlier versions of Get-Alias

Posted by RichardSiddaway | with no comments
Filed under: ,

Test windows activation

I’m currently upgrading my lab environment to Windows Server 2012 R2 which involves upgrading some machines and rebuilding the others.  One task in any build or upgrade situation is to make sure that Windows is activated.

Windows Server 2012 R2 will activate once an Internet connection is established. This can sometimes take a few minutes. Rather than keep checking in the GUI I wrote a little function to do the job for me:

function test-activation {
  $slp = Get-CimInstance -ClassName SoftwareLicensingProduct -Filter "PartialProductKey LIKE '%'"
  if ($slp.LicenseStatus -eq 1) {
    return "$($slp.Name) on $env:COMPUTERNAME is activated"
   }
   else {
    return "$($slp.Name) on $env:COMPUTERNAME is NOT activated"
   }
}

This is based on technique 104 in PowerShell and WMI  - www.manning.com/siddaway2

Get-CimInstance  uses the SoftwareLicensingProduct class and filters on the PartialProductKey property. The filter only picks up those instances where the property has a value.

If the LicensesStatus property equals its activated otherwise it isn’t.

CDXML: Cim jobs

One of the freebies you get when using CDXML is that the cmdlets you create automatically get the –AsJob parameter. I was thinking about jobs in general and realised that I didn’t know how CIM jobs were run.

To put this into context:

PowerShell jobs run in another PowerShell process that is started as a child of the PowerShell process in which you start the job.

WMI jobs use a process called unsecapp - C:\Windows\System32\wbem\unsecapp

Another process - C:\Windows\system32\wbem\wmiprvse.exe will also run.

 

In order to discover the process(es) used by CIM jobs I needed a CIM job that would run for a long time – using CIM_DataFile class to enumerate the files on disk would work. I created a quick module using that class

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

    <InstanceCmdlets>
      <GetCmdletParameters DefaultCmdletParameterSet='DefaultSet'>
             
      </GetCmdletParameters>
    </InstanceCmdlets> 
  </Class>
 
</PowerShellMetadata>

 

and saved it as Cim_DataFile.cdxml

 

After importing the module I opened another PowerShell session and got a list of processes as a baseline.

Then use the new cmdlet in a Job

Get-DataFile –AsJob

 

The job type is CimJob

A new process appears – wmiprvse. This the same process that appears with WMI jobs.  The path to the exe is C:\Windows\system32\wbem\wmiprvse.exe and the Description is: WMI Provider Host

This process provides isolation for WMI activities so that the whole of WMI isn’t pulled down in the event of a failure. 

The same process is started if Get-CimInstance Cim_Datafile is run.

Posted by RichardSiddaway | with no comments