【问题标题】:Function parameter value changing without modification on my behalf功能参数值更改不代表我修改
【发布时间】:2020-05-08 01:41:51
【问题描述】:

我是一个 powershell 新手,目前遇到了一个愚蠢的问题(至少对我而言),我会尽力在下面解释。

在下次调用该函数时,我遇到了一个函数参数的先前值似乎是“预先”到该相同参数的问题。该函数的那个​​或我的两个参数正在组合中,并且正在发生我不知道的其他事情。单步执行 ISE 调试器无助于解决此问题。我将输入我的代码和我正在阅读的文本文件,然后在下面进一步解释这个问题。

[CmdletBinding()]
Param(
    #Path to file containing weak ACL's before software installation
    [Parameter(Mandatory = $false)] [string]$BeforeInstallACL = "./Before.txt", 

    #Path to file containing weak ACL's after software installation
    [Parameter(Mandatory = $false)] [string]$AfterInstallACL = "./After.txt",

    #Folder location of output file
    [Parameter(Mandatory = $false)] [string]$OutputPath = "./"
)

$latestRegPath = $null

function ReadFromBeforeInstallation ($line, $newRegisteryItem) {
    # Checks if the param (file, dir, or registery key path) exists in $BeforeInstallACL 
    $regItem = $newRegistryItem
    $isPath = CheckIfPath($line)
    Write-Host $line
    $pathFound = $false
    if ($isPath) {
        $content = Get-Content $BeforeInstallACL
        $content | ForEach-Object {
            if ($_.ToString().Trim() -eq $line) {
                $pathFound = $true
                break
            }
       }
       if (!$pathFound) {
           # We have a path that only showed up after installation and want to output this
           $regItem = $line
           WriteToOutput("`r`n{0}`r`n" -f $regItem)
       }
   }
   return $regItem
}

function ReadFromAfterInstallation {
    $content = Get-Content $AfterInstallACL
    $newRegistryItem = $null
    $content | ForEach-Object {
        $_ = $_.Trim()
        if ($_) {
            if ($newRegistryItem) {
                WriteToOutput($_)
            }
            $newRegistryItem = ReadFromBeforeInstallation($_, $newRegistryItem)
        }
        else {
            $newRegistryItem = $null
        }
    }            
}

function WriteToOutput {
    param (
        # Line of a File, Dir or Registery Key from $AfterInstallACl
        [Parameter(Mandatory=$true, Position=0)]
        [string] $Line
    )
    $Line | Out-File -FilePath $OutputFile -Append
}

function CheckIfPath($line) {
    # Check if the line paramater is a path or not
    $isMatch = $false
    if ($line -match "HKEY_LOCAL_MACHINE") {
        $isMatch = $true
    }
    return $isMatch
}

#Create the empty output file we're going to use for logging
$OutputFile = Join-Path -Path $OutputPath -ChildPath difference_output.txt
New-Item $OutputFile -type File -force >$null


Get-Date | Out-File -FilePath $OutputFile 
ReadFromAfterInstallation
Get-Date | Out-File -FilePath $OutputFile -Append

这是after.txt

Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\DRM
Everyone
SetValue, CreateSubKey, CreateLink, ReadKey, ChangePermissions, TakeOwnership


Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Function Discovery\RegistryStore\Publication\Explorer
Everyone
SetValue, CreateSubKey, ReadKey
BUILTIN\Users
SetValue, CreateSubKey, ReadKey


Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Input\HwkSettings
BUILTIN\Users
SetValue, CreateSubKey, ReadKey

这里是 before.txt

Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Function Discovery\RegistryStore\Publication\Explorer
Everyone
SetValue, CreateSubKey, ReadKey
BUILTIN\Users
SetValue, CreateSubKey, ReadKey


Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Input\HwkSettings
BUILTIN\Users
SetValue, CreateSubKey, ReadKey


Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Input\Locales
BUILTIN\Users
SetValue, CreateSubKey, ReadKey


Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Input\Locales\loc_0039
BUILTIN\Users
SetValue, CreateSubKey, ReadKey

问题出在 ReadFromBeforeInstallation() 中,它在 ReadFromAfterInstallation() 中调用。在 ReadFromAfterInstallation 中,我遍历 after.txt 的行,将它们传递给 ReadFromBeforeInstallation,然后查看该行是否包含“HKEY_LOCAL_MACHINE”。如果是这样,并且 before.txt 中不存在该行,我想将该行写入我的输出文件。

听起来很简单。我只是想找到在 after.txt 而不是 before.txt 中的 HKLM 注册表项。我注意到 ReadFromBeforeInstallation 中的 $line 参数保存了过去函数调用的结果。一个简单的 Write-Host 语句将显示如下所示的行

Everyone Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\DRM
SetValue, CreateSubKey, ReadKey Everyone Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Function Discovery\RegistryStore\Publication\Explorer 

我在 after.txt 中从未有过这样的行。当程序运行时,将鼠标悬停在 ISE 中 ReadFromBeforeInstallation 中的 $line 参数上显示 $line 也是它应该是的,但是一旦我到达 CheckifPath() 调用它就会附加一个 HKEY 路径。我真的很难过这里会发生什么。我意识到这是一个很长的帖子,但如果有人可以帮助我,我将不胜感激。

顺便说一句,我的 powershell 版本是 5.1

【问题讨论】:

    标签: powershell


    【解决方案1】:

    您使用了错误的调用语法

    改变这个:

    ReadFromBeforeInstallation($_, $newRegistryItem)
    

    到这里:

    ReadFromBeforeInstallation $_ $newRegistryItem
    # or
    ReadFromBeforeInstallation -line $_ -newRegisteryItem $newRegistryItem
    

    否则,PowerShell 会将表达式 ($_, $newRegistryItem) 解释为 1 个参数,并将其仅绑定到函数的第一个位置参数!

    以下帮助主题可能有助于更好地理解 PowerShell 的命令调用语法:

    【讨论】:

    • 我想我会尝试在这里问而不是另一个问题(如果你愿意,我可以提出一个问题),但是有什么理由让 break 退出整个脚本而不仅仅是循环?使用 foreach 而不是 ForEach-Object 并不能解决问题。 (原来foreach是ForEach-Object的别名)现在应该可以知道原因了
    • @ucprogrammer 控制流语句在管道迭代中不起作用。您需要更改为实际循环 -> foreach ($object in $content) { $object.tostring(); break }
    • 基本上就是@AdminOfThings 所说的——像breakcontinue 这样的流控制语句只能在循环语句中工作——而ForEach-Object 不是循环语句,它是一个模仿foreach 的cmdlet循环
    • 谢谢大家。我最终意识到了这一点。只是花了我一点点
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-20
    • 1970-01-01
    • 2019-08-02
    • 2016-02-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多