Workflow Manager

Workflow Manager – Scripted Installation

Allrighty, I was sick and tired of NOT being able to install my Workflow Manager without the Web-platform Installer installation. Secondly I was tired of not being able to install Workflow Manager using my loved one, Powershell. So I called upon my good friend Mads Hjort Larsen and we started to work on it.
The script below will make use of offline msi files for the installation. So make sure you grab those before you run the script. They should be located in the same folder as the script before you run it.

The script

Set-Location (Split-Path -Parent -Path $MyInvocation.MyCommand.Definition)
Clear-Host

#region Variables
$SQLserver = '<SQL SERVER>' # Name of the database server.
$DBprefix = '<Database Pre-fix>' # All databases will be prefixed with this string.

$SBRunAsAccount = '<Service Bus service account>' # The account under which the service runs. This account must be a domain account.
$SBRunAsPasswordString = '<Service Bus service Account passwprd>' # Password for RunAs account (in cleartext).
$SBAdminGroup = '<Service Bus Administrator group>' # The admin group for Service Bus. (Default "BUILTIN\Administrators")
$SBCertificateAutoGenerationKey = '<Certificate passphrase>' # This passphrase is required for certificate auto generation. This parameter is mandatory if you want certificates to be auto generated.
$TcpPort = <Service Bus port> # The port that the Service Bus for Windows Server uses for TCP. (Default 9354) 
$MessageBrokerPort = <Message Broker port> 9356 # The port that the Service Bus for Windows Server uses for MessageBroker communication. (Default 9356)
$InternalPortRangeStart = <Port Range> # The start of the port range that Service Bus for Windows Server uses for internal communication purposes. (Default 9000) 

$WFRunAsAccount = '<Service Bus service account>' # The account under which the service will be running. This account must be a domain account.
$WFRunAsPasswordString = '<Service Bus service account password>' # Password for RunAs account (in cleartext).
$WFAdminGroup = '<Service Bus Administrator group>' # The set of users who are considered workflow administrators. (Default BUILTIN\Administrators)
$WFCertificateAutoGenerationKey = '<Certificate Passphrase>' # This passphrase is required for certificate auto generation. This is a mandatory parameter if you want certificates to be auto generated.
$HttpsPort = <Workflow HTTPS Port> # The port that will be used by the workflow for HTTPS communication. (Default 12290)
$HttpPort = <Workflow HTTP Port> # The port that will be used by the workflow for HTTP communication. (Default 12291)

$SBNamespace = '<Service Bus Namespace>' # Specifies the name for the new Service Bus for Windows Server service namespace.
$AddressingScheme = 'Path' # Specifies the addressing scheme used in the service namespace. The possible values for this parameter are Path (default value) and DNSRegistered. If the value DNSRegistered is specified, the -DnsEntry parameter is required.
$ManageUsers = '<Workflow Namespace Administrator01>','<Workflow Namespace Administrator02>' # Specifies user or group names that will be managers of the service namespace.

#Filelocations:
$WF  = "WindowsFabric.msi"
$SB  = "Service_Bus.msi"
$WMC = "WorkflowManagerClient_x64.msi"
$WM  = "Workflow_Manager.msi"

## Can't touch this... or anything below this line ;P

$Sleep = 90 # Sleep duration is set to 90 seconds because that what all the cool kids online are doing.

$ArgumentList = 'IACCEPTEULA=yes WEBPI=1 /QUIET /NORESTART' 
<# 
    "IACCEPTEULA=yes" is required for quiet install of Windows Fabric, 
    "WEBPI=1" is required for installation of Service Bus and Workflow Manager outside of the Web Platform Installer, 
    "/QUIET" = Quiet mode, no user interaction, 
    "/NORESTART" = Do not restart after the installation is complete.
#>

$fileNotFound = $null
#endregion

Write-Host "VERIFYING THAT FILES EXIST:"
$files = $WF,$SB,$WMC,$WM
foreach ($file in $files) {
    if (Test-Path -Path $file){
        Write-Host "✓ $file" -ForegroundColor Green
    }else{Write-Host "X $file" -ForegroundColor Red;$fileNotFound = $true}
}if ($fileNotFound -eq $true){Exit}
''
foreach ($file in $files) {
    Write-Host "Installing $file... " -NoNewline
    Start-Process $file -ArgumentList $ArgumentList -Wait
    Write-Host "Done"
}

[Environment]::SetEnvironmentVariable("PSModulePath", [Environment]::GetEnvironmentVariable("PSModulePath","Machine"))
Import-Module WorkflowManager

#region StringBuilding
# The strings are created like this to make it easier to put them on different SQL servers
function BuildString ($type, $dbName, $SQLserver) {
    New-Variable -Name $type'DBConnectionStringDataSource' -Value $SQLserver
    New-Variable -Name $type'DBConnectionStringInitialCatalog' -Value $DBprefix$dbName
    New-Variable -Name $type'DBConnectionString' -Scope Script -Value ("Data Source="+(Get-Variable -Name $type'DBConnectionStringDataSource' -ValueOnly)+";Initial Catalog="+(Get-Variable -Name $type'DBConnectionStringInitialCatalog' -ValueOnly)+";Integrated Security=True;Encrypt=False") -Force
}

# Example ConnectionString: Data Source=SQL01;Initial Catalog=Udv_service_SBManagement;Integrated Security=True;Encrypt=False
BuildString SBFarm SBManagement $SQLserver
BuildString GateWay SBGateway $SQLserver
BuildString MessageContainer SBMessageContainer $SQLserver
BuildString WFFarm WFManagement $SQLserver
BuildString Instance WFInstanceManagement $SQLserver
BuildString Resource WFResourceManagement $SQLserver
#endregion

$SBCertificateAutoGenerationKey = ConvertTo-SecureString -AsPlainText -Force -String $SBCertificateAutoGenerationKey -Verbose
New-SBFarm -SBFarmDBConnectionString $SBFarmDBConnectionString -InternalPortRangeStart $InternalPortRangeStart -TcpPort $TcpPort -MessageBrokerPort $MessageBrokerPort -RunAsAccount $SBRunAsAccount -AdminGroup $SBAdminGroup -GatewayDBConnectionString $GatewayDBConnectionString -CertificateAutoGenerationKey $SBCertificateAutoGenerationKey -MessageContainerDBConnectionString $MessageContainerDBConnectionString -Verbose
New-WFFarm -WFFarmDBConnectionString $WFFarmDBConnectionString -RunAsAccount $WFRunAsAccount -AdminGroup $WFAdminGroup -HttpsPort $HttpsPort -HttpPort $HttpPort -InstanceDBConnectionString $InstanceDBConnectionString -ResourceDBConnectionString $ResourceDBConnectionString -CertificateAutoGenerationKey $SBCertificateAutoGenerationKey -Verbose

$SBRunAsPassword = ConvertTo-SecureString -AsPlainText -Force -String $SBRunAsPasswordString -Verbose
Add-SBHost -SBFarmDBConnectionString $SBFarmDBConnectionString -RunAsPassword $SBRunAsPassword -EnableFirewallRules $true -CertificateAutoGenerationKey $SBCertificateAutoGenerationKey -Verbose

Try {
    New-SBNamespace -Name $SBNamespace -AddressingScheme $AddressingScheme -ManageUsers $ManageUsers -Verbose
    for ($i=$Sleep; $i -gt 1; $i--) {
        Write-Progress -Activity "Creating new SB Namespace" -Status "Sleeping" -SecondsRemaining $i
        Start-Sleep 1
    }
}
Catch [system.InvalidOperationException]{}

$SBClientConfiguration = Get-SBClientConfiguration -Namespaces $SBNamespace -Verbose
$WFRunAsPassword = ConvertTo-SecureString -AsPlainText -Force -String $WFRunAsPasswordString -Verbose
Add-WFHost -WFFarmDBConnectionString $WFFarmDBConnectionString -RunAsPassword $WFRunAsPassword -EnableFirewallRules $true -SBClientConfiguration $SBClientConfiguration -CertificateAutoGenerationKey (ConvertTo-SecureString $WFCertificateAutoGenerationKey -AsPlainText -Force) -Verbose

(The script is currently using a self-signed certificate.)

How to get MSI files
WebPICMD.exe /offline /products:”WindowsFabric,ServiceBus_1_1,WorkflowManager” /Path:c:\temp\

WindowsFabric.msi
WebPICMD.exe /offline /products:WindowsFabric /Path:c:\temp\

Service_Bus.msi
WebPICMD.exe /offline /Products:ServiceBus_1_1 /Path:c:\temp\

WorkflowManagerClient_x64.msi
WebPICMD.exe /offline /Products:WorkflowManager /Path:c:\temp\

Workflow_Manager.msi
WebPICMD.exe /offline /Products:WorkflowManager /Path:c:\temp\

Updated 17-June-2015: Incorporated Martin Sandersens comment into the script, removing the need for customized msi files.
Updated 07-August-2015: Updated script for fewer lines of code.

Advertisements

Workflow Manager & Service Bus – Bug

There is a bug in the following CU’s for Workflow Manager and Service Bus which potentially breaks your workflow manager. So have a look on the Workflow Manager server for an Access Denied error against some workflow manager databases. If I get time, I will dig a bit more into the issue.

Cumulative Update for Workflow Manager 1.0 (KB2799754)
Cumulative Update for Service Bus 1.0 (KB2799752)

The following thread describes a possible workaround for the issue.
http://social.msdn.microsoft.com/Forums/windowsazure/en-US/054d2a58-8847-4a6a-b1ab-05a79f49fe65/workflow-manager-cumulative-update-february-error?forum=wflmgr

SharePoint 2013 – Workflow Management – Starting a workflow using Powershell

Had a simple task of creating a Powershell script that would be able to start a SharePoint workflow. Shouldn’t be too much a problem, I mean just get the web, get the list, find the associated workflows and start the right one using Powershell. How hard can it be?
Failing really short on examples on the web I had help from great colleagues again, puzzled together the below. The below code will start a specific workflow on all items within a designated list. The below should give the foundation to work with other management type tasks for SharePoint Workflows; Start, Start, Cancel etc.
I might update with additional examples, if needed 🙂

The Code

$sourceWebURL = '<URL>'
$sourceListName = '<List Name>'
$TargetWorkflow = '<Workflow Name>'
$spSourceWeb = Get-SPWeb $sourceWebURL
$spSourceList = $spSourceWeb.Lists[$sourceListName]

#Getting a Workflow manager object to work with.
$wfm = New-object Microsoft.SharePoint.WorkflowServices.WorkflowServicesManager($spSourceweb)
#Getting the subscriptions
$sub = $wfm.GetWorkflowSubscriptionService()
#Getting the specific workflow within the list of subscriptions on the specific list. (SP2010 associated workflows basically)
$WF = $sub.EnumerateSubscriptionsByList($spSourcelist.ID) | Where-Object {$_.Name -eq "$TargetWorkflow"}
#Getting a Workflow instance in order to perform my commands.
$wfis=$wfm.GetWorkflowInstanceService()

Foreach($item in $spSourceList){
	#Creating the dictonary object I need to parse into StartWorkflow. This could be most other workflow commands.
	$object = New-Object 'system.collections.generic.dictionary[string,object]'
	$object.Add("WorkflowStart", "StartWorkflow");
	$wfis.StartWorkflowOnListItem($WF, $item.ID, $object)

References
Microsoft.SharePoint.Client.WorkflowServices namespace
http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.client.workflowservices%28v=office.15%29.aspx

Additional credit
Frej Laursen, Joachim Bach & Per Jakobsen.