Write Informations into existing csv - powershell

My existing csv looks like this:
"Name","Surename","Workstation"
"Doe","John","PC1"
"Fonzarelli","Arthur","PC4"
"Tribbiani","Joey","PC77"
Now, I want to check whether the host is online or not and write a new column named "Status" with the result into my csv.
$file = Import-Csv "C:\Scripts\WS-Status.csv"
Foreach ($ws in $file) {
If (Test-Connection $ws.Workstation -Count 1 -Quiet) {
Write-Host $ws.Workstation "is online"
}
Else {Write-Host $ws.Workstation "is offline"}
}
It works fine in the console, but how the heck can I export the result into my csv?

You could use the Add-Member cmdlet to add a member (status) to your current entity:
$file = Import-Csv "C:\Scripts\WS-Status.csv"
Foreach ($ws in $file)
{
if (Test-Connection $ws.Workstation -Count 1 -Quiet)
{
Add-Member -InputObject $ws -NotePropertyName "Status" -NotePropertyValue "online"
}
else
{
Add-Member -InputObject $ws -NotePropertyName "Status" -NotePropertyValue "offline"
}
}
$file | Export-Csv "C:\Scripts\WS-Status.csv" -NoTypeInformation

You could create a PSCustomObject within yourForEach loop:
$file = Import-Csv "C:\Scripts\WS-Status.csv"
Foreach ($ws in $file) {
if(Test-Connection $ws.Workstation -Count 1 -Quiet){
Write-Host $ws.Workstation "is online"
$status = "Online"
}else{
Write-Host $ws.Workstation "is offline"
$status = "Offline"
}
[array]$result += [PSCustomObject] #{
Name = $ws.Name
Surename = $ws.Surename
Workstation = $ws.Workstation
Status = $status
}
}
$result | Export-Csv thing.csv -NoTypeInformation

You have to use Out-File cmdlet which enables you to send pipelined output directly to a text file.
$file = Import-Csv "C:\Scripts\WS-Status.csv"
Foreach ($ws in $file) {
If (Test-Connection $ws.Workstation -Count 1 -Quiet) {
$ws.Workstation + " is online" | Out-File -Append OutPutFile.csv
}
Else {
$ws.Workstation + ' is offline' | Out-File -Append OutPutFile.csv
}
}

Related

Powershell change/edit value of Object in Variable

I create variables in a ForEach loop using data collected from a CSV file like this:
New-Variable -Name $FlexVPN.'IP-adress' -Value (New-Object PSObject -Property #{
IP = $FlexVPN.'IP-adress'
Information = $FlexVPN.'Information'
Priority = $FlexVPN.'Priority'
RegisteredUp = $RegisteredUp
RegisteredDown = $RegisteredDown
ResponseTime = $Result = try{ Test-Connection -ComputerName $FlexVPN.'IP-adress' -Count $FlexVPN.'Priority' -ErrorAction Stop | Select ResponseTime} catch [System.Net.NetworkInformation.PingException] { $_.exception | PingFailed }})
What I'm then trying to do is to change the values of RegisteredUp and RegisteredDown depending of the respond of the ping.
I doesn't understand the New-Member stuff which I have tried but faild using.
Now I tried Set-Variable but I don´t get how to only change a Object within the Variable?
Set-Variable -Name $FlexVPN.'IP-adress' -Value (New-Object PSObject -Property #{RegisteredDown = "TESTING"})
I don´t get any errors neither it´s working.
To explain further.
If no respond on ping set Get-Date in RegisteredDown for that Variable.
If respond on ping ser Get-Date in RegisteredUp for that Variable.
I then use if/else to use the result somehow in the next version ;)
Edit
# Clear variables after loop
Remove-Variable * -force -erroraction silentlycontinue
function PingFailed {
# Add date and time when IP-address first didn't responded
$FlexVPN.RegisteredDown = 'AnotherTest'
# If only error should be printed
if($PrintError -eq 'Yes'){Write-Host -ForegroundColor Red $FlexVPN.'IP-adress' "," $FlexVPN.'Information'}
##########################################################################
####################### NO CHANGES ABOVE THIS LINE #######################
##########################################################################
# Choose between printing output or not for all rows in CSV-file [Yes/No]
$PrintOutput = 'Yes'
# Choose between printing out error or not [Yes/No]
$PrintError = 'No'
##########################################################################
####################### NO CHANGES BELOW THIS LINE #######################
##########################################################################
# Import CSV-file to Powershell to use data in code
$FlexVPNlist = Import-Csv -Path $PSScriptRoot\PingIPEmail.csv -Header 'IP-adress', 'Information', 'Priority' -Delimiter ';' -Encoding UTF7
Foreach($FlexVPN in $FlexVPNlist) {
New-Variable -Name $FlexVPN.'IP-adress' -Value (New-Object PSObject -Property #{
IP = $FlexVPN.'IP-adress'
Information = $FlexVPN.'Information'
Priority = $FlexVPN.'Priority'
RegisteredDown = 'Test'
ResponseTime = $Result = try{ Test-Connection -ComputerName $FlexVPN.'IP-adress' -Count $FlexVPN.'Priority' -ErrorAction Stop | Select ResponseTime} catch [System.Net.NetworkInformation.PingException] { $_.exception | PingFailed }})
if($PrintOutput -eq 'Yes'){
if ($host.name -eq 'Windows PowerShell ISE Host') {if ($Result.ResponseTime -eq $null) { $Host.UI.RawUI.BackgroundColor = ($bckgrnd = 'Red') } else { $psISE.Options.RestoreDefaults() }}
[PSCustomObject]#{
"IP address" = $FlexVPN.'IP-adress'
"Information" = $FlexVPN.'Information'
"Priority" = $FlexVPN.'Priority'
"Response time" = $Result.ResponseTime
"RegisteredDown" = 'Test'
}}
}
}
My Second try above works fine until I catch an exeption during ping and goes to my function PingFailed.
I want to run that function when an IP-address doesn´t respond and add Get-Date to RegisteredDown in those cases.
The error I recieve is:
At C:\Temp\Powershell scripts\PingIPEmail\PingIPEmail.ps1:49 char:13
+ $FlexVPN.RegisteredDown = 'AnotherTest'
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], SetValueInvocationException
+ FullyQualifiedErrorId : ExceptionWhenSetting`
Tried the other code
# Importing a csv
$FlexVPNList = Import-Csv -Path 'C:\Temp\Powershell scripts\PingIPEmail\PingIPEmail.csv' -Header 'IP-adress', 'Information', 'Priority' -Delimiter ';' -Encoding UTF7
Foreach($FlexVPN in $FlexVPNlist) {
$FlexVPN.GetType() # Object[]
$FlexVPN[0].GetType() # PSCustomObject
($FlexVPN[0] | gm -MemberType NoteProperty).Count # 3 Noteproperties
$FlexVPN | % {
Add-Member -InputObject $_ -NotePropertyName 'RegisteredUp' -NotePropertyValue 1 -Force
Add-Member -InputObject $_ -NotePropertyName 'RegisteredDown' -NotePropertyValue 1 -Force
}
($FlexVPN[0] | gm -MemberType NoteProperty).Count # 5 Noteproperties
$Result = try{ Test-Connection -ComputerName $FlexVPN.'IP-adress' -Count $FlexVPN.'Priority' -ErrorAction Stop | Select ResponseTime} catch [System.Net.NetworkInformation.PingException] { $_ }
if ($Result.ResponseTime -eq $null){
if ($host.name -eq 'Windows PowerShell ISE Host') { $Host.UI.RawUI.BackgroundColor = ($bckgrnd = 'Red') }
$FlexVPN.RegisteredDown = Get-Date
[PSCustomObject]#{
"IP address" = $FlexVPN.'IP-adress'
"Information" = $FlexVPN.'Information'
"Priority" = $FlexVPN.'Priority'
"Response time" = $Result.ResponseTime
"RegisteredUp" = $FlexVPN.RegisteredUp
"RegisteredDown" = $FlexVPN.RegisteredDown
}
}
if ($Result.ResponseTime -ge '0'){
if ($host.name -eq 'Windows PowerShell ISE Host') { $psISE.Options.RestoreDefaults() }
$FlexVPN.RegisteredUp = Get-Date
[PSCustomObject]#{
"IP address" = $FlexVPN.'IP-adress'
"Information" = $FlexVPN.'Information'
"Priority" = $FlexVPN.'Priority'
"Response time" = $Result.ResponseTime
"RegisteredUp" = $FlexVPN.RegisteredUp
"RegisteredDown" = $FlexVPN.RegisteredDown
}
}
This code if I understand correctly reuse the same variable for each row in my CSV file.
I want to create one variable for each row (name them the IP-address) so that I can reuse the values stored for as long as the script i running.
Looks like you are overcomplicating things. You can create a new variable (object) like this
$FlexVPN = [PSCustomObject] #{
Information='Test'
}
Show the value of Information
$FlexVPN.Information
Change the value of Information
$FlexVPN.Information = 'AnotherTest'
Show the changed value of Information
$FlexVPN.Information
a valid use case for using new-variable would be if you dynamically create/use variables
Edit
your intent is not actual clear to me but following testbed might get you some new ideas to proceed from
# Mimick importing a csv
$FlexVPN = #'
IP-Adress,Information,Priority
1.1.1.1,FlexVPN,1
2.2.2.2,FlexVPN,2
'# | ConvertFrom-Csv
$FlexVPN.GetType() # Object[]
$FlexVPN[0].GetType() # PSCustomObject
($FlexVPN[0] | gm -MemberType NoteProperty).Count # 3 Noteproperties
$FlexVPN | % {
Add-Member -InputObject $_ -NotePropertyName 'RegisteredUp' -NotePropertyValue 1 -Force
Add-Member -InputObject $_ -NotePropertyName 'RegisteredDown' -NotePropertyValue 1 -Force
}
($FlexVPN[0] | gm -MemberType NoteProperty).Count # 5 Noteproperties
Managed what I wanted by doing like this:
# Clear variables after loop
Remove-Variable * -force -erroraction silentlycontinue
# Importing a csv
$FlexVPNList = Import-Csv -Path 'C:\Temp\Powershell scripts\PingIPEmail\PingIPEmail.csv' -Header 'IP', 'Information', 'Priority' -Delimiter ';' -Encoding UTF7
$FlexVPNList | % {
Add-Member -InputObject $_ -NotePropertyName 'RegisteredUp' -NotePropertyValue '' -Force
Add-Member -InputObject $_ -NotePropertyName 'RegisteredDown' -NotePropertyValue '' -Force
Add-Member -InputObject $_ -NotePropertyName 'ResponseTime' -NotePropertyValue '' -Force
}
Foreach($FlexVPN in $FlexVPNlist) {
$Ping = try{ Test-Connection -ComputerName $FlexVPN.IP -Count $FlexVPN.'Priority' -ErrorAction Stop | Select ResponseTime } catch [System.Net.NetworkInformation.PingException] { $_ }
if($Ping.ResponseTime -ge '0'){
$FlexVPN.RegisteredUp = Get-Date
$FlexVPN.ResponseTime = $Ping.ResponseTime
}
if($Ping.ResponseTime -eq $null){ $FlexVPN.RegisteredDown = Get-Date }
New-Variable -Name $FlexVPN.IP -Value (New-Object PSObject -Property #{
IP = $FlexVPN.IP
Information = $FlexVPN.Information
Priority = $FlexVPN.Priority
RegisteredUp = $FlexVPN.RegisteredUp
RegisteredDown = $FlexVPN.RegisteredDown
ResponseTime = $Ping.ResponseTime
})
[PSCustomObject]#{
"IP address" = $FlexVPN.IP
"Information" = $FlexVPN.Information
"Priority" = $FlexVPN.Priority
"Response time" = $FlexVPN.ResponseTime
"RegisteredUp" = $FlexVPN.RegisteredUp
"RegisteredDown" = $FlexVPN.RegisteredDown
}
}
I can now do stuff If computer responded or not!

Output if/else statement results to formatted table

I have written an environment IP check script in Powershell which works but I can't figure out how to display the output to screen in a formatted table which auto sizes the columns.
$infile = Import-Csv "~\Env_IPlist.csv" -Delimiter ","
$arr1 = #()
$IP_Addresses = $infile |
Select-Object "Device_Type", "Device_Name", "IP_Address",
"IP_Role", "Location"
Write-Host "Started Ping Test ..."
foreach ($IP in $IP_Addresses) {
if (Test-Connection $IP.("IP_Address") -Quiet -Count 1 -ErrorAction SilentlyContinue) {
Write-Host $IP.("Device_Name") ":" $IP.("IP_Address") "Ping successful" -ForegroundColor Green
} else {
Write-Host $IP."Device_Name" ":" $IP.("IP_Address") "Ping failed" -ForegroundColor Red -BackgroundColor white
}
}
Write-Host "Ping Test Completed!"
Add the Test-Connection result via a calculated property, then pipe the output to Format-Table.
$infile |
Select-Object Device_Type, Device_Name, IP_Address, IP_Role, Location,
#{n='Online';e={
[bool](Test-Connection $_.IP_Address -Quiet -Count 1 -EA SilentlyContinue)
}} |
Format-Table -AutoSize
I rewrote the script using PSObject as initially suggested but now I do not know how to add the ForegroundColor in the if..else statement.
$infile = Import-Csv "~\Env_IPlist.csv" -Delimiter ","
$arr1 = #()
$IP_Addresses = $infile |
Select-Object Device_Type, Device_Name, IP_Address, IP_Role,
Location, Status
foreach ($IP in $IP_Addresses) {
if (Test-Connection $IP.IP_Address -Quiet -Count 1 -ErrorAction SilentlyContinue) {
$PSObject = New-Object PSObject -Property #{
Device_Type = $IP.Device_Type
Device_Name = $IP.Device_Name
IP_Address = $IP.IP_Address
IP_Role = $IP.IP_Role
Location = $IP.Location
Status = "Successful"
}
} else {
$PSObject = New-Object PSObject -Property #{
Device_Type = $IP.Device_Type
Device_Name = $IP.Device_Name
IP_Address = $IP.IP_Address
IP_Role = $IP.IP_Role
Location = $IP.Location
Status = "Failed"
}
}
$arr1 += $PSObject
}
$arr1 | Format-Table -AutoSize

Add content to csv with Add-Member

I've got a csv export from Active Directory which looks like this:
Name,"GivenName","Surname","Department","LogonWorkstations"
jdoe,"John","Doe","Finance","pc1"
fbueller,"Ferris","Bueller","Sales","pc2"
Now I want to search on each Workstation, check if a folder exists and write that information back into the csv.
$input = Import-Csv "C:\Scripts\input.csv"
ForEach ($line in $input) {
$wst = $line.LogonWorkstations
If ($wst -ne "") {
If (Test-Connection $wst -Count 1 -Quiet -ErrorAction SilentlyContinue) {
If (Test-Path "\\$wst\c$\Program Files\xyz" -ErrorAction SilentlyContinue) {
Add-Member -InputObject $line -NotePropertyName "xyz" -NotePropertyValue "exists"
}
}
}
}
$input | Export-Csv "C:\Scripts\output.csv" -NoTypeInformation -Encoding Unicode
As you can see in the code, Add-Member adds the additional information to $input, however the information isn't available after exporting it to csv.
It works. The problem is with If conditions.
$input = Import-Csv "C:\Scripts\input.csv"
ForEach ($line in $input) {
Add-Member -InputObject $line -NotePropertyName "xyz" -NotePropertyValue "exists"
}
$input # here I get the information
$input | Export-Csv "C:\Scripts\output.csv" -NoTypeInformation -Encoding Unicode
I recommend to move Add-Member invocation as first command in the loop with default value (probably empty) then set the value in the condition.
ForEach ($line in $input)
{
Add-Member -InputObject $line -NotePropertyName "xyz" -NotePropertyValue $null
$wst = $line.LogonWorkstations
If ($wst -ne "")
{
If (Test-Connection $wst -Count 1 -Quiet -ErrorAction SilentlyContinue)
{
If (Test-Path "\\$wst\c$\Program Files\xyz" -ErrorAction SilentlyContinue)
{
$line.xyz = 'exists'
}
}
}
}
you add the new member to the variable $line and expect it is written back to $input .. which is not.
try this:
$input = Import-Csv "C:\Scripts\input.csv"
$counter=0
ForEach ($line in $input) {
$wst = $line.LogonWorkstations
If ($wst -ne "") {
If (-not ( Test-Connection $wst -Count 1 -Quiet -ErrorAction SilentlyContinue)) {
If (-not (Test-Path "\\$wst\c$\Program Files\xyz" -ErrorAction SilentlyContinue)) {
Add-Member -InputObject $input[$counter] -NotePropertyName "xyz" -NotePropertyValue "exists"
}
}
}
$counter++
}
$input # here I get the information
$input | Export-Csv "C:\Scripts\output.csv" -NoTypeInformation -Encoding Unicode
I changed the InputObject-Parameter to write the new member to the input variable.
I would recommend using a calculated property for this kind of modification:
Import-Csv "C:\Scripts\input.csv" |
Select-Object *, #{n='xyz';e={
$wst = $_.LogonWorkstations
if ($wst) {
if (Test-Connection $wst -Count 1 -Quiet -EA SilentlyContinue) {
$path = "\\$wst\c$\Program Files\xyz"
[bool](Test-Path $path -EA SilentlyContinue)
}
}
}} |
Export-Csv 'C:\Scripts\output.csv' -NoType -Encoding Unicode

Powershell Forloop with custom header

Desired output:
Server Data1 Data2
------ ----- -----
Server1 Stuff1 Thing1
Server2 Stuff2 Thing2
Server3 Stuff3 Thing3
Question:
I have 3-4 different variables that I want in a custom table view with a custom header. The problem is that I use a ForEach and I'm not sure how to get it into a table view. Right now the best I can do is Write-Host "$server $stuff $thing" and that puts each one in a row. I tried to some magic with #{Expression={$_.Name};Label="Name" but did not get anywhere.
The main point is that I have 3 vars at the end of the day and I need to get it into a custom table view.
$data = #("Server1", "Server2", "Server3")
while($true) {
cls
"`r"
ForEach ($server in $data) {
if (Test-Connection $server -count 1 -quiet) {
net use r: \\$server\s$\Folder /user:server\administrator password >$null
r:
$inputcount = (dir input -Recurse | Measure-Object).Count
$forwardcount = (dir forward -Recurse | Measure-Object).Count
$forwardcount = ($forwardcount-2)
if($fowardcount -lt 0) {
$forwardcount = 0
}
if($inputcount -gt 0 -or $forwardcount -gt 0) {
if($inputcount -gt 5000 -or $forwardcount -gt 200) {
$sleepless = "1"
}
Write-Host "$server" -ForegroundColor Red -NoNewline
Write-Host ": " -NoNewline
Write-Host "$inputcount" -ForegroundColor Red -NoNewline
Write-Host " - " -NoNewline
Write-Host "$forwardcount" -ForegroundColor Red
$inputcount = ""
c: >$null
net use r: /Delete >$null
} else {
Write-Host "$server" -NoNewline
Write-Host ": " -NoNewline
Write-Host "$inputcount" -NoNewline
Write-Host " - " -NoNewline
Write-Host "$forwardcount"
$inputcount = ""
c: >$null
net use r: /Delete >$null
}
}
}
}
Use a collection of custom objects:
"Server1", "Server2", "Server3" | ForEach-Object {
# NB: Test-Connection "host" -Count 1 sometimes fails on an online host
if(Test-Connection $_ -Quiet -Count 2 -ErrorAction SilentlyContinue) {
$status = "online"
} else {
$status = "offline"
}
# PowerShell v3+
[PSCustomObject]#{
Server = $_
Status = $status
Count = 20
What = "ever"
}
# PowerShell v2
$item = New-Object -TypeName PSObject
$item | Add-Member -MemberType NoteProperty -Name Server -Value $_
$item | Add-Member -MemberType NoteProperty -Name Status -Value $status
$item | Add-Member -MemberType NoteProperty -Name Count -Value 20
$item | Add-Member -MemberType NoteProperty -Name What -Value "ever"
$item
}
Returns:
Server Status Count What
------ ------ ----- ----
Server1 offline 20 ever
Server1 offline 20 ever
Server2 offline 20 ever
Server2 offline 20 ever
Server3 offline 20 ever
Server3 offline 20 ever
This is the general format I would use. The foreach is completely incorrect as I don't know how you're going from one row of data to the next; whatever it is, loop over that.
Bare in mind this is destructive; += deletes the previous array and creates a new one. However it tends to be my goto when dealing with small data sets because of simplicity and readability.
foreach ($line in $lines) {
[array]$tableVariable += New-Object PSObject -Property #{
Server = $server
Data1 = $stuff
Data3 = $thing
}
}

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