Get the SSIS Event Name in Script Task - events

I am wanting to run a standard script task in package level events (OnError, OnPreExecute, OnPostExecute) for logging.
Ideally I would like to be able to just copy and paste the Script task, but it needs to know the Event that it is running inside of. Currently I pass that in as a use variable, but this means that I need to manually set the variable to store the name of the event. That's not too arduous, but it is easily forgotten. Thus my question is, is there a performant way to detect which event the script task is running within.
My suspicion is that this is not easy as essentially this is the same as finding out the name of the parent container, which turns out to be next to impossible.
Another option is to be able to sniff the scope of standard event variables, such as 'EventHandlerStartTime', but I can't find a way to determine the scope of a variable from within the script task.
Any help is much appreciated.

Since #Mark mentioned Biml, I thought I'd take a moment to explode out the concept of using some very basic concepts to make this happen.
Assuming I had a pathetic logging table like
CREATE TABLE
dbo.DoWhat
(
PackageName nvarchar(150) NULL
, ParentContainerGUID varchar(38) NULL
, SourceDescription nvarchar(1000) NULL
, SourceName nvarchar(150) NULL
, SourceParentGUID varchar(38) NULL
, EventName varchar(20) NULL
);
then I could define a "function" in a file called inc_events.biml
What that says, this file expects a parameter of type string that will populate the eventName variable. I then use a classic ASP style syntax for subbing in that value <#=eventName#>
So, this biml will create an Event. That event has a Variable named WhereAmI that is scoped to the Event. I then have an Execute SQL Task in there that does an insert into the logging table passing along System variables and my local variable name.
You're looking to use a Script Task so you'd replace the Execute SQL Task but the concept is the same. There's a something in there that's going to use our local variable that had the event's name assigned to it.
<## property name="eventName" type="String" #>
<Event EventType="<#=eventName#>" ConstraintMode="Linear" Name="<#=eventName#>">
<Variables>
<Variable DataType="String" Name="WhereAmI"><#=eventName#></Variable>
</Variables>
<Tasks>
<ExecuteSQL ConnectionName="tempdb" Name="SQL Log notes">
<VariableInput VariableName="User.QueryLog"></VariableInput>
<Parameters>
<Parameter DataType="String" VariableName="System.PackageName" Name="0" />
<Parameter DataType="AnsiString" VariableName="System.ParentContainerGUID" Name="1" DataTypeCodeOverride="129" />
<Parameter DataType="String" VariableName="System.SourceDescription" Name="2" />
<Parameter DataType="String" VariableName="System.SourceName" Name="3" />
<Parameter DataType="AnsiString" VariableName="System.SourceParentGUID" Name="4" DataTypeCodeOverride="129" />
<Parameter DataType="AnsiString" VariableName="User.WhereAmI" Name="5" DataTypeCodeOverride="129" />
</Parameters>
</ExecuteSQL>
</Tasks>
</Event>
Using the include file
I add a second Biml file, so_27378254_inc.biml to my project. This one is going to demonstrate how we use the function/include file.
I define an OLE DB database connection in Connections collection called tempdb
In my Packages collection, I define a new package called so_27378254_inc. It has a Variable, QueryLog which just contains the format for an insert statement into my log table.
In the package's Events collection, I then invoke CallBimlScript 3 times, one for each Event Handler I want to add at the package level scope.
Into the Tasks collection, I add a Sequence Container just so I can get some variety in my log.
<Biml xmlns="http://schemas.varigence.com/biml.xsd">
<Connections>
<OleDbConnection Name="tempdb" ConnectionString="Data Source=localhost\dev2014;Initial Catalog=tempdb;Provider=SQLNCLI10.1;Integrated Security=SSPI;" />
</Connections>
<Packages>
<Package ConstraintMode="Linear" Name="so_27378254_inc">
<Variables>
<Variable DataType="String" Name="QueryLog">
<![CDATA[INSERT INTO
dbo.DoWhat
(
PackageName
, ParentContainerGUID
, SourceDescription
, SourceName
, SourceParentGUID
, EventName
)
SELECT
? /* AS PackageName */
, ? /* AS ParentContainerGUID */
, ? /* AS SourceDescription */
, ? /* AS SourceName */
, ? /* AS SourceParentGUID */
, ? /* AS EventName */
;]]>
</Variable>
</Variables>
<Events>
<#=CallBimlScript("inc_events.biml", "OnError")#>
<#=CallBimlScript("inc_events.biml", "OnPreExecute")#>
<#=CallBimlScript("inc_events.biml", "OnPostExecute")#>
</Events>
<Tasks>
<Container Name="SEQC Container on Control Flow" ConstraintMode="Linear">
</Container>
</Tasks>
</Package>
</Packages>
</Biml>
So, what do you do with it? You right click on the so_27378254_inc.biml file and whoosh, a new package is generated.
How the heck do I sell this?
You mention in your comments, and rightfully so, concerns over anything that would "add friction to adoption".
My counter to that is
BIDS Helper is free and if you're not using it, you're not being as effective in your delivery as you could be. Especially pre-2012, there's just too many sharp edges in the product.
Using an approach like this will get everyone to a consistent starting point, without some of the hassles that come with template packages (IDs are not automatically updated until 2012)
You don't have to go all in on the Biml approach. Assuming you're the architect/lead developer, use it to define best practices. Everyone has logging turned on, apply configurations, get the standard connections defined, etc. All people have to do is instead of creating new SSIS, they right click and generate the template package and then rename it to something appropriate and they're off the races worrying about data flows and file acquisition, etc.

Related

How can I show the details related to the submitted report in the output xml?

I am creating a report which should contain the Report Name, request id of the report, operating unit as well as date and time of the report submitted.
I am not sure how to do that.
Basically I need information related to the report on Oracle EBS to be displayed in the output xml.
Operating Unit: Use a hidden parameter on your concurrent request definition or just select it in your data definition.
These can be used in select statements. You can either get, or derive, what you need to from these.
fnd_profile.value('PROFILEOPTION')
fnd_profile.value('MFG_ORGANIZATION_ID')
fnd_profile.value('ORG_ID') --Operating Unit
fnd_profile.value('LOGIN_ID')
fnd_profile.value('USER_ID')
fnd_profile.value('USERNAME')
fnd_profile.value('CONCURRENT_REQUEST_ID')
fnd_profile.value('GL_SET_OF_BKS_ID')
fnd_profile.value('SO_ORGANIZATION_ID')
fnd_profile.value('APPL_SHRT_NAME')
fnd_profile.value('RESP_NAME')
fnd_profile.value('RESP_ID')
fnd_profile.value('PER_BUSINESS_GROUP_ID')
fnd_profile.value('GL_SET_OF_BKS_ID')
fnd_profile.value('CURRENT_ORG_CONTEXT')
Something like this:
<dataQuery>
<sqlStatement name="Q_GENERAL_INFO">
<![CDATA[
SELECT USERENV('LANG') language_code,
sysdate print_date,
fnd_profile.value('USERNAME') username
FROM dual
]]></sqlStatement>
</dataQuery>
Then you can make a section in your XML to select them into the XML.
<dataStructure>
<group name="General_Info" source="Q_GENERAL_INFO">
<element name="Language_Code" value="language_code"></element>
<element name="Print_Date" value="print_date"></element>
<element name="Username" value="username"></element>
</group>
</dataStructure>

Setting coordinator names in Oozie bundle from bundle.properties

I'm using an Oozie bundle to manage two coordinators (for now). They are the same process, but for two different clients. I have the client names defined in the bundle.properties file that I call when I launch the bundle.xml. I'm trying to use the client name to name each of the coordinators, but I keep seeing variations of the following error:
Error: E0701 : E0701: XML schema error, cvc-pattern-valid: Value
'Daily_job_#{client1}' is not facet-valid with respect to pattern
'(a-zA-Z*){1,39}' for type 'IDENTIFIER'
I have been playing around with using ${} to access the variable name vs #{} based on this post here: Renaming Oozie coordinator dynamically. I seem to be able to access the variables as properties just fine from the bundle.properties just not in the name.
Here is what I've tried in the bundle.xml:
<coordinator name='Daily_job_#{client1}' >
...
<property>
<name>client</name>
<value>${client1}</value>
</property>
</coordinator>
and
<coordinator name='Daily_job_${client1}' >
...
</coordinator>
In the bundle.properties:
client1=firstclientname
client2=secondclientname
I'm able to access the value of client within the property in the coordinator and workflow but I can't seem to name the coordinator based on the property. Can anyone help me? Thank you!
Seeing as you're getting that particular error seems to indicate the name which happens to be a bundle:IDENTIFIER type does not conform to the schema that was defined by the Oozie developers.
What this means is that your XML is being validated for well-formedness against a schema and the bundle:IDENTIFIER is checked against a regular expression that only allows alphanumerics, dashes and underscores in the name with a minimum of 1 character up to 40 characters.
<xs:simpleType name="IDENTIFIER">
<xs:restriction base="xs:string">
<xs:pattern value="([a-zA-Z]([\-_a-zA-Z0-9])*){1,39})"/>
</xs:restriction>
</xs:simpleType>
Well-formedness is a XML pre-processing step and is probably restricting your substitution characters as $ # { } are not included in the regular expression.
https://github.com/apache/oozie/blob/master/client/src/main/resources/oozie-bundle-0.2.xsd
I was using Oozie bundle schema 0.1: xmlns='uri:oozie:bundle:0.1', and by changing it to 0.2:xmlns='uri:oozie:bundle:0.2' it works now. I am also using the second variation with ${}, so in the bundle.xml:
<coordinator name='Daily_job_${client1}' >
...
</coordinator>
Is the one to use.

WebSphere Commerce IDResGen query

I'm trying to load em spots using massload. I'm finding the internal alias method of idresgen.bat is only resolving the internal alias for foreign key references, but I need to use the value in dmelementnvp value column which doesn't have a foreign key reference.
In the sample code below the last dmelementnvp definition is rejected with an error that value could not be resolved. Does anyone know how to resolve the emspot id to populate the value column required?
<emspot
emspot_id="#emspot_id_1"
storeent_id="&MAR_STOREENT_ID;"
name="Home_BestSellers"
description="Display catalog entry recommendations from Coremetrics Intelligent Offer on the home page."
usagetype="MARKETING"
supportedtypes="P"
/>
<dmactivity
dmactivity_id="#dmactivity_bestseller1"
storeent_id="&MAR_STOREENT_ID;"
name="HomePageBestSellersActivity"
description="The test activity for the home page best sellers"
published="1"
state="1"
behavior="1"
dmcampaign_id="#campaign_initial_launch"
/>
<dmelement
dmelement_id="#dmactivity_bestseller_elem1"
name="Flow0.0"
dmeletemplate_id="6"
dmactivity_id="#dmactivity_bestseller1"
sequence="0"
/>
<dmelement
dmelement_id="#dmactivity_bestseller_elem2"
name="Coremetrics Target"
dmeletemplate_id="339"
dmactivity_id="#dmactivity_bestseller1"
sequence="1500"
parent="Flow0.0"
/>
<dmelement
dmelement_id="#dmactivity_bestseller_elem3"
name="Espot Target"
dmeletemplate_id="105"
dmactivity_id="#dmactivity_bestseller1"
sequence="1000"
parent="Flow0.0"
/>
<dmelementnvp
dmelement_id="#dmactivity_bestseller_elem2"
name="zoneIdList"
value="ZoneA"
/>
<dmelementnvp
dmelement_id="#dmactivity_bestseller_elem3"
name="emsId"
value="#emspot_id_1"
/>
I would ask this question to IBM Software Support.

Adding comments using XDT-Transform

I am using XDT-Transform in Visual Studio 2010 to generate multiple config files.
Xml transformation is working fine. But I cannot seem to find way to carry comments from an xml transform file to final file.
Just like there is Insert transform for adding config settings, is there anyway to add comments? Without comments I may have to give up on the whole transform approach.
I've found a possible solution for you.
It is only necessary to denote something as being an Insert at the highest level you are adding it. After that you may just add elements like you would normally.
Meaning this doesn't work to bring over your comment
<appSettings>
<!--My Secret Encryption Key-->
<add key="ENCRYPT_KEY" value="hunter2" xdt:Transform="Insert" />
</appSettings>
But this would
<appSettings xdt:Transform="Remove" />
<appSettings xdt:Transform="Insert" >
<!--My Secret Encryption Key-->
<add key="ENCRYPT_KEY" value="hunter2"/>
</appSettings>
Nothing else requires a transform as it copies over the element entirely.
Upside: You get your comments and don't have to insert xdt:Transform="Insert" into every key element.
Downside: You end up destroying the section entirely and re add it which ends up appending it to the bottom of your Web.config. If the change in total formatting is okay then awesome. Also it requires you recreate the entire section which could increase the size of your transforms.
This isn't exactly what you want, but I find it useful once in a while.
XmlTransform will add comments if they are contained in an added element.
e.g.
<appSettings>
<remove key="comment" value="" xdt:Transform="Insert"><!-- this comment will appear in the transformed config file! --></remove>
</appSettings>
Not possible without writing code.
However, my current solution is to extent the XDT Transform library, by basically following the link: Extending XML (web.config) Config transformation
And here is my example of CommentAppend, CommentPrepend which take comment text as input parameter, as I believe otherwise Insert itself can't work as the comment you would put your xdt:Transform="Insert" will be ignored by XDT Transform as it is comment.
internal class CommentInsert: Transform
{
protected override void Apply()
{
if (this.TargetNode != null && this.TargetNode.OwnerDocument != null)
{
var commentNode = this.TargetNode.OwnerDocument.CreateComment(this.ArgumentString);
this.TargetNode.AppendChild(commentNode);
}
}
}
internal class CommentAppend: Transform
{
protected override void Apply()
{
if (this.TargetNode != null && this.TargetNode.OwnerDocument != null)
{
var commentNode = this.TargetNode.OwnerDocument.CreateComment(this.ArgumentString);
this.TargetNode.ParentNode.InsertAfter(commentNode, this.TargetNode);
}
}
}
And the input web.Release.config:
<security xdt:Transform="CommentPrepend(comment line 123)" >
</security>
<security xdt:Transform="CommentAppend(comment line 123)" >
</security>
And the output:
<!--comment line 123--><security>
<requestFiltering>
<hiddenSegments>
<add segment="NWebsecConfig" />
<add segment="Logs" />
</hiddenSegments>
</requestFiltering>
</security><!--comment line 123-->
I am currently using Reflector to look at Microsoft.Web.XmTransform comes with Visual Studio V12.0 to figure out how it works, but probably it's better to look at the source code itself
As far as I am aware adding comments using XDT-Transform is not possible I'm afraid.
At least it doesn't appear to be mentioned within the XDT-Transform documentation
I built an extension for XDT to handle comment injection and other related tasks.
You can try it online.

Howto use configurable Merge Modules in Wix?

AFAIK it's done like this:
Product:
<Merge Id ="HelpInstaller" SourceFile="HelpInstaller.msm" Language="1033" DiskId="1">
<ConfigurationData Name="SurpressInstallation_Config" Value="&HelpFeature"/>
</Merge>
Merge Module:
<Property Id="SupressInstallation" Value='0' />
<Substitution Table='CustomAction' Row='SetSupressInstallationProperty' Column='Target' Value='[=SupressInstallation_Config]'/>
<CustomAction Id='SetSupressInstallationProperty' Property='SupressInstallation' Value='[SupressInstallation]'/>
<InstallExecuteSequence>
<Custom Action='SetSupressInstallationProperty' Before='RegisterHelp' />
<Custom Action='RegisterHelp' After='CostFinalize'>(NOT Installed) AND (NOT UPGRADINGPRODUCTCODE) AND SupressInstallation = 3) </Custom>
</InstallExecuteSequence>
But when i did it like above i get an error:
Encountered an unexpected merge error of type 'msmErrorDataRequestFailed' for which therer is currently no error messagte to display.
Can anyone tell me howto solve that problem? What i basically want to do is to execute a custom action in the merge module only when a certain feature is selected..Is this the right way to do it? Thanks Daniel
You have to define Configuration node under module:
<Property Id="SupressInstallation" Value='0' />
<Configuration Name="SupressInstallation_Config" Format="Text"/>
<Substitution Table='CustomAction' Row='SetSupressInstallationProperty' Column='Target' Value='[=SupressInstallation_Config]'/>
<CustomAction Id='SetSupressInstallationProperty' Property='SupressInstallation' Value='[SupressInstallation]'/>
<InstallExecuteSequence>
<Custom Action='SetSupressInstallationProperty' Before='RegisterHelp' />
<Custom Action='RegisterHelp' After='CostFinalize'>(NOT Installed) AND (NOT UPGRADINGPRODUCTCODE) AND SupressInstallation = 3) </Custom>
</InstallExecuteSequence>
That sounds like a bug. You should at least get a more descriptive error message explaining what went wrong. Feel free to file the bug at http://wixtoolset.org/bugs
A feature has a dependency on a merge module, not the other way around. Nothing in the merge module should have a reference to anything outside of the merge module such as a ProductName, ProductCode or Feature name because that would tightly couple the merge module to a specific product rather then being a generic reusable module. Doing such would essentially create a circular reference and is not idea.
What you probably need ( hard to say without knowing more information ) is to use the action state of one of the Components in the merge module for your condition.
For example if component1 has file1 and you need customaction1 to fire when this component/file is being installed then you'd use an expression of:
$component1=3 //INSTALLSTATE_LOCAL
That way if this merge module gets merged into Product1, Product 2 or Product3 with Feature Name A, B or C it won't matter because the association is at the component level.
If the feature you are trying to tie off of is a different feature then this all needs to be moved into a different merge module that get's merged into that feature. You might need to create a dummy component to associate to.
Now if you want to ignore all of this advice, then look at the Feature Action state operator and tightly couple away.
Conditional Statement Syntax

Resources