空值似乎在foreach循环中产生不正确的数据

时间:2018-10-17 08:32:48

标签: powershell null

我有几个示例,但是我发现,如果在foreach循环中的某个迭代返回Null谷值,或者不存在,则它会传播前一个迭代的值。

例如,在这里,我尝试获取一组远程计算机上的默认浏览器详细信息:

$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 :(得分:0)

将值保存到变量时,变量将保持该值,直到另行通知为止。本质上,当您到达循环中没有值的计算机时,该变量将不会更新,并且会使用以前的值。

要解决此问题,您可以将代码包装在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"
}
}

至少,这样一来,您就不应该重复上一个结果。 我确定其他人可以通过更漂亮的方式来解决此问题,但这就是我想到的查看您的代码的想法。

答案 1 :(得分:0)

我稍微整理了一下代码并添加了try{..} catch{..}块,因为读取远程计算机上的注册表值可能由于各种原因而出错。

就像SimonBøgelund一样,如果您确实发现了一些东西,我已经添加了一个测试,仅将新的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