Use ping output to create a CSV - function

I have written following code to use ping command to ping multiple computers, I would like to capture following values it:
Reply from / Request timed out etc.
Actual IP Address of the remote host
This function is working fine however, if I am trying to get its returned values to a CSV I am unable to do so.
# Declaration of the function name and expected parameters
Function Ping-Check{
[cmdletbinding()]
PARAM (
[Parameter(Mandatory=$True,
ValueFromPipeline=$True,
ValueFromPipelineByPropertyName=$True,
HelpMessage='Enter the name of the remote host.')]
[String]$ObjCompName
)
Begin{
# Setup the Process startup info
$pinfo = New-Object System.Diagnostics.ProcessStartInfo
$pinfo.FileName = "ping.exe"
$pinfo.Arguments = " -a " + $ObjCompName + " -n 2"
$pinfo.UseShellExecute = $false
$pinfo.CreateNoWindow = $true
$pinfo.RedirectStandardOutput = $true
$pinfo.RedirectStandardError = $true
}
Process{
$p = New-Object System.Diagnostics.Process
$p.StartInfo = $pinfo
$p.Start() | Out-Null
$p.WaitForExit()
# Redirect the Output
$stdout = $p.StandardOutput.ReadToEnd()
$stderr = $p.StandardError.ReadToEnd()
}
End{
Write-Output "stdout: $stdout"
Write-Output "stderr: $stderr"
Write-Output "exit code: " + $p.ExitCode
}
}

There is a Test-Connection cmdlet available in powershell which returns an object array with properties you can use. If you wan't to stick with your attempt, be aware that you have to parse the output yourself.

Related

Script to Enforce MFA failing to grab dataset from servers

function Enforce-MFA($exclude){
Connect-MsolService
$excludedUsers = 'admin','admin2','admin3','admin4' + $exclude
$excluded = ($excludedUsers | ForEach-Object { [regex]::Escape($_) }) -join '|'
$st = New-Object -TypeName Microsoft.Online.Administration.StrongAuthenticationRequirement
$st.RelyingParty = "*"
$st.State = "Enforced"
$sta = #($st)
$array = (Get-MsolUser | Where-Object { $_.DisplayName -notmatch $excluded }).UserPrincipalName
ForEach ($user in $array)
{
Set-MsolUser -UserPrincipalName $user -StrongAuthenticationRequirements $sta
Write-Host "Complete"
}
}
The general function is to grab a list of objects, exclude certain objects, and Enforce MFA for the remaining objects. This script seemed to work without any issue last week, but this week, I'm getting no data from the Array variable. I was working on a lot of different changes and I'm thinking I may have messed something up in the process, but I'm just not seeing it. What did I mess up or what am I not seeing?
You forgot to add -Credential $cred to the Connect-MsolService.
You should create that connection first and take it out of the function.
function Enforce-MFA {
$excludeTheseUsers = 'admin', 'user1', 'user2' # etc.
# for using the regex `-notmatch` operator later, you need to combine the entries with the regex OR sign ('|'),
# but you need to make sure to escape special characters some names may contain
$excludes = ($excludeTheseUsers | ForEach-Object { [regex]::Escape($_) }) -join '|'
# create the StrongAuthenticationRequirement object just once, to use on all users
$st = New-Object -TypeName Microsoft.Online.Administration.StrongAuthenticationRequirement
$st.RelyingParty = "*"
$st.State = "Enabled"
$sta = #($st)
# get an array of UserPrincipalNames
$array = (Get-MsolUser | Where-Object { $_.DisplayName -notmatch $excludes }).UserPrincipalName
foreach ($user in $array) {
Set-MsolUser -UserPrincipalName $user -StrongAuthenticationRequirements $sta
}
Write-Host "Enforcing MFA Complete"
}
# ask for credentials to make the connection
$cred = Get-Credential -Message 'Please enter your credentials to connect to Azure Active Directory'
Connect-MsolService -Credential $cred
As for your loop, try something like this:
# enter an endless loop
while($true) {
$var = Read-Host -Prompt "Enter the corresponding number: 1: Enforce 2: Enable 3: Disable 4: Exit"
switch($var){
1 { Enforce-MFA }
2 { Enable-MFA }
3 { Disable-MFA }
4 { exit }
default{ "Please choose either 1, 2 ,3 or 4" }
}
}

How can you pass the HashTable as a parameter to the function and export the data into the csv?

I have build the PowerShell module function which captures the data such as:
Start Date
Start Time
Server Name
User (who executes the script
Technology
Script Name
Script Path
Execution Time (# of seconds took the script from start to end)
Error Message (if there is any error message in the script)
The above points provides data for each of the script, I have enabled the module and calling out the function in each of my script. However, there are some scripts which provides build data and some scripts which don't. For example, there is one script which enables MS Project and MS Visio license to the end users and it gives me the data on # of Project license assigned and # of Visio license assigned.
I am trying to find the way on how to capture the build data from some of my scripts. I want to capture the data with headers and merge them with my HashTable which is in my module script. Altogether, I want to export the data to the csv file.
I am trying to understand what I am missing? I used param method but couldn't output any data.
Here is my PowerShell module code
function Get-Info(){
$date = (Get-Date -f "MM_dd_yyyy_hh_mm")
#TimeStamp
$reportDate = (Get-Date -f "MM/dd/yyyy")
$reportTime = (Get-Date -f "hh:mm:ss tt")
#Server
$serverName = $env:COMPUTERNAME
#user
$user = $env:UserName
#script name
$scriptName = split-path $MyInvocation.PSCommandPath -Leaf
#script path
$scriptPath = split-path $MyInvocation.PSCommandPath
#service account
$serviceAccount = $tenantAdmin
#measure execution time (start to finish)
[timespan]$executionTime = Measure-Command {0..10000 | ForEach-Object {$i++} }
$runTime = $executionTime.Milliseconds
#Technology Type
$technology = Split-Path (Split-Path $scriptPath -Parent) -Leaf
#error handling
If($errorMessage -eq $null){
$errorMessage = "None"
}
if ($errorMessage -ne $null){
$errorMessage = $ErrorMessage
}
$fileName = $scriptName.Trim(".ps1")
$Hashtable = #()
$Hashtable += New-Object psobject -Property #{
"Script Name" = $scriptName;
"Execution Date" = $reportDate;
"Execution Time" = $reportTime;
"Service Account" = $serviceAccount;
"User" = $user;
"Server Name" = $serverName;
"Script Path" = $scriptPath;
"RunTimeMS" = $runTime;
"Error Message" = $errorMessage;
"Technology" = $technology;
}
if($myHashTable -eq $null){
$Hashtable | Export-Csv "D:\MyFileName\$fileName$date.csv" -NoTypeInformation
}
if($myHashTable -ne $null){
$finalTable = $Hashtable + $myHashTable
$finalTable | Export-Csv "D:\MyFileName\$fileName$date.csv" -NoTypeInformation
}

Powershell scripts work when run directly but not when called by another

I have a long list of simple jobs I would like to somewhat automate. It's simple stuff, grab or post info via API and build some reports, nothing fancy.
I decided to build a master script which directs out to a variety of other scripts, each handling its own job. Each one of those little scripts, reference functions from a Utility script which I built that has functions which are common to all the other simple job scripts.
Each of the scripts work perfectly when I run them directly, however, when I try to run them via the master script, which routes to them, they all fail.
One example is that in many cases I need to fetch data from an API but get capped at 1000 object returns when I need 10k+. To solve this, I built a function which recursively calls itself until there is no more data left to collect. Again, this works when called by itself but not from the master script, for some reason, it bails out after the first run (should run 10+ times in this case). Then, it returns nothing.
I am thinking maybe this has something to do with how I am scoping the functions/variables?? Not sure. I have tried scoping to Global, Local & Script but none seem to work. Here's some of the code...
*Master Director Script runs script based on user input*
...
&$choice_hash[$action].script_path
$ScriptDirectory = Split-Path -Path $MyInvocation.MyCommand.Definition -Parent
. "$ScriptDirectory\Utilities.psm1"
$user_data = $null
$env_choice = $null
$csv_output_path = $null
$collated_user_data = [System.Collections.ArrayList]#()
function selectEnv {
$global:env_choice = Read-Host #"
> Select an Environment: [Prod] or [Dev]
Your Choice
"#
if ($env_choice -ne 'Prod' -and $env_choice -ne 'Dev') {
consoleCmt $env_choice
consoleCmt 'Invalid Choice. Try again...'
selectEnv
} else {
if ($env_choice -eq 'Prod') {
$global:csv_output_path = '\\etoprod\******\Exports\Report_Users_Prod.csv'
} else {
$global:csv_output_path = '\\etoprod\******\Exports\Report_Users_Dev.csv'
}
$global:user_data = process_data $env_choice 'api/xm/1/people?embed=roles&limit=1000'
}
}
function processUsersData {
foreach($user in $user_data) {
$user_roles = ''
$role_divider = ','
for($i = 0; $i -lt $user.roles.data.length; $i++) {
# Only append a comma if there are more, otherwise leave blank for CSV deliniation
if ($i -eq $user.roles.data.length - 1) {
$role_divider = ''
}
$user_roles += $user.roles.data[$i].name + $role_divider
}
# Build ordered hash table with above data
$sanatized_user = [pscustomobject][ordered]#{id = $user.targetName; firstName = $user.firstName; lastName = $user.lastName; siteName = $user.site.name; roles = $user_roles }
# Shovel into storage array used for building the CSV
$global:collated_user_data += $sanatized_user
}
}
notice 'Initiating Groups Report Script'
selectEnv
processUsersData
exportCsv $collated_user_data $csv_output_path
Utility Script (relevant functions being called)
$res = $null
$content = #()
...
function process_data($env, $url) {
fetch_data $env $url
foreach($i in $res.data) {
$global:content += $i
}
if($res.links.next) {
fetch_more $env $res.links.next
}
return $content **Should return full collection of data, but fails after one pass**
}
function fetch_data($env, $url) {
$base = generateEnvBase $env
$path = "$base/$url"
$req = Invoke-WebRequest -Credential $cred -Uri $path -Method GET
$global:res = ConvertFrom-Json $req
}
function fetch_more($env, $url) {
$base = generateEnvBase $env
$path = "$base$url"
$req = Invoke-WebRequest -Credential $cred -Uri $path -Method GET
$res = ConvertFrom-Json $req
foreach($i in $res.data) {
$global:content += $i
}
if($res.links.next) {
fetch_more $env $res.links.next
}
}
Sorry in advance if I have not followed procedure or etiquette, I'm new here.
This should work if you declare all variables in Main.ps1 that are needed by functions. You could also use the "Script" scope when creating a new variable inside a function that you want to use outside the function. Example $Script:Var = "Stuff" created inside a function will be available to whole script.
Directory Structure
C:\Script\Root
| Main.ps1
\---Utilities
fetch_data.ps1
fetch_more.ps1
processUsersData.ps1
process_data.ps1
selectEnv.ps1
Main.ps1
#---[ Initization ]---#
# Strings
[String]$RootPath = $PSScriptRoot
[String]$UtilPath = "$($RootPath)\Utilities"
[String]$env_choice = $null
[String]$csv_output_path = $null
# Arrays
[Array]$user_data = #()
[Array]$content = #()
[Array]$collated_user_data = #()
[Array]$res = #()
#---[ Source in Utilities ]---#
# Get the scripts
$Utilities = Get-ChildItem -Path "$UtilPath" -File | Where-Object {$_.Extension -eq ".ps1"}
# Source in each one
foreach ($Item in $Utilities) {
.$Item.FullName
}
#---[ Select an Environment ]---#
# Get the User's choice
$env_choice = selectEnv
# Process the choice
switch ($env_choice) {
Prod {
$csv_output_path = '\\etoprod\******\Exports\Report_Users_Prod.csv'
$user_data = process_data 'Prod' 'api/xm/1/people?embed=roles&limit=1000'
}
Dev {
$csv_output_path = '\\etoprod\******\Exports\Report_Users_Dev.csv'
$user_data = process_data 'Dev' 'api/xm/1/people?embed=roles&limit=1000'
}
Test {
Write-Output "Test is not an option. Choose wisely."
exit 1
}
Default {
Write-Output "Unknown Environment Choice."
exit 1
}
}
#---[ Process Users and Export ]---#
processUsersData
exportCsv $collated_user_data $csv_output_path
selectEnv.ps1
function selectEnv {
$Title = "Environment:"
$Info = "Please choose an environment"
# Options
$Prod = New-Object System.Management.Automation.Host.ChoiceDescription '&Prod', 'Production environment'
$Dev = New-Object System.Management.Automation.Host.ChoiceDescription '&Dev', 'Development environment'
$Test = New-Object System.Management.Automation.Host.ChoiceDescription '&Test', 'Testing environment'
$Options = [System.Management.Automation.Host.ChoiceDescription[]]($Prod, $Dev, $Test)
$Default = 0
# Promp the User
$Choice = $host.UI.PromptForChoice($Title , $Info , $Options, $Default)
$Result = $Options[$Choice].Label -Replace '&',''
return $Result
}

When using Powershell's Dynamic parameters can I suppress Errors?

When using Powershell's Dynamic parameters can I suppress Errors?
Specifically the error being:
f foo
Search-FrequentDirectory : Cannot validate argument on parameter 'dirSearch'. The argument "foo" does not belong to the set
"bin,omega,ehiller,psmodules,deploy,gh.riotgames.com,build-go,vim74,cmder,dzr,vimfiles,src,openssh,git" specified by the ValidateSet attribute. Supply an argument
that is in the set and then try the command again.
At line:1 char:3
+ f foo
+ ~~~
+ CategoryInfo : InvalidData: (:) [Search-FrequentDirectory], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,Search-FrequentDirectory
Dynamic parameters being:
DynamicParam {
$dirSearch = new-object -Type System.Collections.ObjectModel.Collection[System.Attribute]
# [parameter(mandatory=...,
# ...
# )]
$dirSearchParamAttribute = new-object System.Management.Automation.ParameterAttribute
$dirSearchParamAttribute.Mandatory = $true
$dirSearchParamAttribute.Position = 1
$dirSearchParamAttribute.HelpMessage = "Enter one or more module names, separated by commas"
$dirSearch.Add($dirSearchParamAttribute)
# [ValidateSet[(...)]
$dirPossibles = #()
$historyFile = (Get-PSReadlineOption).HistorySavePath
# directory Seperating character for the os; \ (escaped to \\) for windows (as C:\Users\); / for linux (as in /var/www/);
# a catch all would be \\\/ ; but this invalidates the whitespace escape character that may be used mid-drectory.
$dirSep = "\\"
# Group[1] = Directory , Group[length-1] = lowest folder
$regex = "^[[:blank:]]*cd ([a-zA-Z\~:]+([$dirSep][^$dirSep]+)*[$dirSep]([^$dirSep]+)[$dirSep]?)$"
# original: ^[[:blank:]]*cd [a-zA-Z\~:\\\/]+([^\\\/]+[\\\/]?)*[\\\/]([^\\\/]+)[\/\\]?$
# test for historyFile existance
if( -not (Test-Path $historyFile )){
Write-Warning "File $historyFile not found, unable to load command history. Exiting.";
return 1;
}
$historyLines = Get-Content $historyFile
# create a hash table, format of ;;; [directory path] = [lowest directory]
$searchHistory = #{}
# create a hash table for the count (number of times the command has been run)
$searchCount = #{}
ForEach ( $line in $historyLines ) {
if( $line -match $regex ){
try {
# since the matches index can change, and a hashtable.count is not a valid way to find the index...
# I need this to figure out the highest integer index
$lowestDirectory = $matches[($matches.keys | sort -Descending | Select-Object -First 1)]
$fullPath = $matches[1]
if($searchHistory.keys -notcontains $matches[1]){
$searchHistory.Add($matches[1],$lowestDirectory)
}
$searchCount[$fullPath] = 1
} catch {
$searchCount[$fullPath]++
}
}
}
# this helps with hashtables
# https://www.simple-talk.com/sysadmin/powershell/powershell-one-liners-collections-hashtables-arrays-and-strings/
$dirPossibles = ( $searchHistory.values | Select -Unique )
$modulesValidated_SetAttribute = New-Object -type System.Management.Automation.ValidateSetAttribute($dirPossibles)
$dirSearch.Add($modulesValidated_SetAttribute)
# Remaining boilerplate
$dirSearchDefinition = new-object -Type System.Management.Automation.RuntimeDefinedParameter("dirSearch", [String[]], $dirSearch)
$paramDictionary = new-object -Type System.Management.Automation.RuntimeDefinedParameterDictionary
$paramDictionary.Add("dirSearch", $dirSearchDefinition)
return $paramDictionary
}
The function works, when I'm in the set everything is great. When I miskey or whatever, I get a rather unpleasant looking (non-user friendly error) - which I would like to style.
Is there a way to do this? To suppress the error? I tried try / catch and it was a no go, and I haven't been able to find much else on this - that is, error suppression in dynamic parameters.
I found a way to do it, but not sure I really recommend its use, and it has some downsides of duplicated code. Maybe there is a way to solve this better, but I did this more as an exercise of if it could be done.
Code Get-DynamicParamTestCustom.ps1
<#
Reference: http://blog.enowsoftware.com/solutions-engine/bid/185867/Powershell-Upping-your-Parameter-Validation-Game-with-Dynamic-Parameters-Part-II
#>
[CmdletBinding()]
param (
)
DynamicParam {
function New-ValidationDynamicParam {
[CmdletBinding()]
[OutputType('System.Management.Automation.RuntimeDefinedParameter')]
param (
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[string]$Name,
[ValidateNotNullOrEmpty()]
[Parameter(Mandatory)]
[array]$ValidateSetOptions,
[Parameter()]
[switch]$Mandatory = $false,
[Parameter()]
[string]$ParameterSetName = '__AllParameterSets',
[Parameter()]
[switch]$ValueFromPipeline = $false,
[Parameter()]
[switch]$ValueFromPipelineByPropertyName = $false
)
$AttribColl = New-Object System.Collections.ObjectModel.Collection[System.Attribute]
$ParamAttrib = New-Object System.Management.Automation.ParameterAttribute
$ParamAttrib.Mandatory = $Mandatory.IsPresent
$ParamAttrib.ParameterSetName = $ParameterSetName
$ParamAttrib.ValueFromPipeline = $ValueFromPipeline.IsPresent
$ParamAttrib.ValueFromPipelineByPropertyName = $ValueFromPipelineByPropertyName.IsPresent
$AttribColl.Add($ParamAttrib)
$AttribColl.Add((New-Object System.Management.Automation.ValidateSetAttribute($Param.ValidateSetOptions)))
$RuntimeParam = New-Object System.Management.Automation.RuntimeDefinedParameter($Param.Name, [string], $AttribColl)
$RuntimeParam
}
function Get-ValidValues
{
# get list of valid values
$validValues = #()
$validValues += 'a'
$validValues += 'b'
$validValues += 'c'
$validValues += $global:dynamic1Value
$validValues
}
# coerce the current passed value into our list, and we detect later
# to customize message
# the heart of this problem is getting the param from the Call Stack
# and stashing it away (a hack, but it IS a solution).
$line = (Get-PSCallStack | Select -First 1 | Select *).InvocationInfo.Line
# parse this for the command line arg
# TODO: make this more robust
$null = $line -match "-Dynamic1 (.*?)(\s+|$)"
$global:dynamic1Value = $Matches[1]
$ParamOptions = #(
#{
'Name' = 'Dynamic1';
'Mandatory' = $true;
'ValidateSetOptions' = Get-ValidValues
}
)
$RuntimeParamDic = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
foreach ($Param in $ParamOptions)
{
$RuntimeParam = New-ValidationDynamicParam #Param
$RuntimeParamDic.Add($Param.Name, $RuntimeParam)
}
return $RuntimeParamDic
}
begin
{
$PsBoundParameters.GetEnumerator() | foreach { New-Variable -Name $_.Key -Value $_.Value -ea 'SilentlyContinue'}
}
process
{
# not sure how else to write this because the function needs to be inside
# DynamicParam{} block for its usage, and here for 'process' usage.
function Get-ValidValuesReal
{
# get list of valid values
$validValues = #()
$validValues += 'a'
$validValues += 'b'
$validValues += 'c'
$validValues
}
function foo
{
}
Write-Output "global:dynamic1Value is: '$($global:dynamic1Value)'."
Write-Output "Dynamic1 is: '$($Dynamic1)'."
$realValues = Get-ValidValuesReal
if ($global:dynamic1Value -notin $realValues)
{
Write-Error "Hey, '$global:dynamic1Value' is not allowed."
}
else
{
Write-Output "Dynamic1 is: '$($Dynamic1)' and is cool."
}
}
end {}
Test Cases
.\Get-DynamicParamTestCustom.ps1 -Dynamic1 t
.\Get-DynamicParamTestCustom.ps1 -Dynamic1 test
.\Get-DynamicParamTestCustom.ps1 -Dynamic1 test -Verbpse
.\Get-DynamicParamTestCustom.ps1 -Dynamic1 a

Powershell 2.0 - loop through records in CSV for FTP Login validate and update csv with confirmation

Current issue, probably stupid simple but have been grinding my wheels for awhile. I have 600+ FTP accounts to validate if they are able to be logged on. Verified field to be updated in CSV.
CSV Sample:
Connection,Name,Path,Password,Phonetic,Client Name,Client ID,Verified
FTP,BFGftp,d:\data\ftpaccounts\BFGftp,8Wu8Agec8$,(Eight - WHISKEY - uniform - Eight - ALPHA - golf - echo - charlie - Eight - Dollar),(Nine - papa - ECHO - foxtrot - ROMEO - Two - kilo - echo - NOVEMBER - Two),,
FTP,bookitftp,d:\data\ftpaccounts\flipitftp,i3439flip12##,,Flipitftp,30342,
Missing statement block after 'else' keyword.
At C:\Users\mgoeres\Desktop\B-SWIFT FTP TEST2.ps1:118 char:10
+ else <<<< ($i++){ $GetFTP }
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : MissingStatementBlockAfterElse
FTP ACCOUNT VALIDATOR
Function Get-FtpDirectory($Directory) {
#Example
#$Server = "ftp://ftp.example.com/"
#$User = "anonymous#example.com"
#$Pass = "anonymous#anonymous.com"
$Server = "ftp://ftp.localhost.com/"
$User = $FTPLogon
$Pass = $FTPPass
# Credentials
$FTPRequest = [System.Net.FtpWebRequest]::Create("$($Server)$($Directory)")
$FTPRequest.Credentials = New-Object System.Net.NetworkCredential($User,$Pass)
$FTPRequest.Method = [System.Net.WebRequestMethods+FTP]::ListDirectoryDetails
# Don't want Binary, Keep Alive unecessary.
$FTPRequest.UseBinary = $False
$FTPRequest.KeepAlive = $False
$FTPResponse = $FTPRequest.GetResponse()
$ResponseStream = $FTPResponse.GetResponseStream()
# Create a nice Array of the detailed directory listing
$StreamReader = New-Object System.IO.Streamreader $ResponseStream
$DirListing = (($StreamReader.ReadToEnd()) -split [Environment]::NewLine)
$StreamReader.Close()
# Remove first two elements ( . and .. ) and last element (\n)
$DirListing = $DirListing[2..($DirListing.Length-2)]
# Close the FTP connection so only one is open at a time
$FTPResponse.Close()
# This array will hold the final result
$FileTree = #()
# Loop through the listings
foreach ($CurLine in $DirListing) {
# Split line into space separated array
$LineTok = ($CurLine -split '\ +')
# Get the filename (can even contain spaces)
$CurFile = $LineTok[8..($LineTok.Length-1)]
# Figure out if it's a directory. Super hax.
$DirBool = $LineTok[0].StartsWith("d")
# Determine what to do next (file or dir?)
If ($DirBool) {
# Recursively traverse sub-directories
$FileTree += ,(Get-FtpDirectory "$($Directory)$($CurFile)/")
}
Else {
# Add the output to the file tree
$FileTree += ,"$($Directory)$($CurFile)"
}
}
if (!$FileTree -eq $null) {
$Verified = "Y"
Return $FileTree
}
else {
$Verified = "Failed"}
}
# Update data record field "Verified" in CSV '$data' file with status value[Y,Failed,Other]
There is where the import of the FTP login ID and Password should start
#Column Names [Connection,Name,Path,Password,Phonetic,Client Name,Client ID,Verified]
#Variables
$AllName = #()
$AllPassword = #()
$AllVerified = #()
$data = #()
$FTPLogon = #()
$FTPPass = #()
$response = #()
$GetFTP = Get-FtpDirectory
# Import CSV File "FTP_Account_List_with_Password_and_Path.csv"
$data = Import-Csv C:\Users\mgoeres\Desktop\FTP_Account_List_with_Password_and_Path.csv | where-object {$_.Connection -eq "FTP"}
# This import allows key columns to be referenced as variables.
#Import-Csv C:\Users\mgoeres\Desktop\FTP_Account_List_with_Password_and_Path.csv | ForEach-Object {
#$AllName += $_.Name
#$AllPassword += $_.Password
#$AllVerified += $_.Verified}
# Simple test to see if CSV was imported into '$data' and column headers are working as variables
$data|select-object Name,Connection,Verified
Write-Host "CSV File Opened and Loaded"
## Select (next)record from '$data' and store correlating values in '$UserName' and '$Password'
# .EXAMPLE '$data[0].Password' <= First records Password value.
# .EXAMPLE '$data[1].Name' <= Second records Name value.
for ($i=0; $i -lt $data.count; $i++){
$FTPLogon = $data[$i].Name
$FTPPass = $data[$i].Password
$Verified = $data[$i].Verified }
if ($Verifed -eq $null){ $GetFTP }
else ($i++){ $GetFTP }