Export Loops to CSV - PowerShell - powershell

I have a script that takes properties of schedules from two directories and writes the output to the host. I want to capture this output into a csv. So far the script writes all attributes to the host correctly, but the csv only has the headers, i.e "Name" and "Path".
Here is what I have:
$results = #()
$JobObjects = $SchedulerObject.Search("/TradeSupport/Objects/Schedules/","*",65535,"*",$true);
foreach($JobObject in $JobObjects){
$Schedules = $JobObject.getabatobject();
foreach ($Schedule in $Schedules){
write-host("Name :" + $Schedule.Name)
write-host("Path :" + $Schedule.Path)
$details = #{
Name = $ScheduleObjects.Name
Path = $ScheduleObjects.FullPath
}}}
$JobObjects2 = $SchedulerObject.Search("/Operations/Objects/Schedules/","*",65535,"*",$true);
foreach($JobObject2 in $JobObjects2){
$Schedules2 = $JobObject2.getabatobject();
foreach ($Schedule2 in $Schedules2){
write-host("Name :" + $Schedule2.Name)
write-host("Path :" + $Schedule2.Path)
$details = #{
Name = $ScheduleObjects2.Name
Path = $ScheduleObjects2.FullPath
}}
}
$results += New-Object PSObject -Property $details
$results | select-object -property Name,Path | export-csv -Path \\ch0-craab-01\c$\Support\AB_Reports\Objects_Report.csv -NoTypeInformation
What am I doing wrong?

Put the $Results inside the Foreach Loops not on the outside
The OP said this didn't work and i took a second look at the script.
The variable the OP is using to save to $results is unique and holds no information.
The correct variables are
$Schedule.Name
$Schedule.Name
But you are using
$ScheduleObjects.Name
$ScheduleObjects.FullPath
The below script should now work
$results = #()
$JobObjects = $SchedulerObject.Search("/TradeSupport/Objects/Schedules/","*",65535,"*",$true);
foreach($JobObject in $JobObjects){
$Schedules = $JobObject.getabatobject();
foreach ($Schedule in $Schedules){
write-host("Name :" + $Schedule.Name)
write-host("Path :" + $Schedule.Path)
$details = #{
Name = $Schedule.Name
Path = $Schedule.Path
}
$results += New-Object PSObject -Property $details
}
}
$JobObjects2 = $SchedulerObject.Search("/Operations/Objects/Schedules/","*",65535,"*",$true);
foreach($JobObject2 in $JobObjects2){
$Schedules2 = $JobObject2.getabatobject();
foreach ($Schedule2 in $Schedules2){
write-host("Name :" + $Schedule2.Name)
write-host("Path :" + $Schedule2.Path)
$details = #{
Name = $Schedule2.Name
Path = $Schedule2.Path
}
$results += New-Object PSObject -Property $details
}
}
$results | select-object -property Name,Path | export-csv -Path \\ch0-craab-01\c$\Support\AB_Reports\Objects_Report.csv -NoTypeInformation

It's easier to see where you go wrong when you indent the code properly to line up with your loops:
$results = #()
$JobObjects = $SchedulerObject.Search("/TradeSupport/Objects/Schedules/","*",65535,"*",$true);
foreach($JobObject in $JobObjects) {
$Schedules = $JobObject.getabatobject();
foreach ($Schedule in $Schedules){
write-host("Name :" + $Schedule.Name)
write-host("Path :" + $Schedule.Path)
$details = #{
Name = $ScheduleObjects.Name
Path = $ScheduleObjects.FullPath
}
}
}
$JobObjects2 = $SchedulerObject.Search("/Operations/Objects/Schedules/","*",65535,"*",$true);
foreach($JobObject2 in $JobObjects2) {
$Schedules2 = $JobObject2.getabatobject();
foreach ($Schedule2 in $Schedules2) {
write-host("Name :" + $Schedule2.Name)
write-host("Path :" + $Schedule2.Path)
$details = #{
Name = $ScheduleObjects2.Name
Path = $ScheduleObjects2.FullPath
}
}
}
$results += New-Object PSObject -Property $details
$results | select-object -property Name,Path | export-csv -Path \\ch0-craab-01\c$\Support\AB_Reports\Objects_Report.csv -NoTypeInformation
Now you can more easily see that you only ever use your $details variable outside of the loops. You want to append that item on to your $results array on every iteration.

Related

Powershell script only works if breakpoint is present

I have a powershell script which reads file and folder info and adds data to an array.
The script runs fine if there is a breakpoint present. The breakpoint can be anywhere in the script and as soon as it is reached and I continue the execution the code finishes without error.
Even if I set the breakpoint to Disabled with Get-PSBreakpoint | Disable-PSBreakpoint the line before the breakpoint the code executes without error.
When the breakpoint is removed the code errors with "Method invocation failed because [System.ManagementAutomation.PSObject] doesn't contain method named op_Addition when adding to the array.
The error occurs here
$report += New-Object -TypeName PSObject -Property $props
and here
$filerec += New-Object -TypeName PSObject -Property $propsfile
This is the function where the error occurs
function ScanDrive([string]$scanpath)
{
#Scan the drive
$files = Get-ChildItem -Path $scanpath -Force -Recurse
$filecount = $files.Count
$Counter = 0
#Set up the result array
$folderRes = #()
$filesRes = #()
ForEach ($file in $files)
{
$lblInfo.Text = $file.FullName
$Form.Refresh()
$Counter++
[Int]$Percentage = ($Counter/$filecount)*100
$pbScan.Value = $Percentage
Write-Debug "Help"
if ($file.Attributes -eq 'Directory')
{
write-host 'This is a folder' + $file.FullName -ForegroundColor DarkGreen
try
{
$acl = Get-Acl -path $file.PSPath
Write-Host 'ACL' + $acl.Group.ToString()
$access = $acl.access
foreach($ar in $access)
{
$props = [ordered]#{
'ID' = ''
'FolderName' = $file.Name;
'ADGroupUser' = $ar.IdentityReference;
'Permissions' = $ar.FileSystemRights.ToString();
'ControlType' = $ar.AccessControlType;
'IsInherited' = $ar.IsInherited
}
$report += New-Object -TypeName PSObject -Property $props
$folderRes += $report
}
Write-Host "Folder record count : " + $folderRes.Count.ToString()
}
catch
{
Write-Host '******************************' -ForegroundColor Yellow
Write-Host 'Error ' + $_.Exception.Message -ForegroundColor Red
Write-Host '******************************' -ForegroundColor Yellow
}
}
else
{
write-host 'This is a file' + write-host $file.FullName -ForegroundColor DarkGreen
$iname = $file.Name
$iparent = $file.PSParentPath
$isize = $file.Length
$itype = $file.Extension
$iowner = get-acl $file.FullName
$owner = $iowner.Owner
$icreated = $file.CreationTime
$ilasmod = $file.LastWriteTime
$idirectory = $file.Directory
$ireadonly = $file.IsReadOnly
$ilastacc = $file.LastAccessTime
$ifilename = $file.FullName
$usergroup = $iowner.Group
$iatts = $file.Attributes
$propsfile = [ordered]#{
'ID' = ''
'Name' = $iname;
'Parent' = $iparent;
'Size' = $isize;
'Type' = $itype;
'Owner' = $owner;
'CreatedDate' = $icreated;
'LastModDate' = $ilasmod;
'Directory' = $idirectory;
'IsReadOnly' = $ireadonly;
'LastAccessedDate' = $ilastacc;
'FileName' = $ifilename;
'UserGroup' = $usergroup;
'Attributes' = $iatts;
'LoggedDate' = Get-Date
}
$filerec += New-Object -TypeName PSObject -Property $propsfile
$filesRes += $filerec
}
}
Write-Host "File record count : " + $filesRes.Count.ToString()
Return $filesRes,$folderRes
}
You don't need to add to $filerec and $report, you can just overwrite them (change += to =):
$filerec = New-Object -TypeName PSObject -Property $propsfile
$report = New-Object -TypeName PSObject -Property $props
Current code tries to create an array of objects and then add it to another array which would create duplicates in $folderRes and $filesRes.

Powershell Search AD via CSV and report on disabled / enable / non-existant users

The script below has a CSV input with a column samaccountname and a list of users. When ran it generates a CSV report with 3 columns:
AccountExists
AccountDisabled
samaccountname
If run in its present state it does indeed generate a report on whether the account is disabled and if it does exist, however if it encounters a user that does not exist in AD they are not added to the CSV report and the following error for each user is thrown:
Cannot index into a null array. At line:4 char:75
+ ... ($account=([adsisearcher]"(samaccountname=$($_.samaccountname))").fin
...
+ ~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : NullArray
Is it possible instead for the non-existent users to be added to the CSV report under the column account exists with a value of FALSE
Import-CSV C:\ScriptRepository\Users.csv | ForEach-Object {
New-Object -TypeName PSCustomObject -Property #{
samaccountname = $_.samaccountname
AccountExists = [bool]($account=([adsisearcher]"(samaccountname=$($_.samaccountname))").findone()).count
AccountDisabled = [bool]($account.properties.useraccountcontrol[0] -band 2)
}
} | Export-Csv C:\ScriptRepository\UsersState.csv -NoTypeInformation
Here's how I'd handle it:
$ADS_UF_ACCOUNTDISABLE = 2
$searcher = [ADSISearcher] ""
$searcher.PropertiesToLoad.AddRange(#("userAccountControl"))
Import-Csv "Users.csv" | ForEach-Object {
$searcher.Filter = "(sAMAccountName=$($_.sAMAccountName))"
$account = $searcher.FindOne()
if ( $account ) {
$exists = $true
$disabled = ($account.Properties["useraccountcontrol"][0] -band $ADS_UF_ACCOUNTDISABLE) -ne 0
}
else {
$exists = $false
$disabled = "N/A"
}
[PSCustomObject] #{
"sAMAccountName" = $_.sAMAccountName
"AccountExists" = $exists
"AccountDisabled" = $disabled
}
}
You could do this by moving the logic to before the hashtable:
Import-CSV C:\ScriptRepository\Users.csv | ForEach-Object {
$AccountExists = If ( (([adsisearcher]"(samaccountname=$($_.samaccountname))").FindOne()) ) { $true } else { $false }
If ($AccountExists) { $AccountDisabled = [bool]($AccountExists.properties.useraccountcontrol[0] -band 2) } Else { $AccountDisabled = '' }
New-Object -TypeName PSCustomObject -Property #{
samaccountname = $_.samaccountname
AccountExists = $AccountExists
AccountDisabled = $AccountDisabled
}
} | Export-Csv C:\ScriptRepository\UsersState.csv -NoTypeInformation

Return variable value from second powershell script to first PowerShell script?

I created 1.ps1 script which calls 2.ps1 script. After calling 2.ps1 it give some result in $variable. I want this $variable result to be used in my 1.ps1 for manipulation.
$csv = Get-Content \\10.46.198.141\try\windowserver.csv
foreach ($servername in $csv) {
$TARGET = $servername
$ProfileName = "CustomPowershell"
$SCRIPT = "powershell.exe -ExecutionPolicy Bypass -File '\\10.46.198.141\try\disk_space.ps1' '$servername'"
$HubRobotListPath = "C:\Users\Automation\Desktop\hubrobots.txt"
$UserName = "aaaaa"
$Password = "aaaaaaa"
$Domain = "SW02111_domain"
$HubOne = "sw02111"
#lots of code here
}
Now I have a second script which is:
Param([string]$servername)
$hash = New-Object PSObject -Property #{
Servername = "";
UsedSpace = "";
DeviceID = "";
Size = "";
FreeSpace = ""
}
$final =#()
$hashes =#()
$hash = New-Object PSObject -Property #{
Servername = $servername;
UsedSpace = "";
DeviceID = "";
Size = "";
FreeSpace = ""
}
$hashes += $hash
$space = Get-WmiObject Win32_LogicalDisk
foreach ($drive in $space) {
$a = $drive.DeviceID
$b = [System.Math]::Round($drive.Size/1GB)
$c = [System.Math]::Round($drive.FreeSpace/1GB)
$d = [System.Math]::Round(($drive.Size - $drive.FreeSpace)/1GB)
$hash = New-Object PSObject -Property #{
Servername = "";
UsedSpace = $d;
DeviceID = $a;
Size = $b;
FreeSpace = $c
}
$hashes += $hash
}
$final += $hashes
return $final
I want to use this $final output to create a CSV file with code in the first PowerShell script:
$final | Export-Csv C:\Users\Automation\Desktop\disk_space.csv -Force -NoType
Don't make things more complicated than they need to be. Use the pipeline and calculated properties.
Get-Content serverlist.txt |
ForEach-Object { Get-WmiObject Win32_LogicalDisk -Computer $_ } |
Select-Object PSComputerName, DeviceID,
#{n='Size';e={[Math]::Round($_.Size/1GB)}},
#{n='FreeSpace';e={[Math]::Round($_.FreeSpace/1GB)}},
#{n='UsedSpace';e={[Math]::Round(($_.Size - $_.FreeSpace)/1GB)}} |
Export-Csv disksize.csv -Force -NoType

How to Export-Csv with variables?

I'm trying to write 8 variables into an CSV file with PowerShell, but it just ends up as ,,,,,,, instead of var1,var2,var3,var4,var5,var6,var7,var8
My code is as follows:
$newRow = "{0},{1},{2},{3},{4},{5},{6},{7}" -f $var1,$var2,$var3,$var4,$var5,$var6,$var7,$var8
$newRow = $newRow -Replace "`t|`n|`r",""
$newRow = $newRow -Replace " ;|; ",";"
$newRow += "`n"
$newRow | Export-Csv -Path $file -Append -noType -Force
Without -Force I get the following error message:
Export-Csv : Cannot append CSV content to the following file: C:\result.txt. The
appended object does not have a property that corresponds to the following column:
var1. To continue with mismatched properties, add the -Force parameter, and then
retry the command.
At C:\Test.ps1:72 char:12
+ $newRow | Export-Csv -Path $file -Append -noType
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidData: (var1:String) [Export-Csv], InvalidOperationException
+ FullyQualifiedErrorId : CannotAppendCsvWithMismatchedPropertyNames,Microsoft.PowerShell.Commands.ExportCsvCommand
EDIT:
Script:
$startInfo = New-Object System.Diagnostics.ProcessStartInfo
$startInfo.FileName = "powershell.exe"
$startInfo.Arguments = 'C:\zabbix\script\zabbix_vbr_job.ps1 "Discovery"'
$startInfo.RedirectStandardOutput = $true
$startInfo.UseShellExecute = $false
$startInfo.CreateNoWindow = $false
#$startInfo.Username = "DOMAIN\Username"
#$startInfo.Password = $password
$process = New-Object System.Diagnostics.Process
$process.StartInfo = $startInfo
$process.Start() | Out-Null
$discoveryJson = $process.StandardOutput.ReadToEnd()
$process.WaitForExit()
cls
$discovery = $discoveryJson | ConvertFrom-Json
$file = "C:\zabbix\script\result.txt"
function RunScript ($param, $id)
{
$startInfo = New-Object System.Diagnostics.ProcessStartInfo
$startInfo.FileName = "powershell.exe"
$startInfo.Arguments = "C:\zabbix\script\zabbix_vbr_job.ps1 '$param' '$id'"
$startInfo.RedirectStandardOutput = $true
$startInfo.UseShellExecute = $false
$startInfo.CreateNoWindow = $false
$process = New-Object System.Diagnostics.Process
$process.StartInfo = $startInfo
$process.Start() | Out-Null
$output = $process.StandardOutput.ReadToEnd()
$process.WaitForExit()
return $output
}
$fileContent = Import-csv $file
$NewCSVObject = #()
foreach($obj in $discovery.data)
{
$index = [array]::indexof($discovery.data, $obj)
Write-Host $index "/" $discovery.data.count
#Write-Host (RunScript "Result" $obj.JOBID )
$Result = RunScript "Result" $obj.JOBID
#Write-Host $Result
$RunStatus = RunScript "RunStatus" $obj.JOBID
#Write-Host $RunStatus
$IncludedSize = RunScript "IncludedSize" $obj.JOBID
#Write-Host $IncludedSize
$ExcludedSize = RunScript "ExcludedSize" $obj.JOBID
#Write-Host $ExcludedSize
$VmCount = RunScript "VmCount" $obj.JOBID
#Write-Host $VmCount
$Type = RunScript "Type" $obj.JOBID
#Write-Host $Type
$RunningJob = "RunningJob"#RunScript "RunningJob" $obj.JOBID
#Write-Host $RunningJob
#$newRow = New-Object PsObject -Property #{ JobID = $obj.JOBID ; Result = $Result ; RunStatus = $RunStatus ; IncludedSize = $IncludedSize ; ExcludedSize = $ExcludedSize ; VmCount = $VmCount ; Type = $Type ; RunningJob = $RunningJob }
$newRow = "{0},{1},{2},{3},{4},{5},{6},{7}" -f $obj.JOBID,$Result,$RunStatus,$IncludedSize,$ExcludedSize,$VmCount,$Type,$RunningJob
$newRow = $newRow -Replace "`t|`n|`r",""
$newRow = $newRow -Replace " ;|; ",";"
$newRow += "`n"
#$newRow | Out-File $file
#[io.file]::WriteAllText("C:\zabbix\script\test.txt",$newRow)
Write-Host $newRow
$newRow | Export-Csv -Path $file -Append -noType
break
}
#cls
Write-Host $fileContent
CSV headers:
JobID,Result,RunStatus,IncludedSize,ExcludedSize,VmCount,Type,RunningJob
There is no point in using Export-Csv if you're building the CSV line by hand anyway.
Either change
$newRow | Export-Csv -Path $file -Append -noType -Force
into
$newRow | Add-Content $file
or build $newRow like this:
$newRow = New-Object -Type PSObject -Property #{
'JobID' = $var1
'Result' = $var2
'RunStatus' = $var3
'IncludedSize' = $var4
'ExcludedSize' = $var5
'VmCount' = $var6
'Type' = $var7
'RunningJob' = $var8
}
and the problem will disappear.
The reason for this behavior is that Export-Csv is for transforming objects into a tabular string representation of their properties. Essentially, an object
#{
propertyA: 'foo'
propertyB: 23
}
becomes
propertyA,propertyB
"foo","23"
If you're already building a string, the resulting (string) object has just a single property (Length), which doesn't match any of the properties from your existing CSV. Hence the error you're getting without -Force. Even if you use -Force, the properties written to the CSV are determined from the first item in the existing CSV. Properties that are not present in this set are omitted from the output, and properties from that set that are not present in the object are filled with null values.

Powershell v2 | Script Won't Declare Variable, need help debugging

Alright there seems to be several issues with the script and i can't seem to figure out any of them, also some feedback on the script would be greatly apperciated. This is still my first script so it probably needs lots of little tweaks so please tell me whatever suggestions comes to mind.
Issues: Mostly all issues revolve around the logging.
Log file is not being checked so the script keeps adding computers to the log file over and over.
The log file does not update the information that is generated such as os,mac,ip, etc.
Issues Being Displayed:
Property 'Result' cannot be found on this object. Make sure that it
exists. At W:\Powershell Scripting\Test Lab\TestFunction.ps1:86
char:17
+ IF ($Computer. <<<< Result -ne "Successful") {
+ CategoryInfo : InvalidOperation: (.:OperatorToken) [], RuntimeException
+ FullyQualifiedErrorId : PropertyNotFoundStrict
The Script
Set-PSDebug -strict
Set-StrictMode -Version latest
$consoleObject = (Get-Host).UI.RawUI
# Adjustable Variables
$Computers_Path = ".\computers.txt"
$Log_Path = ".\Log.txt"
$Log_MaxTick = 5
$RunOnServers = 0
# Multi-Threading Variables
$Jobs_MaxAtOnce = 20
$SleepTimer = 500
# Script Specific Variables
$ScriptTitle = "Local Admin Check"
# Validate Adjustable Variables
$Computers = #(Import-CSV $Computers_Path -header "Name","MAC")
# Framework Specific Variables (Pre-Setting Variables)
$Run = 0; $Succssful = 0; $Jobs_Count = 0; $Log_Tick= 0; $WriteToLog = "No"
# Misc
$Total = $Computers.length
IF (!(Test-Path $Log_Path)) { Add-Content $Log_Path "Name,OS,Mac,IPAddress,Status,Attempts,Result,LastAttempt" }
$Log = #(Import-Csv $Log_Path)
$Successful = ($Log | Where-Object {$_.Result -eq "Successful"} | Select-String -inputobject {$_.Name} -pattern $Computers | Measure-Object).Count
# Load Functions
Function GetOS {
$RegCon = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine', $Computer.Name )
$RegKey = $RegCon.OpenSubKey("SOFTWARE\Microsoft\Windows NT\CurrentVersion\")
$RegValue = $RegKey.GetValue("ProductName")
$RegCon.Close()
$Computer.OS = $RegValue
}
Function SmartLogging {
If ($Args[0] -eq "AddComputer") {
Add-Content ($Computer.Name + "," + $Computer.OS + "," + $Computer.Mac + "," + $Computer.IPAddress + "," + $Computer.Status + "," + $Computer.Attempts + "," + $Computer.Result + "," + $Computer.LastAttempt) -path .\log.txt
} ELSEIF ( $Log_Tick -eq $Log_MaxTick -OR $Args -eq "Update" ) {
$Log_Tick = 0;
Get-Content $Log_Path | Foreach-Object {$_ -replace "$Computer.Name,.*", ($Computer.Name + "," + $Computer.OS + "," + $Computer.Mac + "," + $Computer.IPAddress + "," + $Computer.Status + "," + $Computer.Attempts + "," + $Computer.Result + "," + $Computer.LastAttempt)} | Set-Content $Log_Path
} ELSEIF ($Args[0] -eq "CheckComputer") {
IF (!($Log | Select-String -pattern $Computer.Name -SimpleMatch)) {
$Log += New-Object PSObject -Property #{ Name = $Computer.Name; OS = $NULL; Mac = $Computer.MAC; IPAddress = $NULL; Status = $NULL; Attempts = 0; Result = $NULL; LastAttempt = $NULL;}
$Computer = $Log | Where-Object {$_.Name -eq $Computer.Name}
SmartLogging AddComputer
} ELSE {
$Computer = $Log | Where-Object {$_.Name -eq $Computer.Name}
}
} ELSEIF (-not $Args[0]) {
"Log Ticked"
$Log_Tick++
}
}
Function GetIPAddress {
$IPAddress = [System.Net.Dns]::GetHostAddresses("TrinityTechCorp") | Where-Object {$_.IPAddressToString -like "*.*.*.*"};
$Computer.IPAddress = $IPAddress.IPAddressToString
}
Function WindowTitle {
[int]$Successful_Percent = $Successful / $Total * 100
$consoleObject.WindowTitle = “$ScriptTitle - $Successful Out Of $Total ($Successful_Percent%) Successful `| Run`: $Run”
}
# Start Script
while ( $Successful -le $Total ) {
$Run++
ForEach ($Computer in $Computers) {
WindowTitle
SmartLogging CheckComputer
IF ($Computer.Result -ne "Successful") {
IF (test-connection $Computer.Name -quiet ) {
$Computer.Status = "Awake"
IF (!$Computer.OS){GetOS}
IF (!$Computer.IPAddress){GetIPAddress}
## Start Script ##
$CheckComputer = [ADSI]("WinNT://" + $Computer.Name + ",computer")
$Group = $CheckComputer.psbase.children.find("Administrators")
$members= $Group.psbase.invoke("Members") | %{$_.GetType().InvokeMember("Name", 'GetProperty', $null, $_, $null)}
ForEach($user in $members) {
$Result = $Computer.Name + "," + $user.ToString()
Add-Content $Result -path .\Result.csv
}
## End Script ##
SmartLogging Update
$Computer.Result = "Successful"
$Successful += 1
} ELSE {
$Computer.Status = "Unknown"
}
$Computer.Attempts = [int] $Computer.Attempts + 1
$Computer.LastAttempt = Get-Date -uFormat "%I:%M:%S%p %d%b%y"
}
SmartLogging
}
}
Write-Output "Script Completed"
This declaration of $Computers collection....
$Computers = #(Import-CSV $Computers_Path -header "Name","MAC")
...will not work with this condition:
IF ($Computer.Result -ne "Successful")
The exception message explicitly states this, and where:
Property 'Result' cannot be found on this object. Make sure that it exists. \TestFunction.ps1:86 char:17
To resolve this, I would recommend initializing the property of Result, most likely like so:
$Computers = #(Import-CSV $Computers_Path -header "Name","MAC","Result")
The problem this time is that you don't have Result member in $Computers collection member, only Name and MAC. Unless you add such a member later on your code, which I don't really want to read, as it already is about 100 rows and contains a lot of code that is not related to the actual problem statement.
$Computers = #(Import-CSV $Computers_Path -header "Name","MAC")
Have you tried debugging the script on Powershell ISE? It's built-in debugger for Powershell 2. Take a look at a Technet article about it.