Why is powershell changing the variable data? Can i make it stop? - powershell

My script takes the content of 2 files, which have an id in the first element of each line. I'm trying to take the id of each line in file 1, find a matching line in file 2, then compare the file 1 line to the file 2 line. If they are different, that difference will be sent to a database file to update. For some reason, the variables holding my data just decide to not hold data anymore. In the following example, the CompareData loses the value of $web and $data, sometime after the first if ($web -match) statement.
function CompareData($web, $data)
{
$webs = $web -split "###"
$datas = $data -split "###"
if ($web -match "1862185823")
{
write-host "$web"
###this will display the full line of the web file, and was only
#added to show what i'm talking about
}
##########################The value of web seems to break sometime after these
##########################variable declarations.
$wid = $webs[0];$wit = $webs[1];$wst = $webs[2];$wpr = $webs[3];$won = $webs[4];$wsd = $webs[5];$wtd = $webs[6];$wcd = $webs[7];$weh = $webs[8];$wdh = $webs[9];$wah = $webs[10];$wac = $webs[11];$wpd = $webs[12]
$did = $datas[0];$dit = $datas[1];$dst = $datas[2];$dpr = $datas[3];$don = $datas[4];$dsd = $datas[5];$dtd = $datas[6];$dcd = $datas[7];$deh = $datas[8];$ddh = $datas[9];$dah = $datas[10];$dac = $datas[11];$dpd = $datas[12]
$wehstr = [string]$weh;$wdhstr = [string]$wdh;$wahstr = [string]$wah;$dehstr = [string]$deh;$dahstr = [string]$dah;$ddhstr = [string]$ddh
$wdCount = $wit.Length / 2
$dtCount = $wit.Length / 2
$newWtitle = $wit.Substring(0, $wdCount)
$newDtitle = $dit.Substring(0, $dtCount)
if ($web -match "1862185823")
{
#the actual contents of $web are now wrong!!!!!!!!!!!!!!!!
}
if ($wehstr.Length -gt $dehstr.Length){$dehstr = $dehstr.PadRight($dehstr.Length + 1, "0")}
if ($wdhstr.Length -gt $ddhstr.Length){$ddhstr = $ddhstr.PadRight($ddhstr.Length + 1, "0")}
if ($wahstr.Length -gt $dahstr.Length){$dahstr = $dahstr.PadRight($dahstr.Length + 1, "0")}
if ($dehstr.Length -gt $wehstr.Length){$wehstr = $wehstr.PadRight($wehstr.Length + 1, "0")}
if ($dahstr.Length -gt $wahstr.Length){$wahstr = $wahstr.PadRight($wahstr.Length + 1, "0")}
if ($ddhstr.Length -gt $wdhstr.Length){$wdhstr = $wdhstr.PadRight($wdhstr.Length + 1, "0")}
if ($newWtitle -match $newDtitle -and $wehstr -match $dehstr -and $wahstr -match $dahstr -and $ddhstr -match $wdhstr -and $wsd -match $dsd -and $wtd -match $dtd -and $wcd -match $dcd -and $won -match $don -and $wst -match $dst -and $wpr -match $dpr -and $wac -match $dac -and $wpd -match $dpd)
{
#write-host "$wid and $did match"
}
else
{
write-host "they didn't match"
}
$wid = "";$wit = "";$wst = "";$wpr = "";$won = "";$wsd = "";$wtd = "";$wcd = "";$weh = "";$wdh = "";$wah = "";$wac = "";$wpd = "";
$did = "";$dit = "";$dst = "";$dpr = "";$don = "";$dsd = "";$dtd = "";$dcd = "";$deh = "";$ddh = "";$dah = "";$dac = "";$dpd = "";
$webs = ""
$datas = ""
}
$dc = gc "${DatabaseFile}"
$wc = gc "${WebFile}"
write-host "Started"
foreach ($w in $wc)
{
try
{
$x = 0
$ws = $w -split "###"#custom delimiter since people are using tabs pipes and everything else in the titles....
$webid = $ws[0]
$result = select-string -Path "${DatabaseFile}" -pattern $webid
if ($result -ne $null)
{
$newresult = $result -replace "D\:\\phi\\phs\\Oversight\\Projects\\Database.txt:\d{1,}:", ""
$doublecheck = $newresult -split "###"
if ($doublecheck[0] -eq $webid)
{
CompareData $w $newresult
}
else
{
write-host "Found a mismatch id, searching individual records line by line for a matching id"
foreach ($d in $dc)#this slow method is only called when someone has another ID in the title in addition to the
{#first element which is also id. Select-string grabs a match in the entire document, so this is here for single
#searching each record for a matching id in the first element
$ds = $d -split "###"
$did = $ds[0]
$found = 0
if ($did -eq $webid)
{
CompareData $w $d
$found = 1
break
}
if ($found -eq 0)
{
write-host "Added $w to Insert file"
$w|out-file -append "${InsertFile}"
}
}
}
}
else
{
write-host "Added $w to Insert file"
$w|out-file -append "${InsertFile}"
}
}
catch
{
}
}

It turns out, the bug in this instance was with the lines
$wdCount = $wit.Length / 2
$dtCount = $wit.Length / 2
$newWtitle = $wit.Substring(0, $wdCount)
$newDtitle = $dit.Substring(0, $dtCount)
These actually take the length of the title element then halve it. I don't need an exact title comparison, just the first half of it's letters just incase someone did infact change the title completely. The new code has corrected this issue, and things are working again.
$wtl = $wit.length
$dtl = $dit.length
$sublength = 0
if ($wtl -ge $dtl)
{
$sublength = $dtl / 2
}
else
{
$sublength = $wtl / 2
}
$newWtitle = $wit.Substring(0, $sublength)
$newDtitle = $dit.Substring(0, $sublength)

Related

Problem assign data from a file read to variables

This is a PowerShell question, sorry if it wound up in the wrong place.
I have a data file which I will call PS_Upgrade_Data. It has 6 items in it listed like this:
item1=item-2=item.3=item 4=item5=item6
Please note that items 2 through 4 are written that way due to the data coming in over which I have no control. There is a dash in item2, a period in intem3 and a space in item4 just to be clear. Items 1, 5, and 6 have nothing between the word item and the number.
I am using the follow PS line to read the data in from the file:
Get-Content "P:\PS_Upgrade_Data.txt" | Where-Object {$_.length -gt 0} | Where-Object {!$_.StartsWith("#")} | Foreach-Object -begin {$count1=0} -process {$var = $_.Split('=',6).Trim()}
This does read the data from the file in ok.
I want to take that data and drop it into six (6) different variables and I tried a foreach loop like the one below:
$count1 = 0
ForEach ($item in $var) {
Write-Host "`n"
Write-Host "count = " , $count1
if($count1 = 0) {
Write-Host "UserInit"
$UserInit = $item
}
elseif ($count1 = 1) {
Write-Host "UserInit"
$TicketNumber = $item
}
elseif ($count1 = 2) {
Write-Host "UserInit"
$UpgradeVersion = $item
}
elseif ($count1 = 3) {
Write-Host "UserInit"
$ClientName = $item
}
elseif ($count1 = 4) {
Write-Host "UserInit"
$InstName = $item
}
elseif ($count1 = 5) {
Write-Host "UserInit"
$Coffee = $item
}
$count1 +=1
}
The problem is that the counter is jumping from 0 (zero) to two (2) and then wont increase and I have no idea why.
What stupid thing am I doing or missing?
Thanks for any help.
PowerShell's assignment operator = supports multiple assignment targets per operation, so you can skip the counter and foreach loop and instead, simply do:
Get-Content "P:\PS_Upgrade_Data.txt" | Where-Object {$_.length -gt 0} | Where-Object {!$_.StartsWith("#")} | Foreach-Object {
$UserInit,$TicketNumber,$UpgradeVersion,$ClientName,$InstName,$Coffee = $_.Split('=',6).Trim()
# do with your variables what you want here
}

Two Objects with different information

When I get email delegation I do it like this
If ($Delegate.count -eq 0) {
$Result = [PSCustomObject]#{
PrimaryEmail = $SourceEmail
Delegate = "None"
}
$resultsEmail += $Result
}
Else {
Foreach ($user in $Delegate) {
$Result = [PSCustomObject]#{
PrimaryEmail = $SourceEmail
Delegate = $user.DelegateAddress
}
$resultsEmail += $Result
}
}
I would like to also get Calendar delegation and add it. The problem is it is two separate amounts of information. Either can be various amounts.
Foreach ($user in $DelegateCalendarl) {
$Result = [PSCustomObject]#{
CalendarDelegateEmail = $DelegateCalendar.'scope.value'
CalendarRole = $DelegateCalendar.role
CalendarDelegateType = $DelegateCalendar.'scope.type'
}
$ResultsCal += $Result
The end out out would be a nice table like
PrimaryEmail | Delegate | CalendarDelegateEmail | CalendarRole | CalendarDelegateType
user#email Delagate#email Delagate#email manager user
user#email "" Delagate2#email Reader user
How can I combine both Results into one nice table csv file out like this example above?
(I know how to output them separately )
This is what I did. Not pretty but it works.
$SourceEmail = 'test#email.com'
[array]$DelegateEmail = gam user $SourceEmail print delegates | ConvertFrom-Csv
[array]$DelegateCalendar = gam calendar $SourceEmail print acls | ConvertFrom-Csv
[int]$max = $DelegateCalendar.Count
if ([int]$DelegateEmail.count -gt [int]$DelegateCalendar.count) { $max = $DelegateEmail.Count; }
$Output = #()
$Result = $null
If ($DelegateEmail.count -eq 0) {$mailD = "None"}
If ($DelegateEmail.count -eq 1) {$mailD = $DelegateEmail.DelegateAddress}
for ( $i = 0; $i -lt $max; $i++) {
If ($DelegateEmail.count -eq 0 -and $i -ige 1) {$mailD = ""}
If ($DelegateEmail.count -eq 1 -and $i -gt 0) {$mailD = ""}
if ($DelegateEmail.count -gt 1) {$MailD = $DelegateEmail.DelegateAddress[$i]}
$Result = [PSCustomObject]#{
PrimaryEmail = $SourceEmail
DelegateEmailAddress = $mailD
CalendarDelegateEmail = $DelegateCalendar.'scope.value'[$i]
CalendarRole = $DelegateCalendar.Role[$i]
CalendarDelegateType = $DelegateCalendar.'scope.type'[$i]
}
$Output += $Result
}
$Output | Export-Csv C:\test.csv -NoTypeInformation

How to get the string name which has failed consecutively for 3 days in powershell

I have data in a text file with the following columns.
Date
StringName
1/1/2021
ABC
2/1/2021
ABC
3/1/2021
ABC
1/1/2021
XYZ
2/1/2021
XYZ
3/1/2021
ABC
4/1/2021
ZZZ
I want only the StringName in the output which has consecutively failed for 3 days or more & ignore the rest. In the above data, ABC has failed for 1 2 3 days consecutively in Calendar month January. So the output should be ABC. If there are more than one stringName then the output should be like below
StringName
ABC
XYZ
Finally, I was able to achieve this. Thank you all
$file_data = get-content "c:\temp\txt.txt"
$dict_counter = #{}
$dict_dates = #{}
Foreach ($line in $file_data)
{
$values = $line.split(" ")
$pattern = '\d{4}-\d{2}-\d{2}'
[System.Text.RegularExpressions.Regex]$regex = New-Object System.Text.RegularExpressions.Regex($pattern)
[System.Text.RegularExpressions.Match]$m = $regex.Match($line)
if($m.Success)
{
$current_date = $m.Value
$sch_name = $values[7]
if($dict_dates.containsKey($sch_name))
{
$existing_date = $dict_dates.get_item($sch_name)
if($existing_date -ne $current_date)
{
$existing_date_format = [datetime]::parseexact($existing_date, 'yyyy-MM-dd', $null)
$current_date_format = [datetime]::parseexact($current_date, 'yyyy-MM-dd', $null)
$difference = (new-timespan -start $existing_date_format -end $current_date_format).days
if($dict_counter.containsKey($sch_name))
{
$diff = $dict_counter.get_item($sch_name)
$diff_new = [string]$diff + "," + [string]$difference
$dict_counter.set_item($sch_name, $diff_new)
}
else
{
$dict_counter.add($sch_name, $difference)
}
}
}
else
{
$dict_dates.add($sch_name, $current_date)
$dict_counter.add($sch_name, 0)
}
}
}
$fail_count = 0
$flagSequence = $false
$seqcounter = 0
Foreach ($value in $dict_counter.values)
{
if($value -ne 0)
{
$arr1 = $value.split(",")
$arr = foreach($number in $arr1){([int]::parse($number))}
$arr = $arr | sort
For($i = 1; $i -lt $arr.count; $i++)
{
$prev = $arr[$i - 1]
$curr = $arr[$i]
$dff = $curr - $prev
if(($dff -eq 1) -or ($dff -eq -1))
{
$flagSequence = $true
$seqcounter += 1
}
else
{
$flagSequence = $false
$seqcounter = 0
}
}
if($seqcounter -ge 2)
{
$fail_count += 1
}
}
}
$dict_counter
$fail_count

Compare Multiple Spreadsheets and Produce CSV output

I am trying to compare two csv files, the first is called tickets.csv and contains the column headers: "tcn", "two", "twod". The second file is called tracker.csv and contains the headers: "cn", "wo", and "wod". I would like to output the contents of tracker.csv, and if any "tcn" (tickets.csv) match "cn" (tracker.csv), then write its associated "two" (tickets.csv) to "wo" (tracker.csv), and "twod" (tickets.csv) to "wod" (tracker.csv).
I'm running into the issue where my code isn't moving the "two" or "wod", and its also writing each object 4 times.
Input CSVs
Import-Csv "$home\Desktop\nestTest\tracker.csv" |
ForEach-Object {
$machine = $_.machine
$wo = ""
$wod = ""
$tickets = import-csv "$home\Desktop\nestTest\tickets.csv"
foreach ($ticket in $tickets) {
try {
$tcn = ""
$two = ""
$twod = ""
$two = $_.wo
$twod = $_.wod
$tcn = $_.cn
if ($tcn -eq $machine) {
$wo = $two
$wod = $twod
}
else {
$wo = ""
$wod = ""
}
}
catch {
}
[pscustomobject]#{
"Machine Name"=$machine
"Work Order #"=$wo
"Work Order Date"=$wod
}
}
} |
select "Machine Name","Work Order #","Work Order Date" |
Export-Csv "$home\Desktop\nestTest\output.csv"
I was looking in the wrong direction before. But I figured it out.
$tracker = Import-Csv "$home\Desktop\nestTest\tracker.csv" |
ForEach-Object {
$machine = ""
$wo = ""
$wod = ""
$machine = $_.machine
$tickets = import-csv "$home\Desktop\nestTest\tickets.csv" |
ForEach-Object {
$two = ""
$twod = ""
$two = $_."wo"
$twod = $_."wod"
$tcn = $_."cn"
if ($tcn -eq $machine) {
$wo = $two
$wod = $twod
}
else {
}
}
[pscustomobject]#{
"Machine Name"=$machine
"Work Order #"=$wo
"Work Order Date"=$wod
}
} |
select "Machine Name","Work Order #","Work Order Date" |
Export-Csv "$home\Desktop\nestTest\output.csv" -NoTypeInformation

Convert Array of Numbers into a String of Ranges

I was asking myself how easily you could convert an Array of Numbers Like = 1,2,3,6,7,8,9,12,13,15 into 1 String that "Minimizes" the numbers, so Like = "1-3,6-9,12-13,15".
I am probably overthinking it because right now I don't know how I could achieve this easily.
My Attempt:
$newArray = ""
$array = 1,2,3,6,7,8,9,12,13,15
$before
Foreach($num in $array){
If(($num-1) -eq $before){
# Here Im probably overthinking it because I don't know how I should continue
}else{
$before = $num
$newArray += $num
}
}
This should working, Code is self explaining, hopefully:
$array = #( 1,2,3,6,7,8,9,12,13,15 )
$result = "$($array[0])"
$last = $array[0]
for( $i = 1; $i -lt $array.Length; $i++ ) {
$current = $array[$i]
if( $current -eq $last + 1 ) {
if( !$result.EndsWith('-') ) {
$result += '-'
}
}
elseif( $result.EndsWith('-') ) {
$result += "$last,$current"
}
else {
$result += ",$current"
}
$last = $current
}
if( $result.EndsWith('-') ) {
$result += "$last"
}
$result = $result.Trim(',')
$result = '"' + $result.Replace(',', '","') +'"'
$result
I have a slightly different approach, but was a little too slow to answer. Here it is:
$newArray = ""
$array = 1,2,3,6,7,8,9,12,13,15
$i = 0
while($i -lt $array.Length)
{
$first = $array[$i]
$last = $array[$i]
# while the next number is the successor increment last
while ($array[$i]+1 -eq $array[$i+1] -and ($i -lt $array.Length))
{
$last = $array[++$i]
}
# if only one in the interval, output that
if ($first -eq $last)
{
$newArray += $first
}
else
{
# else output first and last
$newArray += "$first-$last"
}
# don't add the final comma
if ($i -ne $array.Length-1)
{
$newArray += ","
}
$i++
}
$newArray
Here is another approach to the problem. Firstly, you can group elements by index into a hashtable, using index - element as the key. Secondly, you need to sort the dictionary by key then collect the range strings split by "-" in an array. Finally, you can simply join this array by "," and output the result.
$array = 1, 2, 3, 6, 7, 8, 9, 12, 13, 15
$ranges = #{ }
for ($i = 0; $i -lt $array.Length; $i++) {
$key = $i - $array[$i]
if (-not ($ranges.ContainsKey($key))) {
$ranges[$key] = #()
}
$ranges[$key] += $array[$i]
}
$sequences = #()
$ranges.GetEnumerator() | Sort-Object -Property Key -Descending | ForEach-Object {
$sequence = $_.Value
$start = $sequence[0]
if ($sequence.Length -gt 1) {
$end = $sequence[-1]
$sequences += "$start-$end"
}
else {
$sequences += $start
}
}
Write-Output ($sequences -join ",")
Output:
1-3,6-9,12-13,15