how to use sub-Array notation to specify variables in remote sessions?

This topic contains 2 replies, has 2 voices, and was last updated by  Ian Douglas 4 years, 4 months ago.

  • Author
    Posts
  • #7644

    Ian Douglas
    Participant

    I'm trying to create a script that will query the registry on remote machines.

    I'm running into difficulty when trying to parametrize the keys and values to query.

    My thought is to specify the key/value as an array of 2-tuples, e.g.,

    .\Query-Registry.ps1 -hosts $hosts -RegItems ("HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings","ProxyServer"),("HKLM:\SOFTWARE\Policies\Microsoft\Windows\CurrentVersion\Internet Settings","ProxySettingsPerUser")

     

    The script as I have it so far 'would' work but apparently the matrix notation isn't allowed with the '$using:variable' notation. How can I achieve this with other notation?

    Many thanks!

    Here is my script:

    # —————-

    param (

    [Parameter(Mandatory=$true)][string[]] $Hosts,

    [string[]] $RegItems =(("HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings","ProxyServer"),("HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings","AutoConfigUrl"))

    )

    $IC = Invoke-Command -ComputerName $Hosts -ThrottleLimit 128 -ScriptBlock {

    $RegResult =  @()

    $splat = @{}

    for ($i=0; $i -lt $using:RegItems.count; $i++) {

    $splat[$using:RegItems[$i][0] + " | " + $using:RegItems[$i][1]] = (Get-ItemProperty -Path $using:RegItems[$i][0] -Name $using:RegItems[$i][1]).$using:RegItems[$i][1]

    }

    $RegResult += New-Object PSObject -Property $splat

    $RegResult

    }  -ErrorVariable errmsg 2>$null

     

  • #7645

    Poshoholic
    Participant

    Always peel back the onion so that you can see what is actually happening.

    First, look at the collection you create:

    PS C:\> [string[]] $RegItems =(("HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings","Pro
    xyServer"),("HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings","AutoConfigUrl"))
    PS C:\> $RegItems.GetType()

    IsPublic IsSerial Name BaseType
    ——– ——– —- ——–
    True True String[] System.Array

    That shows you that you created a one-dimensional array of type String. Now look at the contents:

    PS C:\> $RegItems[0]
    HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings ProxyServer
    PS C:\> $RegItems[1]
    HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings AutoConfigUrl

    This confirms the values in each position in that array. You can see here that your array is not created as you expected it to be. Back to the drawing board, try this way:

    PS C:\> [string[][]]$RegItems =(("HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings","ProxyServer"),("HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings","AutoConfigUrl"))

    The key difference here is making sure you identify that you are creating an array of arrays of strings.

    Next, try passing that array to a "remote" system (the local machine):

    PS C:\> Invoke-Command -ComputerName localhost -ScriptBlock {$using:RegItems}
    HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings
    ProxyServer
    HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings
    AutoConfigUrl

    That works, so what if you want to access a property of those values:

    PS C:\> Invoke-Command -ComputerName localhost -ScriptBlock {$using:RegItems.GetType().FullName}
    At line:1 char:54
    + Invoke-Command -ComputerName localhost -ScriptBlock {$using:RegItems.GetType().F ...
    + ~~~~~~~~~~~~~~~~~~~~~~~~~
    Expression is not allowed in a Using expression.
    + CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : InvalidUsingExpression

    Ok, so "using" doesn't allow that. But we can do it if we use parentheses:

    PS C:\> Invoke-Command -ComputerName localhost -ScriptBlock {($using:RegItems).GetType().FullName}
    System.Collections.ArrayList

    Now you can see that on the other side (on the "remote" system), the array was received as an array list. What about individual items in the array list:

    PS C:\> Invoke-Command -ComputerName localhost -ScriptBlock {$using:RegItems[0]}
    HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings
    ProxyServer

    Yup, works. And getting a specific item in one of those arrays:

    PS C:\> Invoke-Command -ComputerName localhost -ScriptBlock {$using:RegItems[0][1]}
    ProxyServer

    Now that you verified each of the pieces, you can make your script work.

  • #7646

    Ian Douglas
    Participant

    Excellent response! Thank you for teaching me how to fish rather than just giving me the fish.

    My script is now working as desired.

     

     

You must be logged in to reply to this topic.