您应该组合两个外部foreach
循环,不仅因为它们正在迭代同一个集合,而且因为第二个循环试图使用$data
在第一个循环中创建的变量 , 。此外,由于Export-Csv
是在循环中调用的,因此您需要传递-Append
参数以防止每次都覆盖输出文件。
$Users = (Get-Content C:\temp\Users.csv) -notmatch '^\s*$'
foreach ($User in $Users) {
$Shortcuts = Get-ChildItem -Recurse \\UNCPATHTOUSERPROFILES\$User -Include *.lnk
$Shell = New-Object -ComObject WScript.Shell
$data = foreach ($Shortcut in $Shortcuts) {
[PSCustomObject]@{
ShortcutName = $Shortcut.Name;
Target = $Shell.CreateShortcut($Shortcut).targetpath
User = $User
}
}
$data | Export-Csv c:\temp\report.csv -Append -NoTypeInformation
[Runtime.InteropServices.Marshal]::ReleaseComObject($Shell) | Out-Null
}
您还可以消除$Shortcuts
和$data
变量以支持使用管道...
$Users = (Get-Content C:\temp\Users.csv) -notmatch '^\s*$'
foreach ($User in $Users) {
$Shell = New-Object -ComObject WScript.Shell
Get-ChildItem -Recurse \\UNCPATHTOUSERPROFILES\$User -Include *.lnk `
| ForEach-Object -Process {
[PSCustomObject]@{
ShortcutName = $_.Name;
Target = $Shell.CreateShortcut($_).targetpath
User = $User
}
} `
| Export-Csv c:\temp\report.csv -Append -NoTypeInformation
[Runtime.InteropServices.Marshal]::ReleaseComObject($Shell) | Out-Null
}
...但请注意,这-Append
仍然是必需的。最后,您可以使用管道重写整个事情......
$Shell = New-Object -ComObject WScript.Shell
try
{
Get-Content C:\temp\Users.csv `
| Where-Object { $_ -notmatch '^\s*$' } -PipelineVariable 'User' `
| ForEach-Object -Process { "\\UNCPATHTOUSERPROFILES\$User" } `
| Get-ChildItem -Recurse -Include *.lnk `
| ForEach-Object -Process {
[PSCustomObject]@{
ShortcutName = $_.Name;
Target = $Shell.CreateShortcut($_).targetpath
User = $User
} `
} `
| Export-Csv c:\temp\report.csv -NoTypeInformation
}
finally
{
[Runtime.InteropServices.Marshal]::ReleaseComObject($Shell) | Out-Null
}
...所以report.csv
它只打开写一次,-Append
不需要。请注意,我正在创建一个WScript.Shell
实例并使用try
/finally
来确保它被释放。
如果用户在Users.csv
下没有目录,则上述任何解决方案和问题中的代码在尝试枚举该目录\\UNCPATHTOUSERPROFILES
时都会引发错误。Get-ChildItem
您可以通过首先检查目录是否存在或传递-ErrorAction SilentlyContinue
给来解决此问题Get-ChildItem
,或者您可以枚举\\UNCPATHTOUSERPROFILES
并过滤出现在Users.csv
...
$Shell = New-Object -ComObject WScript.Shell
try
{
# Performs faster filtering and eliminates duplicate user rows
$UsersTable = Get-Content C:\temp\Users.csv `
| Where-Object { $_ -notmatch '^\s*$' } `
| Group-Object -AsHashTable
# Get immediate child directories of \\UNCPATHTOUSERPROFILES
Get-ChildItem -Path \\UNCPATHTOUSERPROFILES -Directory -PipelineVariable 'UserDirectory' `
<# Filter for user directories specified in Users.csv #> `
| Where-Object { $UsersTable.ContainsKey($UserDirectory.Name) } `
<# Get *.lnk descendant files of the user directory #> `
| Get-ChildItem -Recurse -Include *.lnk -File `
| ForEach-Object -Process {
[PSCustomObject]@{
ShortcutName = $_.Name;
Target = $Shell.CreateShortcut($_).targetpath
User = $UserDirectory.Name
} `
} `
| Export-Csv c:\temp\report.csv -NoTypeInformation
}
finally
{
[Runtime.InteropServices.Marshal]::ReleaseComObject($Shell) | Out-Null
}