Improving the speed of PowerShell commands in Windows 2016 - powershell

Example of a problem:
Measure-Command { Get-VMSwitch -SwitchType "External" }
Windows 2012 and 2016 have the same hardware and CPU load is ~50%
Windows Server 2016 (3 external Switches)
Days : 0
Hours : 0
Minutes : 0
Seconds : 6
Milliseconds : 377
Ticks : 63779086
TotalDays : 7.38183865740741E-05
TotalHours : 0.00177164127777778
TotalMinutes : 0.106298476666667
TotalSeconds : 6.3779086
TotalMilliseconds : 6377.9086
Windows Server 2012R2 (3 external Switches)
Days : 0
Hours : 0
Minutes : 0
Seconds : 1
Milliseconds : 376
Ticks : 13762494
TotalDays : 1.59288125E-05
TotalHours : 0.0003822915
TotalMinutes : 0.02293749
TotalSeconds : 1.3762494
TotalMilliseconds : 1376.2494
Windows 2012R2 with a greater or equal CPU load is 6 times faster.
Windows Server 2016 (9 external Switches)
Days : 0
Hours : 0
Minutes : 1
Seconds : 6
Milliseconds : 168
Ticks : 661689307
TotalDays : 0.000765844105324074
TotalHours : 0.0183802585277778
TotalMinutes : 1.10281551166667
TotalSeconds : 66.1689307
TotalMilliseconds : 66168.9307
Windows 2016 slower now 48 times! :)
In Windows 2016 Meltdown/Specter fixes are disabled.
Is there any option for improving the performance of powershell commands in Windows 2016?
Thanks.

Well, I found another solution. It's using bottlenecks through WMI.
The WMI msvm-ethernetswitchport class can provide all the VMSwitches elements, where we can already get the same information that Powershel CMD Get-VMSwitch provides.
https://learn.microsoft.com/en-us/windows/desktop/hyperv_v2/msvm-ethernetswitchport and etc.
A simple example:
ManagementScope scope = new ManagementScope("\\\\.\\ROOT\\virtualization\\v2");
ObjectQuery query = new ObjectQuery("SELECT * FROM Msvm_EthernetSwitchPort");
ManagementObjectSearcher searcher =
new ManagementObjectSearcher(scope, query);
ManagementObjectCollection queryCollection = searcher.Get();
foreach (ManagementObject m in queryCollection)
{
Console.WriteLine("DeviceID : {0}", m["DeviceID"]);
Console.WriteLine("ElementName : {0}", m["ElementName"]);
}
It's sad that PowerShell in Windows 2016 runs so slowly...
In fact, through WMI there are so many options how to get this data.
https://learn.microsoft.com/en-us/windows/desktop/hyperv_v2/hyper-v-networking-api

Related

Powershell get timezone with DST

In powershell I'm using
(Get-Timezone).BaseUtcOffset
to get the UTC offset of a computer which gives me +1h for my timezone. That is technically correct since I'm in CET in winter (UTC+1) and CEST in summer (UTC+2). Right now tho it is DST, so CEST (UTC+2) for me so I'm wondering how I could get this information in powershell since the above command tells me that my timezone is UTC+1 and doesn't mention DST at all.
As a workaround I currently use
$date = Get-Date
($date - $date.ToUniversalTime()).TotalMinutes
to get the offset from UTC of my timezone with DST. It evaluates to +120 minutes which is exactly what i need.
Output of Get-Timezone:
Id : W. Europe Standard Time
DisplayName : (UTC+01:00) Amsterdam, Berlin, Bern, Rom, Stockholm, Wien
StandardName : Mitteleuropäische Zeit
DaylightName : Mitteleuropäische Sommerzeit
BaseUtcOffset : 01:00:00
SupportsDaylightSavingTime : True
Output of $date - $date.ToUniversalTime():
Days : 0
Hours : 2
Minutes : 0
Seconds : 0
Milliseconds : 0
Ticks : 72000000000
TotalDays : 0,0833333333333333
TotalHours : 2
TotalMinutes : 120
TotalSeconds : 7200
TotalMilliseconds : 7200000
Yes, you can use the static method IsDaylightSavingTime on the TimeZoneInfo class to get this information from a desired DateTime:
$now = [DateTime]::Now
[System.TimeZoneInfo]::Local.IsDaylightSavingTime($now) # Returns $True or $False
thank you Bender the Greatest you got me on the right path. The class System.TimeZoneInfo has a function that does what i want:
[System.TimeZoneInfo]::Local.GetUtcOffset((Get-Date)).TotalMinutes
gives me +120 minutes

retrieving RDS license

I have a question, iam running a PowerShell command to retrieved RDS LicenseKeyPack details, according to win32-tslicensekeypack KeyPackType should a number between 0 and 6, yet i am getting 7 on some outputs. What dose this mean?.
Example output:
KeyPackId : 3
KeyPackType : 2
ProductVersion : Windows Server 2016
TypeAndModel : RDS Per User CAL
AvailableLicenses : 48
IssuedLicenses : 1202
ExpirationDate : 20380101000000.000000-000
KeyPackId : 5
KeyPackType : 7
ProductVersion : Windows Server 2012
TypeAndModel : RDS Per User CAL
AvailableLicenses : 0
IssuedLicenses : 1
ExpirationDate : 20380119031407.000000-000
KeyPackId : 7
KeyPackType : 7
ProductVersion : Windows Server 2016
TypeAndModel : RDS Per User CAL
AvailableLicenses : 0
IssuedLicenses : 49
ExpirationDate : 20380119031407.000000-000"

How can I filter .content from a invoke-webrequest command

I have an internal web app that provides connection statistics. I am trying to use PS to collect those statistics, which are in .conent. The .content property has a lot of other values I am trying to filter out and I haven't been very successful.
My Command:
invoke-webrequest -URI http://<my internal web site> | Select-Object -ExpandProperty Content
Returned Results:
Greetings from live node: server-name [ FQDN ] , serving at port: 443 since [4 days, 0 hour, 3
3 minutes, 33 seconds] with following settings:
IN_MEMORY_MESSAGE_LIFE_IN_HOURS : 1
DELIVERY_GRACE_WINDOW_IN_SECONDS : 10
BUILD_NUMBER : 4
STATISTICS_LOG_FREQUENCY_IN_MINUTES : 0
HEARTBEAT_INTERVAL_IN_MINUTES : 2
CLUSTERING_MODE : IMPLICIT
CLEAN_ORPHANED_SESSIONS : Y
OFFLOAD_SSL : Y
SERVICE_HOST : 192.168.1.1
REQUEST_TIMEOUT_MILLIS : 3000
SERVICE_PORT : 443
VALIDATE_REQUEST_CONTENT_TYPE : N
APP_BROADCAST_LIFE_IN_MINUTES : 1
DEFAULT_MESSAGE_LIFE_IN_DAYS : 1
VERSION : release/2008
ENABLE_IDLER_STATISTICS : Y
ORIGIN_STATS_EXPIRY_IN_MINUTES : 60
INCLUDE_CACHE_CONTROL_HEADER_IN_HEALTH_CHECK : N
DATABASE_PROVIDER : INMEMORY
QUEUEMONITOR_THREADPOOLSIZE : 100
BUILD_DATE : Mon 27 Jul 2020 10:02:44 AM EDT -0400
BUILD_PLAN : AWCM-AWCM302-JOB1-4
Persistence Store Type:INMEMORY , status: live
Current Active Sessions: 6
They only line I care about is "Current Active Sessions: 6" and really all I care about is the numerical value which I will use in a test later in the script.
How can I just grab the one value I need?
$iwr=invoke-webrequest -URI http://<my internal web site> |
Select-Object -ExpandProperty Content
$cas=$iwr -split [System.Environment]::NewLine |
Select-String -Pattern "Current Active Sessions:\s*(.*)"
$cas.Matches[0].Groups[1].Value
Above code snippet should return 6. Tested using the following (constant) value of $iwr instead of invoke-webrequest:
$iwr=#'
Greetings from live node: server-name [ FQDN ] , serving at port: 443 since [4 days, 0 hour, 3
3 minutes, 33 seconds] with following settings:
IN_MEMORY_MESSAGE_LIFE_IN_HOURS : 1
DELIVERY_GRACE_WINDOW_IN_SECONDS : 10
BUILD_NUMBER : 4
STATISTICS_LOG_FREQUENCY_IN_MINUTES : 0
HEARTBEAT_INTERVAL_IN_MINUTES : 2
CLUSTERING_MODE : IMPLICIT
CLEAN_ORPHANED_SESSIONS : Y
OFFLOAD_SSL : Y
SERVICE_HOST : 192.168.1.1
REQUEST_TIMEOUT_MILLIS : 3000
SERVICE_PORT : 443
VALIDATE_REQUEST_CONTENT_TYPE : N
APP_BROADCAST_LIFE_IN_MINUTES : 1
DEFAULT_MESSAGE_LIFE_IN_DAYS : 1
VERSION : release/2008
ENABLE_IDLER_STATISTICS : Y
ORIGIN_STATS_EXPIRY_IN_MINUTES : 60
INCLUDE_CACHE_CONTROL_HEADER_IN_HEALTH_CHECK : N
DATABASE_PROVIDER : INMEMORY
QUEUEMONITOR_THREADPOOLSIZE : 100
BUILD_DATE : Mon 27 Jul 2020 10:02:44 AM EDT -0400
BUILD_PLAN : AWCM-AWCM302-JOB1-4
Persistence Store Type:INMEMORY , status: live
Current Active Sessions: 6
'#
Try this:
$iwr=invoke-webrequest -URI http://<my internal web site> | Select-Object -ExpandProperty Content
$iwr|Select-String -Pattern "Current Active Sessions: (.*)"

How to format output to DD, HH, MM

I'm trying to work out a devices up time using PowerShell. My code is as so:
$wmi = Get-WmiObject -Class Win32_OperatingSystem
$upTime = $wmi.ConvertToDateTime($wmi.LocalDateTime) – $wmi.ConvertToDateTime($wmi.LastBootUpTime)
When I call $upTime, it returns the following:
Days : 0
Hours : 1
Minutes : 8
Seconds : 5
Milliseconds : 311
Ticks : 40853110010
TotalDays : 0.0472836921412037
TotalHours : 1.13480861138889
TotalMinutes : 68.0885166833333
TotalSeconds : 4085.311001
TotalMilliseconds : 4085311.001
While I can see the up time, I need to specifically format the output to D:dd, H:hh, M:mm as I will be automatically feeding this into a monitoring system, but after much searching on here, google etc, I can't see how to achieve this. Can anyone suggest how to go about doing this?
Try:
"D:{0:dd}, H:{0:hh}, M:{0:mm}" -f $upTime
alternatively, if you like to escape lots of things:
$upTime.ToString('\D\:dd\,\ \H\:hh\,\ \M\:mm')
This will format the string to have 2 leading zeros when ether days, hours or seconds is 0. And 1 leading zero if they are 1-9.
"D:01, H:02, M:23"
You can format it in normal .NET style
$UptimeStr = $Uptime.ToString("ddd:dd, H:hh, mmm:mm")
or
$UptimeStr = '{0:ddd:dd, H:hh, mmm:mm}' -f $Uptime
If the above formatting is not what you wanted the formatting is explained on MSDN

How to get a child item into a variable on its own

I am relatively sure this is quite easy to do but my google fu is not running strong
At the moment I am doing:
add-pssnapin windows.serverbackup
get-wbsummary
This returns me:
NextBackupTime : 07/09/2012 12:00:00
NumberOfVersions : 210
LastSuccessfulBackupTime : 06/09/2012 21:00:13
LastSuccessfulBackupTargetPath : \\?\Volume{bf315689-e5ed-11e1-a376-d067e5f384ea}
LastSuccessfulBackupTargetLabel : SBSERVE 2012_08_21 12:20 DISK_01
LastBackupTime : 06/09/2012 21:00:13
LastBackupTarget : SBSERVE 2012_08_21 12:20 DISK_01
DetailedMessage :
LastBackupResultHR : 0
LastBackupResultDetailedHR : 0
CurrentOperationStatus : NoOperationInProgress
What I want to do is get just the result portion (not its title into a variable) so for example $lastbackuptime = 07/09/2012 12:00:00
PS> $wbs = Get-WBSummary
PS> $lastbackuptime = $wbs.NextBackupTime