How to format piped output in powershell to a line - powershell

I have a script powershell to get PercentProcessorTime of processes.
$Processes = (get-wmiobject Win32_PerfFormattedData_PerfProc_Process)
$Processes | %{ New-Object psobject -Property `
#{ Time = $_.PercentProcessorTime;
Name = ($_.name -replace "#\d+", "" )}}`
| ?{ $_.Name -notmatch "_Total|Idle" } `
| Group-Object Name `
| %{ New-Object psobject -Property `
#{ Name = $_.Name;
Sum = ($_.Group | Measure-Object Time -Sum ).Sum }} `
| Format-Table
Format of result as below:
But I want to format result as below to insert to database:
OK |Idle=100 System=6 smss=0 csrss=0 wininit=0 services=0 lsass=0 lsm=0 svchost=18 ICTrigger=0 nvvsvc=0 ICDCMGR64=0 svchost#2=0 winlogon=0 svchost#3=0 svchost#4=0 svchost#5=0 igfxCUIService=0 svchost#6=0 spoolsv=0 svchost#7=0 armsvc=0 ShieldStart=0 svchost#8=0 GateMan=0 HeciServer=0 Jhi_service=0 NHCAAgent=0 nvxdsync=0 nvvsvc#1=0 nscp=0 PaSvc=0 pcdrmsvc=0 NSCHIM=0 ASDSvc=0 secugate64=0 WindowsSecuService=0 WinFil32=0 WmiPrvSE=0 svchost#9=0 papersrv64=0 WUDFHost=0 svchost#10=0 svchost#11=0 WmiP rvSE#1=0 PaTray=0 unsecapp=0 WmiPrvSE#2=0 LMS=0 SWMAgent=0
Please help me to solve it.
Thanks very much ^^

I don't think there is an "easy", builtin command for it, but it doesn't take much to update the function to do what you want:
$Processes = (get-wmiobject Win32_PerfFormattedData_PerfProc_Process)
$procStrings = #()
$Processes | %{ New-Object psobject -Property `
#{ Time = $_.PercentProcessorTime;
Name = ($_.name -replace "#\d+", "" )}}`
| ?{ $_.Name -notmatch "_Total|Idle" } `
| Group-Object Name `
| %{
$procStrings += "$($_.Name)=$(($_.Group | Measure-Object Time -Sum ).Sum)"}
$procStrings -join " "
Basically, I added an array to hold the string key/value paris and replaced the final New-Object with code to create the desired string. Finally it is joined with spaces to create the final string.
You could absolutely skip the array part and just build up the string directly, instead of creating an array, I just like that approach :)
It doesn't include the "OK |" in the beginning, i don't know what you constitutes an OK, but I'm sure you can add yourself to get what you want :)

Related

Not able find datastore.totalReadLatency.average using Get-StatType

I am trying to find Latency for a datastore.
below is the code
$vmName = ""
$stat = "datastore.totalReadLatency.average","datastore.totalWriteLatency.average"
$entity = Get-VM -Name $vmName | select -Unique
$start = (Get-Date).AddHours(-1)
$dsTab = #{}
$dsTab = Get-Datastore | Where {$_.Type -eq "VMFS"} | %{
$key = $_.ExtensionData.Info.Vmfs.Uuid
if(!$dsTab.ContainsKey($key)){
$dsTab.Add($key,$_.Name)
}
else{
"Datastore $($_.Name) with UUID $key already in hash table"
}
}
Get-Stat -Entity $entity -Stat $stat -Start $start |
Group-Object -Property {$_.Entity.Name} | %{
$vmName = $_.Values[0]
$VMReadLatency = $_.Group |
where {$_.MetricId -eq "datastore.totalReadLatency.average"} |
Measure-Object -Property Value -Average |
Select -ExpandProperty Average
$VMWriteLatency = $_.Group |
where {$_.MetricId -eq "datastore.totalWriteLatency.average"} |
Measure-Object -Property Value -Average |
Select -ExpandProperty Average
$VMReadIOPSAverage = $_.Group |
where {$_.MetricId -eq "datastore.numberReadAveraged.average"} |
Measure-Object -Property Value -Average |
Select -ExpandProperty Average
$VMWriteIOPSAverage = $_.Group |
where {$_.MetricId -eq "datastore.numberWriteAveraged.average"} |
Measure-Object -Property Value -Average |
Select -ExpandProperty Average
$_.Group | Group-Object -Property Instance | %{
New-Object PSObject -Property #{
VM = $vmName
Host = $_.Group[0].Entity.Host.Name
Datastore = $dsTab[$($_.Values[0])]
Start = $start
DSReadLatencyAvg = [math]::Round(($_.Group |
where {$_.MetricId -eq "datastore.totalReadLatency.average"} |
Measure-Object -Property Value -Average |
Select -ExpandProperty Average),2)
DSWriteLatencyAvg = [math]::Round(($_.Group |
where {$_.MetricId -eq "datastore.totalWriteLatency.average"} |
Measure-Object -Property Value -Average |
Select -ExpandProperty Average),2)
VMReadLatencyAvg = [math]::Round($VMReadLatency,2)
VMWriteLatencyAvg = [math]::Round($VMWriteLatency,2)
VMReadIOPSAvg = [math]::Round($VMReadIOPSAverage,2)
VMWriteIOPSAvg = [math]::Round($VMWriteIOPSAverage,2)
}
}
} | Export-Csv c:\report.csv -NoTypeInformation -UseCulture
When I check with any datastore, I am not able to find stat "datastore.totalReadLatency.average","datastore.totalWriteLatency.average"
Please let me know what is wrong I am doing or is there anything which needs to be done ( any update/Installation )
Running your
Get-Stat -Entity $entity -Stat $stat -Start $start
in PowerCLI v12.4 I see errors like below and no data returned
The metric counter "datastore.totalreadlatency.average" doesn't exist for
entity <$vmname>
which led me to this thread where the solution code looks close to yours. Anyway, using -Realtime seems to fix that piece for your last-hour scenario. Offhand I'm not sure if something changed in recent versions, or what.
Not finding this documented, but Get-Stat appears to ignore -Start when -Realtime is specified. So try
Get-Stat -Entity $entity -Stat $stat -Realtime
(Maybe you grabbed the $stat definition from the first answer in that thread, but grabbed the remaining code from the accepted answer? You're attempting to parse results for numberReadAveraged & numberWriteAveraged without gathering those results.)
To look beyond realtime/last-hour, you'd need collection level 3 or higher for totalReadLatency and totalWriteLatency. Increasing stat levels will grow the vCenter db.

Change variable specific text with powershell and create a table

I'm trying to change some words inside a variable that contains a table.
I was able to do it using a foreach with -replace but then I can't form again the table.
1st try
$vms = Get-AZVm -status | Select-Object -Property Name, ResourceGroupName , PowerState
$tabla = foreach ($item in $vms) {
$item.Name
$item.ResourceGroupName
$item.PowerState -replace 'VM Deallocated','Apagada' -replace 'VM running','Encendida'
} | Format-Table
2nd try
$vms |foreach{$_.PowerState -replace 'VM Deallocated','Apagada' -replace 'VM running','Encendida'} | Select-Object -Property Name, ResourceGroupName , PowerState | format-table -autosize
I expect after the replacement of text inside the table to leave the same as a table and not text
I cannot test this myself, but I think using a calculated property would be easiest:
$vms = Get-AzVM -status |
Select-Object -Property Name, ResourceGroupName,
#{Name = 'PowerState'; Expression = {($_.PowerState -replace 'VM Deallocated','Apagada') -replace 'VM running','Encendida'}}
$vms | Format-Table -AutoSize
I would create my table inside an array and set its content...
$vms = Get-AZVm -status | Select-Object -Property Name, ResourceGroupName , PowerState
$tabla = #{
"Name" = ""
"ResourceGroupName" = ""
"PowerState" = ""
}
foreach ($item in $vms) {
$record."Name" = $item.Name
$record."ResourceGroupName" = $item.ResourceGroupName
$record."PowerState" = $item.PowerState -replace 'VM Deallocated','Apagada' -replace 'VM running','Encendida'
$objRecord = New-Object PSObject -Property $record
$tabla += $objRecord
}
$tabla

Reading txt-file, change rows to columns, save txt file

I have a txt files (semicolon separated) containing over 3 million records where columns 1 to 4 have some general information. Columns 5 and 6 have detailed information. There can be up to 4 different detailed information for the same general information in columns 1 to 4.
My sample input:
Server;Owner;Company;Username;Property;Value
Srv1;Dave;Sandbox;kwus91;Memory;4GB
Srv1;Dave;Sandbox;kwus91;Processes;135
Srv1;Dave;Sandbox;kwus91;Storage;120GB
Srv1;Dave;Sandbox;kwus91;Variant;16
Srv2;Pete;GWZ;aiwq71;Memory;8GB
Srv2;Pete;GWZ;aiwq71;Processes;234
Srv3;Micael;P12;mxuq01;Memory;16GB
Srv3;Micael;P12;mxuq01;Processes;239
Srv3;Micael;P12;mxuq01;Storage;160GB
Srv4;Stefan;MTC;spq61ep;Storage;120GB
Desired output:
Server;Owner;Company;Username;Memory;Processes;Storage;Variant
Srv1;Dave;Sandbox;kwus91;4GB;135;120GB;16
Srv2;Pete;GWZ;aiwq71;8GB;234;;
Srv3;Micael;P12;mxuq01;16GB;239;160GB;
Srv4;Stefan;MTC;spq61ep;;;120GB;
If a values doesn't exist for general information (Columns 1-4) it has to stay blank.
My current code:
$a = Import-csv .\Input.txt -Delimiter ";"
$a | FT -AutoSize
$b = #()
foreach ($Server in $a.Server | Select -Unique) {
$Props = [ordered]#{ Server = $Server }
$Owner = ($a.where({ $_.Server -eq $Server})).Owner | Select -Unique
$Company = ($a.where({ $_.Server -eq $Server})).Company | Select -Unique
$Username = ($a.where({ $_.Server -eq $Server})).Username | Select -Unique
$Props += #{Owner = $Owner}
$Props += #{Company = $Company}
$Props += #{Username = $Username}
foreach ($Property in $a.Property | Select -Unique){
$Value = ($a.where({ $_.Server -eq $Server -and
$_.Property -eq $Property})).Value
$Props += #{ $Property = $Value }
}
$b += New-Object -TypeName PSObject -Property $Props
}
$b | FT -AutoSize
$b | Export-Csv .\Output.txt -NoTypeInformation -Delimiter ";"
After a lot of trying and getting errors: My script works.
But it takes a lot of time.
Is there a possibility to make performance better for around 3 Million lines in txt file? I'm calculating with more or less 2.5 Million unique values for $Server.
I'm running Windows 7 64bit with PowerShell 4.0.
try Something like this:
#Import Data and create empty columns
$List=import-csv "C:\temp\file.csv" -Delimiter ";"
#get all properties name with value not empty
$ListProperty=($List | where Value -ne '' | select property -Unique).Property
#group by server
$Groups=$List | group Server
#loop every rows and store data by group and Property Name
$List | %{
$Current=$_
#Take value not empty and group by Property Name
$Group=($Groups | where Name -eq $Current.Server).Group | where Value -ne '' | group Property
#Add all property and first value not empty
$ListProperty | %{
$PropertyName=$_
$PropertyValue=($Group | where Name -eq $PropertyName | select -first 1).Group.Value
$Current | Add-Member -Name $PropertyName -MemberType NoteProperty -Value $PropertyValue
}
$Current
} | select * -ExcludeProperty Property, Value -unique | export-csv "c:\temp\result.csv" -notype -Delimiter ";"

How to sum CPU usage value of processes name in Powershell

I have a powershell script to check CPU Usage of process in Window.
$Output=""
$Processes = (get-wmiobject Win32_PerfFormattedData_PerfProc_Process)
foreach($Process in $Processes)
{
$Output += $Process.name + "=" + $Process.PercentProcessorTime + " "
}
Write-Host "${Output}"
I ran it. The result have many same process name.
Ex:
chrome=0 chrome#1=0 chrome#2=0 chrome#3=0 chrome#4=0 chrome#5=0 chrome#6=0 chrome#7=0 chrome#8=0 chrome#9=0 PUTTY=0 chrome#10=18 chrome#11=0
I want to list all process and CPU Usage of them as in picture.
And same process will be sum.
I want to sum value same process as below:
$Processes = get-process | Group-Object -Property ProcessName
$Output="OK |"
foreach($Process in $Processes)
{
$Obj = New-Object psobject
$Obj | Add-Member -MemberType NoteProperty -Name Name -Value $Process.Name
$Obj | Add-Member -MemberType NoteProperty -Name Mem -Value ($Process.Group|Measure-Object WorkingSet -Sum).Sum
$Output += $Process.Name + "=" + $($Process.Group|Measure-Object WorkingSet -Sum).Sum +" "
}
Write-Host "${Output}"
And result is sum of same process:
armsvc=1736704 ASDSvc=11309056 audiodg=18563072 bash=1323008 calc=4136960 chrome=2138599424
You are concatenating together a string (of text) rather than adding up the total.
This will give you the total process processor usage.
*Note: the total will be greater than 100%, because the output also includes the _Total and Idle (bot 100% on my machine)
$Output=0
$Processes = (get-wmiobject Win32_PerfFormattedData_PerfProc_Process)
foreach($Process in $Processes)
{
$Output += $Process.PercentProcessorTime
}
Write-Host "Total Processor Usage: $Output %"
Example output:
Total Processor Usage: 318 %
Edit
This should output something similar to what you see in the task manager.
$Processes = (get-wmiobject Win32_PerfFormattedData_PerfProc_Process)
$Processes | %{ New-Object psobject -Property `
#{ Time = $_.PercentProcessorTime;
Name = ($_.name -replace "#\d+", "" )}}`
| ?{ $_.Name -notmatch "_Total|Idle" } `
| Group-Object Name `
| %{ New-Object psobject -Property `
#{ Name = $_.Name;
Sum = ($_.Group | Measure-Object Time -Sum ).Sum }} `
| Format-Table
$Processes = (get-wmiobject Win32_PerfFormattedData_PerfProc_Process)
$procStrings = #()
$Processes | %{ New-Object psobject -Property `
#{ Time = $_.PercentProcessorTime;
Name = ($_.name -replace "#\d+", "" )}}`
| ?{ $_.Name -notmatch "_Total|Idle" } `
| Group-Object Name `
| %{
$procStrings += "$($_.Name)=$(($_.Group | Measure-Object Time -Sum ).Sum)"}
$procStrings -join " "

Exchange Get-MailboxFolderStatistics FolderSize to MB

Morning folks, and what a sad day it is to be British.
Anyway, I'm trying to get MailboxFolderStatistics's FolderSize to MB.
The following line:
Get-MailboxFolderStatistics Joe.Bloggs |
Where-Object { $_.FolderPath -ne "/Deletions" } |
Select-Object FolderPath, #{ N = "FolderSize (MB)"; E = { $_.FolderSize.ToMB() } }
works fine when I'm using Exchange Management Shell.
But if I'm using a remote PS session into one of my Exchange boxes, I don't get anything for FolderSize.
Any ideas?
It's because the Exchange Management Shell you run on the server includes a type named Microsoft.Exchange.Data.ByteQuantifiedSize that gets converted to a System.String through remoting. The former exposes a ToMB() method, the latter does not.
I have written a workaround, but maybe there is a simpler and/or prettier method :
Get-MailboxFolderStatistics Joe.Bloggs |
Where-Object { $_.FolderPath -ne "/Deletions" } |
Select-Object FolderPath, #{
N = "FolderSize (MB)";
E = {
"{0:N2}" -f ((($_.FolderSize -replace "[0-9\.]+ [A-Z]* \(([0-9,]+) bytes\)","`$1") -replace ",","") / 1MB)
}
}
This uses a regular expression to turn the ugly string (example : 3.712 KB (3,801 bytes)) into a usable number. On my system , is not a valid digit grouping symbol so I had to remove it from the string, too.
You can use the following lines to get the $_.FolderSize represented in [decimals]
Select-Object #{
N = "FS_MB";
E = {
[math]::round( ([decimal](($_.FolderSize -replace "[0-9\.]+ [A-Z]* \(([0-9,]+) bytes\)","`$1") -replace ",","") / 1MB),2)
}
}
Typically when looking at folder sizes there is desire to sort them by size descending. To achieve this we need to know the FolderAndSubfolderSize in Bytes and store that in a bigint property as opposed to System.String. It's not rocket science to convert Bytes to Kb,Mb,Gb so I won't go into that here.
In-line syntax for dynamically adding a new property FolderAndSubfolderSizeBytes (I've used backticks to split over several lines for legibility only)
Get-EXOMailbox -Identity user.name#domain.com`
| Get-EXOMailboxFolderStatistics `
| Select Name,FolderAndSubfolderSize,#{`
name="FolderAndSubfolderSizeBytes";`
expression={((($_.FolderAndSubfolderSize -replace '^(.*\()(.*)(\sbytes\))$','$2').Replace(',','')) -as [bigint])}} `
| Sort-Object -Property FolderAndSubfolderSizeBytes -Descending | ft
Long-hand add new properties to variable object for later re-use
$mb = Get-EXOMailbox -Identity user.name#domain.com | Get-EXOMailboxFolderStatistics
foreach ($folder in $mb) {
$folder | Add-Member -NotePropertyName FolderSizeBytes -NotePropertyValue ((($folder.FolderSize -replace '^(.*\()(.*)(\sbytes\))$','$2').Replace(',','')) -as [bigint])
$folder | Add-Member -NotePropertyName FolderAndSubfolderSizeBytes -NotePropertyValue ((($folder.FolderAndSubfolderSize -replace '^(.*\()(.*)(\sbytes\))$','$2').Replace(',','')) -as [bigint])
}
$mb | Select Name,FolderPath,FolderAndSubfolderSize,FolderAndSubfolderSizeBytes | Sort-Object -Property FolderAndSubfolderSizeBytes -Descending | ft