快捷方式列表脚本

Shortcut List script

我创建了一个脚本,它将读取名为 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 
} 

您应该合并两个外部 foreach 循环,不仅因为它们迭代同一个集合,而且因为第二个循环试图使用在第一个循环。另外,由于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
}