我有几个示例,但是我发现,如果在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”的计算机,它就会重复最后一个值。
那是为什么,我该怎么做才能避免?
答案 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