PowerShell for Windows Admins


January 14, 2014  12:50 PM

Win32_Process examples–processor time and memory usage



Posted by: Richard Siddaway
CIM, PowerShell 3, PowerShell v4, WMI

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

January 14, 2014  12:24 PM

VM disk info



Posted by: Richard Siddaway
Hyper-V, PowerShell, Windows Server 2012, Windows Server 2012 R2

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


January 10, 2014  6:28 AM

Finding a sequence



Posted by: Richard Siddaway
PowerShell Basics

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


January 9, 2014  4:34 PM

Cim cmdlet aliases



Posted by: Richard Siddaway
CIM, PowerShell v4

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


January 8, 2014  12:47 PM

Test windows activation



Posted by: Richard Siddaway
CIM, PowerShell v4, Windows Server 2012 R2, WMI

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.


January 5, 2014  10:27 AM

CDXML: Cim jobs



Posted by: Richard Siddaway
CDXML, CIM, PowerShell 3, PowerShell v4

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.


December 31, 2013  6:15 AM

The PowerShell year – 2013



Posted by: Richard Siddaway
Opinion, PowerShell

This year has been a pretty good year for the PowerShell community. The highlights include:

  • PowerShell 4.0 becomes available
  • A very successful PowerShell Summit in April
  • A community hosted and judged Scripting Games – though as PowerShell is the only accepted language maybe a name change is needed?
  • PowerShell in Depth and PowerShell Deep Dives are published

The big ticket item in PowerShell 4.0 is Desired State Configuration. This functionality was extended at the end of the year with the publication of the  Desired State Configuration Resource Kit Wave 1 -  see the PowerShell team blog at http://blogs.msdn.com/b/powershell/archive/2013/12/26/holiday-gift-desired-state-configuration-dsc-resource-kit-wave-1.aspx

The most important part of the announcement is that it is wave 1 – meaning we should expect more DSC resources in the New Year.

Looking forward to 2014 what do we expect?

  • More DSC resources
  • 2014 Winter Scripting Games – this time we’re making them a team based event. Should be interesting
  • A PowerShell Summit in Seattle in April
  • A European PowerShell summit later in the year

Assuming you already know the PowerShell basics, or more, where should you be spending your PowerShell time in 2014?

If your work involves creating servers on a regular basis make sure you understand DSC

If you need to administer many servers – look to PowerShell workflow, PowerShell jobs and Scheduled jobs.  These options seem to have slipped out of the limelight lately.

Workflows are different – they use a PowerShell syntax but aren’t pure PowerShell. Some of the rules for using them are a bit strange and need some practice.

PowerShell jobs were introduced in PowerShell 2.0 but have always been overshadowed by remoting. The ability to run PowerShell jobs asynchronously and schedule them makes for a very powerful system for performing bulk tasks overnight.

The last recommendation for 2014 – learn more about CIM/WMI.  A significant fraction of the PowerShell functionality in Windows 8/2012 and later is built on WMI. If you don’t understand how it works you won’t get the best out of it. The OMI initiative is gaining traction which makes CIM an even more important technology to learn.

I’d also recommend experimenting with any of the areas of PowerShell you don’t know so well.

Finally, and most importantly, share what you learn with the rest of the PowerShell community – powershell.org is a very good place to start.


December 23, 2013  5:55 PM

CDXML–NetworkAdapterConfiguration–Search on Index



Posted by: Richard Siddaway
CDXML, CIM, PowerShell 3, PowerShell v4

The Win32_NetworkAdapterConfiguration class has an Index and an InterfaceIndex property. Both are suitable search properties.

 

The take an unsigned integer as their value – leading to this addition to the CDXML file:

 

<Property PropertyName=”Index”>

<Type PSType = “System.UInt32″/>

<RegularQuery >

<CmdletParameterMetadata PSName=”Index” />

</RegularQuery>

</Property>

 

 

<Property PropertyName=”InterfaceIndex”>

<Type PSType = “System.UInt32″/>

<RegularQuery >

<CmdletParameterMetadata PSName=”InterfaceIndex” />

</RegularQuery>

</Property>

 

 

You can use the new parameters like this:

 

Get-NetworkAdapterConfiguration -Index 4

 

Get-NetworkAdapterConfiguration -InterfaceIndex 5

 

You should see by now how much easier it is working with cmdlets like this rather than having to remember the syntax for WQL filters and even the class names.

 

The full CDXML file looks like this

 

<?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=”DHCPEnabled”>

<Type PSType = “System.Boolean”/>

<RegularQuery >

<CmdletParameterMetadata PSName=”DHCPEnabled” />

</RegularQuery>

</Property>

 

<Property PropertyName=”IPEnabled”>

<Type PSType = “System.Boolean”/>

<RegularQuery >

<CmdletParameterMetadata PSName=”IPEnabled” />

</RegularQuery>

</Property>

 

<Property PropertyName=”Index”>

<Type PSType = “System.UInt32″/>

<RegularQuery >

<CmdletParameterMetadata PSName=”Index” />

</RegularQuery>

</Property>

 

<Property PropertyName=”InterfaceIndex”>

<Type PSType = “System.UInt32″/>

<RegularQuery >

<CmdletParameterMetadata PSName=”InterfaceIndex” />

</RegularQuery>

</Property>

 

</QueryableProperties>

 

</GetCmdletParameters>

</InstanceCmdlets>

</Class>

</PowerShellMetadata>

 

The module manifest file hasn’t needed to be changed to add this additional functionality. One of the great things about CDXML is that once you have the basic cmdlet working it is so easy to add extra parameters.

 

The next step is to use some of the methods on the class

 


December 23, 2013  11:57 AM

CDXML–NetworkAdapterConfiguration–IP Enabled



Posted by: Richard Siddaway
CDXML, CIM, PowerShell 3, PowerShell v4

Last time we added a search parameter enabling this:

Get-NetworkAdapterConfiguration -DHCPEnabled $true

 

I also want to be able to search based on if the adapter if IP Enabled using:

Get-NetworkAdapterConfiguration -IPEnabled $true

 

This can be achieved by specifying another search parameter:

<Property PropertyName=”IPEnabled”>

<Type PSType = “System.Boolean”/>

<RegularQuery >

<CmdletParameterMetadata PSName=”IPEnabled” />

</RegularQuery>

</Property>

 

This the same as was done for DHCPEnabled except that the IPEnabled property is used.

The full XML now looks like this:

<?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=”DHCPEnabled”>

<Type PSType = “System.Boolean”/>

<RegularQuery >

<CmdletParameterMetadata PSName=”DHCPEnabled” />

</RegularQuery>

</Property>

 

<Property PropertyName=”IPEnabled”>

<Type PSType = “System.Boolean”/>

<RegularQuery >

<CmdletParameterMetadata PSName=”IPEnabled” />

</RegularQuery>

</Property>

 

</QueryableProperties>

 

</GetCmdletParameters>

</InstanceCmdlets>

</Class>

</PowerShellMetadata>


December 23, 2013  10:06 AM

LastLogoff timestamp



Posted by: Richard Siddaway
Security

I was recently asked if there was any way to fill in the LastLogoff timestamp

The short answer is no.  The values in the attributes related to logons are maintained by Active Directory during the logon process.

I wouldn’t want them to be programmable as that as would create a potential loop hole in my logging process.

As far as I can tell LastLogoff isn’t currently used in Active Directory though if you have access to the Exchange cmdlets you could use Get-mailboxStatistics to discover logon and loggoff times to the mailbox which would be close


Forgot Password

No problem! Submit your e-mail address below. We'll send you an e-mail containing your password.

Your password has been sent to: