Skip to content

Instantly share code, notes, and snippets.

@jeremybeavon
Last active August 15, 2017 05:04
Show Gist options
  • Save jeremybeavon/5514bee0b38bcd46d481681c2537ee9c to your computer and use it in GitHub Desktop.
Save jeremybeavon/5514bee0b38bcd46d481681c2537ee9c to your computer and use it in GitHub Desktop.
Powershell task runner that outputs to a service bus
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{7A85FC1A-9ED6-4E26-865B-E2063C3F4000}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>MsBuildServiceBusLogger</RootNamespace>
<AssemblyName>MsBuildServiceBusLogger</AssemblyName>
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.Build.Framework" />
<Reference Include="Microsoft.ServiceBus, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\WindowsAzure.ServiceBus.4.1.3\lib\net45\Microsoft.ServiceBus.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="System" />
</ItemGroup>
<ItemGroup>
<Compile Include="ServiceBusLogger.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Newtonsoft.Json" version="10.0.3" targetFramework="net461" />
<package id="WindowsAzure.ServiceBus" version="4.1.3" targetFramework="net461" />
</packages>
using Microsoft.Build.Framework;
using Microsoft.ServiceBus.Messaging;
using Newtonsoft.Json;
using System.IO;
public class ServiceBusLogger : ILogger
{
private QueueClient queue;
private string taskName;
public ServiceBusLogger()
{
Verbosity = LoggerVerbosity.Minimal;
}
public LoggerVerbosity Verbosity { get; set; }
public string Parameters { get; set; }
public static string Receive(QueueClient queue)
{
return queue.Receive().GetBody<string>();
}
public void Initialize(IEventSource eventSource)
{
queue = QueueClient.CreateFromConnectionString(Parameters);
eventSource.ProjectStarted += OnProjectStarted;
eventSource.MessageRaised += OnMessageRaised;
}
private void OnProjectStarted(object sender, ProjectStartedEventArgs e)
{
if (e.GlobalProperties.ContainsKey("FileToRun"))
{
taskName = Path.GetFileNameWithoutExtension(e.GlobalProperties["FileToRun"]);
}
}
private void OnMessageRaised(object sender, BuildMessageEventArgs e)
{
if (taskName != null)
{
var message = new
{
TaskName = taskName,
Message = e.Message,
IsFinalMessage = false
};
queue.Send(new BrokeredMessage(JsonConvert.SerializeObject(message)));
}
}
public void Shutdown()
{
queue.Close();
}
}
function Invoke-PowershellFileWithServiceBusLogging
{
[CmdletBinding()]
param (
[Parameter(Mandatory=$true)]
[string]
$TaskName,
[Parameter(Mandatory=$true)]
[string]
$PowershellFile,
[Parameter(Mandatory=$true)]
[securestring]
$QueueConnectionString,
[Parameter(Mandatory=$true)]
[string]
$PowershellFileParameters
)
$tempDirectory = [System.IO.Path]::GetTempPath()
$directoryPath = Join-Path $tempDirectory ([System.Guid]::NewGuid().ToString("N"))
New-Item -Type Directory $directoryPath | Out-Null
$fileToRun = Join-Path $directoryPath $TaskName
Set-Content $fileToRun "powershell -ExecutionPolicy ByPass -File `"$PowershellFile`" $PowershellFileParameters"
$plainTextQueueConnectionString = (New-Object PSCredential "N/A", $QueueConnectionString).GetNetworkCredential().Password
& C:\Windows\Microsoft.NET\Framework\v4.0.30319\msbuild.exe /nologo /verbosity:minimal `
/property:FileToRun="$fileToRun"
/logger:ServiceBusLogger,MsBuildServiceBusLogger.dll;`"$plainTextQueueConnectionString`" `
"$PSScriptRoot\ServiceBusTaskRunner.targets"
$MsBuildExitCode = $LASTEXITCODE
Remove-Item -Recurse -Force $directoryPath
$queueClient = [Microsoft.ServiceBus.Messaging.QueueClient]::CreateFromConnectionString($plainTextQueueConnectionString)
$messageToSend = @{
TaskName = $TaskName
Message = "Exit code: $MsBuildExitCode"
IsFinalMessage = $true
}
$messageJson = ConvertTo-Json $messageToSend
$queueMessage = New-Object "Microsoft.ServiceBus.Messaging.BrokeredClient" $messageJson
$queueClient.Send($queueMessage)
$queueClient.Close()
if ($MsBuildExitCode -ne 0)
{
throw "Parallel powershell scripts failed."
}
}
function Receive-ServiceBusLogging
{
[CmdletBinding()]
param (
[Parameter(Mandatory=$true)]
[string[]]
$TaskNames,
[Parameter(Mandatory=$true)]
[securestring]
$QueueConnectionString,
[Parameter(Mandatory=$false)]
[string]
$LogDirectory = ((Get-Location).Path)
)
Add-Type -Path "$PSScriptRoot\MsBuildServiceBusLogger.dll"
$unfinishedTaskNames = New-Object "System.Collections.List[string]" $TaskNames
$plainTextQueueConnectionString = (New-Object PSCredential "N/A", $QueueConnectionString).GetNetworkCredential().Password
$queueClient = [Microsoft.ServiceBus.Messaging.QueueClient]::CreateFromConnectionString($plainTextQueueConnectionString)
while ($unfinishedTaskName.Count -ne 0)
{
$messageText = [ServiceBusLogger]::Receive($queueClient)
$message = ConvertFrom-Json $messageText
$logFile = Join-Path $LogDirectory "$($message.TaskName).log"
Add-Content $logFile $message.Message
if ($message.IsFinalMessage)
{
$unfinishedTaskNames.Remove($message.TaskName) | Out-Null
}
}
$queueClient.Close()
}
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="RunTask" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
<Target Name="RunTask">
<Error Text="Property missing: FileToRun" Condition="'$(FileToRun)' == ''"/>
<Error Text="$(FileToRun) does not exist" Condition="!Exists('$(FileToRun)')" />
<Exec Command="$(FileToRun)" EchoOff="true" />
</Target>
</Project>
@jeremybeavon
Copy link
Author

jeremybeavon commented Aug 4, 2017

Powershell management commands:

New-AzureRmServiceBusQueue -ResourceGroup myResourceGroup -NamespaceName myServiceBus -QueueName myQueue -EnablePartitioning $true
New-AzureRmServiceBusQueueAuthorizationRule -ResourceGroup myResourceGroup -NamespaceName myServiceBus -QueueName myQueue -AuthorizationRuleName Sender -Rights Send
Get-AzureRmServiceBusQueueKey -ResourceGroup myResourceGroup -NamespaceName myServiceBus -QueueName myQueue -AuthorizationRuleName Sender

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment