In my script I've collected all the data I want to report in different variables. Now I'm trying to generate an HTML-table so I can send this by mail.
What I would like to achieve is HTML-code that generates this:
OU | Logon scripts incorrect | Name incorrect | No description
\\Domain\NLD Users | 2 | 6 | 2
\\Domain\FRA users | 5 | 7 | 0
\\Domain\BEL users | 6 | 1 | 1
TOTAL USERS: 2048 | 13 | 14 | 3
I'm a bit confused on what would be the best approach for this (array, psobject, hashtable, ..). Because I'm not going to work with a foreach loop, the data would be static.
What I tried so far but isn't quite giving the desired result:
$Table = #( ('OU', 'Logon scripts incorrect', 'Name incorrect', 'No description'),
('\\Domain\NLD Users','2','6','2' ),
('\\Domain\FRA Users','5','7','0' ),
('\\Domain\BEL Users','6','1','1' ),
('TOTAL USERS: 2048','13','14','3' )
)
$Table | ConvertTo-Html -As Table -Fragment
It feels like I'm over-complicating things.
convertto-html is waiting for a psobject as its input.
What you can do is pass your data as csv then use convertfrom-csv to tansform it to psobject the run convertto-html :
$Table = #"
'\\Domain\NLD Users','2','6','2'
'\\Domain\FRA Users','5','7','0'
"#
$Table | ConvertFrom-Csv -Header 'OU', 'Logon scripts incorrect', 'Name incorrect', 'No description' | ConvertTo-Html -Fragment -As Table
#( ('OU', 'Logon scripts incorrect', 'Name incorrect', 'No description'),
('\\Domain\NLD Users','2','6','2' ),
('\\Domain\FRA Users','5','7','0' ),
('\\Domain\BEL Users','6','1','1' ),
('TOTAL USERS: 2048','13','14','3' )
) | Select-Object -Skip 1 | ForEach-Object{
[PSCustomObject]#{
OU = $_[0]
"Logon scripts incorrect" = $_[1]
"Name incorrect" = $_[2]
"No Description" = $_[3]
}
} | ConvertTo-Html -As Table -Fragment
From what i have read ConvertTo-Html takes .Net Objects and not arrays to convert to html. I converted your static table to a custom object which then was exported. This might look more to your liking.
You're creating an array of arrays with your statement, which looks neat, but isn't something ConvertTo-Html can handle. Create new objects instead (this is for v3):
$x = #(
([pscustomobject] #{
"OU" = "\\Domain\NLD Users";
"Logon scripts incorrect" = 2;
"Name incorrect" = 6;
"No description" = 2;
}),
([pscustomobject] #{
"OU" = "\\Domain\FRA Users";
"Logon scripts incorrect" = 5;
"Name incorrect" = 7;
"No description" = 0;
})
# ...and so on, or more realistically, constructed using Foreach-Object
)
$x | convertto-html -fragment
If you're confined to PowerShell v2, you can use new-object -type psobject -prop instead, but then the properties are not ordered so you will need an explicit Select.
Related
I have a script which get a tcp connections Get-NetTCPConnection.
The $flam variable can get last record for each object, and the $rfrt variable can get all output objects without the last one.
As I show the $CntTableBodyr variable is my mistake, I want to add $flam and $rfrt variable as HTML table with the following details :
Each tr of the $flam which has recognized by Id=111, to the first row then the $rfrt which has recognized by Id=222 to those rows which contain by the first above rows digitalis!
Can't understand? Here what I mean :
Screenshot :
Explanation :
For example, in my $GetCon variable which includes all tcp-connections [as you know]. my complete output count is [7 Count] as I show in above image, for example the [OwningProcess for 1177] has 3 count result, and so on, I want to get last object of 1177 as the first row with id=111 then second and all connections about 1177 to bottom. Other connections are same as 1177 and [LocalAddress].
Example:
$GetCon = Get-NetTCPConnection
$ss = $GetCon | select OwningProcess | Group-Object -Property OwningProcess | select Count, Name
$cccs = $ss | Select -ExpandProperty Name
$flam = ForEach ($oio in $cccs) {
$GetCon | Where-Object {$_.OwningProcess -eq $oio} | select -Last 1
}
$yyoiu = $GetCon | Group-Object -Property OwningProcess
for ($irt = 0; $irt -lt $yyoiu.Count; $irt++)
{
$rfrt = foreach($grpop in $yyoiu[0..$irt]){
$jrtgrpcnt = [int]($grpop.Group.Count - 1)
$grpop.Group | select -First (0+$jrtgrpcnt)
}
}
$CntTableBodyr=""
#$frcntArrr = $flam | select -ExpandProperty OwningProcess #$frcntr.GetEnumerator() |%{$_}
ForEach ($Rowr in $flam) {
$CntTableBodyr+="<tr id='111' style='background-color: lightblue;'><td>$($Rowr.OwningProcess)</td><td>$($Rowr.LocalAddress)</td></tr>
<tr id='222' style='background-color: lightgray;'><td>$($rfrt.OwningProcess)</td><td>$($rfrt.LocalAddress)</td></tr>"
}
$html=#"
<table id='tblId'>
$CntTableBodyr
</table>
"#
ConvertTo-Html -Body $html | Out-File c:\out.html
Invoke-Item c:\out.html
Just taking the essential part (as I do not have access to the same resources):
$flam = ConvertFrom-CSV #"
OwningProcess,LocalAddress
1177,127.0.0.1
1177,192.168.1.2
1177,192.168.1.1
2211,192.168.1.1
2211,127.0.0.1
3122,192.168.1.1
3122,192.168.1.1
"#
$OwningProcesses = #()
$flam | ForEach {
$id = If ($OwningProcesses -Contains $_.OwningProcess) {"222"} Else {$OwningProcesses += $_.OwningProcess; "111"}
$_ | Add-Member -Force id $id
}
Result:
PS C:\> $flam
OwningProcess LocalAddress id
------------- ------------ --
1177 127.0.0.1 111
1177 192.168.1.2 222
1177 192.168.1.1 222
2211 192.168.1.1 111
2211 127.0.0.1 222
3122 192.168.1.1 111
3122 192.168.1.1 222
Including this in the HTML file:
$CntTableBodyr=""
#$frcntArrr = $flam | select -ExpandProperty OwningProcess #$frcntr.GetEnumerator() |%{$_}
$flam | {
$CntTableBodyr+="<tr id='$($_.id)' style='background-color: lightblue;'><td>$($_.OwningProcess)</td><td>$($_.LocalAddress)</td></tr>"
}
$html=#"
<table id='tblId'>
$CntTableBodyr
</table>
"#
ConvertTo-Html -Body $html | Out-File c:\out.html
I can't seem to get this function quite right. I want to pass it an object and if the object is empty, return 1, else count items in the object and increment by 1.
Assuming the following function "New-Test":
function New-Test
{
[cmdletbinding()]
Param
(
[Parameter(ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
[object[]]$Object
#[object]$object
)
Begin
{
$oData=#()
}
Process
{
"Total objects: $($object.count)"
if($Object.count -gt 0)
{
$oData += [pscustomobject]#{
Name = $_.Name
Value = $_.Value
}
}
Else
{
Write-Verbose "No existing object to increment. Assuming first entry."
$oData = [pscustomobject]#{Value = 0}
}
}
End
{
$LatestName = ($oData | Sort-Object -Descending -Property Value | Select -First 1).value
[int]$intNum = [convert]::ToInt32($LatestName, 10)
$NextNumber = "{0:00}" -f ($intNum+1)
$NextNumber
}
}
And the following test hashtable:
#Create test hashtable:
$a = 00..08
$obj = #()
$a | foreach-object{
$obj +=[pscustomobject]#{
Name = "TestSting" + "{0:00}" -f $_
Value = "{0:00}" -f $_
}
}
As per the function above, if I pass it $Obj, I get:
$obj | New-Test -Verbose
Total objects: 1
Total objects: 1
Total objects: 1
Total objects: 1
Total objects: 1
Total objects: 1
Total objects: 1
Total objects: 1
Total objects: 1
09
Which is as expected. However, if I pass it $Obj2:
#Create empty hash
$obj2 = $null
$obj2 = #{}
$obj2 | New-Test -Verbose
I get:
Total objects: 1
Exception calling "ToInt32" with "2" argument(s): "Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: startIndex"
At line:33 char:9
+ [int]$intNum = [convert]::ToInt32($LatestName, 10)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : ArgumentOutOfRangeException
01
I don't understand why $object.count is 1, when there's nothing in the hashtable.
If I change the parameter, $object's type from [object[]] to [object], the empty hashtable test results in:
$obj2 | New-Test -Verbose
Total objects: 0
VERBOSE: No existing object to increment. Assuming first entry.
01
Which is what I'd expect, however, if I run the first test, it results in:
$obj | New-Test -Verbose
Total objects:
VERBOSE: No existing object to increment. Assuming first entry.
Total objects:
VERBOSE: No existing object to increment. Assuming first entry.
This time $objects has nothing in it.
I'm sure it's simple, but I can't fathom this one out. Any help is appreciated.
P.S. PowerShell 5.1
$obj2 is a hashtable, not an array. Hashtables are not enumerated by default, so the hashtable itself is the one object. If you want to loop through an hashtable using the pipeline you need to use $obj2.GetEnumerator().
#{"hello"="world";"foo"="bar"} | Measure-Object | Select-Object Count
Count
-----
1
#{"hello"="world";"foo"="bar"}.GetEnumerator() | Measure-Object | Select-Object Count
Count
-----
2
I'm reading a fixed-width file with 4000 rows though substrings, and assigning each substring to a header in a csv. But I'm not sure how to save the csv.
An example row am reading:
$line = ABC 7112123207/24/16Smith Timpson Head Coach 412-222-0000 00011848660 ELl CAAN HIGH SCHOOL 325 N Peal AVE. Smith Timpson Head Coach COLORADO CITY AZ 86021 01 FALL MALE 07/29/16EQ15031 1977904 BUDDY'S ALL STARS INC. BUDDY ALL STARS N V12V70R16 1.00V12V70R16
I've the csv with the headers.
$csvheaders = import-csv temp.csv
foreach ($Line in (Get-Content $FILE.FullName))
{
foreach($csh in $csvheaders)
{
$csh.GROUP = $line.Substring(0,10).Trim()
$csh.NUMBER = $line.Substring(10,8).Trim()
$csh.DATE=$line.Substring(18,8).Trim()
$csh.CONTACT_FIRST=$line.Substring(26,35).Trim()
$csh.CONTACT_LAST=$line.Substring(61,35).Trim()
}
}
I would need the csv output as:
Group Number Date Contact_First Contact_Last
ABC 71121232 07/24/16 Smith Timpson
There is a Export-Csv cmdlet:
Get-Content $FILE.FullName | ForEach-Object {
[PSCustomObject]#{
Group = $_.Substring(0,10).Trim()
Number = $_.Substring(10,8).Trim()
Date = $_.Substring(18,8).Trim()
Contact_First = $_.Substring(26,35).Trim()
Contact_Last = $_.Substring(61,35).Trim()
}
} | Export-Csv -Path 'Your_Output_Path.csv' -NoTypeInformation
Note: You probably need to specify a tab delimiter for the Export-Csv cmdlet.
I am trying to retrieve the running applications, the computers' username and its IP address. Now, every time that the results are saved on the text file, the IP address part would always give me this result:
"Length"
"11"
Is there any way to get the IP address?
$savepath = "C:\Users\$([Environment]::UserName)\Desktop\apps\runningapps.txt"
Get-Process | where {$_.mainwindowtitle.length -ne 0} |
select name, mainwindowtitle| ConvertTo-Csv -NoType |
Set-Content $savepath
Get-WmiObject -Class Win32_ComputerSystem | select username |
ConvertTo-Csv -NoType | Add-Content $savepath
Get-WmiObject Win32_NetworkAdapterConfiguration |
Where { $_.IPAddress } |
Select -Expand IPAddress |
Where { $_ -notlike "*:*" } | ConvertTo-Csv -NoType | Add-Content $savepath
The IP addresses are a list of strings, so you can write them directly to the output file if you want them one address per line:
Get-WmiObject Win32_NetworkAdapterConfiguration |
Where { $_.IPAddress } |
Select -Expand IPAddress |
Where { $_ -notlike "*:*" } | Add-Content $savepath
If you want the addresses as a comma separated list in one line you need to join them first:
(Get-WmiObject Win32_NetworkAdapterConfiguration |
Where { $_.IPAddress } |
Select -Expand IPAddress |
Where { $_ -notlike "*:*" }) -join ',' | Add-Content $savepath
ConvertTo-Csv won't help you here, because it takes an object as input and outputs a comma-separated list of the object's properties. If your input objects are strings (which have only the property Length) then the output becomes a list of the lengths of the input strings.
As a side note: a simpler way of building the output file path is to use the USERPROFILE environment variable:
$savepath = "$env:USERPROFILE\Desktop\apps\runningapps.txt"
Powershell Script to Delete Blank Columns from CSV
I have a spread sheet which I'm importing into a MySQL database, the import fails because of blank columns in the spread sheet.
Is there a powershell script I can run / create that will check any given CSV file and remove blank columns?
Col1,Col2,Col3,Col4,,,,
Val1,Val2,Val3,Val4
How about something like this:
$x = Import-Csv YourFile.csv
$f = $x[0] | Get-Member -MemberType NoteProperty | Select name
$f | Add-Member -Name count -Type NoteProperty -Value 0
$f | %{
$n = $_.Name
$_.Count = #($x | Select $n -ExpandProperty $n | ? {$_ -ne ''}).count
}
$f = #($f | ? {$_.count -gt 0} | Select Name -expandproperty Name)
$x | Select $f | Export-Csv NewFile.csv -NoTypeInformation
It uses Get-Member to get the column names, cycles though each one to check how many are not blank and then uses the results in a select.
When I run Dave Sexton's code, I get:
Select-Object : Cannot convert System.Management.Automation.PSObject to one of the following
types {System.String, System.Management.Automation.ScriptBlock}.
At line:15 char:12
+ $x | Select <<<< $f | Export-Csv ColsRem.test.$time.csv -NoTypeInformation
+ CategoryInfo : InvalidArgument: (:) [Select-Object], NotSupportedException
+ FullyQualifiedErrorId :
DictionaryKeyUnknownType,Microsoft.PowerShell.Commands.SelectObjectCommand
I corrected this issue by adding one more line, to force each array element to be a string.
$x = Import-Csv YourFile.csv
$f = $x[0] | Get-Member -MemberType NoteProperty | Select name
$f | Add-Member -Name count -Type NoteProperty -Value 0
$f | %{
$n = $_.Name
$_.Count = #($x | Select $n -ExpandProperty $n | ? {$_ -ne ''}).count
}
$f = #($f | ? {$_.count -gt 0} | Select Name -expandproperty Name)
# I could get the select to work with strings separated by commas, but the array would
# always produce the error until I added the following line, explicitly changing the
#values to strings.
$f = $f | Foreach-Object { "$_" }
$x | Select $f | Export-Csv NewFile.csv -NoTypeInformation
My import CSV contains a few hundred columns and about half likely won't be populated, so getting rid of the extra columns was necessary. Now I just need to figure out how to counteract the unintended re-ordering of the columns into alphabetical order by name, without changing the names.