No output from Powershell command when run from script vs cli - powershell

This one command doesn't write output to the screen when running it in a script, but it works when executing it in the PowerShell ISE cli:
$toptenseverity = $csvData | select Severity, Title -Unique | sort Severity -Descending | select -First 11
$toptenseverity
Code:
Write-Host "`r`nTop 10 most severe vulnerabilities:"
$toptenseverity = $csvData | select Severity, Title -Unique | sort Severity -Descending | select -First 11
$toptenseverity
Write-Host "Trying again to write output of toptenseverity using write host toptenseverity:"
Write-Host $toptenseverity
Write-Host "Trying again to write output of toptenseverity using write output toptenseverity:"
Write-Output $toptenseverity
Output:
Generating P1 report. Please wait...
Total P1 count: 352
Severity 5 total: 11
Severity 4 total: 16
Severity 3 total: 325
Top 10 most severe vulnerabilities:
Trying again to write output of toptenseverity using write host toptenseverity:
#{Severity=5; YouDon'tNeedToKnowThis} #{Severity=4; Title=YouDon'tNeedToKnowThis} #{Severity=4; Title=YouDon'tNeedToKnowThis
} #{Severity=4; Title=YouDon'tNeedToKnowThis} #{Severity=4; Title=YouDon'tNeedToKnowThis}
Trying again to write output of toptenseverity using write output toptenseverity:
When I run it from the cli in PS ISE I get this output:
Severity Title
-------- -----
5 YouDon'tNeedToKnowThis
4 YouDon'tNeedToKnowThis
4 YouDon'tNeedToKnowThis
4 YouDon'tNeedToKnowThis
4 YouDon'tNeedToKnowThis

Use:
Write-Output $toptenseverity | Format-Table
This forces the object to be formatted as a table, which is what's going on in the ISE (by default)

Related

Powershell to match the current line and next line then out-file

I'm trying to extract the data whereby:
line 1 = Report ID + Line 2 = "Machine no" + Line 3 = OFFLINE
Then Out-File to a new file.
Sample data
Report ID page1
Machine no 1234
OTHERS
12
offline
12
OTHERS
23
offline
37
OTHERS
89
offline
65
The result I'm looking for look something like the below after processing:
Report ID page 4
Machine no 1234
offline
12
offline
37
offline
65
You can use the Select-String cmdlet with the -Context Parameter to search through a file and then select how many lines of contextual info you want to get back from your search.
For instance, if we take your input file and store it in a variable called $input like so:
$inputFile= Get-Content C:\Path\To\YourFile.txt
$inputFile| Select-string 'machine no'
>Machine no 1234
We can then find matches for the phrase 'offline' with this:
$inputFile| Select-String offline -Context 0,1
This states that I want you to search for the word 'offline' and give me zero lines proceeding it, and one line after it, giving us this output:
> offline
12
> offline
37
> offline
65
We can put this all together to build this and generate a new output file that would look like this.
$out= ''
$out += $inputFile| Select-string 'machine no'
$out += "`n"
$out += $inputFile| Select-String offline -Context 0,1 | ForEach-Object {$_.Context.DisplayPostContext}
#Resulting file would look this, just the name of the machine and then the number of each offline...uh, whatever it is.
Machine no 1234
12 37 65
If I were you, I'd adapt this flow to make PowerShell objects and properties instead, like this:
$Report = [pscustomobject]#{ID='';MachineNo='';OfflineMembers=#()}
$Report.ID = ($inputFile | select-string page -Context 0 ).ToString().Split('page')[-1]
$Report.MachineNo = ($inputFile | Select-string 'machine no').ToString().Trim().Split()[-1]
$Report.OfflineMembers = $inputFile | Select-String offline -Context 0,1 | ForEach-Object {
[pscustomobject]#{Value='Offline';ID=$_.Context.DisplayPostContext.Trim()}
}
>$Report
ID MachineNo OfflineMembers
-- --------- --------------
1 1234 {#{Value=Offline; ID=12}, #{Value=Offline; ID=37}, #{Value=Offline; ID=65}}
$Report.OfflineMembers
Value ID
----- --
Offline 12
Offline 37
Offline 65

PowerShell Script: Sorting by Object Size in MBs

Consider the following PowerShell script:
Get-Process |
Select-Object #{Name='ID';Expression={$_.Id}}, #{Name='Process Name';Expression={$_.Name}},
#{Name='WS';Expression={"{0:N1}" -f($_.WorkingSet/1MB)}},
#{Name='Private';Expression={"{0:N1}" -f($_.PrivateMemorySize/1MB)}},
#{Name='Virtual';Expression={"{0:N1}" -f($_.VirtualMemorySize/1MB)}} | Sort-Object WS |
Format-Table -AutoSize
It seemingly runs without issues. However, as I go through the results, I can see that the sorting of the "Working Set" object is not working as expected (notice how the process orders "106.8" before "11.7", as if it was sorting first by the first digit and then by the second, and so on):
ID Process Name WS Private Virtual
-- ------------ -- ------- -------
1156 svchost 1.9 1.5 73.2
628 svchost 10.5 15.4 148.7
116 svchost 10.8 4.5 119.4
660 chrome 106.8 163.8 601.0
5708 svchost 11.7 5.1 115.3
Any thoughts as to how I could fix this?
I have also tried sorting by "WorkingSet", as in:
Sort-Object WorkingSet
This ends up not sorting the results at all, though.
You should put Sort-Object before Select-object.
Get-Process | Sort-Object WS
This will give you desired output.
You can keep a property in num for sort and remove after, like this :
Get-Process | %{
[pscustomobject]#{
ID=$_.Id
'Process Name'=$_.Name
WS="{0:N1}" -f ($_.WorkingSet/1MB)
Private="{0:N1}" -f ($_.PrivateMemorySize/1MB)
Virtual="{0:N1}" -f ($_.VirtualMemorySize/1MB)
WSNum=$_.WorkingSet
}
} | Sort WSNum | select * -ExcludeProperty WSNum | ft -AutoSize
You can keep your variable in decimal with a round like it:
Get-Process | %{
[pscustomobject]#{
ID=$_.Id
'Process Name'=$_.Name
WS=[math]::Round($_.WorkingSet/1MB, 1)
Private=[math]::Round($_.PrivateMemorySize/1MB, 1)
Virtual=[math]::Round($_.VirtualMemorySize/1MB, 1)
}
} | Sort WS | ft -AutoSize

Returning the member in a group with the highest of a specific property

I'm trying to find the process with the highest CPU in a given group, in my case the group is simply by processname. Assume I have these processes running:
Id ProcessName CPU Memory Threads
-- ----------- --- ------ -------
7532 MicrosoftEdgeCP 40,3125 355,51953125 27
1680 powershell_ise 47,875 214,1015625 23
7568 lync 7,9375 213,859375 52
9664 chrome 19,71875 167,9609375 12
4216 MicrosoftEdgeCP 92,578125 152,2890625 26
5392 explorer 31,09375 116,390625 66
2676 chrome 23,390625 110,96875 41
9812 chrome 14,625 100,859375 8
2872 MsMpEng 100,5234375 36
5752 SearchUI 2,609375 90,0625 23
I'm trying to find Chrome (9664). Currently I have this code:
$list = #()
$grouped = Get-Process | Where ProcessName -Like "c*" |
Sort CPU -Descending |
Group ProcessName |
Select $_ -First 10
$grouped
foreach($item in $grouped) {
$list += #($item.Group |
Sort CPU -Descending |
Select Id, ProcessName, CPU, Memory, Threads -First 1)
}
$list | ft -Wrap
Is it possible to do the same without storing the first in each group in the $list array?
So you wanted to get the process where the CPU is the highest among the threads of the same name correct?
Get-Process -Name "c*" |
Sort-Object CPU -Descending |
Group ProcessName |
ForEach-Object{$_.Group | Select Id, ProcessName, CPU, Memory, Threads -First 1}
-Name supports wildcards so we can save returning all the processes just to drop most of them. Do the first sort and group on processname. Then just take the first entry from each individual group. The last for each is required to prevent the object array from being unrolled and only returning the highest overall entry.

Sorting by (custom) expression output

So I have this as my current code:
Get-Process | Sort Valid,ProcessName |
Format-Table #{n='ProcessName';e={$_.ProcessName}},
#{n='Valid';e={if(($_.mainmodule.filename | Get-AuthenticodeSignature).Status -eq 'Valid') {1} else {0}}} -AutoSize
which gives me an output of:
ProcessName Valid
----------- -----
3DG4me 1
Adobe CEF Helper 1
Adobe CEF Helper 1
Adobe Desktop Service 1
AdobeIPCBroker 1
AdobeUpdateService 1
AGSService 1
ApplicationFrameHost 1
audiodg 0
avgnt 1
avguard 1
Avira.ServiceHost 1
Avira.Systray 1
avshadow 1
Calculator 0
CCLibrary 1
....etc etc
Even though I put a sort before I formatted it won't let me sort by Valid, which is an integer. I've tried adding [int] before {1} and {0} but it doesn't seem to be working.
You cannot sort by properties that aren't created until after the sorting happened. Valid is not a property of System.Diagnostic.Process objects. If you want to sort by that calculated property you need to add it before sorting. This insertion is usually done via Select-Object:
Get-Process |
Select-Object ProcessName,
#{n='Valid';e={if(($_.mainmodule.filename | Get-AuthenticodeSignature).Status -eq 'Valid') {1} else {0}}} |
Sort Valid, ProcessName |
Format-Table -AutoSize

How do I get filename and line count per file using powershell

I have the following powershell script to count lines per file in a given directory:
dir -Include *.csv -Recurse | foreach{get-content $_ | measure-object -line}
This is giving me the following output:
Lines Words Characters Property
----- ----- ---------- --------
27
90
11
95
449
...
The counts-per-file is fine (I don't require words, characters, or property), but I don't know what filename the count is for.
The ideal output would be something like:
Filename Lines
-------- -----
Filename1.txt 27
Filename1.txt 90
Filename1.txt 11
Filename1.txt 95
Filename1.txt 449
...
How do I add the filename to the output?
try this:
dir -Include *.csv -Recurse |
% { $_ | select name, #{n="lines";e={
get-content $_ |
measure-object -line |
select -expa lines }
}
} | ft -AutoSize
I can offer another solution :
Get-ChildItem $testPath | % {
$_ | Select-Object -Property 'Name', #{
label = 'Lines'; expression = {
($_ | Get-Content).Length
}
}
}
I operate on the. TXT file, the return value is like this ↓
Name Lines
---- ----
1.txt 1
2.txt 2
3.txt 3
4.txt 4
5.txt 5
6.txt 6
7.txt 7
8.txt 8
9.txt 9
The reason why I want to sort like this is that I am rewriting a UNIX shell command (from The Pragmatic Programmer: Your Journey to Mastery on page 145).
The purpose of this command is to find out the five files with the largest number of lines.
At present, my progress is the above content,i'm close to success.
However, this command is far more complicated than the UNIX shell command!
I believe there should be a simpler way, I'm trying to find it.
find . -type f | xargs wc -l | sort -n | tail -5
I have used the following script that gives me lines in files of all sub directories in folder c:\temp\A. The output is in lines1.txt file. I have applied a filer to choose only file types of ".TXT".
Get-ChildItem c:\temp\A -recurse | where {$_.extension -eq ".txt"} | % {
$_ | Select-Object -Property 'Name', #{
label = 'Lines'; expression = {
($_ | Get-Content).Length
}
}
} | out-file C:\temp\lines1.txt