Another grep / awk q, parsing diskpart output - powershell

I've googled this a lot and there are a lot of similar questions but I can't figure out how to put them together to make it work for me. Also, the fact that MS decided to leave dynamic volumes out of their PowerShell cmdlets is really frustrating.
In the following code I'm trying to identify that "Disk 2" is dynamic.
PS C:\Windows\system32> echo 'list disk' | diskpart
Microsoft DiskPart version 10.0.14393.0
Copyright (C) 1999-2013 Microsoft Corporation.
On computer: AHPAP2704
DISKPART>
Disk ### Status Size Free Dyn Gpt
-------- ------------- ------- ------- --- ---
Disk 0 Online 65 GB 0 B
Disk 1 Online 20 GB 0 B *
Disk 2 Offline 50 GB 0 B *
Ideally from the output above I'm going to set a variable to identify the dynamic volume (my script will always only have one) so when complete I'm left with something like $DynDisk = 2.
When I pipe the output to Get-Member the only member types containing property in the name are Chars and Length.
Is there an easy way to get the data into an array or a better method? Or, any chance there is some hidden grep and awk like cmdlets out there?

diskpart output isn't trimmed, so you can parse the relevant information from the end of the string, e.g. like this:
$re = 'disk (\d+)\s+(\w+)\s+(\d+ .?b)\s+(\d+ .?b) (.*)'
'list disk' | diskpart | Select-String -Pattern $re | ForEach-Object {
New-Object -Type PSObject -Property #{
ID = [int]$_.Matches.Groups[1].Value
Status = $_.Matches.Groups[2].Value -eq 'online'
Size = $_.Matches.Groups[3].Value
FreeSpace = $_.Matches.Groups[4].Value
Dynamic = $_.Matches.Groups[5].Value.Substring(0, 3).Trim() -eq '*'
GPT = $_.Matches.Groups[5].Value.Substring(4, 3).Trim() -eq '*'
}
}

All I needed was another half hour of googling.
https://gallery.technet.microsoft.com/DiskPartexe-Powershell-0f7a1bab
That script creates 3 objects which have properties I know now to handle

Related

Office 365 Powershell - Formatting the output of a foreach-object loop

Good evening all,
Still pretty new to Powershell but I've been trying to get some scripts together to make some of the reporting easier for a lot of the information that we need to pull from our clients' Office 365 tenants.
The script already does what I need it to (grab the subscriptions from the tenant, grab the friendly name of the subscription from my CSV, then write to the console), however my question is about the formatting: I would like to format this output in a table with the column headers Subscriptions, Active, Suspended, Assigned.
$sku = Get-MsolAccountSku | select-object skupartnumber,ActiveUnits,suspendedUnits,ConsumedUnits | sort-object -property skupartnumber
$skudata = import-csv -Header friendlyname,skupartnumber "C:\PShell\SKUs.csv" | where-object {$sku.skupartnumber -eq $_.skupartnumber} | sort-object -property skupartnumber
$skudata | foreach-object {$n = 0}{write-host $skudata.friendlyname[$n], $sku.ActiveUnits[$n], $sku.SuspendedUnits[$n], $sku.ConsumedUnits[$n]; $n = $n + 1}
## Output:
POWER BI (FREE) 1000000 0 1
MICROSOFT TEAMS EXPLORATORY 100 0 6
Here's the script and output, I'm using write-host right now because this formats the data in the same way that we already want it and I can easily copy it out of the console and in to our tickets. When I use write-output, however, it puts each cell on its own line and I can't seem to figure out how to pipe this in to format-table .
$skudata | foreach-object {$n = 0}{write-output $skudata.friendlyname[$n], $sku.ActiveUnits[$n], $sku.SuspendedUnits[$n], $sku.ConsumedUnits[$n]; $n = $n + 1}
# Output:
POWER BI (FREE)
1000000
0
1
MICROSOFT TEAMS EXPLORATORY
100
0
6
I'm already able to get everything I need using the below hash table and simple script, the only problem is that it can't pull the common subscription name and Microsoft's skupartnumber identifier is the best option which isn't always very descriptive. I'm sure there's some very simple solution I'm just missing, but if anyone could point me in the right direction for either solution I've tried it would be greatly appreciated!
$subs = #{Label="Subscription"; Expression={$_.skupartnumber}; Alignment = "right";}
$active = #{Label="Active"; Expression={$_.ActiveUnits}; Alignment = "right"}
$assigned = #{Label="Assigned"; Expression={$_.ConsumedUnits}; Alignment = "right"}
$suspended = #{Label="Suspended"; Expression={$_.SuspendedUnits}; Alignment = "right"}
Get-MsolAccountSku | Format-Table $subs, $active, $suspended, $assigned -autosize
# Output:
Subscription Active Suspended Assigned
------------ ------ --------- --------
POWER_BI_STANDARD 1000000 0 1
TEAMS_EXPLORATORY 100 0 6
PowerShell is an object oriented language and what you need is to gather the info you want in objects for further processing or output.
Try
$result = for ($n = 0; $n -lt $skudata.Count; $n++) {
# output the data as PSObject that gets collected in variable $result
[PsCustomObject]#{
Subscription = $skudata.friendlyname[$n]
Active = $sku.ActiveUnits[$n]
Suspended = $sku.SuspendedUnits[$n]
Assigned = $sku.ConsumedUnits[$n]
}
}
# output on screen
$result | Format-Table -AutoSize
# output to CSV
$result | Export-Csv -Path "C:\PShell\SkuUsage.csv" -NoTypeInformation

How to process out put of diskpart command using PowerShell

I'm trying to capture volume number from diskpart command output. At present I'm doing it like this:
Using batch script:
#echo off
set VOLNO=''
set DRIVE=C
for /f "tokens=2,3" %%a in ('echo list volume ^| diskpart') do (
if %%b==%DRIVE% set VOLNO=%%a
)
echo Volume No. for C Drive is: %VOLNO%
Output:
Volume No. for C Drive is: 2
Using PowerShell:
$dp = "list volume" | diskpart | ? { $_ -match "^ [^-]" }>
$dp
Output:
Volume ### Ltr Label Fs Type Size Status Info
Volume 0 E DVD-ROM 0 B No Media
Volume 1 System Rese NTFS Partition 350 MB Healthy System
Volume 2 C NTFS Partition 59 GB Healthy Boot
Volume 3 D New Volume NTFS Partition 49 GB Healthy
I want to capture the Volume-Number e.g. it's 2 for C:\ to a variable using PowerShell.
Adjust your regular expression so that you can extract the desired information via capturing groups. I generally recommend building custom objects from the extracted information, to facilitate further processing.
Something like this should do what you want:
$drive = 'c'
'list volume' | diskpart | Where-Object {
$_ -match 'Volume (\d+)\s+([a-z])\s+'
} | ForEach-Object {
New-Object -Type PSObject -Property #{
'DriveLetter' = $matches[2]
'VolumeNumber' = [int]$matches[1]
}
} | Where-Object {
$_.DriveLetter -eq $drive
} | Select-Object -Expand VolumeNumber
A concise solution that uses -match to find the line of interest and the unary form of -split to split it into whitespace-separated tokens that can be accessed by index:
$drive = 'C'
$volNo = (-split (('list volume' | diskpart) -match " $drive "))[1]
"Volume No. for $drive Drive is: $volNo"
Note that diskpart must be run from an elevated session.

How to Get Actual Hard Disk Memory of A VM?

Is it possible to get the actual hard disk usage of a virtual machine?
Measure-VM -Name * | select-object -property TotalDiskAllocation
The TotalDiskAllocation property gets the total disk space assigned to the VM and even though this is helpful I also need to know how much is really being used.
For example, if a VM has 150 GB of allocated memory and it only uses 50 GB, is there any Powershell command that will be able to extract the 50 GB? If yes, how will I be able to incorporate that script to the script above?
Based on your attempt to use Measure-VM, I assumed you are using Hyper-V. I use something similar to this in one of my Hyper-V scripts:
(Get-VM dechiro1).HardDrives | ForEach {
$GetVhd = Get-VHD -Path $_.Path
[pscustomobject]#{
Name = $_.Name
Type = $GetVhd.VhdType
ProvisionedGB = ($GetVhd.Size / 1GB)
CommittedGB = ($GetVhd.FileSize / 1GB)
}
}
Basically, for each of the virtual machine's hard drives, use Get-VHD to get the VHD details which includes the full size and what I refer to as the committed size (actual space on disk).
Example output:
Name Type ProvisionedGB CommittedGB
---- ---- ------------- -----------
Hard Drive on IDE controll... Dynamic 20 0.00390625
Hard Drive on IDE controll... Dynamic 40 0.00390625
Edit:
If you wanted to pull from every VM and include the VM name with the returned object and you prefer to use the pipeline form, this will work:
Get-VM | ForEach { $Vm = $_; $_.HardDrives } | ForEach {
$GetVhd = Get-VHD -Path $_.Path
[pscustomobject]#{
Vm = $Vm.Name
Name = $_.Name
Type = $GetVhd.VhdType
ProvisionedGB = ($GetVhd.Size / 1GB)
CommittedGB = ($GetVhd.FileSize / 1GB)
}
}

Powershell get process name (with #) by PID when multiple instances

I am trying to use Get-Counter '\process(APPNAME)\% processor time however for many processes APPNAME repeats. I can use APPNAME#1, APPNAME#2, APPNAME#3 in Get-Counter '\process(APPNAME#2)\% processor time. However, I can't find how to get the "full" appname (i.e the one that has # in it) from just the PID, is this possible?
The second answer here seems to explain it, but I don't understand exactly what they are doing.
Difficult to help you on this accurately because counters are culture sensitive and I'am too lazy to start my US VM.
You can find the PID of a process using :
Get-Counter '\\ComputerName\processus(chrome#4)\id de processus'
For me it gives :
Timestamp CounterSamples
--------- --------------
29/10/2015 08:31:55 \\ComputerName\processus(chrome#4)\id de processus :
3296
For UK or US I would try :
Get-Counter '\\ComputerName\process(chrome#4)\process id'
This One Line (that you have to adapt to your culture) gives a process list with PIDs and counter instance Id.
(Get-Counter '\processus(*)\id de processus').CounterSamples | % {[regex]$a = "^.*\($([regex]::Escape($_.InstanceName))(.*)\).*$";[PSCustomObject]#{InstanceName=$_.InstanceName;PID=$_.CookedValue;InstanceId=$a.Matches($($_.Path)).groups[1].value}}
Edited :
So here is a solution with the PID in input :
$p = $((Get-Counter '\processus(*)\id de processus' -ErrorAction SilentlyContinue).CounterSamples | % {[regex]$a = "^.*\($([regex]::Escape($_.InstanceName))(.*)\).*$";[PSCustomObject]#{InstanceName=$_.InstanceName;PID=$_.CookedValue;InstanceId=$a.Matches($($_.Path)).groups[1].value}})
$id = # your process id
$p1 = $p | where {$_.PID -eq $id}
Get-Counter -Counter "\Process($($p1.InstanceName+$p1.InstanceId))\% Processor Time"
# In french
# Get-Counter -Counter "\Processus($($p1.InstanceName+$p1.InstanceId))\% temps processeur"
you need something like this, select the items you need, and after that join them together.
Get-Process | Select ProcessName,Id | % {$_.ProcessName + " " + $_.Id}

Change powershell script to output without ellipses (...)

I need some help with the output of the following script so the output doesn't show with the ellipses (...).
I tried to insert | Format-Table -Wrap -AutoSize but I just can't seem to get it right.
clear-host Add-PSSnapin microsoft.sharepoint.powershell -ErrorAction SilentlyContinue
$services = new-object system.collections.sortedlist
$servers = (get-spfarm).servers
foreach ($server in $servers) {
foreach($service in $server.serviceinstances)
{
if ($service.status = "Online")
{
$s = $service.typename
if ($services.contains($s))
{
$serverlist = $services[$s]
$servername = $server.name
$services[$s] = "$serverlist - $servername"
}
else
{
$services[$s] = $server.name
}
}
} }
$services
output:
Name Value
---- -----
Access Database Service SE5APP - SE5FE - SE7FE - FAQ3
Application Discovery **and L...** SE5APP - SE5FE - SE7FE - FAQ3
Application Registry Service SE5APP - SE5FE - SE7FE - FAQ3
Either Format-List (fl) or Format-Table -auto (ft -auto) should help here.
$services | fl
OR
$services | ft -auto
I came across this post and would like to add some information, as the accepted solution did not resolve my problem and I'm sure others may find the following information useful:
Quick Story: Running commands using Microsoft Online Services Module with Powershell, much of the results were continually be retrieved as truncated with data cutoff and missing as an ellipsis (...).
The fix: As explained in this post by Greig, I inevitably came to the conclusion $FormatEnumerationLimit=-1 is the unlimate solution to the problem. Using any variant of Format-Wide, Format-List, Format-Table, Format-Custom, -AutoSize, Out-String -Width, etc. require a hefty amount of additional considerations/code. In the case where all you want is to see all the data being returned, regardless of columns, arrays, etc., $FormatEnumerationLimit=-1 ensures you will get everything and you don't need to mess around.
Additional information, as credited in Greig's post include:
PowerShell Quick Tip: Creating wide tables with PowerShell, where the author explains:
If you have a specific property that contains a collection of items,
that property may still show an ellipsis in the file produced here if
the number of items in that collection exceeds the number assigned to
the built-in $FormatEnumerationLimit variable.
...and that "passing the results to | Format-Table -Property * [will] show all of the columns." But content from the columns may still be truncated ("PowerShell truncates table output by default"), and that even using | Format-Table -Property * -AutoSize will be limited by your screen buffer
("Auto-sized tables are limited to the width of your screen buffer"). The solution offered, before the absolute $FormatEnumerationLimit=-1, seems to be using | Format-Table -Property * -AutoSize in conjunction with | Out-String -Width 4096 or whatever width you require.
Using Format Commands to Change Output View provides some more delailed documentation on the Format cmdlets: Format-Wide, Format-List, and Format-Table.
What I do in this situation is to create a format description then use that as an argument to my Format-Table command. I've developed a function (Get-MaxLength) to examine the data field with the longest data (helps to have this at the end of the format description) and set the width in the format description with the value it returns. You can see the calculations in the code below. Notice the Number value for the Intel(4) Management Engine Interface. Also notice the use of -Wrap on the Format-Table command. This concept can be modified to calculate all fields widths or just the last one, it's just a little math.
Function Get-MaxLength {
<#
.SYNOPSIS
Finds the length of the longest item in collection.
.DESCRIPTION
Use this Function to get the length of the longest item in a
collection for use in format strings or other places where
needed.
.PARAMETER TestObj
The qualified object to be tested. See example!
.Parameter MinLen
The minimum length of the item (if using for formatting) which
should be the Label (title) length. Note if the object item
being tested does not have a Length property you MUST specify
the label length!
.OUTPUTS
Returns a numerical value
.EXAMPLE
$NameLen = Get-MaxLength -TestObj $DotNet.PSChildName
$VerLen = Get-MaxLength -TestObj $DotNet.Version
$RNLen = Get-MaxLength -TestObj $DotNet.Release -MinLen 11
#--- .Net Information ---
$fmtDotNet =
#{Expression={$_.PSChildName};Label=".Net Type";Width=$NameLen},
#{Expression={$_.Version};Label="Version No:";Width=$VerLen},
#{Expression={$_.Release};Label="Release No:";Width=$RNLen}
$Dotnet | Format-Table $fmtDotNet
#>
Param(
[Parameter(Mandatory=$True)]
[object] $TestObj,
[Parameter(Mandatory=$False)]
[int] $MinLen = 0,
[Parameter(Mandatory=$False)]
[int] $MaxLen = 0
)
$ErrorActionPreference = "SilentlyContinue"
foreach ($x in $TestObj) {
If ($x.Trim().length -gt $MinLen) {
$MinLen = $x.Trim().length
}
}
If ($MaxLen -ne 0) {
If ($MinLen -gt $MaxLen) {
$MinLen = $MaxLen
}
}
$ErrorActionPreference = "Continue"
Return ,$MinLen
} #End Function ----------- Get-MaxLength -------------------
$OstrWidth = 80
$DriverInfo =
Get-CimInstance -ClassName 'Win32_PNPSignedDriver' |
Where-Object -Property DriverProviderName -ne "Microsoft" |
Where-Object -Property DeviceName -ne -Value $Null |
Sort-Object -Property DeviceName -Unique
$DriverCnt = $DriverInfo.Count
$DVLen =
Get-MaxLength -TestObj $DriverInfo.DriverVersion -MinLen 14
$DDLen = $OstrWidth - $DVLen
$fmtDRVR = #{Label="`nDriver Description";Width=$DDLen;
Expression={$_.DeviceName}},
#{Label="Version Number"; Width=$DVLen;
Expression={$_.DriverVersion}}
$DrvTitle = "$($DriverCnt) Non-Windows Unique Drivers and " +
"Version Numbers:" | Out-String
$DriverInfo =
$DriverInfo | Format-Table -Property $fmtDRVR -Wrap |
Out-String -Width $OStrWidth
Sample Output:
Driver Description Number
------------------- -------------
Alcor Micro USB 2.0 Card Reader 2.0.150.10135
ASMedia USB3.1 eXtensible Host Controller 1.16.42.1
...
Intel(R) HD Graphics 630 21.20.16.4550
Intel(R) Management Engine Interface 1914.12.0.125
6
Intel(R) Ready Mode Technology Device 1.2.0.0
...
Realtek Audio 6.0.1.8248
Samsung NVMe Controller 3.0.0.1802