Saritasa.AppDeploy.psm1
Enum AppDeployOverwriteMode { Backup = 0 Overwrite = 1 } <# .SYNOPSIS Deploys the folder contents to a remote computer. .PARAMETER OverwriteMode The logic which should be used during copy If set to Backup, the destination folder first will be backed up and then the files will be transferred If set to Overwrite, the destination folder contents will be overwritten with the BinPath fiels .EXAMPLE PS C:\> $s = New-PSSession PS C:\> Invoke-DesktopProjectDeployment $s -BinPath .\Project\MyProject\bin\Release -DestinationPath C:\inetpub\www\myproject -OverwriteMode [AppDeployOverwriteMode]::Overwrite In this example, the contents of MyProject\bin\Release folder will be placed on a remote server under myproject folder. If this folder already exists, the files in it will be replaced with newest version. Files which do exist in destination folder, but not exist in source folder, will not be deleted. #> function Invoke-DesktopProjectDeployment { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [System.Management.Automation.Runspaces.PSSession] $Session, # Folder path which contents will be copied over [Parameter(Mandatory = $true)] [string] $BinPath, # Folder path where the files should be placed [Parameter(Mandatory = $true)] [string] $DestinationPath, [ScriptBlock] $BeforeDeploy, [ScriptBlock] $AfterDeploy, [AppDeployOverwriteMode] $OverwriteMode = [AppDeployOverwriteMode]::Backup ) Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState Write-Information 'Creating ZIP archive...' $archiveName = "$([guid]::NewGuid()).zip" Compress-Archive "$BinPath\*" $archiveName -Force Write-Information 'Done.' $remoteTempDir = Get-RemoteTempPath $Session $remoteArchive = "$remoteTempDir\$archiveName" Write-Information "Copying $archiveName to remote server..." Copy-Item ".\$archiveName" $remoteTempDir -ToSession $Session Write-Information 'Done.' if ($BeforeDeploy) { Invoke-Command -Session $Session -ScriptBlock $BeforeDeploy } if ($OverwriteMode -eq [AppDeployOverwriteMode]::Backup) { Invoke-Command -Session $Session -ScriptBlock ` { $backupPath = "$($using:DestinationPath)Old" if (Test-Path $backupPath) { Remove-Item $backupPath -Recurse } if (Test-Path $using:DestinationPath) { $retries = 0 while ($true) { try { Rename-Item $using:DestinationPath $backupPath -EA Stop break } catch { $retries++ if ($retries -eq 10) { throw } else { Write-Warning 'Warning: Rename operation failed. Retrying...' Start-Sleep $retries } } } } # Directory should exist, if PSCX is used. New-Item -ItemType directory $using:DestinationPath Expand-Archive $using:remoteArchive $using:DestinationPath } } # OverwriteMode - Backup elseif ($OverwriteMode -eq [AppDeployOverwriteMode]::Overwrite) { Invoke-Command -Session $session -ScriptBlock ` { Expand-Archive $using:remoteArchive $using:DestinationPath -Force } } else { throw 'Unknown OverwriteMode.' } Invoke-Command -Session $Session -ScriptBlock ` { $appName = (Get-Item $using:DestinationPath).BaseName Write-Information "$appName app is updated." Remove-Item $using:remoteTempDir -Recurse -ErrorAction Stop } if ($AfterDeploy) { Invoke-Command -Session $Session -ScriptBlock $AfterDeploy } } <# .SYNOPSIS Deploys a service to a remote computer. .DESCRIPTION Deploys a service to a remote computer by copying over the provided files and restarting the service. If service does not exist, it will be automatically created. .EXAMPLE PS C:\> $s = New-PSSession PS C:\> Invoke-ServiceProjectDeployment $s -ServiceName MyWebSite -ProjectName Web -BinPath .\Project\MyWebSite\bin\Release -DestinationPath C:\inetpub\www\MyWebSite .NOTES User should have 'Log on as a service right (https://technet.microsoft.com/en-us/library/cc739424(v=ws.10).aspx). Local user name example: .\administrator Service user accounts: LocalService, NetworkService, LocalSystem https://msdn.microsoft.com/en-us/library/windows/desktop/ms686005(v=vs.85).aspx Credentials for built-in service user accounts: New-Object System.Management.Automation.PSCredential('NT AUTHORITY\LocalService', (New-Object System.Security.SecureString)) New-Object System.Management.Automation.PSCredential('NT AUTHORITY\NetworkService', (New-Object System.Security.SecureString)) New-Object System.Management.Automation.PSCredential('.\LocalSystem', (New-Object System.Security.SecureString)) #> function Invoke-ServiceProjectDeployment { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [System.Management.Automation.Runspaces.PSSession] $Session, # Name of deploying service on a remote computer [Parameter(Mandatory = $true)] [string] $ServiceName, # The name of executable which should be used to run the service [Parameter(Mandatory = $true)] [string] $ProjectName, # Folder path containing files which should be deployed [Parameter(Mandatory = $true)] [string] $BinPath, # Destination path on remote computer [Parameter(Mandatory = $true)] [string] $DestinationPath, # Credentials to be used to create a new service if it does not exist on remote computer [System.Management.Automation.Credential()] [System.Management.Automation.PSCredential] $ServiceCredential ) Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState Invoke-DesktopProjectDeployment -Session $Session -DestinationPath $DestinationPath -BinPath $BinPath ` -BeforeDeploy ` { $service = Get-Service -Name $using:ServiceName -ErrorAction SilentlyContinue if ($service) { Stop-Service $service Write-Information "Service $using:ServiceName is stopped." } else { Write-Information "Service $using:ServiceName is not installed." } } ` -AfterDeploy ` { $service = Get-Service -Name $using:ServiceName -ErrorAction SilentlyContinue if ($service) { Start-Service $service -ErrorAction Stop Write-Information "Service $using:ServiceName is started." } else { Write-Information "Creating $using:ServiceName service..." $credential = $using:ServiceCredential if ($credential.UserName -notlike '*\*') # Not a domain user. { $credential = New-Object System.Management.Automation.PSCredential(".\$($credential.UserName)", $credential.Password) } $service = New-Service -Name $using:ServiceName -ErrorAction Stop -Credential $credential ` -BinaryPathName "$using:DestinationPath\$using:ProjectName.exe" Write-Information "Done." Start-Service $using:ServiceName -ErrorAction Stop Write-Information "Service $using:ServiceName is started." } } } |