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