我正在使用PowerShell编写部署脚本。使用Copy-Item
命令在运行之间不会提供相同的结果,即使使用相同的数据也是如此。 (它似乎不是幂等的)
请参阅下面的结果,了解我的意思。我意识到我可以在复制“新”版本之前删除C:\products
中的文件,但我更好奇这是否是Powershell中的预期行为。 (而且我假设它是)
我宁愿学习使用Copy-Item
的'正确'方法,而不是在我缺乏知识的情况下进行黑客攻击。
我尝试使用target\*
路径代替target
,但是我将lib
文件夹分解为showcase
的根目录,我甚至没想到-Recurse
标志。
C:\products
- showcase
- showcase.jar
- logback.jar
- foo.jar
- junit.jar
- etc, etc
我也对文档here(特别是示例7,10和11)感到困惑,因为7使用-Recurse
标志而11则不使用C:\products
- backup
标志。同时示例10说:
如果脚本文件夹包含子文件夹中的文件,那么这些子文件夹将被复制,文件树完好无损。
但是从不指定递归标记。
C:\products
- showcase
- showcase.jar
- lib
- <dependencies for showcase.jar>
- backup
<empty>
# Expected, as there wasn't a prior deployment yet.
C:\products
- showcase
- showcase.jar
- lib
- <dependencies for showcase.jar>
- target
- showcase.jar
- lib
- <dependencies for inner showcase.jar>
- backup
- showcase
- showcase.jar
- lib
- <dependencies for "old" showcase.jar>
# Expected, the old version was backed up
./deploy.ps1 -hostname foobar (it's a remote server)
param( [String]$hostname, [switch]$debug )
$folder_to_copy = "target"
$init_file = "./init.ps1"
function Backup-Binary ( [String]$source, [String]$name, [String]$dest ) {
$FullyQualifiedSourcePath = "$source\$name"
if (Test-Path $FullyQualifiedSourcePath) {
Write-Host "Backing up $FullyQualifiedSourcePath to the destination $dest"
Copy-Item -Recurse -Force -Path $FullyQualifiedSourcePath -Destination $dest -ErrorAction Stop
} else {
Write-Output "Directory $FullyQualifiedSourcePath didn't exist. May be an initial deployment. Continuing with deployment."
}
}
function Verify-Env ([String]$env_var) {
$check = [Environment]::GetEnvironmentVariable($env_var)
if ($check -eq $null) {
Write-Error "$env_var environment variable doesn't exist. Exiting program."
exit 1
}
}
function Deploy-Local {
# Checks that the given string exists as an Environment variable
Verify-Env "DEPLOY_DRIVE"
Verify-Env "CI_PROJECT_NAME"
# C:\products or D:\products *most* of the time.
$root = "$env:DEPLOY_DRIVE\products"
$destination = "$root\$env:CI_PROJECT_NAME"
$backup_loc = "$root\backup"
# Removes prior binaries
Backup-Binary -source $root -name $env:CI_PROJECT_NAME -dest $backup_loc
# Copy binary locally since we're deploying to local machine.
Copy-Item -Recurse -Force -Path $folder_to_copy -Destination $destination -ErrorAction Stop
# Run the init script the developer has written
Invoke-Expression "$init_file" -ErrorAction Stop
}
function Deploy-Remote {
$session = New-PSSession -ComputerName $hostname
$DEPLOY_DRIVE = Invoke-Command -Session $session -ScriptBlock {
[Environment]::GetEnvironmentVariable("DEPLOY_DRIVE")
} -ErrorAction Stop
$root = "$DEPLOY_DRIVE\products"
$destination = "$root\$env:CI_PROJECT_NAME"
$backup_loc = "$root\backup"
Write-Host "$root = root $destination = destination $backup_loc = backup_location"
Invoke-Command -Session $session -ScriptBlock ${function:Backup-Binary} -ArgumentList $root,$env:CI_PROJECT_NAME,$backup_loc -ErrorAction Stop
Copy-Item -Recurse -Force -ToSession $session -Path $folder_to_copy -Destination $destination -ErrorAction Stop
Invoke-Command -Session $session -FilePath $init_file -ErrorAction Stop
Remove-PSSession $session -ErrorAction Stop
}
if ( $hostname.ToLower() -eq $env:COMPUTERNAME.ToLower() ) {
Deploy-Local
} else {
Deploy-Remote
}
Sub SapConfirm()
Application.ScreenUpdating = False
'Sap automated confirmation
Dim answer As Integer
answer = MsgBox("You are about to confirm " & ActiveSheet.Range("B1") & " tray(s) of " & ActiveSheet.Range("A2").Value & vbNewLine & " SAP No. : " & ActiveSheet.Range("A1"), vbYesNo + vbQuestion, "Canceled")
If answer = vbYes Then
On Error GoTo safe_exit
session.findById("wnd[0]/tbar[0]/okcd").Text = "z490"
session.findById("wnd[0]/tbar[0]/btn[0]").press
session.findById("wnd[0]/usr/ctxtMATNR-LOW").Text = ActiveSheet.Range("A1")
session.findById("wnd[0]/usr/ctxtMATNR-LOW").SetFocus
session.findById("wnd[0]/usr/ctxtMATNR-LOW").caretPosition = 6
session.findById("wnd[0]/tbar[1]/btn[8]").press
session.findById("wnd[1]").sendVKey 4
session.findById("wnd[2]/usr/lbl[1,8]").SetFocus
session.findById("wnd[2]/usr/lbl[1,8]").caretPosition = 4
session.findById("wnd[2]").sendVKey 2
session.findById("wnd[1]/tbar[0]/btn[0]").press
session.findById("wnd[0]/tbar[1]/btn[5]").press
session.findById("wnd[0]/usr/chk[1,3]").Selected = True
session.findById("wnd[0]/tbar[1]/btn[5]").press
session.findById("wnd[1]/usr/txtV_CONFIRMATION_QTY").Text = ActiveSheet.Range("B1")
session.findById("wnd[1]").sendVKey 5
session.findById("wnd[0]/tbar[0]/btn[15]").press
session.findById("wnd[0]/tbar[0]/btn[15]").press
'Here is where I would like the comment adding to take place
Else
MsgBox ("Please login to SAP to enable confirmation process")
Application.ScreenUpdating = True
safe_exit:
MsgBox ("Please Login to SAP")
Application.ScreenUpdating = True
End If
End Sub
答案 0 :(得分:0)
@huffstler:
是的,但这与#2934的问题相同,只是在更大的命令的上下文中:
- 当子目录。 a正在复制,$ b尚未存在,因此正在将内容直接复制到$ b(上述行为(a))。
- 按时间分区。 b被复制,$ b已经存在,并且当不一致的情况发生时:b&#39; s内容被复制到$ b / b(上面的行为(b))。
因此,如果再次运行该命令,则会获得所需的行为。
鉴于当前行为,您可以按如下方式解决问题:
Get-ChildItem -Path $a | ForEach-Object { New-Item -Force -Type Directory $b } { Copy-Item -Recurse -Path $_.FullName -Destination $b }
但更大的问题是这种不一致是否应该解决行为(a)或行为(b)。
您明确期望(a),但其他人可能会有不同的期望,基于xcopy。
坦率地说,我很困惑地发现与Unix世界中的Copy-Item -Recurse(cp -R)相同的不一致。
目前获得可预测行为的唯一方法是:
确保目标目录。已存在。
然后,取决于您是否需要行为(a)或(b):
获取行为(a):明确定位源目录的内容:
Copy-Item -Recurse -Force $a/* $b
请注意需要-Force,这是确保隐藏项目也被复制所必需的。
在Unix上使用cp,你可以更简单地只是
$a/.
,但这在PowerShell中不起作用。获取行为(b):无需采取进一步行动。