警告
本文最后更新于 2023-10-22,文中内容可能已过时。
Powershell 自动提交代码到 Github
前提
当前 Powershell 版本:
当前 Git 版本:
远程仓库:
监听特定的文件夹下的文件修改,并写入日志
参考博客:Monitoring Folders for File Changes - powershell.one
以下为我的脚本,替换>>>
开头的注释所在的变量,然后保存为.ps1
文件即可使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
|
# >>> 指定监控路径
$BlogRepoPath = 'path2monitoredFolder'
# >>> 指定日志文件夹
$basicLogPath = 'path2logFolder'
# >>> 指定监控路径对应的远程仓库名
$remoteReposity = 'remoteRepositoryName'
# specify which files you want to monitor
$FileFilter = '*'
# specify whether you want to monitor subfolders as well:
$IncludeSubfolders = $true
# specify the file or folder properties you want to monitor:
$AttributeFilter = [IO.NotifyFilters]::FileName, [IO.NotifyFilters]::LastWrite
try {
$watcher = New-Object -TypeName System.IO.FileSystemWatcher -Property @{
Path = $BlogRepoPath
Filter = $FileFilter
IncludeSubdirectories = $IncludeSubfolders
NotifyFilter = $AttributeFilter
}
# define the code that should execute when a change occurs:
$action = {
# the code is receiving this to work with:
# change type information:
$details = $event.SourceEventArgs
$Name = $details.Name
$OldName = $details.OldName
$FullPath = $details.FullPath
$OldFullPath = $details.OldFullPath
if ($FullPath.StartsWith("$BlogRepoPath\.git") -and -not($FullPath.Contains(".github")) ){
<# Action to perform if the condition is true #>
return
}
# node_modules/
# if ($FullPath.StartsWith("$BlogRepoPath\node_modules")){
# <# Action to perform if the condition is true #>
# return
# }
# public/
if ($FullPath.StartsWith("$BlogRepoPath\public")){
<# Action to perform if the condition is true #>
return
}
# db.json
if ($FullPath.StartsWith("$BlogRepoPath\db.json")){
<# Action to perform if the condition is true #>
return
}
# 准备日志
if (-not (Get-Item -Path $basicLogPath)) {
return
}
$year = (get-date).Year
$mouth = (get-date).Month
$day = (get-date).Day
$filePath = "$basicLogPath\$year-$mouth"
if (-not (Get-Item -Path $filePath)) {
New-Item -ItemType Directory -Path $filePath
}
$logFile = "$filePath\$year-$mouth-$day.log"
if (-not (Get-Item -Path $logFile)) {
New-Item -ItemType File -Path $logFile
}
# type of change:
$ChangeType = $details.ChangeType
# when the change occured:
$Timestamp = $event.TimeGenerated
# save information to a global variable for testing purposes
# so you can examine it later
# MAKE SURE YOU REMOVE THIS IN PRODUCTION!
$global:all = $details
# now you can define some action to take based on the
# details about the change event:
# let's compose a message:
$text = "{0} was {1} at {2}" -f $FullPath, $ChangeType, $Timestamp
# Write-Host ""
# Write-Host $text -ForegroundColor DarkYellow
# Out-File -Append -FilePath $logFile -InputObject ""
Out-File -Append -FilePath $logFile -InputObject $text
# you can also execute code based on change type here:
switch ($ChangeType) {
'Changed' {
"CHANGE"
# 修改的时候提交也要等 5 秒
Start-Sleep -Seconds 1
}
'Created' { "CREATED" }
'Deleted' {
"DELETED"
# to illustrate that ALL changes are picked up even if
# handling an event takes a lot of time, we artifically
# extend the time the handler needs whenever a file is deleted
# Write-Host "Deletion Handler Start" -ForegroundColor Gray
Out-File -Append -FilePath $logFile -InputObject "Deletion Handler Start"
Start-Sleep -Seconds 1
# Write-Host "Deletion Handler End" -ForegroundColor Gray
Out-File -Append -FilePath $logFile -InputObject "Deletion Handler End"
}
'Renamed' {
# this executes only when a file was renamed
$text = "File {0} was renamed to {1}" -f $OldName, $Name
# Write-Host $text -ForegroundColor Yellow
Out-File -Append -FilePath $logFile -InputObject $text
}
# any unhandled change types surface here:
default {
# Write-Host $_ -ForegroundColor Red -BackgroundColor White
Out-File -Append -FilePath $logFile -InputObject $_
}
}
# git 先更新 再提交
# 日志添加时间,
# 目录添加忽略条件。不监听 .git目录下的文件
# 添加一个延时,不要提交太频繁
git -C $BlogRepoPath pull $remoteReposity master
git -C $BlogRepoPath add -A
git -C $BlogRepoPath commit -m 'auto commit'
git -C $BlogRepoPath push $remoteReposity
Out-File -Append -FilePath $logFile -InputObject "push to github $remoteReposity"
}
# subscribe your event handler to all event types that are
# important to you. Do this as a scriptblock so all returned
# event handlers can be easily stored in $handlers:
$handlers = . {
Register-ObjectEvent -InputObject $watcher -EventName Changed -Action $action
Register-ObjectEvent -InputObject $watcher -EventName Created -Action $action
Register-ObjectEvent -InputObject $watcher -EventName Deleted -Action $action
Register-ObjectEvent -InputObject $watcher -EventName Renamed -Action $action
}
# monitoring starts now:
$watcher.EnableRaisingEvents = $true
# Write-Host "Watching for changes to $BlogRepoPath"
# Out-File -Append -FilePath $logFile -InputObject '------------------------------------------------------------------------------------------------------------------------'
# Out-File -Append -FilePath $logFile -InputObject "Watching for changes to $BlogRepoPath"
# since the FileSystemWatcher is no longer blocking PowerShell
# we need a way to pause PowerShell while being responsive to
# incoming events. Use an endless loop to keep PowerShell busy:
do {
# Wait-Event waits for a second and stays responsive to events
# Start-Sleep in contrast would NOT work and ignore incoming events
Wait-Event -Timeout 60
# write a dot to indicate we are still monitoring:
# Write-Host "." -NoNewline
# Out-File -Append -FilePath $logFile -InputObject "."
} while ($true)
}
finally {
# this gets executed when user presses CTRL+C:
# stop monitoring
$watcher.EnableRaisingEvents = $false
# remove the event handlers
$handlers | ForEach-Object {
Unregister-Event -SourceIdentifier $_.Name
}
# event handlers are technically implemented as a special kind
# of background job, so remove the jobs now:
$handlers | Remove-Job
# properly dispose the FileSystemWatcher:
$watcher.Dispose()
# Write-Warning "Event Handler disabled, monitoring ends."
Out-File -Append -FilePath $logFile -InputObject "Event Handler disabled, monitoring ends."
}
|
对此,相比于参考博客中的源码,这里做出了几点改进:
将此 ps1 脚本设置为开机自启
设置 powershell 脚本开机启动有点麻烦,需要在外面套一层.bat
文件,同时还会有闪屏的问题,即打开一个 cmd 窗口执行完语句之后又快速关闭。为了解决这个问题,在.bat
文件的外面再套一层.vbs
即可解决,最终文件如下:
-
创建script.vbs
1
2
3
4
|
Dim WinScriptHost
Set WinScriptHost = CreateObject("WScript.Shell")
WinScriptHost.Run Chr(34) & "path2batfile\script.bat" & Chr(34), 0
Set WinScriptHost = Nothing
|
-
创建script.bat
1
|
pwsh.exe -file path2powershellScript\script.ps1
|
-
将上一小节的脚本保存为script.ps1
,放到 path2powershellScript 指定的位置即可。
-
将script.vbs
创建快捷方式,然后放到C:\Users\<user_name>\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup
文件夹,系统开机的时候,会自动执行此文件夹下的脚本或者软件。