I need help with manipulating data that I export to a CSV. Right now I actually learned how to merge columns together so that once it is put into a CSV the hostname shows on only 1 line and the other two columns I merge together so that each line will only have one hostname. I however need to take it a step further.
Below is my progression:
Phase 1:
This was only good because the script retrieved the data, but as you can see below Hostname1 shows up on every line for each caption and version, which would lead to several repeats of a machine name for several lines making the CSV file extremely longer than it necessarily should be.
Script:
GWMI -Class Win32_Product -Comp (GC D:\McAfeeHost.txt) |
Where {$_.Vendor -like "mcafee*" -or $_.Vendor -like "usaf*"} |
Select PSComputerName, Caption, Version |
Export-Csv -NoTypeInformation d:\Get-HBSSModules-Test.csv
Output in CSV:
PSComputerName caption version
Hostname1 McAfee Host Intrusion Prevention 8.00.0801
Hostname1 McAfee Policy Auditor Agent 6.2.0
Hostname1 McAfee DLP Endpoint 10.0.260.42
Hostname1 McAfee VirusScan Enterprise 8.8.08000
Hostname1 ACCM 3.0.4.1
Hostname1 McAfee Agent 5.00.4006
Phase 2:
I have progressed by merging the caption and version together, so that each hostname that is fetched from -Comp (GC D:\McAfeeHost.txt) shows up only once per line. While this is more of what I am looking for, it isn't the best option for formatting as shown below the in the output of the CSV.
Script:
GWMI -Class Win32_Product -Comp (GC D:\McAfeeHost.txt) |
Where {$_.Vendor -like "mcafee*" -or $_.Vendor -like "usaf*"} |
Select PSComputername, Caption, Version |
Sort-Object Caption |
Export-Csv -NoTypeInformation d:\Get-HBSSModules-Test.csv
$a = Import-Csv d:\Get-HBSSModules-Test.csv
$a | Group-Object PSComputerName |
Select-Object #{name="PSComputerName";expression={$_.Name}},
#{name="caption, version";expression={($_.Group | % { $_.Caption, $_.Version }) -join ';'}} |
Export-Csv d:\Get-HBSSModules-Test.csv -NoTypeInformation
Output to CSV:
Phase 3:
If at all possible I would like to take each caption along with its version and put them together like phase 2, but separated by columns and still only having one hostname per line as shown below:
I do not have multiple computers available, nor have I any McAffee product installed. However, here is a possible solution to your problem. You would have to adjust Vendor to PSComputerName, the -match RegEx, and add the -ComputerName or -CimSession parameter to Get-CimInstance. But the basic concept should work.
$Product = Get-CimInstance -ClassName Win32_Product | Where-Object {$_.Vendor -match '(microsoft|intel)'}
$Group = $Product | Group-Object -Property Vendor
$result = foreach ($Vendor in $Group) {
$Products = foreach ($item in $Vendor.Group) {
"$($item.Caption);$($item.Version)"
}
$Products = $Products -join ','
"$($Vendor.Name),$Products"
}
$HeaderLength = ($result | ForEach-Object {($_ -split ',').Count} | Sort-Object -Descending)[0]-1
$Header = "Vendor,"
$x = 1
$Header += do {
$x++
"Caption;Version,"
} until ($x -eq $HeaderLength)
$Header | Out-File -FilePath $env:TEMP\strange.csv
$result | Out-File -FilePath $env:TEMP\strange.csv -Append
If you open $env:TEMP\strange.csv in Excel and use the Text to columns function with , as the delimiter, you get the result es requested in your Phase 3 Output.
It's not beautiful and also it doesn*t make any sense to me, but that's what you requested for. :p
Using Group-Object and Flatten-Object:
Given:
$CSV = ConvertFrom-CSV #"
PSComputerName,caption,version
Hostname1,McAfee Host Intrusion Prevention,8.00.0801
Hostname1,McAfee Policy Auditor Agent,6.2.0
Hostname1,McAfee DLP Endpoint,10.0.260.42
Hostname1,McAfee VirusScan Enterprise,8.8.08000
Hostname1,ACCM,3.0.4.1
Hostname1,McAfee Agent,5.00.4006
Hostname2,McAfee Agent,5.00.4006
Hostname2,McAfee DLP Endpoint,10.0.260.42
Hostname2,McAfee DLP Endpoint,10.0.260.42
Hostname3,McAfee Policy Auditor Agent,6.2.0
Hostname3,McAfee DLP Endpoint,10.0.260.42
"#
Command:
$CSV | Group PSComputerName | Flatten | Format-Table
Result:
Values.1 Count Group.1.PSComputerName Group.1.caption Group.1.version Group.2.PSComputerName Group.2.caption
-------- ----- ---------------------- --------------- --------------- ---------------------- ---------------
Hostname1 6 Hostname1 McAfee Host Intrusion Prevention 8.00.0801 Hostname1 McAfee Policy A...
Hostname2 3 Hostname2 McAfee Agent 5.00.4006 Hostname2 McAfee DLP Endp...
Hostname3 2 Hostname3 McAfee Policy Auditor Agent 6.2.0 Hostname3 McAfee DLP Endp...
Related
I am having an issue with exporting results to a txt in Powershell.
I have 2 commands I need to run and when they are done, I am hoping to get something like this:
Name Version
---- -------
Mitel Connect 214.100.1252.0
Cylance Unified Agent 2.4.1070.1
Instead of this:
Name Version
---- -------
Mitel Connect 214.100.1252.0
Name Version
---- -------
Cylance Unified Agent 2.4.1070.1
Here is the code:
get-package 'Microsoft Edge','Mitel Connect', '*7-Zip*','*Cylance*','*Office Profession*','*Dameware*','Cisco AnyConnect Secure Mobility Client' | select name,version | Out-File "C:\temp\export.txt" -Append
Get-WmiObject -Class Win32_Product | where Name -eq "Manageengine AssetExplorer Agent" | select Name, Version | Out-File "C:\temp\export.txt" -Append
I have tried piping the code, google and nothing works,
Does anyone have any idea who to get the output?
If the output file only needs to record the output from these two commands:
Call (& ) them in sequence via a script block ({ ... })...
... pipe the output to a single Select-Object call ...
... which you can then pipe to a single Out-File call.
& {
Get-Package 'Microsoft Edge','Mitel Connect', '*7-Zip*','*Cylance*','*Office Profession*','*Dameware*','Cisco AnyConnect Secure Mobility Client'
Get-CimInstance -Class Win32_Product | Where-Object Name -eq "Manageengine AssetExplorer Agent"
} |
Select-Object Name, Version |
Out-File "C:\temp\export.txt"
That way, the output objects are formatted together, as a single table, by the single Out-File call.
(By contrast, if you call Out-File multiple times, you'll get a separate table in the file for each call, which is what you saw.)
Note, however, that the resulting file format is only meant for display purposes, as it uses the same rich formatting you'd see in the console (terminal) by default, which is meant for the human observer rather than programmatic processing.
For programmatic processing, consider a structured text format, such as CSV (Export-Csv), which also allows you to append to the file iteratively later.
Since you only get the name and version of these objects, pushing them into an array and then exporting the array would work as you intend it to. However, in case you try to add more properties in each select, this will not work. The objects in the array will preserve the structure of the 1st element added to it.
This is the code that managed to create the desired result.
$arr = #()
get-package 'Microsoft Edge' | select name, version | % { $arr += $_ }
Get-WmiObject -Class Win32_Product | where Name -eq "Go Programming Language amd64 go1.18" | select Name, Version | % { $arr += $_ }
$arr | Out-File "C:\temp\export.txt" -Append
The following 2 snippets show the undesired effect if you try to add properties in the select that don't exist in both structures.
$arr = #()
Get-WmiObject -Class Win32_Product | where Name -eq "Go Programming Language amd64 go1.18" | select Name, Vendor, Version | % { $arr += $_ }
get-package 'Microsoft Edge' | select name,version | % { $arr += $_ }
$arr | Out-File "C:\temp\export.txt" -Append
This will have an empty Vendor prop for the "get-package" objects
$arr = #()
get-package 'Microsoft Edge' | select name,version | % { $arr += $_ }
Get-WmiObject -Class Win32_Product | where Name -eq "Go Programming Language amd64 go1.18" | select Name, Vendor, Version | % { $arr += $_ }
$arr | Out-File "C:\temp\export.txt" -Append
This will disregard the "Vendor" property for all data from "Get-WmiObject" Command
I am writing a script to compare 2 csv files to get the outdated software's and put them into another csv file. I have a problem when I try to get the outdated softwares, it just shows all the softwares installed again. This is my script.
$CurrentList = Import-csv C:\Users\Administrator\CSVReports\InstalledSoftware.csv | select
ComputerName, DisplayName, DisplayVersion, Publisher
$ApprovedList = Import-csv C:\Users\Administrator\ApprovedSoftware\ApprovedSoftwareList.csv | select
DisplayName, DisplayVersion, Publisher
$ApprovedList = $ApprovedList | select ComputerName, DisplayName, DisplayVersion, Publisher
$Outdated = Compare-Object -ReferenceObject $CurrentList -DifferenceObject $ApprovedList -Property
DisplayName, DisplayVersion, Publisher -PassThru | Where Sideindicator -eq '<='
$Outdated = $Outdated | Foreach {
$Item = $_
$ApprovedVersion = $ApprovedList | Where {$_.DisplayName -eq $Item.DisplayName -and $_.Publisher -eq
$Item.Publisher } | Select -ExpandProperty DisplayVersion -First 1
[PSCustomObject]#{
ComputerName = $_.ComputerName
DisplayName = $_.DisplayName
CurrentVersion = $_.DisplayVersion
ApprovedVersion = $ApprovedVersion
Publisher = $_.Publisher
}
}
$Outdated | export-csv OutdatedSoftware.csv -NoTypeInformation
My CSV files look like this
InstalledSoftware.csv
ComputerName DisplayName DisplayVersion Publisher
Win2008R2 Google Chrome 86.0.4280.88 Google LLC
Win2008R2 VmWare Tools 10.3.5.10430147 VMWare, LLC
Win2012R2 Google Chrome 86.0.4280.88 Google LLC
Win2012R2 VmWare Tools 10.3.5.10430147 VMWare, LLC
Win2016 Google Chrome 86.0.4280.88 Google LLC
Win2016 VmWare Tools 10.3.5.10430147 VMWare, LLC
ApprovedList.csv
DisplayName DisplayVersion Publisher
Google Chrome 87.0.4280.88 Google LLC
VmWare Tools 10.3.5.10430147 VMWare, LLC
Only chrome should be in the OutDatedSoftware csv as only the chrome version is different but I get all the softwares. I also want to know which server the software is on. Appreciate the help.
I'm having weird results with Publisher. This should do the trick, however
$CurrentList = Import-csv C:\Users\Administrator\CSVReports\InstalledSoftware.csv
$ApprovedList = Import-csv C:\Users\Administrator\ApprovedSoftware\ApprovedSoftwareList.csv
$Outdated = Compare-Object -ReferenceObject $CurrentList -DifferenceObject $ApprovedList -Property DisplayName, DisplayVersion -PassThru | Where-Object Sideindicator -eq '<='
$Outdated = foreach($oldversion in $Outdated)
{
$oldversion.DisplayName
$ApprovedList | Where {$_.DisplayName -eq $oldversion.DisplayName} | ForEach-Object {
[PSCustomObject]#{
ComputerName = $oldversion.ComputerName
DisplayName = $oldversion.DisplayName
CurrentVersion = $oldversion.DisplayVersion
ApprovedVersion = $_.DisplayVersion
Publisher = $oldversion.Publisher
}
}
}
$Outdated | Export-Csv OutdatedSoftware.csv -NoTypeInformation
That new code work fine ...
Except that if your csv are tab delimited, you will need to specify it when importing the csv.
Add
`-Delimiter "`t"`
to your 2 Import-csv statements.
Import-csv C:\Users\Administrator\CSVReports\InstalledSoftware.csv | select ComputerName, DisplayName, DisplayVersion, Publisher
Import-csv C:\Users\Administrator\ApprovedSoftware\ApprovedSoftwareList.csv -Delimiter "`t" | select DisplayName, DisplayVersion, Publisher
Assuming your csv are tab-delimited properly, it should work.
If it still doesn't afterward, try the Import statement in the console alone to see what is actually imported before going further.
When testing from your example, SO did not preserve the tab delimiter so it didn't produce the proper results at first.
edit:
Based on your comment, your csv appear to be improperly formatted.
Not specifying the tab delimited for a tab delimited csv will import the csv as a 1 column object.
Incorrect -
While pretty, all the columns are linked together, meaning you actually have only one column. This can be validated by trying to access any of the column. They will all be blanks.
The only column being imported in this case is called ComputerName DisplayName DisplayVersion Publisher
Correct
Notice there is no dashes in-between each column. The csv have definitely 4 columns.
I have the following code that finds the free space on a drive on a server called 'Automate' and outputs the result to a .csv file:
$AutomateD = #()
Clear-Host
$AutomateD += Get-WmiObject Win32_logicaldisk -ComputerName Automate ` | Where-Object {$_.VolumeName -ne 'Logs' -and $_.DeviceID -eq 'D:'}| Format-Table DeviceID, MediaType, `
#{Name="Size(GB)";Expression={[decimal]("{0:N0}" -f($_.size/1gb))}}, `
#{Name="Free Space(GB)";Expression={[decimal]("{0:N0}" -f($_.freespace/1gb))}}, `
#{Name="Free (%)";Expression={"{0,6:P0}" -f(($_.freespace/1gb) / ($_.size/1gb))}} `
-AutoSize
$AutomateD | Export-Csv -path "C:\Powershell\Automate\AutomateD.csv" -NoTypeInformation -Encoding Unicode
$ImportAutoD = Import-CSV C:\Powershell\Automate\AutomateD.csv | ConvertTo-Html
The issue is that I get some strange results when I open the csv -
"ClassId2e4f51ef21dd47e99d3c952918aff9cd","pageHeaderEntry","pageFooterEntry","autosizeInfo","shapeInfo","groupingEntry"
"033ecb2bc07a4d43b5ef94ed5a35d280",,,"Microsoft.PowerShell.Commands.Internal.Format.AutosizeInfo","Microsoft.PowerShell.Commands.Internal.Format.TableHeaderInfo",
"9e210fe47d09416682b841769c78b8a3",,,,,
"27c87ef9bbda4f709f6b4002fa4af63c",,,,,
"4ec4f0187cb04f4cb6973460dfe252df",,,,,
"cf522b78d86c486691226b40aa69e95c",,,,,
However, if I just output the $AutomateD variable on the screen, I get a nice table like so:
PS C:\Powershell\SCRIPT> $AutomateD
DeviceID MediaType Size(GB) Free Space(GB) Free (%)
-------- --------- -------- -------------- --------
D: 12 1225 183 15%
Any ideas as to what is going on? There seems to be an problem in the export process, although I don't have any errors to go on what I'm doing wrong.
You need to remove the format-table and replace it with a select-object. You'll also need to drop the -autosize from the end of your pipeline. In addition it is not required but I would recommend dropping the kind odd array creation and then adding a single value to the array, the script can actually get done in a single pipeline with the exception of the import-csv (which I'm not really sure you need but I'll leave it in assuming it's required elsewhere in the script)
Clear-Host
Get-WmiObject Win32_logicaldisk ` | Where-Object {$_.VolumeName -ne 'Logs' -and $_.DeviceID -eq 'D:'}| Select-Object DeviceID, MediaType, `
#{Name="Size(GB)";Expression={[decimal]("{0:N0}" -f($_.size/1gb))}}, `
#{Name="Free Space(GB)";Expression={[decimal]("{0:N0}" -f($_.freespace/1gb))}}, `
#{Name="Free (%)";Expression={"{0,6:P0}" -f(($_.freespace/1gb) / ($_.size/1gb))}} |
Export-Csv -path d:\scripts\test.csv -NoTypeInformation -Encoding Unicode -Force
$ImportAutoD = Import-CSV d:\scripts\test.csv | ConvertTo-Html
Also note that I did make some path changes to make it work on my machine without building out a new folder structure.
when exporting the csv use -NoTypeInformation
I am trying to run this simple script to get the services and the accounts that are running them. My problem is that the data looks correct in the report but the server name does not change in the report. Here is the code.
$servers = get-content C:\temp\servers.txt
foreach ($server in $servers)
{
Get-WmiObject win32_service | Select-Object -Property SystemName, DisplayName, startname | format-list -GroupBy startname | Out-File c:\temp\results.txt
}
This will work.
$servers = get-content C:\temp\servers.txt
foreach ($server in $servers)
{
Get-WmiObject win32_service -Computername $server | Select-Object -Property SystemName, DisplayName, startname | format-list -GroupBy startname | Out-File -append c:\temp\results.txt
}
You can also use the following but note SystemName is not a property of Win32_Service. To troubleshoot this, try using Get-Service | Select -first 1 | Get-Member will display the available attributes (sorry if this is the wrong term) with the important one being MachineName thus replace SystemName for MachineName and you'll get the desired results. Look up Hey Scripting Guy articles for further information. For example, this page
gc .\Servers.txt | foreach {get-service -ComputerName $_ | `
Select-Object -Property MachineName, DisplayName, startname | `
format-list -GroupBy startname | Out-File -append c:\temp\results.txt}
Note, I'm using the backtick ` to make the command readable, paste into the Powershell ISE to save/run the script or just paste the lines into the console and press enter twice to run the multi-line script.
I have the following powershell to output a list of IP addresses for failed logon events:
$DT = [DateTime]::Now.AddDays(-1) # check only last 24 hours
$l = Get-EventLog -LogName 'Security' -InstanceId 4625 -After $DT | Select-Object #{n='IpAddress';e={$_.ReplacementStrings[-2]} }
$g = $l | group-object -property IpAddress | where {$_.Count -gt 20} | Select -property Name | export-csv c:\users\export.csv
I'd really like to improve it so it outputs the IP address like it is now, plus the $_.Count. I've tried a few things but I think I'm stuck in SQL world!
I think all you need to do is, in the second pipeline, replace
Select -property Name
with
Select -property Name, Count
(But I would check by looking at the properties on the objects returned from the group-object with get-member first.)