Скрипт списка ярлыков - PullRequest
       87

Скрипт списка ярлыков

0 голосов
/ 13 февраля 2020

Я создал скрипт, который будет читать список имен пользователей в файле с именем 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 
} 

1 Ответ

1 голос
/ 13 февраля 2020

Вам следует объединить два внешних цикла foreach не только потому, что они повторяют одну и ту же коллекцию, но и потому, что второй l oop пытается использовать переменную $data, созданную в первом l oop. Кроме того, поскольку Export-Csv вызывается в al oop, вам нужно будет передать параметр -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
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...