电源外壳.无法从{}获取变量 [英] PowerShell. Can't get variable from {}

查看:89
本文介绍了电源外壳.无法从{}获取变量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在下面的代码中,有一个名为"$ action" = {...}的参数.在方括号内有一些变量($ path,$ logPath等),如何从括号"{}"之外的该参数访问变量?我需要一个函数("RunFunctions")的结果进行while循环.或者,如果这是一个愚蠢的问题,请您指出我可以找到有关此{}表示法的某些信息的地方吗?谢谢.

In the code below there is a parameter named "$action" = {...}. Inside the brackets there are some variables ($path, $logPath, etc.) How can I access variables from this parameter outside of the braces "{}"? I need result of one of my functions("RunFunctions") for a while loop. Or if it's some stupid question please can you point me to the place where I can find some information about this {} notation? Thanks.

try {
    ### SET FOLDER TO WATCH + FILES TO WATCH + SUBFOLDERS YES/NO
    $watcher = New-Object System.IO.FileSystemWatcher
    $watcher.Path = "C:\Testers\ResetOptimisation\tracking"
    $watcher.Filter = "user_name*.*"
    $watcher.IncludeSubdirectories = $true
    $watcher.EnableRaisingEvents = $true

    ### DEFINE ACTIONS AFTER AN EVENT IS DETECTED
    $action = { $path = $Event.SourceEventArgs.FullPath
                $logPath = "C:\Testers\ResetOptimisation\output\log.txt"
                $changeType = $Event.SourceEventArgs.ChangeType
                $logline = "$(Get-Date), $changeType, $path"
                Add-content $logPath -value $logline
                $terminateFlag = RunFunctions $path $changeType $logPath
            }

    ### DECIDE WHICH EVENTS SHOULD BE WATCHED
    Register-ObjectEvent $watcher "Created" -Action $action
    Register-ObjectEvent $watcher "Changed" -Action $action
    Register-ObjectEvent $watcher "Deleted" -Action $action
    Register-ObjectEvent $watcher "Renamed" -Action $action
    while ($true) {
        Write-Host $teminateFlag
        if ($teminateFlag -eq 1) {
            Exit
        }
        Start-Sleep 3
    }
}
catch {
    Write-Host $_
}

推荐答案

{ ... }脚本块(字面意思)-可重用的PowerShell代码片段,您可以按需执行(例如函数指针或其他语言的委托.)

{ ... } is a script block (literal) - a reusable piece of PowerShell code that you can execute on demand (like a function pointer or delegate in other languages).

通过将存储在变量$action中的此类块传递给Register-ObjectEvent -Action,PowerShell会在感兴趣的事件触发时调用它,并在动态模块中进行调用,该模块的作用域完全是与呼叫者分开.

By passing such a block, stored in variable $action, to Register-ObjectEvent -Action, PowerShell invokes it whenever the event of interest fires, and does so in a dynamic module, whose scope is entirely separate from the caller's.

因此,您的调用代码看不到在该块内部创建的变量,因为它们是该块的本地变量.

Therefore, your calling code doesn't see the variables created inside the block, as they are local to that block.

有关PowerShell中作用域的更多信息,请参见此答案的底部.

For more information about scopes in PowerShell, see the bottom section of this answer.

虽然PowerShell通常 允许您在 other 范围内创建和修改变量,但是如果您采取显式操作,则不是使用Register-ObjectEvent -Action,因为动态模块的作用域从根本上不能访问调用者的作用域,而只能访问 global 作用域.

While PowerShell generally lets you create and modify variables in other scopes as well, if you take explicit action, this is not an option with Register-ObjectEvent -Action, because a dynamic module's scope fundamentally doesn't have access to the caller's scope, only to the global scope.

# !! This works, but is ill-advised.
$global:terminateFlag = RunFunctions $path $changeType $logPath

但是,最好避免使用全局范围,因为即使脚本退出后,全局变量仍然存在(它们是 session -global).

However, using the global scope is best avoided, because global variables linger even after the script exits (they are session-global).

更好的解决方案是:

  • 使动作脚本块 output 为调用者的值.

使用事件作业
,使调用者通过Receive-Job接收该输出. Register-ObjectEvent -Action返回.

have the caller receive that output via Receive-Job, using the event job that
Register-ObjectEvent -Action returns.

这是一个简化的,独立的示例,演示了该技术:

Here's a simplified, self-contained example that demonstrates the technique:

它设置了一个观察程序,附加了一个事件处理程序,并创建了一个触发观察程序事件的文件.

It sets up a watcher, attaches an event handler, and creates a file that triggers a watcher event.

try {

  # Specify the target folder: the system's temp folder in this example.
  $dir = (Get-Item -EA Ignore temp:).FullName; if (-not $dir) { $dir = $env:TEMP }

  # Create and initialize the watcher.
  $watcher = [System.IO.FileSystemWatcher] @{
    Filter                = '*.tmp'
    Path                  = $dir
  }

  # Define the action script block (event handler).
  $action = {
    # Print the event data to the host.
    Write-Host "Event raised:`n$($EventArgs | Format-List | Out-String)"
    $terminateFlag = $true
    # *Return* a value that indicates whether watching should be stopped.
    # This value is later retrieved via Receive-Job.
    return $terminateFlag
  }

  # Subscribe to the watcher's Created events, which returns an event job.
  # This indefinitely running job receives the output from the -Action script
  # block whenever the latter is called after an event fires.
  $eventJob = Register-ObjectEvent $watcher Created -Action $action

  # Start watching:
  # Note: Not strictly necessary, because, curiously, 
  #       Register-ObjectEvent has aleady done this for us.
  $watcher.EnableRaisingEvents = $true 

  # Using an aux. background job, create a sample file that will trigger the 
  # watcher, after a delay.
  $tempFile = Join-Path $dir "$PID.tmp"
  $auxJob = Start-Job { Start-Sleep 3; 'hi' > $using:tempFile }

  Write-Host "Watching $dir for creation of $($watcher.Filter) files..."

  # Wait in a loop until the action block is run in response to an event and
  # produces $true as output to signal the intent to terminate, via Receive-Job.
  while ($true -ne (Receive-Job $eventJob)) {
    write-host . -NoNewline
    Start-Sleep -Milliseconds 500  # sleep a little
  }

}
finally {
  # Clean up.
  # Dispose of the watcher.
  $watcher.Dispose() 
  # Remove the event job (and with it the event subscription).
  $eventJob | Remove-Job -Force 
  # Clean up the helper job.
  Remove-Job -ea Ignore -Force $auxJob 
  # Remove the temp. file
  Remove-Item -ea Ignore $tempFile
}

这篇关于电源外壳.无法从{}获取变量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆