Powershell Convert Process-list into HTML - html

Export Name and the status of the first 10 services into a html file and color the lines with Running green and Stopped red.
This was the task.
I tried to:
Get-Service | Select-Object -First 10 -Property Name,Status
Get-Service | Select-Object -First 10 -Property Name,Status | ConvertTo-Html > first.txt
(Get-Content hallo.txt) -replace '<td>','<td style="color:#00ff00">'|Set-Content final.html
But now I have the problem that everything is green.
How do I manage to distinguish between Stopped and Running?
I think this idea I've been trying to come up with isn't working.
Maybe you could make the distinction before you export the processes to the file? But I have no idea how to do that.

If we are sticking with the theme of text replacement, you could do the following:
$html = Get-Service | Select-Object -First 10 -property Name,Status |
ConvertTo-Html | Foreach-Object {
if ($_ -match '<td>Stopped</td>') {
$_ -replace '<td>','<td style="color:red">'
}
elseif ($_ -match '<td>Running</td>') {
$_ -replace '<td>','<td style="color:green">'
}
else {
$_
}
}
$html | Set-Content final.html

You can also do this:
Get-Service | Select -First 10 -Property Name,Status | ConvertTo-Html | Foreach {
Switch -regex ($_) {
".*<td>Stopped</td>.*" { $_ -replace '<td>','<td style="color:red">' }
".*<td>Running</td>.*" { $_ -replace '<td>','<td style="color:green">'
}
} | Set-Content "Filepath"

Related

Modifying JSON file using data from CSV in PowerShell

I'm trying to modify some specific values in a .json file based on two columns in a .csv file. If the current value in the .json file is identical to the one in the left column, I want to change it to the one in the right column.
This is my first time with PowerShell though, so I'm struggling to figure out how to go about doing this. I feel like my solution is not only wrong, but is using a double for loop when it might not need to. Here's what I have so far.
$jsonData = Get-Content -Path $jsonFile | ConvertFrom-Json
$csvData = Get-Content -Path $csvFile | Select-Object -Skip 1 # Skipping the header
foreach ($jsonItem in $jsonData.'Placeable List') {
foreach ($csvRow in $csvData) {
$splitRow = $csvRow -split ","
$lCol = $splitRow[0]
$rCol = $splitRow[1]
$currentItem = $jsonItem.'value'.'Appearance'.'value'
if ($currentItem -eq $lCol) {
$currentItem -eq $rCol
}
}
}
I managed to figure it out.
$csvData = Get-Content -Path $csvFile | Select-Object -Skip 1 # Skipping the header
$jsonData = Get-Content -Path $jsonFile -raw | ConvertFrom-Json
foreach($csvRow in $csvData) {
$splitRow = $csvRow -split ","
$lCol = $splitRow[0]
$rCol = $splitRow[1]
foreach($item in $jsonData.'Placeable List'.value) {
$item.Appearance | % {
if ($_.value -eq $lCol) {
$_.value = $rCol
}
}
}
}
$jsonData | ConvertTo-Json -depth 32 | Set-Content $jsonFile

How to apply colors in powershell output

Requirement :
I am beginner in powershell. Below ps script is giving the details about services are in started state or in stopped state but my requirement is I need to see this out put as background color in 'Sky Blue', if services are running then highlight in Green ,Stopped services in Red color. How do I achieve it.
Help on this is highly appriciated.
$Result = #()
foreach($server in Get-Content C:\PowerSQL\List.txt)
{
$Services=gwmi win32_service -computername $server | where {$_.Name -like ‘*SQL*’}
if(!(Test-Connection -Cn $server -BufferSize 16 -Count 1 -ea 0 -quiet))
{“Problem still exists in connecting to $server”}
ELSE {
$services | ForEach {
If ($_)
{ $Result += New-Object PSObject -Property #{
‘Host Name’ = $_.Systemname
‘Service Display Name’ = $_.Displayname
‘Service Name’ = $_.Name
‘Start Mode’ = $_.Startmode
‘Service Account Name’ = $_.Startname
‘State’ = $_.State
‘Status’= $_.Status
}
}
}
}
}
$Result | ConvertTo-HTML | Out-File C:\PowerSQL\service.htm
See my answer to similar question to this.
Communary.ConsoleExtensions [link] might help you
Invoke-ColorizedFileListing C:\Windows -m *.dmp
The above command will colorise file types and highlight dump files.
To save a color output, you would have to save to a format that preserves color, like RTF, or HTML. Txt (plain text file) only stores text.
The code below will save your output as an html file.
$time = (Get-Date).AddYears(-2)
Get-ChildItem -Recurse | Where-Object {$_.LastWriteTime -lt $time} |
Select Directory,Name,LastWriteTime |
ConvertTo-Html -Title "Services" -Body "<H2>The result of Get-ChildItem</H2> " -Property Directory,Name,LastWriteTime |
ForEach-Object {
if ($_ -like '<tr><td>*') {
$_ -replace '^(.*?)(<td>.*?</td>)<td>(.*?)</td>(.*)','$1$2<td><font color="green">$3</font></td>$4'
} else {
$_
}
} | Set-Content "$env:TEMP\ColorDirList.html" -Force
The line:
if ($_ -like '<tr><td>*') {
...checks for line in the html output that is a table row.
The line:
$_ -replace '^(.*?)(<td>.*?</td>)<td>(.*?)</td>(.*)','$1$2<td><font color="green">$3</font></td>$4'
...uses a RegEx to replace the 2nd table cell contents with a font tag with the color green. This is a very simple RegEx search & replace that will only color the 2nd column.
And here's another implementation of console only coloring, based on this link
$linestocolor = #(
'CSName Version OSArchitecture'
'------ ------- --------------'
'BENDER 6.1.7601 64-bit '
'LEELA 6.1.7601 64-bit '
'FRY 6.1.7600 64-bit '
'FARNSWORTH 6.1.7601 32-bit '
)
# http://www.bgreco.net/powershell/format-color/
function Format-Color {
[CmdletBinding()]
param(
[Parameter(ValueFromPipeline=$true,Mandatory=$true)]
$ToColorize
, [hashtable]$Colors=#{}
, [switch]$SimpleMatch
, [switch]$FullLine
)
Process {
$lines = ($ToColorize | Out-String).Trim() -replace "`r", "" -split "`n"
foreach($line in $lines) {
$color = ''
foreach($pattern in $Colors.Keys){
if (!$SimpleMatch -and !$FullLine -and $line -match "([\s\S]*?)($pattern)([\s\S]*)") { $color = $Colors[$pattern] }
elseif (!$SimpleMatch -and $line -match $pattern) { $color = $Colors[$pattern] }
elseif ($SimpleMatch -and $line -like $pattern) { $color = $Colors[$pattern] }
}
if ($color -eq '') { Write-Host $line }
elseif ($FullLine -or $SimpleMatch) { Write-Host $line -ForegroundColor $color }
else {
Write-Host $Matches[1] -NoNewline
Write-Host $Matches[2] -NoNewline -ForegroundColor $color
Write-Host $Matches[3]
}
}
}
}
$linestocolor | Format-Color -Colors #{'6.1.7600' = 'Red'; '32-bit' = 'Green'}
# doesn't work...
# (Get-ChildItem | Format-Table -AutoSize) | Format-Color -Colors #{'sql' = 'Red'; '08/07/2016' = 'Green'}
# does work...
Format-Color -ToColorize (Get-ChildItem | Format-Table -AutoSize) -Colors #{'sql' = 'Red'; '08/07/2016' = 'Green'}
return
EDIT. to answer the OPs request
$Result = #()
foreach($server in Get-Content C:\PowerSQL\List.txt)
{
$Services=gwmi win32_service -computername $server | where {$_.Name -like ‘*SQL*’}
if(!(Test-Connection -Cn $server -BufferSize 16 -Count 1 -ea 0 -quiet))
{“Problem still exists in connecting to $server”}
else {
$services | ForEach {
If ($_)
{ $Result += New-Object PSObject -Property #{
HostName = $_.Systemname
ServiceDisplayName = $_.Displayname
ServiceName = $_.Name
StartMode = $_.Startmode
ServiceAccountName = $_.Startname
State = $_.State
Status = $_.Status
}
}
}
}
}
$Result | ConvertTo-HTML `
-Title "Services" `
-Body "<H2>The result of gwmi win32_service</H2> " `
-Property HostName,ServiceDisplayName,ServiceName,StartMode,ServiceAccountName,State,Status |
ForEach-Object {
if ($_ -like '<tr><td>*') {
switch ($_) {
{ $_ -like '*<td>Stopped</td>*' } {$color='red'}
{ $_ -like '*<td>Running</td>*' } {$color='green'}
Default {$color='white'}
}
$_.Replace('<tr>', "<tr bgcolor=`"$color`">")
} else {
$_
}
} | Set-Content C:\PowerSQL\service.htm -Force

Where-Object with complex evaluation

I have a PowerShell script where I read in a CSV file, and if the date in a certain column is greater than a parameter date, I output that row to a new file.
As of now, I read the CSV file and then pipe to a ForEach-Object where if the row "passes" I store it in an Arraylist. Then when all the rows are processed, I output the Arraylist to an output CSV file. My starting CSV file is 225MB with over a quarter million rows, meaning that this process is slow.
Is there a way I can add a filter function to my piping so that only the passing rows are passed to the output CSV in one fell swoop? The current Where-Object just uses things like -like, -contains... and not more complex forms of evaluation.
For best practices, I've got my code below:
Import-Csv -Delimiter "`t" -Header $headerCounter -Path $filePath |
Select-Object -Skip(1) |
ForEach-Object {
#Skip the header
if( $lineCounter -eq 1)
{
return
}
$newDate = if ([string]::IsNullOrEmpty($_.1) -eq $true)
{ [DateTime]::MinValue }
else { [datetime]::ParseExact($_.1,”yyyyMMdd”,$null) }
$updateDate = if ([string]::IsNullOrEmpty($_.2) -eq $true)
{ [DateTime]::MinValue }
else { [datetime]::ParseExact($_.2,”yyyyMMdd”,$null) }
$distanceDate = (Get-Date).AddDays($daysBack * -1)
if( $newDate -gt $distanceDate -or $updateDate -gt $distanceDate )
{
[void]$filteredArrayList.Add($_)
}
}
...
$filteredArrayList |
ConvertTo-Csv -Delimiter "`t" -NoTypeInformation |
select -Skip 1 |
% { $_ -replace '"', ""} |
out-file $ouputFile -fo -en unicode -Append
I've added ConvertToDate as a function to stop that confusing the Where block.
DistanceDate is out because it appears to be calculated only once.
ExportCsv is a little function that writes pipeline input to a file.
I haven't tested it, so bugs are quite likely unless I got lucky.
function ConvertToDate {
param(
[String]$DateString
)
if ($DateString -eq '') {
return [DateTime]::MinValue
} else {
return [DateTime]::ParseExact($DateString, ”yyyyMMdd”, $null)
}
}
filter ExportCsv {
param(
[Parameter(Position = 1)]
[String]$Path
)
$csv = $_ | ConvertTo-Csv -Delimiter "`t" | Select-Object -Last 1
$csv -replace '"' | Out-File $Path -Append -Encoding Unicode -Force
}
$distanceDate = (Get-Date).AddDays($daysBack * -1)
Import-Csv -Delimiter "`t" -Header $headerCounter -Path $filePath |
Select-Object -Skip 1 |
Where-Object { (ConvertToDate $_.1) -gt $distanceDate -or (ConvertToDate $_.2) -gt $distanceDate } |
ExportCsv $OutputFile
Sure, just add a function that takes a value from the pipeline and pipe the result of Import-Csv to it. Within the function you check whether you want to filter the current item or not. Here a simple example which uses a string list and filter all strings that starts with h:
$x = #('hello', 'world', 'hello', 'tree')
filter Filter-CsvByMyRequirements
{
Param(
[Parameter(Mandatory=$true,
ValueFromPipeline=$true)]
$InputObject
)
Process
{
if ($_ -match '^h.*')
{
$_
}
}
}
$x | Filter-CsvByMyRequirements | Write-Host
Output:
hello
hello

Issue in export Array to CSV file

I have list of machine in text file and I am trying to get the details of physical drives, OS architecture and physical memory. With the help of Matt (SO user) here is the powershell script.
$server = Get-Content .\Server.txt
#$infoObject11 = #{}
$infoObject11 = #{}
foreach ($server in $servers) {
# Gather all wmi drives query at once
$alldisksInfo = Get-WmiObject -Query "SELECT * FROM Win32_DiskDrive" -ComputerName $server -ErrorAction SilentlyContinue | Group-Object __Server
# Figure out the maximum number of disks
$MaximumDrives = $alldisksInfo | Measure-Object -Property Count -Maximum | Select-Object -ExpandProperty Maximum
# Build the objects, making empty properties for the drives that dont exist for each server where need be.
$server | ForEach-Object {
# Clean the hashtable
$infoObject1 = #{}
# Populate Server
$infoObject1.Server = $server
$HOSTNAME = Get-WMIObject -Query "Select * from Win32_OperatingSystem" -ComputerName $infoObject1.Server
# Add other simple properties here
$infoObject1.PhysicalMemory = (Get-WmiObject Win32_PhysicalMemory -ComputerName $infoObject1.Server | Measure-Object Capacity -Sum).Sum/1gb
$infoObject1.OSarchitecture =$HOSTNAME.osarchitecture
# Add the disks information from the $diskInfo Array
$serverDisksWMI = $alldisksInfo | Where-Object{$_.Name -eq $infoObject1.Server} | Select-Object -ExpandProperty Group
for ($diskIndex =0; $diskIndex -lt $MaximumDrives;$diskIndex++) {
$infoObject1."PhysicalDisk$diskIndex" = [Math]::Round(($serverDisksWMI | Where-Object{($_.DeviceID -replace "^\D*") -eq $diskIndex} | Select -Expand Size)/1GB)
}
}
# Create the custom object now.
New-Object -TypeName psobject -Property $infoObject1 | Export-Csv -path .\Server_Inventory_$((Get-Date).ToString('MM-dd-yyyy')).csv -NoTypeInformation
}
Problem is in the CSV file I am getting single machine details but in server.txt file there are more than 1 machine. If I print $infoObject1 before New-Object then I can see there are details of multiple machine. It seems like some issue with array and I am not able to export it in CSV.
Can anybody please suggest on this.
It looks like you are having issues integrating my code. You have added a second loop that should not be there. Also as other users pointed out you are not creating the per server object outside the loop. The answer, from where your code comes from, has that part correct. I had even showed you where to put the Export-CSV.
$servers = Get-Content .\Server.txt
# Gather all wmi drives query at once
$alldisksInfo = Get-WmiObject -Query "SELECT * FROM Win32_DiskDrive" -ComputerName $servers -ErrorAction SilentlyContinue | Group-Object __Server
# Figure out the maximum number of disks
$MaximumDrives = $alldisksInfo | Measure-Object -Property Count -Maximum | Select-Object -ExpandProperty Maximum
# Build the objects, making empty properties for the drives that dont exist for each server where need be.
$servers | ForEach-Object {
# Clean the hashtable
$infoObject1 = #{}
# Populate Server
$infoObject1.Server = $_
# Add other simple properties here
$infoObject1.PhysicalMemory = (Get-WmiObject Win32_PhysicalMemory -ComputerName $infoObject1.Server | Measure-Object Capacity -Sum | Select-Object -ExpandProperty Sum)/1GB
$infoObject1.OSarchitecture = Get-WMIObject -Query "Select * from Win32_OperatingSystem" -ComputerName $infoObject1.Server | Select-Object -ExpandProperty OSArchitecture
# Add the disks information from the $diskInfo Array
$serverDisksWMI = $alldisksInfo | Where-Object{$_.Name -eq $infoObject1.Server} | Select-Object -ExpandProperty Group
for ($diskIndex =0; $diskIndex -lt $MaximumDrives;$diskIndex++) {
$infoObject1."PhysicalDisk$diskIndex" = [Math]::Round(($serverDisksWMI | Where-Object{($_.DeviceID -replace "^\D*") -eq $diskIndex} | Select-Object -ExpandProperty Size)/1GB)
}
# Create the custom object now for this pass in the loop.
New-Object -TypeName psobject -Property $infoObject1
} | Export-Csv -path .\Server_Inventory_$((Get-Date).ToString('MM-dd-yyyy')).csv -NoTypeInformation
foreach ($server in $servers) {
...
New-Object -TypeName PSObject -Property $infoObject1 |
Export-Csv -Path .\Server_Inventory_$((Get-Date).ToString('MM-dd-yyyy')).csv -NoTypeInformation
}
You're exporting inside the loop without using the parameter -Append (available in PowerShell v3 and newer). That overwrites your output file with each iteration, leaving you with just the data of the last server.
Either use the parameter -Append (if you have PowerShell v3 or newer):
foreach ($server in $servers) {
...
New-Object -TypeName PSObject -Property $infoObject1 |
Export-Csv -Append -Path .\Server_Inventory_$((Get-Date).ToString('MM-dd-yyyy')).csv -NoTypeInformation
}
or move Export-Csv outside the loop (works with all PowerShell versions):
(foreach ($server in $servers) {
...
New-Object -TypeName PSObject -Property $infoObject1
}) | Export-Csv -Path .\Server_Inventory_$((Get-Date).ToString('MM-dd-yyyy')).csv -NoTypeInformation
Note that you need to run the loop in parentheses for this to work, as foreach loops don't output to the pipeline.
You could also replace the foreach loop with ForEach-Object if you want to feed the pipeline directly:
Get-Content .\Server.txt | ForEach-Object {
$server = $_
...
New-Object -TypeName PSObject -Property $infoObject1
} | Export-Csv -Path .\Server_Inventory_$((Get-Date).ToString('MM-dd-yyyy')).csv -NoTypeInformation

Include file owner to powershell pipe

I've got a script which works fine which lists all files modified since last 7 days and want to modify it to add file owner to the export csv file.
$dir_to_look="F:\"
$month_backdate=$(Get-Date).AddDays(-7)
Get-Childitem $dir_to_look -Recurse | ? { !($_.psiscontainer) -and $_.LastWriteTime -gt $month_backdate } | ForEach-Object {Get-Acl $_.FullName}.owner | Select-object LastWriteTime, Directory, FullName | export-csv -path \\sharename\report.csv -encoding "unicode"
But not sure how to correctly add get-acl to the pipe as currently it prints nothing to my report file
Your Foreach-Object command should be:
... | Foreach-Object {Add-Member -Input $_ -Type NoteProperty -Name Owner -Value (Get-Acl $_.Fullname).Owner -PassThru} | Select-object LastWriteTime, Directory, FullName, Owner | ...
Add-Member is handy for adding properties (and methods) to objects.
Use a hash table with Select-Object.
$dir_to_look="F:\"
$month_backdate=$(Get-Date).AddDays(-7)
Get-Childitem $dir_to_look -Recurse | ? { !($_.psiscontainer) -and $_.LastWriteTime -gt $month_backdate } |
Select-object LastWriteTime, Directory, FullName, #{n='Owner';e={(Get-ACL $_.FullName).owner}}
$dir_to_look="F:\"
$month_backdate=$(Get-Date).AddDays(-7)
Get-Childitem $dir_to_look -Recurse | ? { !($_.psiscontainer) -and $_.LastWriteTime -gt $month_backdate } |
Select-object LastWriteTime, Directory, FullName, #{n='Owner';e={(Get-ACL $_.FullName).owner}}