Нулевые значения, кажется, производят неправильные данные в цикле foreach - PullRequest
0 голосов
/ 17 октября 2018

У меня есть несколько примеров этого, но я обнаружил, что если итерация в цикле foreach возвращает пустое значение или не существует, она распространяет значение предыдущей итерации.

Например, здесь я пытаюсьчтобы получить сведения о браузере по умолчанию для группы удаленных компьютеров:

$Results = foreach ($Computer in $Computers) {
    $User = $computer -Replace '\D*\d*(\w*)', '$1'
    $ADUser = Get-ADUser -Server server.com -Identity $User -Properties *
    $CompProps = Get-ADComputer -Server servercom -Identity $Computer

    $SID = (Get-ADUser -Server server.com -Identity $User).SID.Value

    $ComputerName = "$Computer"
    $Hive = 'Users'

    $KeyPath = "$SID\Software\Microsoft\windows\Shell\Associations\UrlAssociations\http\UserChoice"
    $Value = 'Progid'
    $reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey("$hive", "$ComputerName")
    $key = $reg.OpenSubKey("$KeyPath")
    $Browser = $key.GetValue($Value)

    [PSCustomObject]@{
        FullName       = $ADUser.Name
        UserName       = $ADUser.SamAccountName
        Computer       = $CompProps.Name
        DefaultBrowser = switch ($Browser) {
            'ChromeHTML' { Write-Output "Google Chrome" }
            'IE.HTTP' { Write-Output "Internet Explorer" }
            'AppXq0fevzme2pys62n3e0fbqa7peapykr8v' { Write-Output "Microsoft Edge" }
        }
    }
}
$Results

Когда результаты появятся, как только появится компьютер без пути реестра "$ SID \ Software \ Microsoft \ windows \ Shell\ Associations \ UrlAssociations \ http \ UserChoice ", он повторяет последнее значение.

Почему это так и что я могу сделать, чтобы обойти это?

Ответы [ 2 ]

0 голосов
/ 17 октября 2018

Я немного прибрал ваш код и добавил блок try{..} catch{..}, потому что чтение значений реестра на удаленных машинах может привести к ошибкам по разным причинам.

Как и Симон Бегелунд, я добавил тест только для добавленияновый PSCustomObject к результатам, если вы действительно что-то нашли.

Важно, я думаю: При открытии ключей реестра всегда выполняйте очистку, закрывая их снова после того, как вы закончили их использовать.

В любом случае, вот код:

# the $Computers is an array of remote machine names

$Results = @()
ForEach ($Computer in $Computers) {
    # don't know what the $Computers list contains, but.. is this correct?
    $User      = $computer -Replace '\D*\d*(\w*)', '$1'          
    # these properties are returned by default for Get-ADUser: 
    # DistinguishedName, Enabled, GivenName, Name, ObjectClass, ObjectGUID, SamAccountName, SID, Surname, UserPrincipalName
    $ADUser    = Get-ADUser -Server server.com -Identity $User   
    $CompProps = Get-ADComputer -Server server.com -Identity $Computer 
    $SID       = $ADUser.SID.Value 
    $KeyPath   = "$SID\Software\Microsoft\windows\Shell\Associations\UrlAssociations\http\UserChoice" 

    try {
        $reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey("Users", $Computer) 
        $key = $reg.OpenSubKey($KeyPath) 
        $Browser = $key.GetValue('Progid') 

        if ($Browser) {
            $Results += [PSCustomObject]@{
                 FullName       = $ADUser.Name
                 UserName       = $ADUser.SamAccountName
                 Computer       = $CompProps.Name 
                 DefaultBrowser = Switch ($Browser) {
                                        'ChromeHTML'                           { "Google Chrome" }
                                        'IE.HTTP'                              { "Internet Explorer" }
                                        'AppXq0fevzme2pys62n3e0fbqa7peapykr8v' { "Microsoft Edge" }
                                     }
            }
        }
    }
    catch {
        Write-Warning "Could not open registry key on computer $computer. Reason: $($_.Exception.Message)"
    }
    finally {
        # close the registry keys when done!
        if ($key) { $key.Close() }
        if ($reg) { $reg.Close() }
    }
}

$Results 
0 голосов
/ 17 октября 2018

Когда вы сохраняете значения в переменной, переменная будет сохранять значение, пока не будет указано иное.В сущности, когда вы достигнете компьютера без значения в вашем цикле, переменная не будет обновлена, и будет использоваться предыдущее используемое значение.

Чтобы обойти это, вы можете заключить код в цикл воператор if

$User = $computer -Replace '\D*\d*(\w*)', '$1'
$ADUser = Get-ADUser -Server server.com -Identity $User -Properties * 
$CompProps = Get-ADComputer -Server servercom -Identity $Computer 


$SID = (Get-ADUser -server server.com -Identity $User).SID.Value 


$ComputerName = "$Computer"
$Hive = 'Users'

$KeyPath = "$SID\Software\Microsoft\windows\Shell\Associations\UrlAssociations\http\UserChoice" 
$Value = 'Progid'
$reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey("$hive", "$ComputerName") 
$key = $reg.OpenSubKey("$KeyPath") 
$Browser = $key.GetValue($Value) 

if($keypath -neq $keypathprevious)
{
[PSCustomObject]@{
     FullName          = $ADUser.Name
     UserName          = $ADUser.SamAccountName
     Computer          = $CompProps.Name 
     DefaultBrowser    = Switch ($Browser) {

                    'ChromeHTML' { Write-Output "Google Chrome" }
                    'IE.HTTP' { Write-Output "Internet Explorer" }
                    'AppXq0fevzme2pys62n3e0fbqa7peapykr8v' { Write-Output "Microsoft Edge" }

                }
$keypathprevious = $keypath
}
else
{
write-host "error"
}
}

По крайней мере, таким образом вы не должны сталкиваться с повторениями предыдущего результата.Я уверен, что у кого-то есть более хороший способ решить это, но это то, что я мог бы подумать, глядя на ваш код.

...