通过 Powershell 按计划导出和存档您的项目 => 轻松搞定!
如何编写一个 Powershell 脚本,该脚本将首先导出您的所有项目(不包括源代码控制数据),然后使用 7-Zip 对其进行打包。
引言
在多年的 Web 开发工作中,我创建了相当多的 MVC 和 WebForms 项目。当然,我希望它们随时都能得到备份。由于它们都处于某种源代码控制之下,所以它们基本上已经得到了备份(备份到Subversion服务器和共享文件夹中的Git裸仓库)。此外,我的计算机每天都会创建备份映像。
但这对我来说还不够!而且,由于我像个偏执狂一样担心硬盘故障 == 渴望 N 次备份,所以我还手动创建了特定项目的存档... 更不用说,我没有从那些存档中删除版本控制和临时数据(例如 'bin' 和 'obj' 文件夹),尽管我多么希望做到这一点。
最近,我厌倦了那些讨厌的重复鼠标点击和肮脏的拖放操作。我想:“这太愚蠢了,我们生活在科技和信息的时代,有 国际空间站 在我们头顶上飞翔,有 大型强子对撞机 在欧洲不断失败,而我还在像原始人一样手动创建存档……我的电脑必须为我做这项繁琐的工作!”
所以,在本文中,我将解释我做了什么来摆脱我的痛苦。
目录
目标
本文实现了以下目标
- 复制特定的项目文件夹,同时保留子文件夹结构
- 删除所有版本控制信息(来自 Subversion 和 Git)
- 删除临时、二进制和不需要的文件和文件夹(例如,'obj' 和 'bin' 文件夹、ReSharper 数据和其他)。
- 归档清理过的项目副本
- 最后,按计划执行以上所有操作
使用 Windows 批处理文件
我过去经常玩 Linux Mint,在那里我喜欢编写简单的 shell 脚本来完成日常任务,例如关闭 WiFi、启动备份、更改键盘布局、挂载系统映像等等。
例如,这个 shell 脚本创建一个 Gzip 存档,其中包含系统驱动器上的所有文件,同时排除自身和某些其他系统文件夹
cd /
sudo tar cvpzf backup.tgz --exclude=/backup.tgz --exclude=/proc --exclude=/lost+found --exclude=/sys /
所以,我想在 Windows 中做类似的事情,并希望让它变得智能。
我首先想到的就是编写一个简单的批处理文件(扩展名为 .bat 的文本文件),这样当你执行它时,它就会按顺序运行一些命令。
要开始使用批处理文件,我首先需要一个 Windows 命令行命令,该命令可以从我的项目目录中仅复制特定的项目文件夹和文件,并保留子文件夹结构。经过一些研究,我找到了一个名为“XCopy”的命令,它非常适合我的需求。下面是它的样子
XCopy SourcePath DestinationPath /EXCLUDE:C:\export_exclude.txt /C /F /I /E /R /H /Y
现在我将详细介绍该命令。
/EXCLUDE:C:\export_exclude.txt
- 包含要从复制中排除的所有名称的文本文件的路径。在我的情况下,我添加了这些名称
.svn
.git
.suo
\obj\
Thumbs.db
ReSharper
这里我有一套基本的要清理的内容 - Subversion 和 Git 数据(.svn
和 .git
),项目临时数据(.suo
和 \obj\
),Windows 图像缩略图(Thumbs.db
),以及 ReSharper 项目数据(ReSharper
)。
更具体地说,下面是如何设置排除列表(引自 此处)
“每行一个字符串。如果列出的任何字符串与要复制的文件的绝对路径的任何部分匹配,则该文件将被排除在复制过程之外。例如,如果指定字符串‘\Obj\
’,则排除 Obj 目录下的所有文件。如果指定字符串‘.obj’,则排除所有扩展名为 .obj 的文件。”
现在我来解释一下该命令末尾键的含义。
/C
- 忽略错误。
/F
- 复制时显示源和目标文件名。
/I
- 显示将要复制的文件列表。
/E
- 复制所有子目录,即使它们是空的。
/R
- 复制只读文件。
/H
- 复制具有隐藏和系统文件属性的文件。默认情况下,XCopy 不会复制隐藏或系统文件。
/Y
- 禁止提示确认是否要覆盖现有目标文件。
我以这种方式设置了这些键,以便所有内容都将在后台静默复制,但如果我手动运行此命令,我也可以看到一些输出。
之后,我创建了一个批处理文件(copy.bat)- 它只是一个扩展名为 .bat
的文本文件。由于我需要干净地复制特定的项目,我的批处理文件看起来是这样的
XCopy Project1Path Project1CopyPath /EXCLUDE:C:\export_exclude.txt /C /F /I /E /R /H /Y
XCopy Project2Path Project2CopyPath /EXCLUDE:C:\export_exclude.txt /C /F /I /E /R /H /Y
XCopy Project3Path Project3CopyPath /EXCLUDE:C:\export_exclude.txt /C /F /I /E /R /H /Y
...
XCopy ProjectNPath ProjectNCopyPath /EXCLUDE:C:\export_exclude.txt /C /F /I /E /R /H /Y
它运行得还可以。但从程序员的角度来看,感觉不太对劲。太多的重复(而且 我们不需要那些该死的徽章…… 哎呀,重复:)。
你可以看到,如果项目列表很大,它将变得多么难以维护。如果想更改 XCopy 键怎么办?在记事本中执行‘Ctrl+H’也不太方便……
我需要一个更好的解决方案,而它以 PowerShell 的形式出现。
使用 PowerShell(基础知识)
如果您已经有一些 PowerShell 经验,您可能想跳到下一节,因为本节只介绍 PowerShell 的基础知识。否则,请继续阅读!
PowerShell 是一个高级的 Windows 控制台应用程序。它的目的是为命令行操作(类似于 Linux 中的 bash shell)添加高级功能,并为编写 shell 脚本提供强大的环境。
PowerShell 运行在 .NET Framework 之上,因此它所有的强大功能都可以供 PowerShell 使用。例如,与常规的批处理文件不同,PowerShell 脚本文件(扩展名为 .ps1 的文本文件)可以包含 C# 风格的代码 - 声明变量
和数组
,'For' 循环
和'If' 语句
等;所有这些都为编写高级有效的脚本开辟了全新的可能性。
如果您有 Windows 7 SP1,那么您的系统中很可能已经安装了 PowerShell。只需从开始菜单搜索“PowerShell”即可检查您是否拥有它。如果没有,请从此处下载并安装:http://www.microsoft.com/PowerShell。
也请记住!安装 PowerShell 后,您将无法立即运行 PowerShell 脚本!听起来很荒谬,对吧?嗯,这是微软风格的安全措施。要启用脚本运行,请打开 PowerShell 命令提示符并输入(或通过 Shift+Insert 复制)此命令
Set-ExecutionPolicy RemoteSigned
这将使您的系统能够运行在本地创建的脚本,而不是从互联网下载的脚本(您可能不想这样做)……有关此的更多信息,请阅读此文。
让我们看看我需要了解的、能够实现我的目标的基本知识
在 PowerShell 中声明变量
我们需要了解的第一件事是如何设置变量。打开 PowerShell 提示符并像这样声明一个变量
$test = "test"
这将创建一个字符串变量 test,其值为“test”。这是它在 PowerShell 中的样子,我先声明了变量,然后按名称调用它
很简单,不是吗?
在 PowerShell 中声明数据数组
之后,我想知道如何声明一个数据数组,以便保存我想备份的项目文件夹的名称
$array = @(0,9,0,9,1,9,8,2)
这基本上创建了一个整数列表,并且输出它的方式与普通变量相同
看起来不错,接下来我还需要什么?
在“For”循环中运行代码
这与您的常规 C# 应用程序非常相似。让我们使用我之前声明的数组 $array 来输出其内容
$array = @(0,9,0,9,1,9,8,2)
for ($i = 0; $i -le $array.Length - 1; $i++) {
Write-Host $array[$i]
}
现在是坏消息 - 您不能简单地将这段代码复制并粘贴到控制台中。您需要将它们输入到一行中,用“;”分隔,它会看起来像这样
不太方便,对吧?但是让我向您介绍一种运行和测试 PowerShell 脚本的更好方法 - PowerShell Script Editor 或“Windows PowerShell ISE”。这个程序与 PowerShell 一起安装。从 Windows 7 的开始菜单搜索中,您可以通过输入“ise”在搜索区域找到它。或者您可以从它的文件夹手动启动它 - C:\Windows\System32\WindowsPowerShell\v1.0\PowerShell_ISE.exe。
现在我们的这个小脚本看起来是这样的
所有内容都经过了漂亮的着色,无需在单行中输入命令(并使用“;”分隔命令),您现在可以保存脚本,并立即看到它的输出!
在“Foreach”循环中运行代码
For 循环很不错,但我希望为我的小项目做些更简单的事情,我想要一个 Foreach 循环
$array = @(0,9,0,9,1,9,8,2)
foreach ($element in $array) {
$element
}
运行此代码后,输出与之前完全相同。您也可以省略 'Write-Host' 命令
接下来,我将描述一些对 PowerShell 有用的提示,但与本文的主要目标不一定相关。
查找特定文件并进行归档
您可以使用类似的命令查找驱动器 'C:\' 上所有扩展名为 '.ps1' 的文件:
$FilesList = Get-ChildItem "C:\" -recurse -include "*.ps1"
有关 Get-ChildItem 命令的更多信息,请 在此处。
然后您可以像这样列出所有发现的文件及其数据
$FilesList | Format-Table Name, Directory
上面命令的所有可用列是: Name
、Directory
、Length
、Mode
、LastWriteTime
。
现在 - 一个关于如何处理发现文件的简单示例。例如,让我们使用 7-Zip 将它们归档 并保存在驱动器 'C:\' 上:
foreach ($file in $FilesList) {
$dp = $file.Directory; $fn = $file.Name; $fp = "$dp\$fn";
cd "C:\Program Files\7-Zip"
./7z.exe a C:\PowerShell_Scripts.7z $fp
}
到目前为止,这几乎是我需要了解的关于 PowerShell 的全部内容。现在是时候开始编写主脚本了
编写主要的 PowerShell 脚本
再说一遍,我的主要目标是编写一个应该执行以下操作的脚本
创建选定项目的干净副本 > 归档清理过的项目 > 删除临时目录.
我创建了一个新的空文件 export_projects.ps1(只是一个扩展名为 .ps1
的文本文件),其中将包含以下所有命令。
在开始之前,我意识到最好将当前日期和/或时间附加到我的备份存档的名称中,所以我首先添加了这个变量
$date = Get-Date -uformat "%Y-%m-%d_%H-%M"
您可以通过使用以下键轻松地将日期/时间格式化为您需要的样子:
日期
%D // full date with slashes '/' (e.g. 03/27/12)
%Y // full year (e.g. 2012)
%y // short year (e.g. 12)
%m // month number (e.g. 03)
%h // month short name (e.g. Mar)
%B // month long name (e.g. March)
%d // day number (e.g. 27)
时间
%H // hour in 24-hour format
%I // hour in 12-hour format
%M // minute
%S // second
要了解更多关于 Get-Date
命令的键,请 阅读此文。
其次,我声明了所有必要的变量和数组
$exclude = "C:\export_exclude.txt" # full path to file with exclusions
$projects_directory = "C:\projects_directory\" # full path to source projects directory
$projects_destination = "C:\projects_backup\" # where to copy cleaned projects
$projects_archive = "C:\projects_backup_$date.7z" # where to save projects archive
# list of project folder names (inside of the 'projects_directory')
$projects = @(
"Project1",
"Project2",
"Project3"
)
然后,我添加了 foreach 循环,使用前面描述的 XCopy 命令来干净地复制 $projects 数组中的每个项目,通过将固定路径替换为我们的变量
foreach ($project in $projects) {
XCopy $projects_directory$project $projects_destination$project /EXCLUDE:$exclude /C /F /I /E /R /H /Y
}
之后,我添加了使用流行的 7-Zip 归档器归档干净项目副本的命令。我之所以选择 7-Zip,是因为它快速、免费且开源。而且由于所有现代归档器都有通过命令行使用的选项,所以我欣然利用了这一点 -
首先,我告诉 PowerShell 进入 7-Zip 程序目录
cd "C:\Program Files\7-Zip"
然后,我告诉 PowerShell 通过运行 7-Zip 命令行可执行文件 '7z.exe' 和 'a' 参数(表示'添加到存档')来创建存档,并指定存档目标($projects_archive
)和源文件夹($projects_destination
)
./7z.exe a $projects_archive $projects_destination
当然,您也可以以类似的方式使用任何主要的归档器。
您是否注意到 '7z.exe' 前面的 './' 前缀?这是因为在 PowerShell 中,要运行任何程序或由 PowerShell 执行脚本,您必须在程序/脚本名称前加上 './',这与 Linux bash shell 中的相同操作完全相似(这是一件好事!)。
最后(在创建存档之后),我使用不言自明的命令 'Remove-Item
' 删除清理过的项目副本
Remove-Item -Recurse -Force $projects_destination
这成功地完成了我几乎所有的目标!现在是时候让 Windows 7 按计划运行这个脚本了,这样我就可以放松一下,继续我的生活了。
您可以通过此链接下载最终的脚本和排除文件
现在是时候进行下一步,也是最后一步了 - 安排脚本自动运行!
如何按计划运行脚本
要在 Windows 7 中添加任务,让我们打开 Windows 任务计划程序程序。查找它的简单方法是:在开始菜单搜索中输入‘task’,然后在结果中点击‘任务计划程序’。
1) 任务计划程序打开后,点击左侧的‘任务计划程序库’以展开当前所有任务的列表。
2) 在顶部菜单中,点击‘操作’ > ‘创建任务…’,或者在所有任务列表中的空白处右键单击并选择‘创建新任务…’。
3) 输入任务的‘名称’和‘描述’(可选),我还建议选择‘不管用户是否登录都要运行’选项,这样即使在系统重启后但未登录用户帐户时,该任务也会运行
4) 接下来,选择‘触发器’选项卡,然后点击底部的‘新建…’(确保‘启用’复选框已选中),并选择一个方便的时间来运行您的脚本
5) 现在是时候添加您希望 任务计划程序执行的操作了。
这比您想象的要棘手一些,因为 任务计划程序无法直接运行 PowerShell 脚本。它只能运行一个特定的程序。而且我花了很多时间才弄清楚如何通过 任务计划程序运行 PowerShell 脚本……
诀窍在于,您可以通过从标准的 Windows 命令提示符(或‘运行…’命令)中运行 PowerShell 应用程序来运行任何 PowerShell 脚本,只需将脚本路径指定为参数即可
PowerShell c:\export_projects.ps1
在 命令提示符中它看起来是这样的
因此,您需要以类似的方式配置 任务计划程序操作。在‘创建任务’窗口中选择‘操作’选项卡,然后点击‘新建…’。
在那里,确保操作设置为‘启动程序’,‘程序/脚本’只填写一个词‘PowerShell’,并将 PowerShell 脚本的路径作为参数(在‘添加参数(可选)’字段中)指定
要测试您的新任务,请右键单击它,然后选择‘运行’。如果您刷新任务列表,您可以看到任务的‘状态’将变为‘正在运行’。要检查它是否成功,请向右滚动以找到‘上次运行结果’列。
因此,这成功地完成了所有目标,让我非常高兴,因为我再也不用(手动)进行无聊的项目备份了,我可以专注于行星统治编码。:)
本文到此结束。我真诚地希望它有所帮助,感谢您的阅读!
参考文献
- http://www.svnforum.org/threads/31535-TortoiseSVN-export-by-command-line
- http://technet.microsoft.com/en-us/library/bb491035.aspx
- http://technet.microsoft.com/en-us/library/ee176949.aspx
- http://technet.microsoft.com/en-us/library/dd347647.aspx
- http://www.PowerShellpro.com/PowerShell-tutorial-introduction/logic-using-loops/
- http://ss64.com/ps/syntax-stampme.html
- http://technet.microsoft.com/en-us/library/dd347686.aspx
历史
- 2012/4/7 - 添加了附加的 PowerShell 基本命令
- 2012/3/30 - 首次发布文章