none
Can't figure out how to get a variable to work inside script block

    Question

  • This might be an easy one for you wise Powershell people:

    I'm working on MS Lync 2010 and I'm trying to get the total number of users that have a specific "dial plan" assigned to them.  We have about 50 dial plans so my goal is to make a variable array with all 50 dial plans, run the get-user command with ().count, and have it spit out the number of users for each dial plan.

    If I try it with one dial plan, and no variables, it works fantastic:

    PS C:\work> (get-csuser -filter {dialplan -eq "lync-dp1"}).count
    164

    This tells me there are 164 people that have the dial plan called "lync-dp1" assigned to their Lync accounts.

    Since that worked so well, can someone tell me why this doesn't work?:

    PS C:\work> $dialtest = "lync-dp1"
    PS C:\work> $dialtest
    lync-dp1
    PS C:\work> (get-csuser -filter {dialplan -eq $dialtest}).count
    10521

    Now this is telling me that there are 10521 users that have the "lync-dp1" dial plan.  That is incorrect, but that is the total number of users we have that are lync enabled.  It's like the command didn't go through the filter or something.  The same thing happens when I try to make $dialtest an array (which is ultimately what I'd like to do, make an array with all the dial plans and just fire it off).

    Can anyone tell me what I'm doing wrong in Powershell?

    Tuesday, September 24, 2013 8:51 PM

Answers

  • Hi,

    the issue is, that the variable is not in scope for the script block. You will need to build a closure around it in order to avoid this. PowerShell v3 has a GetNewClosure() command, but you can also use the static Create method of scriptblock instead like so:

    $dialtest = "lync-dp1"
    $sb=[scriptblock]::Create("dialplan -eq $dialtest")
    (get-csuser -filter $sb).count
    
    
    #with array
    $dialtests="lync-dp1","lync-dp2","lync-dp3"
    foreach ($dialtest in $dialtests){
      $sb=[scriptblock]::Create("dialplan -eq $dialtest")
      (get-csuser -filter $sb).count
    }
    

    • Marked as answer by Lync Viking Wednesday, September 25, 2013 3:12 PM
    Tuesday, September 24, 2013 9:01 PM

All replies

  • Hi,

    Try using a string for the filter instead of a scriptblock and see if that helps.


    Don't retire TechNet! - (Maybe there's still a chance for hope, over 11,925+ strong and growing)

    Tuesday, September 24, 2013 8:59 PM
  • Hi,

    the issue is, that the variable is not in scope for the script block. You will need to build a closure around it in order to avoid this. PowerShell v3 has a GetNewClosure() command, but you can also use the static Create method of scriptblock instead like so:

    $dialtest = "lync-dp1"
    $sb=[scriptblock]::Create("dialplan -eq $dialtest")
    (get-csuser -filter $sb).count
    
    
    #with array
    $dialtests="lync-dp1","lync-dp2","lync-dp3"
    foreach ($dialtest in $dialtests){
      $sb=[scriptblock]::Create("dialplan -eq $dialtest")
      (get-csuser -filter $sb).count
    }
    

    • Marked as answer by Lync Viking Wednesday, September 25, 2013 3:12 PM
    Tuesday, September 24, 2013 9:01 PM
  • This is a common miscoding of a -filter argument.  The argument is actually just a string, but you see many examples that for some reason or other depend on the conversion of a scriptblock to a string for the value for the -filter argument.   Just use a string.   No need for the complication of a scriptblock.
    Tuesday, September 24, 2013 11:13 PM
  • It's not really the community's fault; this syntax is all over Microsoft's own documentation.  Just look at the Get-ADUser help file.  It's full of examples of "-Filter {Something}", even though the cmdlet itself expects a string (and you can see "-Filter <string>" in the Syntax section of the help file).

    I assume that the confusion comes from the fact that Where-Object really does take a ScriptBlock argument, and sometimes the other commands work fine when you allow a ScriptBlock to be implicitly casted to a string.  As a result, people don't notice the difference except in a few odd cases.

    Wednesday, September 25, 2013 12:18 AM
  • It's not really the community's fault; this syntax is all over Microsoft's own documentation.  Just look at the Get-ADUser help file.  It's full of examples of "-Filter {Something}", even though the cmdlet itself expects a string (and you can see "-Filter <string>" in the Syntax section of the help file).

    I assume that the confusion comes from the fact that Where-Object really does take a ScriptBlock argument, and sometimes the other commands work fine when you allow a ScriptBlock to be implicitly casted to a string.  As a result, people don't notice the difference except in a few odd cases.

    This is just another reason why I love ss64.com and always go there first. This one gets it right:

    http://ss64.com/ps/get-aduser.html


    Don't retire TechNet! - (Maybe there's still a chance for hope, over 12,000+ strong and growing)

    Wednesday, September 25, 2013 12:29 AM
  • Regarding  http://ss64.com/ps/

    they frequently use double-quotes in their examples where I would have used single-quotes.

    I use double-quotes only when there is an expectation of expansion within the string.

    For example in   http://ss64.com/ps/get-alias.html

    I would have coded 

    PS C:\> get-alias | where-object {$_.Definition -match 'Set-Location'}



    Wednesday, September 25, 2013 2:43 PM
  • Thanks very much Dirk.  I need to familiarize myself with the scope of variables apparently.  I created my array, and pretty much ran what you suggested exactly, and it's working great.

    Thanks for the help!

    Wednesday, September 25, 2013 3:13 PM
  • Did you try the code below?

    (get-csuser -filter "dialplan -eq $dialtest").count

    Wednesday, September 25, 2013 3:23 PM
  • Good point, the double quotes are a habit I picked up from writing too much vbscript, I'll fix that up now.
    Friday, September 27, 2013 11:07 AM