Update TFS Build Status via Powershell - powershell

I've a TFS Build Definition setup where, I execute a powershell script for security hardening, applying final patches etc.
Sometimes this powershell script can fail and I would like to change the status of build to be un-successfull or fail. Is there a way to change this TFS Build status via a powershell?

Try this:
$script:TFServerName = $ServerName
$script:TFServer = [Microsoft.TeamFoundation.Client.TeamFoundationServerFactory]::GetServer($ServerName)
$script:TFBuildServer = $TFServer.GetService([Microsoft.TeamFoundation.Build.Client.IBuildServer])
$spec = $TFBuildServer.CreateBuildDetailSpec($TeamProject, $DefinitionName)
$spec.Status = 'Failed'
Make sure you've Add-Type the right versions of the TFS assemblies. I'm assuming here that since the properties support setters, they communicate back to the server to affect the change. But I'm not 100% sure of that.

Here's what I pieced together from MSDN:
[Reflection.Assembly]::LoadWithPartialName("Microsoft.TeamFoundation.Build.Client")
[Reflection.Assembly]::LoadWithPartialName("Microsoft.TeamFoundation.Client")
$tfsServerAddress = "http://{tfs hostname}:{port}/{CollectionName}"
$build = "{build definition name}_{build date}.{build count for the day}"
#update build status
$tfsProject = [Microsoft.TeamFoundation.Client.TfsTeamProjectCollectionFactory]::GetTeamProjectCollection($tfsServerAddress)
$tfsBuildServer = $tfsProject.GetService([Microsoft.TeamFoundation.Build.Client.IBuildServer])
$spec = $tfsBuildServer.CreateBuildDetailSpec($teamProject)
$spec.BuildNumber = $build
$builds = $tfsBuildServer.QueryBuilds($spec).Builds
if ($builds[0].TestStatus -eq 'Succeeded'){
echo "updating test status:" $builds[0].TestStatus "to $testOutcome"
$builds[0].TestStatus = $testOutcome
}
if ($builds[0].Status -eq 'Succeeded'){
echo "updating build status:" $builds[0].Status "to $testOutcome"
$builds[0].Status = $testOutcome
}
$tfsBuildServer.SaveBuilds($builds)
Keep in mind that you need a special permission to update build status

Related

Auto creation of Service without DefaultServices on developer machines

At the recent Service Fabric Community Q&A 24th Edition there was a lot of discussion around using the DefaultService construct in the ApplicationManifest.xml and it's drawbacks. Microsoft suggested omitting this from an ApplicationManifest entirely and instead modifying the Deploy-FabricApplication.ps1 to construct a default implementation of an application so developers still have a decent F5 experience.
So I have modified the Deploy-FabricApplication.ps1 to the following (this excerpt is the bottom of the script):
if ($IsUpgrade)
{
$Action = "RegisterAndUpgrade"
if ($DeployOnly)
{
$Action = "Register"
}
$UpgradeParameters = $publishProfile.UpgradeDeployment.Parameters
if ($OverrideUpgradeBehavior -eq 'ForceUpgrade')
{
# Warning: Do not alter these upgrade parameters. It will create an inconsistency with Visual Studio's behavior.
$UpgradeParameters = #{ UnmonitoredAuto = $true; Force = $true }
}
$PublishParameters['Action'] = $Action
$PublishParameters['UpgradeParameters'] = $UpgradeParameters
$PublishParameters['UnregisterUnusedVersions'] = $UnregisterUnusedApplicationVersionsAfterUpgrade
Publish-UpgradedServiceFabricApplication #PublishParameters
}
else
{
$Action = "RegisterAndCreate"
if ($DeployOnly)
{
$Action = "Register"
}
$PublishParameters['Action'] = $Action
$PublishParameters['OverwriteBehavior'] = $OverwriteBehavior
$PublishParameters['SkipPackageValidation'] = $SkipPackageValidation
Publish-NewServiceFabricApplication #PublishParameters
#Get-ServiceFabricApplication
New-ServiceFabricService -Stateless -ApplicationName "fabric:/Acme.Hierarchy" -ServiceTypeName "Acme.Hierarchy.HierarchyServiceType" -ServiceName "fabric:/Acme.Hierarchy/Acme.Hierarchy.HierarchyService"-InstanceCount 1 -PartitionSchemeSingleton
}
The above fails with the error
FabricElementNotFoundException
However, if you uncomment the line #Get-ServiceFabricApplication you will see that it does in fact return an application of
ApplicationName : fabric:/Acme.Hierarchy
ApplicationTypeName : Acme.HierarchyType
ApplicationTypeVersion : 1.0.0
ApplicationParameters : { "_WFDebugParams_" = "[{"CodePackageName":"Code","Cod
ePackageLinkFolder":null,"ConfigPackageName":null,"Con
figPackageLinkFolder":null,"DataPackageName":null,"Dat
aPackageLinkFolder":null,"LockFile":null,"WorkingFolde
r":null,"ServiceManifestName":"Quantium.RetailToolkit.
Fabric.Hierarchy.HierarchyServicePkg","EntryPointType"
:"Main","DebugExePath":"C:\\Program Files
(x86)\\Microsoft Visual Studio\\2017\\Professional\\Co
mmon7\\Packages\\Debugger\\VsDebugLaunchNotify.exe","D
ebugArguments":"
{6286e1ef-907b-4371-961c-d833ab9509dd} -p [ProcessId]
-tid [ThreadId]","DebugParametersFile":null}]";
"Acme.Hierarchy.HierarchyServ
ice_InstanceCount" = "1" }
Create application succeeded.
and running the command that fails after the publish script has finished works perfectly.
Does anyone have a solution as to how I can get a good developer experience by not using DefaultServices and instead using Powershell scripts?
Thanks in advance
I have updated the answer to add more details why the default services should not be used (In production only).
On service fabric, you have two options to create your services:
The Declarative way, done via Default Services feature where you describe services that should run as part of your application using the ApplicationManifest.
and the Dynamic(Imperative) way using powershell commands to create these services once the application is deployed.
The declarative way bring you the convenience of defining the expected structure of your application, so that Service Fabric does the job of creating and starting instances of your services according to the declaration in the ApplicationManifest. The convenience it gives you is very useful for development purposes, imagine if every time you had to debug an application, it had to: Build > Package > Deployed to Service Fabric > You had to manually start the many services that define your application. This would be too inconvenient, so that is why default service become handy.
Another scenario is when your application definition immutable, that means, the same number of services and instances will stay the same without variation throughout the time it is deployed in production.
But we know this is high unlikely that these definitions will keep the same throughout the years or even hours in a day, because the idea of microservices is that they should be scalable and flexible, so that we can tweak the configuration of individual services independent of each other.
By using default services, would be too complex for the orchestration logic identify what changes has been made on your services compared to the default specified in the original deployment, and in cases of conflict, which configuration should have priority, for example:
The deployed default services define a service with 5 instances, after it is deployed you execute an powershell script to update to 10 instances, then a new application upgrade comes in with the default services having 5 instances or a new value of 8, what should happen? which one is the correct?
You add an extra named services (service of same type with other name) to an existing deployment that is not defined in the default services, what happens when the new deployment comes in and say that this service should not be expected? Delete it? And the data? How this service should be removed from production? If I removed by mistake during development?
A new version deletes an existing service, the deployment fails, how the old service should be recreated? And if there was any data there to be migrated as part of the deployment?
A service has been renamed. How do I track that it was renamed instead of removing the old and adding a new one?
These is some of the many issues that can happen. This is why you should move away from default services and create them dynamically(imperatively), with dynamic services, service fabric will receive an upgrade command and what will happen is:
"This is my new application type package with new service type
definitions, whatever version you get deployed there, replace for this
version and keep the same configuration".
If a new configuration is required, you will provide as parameters for the deployment to override the old values or change it on a separate command. This will make things much simpler, as SF won't have to worry about different configurations and will just apply package changes to deployed services.
You can also find a nice info about these issues on these links:
How not to use service fabric default services
Service Fabric Q&A 10
Service Fabric Q&A 11
Regarding your main question:
Does anyone have a solution as to how I can get a good developer
experience by not using DefaultServices and instead using Powershell
scripts?
if you want a good experience you should use the default services, it is intended for this, give the developer a good experience without worrying about services required to run at startup.
The trick is, during your CI process, you should remove the default services from the application manifest before you pack your application, so that you don't face the drawbacks later.
Removing the defaultServices during CI (Like VSTS Build), you have the benefits of defaultServices on dev environment, don't have to maintain the powershell script versions(if a new version comes along) and the removal of the default services is a very simple powershell script added as a build step. Other than that, everything keeps the same.
Ps: I don't have a real script at hand now, but will be very simple like this:
$appManifest = "C:\Temp\ApplicationManifest.xml" #you pass as parameter
[xml]$xml = Get-Content $appManifest
$xml.ApplicationManifest.DefaultServices.RemoveAll()
$xml.save($appManifest)
The solution here is to use a script named Start-Service.ps1 in the Scripts folder in Application project.
Below is an example script for the Data Aggregation sample Microsoft have provided.
$cloud = $false
$singleNode = $true
$constrainedNodeTypes = $false
$lowkey = "-9223372036854775808"
$highkey = "9223372036854775807"
$countyLowKey = 0
$countyHighKey = 57000
$appName = "fabric:/DataAggregation"
$appType = "DataAggregationType"
$appInitialVersion = "1.0.0"
if($singleNode)
{
$webServiceInstanceCount = -1
$deviceCreationInstanceCount = -1
$countyServicePartitionCount = 1
$deviceActorServicePartitionCount = 1
$doctorServicePartitionCount = 1
}
else
{
$webServiceInstanceCount = #{$true=-1;$false=1}[$cloud -eq $true]
$deviceCreationInstanceCount = #{$true=-1;$false=1}[$cloud -eq $true]
$countyServicePartitionCount = #{$true=10;$false=5}[$cloud -eq $true]
$deviceActorServicePartitionCount = #{$true=15;$false=5}[$cloud -eq $true]
$doctorServicePartitionCount = #{$true=100;$false=5}[$cloud -eq $true]
if($constrainedNodeTypes)
{
$webServiceConstraint = "NodeType == "
$countyServiceConstraint = "NodeType == "
$nationalServiceConstraint = "NodeType == "
$deviceServiceConstraint = "NodeType == "
$doctorServiceConstraint = "NodeType == "
$deviceCreationServiceConstraint = "NodeType == "
}
else
{
$webServiceConstraint = ""
$countyServiceConstraint = ""
$nationalServiceConstraint = ""
$deviceServiceConstraint = ""
$doctorServiceConstraint = ""
$deviceCreationServiceConstraint = ""
}
}
$webServiceType = "DataAggregation.WebServiceType"
$webServiceName = "DataAggregation.WebService"
$nationalServiceType = "DataAggregation.NationalServiceType"
$nationalServiceName = "DataAggregation.NationalService"
$nationalServiceReplicaCount = #{$true=1;$false=3}[$singleNode -eq $true]
$countyServiceType = "DataAggregation.CountyServiceType"
$countyServiceName = "DataAggregation.CountyService"
$countyServiceReplicaCount = #{$true=1;$false=3}[$singleNode -eq $true]
$deviceCreationServiceType = "DataAggregation.DeviceCreationServiceType"
$deviceCreationServiceName = "DataAggregation.DeviceCreationService"
$doctorServiceType = "DataAggregation.DoctorServiceType"
$doctorServiceName = "DataAggregation.DoctorService"
$doctorServiceReplicaCount = #{$true=1;$false=3}[$singleNode -eq $true]
$deviceActorServiceType = "DeviceActorServiceType"
$deviceActorServiceName= "DataAggregation.DeviceActorService"
$deviceActorReplicaCount = #{$true=1;$false=3}[$singleNode -eq $true]
New-ServiceFabricService -ServiceTypeName $webServiceType -Stateless -ApplicationName $appName -ServiceName "$appName/$webServiceName" -PartitionSchemeSingleton -InstanceCount $webServiceInstanceCount -PlacementConstraint $webServiceConstraint -ServicePackageActivationMode ExclusiveProcess
#create national
New-ServiceFabricService -ServiceTypeName $nationalServiceType -Stateful -HasPersistedState -ApplicationName $appName -ServiceName "$appName/$nationalServiceName" -PartitionSchemeSingleton -MinReplicaSetSize $nationalServiceReplicaCount -TargetReplicaSetSize $nationalServiceReplicaCount -PlacementConstraint $nationalServiceConstraint -ServicePackageActivationMode ExclusiveProcess
#create county
New-ServiceFabricService -ServiceTypeName $countyServiceType -Stateful -HasPersistedState -ApplicationName $appName -ServiceName "$appName/$countyServiceName" -PartitionSchemeUniformInt64 -LowKey $countyLowKey -HighKey $countyHighKey -PartitionCount $countyServicePartitionCount -MinReplicaSetSize $countyServiceReplicaCount -TargetReplicaSetSize $countyServiceReplicaCount -PlacementConstraint $countyServiceConstraint -ServicePackageActivationMode ExclusiveProcess
#create doctor
New-ServiceFabricService -ServiceTypeName $doctorServiceType -Stateful -HasPersistedState -ApplicationName $appName -ServiceName "$appName/$doctorServiceName" -PartitionSchemeUniformInt64 -LowKey $lowkey -HighKey $highkey -PartitionCount $doctorServicePartitionCount -MinReplicaSetSize $doctorServiceReplicaCount -TargetReplicaSetSize $doctorServiceReplicaCount -PlacementConstraint $doctorServiceConstraint -ServicePackageActivationMode ExclusiveProcess
#create device
New-ServiceFabricService -ServiceTypeName $deviceActorServiceType -Stateful -HasPersistedState -ApplicationName $appName -ServiceName "$appName/$deviceActorServiceName" -PartitionSchemeUniformInt64 -LowKey $lowkey -HighKey $highkey -PartitionCount $deviceActorServicePartitionCount -MinReplicaSetSize $deviceActorReplicaCount -TargetReplicaSetSize $deviceActorReplicaCount -PlacementConstraint $deviceServiceConstraint -ServicePackageActivationMode ExclusiveProcess -Verbose
#create device creation
New-ServiceFabricService -ServiceTypeName $deviceCreationServiceType -Stateless -ApplicationName $appName -ServiceName "$appName/$deviceCreationServiceName" -PartitionSchemeSingleton -InstanceCount $deviceCreationInstanceCount -PlacementConstraint $deviceCreationServiceConstraint -ServicePackageActivationMode ExclusiveProcess

Importing a Powershell Module as LocalSystem Account on TeamCity

I've got some strange behavior between me running a command under my profile, and TeamCity running the same command.
> Import-Module $root\packages\fsm.buildrelease.*\tools\modules\BuildDeployModules -Force
If I run the script manually, the build kicks off as expected. If I let TeamCity execute the script, it pukes with the following.
Import-Module : The specified module 'C:\BuildAgent\work\81eb7c2fdfcfc0af\packages\fsm.buildrelease.*\tools\modules\BuildDeployModules' was not loaded because no valid module file was found in any module directory.
I have double and triple verified that the module exists in that location. And I've gone through my modules and added [cmdletbinding()] before the param, but it doesn't seem to solve this issue.
It's frustrating because it doesn't say "which" module is getting an invalid parameter passed in.
$fsmbrVersion = "1.1.1" # contains the current version of fsm.buildrelease
Write-Host "`nfsm.buildrelease version $fsmbrVersion `nCopyright ($([char]0x00A9)) Future State Mobile Inc. & Contributors`n"
Push-Location $psScriptRoot
. .\Add-HostsFileEntry.ps1
. .\Add-IISHttpVerb.ps1
. .\Add-IISMimeType.ps1
. .\Add-LoopbackFix.ps1
. .\ApplicationAdministration.ps1
. .\AppPoolAdministration.ps1
. .\Approve-Permissions.ps1
. .\Assert-PSVersion.ps1
. .\EntityFramework.ps1
. .\Expand-NugetPackage.ps1
. .\Expand-ZipFile.ps1
. .\Format-TaskNameToHost.ps1
. .\Get-EnvironmentSettings.ps1
. .\Grunt.ps1
. .\Helpers.ps1
. .\Install-WebApplication.ps1
. .\Invoke-Deployment.ps1
. .\Invoke-DeployOctopusNugetPackage.ps1
. .\Invoke-ElevatedCommand.ps1
. .\Invoke-ExternalCommand.ps1
. .\Invoke-Using.ps1
. .\MSBuild.ps1
. .\Nuget.ps1
. .\nUnit.ps1
. .\Set-IISAuthentication.ps1
. .\Set-IISCustomHeader.ps1
. .\SiteAdministration.ps1
. .\Specflow.ps1
. .\SqlHelpers.ps1
. .\Test-PathExtended.ps1
. .\Test-RunAsAdmin.ps1
. .\TextUtils.ps1
. .\Update-AssemblyVersions.ps1
. .\Update-JsonConfigFile.ps1
. .\Update-XmlConfigFile.ps1
. .\WindowsFeatures.ps1
. .\xUnit.ps1
Pop-Location
Export-ModuleMember `
-Alias #(
'*') `
-Function #(
'Add-HostsFileEntry',
'Add-IISHttpVerb',
'Add-IISMimeType',
'Add-LoopbackFix',
'Approve-Permissions',
'Assert-That',
'Assert-PSVersion',
'Confirm-ApplicationExists',
'Confirm-AppPoolExists',
'Confirm-SiteExists',
'Exec',
'Expand-NugetPackage',
'Expand-ZipFile',
'Format-TaskNameToHost',
'Get-Application',
'Get-Applications',
'Get-AppPool',
'Get-AppPools',
'Get-DatabaseConnection',
'Get-EnvironmentSettings',
'Get-Site',
'Get-Sites',
'Get-TestFileName',
'Get-WarningsFromMSBuildLog',
'Get-WindowsFeatures',
'Install-WebApplication',
'Install-WindowsFeatures',
'Invoke-BulkCopy',
'Invoke-DBMigration',
'Invoke-Deployment',
'Invoke-DeployOctopusNugetPackage',
'Invoke-ElevatedCommand',
'Invoke-EntityFrameworkMigrations',
'Invoke-ExternalCommand',
'Invoke-FromBase64',
'Invoke-GruntMinification',
'Invoke-HtmlDecode',
'Invoke-HtmlEncode',
'Invoke-KarmaTests',
'Invoke-MSBuild',
'Invoke-Nunit',
'Invoke-NUnitWithCoverage'
'Invoke-SpecFlow',
'Invoke-SqlFile',
'Invoke-SqlStatement',
'Invoke-ToBase64',
'Invoke-UrlDecode',
'Invoke-UrlEncode',
'Invoke-Using',
'Invoke-XUnit',
'Invoke-XUnitWithCoverage',
'New-Application',
'New-AppPool',
'New-NugetPackage',
'New-Site',
'Remove-Application',
'Remove-AppPool',
'Remove-Site',
'RequiredFeatures',
'Set-IISAuthentication',
'Set-IISCustomHeader',
'Start-Application',
'Start-AppPool',
'Start-Site',
'Step',
'Stop-Application',
'Stop-AppPool',
'Stop-Site',
'Test-PathExtended',
'Test-RunAsAdmin',
'Update-Application',
'Update-AppPool',
'Update-AssemblyVersions',
'Update-JsonConfigValues',
'Update-Site',
'Update-XmlConfigValues'
)
# Messages
DATA msgs {
convertfrom-stringdata #"
error_duplicate_step_name = Step {0} has already been defined.
error_must_supply_a_feature = You must supply at least one Windows Feature.
error_feature_set_invalid = The argument `"{0}`" does not belong to the set `"{1}`".
error_admin_required = You are required to 'Run as Administrator' when running this deployment.
error_loading_sql_file = Error loading '{0}'. {1}.
error_octopus_deploy_failed = Failed to deploy: {0}.
error_specflow_failed = Publishing specflow results for '{0}' failed.
error_coverage_failed = Running code coverage for '{0}' failed.
error_tests_failed = Running tests '{0}' failed.
error_msbuild_compile = Error compiling '{0}'.
wrn_full_permission = You have applied FULL permission to '{0}' for '{1}'. THIS IS DANGEROUS!
wrn_cant_find = Could not find {0} with the name: {0}.
msg_grant_permission = Granting {0} permissions to {1} for {2}.
msg_enabling_windows_feature = Enabling Windows Feature: `"{0}`".
msg_wasnt_found = `"{0}`" wasn't found.
msg_updated_to = Updated `"{0}`" to `"{1}`".
msg_updating_to = Updating `"{0}`" to `"{1}`".
msg_changing_to = Changing `"{0}`" to `"{1}`".
msg_overriding_to = Overriding node `"{0}`" with value `"{1}`".
msg_updating_assembly = Updating AssemblyVersion to '{0}'. Updating AssemblyFileVersion to '{1}'. Updating AssemblyInformationalVersion to '{2}'.
msg_not_updating = Not updating {0}, you must specify the '-updateIfFound' if you wish to update the {0} settings.
msg_custom_header = Setting custom header '{0}' on site '{1}' to value '{2}'.
msg_disable_anon_auth = Disabling Anonymous Authentication for '{0}'.
msg_web_app_success = Successfully deploy Web Application '{0}'.
msg_copying_content = Copying {0} content to {1}.
msg_use_machine_environment = Using config for machine {0} instead of the {1} environment.
msg_octopus_overrides = Checking for Octopus Overrides for environment '{0}'.
msg_teamcity_importdata = ##teamcity[importData type='{0}' tool='{1}' path='{2}']
msg_teamcity_buildstatus = ##teamcity[buildStatus text='{0}']
msg_teamcity_buildstatisticvalue = ##teamcity[buildStatisticValue key='{0}' value='{1}']
msg_add_loopback_fix = Adding loopback fix for '{0}'.
msg_add_mime_type = Adding mime type '{0}' for extension '{1}' to IIS site '{2}'.
msg_add_verb = Adding IIS Http Verb '{0}' to site '{1}'.
msg_add_host_entry = Adding host entry for '{0}' into the hosts file.
msg_validate_host_entry = Validating host entry for '{0} in the hosts file'
msg_loopback_note = note: we're not disabling the loopback check all together, we are simply adding '{0}' to an allowed list.
"#
}
The problem is nothing to do with importing the module; powershell isn't very helpful in leading you to the issue. The root of the issue didn't reveal it's self until I put the -VERBOSE switch on the import. Once I did that, I got a new error above the old one.
: Parameter attributes need to be a constant or a script block.
FullyQualifiedErrorId: ParameterAttributeArgumentNeedsToBeConstandOrScriptBlock
Essentially, I was using ValidatePattern with double quotes instead of single quotes. Check and make sure your writing your regex patterns correctly when you use ValidatePattern
# Bad
[ValidatePattern("^[a-z]$")]
# Good
[ValidatePattern('^[a-z]$')]

How do I retrieve PR_RULE_ACTIONS via PowerShell and the EWS Managed API?

I have need of retrieving and inspecting the delegate forwarding rule (the built-in delegate commands in EWS being inadequate for my needs since they choke on groups being used as delegates).
I am able to successfully locate the rule created by "Schedule+ EMS Interface". However, I am unable to retrieve PR_RULE_ACTIONS. Turning on tracing.
I see that the PidTagRuleMsgProvider property is getting returned just fine, but PR_RULE_ACTIONS never does.
I suspect that I am using the wrong MAPI property type in the propertyset definition, but I've gone through everything listed at http://msdn.microsoft.com/en-us/library/exchangewebservices.mapipropertytypetype(v=exchg.140).aspx . Any clues?
Here is the relevant snippet of code:
# Setup Basic EWS Properties for Message Search - Used to locate Hidden Forwarding Rule
$searchFilterForwardRule = New-Object Microsoft.Exchange.WebServices.Data.SearchFilter+ContainsSubstring([Microsoft.Exchange.WebServices.Data.ItemSchema]::ItemClass, "IPM.Rule", [Microsoft.Exchange.WebServices.Data.ContainmentMode]::Prefixed, [Microsoft.Exchange.WebServices.Data.ComparisonMode]::Exact)
$itemViewForwardRule = New-Object Microsoft.Exchange.WebServices.Data.ItemView(30, 0, [Microsoft.Exchange.Webservices.Data.OffsetBasePoint]::Beginning)
$itemViewForwardRule.PropertySet = New-Object Microsoft.Exchange.WebServices.Data.PropertySet([Microsoft.Exchange.WebServices.Data.BasePropertySet]::FirstClassProperties, [Microsoft.Exchange.WebServices.Data.ItemSchema]::ItemClass, [Microsoft.Exchange.WebServices.Data.ItemSchema]::Subject)
$itemViewForwardRule.Traversal = [Microsoft.Exchange.WebServices.Data.ItemTraversal]::Associated
# Properties for Hidden Delegate Forwarding Rule
$PID_TAG_RULE_MSG_PROVIDER = New-Object Microsoft.Exchange.WebServices.Data.ExtendedPropertyDefinition(0x65EB,[Microsoft.Exchange.WebServices.Data.MapiPropertyType]::String)
$PID_TAG_RULE_ACTIONS = New-Object Microsoft.Exchange.WebServices.Data.ExtendedPropertyDefinition(0x6680,[Microsoft.Exchange.WebServices.Data.MapiPropertyType]::Binary)
# Property Set for Delegate Forward Rule
$propertySetForwardRule = New-Object Microsoft.Exchange.WebServices.Data.PropertySet([Microsoft.Exchange.WebServices.Data.BasePropertySet]::FirstClassProperties, $PID_TAG_RULE_MSG_PROVIDER)
$forwardRuleExists = $false
$findResults = $service.FindItems([Microsoft.Exchange.Webservices.Data.WellKnownFolderName]::Inbox, $searchFilterForwardRule, $itemViewForwardRule)
If ($findResults.TotalCount -lt 1) {
Write-Error "Failed to find rule" "Error"
} Else {
Foreach ($item in $findResults.Items) {
$item.Load($propertySetForwardRule)
If ($item.ExtendedProperties.Count -ge 1) {
If ($item.ExtendedProperties[0].Value -eq "Schedule+ EMS Interface") {
$forwardRuleExists = $true
write-host "Delegate forwarding rule found." -ForegroundColor Cyan
$propertySetForwardRule.Add($PID_TAG_RULE_ACTIONS)
$item.Load($propertySetForwardRule)
Write-Host "Attempting to retrieve x6680 PR_RULE_ACTIONS (PidTagRuleActions)" -ForegroundColor Cyan
$PR_RULE_ACTIONS = $null
if($Item.TryGetProperty($Pid_Tag_Rule_Actions,[ref]$PR_RULE_ACTIONS)){
return $PR_RULE_ACTIONS
} # endif
else {write-host "TryGetProperty for PR_RULE_ACTIONS failed!" -ForegroundColor Red
} # endelse
} # End If - Correct Message
} # End If - Has Extended Properties
} # End ForEach
} # End If - Message Count
Glen Scales was able to set me on the right path. It turns out that PR_RULE_ACTIONS is not exposed via EWS, but the same data exposed via an attribute called PR_EXTENDED_RULE_ACTIONS. Now I'm happily slinging code to parse the binary blob.
http://msdn.microsoft.com/en-us/library/ee218391(v=EXCHG.80).aspx
The property tag for PR_RULE_ACTIONS is 0x668000FE. You can see it (and the property data) in OutlookSpy (I am its author) - go to the Inbox folder, click IMAPIFolder button, go to the PR_RULES_TABLE tab, select the rule, double click on the PR_RULE_ACTIONS property.
Note that PT_ACTIONS MAPI type (0x000FE) is only accessing in Extended MAPI, I don't think EWS will be able to return it.

How to get list of TFS builds running at the moment from command line?

I'm trying to automate the deployment process, and as part of it, I need to run my release build from command line. I can do it, using command like
.\TFSBuild start http://server-name:8080/tfs/project-collection project-name build-name priority:High /queue
It even returns some code for the queued build — Build queued. Queue position: 2, Queue ID: 11057.
What I don't know, is how to get info about currently running builds, or about the state of my running build from powershell command line? The final aim is to start publishing after that build completes.
I've already got all necessary powershell scripts to create the deployment package from the build results, zip it, copy to production and install there. All I need now — to know when my build succeedes.
This function will wait for a build with the Queue ID given by TFSBuild.exe:
function Wait-QueuedBuild {
param(
$QueueID
)
[void][Reflection.Assembly]::LoadWithPartialName('Microsoft.TeamFoundation.Build.Client')
[void][Reflection.Assembly]::LoadWithPartialName('Microsoft.TeamFoundation.Client')
$uri = [URI]"http://server-name:8080/tfs/project-collection"
$projectCollection = [Microsoft.TeamFoundation.Client.TfsTeamProjectCollectionFactory]::GetTeamProjectCollection($uri)
$buildServer = $projectCollection.GetService([Microsoft.TeamFoundation.Build.Client.IBuildServer])
$spec = $buildServer.CreateBuildQueueSpec('*','*')
do {
$build = $buildServer.QueryQueuedBuilds($spec).QueuedBuilds| where {$_.Id -eq $QueueID}
sleep 1
} while ($build)
}
You can get the id returned by TFSBuild.exe, then call the function.
$tfsBuild = .\TFSBuild start http://server-name:8080/tfs/project-collection project-name build-name priority:High /queue
Wait-QueuedBuild [regex]::Match($tfsBuild[-1],'Queue ID: (?<id>\d+)').Groups['id'].Value
Using the work by E.Hofman available here it is possible to write a C# console app that uses TFS SDK and reveals if any build agent is currently running as follows:
using System;
using Microsoft.TeamFoundation.Build.Client;
using Microsoft.TeamFoundation.Client;
namespace ListAgentStatus
{
class Program
{
static void Main()
{
TfsTeamProjectCollection teamProjectCollection = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(new Uri("http://TFSServer:8080"));
var buildServer = teamProjectCollection.GetService<IBuildServer>();
foreach (IBuildController controller in buildServer.QueryBuildControllers(true))
{
foreach (IBuildAgent agent in controller.Agents)
{
Console.WriteLine(agent.Name+" is "+agent.IsReserved);
}
}
}
}
}
The parameter .IsReserved is what toggles to 'True' during execution of a build.
I 'm sorry my powershell skills are not good enough for providing with a PS variant of the above. Please take a look here, where the work by bwerks might help you do that.
# load classes for execution
[Reflection.Assembly]::LoadWithPartialName("Microsoft.TeamFoundation.Build.Client") | Out-Null
[Reflection.Assembly]::LoadWithPartialName("Microsoft.TeamFoundation.Client") | Out-Null
# declare working variables
$Uri = New-Object System.Uri "http://example:8080/tfs"
# get reference to projection collection
$ProjectCollection = [Microsoft.TeamFoundation.Client.TfsTeamProjectCollectionFactory]::GetTeamProjectCollection($Uri)
# get reference to build server
$BuildServer = $ProjectCollection.GetService([Microsoft.TeamFoundation.Build.Client.IBuildServer])
# loop through the build servers
foreach($Controller in $BuildServer.QueryBuildControllers($true))
{
# loop through agents
foreach($BuildAgent in $Controller.Agents)
{
Write-Host "$($BuildAgent.Name) is $($BuildAgent.IsReserved)"
}
}

Get Tfs Shelveset file contents at the command prompt?

I'm interested in getting the contents of a shelveset at the command prompt. Now, you would think that a cmdlet such as Get-TfsShelveset, available in the TFS Power Tools, would do this. You might also think that "tf.exe shelvesets" would do this.
However, unless I've missed something, I'm appalled to report that neither of these is the case. Instead, each command requires you to give it a shelveset name, and then simply regurgitates a single line item for that shelveset, along with some metadata about the shelveset such as creationdate, displayname, etc. But as far as I can tell, no way to tell what's actually in the shelf.
This is especially heinous for Get-TfsShelveset, which has the ability to include an array of file descriptors along with the Shelveset object it returns. I even tried to get clever, thinking that I could harvest the file names from using -WhatIf with Restore-TfsShelveset, but sadly Restore-TfsShelveset doesn't implement -WhatIf.
Please, someone tell me I'm wrong about this!
tf status /shelveset:name
will list out the content of the named shelveset (you can also supplier an owner: see tf help status).
With the TFS PowerToy's PowerShell snapin:
Get-TfsPendingChange -Shelveset name
for the same information.
It is possible to construct a small command-line application that uses the TFS SDK, which returns the list of files contained in a given shelveset.
The sample below assumes knowledge of the Shelveset name & it's owner:
using System;
using System.IO;
using System.Collections.ObjectModel;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.Framework.Common;
using Microsoft.TeamFoundation.Framework.Client;
using Microsoft.TeamFoundation.VersionControl.Client;
namespace ShelvesetDetails
{
class Program
{
static void Main(string[] args)
{
Uri tfsUri = (args.Length < 1) ? new Uri("TFS_URI") : new Uri(args[0]);
TfsConfigurationServer configurationServer = TfsConfigurationServerFactory.GetConfigurationServer(tfsUri);
ReadOnlyCollection<CatalogNode> collectionNodes = configurationServer.CatalogNode.QueryChildren(
new[] { CatalogResourceTypes.ProjectCollection },
false, CatalogQueryOptions.None);
CatalogNode collectionNode = collectionNodes[0];
Guid collectionId = new Guid(collectionNode.Resource.Properties["InstanceId"]);
TfsTeamProjectCollection teamProjectCollection = configurationServer.GetTeamProjectCollection(collectionId);
var vcServer = teamProjectCollection.GetService<VersionControlServer>();
Shelveset[] shelves = vcServer.QueryShelvesets(
"SHELVESET_NAME", "SHELVESET_OWNER");
Shelveset shelveset = shelves[0];
PendingSet[] sets = vcServer.QueryShelvedChanges(shelveset);
foreach (PendingSet set in sets)
{
PendingChange[] changes = set.PendingChanges;
foreach (PendingChange change in changes)
{
Console.WriteLine(change.FileName);
}
}
}
}
}
Invoking this console app & catching the outcome during execution of the powershell should be possible.
Try:
tfpt review
/shelveset:shelvesetName;userName
You may also need to add on the server option so something like:
tfpt review /shelveset:Code Review;jim
/sever:company-source
I think this is what you are looking for.
This is what I ended up with, based on pentelif's code and the technique in the article at http://akutz.wordpress.com/2010/11/03/get-msi/ linked in my comment.
function Get-TfsShelvesetItems
{
[CmdletBinding()]
param
(
[string] $ShelvesetName = $(throw "-ShelvesetName must be specified."),
[string] $ShelvesetOwner = "$env:USERDOMAIN\$env:USERNAME",
[string] $ServerUri = $(throw "-ServerUri must be specified."),
[string] $Collection = $(throw "-Collection must be specified.")
)
$getShelvesetItemsClassDefinition = #'
public IEnumerable<PendingChange> GetShelvesetItems(string shelvesetName, string shelvesetOwner, string tfsUriString, string tfsCollectionName)
{
Uri tfsUri = new Uri(tfsUriString);
TfsConfigurationServer configurationServer = TfsConfigurationServerFactory.GetConfigurationServer(tfsUri);
ReadOnlyCollection<CatalogNode> collectionNodes = configurationServer.CatalogNode.QueryChildren( new[] { CatalogResourceTypes.ProjectCollection }, false, CatalogQueryOptions.None);
CatalogNode collectionNode = collectionNodes.Where(node => node.Resource.DisplayName == tfsCollectionName).SingleOrDefault();
Guid collectionId = new Guid(collectionNode.Resource.Properties["InstanceId"]);
TfsTeamProjectCollection teamProjectCollection = configurationServer.GetTeamProjectCollection(collectionId);
var vcServer = teamProjectCollection.GetService<VersionControlServer>();
var changes = new List<PendingChange>();
foreach (Shelveset shelveset in vcServer.QueryShelvesets(shelvesetName, shelvesetOwner))
{
foreach (PendingSet set in vcServer.QueryShelvedChanges(shelveset))
{
foreach ( PendingChange change in set.PendingChanges )
{
changes.Add(change);
}
}
}
return changes.Count == 0 ? null : changes;
}
'#;
$getShelvesetItemsType = Add-Type `
-MemberDefinition $getShelvesetItemsClassDefinition `
-Name "ShelvesetItemsAPI" `
-Namespace "PowerShellTfs" `
-Language CSharpVersion3 `
-UsingNamespace System.IO, `
System.Linq, `
System.Collections.ObjectModel, `
System.Collections.Generic, `
Microsoft.TeamFoundation.Client, `
Microsoft.TeamFoundation.Framework.Client, `
Microsoft.TeamFoundation.Framework.Common, `
Microsoft.TeamFoundation.VersionControl.Client `
-ReferencedAssemblies "C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\ReferenceAssemblies\v2.0\Microsoft.TeamFoundation.Client.dll", `
"C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\ReferenceAssemblies\v2.0\Microsoft.TeamFoundation.Common.dll", `
"C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\ReferenceAssemblies\v2.0\Microsoft.TeamFoundation.VersionControl.Client.dll" `
-PassThru;
# Initialize an instance of the class.
$getShelvesetItems = New-Object -TypeName "PowerShellTfs.ShelvesetItemsAPI";
# Emit the pending changes to the pipeline.
$getShelvesetItems.GetShelvesetItems($ShelvesetName, $ShelvesetOwner, $ServerUri, $Collection);
}
Spent a few days trying to do this as well, this always popped up on google so here is what I found to help future generations:
To get the contents of the shelveset (at least with Team Explorer Everywhere),
use the command: tf difference /shelveset:<Shelveset name>
That will print out the contents of the shelveset and give filenames in the form :
<Changetype>: <server file path>; C<base change number>
Shelved Change: <server file path again>;<shelveset name>
So if your file is contents/test.txt
in the shelveset shelve1 (with base revision 1), you will see :
edit: $/contents/file.txt;C1
Shelved Change: $/contents/file.txt;shelve1
After that, using the tf print command
(or view if not using TEE) on $/contents/file.txt;shelve1 should get you the contents :
tf print $/contents/file.txt;shelve1
Shows you what is in the file.txt in shelveset shelve1
If you want get shelveset changes from server by using tfs command
Using power shell:
Get-TfsPendingChange -Server http://example.com/org -Shelveset shelvsetName
Using vs commands:
c:\projects>tf shelvesets BuddyTest_23
more info about this please see here
https://learn.microsoft.com/en-us/azure/devops/repos/tfvc/shelvesets-command?view=azure-devops