簡體   English   中英

電源外殼。 無法從 {} 獲取變量

[英]PowerShell. Can't get variable from {}

在下面的代碼中有一個名為“$action” = {...} 的參數。 括號內有一些變量($path、$logPath 等)。如何從大括號“{}”之外的這個參數訪問變量? 我需要我的一個函數(“RunFunctions”)的結果進行 while 循環。 或者,如果這是一些愚蠢的問題,請您指出我可以找到有關此 {} 符號的一些信息的地方嗎? 謝謝。

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 代碼,您可以按需執行(如其他語言中的函數指針或委托)。

通過將存儲在變量$action的塊傳遞給Register-ObjectEvent -Action ,PowerShell 會在感興趣的事件觸發時調用它,並在動態模塊中執行此操作,該模塊的范圍與調用者的范圍完全分開。

因此,您的調用代碼看不到塊內創建的變量,因為它們是該塊的本地變量。

有關 PowerShell 中作用域的更多信息,請參閱此答案的底部部分。

雖然 PowerShell通常也允許您在其他范圍內創建和修改變量,但如果您采取顯式操作,這不是Register-ObjectEvent -Action的選項,因為動態模塊的范圍從根本上無法訪問調用者的范圍,只有到全局范圍。

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

但是,最好避免使用全局作用域,因為即使在腳本退出后全局變量仍然存在(它們是會話全局變量)。

更好的解決方案是:

  • 使動作腳本塊為調用者輸出一個值。

  • 讓調用者通過Receive-Job接收該輸出,使用事件作業
    Register-ObjectEvent -Action返回。

這是一個簡化的、自包含的示例,用於演示該技術:

它設置一個觀察者,附加一個事件處理程序,並創建一個觸發觀察者事件的文件。

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
}

在此代碼中,我的腳本塊“$action”能夠覆蓋在主腳本中初始化的全局參數“terminateFlag” 非常感謝@mklement0 和他提供的鏈接點擊

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
    $global:terminateFlag = 0

    ### 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
                $global:terminateFlag = RunFunctions $path $changeType $logPath
            }

    ### DECIDE WHICH EVENTS SHOULD BE WATCHED
    Register-ObjectEvent $watcher "Created" -Action $action

    while ($true) {
        Write-Host "waiting for file..."
        if ($terminateFlag -eq 1) {
            Exit
        }
        Start-Sleep 10
    }
}
catch {
    Write-Host $_
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM