The Wiert Corner – irregular stream of stuff

Jeroen W. Pluimers on .NET, C#, Delphi, databases, and personal interests

  • My badges

  • Twitter Updates

  • My Flickr Stream

  • Pages

  • All categories

  • Enter your email address to subscribe to this blog and receive notifications of new posts by email.

    Join 1,862 other subscribers

Archive for the ‘PowerShell’ Category

PowerShell: Format-Table to show all columns/members

Posted by jpluimers on 2019/07/18

I’m not even sure if I’ve posted this before, but I always forget how to show all members (or columns) using Format-Table.

It’s dead easy: -Property *

Get-ChildItem | Format-Table -Property *

Later I found out this is equivalent with the shorter version where you omit the -Property part which I wrote about in [WayBackPowerShell: when Format-Table -AutoSize displays only 10 columns and uses the width of the console when redirecting to file.

So you can shorten the above to:

Get-ChildItem | Format-Table *

It has way more columns than this:

Get-ChildItem | Format-Table

The extra members in both marked with *:

  • PSPath
  • PSParentPath
  • PSChildName
  • PSDrive
  • PSProvider
  • PSIsContainer
  • BaseName
  • Mode *
  • Name *
  • FullName
  • Parent
  • Exists
  • Root
  • Extension
  • CreationTime
  • CreationTimeUtc
  • LastAccessTime
  • LastAccessTimeUtc
  • LastWriteTime *
  • LastWriteTimeUtc
  • Attributes

The odd thing: one property fails in the -Property * table:

  • Length

I tracked this down to how -Property * works: it takes the first entry in the list. If that is not a file, then it has no Length property: [WayBackpowershell – Measure-Object : The property “length” cannot be found in the input for any objects – Stack Overflow.

Note that for a GUI version, you can replace Format-Table with Out-GridView. See

-jeroen.

Posted in CommandLine, Development, PowerShell, PowerShell, Scripting, Software Development | Leave a Comment »

PowerShell: the issues you bump into when using Get-Counter and Measure-Object aggregation

Posted by jpluimers on 2019/07/17

Single process data

You can get many process properties using , for instance the total running time in minutes [WayBack] Get-Process:

New-TimeSpan -Start (Get-Process "devenv").StartTime | Select-Object -ExpandProperty "TotalMinutes"

Actually, the it matches multiple process instances, then you need to aggregate, for instance using this:

Get-Process "cmd" | ForEach-Object { New-TimeSpan -Start $_.StartTime } | Measure-Object -Property "TotalMinutes" -Sum | Select-Object -ExpandProperty "Sum"

If you want to see which properties are available, then use either of these:

Get-Process | Select-Object * | Out-GridView
Get-Process | Get-Member

Getting aggregated process CPU usage times

Lets start getting the total CPU time of all processes by using Get-Process which – without arguments – returns data for all processes it has access to:

PS C:\Users\Developer> Get-Process | Measure-Object -Property CPU -Sum

You’d think this gives only the sum. Wrong:

Count : 80
Average :
Sum : 2410.5625
Maximum :
Minimum :
Property : CPU

Ensure you get data for all processes

And you need it with an Administrative UAC token in order to get all processes on the system. It doesn’t show many more processes, but a lot more CPU time since boot:

Count : 83
Average :
Sum : 6078.125
Maximum :
Minimum :
Property : CPU

Showing one aggregate

So how to get rid of [WayBack] Measure-Object showing all aggregates?

The only stable solution I found is to expand that into | Measure-Object -Property CPU -Sum | Select-Object -ExpandProperty Sum which I found in the answer by davidhigh at [WayBack] Listing processes by CPU usage percentage in powershell – Stack Overflow and got me this by using [WayBack] Select-Object.

Note you have to use -ExpandProperty as just -Propertywill not cut it as you get an empty result (I think this has to do with Sum being a nullable type: Sum Property System.Nullable[double]):

PS C:\Windows\system32> Get-Process | Measure-Object -Property CPU -Sum | Select-Object -Property Sum
PS C:\Windows\system32> Get-Process | Measure-Object -Property CPU -Sum | Select-Object -ExpandProperty Sum
6126.40625

CPU % is hard

You’d think a CPU % is an easy thing to measure as it has been available in the Task Manager for such a long time, but it’s harder to determine than for instance process memory. Let me try to explain that (please post comments when it is unclear).

For process memory, you can measure it at the current instant: if you freeze the CPU, you can count the number of bytes used by the process.

For relative CPU usage however, you need to measure how a process executes over time. During that time, CPU usage may (or will) vary a little bit, so you need to measure over a little time-delta. If CPU core frequencies vary over time, you need to adjust for that so it gets even more difficult. Two links with a bit more background information on this:

I think the above difference is the reason that Get-Process doesn’t return a CPU percentage.

Performance Counters using Get-Counter

Instead, you can use [WayBackGet-Counter to get processor CounterSampleslike this:

(Get-Counter '\Process(*)\% Processor Time').CounterSamples

It gets you the % Processor Time which is the percentage of CPU determined by a CPU [WayBackHardware performance counter.

Filtering results

If you want this for a specific process, you first need to find out which processes exist. You can do that by getting the unique InstanceName property values by using [WayBack] Sort-Object:

(Get-Counter '\Process(*)\% Processor Time').CounterSamples | Select-Object -Property InstanceName | Sort-Object -Property InstanceName -Unique

(Here you do not need the -ExpandProperty on Select-Objectas the -Property suffices)

Special InstanceName values

There are always entries with InstanceName having values _total and idle:

(Get-Counter '\Process(*)\% Processor Time').CounterSamples | Where-Object {$_.InstanceName -eq "_total" }
(Get-Counter '\Process(*)\% Processor Time').CounterSamples | Where-Object {$_.InstanceName -eq "idle" }

You can even get both at the same time by using the -or operator with [WayBackWhere-Object:

(Get-Counter '\Process(*)\% Processor Time').CounterSamples | Where-Object {($_.InstanceName -eq "_total") -or ($_.InstanceName -eq "idle") }

Since the outputs are CPU core based, and sampled over time, they can be above 100%, heck even above the 100% * amount-of-CPU-cores as seen on a 2-core CPU system:

Path                                                InstanceName  CookedValue
----                                                ------------  -----------
\\w81entx64vs2015\process(idle)\% processor time    idle          186.168932138452
\\w81entx64vs2015\process(_total)\% processor time  _total        200.016208082634

You see that the CookedValue is what you’re after. If you just want the value for one instance, just use the -ExpandProperty trick shown above:

(Get-Counter '\Process(*)\% Processor Time').CounterSamples | Where-Object {$_.InstanceName -eq "_total" } | Select-Object -ExpandProperty CookedValue

Accommodating for multi-instance processes

(Get-Counter '\Process(*)\% Processor Time').CounterSamples | Where-Object {$_.InstanceName -eq "svchost" } | Select-Object -ExpandProperty CookedValue

This gets you a list like this:

PS C:\Windows\system32> (Get-Counter '\Process(*)\% Processor Time').CounterSamples | Where-Object {$_.InstanceName -eq "svchost" } | Select-Object -ExpandProperty CookedValue
0
0
...
0
0

For that, you need to aggregate by using Measure-Object like described in the Get-Process section:

PS C:\Windows\system32> (Get-Counter '\Process(*)\% Processor Time').CounterSamples | Where-Object {$_.InstanceName -eq "svchost" } | Measure-Object -Property CookedValue -Sum | Select-Object -ExpandProperty Sum
0

A more elaborate example of aggregating is at [Archive.isExportPerfomanceCountersHelpers.ps1.

Aggregated output usually works

This works for a single-instance process as well:

(Get-Counter '\Process(*)\% Processor Time').CounterSamples | Where-Object {$_.InstanceName -eq "lsass" } | Measure-Object -Property CookedValue -Sum | Select-Object -ExpandProperty Sum

Example output:

PS C:\Windows\system32> (Get-Counter '\Process(*)\% Processor Time').CounterSamples | Where-Object {$_.InstanceName -eq "lsass" } | Measure-Object -Property CookedValue -Sum | Select-Object -ExpandProperty Sum
0

The dreaded error

The above often works, but sometimes you get an error, often even earlier in the process.

The error is always like Get-Counter : The data in one of the performance counter samples is not valid. View the Status property for each PerformanceCounterSample object to make sure it contains valid data.:

PS C:\Windows\system32> (Get-Counter '\Process(*)\% Processor Time').CounterSamples | Where-Object {$_.InstanceName -eq "lsass" } | Measure-Object -Property CookedValue -Sum | Select-Object -ExpandProperty Sum
Get-Counter : The data in one of the performance counter samples is not valid. View the Status property for each PerformanceCounterSample object to make sure it contains valid data.
At line:1 char:2
+ (Get-Counter '\Process(*)\% Processor Time').CounterSamples | Where-Object {$_.I ...
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidResult: (:) [Get-Counter], Exception
    + FullyQualifiedErrorId : CounterApiError,Microsoft.PowerShell.Commands.GetCounterCommand

0

It took me a while to figure this out, but the root cause is that in-between Get-Counter retrieving the hardware process counters and processing the values, the CPU continues executing thereby changing some of the values. For instance, processes can quit (the CPU is not aware of processes, so binding CPU thread information from the hardware process counters to logical processes can fail in that step).

These links helped me tremendously as the -ErrorAction SilentlyContinue is not documented by Microsoft at Get-Counter:

Summary

Always use a construct like this to search for CPU usages on one or more processes named powershell:

(Get-Counter '\Process(*)\% Processor Time' -ErrorAction SilentlyContinue).CounterSamples | Where-Object {$_.InstanceName -eq "powershell" } | Measure-Object -Property CookedValue -Sum | Select-Object -ExpandProperty Sum

–jeroen

Posted in CommandLine, Development, PowerShell, PowerShell, Scripting, Software Development | Leave a Comment »

PowerShell: $args variable outer scope has command-line arguments – about_Automatic_Variables | Microsoft Docs

Posted by jpluimers on 2019/07/16

I always forget the exact syntax for getting command-line arguments to PowerShell. It’s the $args implicit array variable:

–jeroen

Posted in CommandLine, Development, PowerShell, PowerShell, Scripting, Software Development | Leave a Comment »

Colored text output in PowerShell console using ANSI / VT100 codes – Stack Overflow

Posted by jpluimers on 2019/07/08

Cool: Windows 10 allows ANSI/VT100 terminal escape codes without extra tooling. [WayBack] Colored text output in PowerShell console using ANSI / VT100 codes – Stack Overflow.

It is off by default (can be modified through the registry), can be turned on by either using an API call, or by piping through PowerShell.

For older versions, read [WayBack] Windows console with ANSI colors handling – Super User, of which this is a small quote:

For Windows version below 10, the Windows command console doesn’t support output coloring by default. You could install either CmderConEmuANSICON or Mintty (used by default in GitBash and Cygwin) to add coloring support to your Windows command console.

Via [WayBack] Did you know that you can enable VT100 terminal emulation in PowerShell as well as the Cmd window? This will allow you to do adb shell to your Android … – Lars Fosdal – Google+

–jeroen

Posted in Color (software development), CommandLine, Development, Power User, PowerShell, PowerShell, Scripting, Software Development, Windows | Leave a Comment »

Run cmd as elevated user (via: windows – How to run batch file command with elevated permissions? – Super User)

Posted by jpluimers on 2019/03/13

Based on [WayBack] windows – How to run batch file command with elevated permissions? – Super User:

powershell -command "Start-Process cmd.exe -Verb runas"

This works better than "runas /user:administrator cmd.exe" as that forces to use the specific Administrator account, whereas the PowerShell way allows you to specify the actual account during elevation.

You can extend this to run a command with one or more parameters based on [WayBack] Launch Elevated CMD.exe from Powershell – Stack Overflow (thanks [WayBack] mklement0):

powershell -command "Start-Process cmd.exe -Verb runas -Args /k, call, goto-bin"

This will actually pass “call goto-bin” to cmd.exe which tries to execute the “goto-bin” command (which I have around on the PATH as goto-bin.bat).

You can either use comma-separated parameters or a quoted string. In this expansion, comma-separated is easier in this PowerShell construct.

–jeroen

Posted in Batch-Files, CommandLine, Console (command prompt window), Development, Power User, PowerShell, PowerShell, Scripting, Software Development, Windows | Leave a Comment »

eventviewer – filtering on service stop/start events

Posted by jpluimers on 2018/12/27

Based on eventviewer – View Shutdown Event Tracker logs under Windows Server 2008 R2 – Server Fault « The Wiert Corner – irregular stream of stuff, I’ve made similar filters for service stop/start events.

Works on translated systems:

PowerShell
Get-EventLog System | Where-Object {$_.EventID -eq "7036"} | ft Machinename, TimeWritten, UserName, EventID, Message -AutoSize -Wrap

Or on one line:

Get-EventLog System ^| Where-Object {$_.EventID -in "6005","6006","7000","7009","7036","7040","7042","7043","7045"} ^| ft Machinename, TimeWritten, UserName, EventID, Message -AutoSize -Wrap

Note the -In operator was introduced in PowerShell 3: [WayBack]

Source: PowerShell v3 – New -in Operator | Jonathan Medd’s Blog

I’ve adapted the custom view to include all these event IDs above (note some links have disappeared moving my notes to a blog post):

  • [WayBack] 6005: The Event log service was started (indication for system startup).
  • [WayBack] 6006: The Event log service was stopped (indication for system shutdown).
  • [WayBack] 7000: The <servicename> service failed to start due to the following error:
    The service did not respond to the start or control request in a timely fashion.
  • [WayBack] 7009: A timeout was reached (30000 milliseconds) while waiting for the <servicename> service to connect.
  • [WayBack] 7036:
    • The <servicename> service entered the stopped state.
    • The <servicename> service entered the running state.
  • [WayBack] 7040: The start type of the <servicename> service was changed from demand start to auto start.
  • [WayBack] 7042: The <servicename> service was successfully sent a stop control.
  • [WayBack] 7043: The <servicename> service did not shut down properly after receiving a preshutdown control.
  • [WayBack] 7045: A service was installed in the system.

Other event IDs that might be relevant via [WayBack] Windows Server restart / shutdown history – Server Fault:

  • [WayBack] 6008: “The previous system shutdown was unexpected.” Records that the system started after it was not shut down properly.
  • [WayBack] 6009: Indicates the Windows product name, version, build number, service pack number, and operating system type detected at boot time.
  • [WayBack] 6013: Displays the uptime of the computer. There is no TechNet page for this id.
  • [WayBack] 1074: “The process X has initiated the restart / shutdown of computer on behalf of user Y for the following reason: Z.” Indicates that an application or a user initiated a restart or shutdown.
  • [WayBack] 1076: “The reason supplied by user X for the last unexpected shutdown of this computer is: Y.” Records when the first user with shutdown privileges logs on to the computer after an unexpected restart or shutdown and supplies a reason for the occurrence.
  • [WayBack] 41 (source: Microsoft-Windows-Kernel-Power)
  • [WayBack] 1001: (source: BugCheck).
  • [WayBack] 12, which is typically the first eventid to be logged after a reboot/reset etc and shows the actual “system start time”, i.e.: “The operating system started at system time ‎2017‎-‎09‎-‎19T02:46:06.582794900Z.”

A more complete list of Windows Kernel related Event IDs is at [WayBack] rootkit.com/NETEVENT.H at master · bowlofstew/rootkit.com.

Steps for the custom view:

Open Event Viewer then

  • Right click Custom Views
  • Click Create Custom View
  • Under the Filter tab
    • Keep Logged as Any time
    • Select all the Event level types (Critical, Warning, etc.)
    • Choose by source = Service Control Manager, Service Control Manager Performance Diagnostic Provider
    • Optionally; For Event ID under the Includes/Excludes Event IDs section enter 6005,6006,7000,7009,7036,7040,7042,7043,7045 for the Event ID
  • Click Ok
  • Enter a name like Shutdown Events and any description then
  • Click Ok again to complete the custom event log.

Your new custom view should show up in the list of custom views with the correct filter applied.

–jeroen

Posted in CommandLine, Development, Power User, PowerShell, PowerShell, Scripting, Software Development, Windows | Leave a Comment »

eventviewer – View Shutdown Event Tracker logs under Windows Server 2008 R2 – Server Fault

Posted by jpluimers on 2018/12/25

Works on translated systems:

PowerShell
Get-EventLog System | Where-Object {$_.EventID -eq "1074" -or $_.EventID -eq "6008" -or $_.EventID -eq "1076"} | ft Machinename, TimeWritten, UserName, EventID, Message -AutoSize -Wrap

Or on one line:

Get-EventLog System ^| Where-Object {$_.EventID -eq "1074" -or $_.EventID -eq "6008" -or $_.EventID -eq "1076"} ^| ft Machinename, TimeWritten, UserName, EventID, Message -AutoSize -Wrap

I’ve adapted the custom view to include all these event IDs above:

  • 12: The operating system started at system time ‎<iso8601utc>.
  • 13: The operating system is shutting down at system time  <iso8601utc>.
  • 109: The kernel power manager has initiated a shutdown transition.
  • 1074: [WayBack] The process <process> has initiated the restart of <computer name> for the following reason: No title for this reason could be found.
    Minor Reason: <reason>
    Shutdown Type: <type>
  • 1076: [WayBack] The reason supplied by user <user name> for the last unexpected shutdown of this computer is: <error description>
    Reason Code: <error code>
    Bug ID: <bug id>
    Bugcheck String: <string>
    Comment: <comment>
  • 6008: [WayBack] The previous system shutdown at <time> on <date> was unexpected.

Steps for the custom view:

Open Event Viewer then

  • Right click Custom Views
  • Click Create Custom View
  • Under the Filter tab
    • Keep Logged as Any time
    • Select all the Event level types (Critical, Warning, etc.)
    • Choose by source = Windows Logs > System
    • For Event ID under the Includes/Excludes Event IDs section enter 12,13,1074,1076,6008 for the Event ID
  • Click Ok
  • Enter a name like Shutdown Events and any description then
  • Click Ok again to complete the custom event log.

Your new custom view should show up in the list of custom views with the correct filter applied.

Source: [WayBackeventviewer – View Shutdown Event Tracker logs under Windows Server 2008 R2 – Server Fault

–jeroen

Posted in CommandLine, Development, Power User, PowerShell, PowerShell, Scripting, Software Development, Windows | Leave a Comment »

PowerShell: measuring size of the Windows TEMP directory

Posted by jpluimers on 2018/10/31

Due some issues in Windows, every now and then the Windows TEMP directory gets huge.

This script helps measuring the recursive size of that folder:

$WindowPath = [System.Environment]::GetFolderPath([System.Environment+SpecialFolder]::Windows)
$WindowTempPath = Join-Path -Path $WindowPath -ChildPath "TEMP"
$Result = Get-ChildItem $WindowTempPath -Recurse | Measure-Object -Property Length -Sum
$RecursiveSumInBytes = $Result.Sum
Write-Host "$RecursiveSumInBytes"

It uses these tricks:

  • Accessing native .NET types; in this case [WayBackEnvironment.SpecialFolder Enumeration (System) to get the “The Windows directory or SYSROOT. This corresponds to the %windir% or %SYSTEMROOT% environment variables. Added in the .NET Framework 4.”
  • Assuming the Windows TEMP directory is always named that way.
  • Using [WayBackJoin-Path to combine a base path with a child path without worrying about the path delimiter.
  • Recursively enumerating all items in that folder using [WayBackGet-ChildItem.
  • Aggregating with [WayBackMeasure-Object over the Length property of each Child-Item to determine their Sum.

After this, cleaning up uses two more tricks:

$WindowPath = [System.Environment]::GetFolderPath([System.Environment+SpecialFolder]::Windows)
$WindowTempPath = Join-Path -Path $WindowPath -ChildPath "TEMP"
Get-ChildItem $WindowTempPath -Recurse | foreach { Remove-Item $_.FullName -Recurse }

Inspired by:

–jeroen

Posted in CommandLine, Development, PowerShell, Software Development | Leave a Comment »

Getting Started with SOAP-Based Web Services and PowerShell

Posted by jpluimers on 2018/09/26

Since one day this could be useful:

–jeroen

Posted in CommandLine, Development, PowerShell, SOAP/WebServices, Software Development | Leave a Comment »

No it was not possible to install PowerShell 3 on a Windows Server 2003 or 2003 R2? – Super User

Posted by jpluimers on 2018/08/28

Since it was not possible to install PowerShell 3 on ancient Windows Server 2003 and Windows Server 2003 R2 machines, I opted for this workaround during the time they were being retired:

I’ve investigating how much work it will be to migrate the machine, as opposed to adapting the scripts with Poshcode/Jaykul modules (of which many have external dependencies that I’d need to check first). It’s about the same order of magnitude, so I’ll be migrating the machine earlier. In the mean time, a different machine will run the scripts and access the required data over a network share.

Source: [WayBackIs it possible to install PowerShell 3 on a Windows Server 2003 or 2003 R2? – Super User

Posted in CommandLine, Development, PowerShell, PowerShell, Scripting, Software Development | Leave a Comment »