Writing errors to CSV in Powershell - powershell

$csv = Get-Content c:\users\user\downloads\OutofContact.csv
foreach ($computer in $csv)
{
try{
$report = New-Object -TypeName PSObject -Property #{
ComputerName = (Resolve-DnsName $computer).Name
IPAddress = (Resolve-DnsName $computer).IPAddress
}
$report | select-object -Property ComputerName, IPAddress | Export-Csv -Path Results.csv -notype -append
}catch{
Write-Error "$computer not found" | Export-Csv -Path Results.csv -notype -append
}
}
I'm using the above code to check the DNS entries for a list of machines. Some of the machines do not exist in DNS and will throw an error. I want those machines to write the error into the CSV, however they just show up as blank rows.
How can I get the errors to write to the CSV as well?

I would refactor and optimize duplicate calls, and only add one object at the end...
Something like this:
#$csv = Get-Content c:\users\user\downloads\OutofContact.csv
# test
$csv = #('localhost', 'doesnotexist', 'localhost', 'doesnotexist')
$allReports = [System.Collections.ArrayList]::new()
foreach ($computer in $csv)
{
$report = [pscustomobject]#{
'ComputerName' = $computer
'IPAddress' = 'none'
'Status' = 'none'
}
try
{
# this can return multiple entries/ipaddresses
$dns = Resolve-DnsName $computer -ErrorAction Stop | Select -First 1
$report.ComputerName = $dns.Name
$report.IPAddress = $dns.IPAddress
$report.Status = 'ok'
}
catch
{
Write-Error "$computer not found"
}
finally
{
$null = $allReports.Add($report);
}
}
# write to csv file once...
$allReports | Export-Csv -Path c:\temp\Results.csv -NoTypeInformation #??? keep this? -Append
You will want to walk through the code and debug and change to your specific requirements.

Related

CSV Output Unreadable

I'm trying to export the results of this simple script to a .csv file. I get the results but it either returns information about data of the results or a long jumble of data I'm sure how to parse correctly.
<#
Will ping all devices in list and display results as a simple UP or DOWN, color coded Red or Green.
#>
$Names = Get-Content -Path "C:\TestFolder\GetNames.txt"
$Output = #()
foreach ($name in $names)
{
if (Test-Connection -ComputerName $name -Count 1 -ErrorAction SilentlyContinue)
{
$Result1 += "$name, up"
Write-Host "$name, up" -ForegroundColor Green
}
else
{
$Result2 += "$name, down"
Write-Host "$name, down" -ForegroundColor Red
}
}
$Output += $Result1, $Result2
$Output = $Output | Select-Object
$Output | Export-Csv -Path 'C:\psCSVFiles\mycsv.csv' -NoTypeInformation
Results of this return:
Length
49768
25081
What am I doing wrong here? Thanks
Don't attempt to "format" the output strings manually - Export-Csv will take care of that part.
What you want to do is create objects with properties corresponding to the columns you want in your CSV:
$Names = Get-Content -Path "C:\TestFolder\GetNames.txt"
$Output = foreach ($name in $names) {
# test if computer is reachable/pingable
$isUp = Test-Connection -ComputerName $name -Count 1 -ErrorAction SilentlyContinue -Quiet
# construct output object with results
[pscustomobject]#{
ComputerName = $name
Status = if($isUp){ 'Up' }else{ 'Down' }
}
}
# Export to CSV
$Output |Export-Csv -Path 'C:\psCSVFiles\mycsv.csv' -NoTypeInformation
Alternatively, use Select-Object to modify the input strings directly using the pipeline:
Get-Content -Path "C:\TestFolder\GetNames.txt" |Select #{Name='ComputerName';Expression={$_}},#{Name='Status';Expression={if(Test-Connection -ComputerName $_ -Count 1 -ErrorAction SilentlyContinue -Quiet){'Up'}else{'Down'}}} |Export-Csv -Path 'C:\psCSVFiles\mycsv.csv' -NoTypeInformation

PowerShell Exporting

Can someone point me in the right direction? Basically, I would like to export the results of my testpath to a csv. Below is what I am working with. I have read a couple Microsoft documents but they only seem to confuse me even more. Any feedback is appreciated.
$ComputerList = (Get-ADComputer -Filter *).name
$ComputerList
write-host "`n"
Foreach ($Computer in $ComputerList)
{
$userfolders = get-childitem "\\$Computer\C$\users\"
foreach ($user in $userfolders) {
$ErrorActionPreference= 'silentlycontinue'
$path = $user.fullname
write-host $path
$t = test-path -Path "$path\AppData\Local\Google\Chrome\User Data\Default"
IF ($t -eq 'True') {write-host "Has it" -ForegroundColor yellow} ELSE {write-host "no"}
write-host "`n"
}
$Output =New-Object -TypeName PSObject -Property #{
} | Select-Object
}
$Output | C:\Users\"user"\Chrome.csv
write-output "Script finished. Please check output files"
Assuming you want a record per user per computer, there's two things you want to change structurally:
Create new objects in the inner foreach loop
Assign all the objects created to $Output:
$ComputerList = (Get-ADComputer -Filter *).name
$ComputerList
write-host "`n"
$Output = Foreach ($Computer in $ComputerList) {
$userfolders = get-childitem "\\$Computer\C$\users\"
foreach ($user in $userfolders) {
$ErrorActionPreference = 'silentlycontinue'
$path = $user.fullname
write-host $path
$t = test-path -Path "$path\AppData\Local\Google\Chrome\User Data\Default"
IF ($t -eq 'True') {write-host "Has it" -ForegroundColor yellow} ELSE {write-host "no"}
write-host "`n"
New-Object -TypeName PSObject -Property #{
# We still need a bit of magic here
}
}
}
$Output | C:\Users\"user"\Chrome.csv
write-output "Script finished. Please check output files"
Now we just need to decide on what properties to add to our output objects:
New-Object -TypeName PSObject -Property #{
# We definitely want to know which computer and user profile the results are for!
ComputerName = $Computer
ProfileName = $user.Name
# And finally we want the results of `Test-Path`
Result = $t
}
Here's another option. Though nowhere near as elegant as what Matthias gave you. ;-}
It's just a refactor, to narrow down your code and pass everything directly and output by default, without the need for all the, Write-* stuff and the like. PowerShell just grants a number of ways to accomplish a use case.
Clear-Host
$null = New-Item -Path 'C:\Temp\Chrome.csv' -Force
$Status = $null
$env:COMPUTERNAME,'Localhost', '127.0.0.1' |
Foreach {
Get-ChildItem "\\$PSItem\C$\users\" |
foreach {
$ErrorActionPreference = 'silentlycontinue'
# Use variable squeezing to assign and output to the screen
($path = $PSItem.fullname)
If (test-path -Path "$path\AppData\Local\Google\Chrome\User Data\Default") {$Status = 'Has it'}
Else {$Status = 'no'}
}
[PSCustomObject] #{
ComputerName = $PSItem
Status = $Status
} | Export-Csv -Path 'C:\Temp\Chrome.csv' -Append
}
'Script finished. Please check output files'
# Results on screen
<#
\\104DB2FE-76B8-4\C$\users\ContainerAdministrator
\\104DB2FE-76B8-4\C$\users\ContainerUser
\\104DB2FE-76B8-4\C$\users\Public
\\104DB2FE-76B8-4\C$\users\WDAGUtilityAccount
\\Localhost\C$\users\ContainerAdministrator
\\Localhost\C$\users\ContainerUser
\\Localhost\C$\users\Public
\\Localhost\C$\users\WDAGUtilityAccount
\\127.0.0.1\C$\users\ContainerAdministrator
\\127.0.0.1\C$\users\ContainerUser
\\127.0.0.1\C$\users\Public
\\127.0.0.1\C$\users\WDAGUtilityAccount
Script finished. Please check output files
#>
Import-Csv -Path 'C:\Temp\Chrome.csv'
# Results
<#
104DB2FE-76B8-4 no
Localhost no
127.0.0.1 no
#>
Clear-Host
$null = New-Item -Path 'C:\Temp\Chrome.csv' -Force
$Status = $null
$env:COMPUTERNAME,'Localhost', '127.0.0.1' |
Foreach {
Get-ChildItem "\\$PSItem\C$\users\" |
foreach {
$ErrorActionPreference = 'silentlycontinue'
# Use variable squeezing to assign and output to the screen
($path = $PSItem.fullname)
If (test-path -Path "$path\AppData\Local\MicrosoftEdge") {$Status = 'Has it'}
Else {$Status = 'no'}
}
[PSCustomObject] #{
ComputerName = $PSItem
Status = $Status
} | Export-Csv -Path 'C:\Temp\Chrome.csv' -Append
}
'Script finished. Please check output files'
# Results
<#
\\104DB2FE-76B8-4\C$\users\ContainerAdministrator
\\104DB2FE-76B8-4\C$\users\ContainerUser
\\104DB2FE-76B8-4\C$\users\Public
\\104DB2FE-76B8-4\C$\users\WDAGUtilityAccount
\\Localhost\C$\users\ContainerAdministrator
\\Localhost\C$\users\ContainerUser
\\Localhost\C$\users\Public
\\Localhost\C$\users\WDAGUtilityAccount
\\127.0.0.1\C$\users\ContainerAdministrator
\\127.0.0.1\C$\users\ContainerUser
\\127.0.0.1\C$\users\Public
\\127.0.0.1\C$\users\WDAGUtilityAccount
Script finished. Please check output files
#>
Import-Csv -Path 'C:\Temp\Chrome.csv'
# Results
<#
ComputerName Status
------------ ------
104DB2FE-76B8-4 Has it
Localhost Has it
127.0.0.1 Has it
#>

Custom Foreach loop nslookup export to csv

I'm new to PowerShell scripting. I am trying to make a script which resolves a list of DNS names to their IPs and outputs them as a CSV file. When a server is unresolvable it should be output to a separate file.
Here is my code:
$location
$location = Read-Host "CSV Path: "
$Names = Import-Csv -Path $location
foreach($n in $Names)
{
try
{
$output = $n.NAME
$variable1 = [system.net.dns]::resolve($output) | Select
HostName,AddressList
$variable1
$IP = $variable1.AddressList | Select-Object IPAddressToString
$IPN = $IP.IPAddressToString
$csv+=New-Object psobject -Property #{IPAddresse= $IPN;Name=
$output} |
Export-Csv \\filepath\Working.csv -NoTypeInformation
}
catch
{
Write-host "$output is unreachable."
Write-Output "$output" | Export-Csv \\Filepath\Unreachable.csv -
Append -Encoding ASCII
}
}
edit: The code was working quite well but now it says there is a delimiter mistake with the import but i dont know why this all of a sudden comes up as the code worked didnt got any edit and suddenly doesnt work anymore
Here's a simplified/corrected version of your code:
$location = Read-Host "CSV Path: "
$Names = Import-Csv -Path $location
foreach($n in $Names)
{
try {
$Computer = [system.net.dns]::resolve($n.NAME) | Select HostName,AddressList
$IP = ($Computer.AddressList).IPAddressToString
New-Object PSObject -Property #{IPAddress=$IP; Name=$Computer.HostName} | Export-Csv \\filepath\Working.csv -NoTypeInformation -Append
} catch {
Write-Host "$($n.NAME) is unreachable."
Write-Output $n | Export-Csv \\Filepath\Unreachable.csv -Append -Encoding ASCII
}
}

Powershell Export to CSV from ForEach Loop

I'm new to Powershell but I've given it my best go.
I'm trying to create a script to copy a file to the All Users Desktop of all the XP machines in an Array. The script basically says "If the machine is pingable, copy the file, if not, don't." I then want to export this information into a CSV file for further analysis.
I've set it all but no matter what I do, it will only export the last PC that it ran though. It seems to run through all the PC's (tested with outputting to a txt file) but it will not log all the machines to a CSV. Can anyone give any advise?
$ArrComputers = "PC1", "PC2", "PC3"
foreach ($Computer in $ArrComputers) {
$Reachable = Test-Connection -Cn $Computer -BufferSize 16 -Count 1 -ea 0 -quiet
$Output = #()
#Is the machine reachable?
if($Reachable)
{
#If Yes, copy file
Copy-Item -Path "\\servername\filelocation" -Destination "\\$Computer\c$\Documents and Settings\All Users\Desktop\filename"
$details = "Copied"
}
else
{
#If not, don't copy the file
$details = "Not Copied"
}
#Store the information from this run into the array
$Output =New-Object -TypeName PSObject -Property #{
SystemName = $Computer
Reachable = $reachable
Result = $details
} | Select-Object SystemName,Reachable,Result
}
#Output the array to the CSV File
$Output | Export-Csv C:\GPoutput.csv
Write-output "Script has finished. Please check output files."
The problem is this:
#Store the information from this run into the array
$Output =New-Object -TypeName PSObject -Property #{
SystemName = $Computer
Reachable = $reachable
Result = $details
} | Select-Object SystemName,Reachable,Result
}
#Output the array to the CSV File
$Output | Export-Csv C:\GPoutput.csv
Each iteration of your foreach loop saves to $Output. Overwriting what was there previously, i.e., the previous iteration. Which means that only the very last iteration is saved to $Output and exported. Because you are running PowerShell v2, I would recommend saving the entire foreach loop into a variable and exporting that.
$Output = foreach ($Computer in $ArrComputers) {
New-Object -TypeName PSObject -Property #{
SystemName = $Computer
Reachable = $reachable
Result = $details
} | Select-Object SystemName,Reachable,Result
}
$Output | Export-Csv C:\GPoutput.csv
You would want to append the export-csv to add items to the csv file
Here is an example
foreach ($item in $ITGlueTest.data)
{
$item.attributes | export-csv C:\organization.csv -Append
}
Here you go. This uses PSCustomObject which enumerates data faster than New-Object. Also appends to the .csv file after each loop so no overwriting of the previous data.
foreach ($Computer in $ArrComputers) {
$Reachable = Test-Connection -Cn $Computer -BufferSize 16 -Count 1 -ea 0 -quiet
#Is the machine reachable?
if($Reachable)
{
#If Yes, copy file
Copy-Item -Path "\\servername\filelocation" -Destination "\\$Computer\c$\Documents and Settings\All Users\Desktop\filename"
$details = "Copied"
}
else
{
#If not, don't copy the file
$details = "Not Copied"
}
#Store the information from this run into the array
[PSCustomObject]#{
SystemName = $Computer
Reachable = $reachable
Result = $details
} | Export-Csv C:\yourcsv.csv -notype -Append
}

How to export data to CSV in PowerShell?

foreach ($computer in $computerlist) {
if((Test-Connection -Cn $computer -BufferSize 16 -Count 1 -ea 0 -quiet))
{
foreach ($file in $REMOVE) {
Remove-Item "\\$computer\$DESTINATION\$file" -Recurse
Copy-Item E:\Code\powershell\shortcuts\* "\\$computer\$DESTINATION\"
}
} else {
Write-Host "\\$computer\$DESTINATION\"
}
}
I want to export Write-Host "\$computer\$DESTINATION\" to the CSV files so I know which computers were offline when the script ran.
I am running this from a Windows 7 machine
This solution creates a psobject and adds each object to an array, it then creates the csv by piping the contents of the array through Export-CSV.
$results = #()
foreach ($computer in $computerlist) {
if((Test-Connection -Cn $computer -BufferSize 16 -Count 1 -ea 0 -quiet))
{
foreach ($file in $REMOVE) {
Remove-Item "\\$computer\$DESTINATION\$file" -Recurse
Copy-Item E:\Code\powershell\shortcuts\* "\\$computer\$DESTINATION\"
}
} else {
$details = #{
Date = get-date
ComputerName = $Computer
Destination = $Destination
}
$results += New-Object PSObject -Property $details
}
}
$results | export-csv -Path c:\temp\so.csv -NoTypeInformation
If you pipe a string object to a csv you will get its length written to the csv, this is because these are properties of the string, See here for more information.
This is why I create a new object first.
Try the following:
write-output "test" | convertto-csv -NoTypeInformation
This will give you:
"Length"
"4"
If you use the Get-Member on Write-Output as follows:
write-output "test" | Get-Member -MemberType Property
You will see that it has one property - 'length':
TypeName: System.String
Name MemberType Definition
---- ---------- ----------
Length Property System.Int32 Length {get;}
This is why Length will be written to the csv file.
Update: Appending a CSV
Not the most efficient way if the file gets large...
$csvFileName = "c:\temp\so.csv"
$results = #()
if (Test-Path $csvFileName)
{
$results += Import-Csv -Path $csvFileName
}
foreach ($computer in $computerlist) {
if((Test-Connection -Cn $computer -BufferSize 16 -Count 1 -ea 0 -quiet))
{
foreach ($file in $REMOVE) {
Remove-Item "\\$computer\$DESTINATION\$file" -Recurse
Copy-Item E:\Code\powershell\shortcuts\* "\\$computer\$DESTINATION\"
}
} else {
$details = #{
Date = get-date
ComputerName = $Computer
Destination = $Destination
}
$results += New-Object PSObject -Property $details
}
}
$results | export-csv -Path $csvFileName -NoTypeInformation
simply use the Out-File cmd but DON'T forget to give an encoding type:
-Encoding UTF8
so use it so:
$log | Out-File -Append C:\as\whatever.csv -Encoding UTF8
-Append is required if you want to write in the file more then once.
what you are searching for is the Export-Csv file.csv
try using Get-Help Export-Csv to see whats possible
also Out-File -FilePath "file.csv" will work
You can always use the
echo "Column1`tColumn2`tColumn3..." >> results.csv
You will need to put "`t" between the columns to separates the variables into their own column. Here is the way I wrote my script:
echo "Host`tState" >> results.csv
$names = Get-Content "hostlist.txt"
foreach ($name in $names) {
$count = 0
$count2 = 13490
if ( Test-Connection -ComputerName $name -Count 1 -ErrorAction SilentlyContinue ) {
echo "$name`tUp" >> results.csv
}
else {
echo "$name`tDown" >> results.csv
}
$count++
Write-Progress -Activity "Gathering Information" -status "Pinging Hosts..." -percentComplete ($count / $count2 *100)
}
This is the easiest way to me. The output I get is :
Host|State
----------
H1 |Up
H2 |UP
H3 |Down
You can play around with the look, but that's the basic idea. The $count is just a progress bar if you want to spice up the look