Skip to content

Instantly share code, notes, and snippets.

@sayedihashimi
Last active August 29, 2015 14:07
Show Gist options
  • Save sayedihashimi/70a23180243c46fdab64 to your computer and use it in GitHub Desktop.
Save sayedihashimi/70a23180243c46fdab64 to your computer and use it in GitHub Desktop.
publish-sample-script.ps1
[cmdletbinding(SupportsShouldProcess=$true)]
param($PublishProperties, $OutputPath)
function Ensure-PublishModuleLoaded{
[cmdletbinding()]
param($versionToInstall = '0.0.3-beta',
$installScriptUrl = 'https://raw.githubusercontent.com/sayedihashimi/publish-module/master/GetPublishModule.ps1',
$toolsDir = ("$env:LOCALAPPDATA\LigerShark\tools\"),
$installScriptPath = (Join-Path $toolsDir 'GetPublishModule.ps1'))
process{
if(!(Test-Path $installScriptPath)){
$installDir = [System.IO.Path]::GetDirectoryName($installScriptPath)
if(!(Test-Path $installDir)){
New-Item -Path $installDir -ItemType Directory -WhatIf:$false | Out-Null
}
'Downloading from [{0}] to [{1}]' -f $installScriptUrl, $installScriptPath| Write-Verbose
(new-object Net.WebClient).DownloadFile($installScriptUrl,$installScriptPath) | Out-Null
}
&($installScriptPath)
}
}
$whatifpassed = !($PSCmdlet.ShouldProcess($env:COMPUTERNAME,"publish"))
'loading publish-module' | Write-Output
Ensure-PublishModuleLoaded
'Calling AspNet-Publish' | Write-Output
# call AspNet-Publish to perform the publish operation
AspNet-Publish -publishProperties $PublishProperties -OutputPath $OutputPath -Verbose -WhatIf:$whatifpassed
[cmdletbinding()]
param($PublishProperties,$OutputPath)
# TODO: Can we add an MSBuild property to pass -Verbose, that would enable
# flowing messages from Write-Verbose. The idea is to let users set that
# in the .pubxml file.
# TODO: In this script there is a call to Get-MSDeploy. It will look at an env var
# named MSDeployPath. I was thinking that VS can set this env var so that we
# ensure the correct version of MSDeploy is picked up. Should we pass this
# in via $PublishProerties instead?
# TODO: How can we pass in the UserAgent string? We should have a different value
# for script execution versus from VS. Perhaps in $PublishProperties or Env Var?
# TODO: Can we pass in all properties listed in .pubxml?
# TODO: We are currently passing in positional parameters, I wonder if we should switch
# to using named parameters (AddParameter(string,object)) instead. With this option
# users don't have to be worried about putting them in the correct position.
# TODO: I'm thinking that we can have two models for publishing with .ps1.
# 1. VS/MSBuild call KPM pack and then call .ps1. The idea is that the user will take
# the output and then publish to the web server
# 2. User want's to completly customize publish and VS/MSBuild calling kpm pack is
# not needed. Instead they just need the path to the source folder.
# I'm thinking we can add a new MSBuild property in .pubxml EnableCallKpmPackOnPublish
# which is set to true by default in our .targets file. If the user adds that to .pubmxl
# it will not call kpm pack.
# Also we should pass the path to the source folder in $PublishProperties
#
function Get-MSDeploy {
[cmdletbinding()]
param()
process{
$msdInstallLoc = $env:MSDeployPath
if(!($msdInstallLoc)) {
# TODO: Get this from HKLM SOFTWARE\Microsoft\IIS Extensions\MSDeploy See MSDeploy VS task for implementation
$progFilesFolder = (Get-ChildItem env:"ProgramFiles").Value
$msdLocToCheck = @()
$msdLocToCheck += ("{0}\IIS\Microsoft Web Deploy V3\msdeploy.exe" -f $progFilesFolder)
$msdLocToCheck += ("{0}\IIS\Microsoft Web Deploy V2\msdeploy.exe" -f $progFilesFolder)
$msdLocToCheck += ("{0}\IIS\Microsoft Web Deploy\msdeploy.exe" -f $progFilesFolder)
foreach($locToCheck in $msdLocToCheck) {
"Looking for msdeploy.exe at [{0}]" -f $locToCheck | Write-Verbose | Out-Null
if(Test-Path $locToCheck) {
$msdInstallLoc = $locToCheck
break;
}
}
}
if(!$msdInstallLoc){
throw "Unable to find msdeploy.exe, please install it and try again"
}
"Found msdeploy.exe at [{0}]" -f $msdInstallLoc | Write-Verbose | Out-Null
return $msdInstallLoc
}
}
function Get-MSDeployFullUrlFor{
[cmdletbinding()]
param($msdeployServiceUrl)
process{
# Convert sayedkdemo.scm.azurewebsites.net:443 to https://sayedkdemo.scm.azurewebsites.net/msdeploy.axd
# TODO: This needs to be improved, it only works with Azure Websites. We have code for this.
'https://{0}/msdeploy.axd' -f $msdeployServiceUrl.TrimEnd(':443')
}
}
######################################################################
# Begin script
######################################################################
if($PublishProperties){
# TODO: How can we get the password? Any security reason why we cannot pass it in? It's all in memory.
$publishPwd = $env:PublishPassword
if(!$publishPwd){
throw 'Publish password is not found please set $env:PublishPassword'
}
<#
"C:\Program Files (x86)\IIS\Microsoft Web Deploy V3\msdeploy.exe"
-source:IisApp='C:\Users\vramak\AppData\Local\Temp\AspNetPublish\WebApplication184-93\wwwroot'
-dest:IisApp='vramak4',ComputerName='https://vramak4.scm.azurewebsites.net/msdeploy.axd',UserName='$vramak4',Password='<PWD>',IncludeAcls='False',AuthType='Basic'
-verb:sync
-enableRule:DoNotDeleteRule
-enableLink:contentLibExtension
-retryAttempts=2
-userAgent="VS14.0:PublishDialog:WTE14.0.51027.0"
#>
$webrootOutputFolder = (get-item (Join-Path $OutputPath 'wwwroot')).FullName
$publishArgs = @()
$publishArgs += ('-source:IisApp=''{0}''' -f "$webrootOutputFolder")
$publishArgs += ('-dest:IisApp=''{0}'',ComputerName=''{1}'',UserName=''{2}'',Password=''{3}'',IncludeAcls=''False'',AuthType=''Basic''' -f
$PublishProperties['DeployIisAppPath'],
(Get-MSDeployFullUrlFor -msdeployServiceUrl $PublishProperties['MSDeployServiceURL']),
$PublishProperties['UserName'],
$publishPwd)
$publishArgs += '-verb:sync'
# TODO: Should we pass this property in?
$publishArgs += '-enableRule:DoNotDeleteRule'
$publishArgs += '-enableLink:contentLibExtension'
$publishArgs += '-retryAttempts=2'
'Calling msdeploy with the call {0}' -f (($publishArgs -join ' ').Replace($publishPwd,'{PASSWORD}')) | Write-Verbose
& (Get-MSDeploy) $publishArgs
}
else{
throw 'PublishProperties is empty, cannot publish'
}
[cmdletbinding()]
param($publishFolder, $deploySettings, $logger, $vscontext)
# $publishFolder
# publishFolder points to the folder where the outputs of kpm pack are located
# When publishing from VS this value will be passed in as a full path
# The default value should be looking for a folder relative to this .ps1 file
# $deploymentSettings
# deploymentSettings is a hashtable containing key/value pairs
# for deployment info.
# When publishing from VS the values from the publish profile will be passed in via this variable
# When this file is created we will take the values from publish profile and use them as defaults
# if this parameter is not passed in
# $logger
# Logger is an object that is passed in by the caller. It has the following methods that can be called.
# - LogMessage()
# - LogWarning()
# - LogError()
# VS will pass in this object to facilite realtime logging. For command line scenarios this will be null
# $vscontext
# This is an object that will be passed in by VS. It will be used for getting preview results and maybe for
# other info as well.
###
# Declare functions here
###
# Log functions below are wrappers that will call $logger if it is not null
function LogMessage{
[cmdletbinding()]
param($message)
process{
$message | Write-Output
if($logger){
$logger.LogMessage($message)
}
}
}
function LogError{
[cmdletbinding()]
param($message)
process{
$message | Write-Error
if($logger){
$logger.LogError($message)
}
}
}
function LogWarning{
[cmdletbinding()]
param($message)
process{
$message | Write-Error
if($logger){
$logger.LogWarning($message)
}
}
}
function GetPublishPassword{
[cmdletbinding()]
param()
process{
# check to see if there is a .pubxml.user file with
# the encrypted password. If so then decrypt that file
$passwordFromUserFile = '<get-password-from-.pubxml.user>'
return $passwordFromUserFile
}
}
function ValidatePublishSettings{
[cmdletbinding()]
param()
process{
# here we can check to ensure that $publishFolder is on disk and settings are passed in
# if there is any issue throw an exception here
# users can customize this method with their own validation
LogMessage('validating publish settings')
}
}
function PublishFromFolder{
[cmdletbinding()]
param($publishFolder, $deploySettings)
process{
LogMessage('starting publish from folder []' -f $publishFolder)
# here is where we make the call to MSDeploy to publish from the kpm pack folder
}
}
###
# Begin script
###
# these values are placed here when the script is created. No need for us to update this file
# because VS will always pass these values in.
# The idea is that the values in this are specific to this script
if(!$deploySettings){
$deploySettings = @{}
$deploySettings.MSdeployServiceUrl = 'sayeddemo02.scm.azurewebsites.net:443'
$deploySettings.DeployIisAppPath = 'sayeddemo02'
$deploySettings.SkipExtraFilesOnServer = $true
$deploySettings.MSDeployPublishMethod = 'WMSVC'
$deploySettings.Username ='$sayeddemo02'
# TODO: We should pass MSDeploy parameters here as well
# TODO: We should probably pass MSDeploy skip rules here as well
}
# if the password is not passed in try and read it from the .pubxml.user file. This will make it
# easy for users to use this file from the local box.
if(!($deploySettings.Password)){
$deploySettings.Password = (GetPublishPassword)
}
ValidatePublishSettings
PublishFromFolder -publishFolder $publishFolder -deploySettings $deploySettings
[cmdletbinding()]
param($PublishProperties,$OutputPath)
# TODO: Can we add an MSBuild property to pass -Verbose, that would enable
# flowing messages from Write-Verbose. The idea is to let users set that
# in the .pubxml file.
# TODO: In this script there is a call to Get-MSDeploy. It will look at an env var
# named MSDeployPath. I was thinking that VS can set this env var so that we
# ensure the correct version of MSDeploy is picked up. Should we pass this
# in via $PublishProerties instead?
# TODO: How can we pass in the UserAgent string? We should have a different value
# for script execution versus from VS. Perhaps in $PublishProperties or Env Var?
function Get-MSDeploy {
[cmdletbinding()]
param()
process{
$msdInstallLoc = $env:MSDeployPath
if(!($msdInstallLoc)) {
# TODO: Get this from HKLM SOFTWARE\Microsoft\IIS Extensions\MSDeploy See MSDeploy VS task for implementation
$progFilesFolder = (Get-ChildItem env:"ProgramFiles").Value
$msdLocToCheck = @()
$msdLocToCheck += ("{0}\IIS\Microsoft Web Deploy V3\msdeploy.exe" -f $progFilesFolder)
$msdLocToCheck += ("{0}\IIS\Microsoft Web Deploy V2\msdeploy.exe" -f $progFilesFolder)
$msdLocToCheck += ("{0}\IIS\Microsoft Web Deploy\msdeploy.exe" -f $progFilesFolder)
foreach($locToCheck in $msdLocToCheck) {
"Looking for msdeploy.exe at [{0}]" -f $locToCheck | Write-Verbose | Out-Null
if(Test-Path $locToCheck) {
$msdInstallLoc = $locToCheck
break;
}
}
}
if(!$msdInstallLoc){
throw "Unable to find msdeploy.exe, please install it and try again"
}
"Found msdeploy.exe at [{0}]" -f $msdInstallLoc | Write-Verbose | Out-Null
return $msdInstallLoc
}
}
function Get-MSDeployFullUrlFor{
[cmdletbinding()]
param($msdeployServiceUrl)
process{
# Convert sayedkdemo.scm.azurewebsites.net:443 to https://sayedkdemo.scm.azurewebsites.net/msdeploy.axd
'https://{0}/msdeploy.axd' -f $msdeployServiceUrl.TrimEnd(':443')
# TODO: This needs to be improved, it only works with Azure Websites. We have code for this.
}
}
function OptimizeImages{
[cmdletbinding()]
param(
$folder,
$force = $false,
$customTemp = "$env:LocalAppData\CustomPublish\",
$imgOptUrl = 'https://raw.githubusercontent.com/ligershark/AzureJobs/master/ImageCompressor.Job/optimize-images.ps1'
)
process{
if(!(Test-Path $customTemp)){New-Item $customTemp -ItemType Directory}
$imgOptPath = (Join-Path $customTemp 'optimize-images.ps1')
if(!(Test-Path $imgOptPath)){
# download the file
'Downloading optimize-images.ps1' | Write-Verbose
(New-Object System.Net.WebClient).DownloadFile($imgOptUrl, $imgOptPath)
}
&$imgOptPath $folder $force
}
}
$customTemp = "$env:LocalAppData\CustomPublish\"
$imgOptPath = Join-Path $customTemp 'optimize-images.ps1'
$imgOptUrl = 'https://raw.githubusercontent.com/ligershark/AzureJobs/master/ImageCompressor.Job/optimize-images.ps1'
######################################################################
# Begin script
######################################################################
if($PublishProperties){
# TODO: How can we get the password? Any security reason why we cannot pass it in? It's all in memory.
$publishPwd = $env:PublishPassword
if(!$publishPwd){
throw 'Publish password is not found please set $env:PublishPassword'
}
<#
"C:\Program Files (x86)\IIS\Microsoft Web Deploy V3\msdeploy.exe"
-source:IisApp='C:\Users\vramak\AppData\Local\Temp\AspNetPublish\WebApplication184-93\wwwroot'
-dest:IisApp='vramak4',ComputerName='https://vramak4.scm.azurewebsites.net/msdeploy.axd',UserName='$vramak4',Password='<PWD>',IncludeAcls='False',AuthType='Basic'
-verb:sync
-enableRule:DoNotDeleteRule
-enableLink:contentLibExtension
-retryAttempts=2
-userAgent="VS14.0:PublishDialog:WTE14.0.51027.0"
#>
$webrootOutputFolder = (get-item (Join-Path $OutputPath 'wwwroot')).FullName
OptimizeImages -folder $webrootOutputFolder
$publishArgs = @()
$publishArgs += ('-source:IisApp=''{0}''' -f "$webrootOutputFolder")
$publishArgs += ('-dest:IisApp=''{0}'',ComputerName=''{1}'',UserName=''{2}'',Password=''{3}'',IncludeAcls=''False'',AuthType=''Basic''' -f
$PublishProperties['DeployIisAppPath'],
(Get-MSDeployFullUrlFor -msdeployServiceUrl $PublishProperties['MSDeployServiceURL']),
$PublishProperties['UserName'],
$publishPwd)
$publishArgs += '-verb:sync'
# TODO: Should we pass this property in?
$publishArgs += '-enableRule:DoNotDeleteRule'
$publishArgs += '-enableLink:contentLibExtension'
$publishArgs += '-retryAttempts=2'
'Calling msdeploy with the call {0}' -f (($publishArgs -join ' ').Replace($publishPwd,'{PASSWORD}')) | Write-Verbose
& (Get-MSDeploy) $publishArgs
}
else{
throw 'PublishProperties is empty, cannot publish'
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment