我有一个简单的脚本,该脚本应监视指定文件夹中的新文件,并在到达时解压缩它们。很简单,但是我的脚本仅在Powershell ISE的调试器下有效。在调试器外部时,在文件创建时,它仅打印“找到新文件xxx”和“完成”,而没有对其进行解压缩,删除,也没有错误。我在这里想念什么吗?
# Folder you to monitor
$PathToMonitor = "C:\tmp1".
$OutputPath = "C:\tmp"
$Filter = "*.zip" # Filter for zip files.
$FileSystemWatcher = New-Object System.IO.FileSystemWatcher
$FileSystemWatcher.Path = $PathToMonitor
$FileSystemWatcher.IncludeSubdirectories = $false
$FileSystemWatcher.Filter = $Filter
# make sure the watcher emits events
$FileSystemWatcher.EnableRaisingEvents = $true
# define the code that should execute when a file change is detected
$Action = {
$details = $event.SourceEventArgs
$FullPath = $details.FullPath
$OldName = $details.OldName
$Timestamp = $event.TimeGenerated
try
{
Write-Host "New file " + $FullPath + " found"
$TarProgram = "tar.exe"
$TarArgs = 'xvf "' + $FullPath + '" -C ' + $OutputPath
Start-Process $TarProgram $TarArgs -Wait -WindowStyle hidden
Remove-Item -Path $FullPath -Force
Write-Host "Done"
}
catch [System.SystemException]
{
Write-Host $_.ScriptStackTrace
}
}
# add event handlers
$handlers = . {
Register-ObjectEvent -InputObject $FileSystemWatcher -EventName Created -Action $Action -SourceIdentifier FSCreateFtpGe
}
Write-Host "Watching for changes to $PathToMonitor"
try
{
do
{
Wait-Event -Timeout 10
} while ($true)
}
catch [System.SystemException]
{
Write-Host $_.ScriptStackTrace
}
finally
{
# this gets executed when user presses CTRL+C
# remove the event handlers
Write-Host "Cleaning up"
Unregister-Event -SourceIdentifier FSCreateFtpGe
# remove background jobs
$handlers | Remove-Job
# remove filesystemwatcher
$FileSystemWatcher.EnableRaisingEvents = $false
$FileSystemWatcher.Dispose()
"Event Handler disabled."
}
你为什么在这里有一段时间...
$PathToMonitor = "C:\tmp1".
...这是无效的语法,脚本仍然应该失败。但是,这可能只是您在此处发布时所做的一种。
您为什么使用tar而不是PowerShell内置存档cmdlet?
如果tar.exe不在PowerShell或系统路径中,则必须完全限定该路径才能使用它。
$ TarProgram ='C:\ ProgramFiles \ tar.exe'
因此,您的代码应可在任何PowerShell主机上运行(ISE [进入/退出调试模式])/ powershell.exe / VSCode等。正如我刚刚测试的那样。再次,这些cmdlet在那里。下面的示例在新的Windows终端中运行。
#region Begin Script
# Folder you to monitor
$PathToMonitor = 'D:\tmp1'
$OutputPath = 'D:\tmp'
$Filter = '*.zip' # Filter for zip files.
$FileSystemWatcher = New-Object System.IO.FileSystemWatcher
$FileSystemWatcher.Path = $PathToMonitor
$FileSystemWatcher.IncludeSubdirectories = $false
$FileSystemWatcher.Filter = $Filter
# make sure the watcher emits events
$FileSystemWatcher.EnableRaisingEvents = $true
# define the code that should execute when a file change is detected
$Action = {
$details = $event.SourceEventArgs
$FullPath = $details.FullPath
$OldName = $details.OldName
$Timestamp = $event.TimeGenerated
try
{
"New file $FullPath found"
Expand-Archive -Path $FullPath -DestinationPath 'D:\tmp'
# Start-Process $TarProgram $TarArgs -Wait -WindowStyle hidden
Remove-Item -Path $FullPath -Force
'Done'
}
catch [System.SystemException]
{$PSItem.ScriptStackTrace}
}
# add event handlers
$handlers = . {
$RegisterObjectEventSplat = @{
InputObject = $FileSystemWatcher
EventName = 'Created'
Action = $Action
SourceIdentifier = 'FSCreateFtpGe'
}
Register-ObjectEvent @RegisterObjectEventSplat
}
"Watching for changes to $PathToMonitor"
try
{
do { Wait-Event -Timeout 10 }
while ($true)
}
catch [System.SystemException]
{$_.ScriptStackTrace}
finally
{
<#
this gets executed when user presses CTRL+C
remove the event handlers
#>
'Cleaning up'
Unregister-Event -SourceIdentifier FSCreateFtpGe
# remove background jobs
$handlers |
Remove-Job
# remove filesystemwatcher
$FileSystemWatcher.EnableRaisingEvents = $false
$FileSystemWatcher.Dispose()
'Event Handler disabled.'
}
#endregion End Script
# Results
Get-CimInstance -ClassName Win32_OperatingSystem | Select-Object -Property Caption, Version
Caption Version
$PSVersionTable
Name Value
---- -----
PSVersion 5.1.18362.752
PSEdition Desktop
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0, 5.0, 5.1.18362.752}
BuildVersion 10.0.18362.752
CLRVersion 4.0.30319.42000
WSManStackVersion 3.0
PSRemotingProtocolVersion 2.3
Get-ChildItem -Path 'D:\tmp' -Verbose
(Get-ChildItem -Path 'D:\tmp').Count
0
Get-ChildItem -Path 'D:\tmp1' -Verbose
(Get-ChildItem -Path 'D:\tmp1').Count
0
.\FSWCopyUnzip.ps1
Watching for changes to D:\tmp1
New file D:\tmp1\book1.zip found
Done
Cleaning up
Get-ChildItem -Path 'D:\tmp' -Verbose
Directory: D:\tmp
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 13-Mar-20 12:19 70 abc.txt
-a---- 13-Mar-20 22:27 71 book1.txt
-a---- 06-Apr-20 21:51 2979 Data.zip
-a---- 04-Mar-20 01:04 72 FileWithLines.txt
Get-ChildItem -Path 'D:\tmp1' -Verbose
(Get-ChildItem -Path 'D:\tmp1').Count
0
仅作记录,我发现了问题。它在某种程度上与Powershell中的变量作用域有关。如果不是使用脚本开头声明的变量来保存$ OutputPath的值,而是使用文字字符串,那么它将起作用。否则,它会抱怨该值在运行时为空(在Powershell ISE中它显示一个值)
所以,动作块现在看起来像这样:
$Action = {
$details = $event.SourceEventArgs
$FullPath = $details.FullPath
$OldName = $details.OldName
$Timestamp = $event.TimeGenerated
try
{
Expand-Archive -LiteralPath $FullPath -DestinationPath "C:\Temp"
Remove-Item -LiteralPath "$FullPath" -Force
}
catch [System.SystemException]
{
Write-Host $_
}
}
我希望一开始就拥有我的所有变量,因此可以根据需要轻松更改它们,但至少此版本有效。