0

I'm setting up a Powershell script to provide some user notifications. The notification is legal in nature and may be updated/changed from time to time so it must be fairly easy to locate. It also has a few 'fill in the blank' variables that depend on the person receiving the notification.

I wanted to have a secondary Powershell file that contained the copy (text) to be used, so something like...

$body = "By accessing this system, you agree that your name ($currentUserName) and IP address ($currentUserIPAddr) will be recorded and stored for up to ($currentUserRetentionPeriod)."

The file could be updated as needed without actually opening the script, finding the line to edit, and potentially messing up other items/just being difficult. However, I'm looping through several thousand users in a single execution, so all the $currentUser... variables will be re-used frequently. This poses a problem because $body tries to get the variables immediately and acts as a static string instead of evaluating the variable contents each time it's invoked.

Is there a clever way for me to define $body a single time (i.e. not inside a loop) but still allow for redefinition of internal variables? I'd also rather not split the string up into multiple parts so it became $part1 + $var1 + part2 + var2....n+1 times.

Brian R
  • 785
  • 1
  • 6
  • 13
  • Define the variable in a script block with parameters (essentially, a function) and invoke it `. { Param($user) $var = "$user" } -user 'thisuser'` – Maximilian Burszley Nov 16 '17 at 16:40
  • Is not this one purpose of having script parameters? Or do I not understand the question? – Bill_Stewart Nov 16 '17 at 16:55
  • @Bill_Stewart Well the variables that would make up the parameters are being retrieved during execution of the script itself. At the moment my script is a single function since it's fairly short, but TheIncorrigible1's response has made me consider the reasonable choice of a secondary call. I'm not sure if this will enable me to have a dot-sourced external file containing my 'copy' variable that I can reference, but it's a step. – Brian R Nov 16 '17 at 17:01
  • I guess I don't understand your question. If you want to retrieve the current user's name, for example, you don't need any fancy processing; just get the `USERNAME` environment variable. – Bill_Stewart Nov 16 '17 at 17:04
  • @Bill_Stewart This is an administrative script that is running on an isolated execution server and getting data from several sources (DBs, SCCM, AD) and sending emails as a batch job. So I'm not actually running this script 1:1 for each user on their local machine, it's just running nightly and performing certain maintenance tasks. – Brian R Nov 16 '17 at 17:09
  • So you are asking about retrieving data from some source into a variable and then using the content of that variable in a script? Is that the question? – Bill_Stewart Nov 16 '17 at 17:16
  • 1
    Is this not a dupe then? https://stackoverflow.com/questions/15168705/how-to-delay-expansion-of-variables-in-powershell-strings cause it sure sound like we are asking about delayed variable expansion – Matt Nov 16 '17 at 20:32

1 Answers1

0

A simple approach would be to just dot-source the script containing the copy whenever you need the variable "re-compiled":

BodyDef.ps1:

$body = "By accessing this system, you agree that your name ($currentUserName) and IP address ($currentUserIPAddr) will be recorded and stored for up to ($currentUserRetentionPeriod)."

Send-Notification.ps1

$bodyDefPath = (Join-Path $PSScriptRoot BodyDef.ps1)
foreach($user in Get-Users){
    $currentUserName = $user.UserName
    $currentUserIPAddr = $user.IPAddress
    $currentUserRetentionPeriod = $user.RententionPeriod
    . $bodyDefPath
    Send-MailMessage -Body $body
}

The above would work just fine, but it's not very powershell-idiomatic, and kind of silly, reading the file over and over again.

As suggested in the comments, you should define a second function (or just a scriptblock) if you want to reuse the same template with different values:

Send-Notification.ps1

# You could as well define this as a function, doesn't make much difference
$NotificationSender = {
    param($User)

    $body = "By accessing this system, you agree that your name ($($user.UserName)) and IP address ($($user.IPAddress)) will be recorded and stored for up to $($user.RetentionPeriod)."
    Send-MailMessage -Body $body
}

foreach($user in Get-Users){
    & $NotificationSender -user $user
}
Mathias R. Jessen
  • 157,619
  • 12
  • 148
  • 206