0

我创建了一个脚本,它将读取一个名为的文件中的用户名列表,Users.csv然后在网络共享中搜索他们的用户配置文件。然后它报告所述用户配置文件的快捷目标路径并将其导出到另一个.csv

当我为每个用户使用它时效果很好,但是当我让它向.csv文件报告数据时,我似乎只能让它报告我的最后一个用户,Users.csv而不是每个用户。我在想这是因为脚本的导出部分覆盖了report.csv它运行的每个用户,我需要它report.csv为每个用户名创建一个唯一的。有人有想法么?

$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
        }        
    }
    [Runtime.InteropServices.Marshal]::ReleaseComObject($Shell) | Out-Null
}
foreach ($User in $Users) {
    $data | Export-Csv c:\temp\report.csv -NoTypeInformation 
} 
4

1 回答 1

1

您应该组合两个外部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
}
于 2020-02-13T20:36:32.477 回答