【问题标题】:Foreach Loop to Create Multiple Shortcuts Not Working as Expected用于创建多个快捷方式的 Foreach 循环未按预期工作
【发布时间】:2019-05-20 23:38:29
【问题描述】:

我正在尝试制作一个脚本,用于在桌面上创建多个可执行文件的快捷方式。因为负责创建快捷方式的代码将被多次使用,并且在其他脚本中我决定将它放入一个函数中。

逻辑很简单:

  • 定义函数
  • 在单独的数组中定义快捷方式的目标文件(我在示例中使用notepad.execmd.exe
  • 定义快捷方式的预期路径

我正在尝试使用嵌套的 foreach 循环来遍历目标文件和快捷方式路径数组,但它没有正确生成快捷方式。也许有更好的方法来遍历我没有看到的程序(很有可能,因为我生病了并且脑雾很重)。

脚本至少可以处理一个快捷方式。

我尝试在函数之外运行函数代码。当我从数组中删除命令提示符时,记事本的快捷方式已正确创建。

function CreateShortcuts {
    [CmdletBinding()]
    Param(
        [Parameter(Mandatory = $true, Position = 0)]
        [System.String]$ShortcutPath,

        [Parameter(Mandatory = $true, Position = 1)]
        [System.String]$TargetFile,

        [Parameter(Mandatory = $false, Position = 2)]
        [System.String]$ShortcutArgs
    )

    $objShell = New-Object -ComObject WScript.Shell
    $objShortcut = $objShell.CreateShortcut($ShortcutPath)
    $objShortcut.TargetPath = $TargetFile
    $objShortcut.Save()
}

$TargetFiles = "$env:SystemRoot\System32\notepad.exe", "$env:SystemRoot\System32\cmd.exe"
$ShortcutPaths = "$env:Public\Desktop\Notepad.lnk", "$env:Public\Desktop\Command Prompt.lnk"

foreach ($ShortcutPath in $ShortcutPaths) {
    foreach ($TargetFile in $TargetFiles) {
        CreateShortcuts -ShortcutPath $ShortcutPath -TargetFile $TargetFile
    }
}

预期的输出是记事本的快捷方式和命令提示符出现在桌面上并链接到预期的程序。相反,会发生两个快捷方式链接到cmd.exe

【问题讨论】:

  • 您正在运行 CreateShortcuts 4 次,最后两次指向 cmd.exe。
  • 旁注:使用 Com 对象时,请务必在使用完它们后进行清理。 [System.Runtime.Interopservices.Marshal]::ReleaseComObject($objShell) | Out-Null; [System.GC]::Collect(); [System.GC]::WaitForPendingFinalizers(); $objShell = $null

标签: powershell foreach shortcut


【解决方案1】:

你做错了循环。您正在做的是循环遍历$ShortcutPaths 中的每个项目,并且对于每个循环遍历$TargetFiles 中的每个项目的每个项目,$ShortcutPaths 中的每个项目最终都会创建一个指向$TargetFiles 中最后一个项目的快捷方式.您想要做的是将每个数组中的每个项目与另一个数组中的相同索引项相关联。所以$ShortcutPaths 中的第 1 项与$TargetFiles 中的第 1 项,依此类推。为此,您可以使用 For 循环:

$TargetFiles = "$env:SystemRoot\System32\notepad.exe", "$env:SystemRoot\System32\cmd.exe"
$ShortcutPaths = "$env:Public\Desktop\Notepad.lnk", "$env:Public\Desktop\Command Prompt.lnk"
For($i=0;$i -lt $ShortcutPaths.count;$i++){
    CreateShortcuts -ShortcutPath $ShortcutPaths[$i] -TargetFile $TargetFiles[$i]
}

【讨论】:

    【解决方案2】:

    我同意 TheMadTechnician,只需添加另一个变量 $i 即可从您提供的字符串数组中进行选择。也可以这样写:

    $i=0    
        Foreach ($TargetFile in $TargetFiles) {
    
            CreateShortcuts -ShortcutPath $ShortcutPaths[$i] -TargetFile $TargetFile
            $i=$i+1
    
        } 
    

    我更喜欢在函数部分中有这个 for 循环,你只需将字符串数组传递给函数。像这样的。

    function CreateShortcuts {
    
        [CmdletBinding()]
        Param(
    
            [Parameter(Mandatory = $true, Position = 0)]
            [system.String[]]$TargetFile,
    
            [Parameter(Mandatory = $true, Position = 1)]
            [system.String[]]$ShortcutPath,
    
            [Parameter(Mandatory = $false, Position = 2)]
            [System.String]$ShortcutArgs
        )
            $i=0
            Foreach ($object in $TargetFile) {
                $objShell = New-Object -ComObject WScript.Shell
                $objShortcut = $objShell.CreateShortcut($ShortcutPath[$i])
                $objShortcut.TargetPath = $object
                $objShortcut.Save()
                $i=$i+1
                }
    
    }
    
    
    $TargetFile = "$env:SystemRoot\System32\notepad.exe", "$env:SystemRoot\System32\cmd.exe"
    $ShortcutPath ="$env:Public\Desktop\Notepad.lnk" ,"$env:Public\Desktop\Command Prompt.lnk"
    
    CreateShortcuts  -TargetFile $TargetFile -ShortcutPath $ShortcutPath
    

    【讨论】:

      【解决方案3】:

      感谢大家的投入。这很有帮助,让我摆脱了困境。第二天我的脑雾散去,我脑子里的齿轮终于又开始转动了。我最终使用哈希表来完成这项任务,以确保目标、快捷方式路径和快捷方式参数值都基于同名键匹配。我意识到使用数组可能会出现问题,如果上述每个值的索引彼此无序,或者某些快捷方式需要参数而其他快捷方式不需要。

      以下是更新后的代码。剩下要做的就是添加帮助信息。

          function CreateShortcuts {
      
          [CmdletBinding()]
          Param(
      
              [Parameter(Mandatory = $true,
                         Position = 0)]
              [System.Collections.Hashtable]$TargetFiles,
      
              [Parameter(Mandatory = $true,
                         Position = 1)]
              [System.Collections.Hashtable]$ShortcutPaths,
      
              [Parameter(Mandatory = $false,
                         Position = 2)]
              [System.Collections.Hashtable]$ShortcutArgs
          )
      
      
          $objShell = New-Object -ComObject WScript.Shell
      
          Foreach ($item in $TargetFiles.Keys) {
      
              $objShortcut = $objShell.CreateShortcut($ShortcutPaths.Item($item))
              $objShortcut.TargetPath = $TargetFiles.Item($item)
              if ($ShortcutArgs)  {
                  $objShortcut.Arguments = $ShortcutArgs.Item($item)
              }
              $objShortcut.Save()
          }
      }
      
      
      $TargetFiles = @{
                          "Notepad" = "$env:SystemRoot\System32\notepad.exe"
                          "CmdPrompt" = "$env:SystemRoot\System32\cmd.exe"
                      }
      
      $ShortcutPaths = @{
                            "Notepad" = "$env:Public\Desktop\Notepad.lnk"
                            "CmdPrompt" = "$env:Public\Desktop\Command Prompt.lnk"
                        }
      
      $ShortcutArgs = @{
                           "CmdPrompt" = "/foo -bar"
                           "Notepad" = "/test"
                       }
      
      CreateShortcuts -ShortcutPaths $ShortcutPaths -TargetFiles $TargetFiles -ShortcutArgs $ShortcutArgs
      

      【讨论】:

        猜你喜欢
        • 2021-10-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-10-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多