Working with multiple rows from SQL

Hello,

We use Issuetrak software for helpdesk currently. When someone leaves a voicemail, it creates a ticket and notifies the technician, but it does not attach the voicemail .wav file. I created a script to do this, and it works great if there is only one result in the last 5 minutes. If there is more than one, it either errors out, or only sends one, or sends the same one twice, can't remember, but it is obviously because of how I handle the rows.

Please help?

https://pastebin.com/4FepQf1Q

Thanks you :)

*Edit, changed to pastebin from pastiebin

12 comments · 86% upvoted · other discussions

comments

jheinikel

Maybe you could put a foreach loop on the results variable. You would need to modify the downstream variable names.

Foreach($Result in $Results){
    Rest of script using $Result for each SQL row
}
danekan

You're assuming your array is only returning one item. In general this is often a bad idea and I would explicitly force it into one @() at the time it's put into that variable. You need a for loop around your assignments from $result

0fsysadminwork [OP]

Thank you, I had a feeling an array was going to be an answer but I don't have much experience with them. Will look into them. Thanks :)

[deleted]

That funky indentation was making my eye twitch, so I took some formatting liberties, but see if this might work.

$logfile = 'C:ScriptsLogslogs.txt'
Start-Transcript -path $LogFile -append
sleep -s 5

$query = @"
SELECT
    dbo.issues.IssueNbr,
    dbo.issues.IssueDescription,
    dbo.issues.SubmittedBy,
    dbo.issues.SubmittedDate,
    dbo.issues.AssignedTo,
    dbo.issues.TargetDate,
    dbo.issues.RequiredByDate,
    dbo.attachments.FileName
FROM
    dbo.Issues
INNER JOIN
    dbo.Attachments on dbo.Issues.IssueNbr = dbo.Attachments.IssueNbr
WHERE
    SubmittedDate < GetDate() and SubmittedDate > dateadd(minute, -5, GetDate()) and dbo.Attachments.FileName like '%.wav%'
"@

$results = invoke-sqlcmd -ServerInstance Server -Database Helpdesk -Query $query

Function Process-Result($result) {
    $issuenbr = $result.Issuenbr
    $description = $result.issuedescription
    $submittedby = $result.submittedby
    $submitteddate = $result.submitteddate
    $assignedto = $result.assignedto
    $filename = $result.filename



    If($assignedto -eq 'ittechs'){
        $toaddress = '[email protected]'
    }
    Else {
        $toaddress = Get-ADuser -identity bh3075 -Properties mail | Select-Object -ExpandProperty mail -ErrorAction Stop
    }

    $filepath = '\server$inetpubwwwrootAttachments'
    $attachmentname = $filename
    $file = ($filepath+$attachmentname)

    $MailMessage = @{
        To = $toaddress
        Bcc = "mecompany.com"
        From = "[email protected]"
        Subject = "issue $issuenbr $description"
        Body = "Greetings,<br><br>A ticket has been opened with a voicemail message. The voicemail is attached to this email<br> Issue Number is $issuenbr"
        BodyAsHtml = $true
        SmtpServer = "10.69.66.99"
        Attachments = $file
    }

    Send-MailMessage @MailMessage
}

If($results){
    ForEach($result in $results){
        Process-Result -result $result
    }
}
Else{<# Enter desired error handling when $results is $null #>}

Stop-Transcript

Edit: Remembered to adjust $results to $result inside the function.

Edit2: Added error handling section if $results array is null.

0fsysadminwork [OP]

Wow thanks. I thought the answer would be arrays, I will do some learning on arrays as I am a bit lacking and implement this.

Thanks again.

[deleted]

You're not wrong. A SQL command like you're using will most often return an array of objects, hence why you need a ForEach loop in your code as others have recommended.

If you're not familiar with arrays, I would definitely recommend reading up on how to work with them, as you'll definitely find yourself working with them regularly as you script.

0fsysadminwork [OP]

Can you explain the process result function?

Does it process it once, then process it again if it has a result?

I see "Function Process-Result" but further down If($results){ ForEach($result in $results){ Process-Result -result $result }

Not really understanding this

Thanks :)

[deleted]

When using functions in a script, you first have to define the code that will be run when the function is called. You can see this with the indentation. Everything that is indented below the Function Process-Results line is code that is part of the function. This code isn't executed automatically when the script is run. It has to be called somewhere else in the script after it is defined.

That's where the If($results) block comes in. That code block is outside of the function (i.e. part of the main script). So you use that to run the code inside the function by calling it's name (Process-Result) and you pass in the SQL row you're currently evaluating with the result parameter for the function (-result $result) so that the code inside the function has a SQL row to work with.

Also, I realize I changed up the MailMessage section which might be unfamiliar. What I did there is called parameter splatting. It's helpful with shortening what would otherwise be a long single line in your code to call just one cmdlet. Send-MailMessage is a big culprit of regularly making a long line when not using splatting.

0fsysadminwork [OP]

So when the function is called is below where the variables are set, is that going to cause an issue where they are blank values?

Guess ill find out :P

Thanks again, still learning but have already implemented many scripts, will make them better the more I learn.

[deleted]

That's where passing in the SQL row object comes into play. Inside the function, you're grabbing all your variables based on the SQL object properties. So as long as I give the function the SQL row object to work with, it has all the info for the variables it needs.

0fsysadminwork [OP]

Ah ok I see.

This is great, I tested it with changing it to 1 day, and changed email to me. and it works as expected. Just got 5 emails, with multiple assignee's and they were addressed to the correct people :)

Thanks again!

[deleted]

Glad to help. Just remember, you'll get the most out of this if you use it as a reference of things to learn. Tinkering and learning more about functions in general will greatly help your scripting ability. Though, you'll probably want to tackle arrays first. They are part of the core foundation needed for more advanced scripting.