I. 源电脑(数据发送方)配置#
在传输之前,必须确保两台电脑可以相互访问。
1.1 同一网络和工作组#
1.1.1 同一网络#
确认“源电脑”和“目标电脑”在“同一网段”,同一“专用网络”或“工作网络”。
1.以管理员身份运行 PowerShell 。
2.查看 IP 地址(确保源&目标电脑在同一网段):
3.获取网络连接的“接口别名”:
1
| Get-NetConnectionProfile
|
命令执行后会返回类似以下的结果:
1
2
3
4
5
6
| Name : 网络
InterfaceAlias : Ethernet0
InterfaceIndex : 12
NetworkCategory : Public
IPv4Connectivity : Internet
IPv6Connectivity : NoTraffic
|
记下你要修改的连接的 InterfaceAlias(例如 Ethernet0)和当前的 NetworkCategory。
4.设置网络类型
1
| Set-NetConnectionProfile -InterfaceAlias "Ethernet0" -NetworkCategory Private
|
1
| Set-NetConnectionProfile -InterfaceAlias "Ethernet0" -NetworkCategory Public
|
注意: “域网络”类型通常是系统自动检测并设置的,不建议手动强制设置。但如果确实需要(例如在特定虚拟化环境中),可以使用:
1
| Set-NetConnectionProfile -InterfaceAlias "Ethernet0" -NetworkCategory DomainAuthenticated
|
5.验证更改:
再次运行 Get-NetConnectionProfile,检查 NetworkCategory 是否已更新。
6.通过本地安全策略(GUI)
按下【Win + R】打开“运行”对话框,输入:secpol.msc ,进入:网络列表管理器策略 → 网络名称 → [ 选择你当前使用的网络 ] → 属性,在“网络位置”选项卡中选择:Private(专用)或 Public(公用)。
1.1.2 启用网络发现和共享#
打开“高级共享设置”找到“专用网络”或“工作网络”:
- ✅启用网络发现(自动设置网络连接的设备)
- ✅文件和打印机共享
1.1.3 同一工作组#
确认“源电脑”和“目标电脑”在同一工作组,一般默认 WORKGROUP 工作组。
打开“运行”,输入:sysdm.cpl ,打开“系统属性”查看‘计算机全名’和‘工作组’。
1.2 创建专用账户#
1.按下【Win + R】打开“运行”对话框,输入 lusrmgr.msc 打开 “本地用户和组”控制台,创建数据迁移专用账户,配置参考如下图👇
2.确认上面创建的专用账户它只属于 Users 组(不要有 Administrators 组权限)
3.在命令行创建用户。在命令提示符(管理员)或 PowerShell(管理员)中执行
1
| net user 用户名 密码 /add /passwordchg:no /expires:never
|
💡默认情况下,新用户会自动加入 Users 组。查看该用户信息
确保该用户仅属于 Users 组(如果不在,可手动加入)
1
| net localgroup Users 用户名 /add
|
如果该用户还属于 Administrators 或其它组,可通过以下命令删除
1
| net localgroup Administrators 用户名 /delete
|
设置用户密码永不过期(可选项)
1
| wmic useraccount where name='用户名' set PasswordExpires=FALSE
|
或在 PowerShell 中
1
| Set-LocalUser -Name "用户名" -PasswordNeverExpires $true
|
删除用户
1.3 拒绝本地登录#
在“运行”对话框中输入 <font style="color:rgb(89, 97, 114);background-color:rgb(241, 243, 244);">secpol.msc</font> 打开“本地安全策略”,配置参考如下图👇
强制立即更新组策略设置,无需等待自动刷新周期
1.4 不显示在登录界面#
以管理员身份打开命令提示符,输入以下命令:
1
| reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\SpecialAccounts\UserList" /v transfer /t REG_DWORD /d 0 /f
|
若要恢复显示,值设为 1 或删除隐藏项:
1
| reg delete "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\SpecialAccounts\UserList" /v transfer /f
|
1.5 共享待发送目录#
1.5.1 设置共享权限#
右键打开目标文件夹属性 -> 选择“共享”选项卡:
1.5.2 设置文件系统权限#
打开“安全”选项卡,配置参考如下图👇
II. 目标电脑(数据接收方)配置#
我们需要在这里创建定时任务,因为它将是主动拉取数据的一方。
2.1 同一网络和工作组#
1.同一网段:确认“目标电脑”和“源电脑”在"同一网段"。
2.同一网络:确认“目标电脑”和“源电脑”在同一“专用网络”或“工作网络”。
3.同一工作组:确认“目标电脑”和“源电脑”在同一工作组,一般默认为 WORKGROUP 工作组。
2.2 添加 Windows 凭据#
在“运行”对话框中输入 <font style="color:rgb(89, 97, 114);background-color:rgb(241, 243, 244);">control.exe keymgr.dll</font> 打开“凭据管理器”,添加在源电脑(数据发送方)上创建的专用账户(服务端名称前不需要添加 \\),配置参考如下图👇
测试连接,在“运行”对话框中输入:\\源电脑的计算机名或 IP 地址(例如 \\DESKTOP-ABC1234 或 \\192.168.1.100)。若能看到一个文件夹,并且能打开,说明共享和网络连接是正常的;若不能,请参考后续章节排查问题。
2.3 编写 Robocopy 脚本#
由于 Robocopy 本身只能按“天”来筛选修改时间(通过 /MINAGE 和 /MAXAGE 参数),不能精确到小时/分钟/秒,实际测试如仅删除昨天(00:00:00 - 23:59:59)的文件,在 Windows 批处理脚本(.bat)中无法实现,建议使用 PowerShell 脚本实现。PowerShell 脚本编码格式建议为 UTF-8 with BOM ,否则控制台和产生的日志会有乱码。
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
| <#
PowerShell 自动备份与清理脚本(最终一体版)
功能:
1. 删除目标目录及日志目录中 14 天前文件;
2. 使用 robocopy 按日期区间复制文件;
3. 每个目标目录日志记录删除和复制操作;
4. 支持每日主日志汇总统计(删除文件数/复制文件数);
5. 多线程 robocopy;
6. 测试模式。
#>
# ======================== 配置区域 ========================
$SourceDir1 = "\\SharePC1\Source1"
$SourceDir2 = "\\SharePC2\Source2"
$SourceDir3 = "\\SharePC3\Source3"
$TargetDir1 = "E:\Backup1"
$TargetDir2 = "E:\Backup2"
$TargetDir3 = "E:\Backup3"
$LogDir = "E:\Logs"
$DeleteDays = 14
$Threads = 16
$TestMode = $false # 设置为 $true 仅打印操作,不实际执行
# ======================== 函数定义 ========================
function Invoke-ForfilesDelete {
param(
[string]$Path,
[int]$Days,
[string]$OutputLogPath = $null,
[switch]$Quiet
)
if (-not (Test-Path $Path)) { Write-Host "路径不存在,跳过删除: $Path"; return }
$escapedPath = '"' + $Path + '"'
$cmd = "forfiles /P $escapedPath /S /D -$Days /C `"cmd /c del /q @path && echo 已删除: @path`""
if ($TestMode) { Write-Host "[TEST MODE] Would run: $cmd"; return }
$output = cmd.exe /c "$cmd" 2>&1 | Where-Object { ($_ -ne "") -and ($_ -notmatch "用指定的搜索标准没有找到文件") }
$timeHeader = "==== 删除执行时间:$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') ===="
if ($Quiet) { return }
elseif ($OutputLogPath) {
$isNewFile = -not (Test-Path $OutputLogPath) -or ((Get-Item $OutputLogPath).Length -eq 0)
if ($isNewFile) {
$logName = Split-Path $OutputLogPath -Leaf
$title = "########## $logName 删除与复制记录 ##########"
$title | Out-File -FilePath $OutputLogPath -Encoding UTF8 -Append
"" | Out-File -FilePath $OutputLogPath -Encoding UTF8 -Append
}
$timeHeader | Out-File -FilePath $OutputLogPath -Encoding UTF8 -Append
if ($output) { $output | Out-File -FilePath $OutputLogPath -Encoding UTF8 -Append }
else { "没有找到可删除的文件。" | Out-File -FilePath $OutputLogPath -Encoding UTF8 -Append }
"" | Out-File -FilePath $OutputLogPath -Encoding UTF8 -Append
}
else {
Write-Host $timeHeader
if ($output) { $output | Write-Host }
else { Write-Host "没有找到可删除的文件。" }
Write-Host ""
}
}
function Copy-FilesByDate {
param(
[string]$SourceDir,
[string]$TargetDir,
[datetime]$StartTime,
[datetime]$EndTime,
[string]$Description,
[string]$OutputLogPath
)
if (-not (Test-Path $SourceDir)) { Write-Host "源目录不存在: $SourceDir"; return }
if (-not (Test-Path $TargetDir)) { New-Item -ItemType Directory -Force -Path $TargetDir | Out-Null }
$timeHeader = "==== 复制执行时间:$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') ===="
$files = Get-ChildItem -Path $SourceDir -Recurse -File |
Where-Object { $_.LastWriteTime -ge $StartTime -and $_.LastWriteTime -le $EndTime }
if ($TestMode) {
Write-Host "[TEST MODE] Would copy $($files.Count) files from $SourceDir to $TargetDir"
foreach ($f in $files) { Write-Host " $($f.FullName)" }
return
}
if ($OutputLogPath) { $timeHeader | Out-File -FilePath $OutputLogPath -Encoding UTF8 -Append }
if ($files.Count -eq 0) {
if ($OutputLogPath) { "没有找到可复制的文件。" | Out-File -FilePath $OutputLogPath -Encoding UTF8 -Append }
else { Write-Host "没有找到可复制的文件。" }
return
}
foreach ($f in $files) {
$relativePath = $f.FullName.Substring($SourceDir.Length)
$destPath = Join-Path $TargetDir $relativePath
$destDir = Split-Path $destPath -Parent
if (-not (Test-Path $destDir)) { New-Item -ItemType Directory -Path $destDir -Force | Out-Null }
robocopy (Split-Path $f.FullName -Parent) $destDir $f.Name /R:1 /W:1 /MT:$Threads /NFL /NDL /NJH /NJS /NP | Out-Null
if ($OutputLogPath) { "已复制: $destPath" | Out-File -FilePath $OutputLogPath -Encoding UTF8 -Append }
}
if ($OutputLogPath) { "" | Out-File -FilePath $OutputLogPath -Encoding UTF8 -Append }
}
# 统计日志文件中的删除数量
function Get-DeletedStats {
param([string]$LogPath)
if (-not (Test-Path $LogPath)) { return @{Count=0; SizeMB=0} }
$deletedLines = Select-String "已删除:" $LogPath | ForEach-Object { $_.Line }
$count = $deletedLines.Count
return @{Count=$count}
}
# 统计日志文件中的复制数量和大小
function Get-CopiedStats {
param([string]$LogPath)
if (-not (Test-Path $LogPath)) { return @{Count=0; SizeMB=0} }
$copiedLines = Select-String "已复制:" $LogPath | ForEach-Object { $_.Line }
$count = $copiedLines.Count
$size = 0
foreach ($line in $copiedLines) {
$filePath = $line -replace "已复制: ",""
if (Test-Path $filePath) { $size += (Get-Item $filePath).Length }
}
return @{Count=$count; SizeMB=[math]::Round($size/1MB,2)}
}
# ======================== 主程序 ========================
$Today = Get-Date
$Yesterday = $Today.AddDays(-1)
$TwoDaysAgo = $Today.AddDays(-2)
if (-not (Test-Path $LogDir)) { New-Item -ItemType Directory -Force -Path $LogDir | Out-Null }
$LogFile1 = Join-Path $LogDir "Log1_$($Today.ToString('yyyyMMdd')).log"
$LogFile2 = Join-Path $LogDir "Log2_$($Today.ToString('yyyyMMdd')).log"
$LogFile3 = Join-Path $LogDir "Log3_$($Today.ToString('yyyyMMdd')).log"
$MainLog = Join-Path $LogDir "Main_$($Today.ToString('yyyyMMdd')).log"
Write-Host "========== 开始执行备份与清理 =========="
# 删除旧文件
Invoke-ForfilesDelete -Path $TargetDir1 -Days $DeleteDays -OutputLogPath $LogFile1
Invoke-ForfilesDelete -Path $TargetDir2 -Days $DeleteDays -OutputLogPath $LogFile2
Invoke-ForfilesDelete -Path $TargetDir3 -Days $DeleteDays -OutputLogPath $LogFile3
# 删除旧日志(静默)
Invoke-ForfilesDelete -Path $LogDir -Days $DeleteDays -Quiet
# 复制文件并写入日志
Copy-FilesByDate -SourceDir $SourceDir1 -TargetDir $TargetDir1 `
-StartTime ($Today.Date) -EndTime $Today -Description "源目录1" -OutputLogPath $LogFile1
Copy-FilesByDate -SourceDir $SourceDir2 -TargetDir $TargetDir2 `
-StartTime ($Yesterday.Date) -EndTime ($Today.Date.AddSeconds(-1)) -Description "源目录2" -OutputLogPath $LogFile2
Copy-FilesByDate -SourceDir $SourceDir3 -TargetDir $TargetDir3 `
-StartTime ($TwoDaysAgo.Date) -EndTime ($Yesterday.Date.AddSeconds(-1)) -Description "源目录3" -OutputLogPath $LogFile3
# ======================== 汇总主日志 ========================
$stats1Del = Get-DeletedStats $LogFile1
$stats2Del = Get-DeletedStats $LogFile2
$stats3Del = Get-DeletedStats $LogFile3
$stats1Copy = Get-CopiedStats $LogFile1
$stats2Copy = Get-CopiedStats $LogFile2
$stats3Copy = Get-CopiedStats $LogFile3
$summary = @"
========== $($Today.ToString('yyyy-MM-dd')) 主日志汇总 ==========
目标目录1: 删除 $($stats1Del.Count) 个文件, 复制 $($stats1Copy.Count) 个文件, 总大小 $($stats1Copy.SizeMB) MB
目标目录2: 删除 $($stats2Del.Count) 个文件, 复制 $($stats2Copy.Count) 个文件, 总大小 $($stats2Copy.SizeMB) MB
目标目录3: 删除 $($stats3Del.Count) 个文件, 复制 $($stats3Copy.Count) 个文件, 总大小 $($stats3Copy.SizeMB) MB
============================================================
"@
$summary | Out-File -FilePath $MainLog -Encoding UTF8 -Append
Write-Host "========== 脚本执行完成 =========="
|
2.4 测试脚本#
测试脚本以验证脚本准确性,PowerShell 控制台测试步骤:
1.以管理员身份打开 PowerShell ;
2.首次运行保留 $TestMode = $true ;
3.在 PowerShell 控制台执行脚本(注意替换为你的脚本路径):
1
| powershell -ExecutionPolicy Bypass -File "E:\Script\backup_task.ps1"
|
4.查看控制台和日志文件是否符合预期(路径、时间、文件名等);
5.验证无误后改为 $false 再正式执行。
III. 任务计划配置#
在“运行”对话框中输入 <font style="color:rgb(89, 97, 114);background-color:rgb(241, 243, 244);">taskschd.msc</font> 打开“任务计划程序”。
1.创建基本任务,输入任务“名称”,描述可选;
2.任务触发器,选择任务执行周期;
3.设置任务开始时间;
4.选择要执行的操作:
5.启动程序:
1
| C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
|
1
| -ExecutionPolicy Bypass -File "D:\Scripts\backup_and_cleanup.ps1"
|
6.点击确定完成后,在任务属性【常规】选项卡中:
- 运行任务时用户,选择管理员用户,如
Administrator; - ✅ 不管用户是否登录都要运行;
- ✅ 使用最高权限运行。
7.在【条件】选项卡中:
- ❎(取消勾选)“只有在计算机使用交流电源时才启动此任务”