Joseph Michael Pesch
VP Programming

SQL Table Valued Function to Parse JSON

by 18. May 2017 11:58

 

 

CREATE FUNCTION [dbo].[parseJSON]( @JSON NVARCHAR(MAX))

RETURNS @hierarchy TABLE
  (
   element_id INT IDENTITY(1, 1) NOT NULL,/* internal surrogate primary key gives the order of parsing and the list order */
   sequenceNo [int] NULL, /* the place in the sequence for the element */
   parent_ID INT,/* if the element has a parent then it is in this column. The document is the ultimate parent, so you can get the structure from recursing from the document */
   Object_ID INT,/* each list or object has an object id. This ties all elements to a parent. Lists are treated as objects here */
   NAME NVARCHAR(2000),/* the name of the object */
   StringValue NVARCHAR(MAX)NOT NULL,/*the string representation of the value of the element. */
   ValueType VARCHAR(10) NOT null/* the declared type of the value represented as a string in StringValue*/
  )
AS
BEGIN
  DECLARE
    @FirstObject INT, --the index of the first open bracket found in the JSON string
    @OpenDelimiter INT,--the index of the next open bracket found in the JSON string
    @NextOpenDelimiter INT,--the index of subsequent open bracket found in the JSON string
    @NextCloseDelimiter INT,--the index of subsequent close bracket found in the JSON string
    @Type NVARCHAR(10),--whether it denotes an object or an array
    @NextCloseDelimiterChar CHAR(1),--either a '}' or a ']'
    @Contents NVARCHAR(MAX),--the unparsed contents of the bracketed expression
    @Start INT, --index of the start of the token that you are parsing
    @end INT,--index of the end of the token that you are parsing
    @param INT,--the parameter at the end of the next Object/Array token
    @EndOfName INT,--the index of the start of the parameter at end of Object/Array token
    @token NVARCHAR(500),--either a string or object -- slayne 7/10/14: increased from 200 to 500
    @value NVARCHAR(MAX),-- the value as a string
    @SequenceNo int, -- the sequence number within a list
    @name NVARCHAR(200),--the name as a string
    @parent_ID INT,--the next parent ID to allocate
    @lenJSON INT,--the current length of the JSON String
    @characters NCHAR(36),--used to convert hex to decimal
    @result BIGINT,--the value of the hex symbol being parsed
    @index SMALLINT,--used for parsing the hex value
    @Escape INT --the index of the next escape character
  DECLARE @Strings TABLE /* in this temporary table we keep all strings, even the names of the elements, since they are 'escaped' in a different way, and may contain, unescaped, brackets denoting objects or lists. These are replaced in the JSON string by tokens representing the string */
    (
     String_ID INT IDENTITY(1, 1),
     StringValue NVARCHAR(MAX)
    )
  SELECT--initialise the characters to convert hex to ascii
    @characters='0123456789abcdefghijklmnopqrstuvwxyz',
    @SequenceNo=0,--set the sequence no. to something sensible.
  /* firstly we process all strings. This is done because [{} and ] aren't escaped in strings, which complicates an iterative parse. */
    @parent_ID=0;
  WHILE 1=1 --forever until there is nothing more to do
    BEGIN
      SELECT
        @start=PATINDEX('%[^a-zA-Z]["]%', @json collate SQL_Latin1_General_CP850_Bin);--next delimited string
      IF @start=0 BREAK--no more so drop through the WHILE loop
      IF SUBSTRING(@json, @start+1, 1)='"'
        BEGIN --Delimited Name
          SET @start=@Start+1;
          SET @end=PATINDEX('%[^\]["]%',RIGHT(@json, LEN(@json+'|')-@start)collate SQL_Latin1_General_CP850_Bin);
        END
      IF @end=0 --no end delimiter to last string
        BREAK --no more
      SELECT @token=SUBSTRING(@json, @start+1, @end-1)
      --now put in the escaped control characters
      SELECT @token=REPLACE(@token, FROMString, TOString)
      FROM
        (SELECT
          '\"' AS FromString,'"' AS ToString
         UNION ALL SELECT'\\', '\'
         UNION ALL SELECT'\/', '/'
         UNION ALL SELECT'\b', CHAR(08)
         UNION ALL SELECT'\f', CHAR(12)
         UNION ALL SELECT'\n', CHAR(10)
         UNION ALL SELECT'\r', CHAR(13)
         UNION ALL SELECT'\t', CHAR(09)
        ) substitutions
      SELECT @result=0, @escape=1
  --Begin to take out any hex escape codes
      WHILE @escape>0
        BEGIN
          SELECT @index=0,
          --find the next hex escape sequence
          @escape=PATINDEX('%\x[0-9a-f][0-9a-f][0-9a-f][0-9a-f]%', @token collate SQL_Latin1_General_CP850_Bin)
          IF @escape>0 --if there is one
            BEGIN
              WHILE @index<4 --there are always four digits to a \x sequence   
                BEGIN 
                  SELECT --determine its value
                    @result=@result+POWER(16, @index)
                    *(CHARINDEX(SUBSTRING(@token, @escape+2+3-@index, 1),
                                @characters)-1), @index=@index+1 ;
                END
                -- and replace the hex sequence by its unicode value
              SELECT @token=STUFF(@token, @escape, 6, NCHAR(@result))
            END
        END
      --now store the string away 
      INSERT INTO @Strings (StringValue) SELECT @token
      -- and replace the string with a token
      SELECT @JSON=STUFF(@json, @start, @end+1,
                    '@string'+CONVERT(NVARCHAR(5),@@identity))
    END
  -- all strings are now removed. Now we find the first leaf.  
  WHILE 1=1  --forever until there is nothing more to do
  BEGIN
  SELECT @parent_ID=@parent_ID+1
  --find the first object or list by looking for the open bracket
  SELECT @FirstObject=PATINDEX('%[{[[]%', @json collate SQL_Latin1_General_CP850_Bin)--object or array
  IF @FirstObject = 0 BREAK
  IF (SUBSTRING(@json, @FirstObject, 1)='{')
    SELECT @NextCloseDelimiterChar='}', @type='object'
  ELSE
    SELECT @NextCloseDelimiterChar=']', @type='array'
  SELECT @OpenDelimiter=@firstObject
  WHILE 1=1 --find the innermost object or list...
    BEGIN
      SELECT
        @lenJSON=LEN(@JSON+'|')-1
  --find the matching close-delimiter proceeding after the open-delimiter
      SELECT
        @NextCloseDelimiter=CHARINDEX(@NextCloseDelimiterChar, @json,
                                      @OpenDelimiter+1)
  --is there an intervening open-delimiter of either type
      SELECT @NextOpenDelimiter=PATINDEX('%[{[[]%',
             RIGHT(@json, @lenJSON-@OpenDelimiter)collate SQL_Latin1_General_CP850_Bin)--object
      IF @NextOpenDelimiter=0 
        BREAK
      SELECT @NextOpenDelimiter=@NextOpenDelimiter+@OpenDelimiter
      IF @NextCloseDelimiter<@NextOpenDelimiter 
        BREAK
      IF SUBSTRING(@json, @NextOpenDelimiter, 1)='{'
        SELECT @NextCloseDelimiterChar='}', @type='object'
      ELSE 
        SELECT @NextCloseDelimiterChar=']', @type='array'
      SELECT @OpenDelimiter=@NextOpenDelimiter
    END
  ---and parse out the list or name/value pairs
  SELECT
    @contents=SUBSTRING(@json, @OpenDelimiter+1,
                        @NextCloseDelimiter-@OpenDelimiter-1)
  SELECT
    @JSON=STUFF(@json, @OpenDelimiter,
                @NextCloseDelimiter-@OpenDelimiter+1,
                '@'+@type+CONVERT(NVARCHAR(5), @parent_ID))
  WHILE (PATINDEX('%[A-Za-z0-9@+.e]%', @contents collate SQL_Latin1_General_CP850_Bin))<>0 
    BEGIN
      IF @Type='Object'--it will be a 0-n list containing a string followed by a string, number,boolean, or null
        BEGIN
          SELECT
            @SequenceNo=0,@end=CHARINDEX(':',' '+@contents)--if there is anything, it will be a string-based name.
          SELECT  @start=PATINDEX('%[^A-Za-z@][@]%',' '+@contents collate SQL_Latin1_General_CP850_Bin)--AAAAAAAA
          SELECT @token=SUBSTRING(' '+@contents, @start+1, @End-@Start-1),
            @endofname=PATINDEX('%[0-9]%', @token collate SQL_Latin1_General_CP850_Bin),
            @param=RIGHT(@token,LEN(@token)-@endofname+1)
          SELECT
            @token=LEFT(@token, @endofname-1),
            @Contents=RIGHT(' '+@contents,LEN(' '+@contents+'|')-@end-1)
          SELECT  @name=stringvalue FROM @strings
            WHERE string_id=@param --fetch the name
        END
      ELSE 
        SELECT @Name=null,@SequenceNo=@SequenceNo+1 
      SELECT
        @end=CHARINDEX(',', @contents)-- a string-token, object-token, list-token, number,boolean, or null
      IF @end=0 
        SELECT  @end=PATINDEX('%[A-Za-z0-9@+.e][^A-Za-z0-9@+.e]%', @Contents+' ' collate SQL_Latin1_General_CP850_Bin)
          +1
       SELECT
        @start=PATINDEX('%[^A-Za-z0-9@+.e][A-Za-z0-9@+.e]%',' '+@contents collate SQL_Latin1_General_CP850_Bin)
      --select @start,@end, LEN(@contents+'|'), @contents  
      SELECT
        @Value=RTRIM(SUBSTRING(@contents, @start, @End-@Start)),
        @Contents=RIGHT(@contents+' ', LEN(@contents+'|')-@end)
      IF SUBSTRING(@value, 1, 7)='@object'
        INSERT INTO @hierarchy
          (NAME, SequenceNo, parent_ID, StringValue,Object_ID, ValueType)
          SELECT @name, @SequenceNo, @parent_ID, SUBSTRING(@value, 8, 5),
            SUBSTRING(@value, 8, 5), 'object'
      ELSE 
        IF SUBSTRING(@value, 1, 6)='@array'
          INSERT INTO @hierarchy
            (NAME, SequenceNo, parent_ID, StringValue,Object_ID, ValueType)
            SELECT @name, @SequenceNo, @parent_ID, SUBSTRING(@value, 7, 5),
              SUBSTRING(@value, 7, 5), 'array'
        ELSE 
          IF SUBSTRING(@value, 1, 7)='@string'
            INSERT INTO @hierarchy
              (NAME, SequenceNo, parent_ID, StringValue, ValueType)
              SELECT @name, @SequenceNo, @parent_ID, stringvalue, 'string'
              FROM @strings
              WHERE string_id=SUBSTRING(@value, 8, 5)
          ELSE 
            IF @value IN ('true','false') 
              INSERT INTO @hierarchy
                (NAME, SequenceNo, parent_ID, StringValue, ValueType)
                SELECT @name, @SequenceNo, @parent_ID, @value, 'boolean'
            ELSE 
              IF @value='null'
                INSERT INTO @hierarchy
                  (NAME, SequenceNo, parent_ID, StringValue, ValueType)
                  SELECT @name, @SequenceNo, @parent_ID, @value, 'null'
              ELSE 
                IF PATINDEX('%[^0-9]%', @value collate SQL_Latin1_General_CP850_Bin)>0 
                  INSERT INTO @hierarchy
                    (NAME, SequenceNo, parent_ID, StringValue, ValueType)
                    SELECT @name, @SequenceNo, @parent_ID, @value, 'real'
                ELSE 
                  INSERT INTO @hierarchy
                    (NAME, SequenceNo, parent_ID, StringValue, ValueType)
                    SELECT @name, @SequenceNo, @parent_ID, @value, 'int'
      if @Contents=' 'Select @SequenceNo=0
    END
  END
INSERT INTO @hierarchy (NAME, SequenceNo, parent_ID, StringValue,Object_ID, ValueType)
  SELECT '-',1,NULL, '', @parent_id-1, @type
--
   RETURN
END

GO

Tags:

SQL Server

TFS Select Multiple Items in Dropdown List by Using Custom Contol "MultiValueControl"

by 6. February 2017 06:01

The TFS standard dropdown list control only allows selecting a single item.  To allow selecting multiple items you can install a custom control.  The MultiValueControl allows selecting multiple items by displaying a checkbox next to each item in the list.  You need to install the control into the TFS server in order to use it on the TFS work item web portal and for use with TFS work items through Visual Studio you need to install the custom control on your PC.  Below are links to the Visual Studio 2013 and 2015 custom controls.

Web Controls Installation - http://witcustomcontrols.codeplex.com (http://witcustomcontrols.codeplex.com/releases/view/620316)

  • Navigate in your browser to the configuration panel for the web extension of TFS: http://servername:8080/tfs/admin/Extensions
  • Click on the '+'-sign and upload the CodePlex.WitCustomControls.MultiValueControl<version>.zip-file, make sure to use the .zip file matching you TFS server version.
  • Enable the extension.

VS2013: https://witcustomcontrols.codeplex.com/downloads/get/865716

VS2015: https://witcustomcontrols.codeplex.com/downloads/get/1629434

WitCustomControlSetup2015-1.3.2.5.zip (200.61 kb)

WitCustomControlSetup2013-1.2.2.0.zip (164.22 kb)

Tags:

TFS Download/Modify/Upload Office Field Mappings for Microsoft Project

by 5. January 2017 15:29

cd %programfiles%\Common Files\microsoft shared\Team Foundation Server\12.0

# Download the mapping file

TFSFieldMapping download /collection:http://az-tfs01:8080/tfs/impac /teamproject:apps /mappingfile:C:\tfs\fieldmappingfile.xml

# Upload the mapping file

TFSFieldMapping upload /collection:http://az-tfs01:8080/tfs/impac /teamproject:apps /mappingfile:"C:\tfs\fieldmappingfile.xml"

 

Tags:

TFS

TFS Add Custom Work Item Type

by 5. January 2017 07:35

The easiest way to create a work item type is to copy an existing one, rename it, and then edit it. In the procedure below, you'll export the Feature work item type and use it as the basis for the Initiative work item type. Throughout the examples, the project name is Phone Saver, and the server name is Fabrikam. The team project collection name is the default name, DefaultCollection.

  1. Open a Command Prompt window in administrator mode and change directories to where Visual Studio (or Team Explorer) is installed.

                  cd %programfiles%\Microsoft Visual Studio 12.0\Common7\IDE
                

    On 64-bit editions of Windows, use %programfiles(x86)%.

  2. Use the witadmin tool to download the Feature work item type definition and save it as Initiative.xml.

                  witadmin exportwitd /collection:"http://fabrikam:8080/tfs/DefaultCollection" /p:"Phone Saver" /n:Feature /f:%userprofile%\documents\Initiative.xml
                
  3. Open the Initiative.xml file, replace <WORKITEMTYPE name="Feature"> with <WORKITEMTYPE name="Initiative">, and update the description.

                  <witd:WITD application="Work item type editor" version="1.0" xmlns:witd="http://schemas.microsoft.com/VisualStudio/2008/workitemtracking/typedef">
                  <WORKITEMTYPE name="Initiative">
                     <DESCRIPTION>Tracks an initiative that will be released with the product. </DESCRIPTION>
                
  4. Edit the Tab element labeled Implementation. Replace <Filter WorkItemType="Product Backlog Item" /> with <Filter WorkItemType="Feature" />. This will show features as children work items of initiatives.

                  <Tab Label="Implementation">
                   <Control Type="LinksControl" Name="Hierarchy" Label="" LabelPosition="Top">
                     <LinksControlOptions>
                        <LinkColumns>
                           <LinkColumn RefName="System.Id" />
                           <LinkColumn RefName="System.Title" />
                           <LinkColumn RefName="System.AssignedTo" />
                           <LinkColumn RefName="System.State" />
                        </LinkColumns>
                        <WorkItemLinkFilters FilterType="include">
                           <Filter LinkType="System.LinkTypes.Hierarchy" FilterOn="forwardname" />
                        </WorkItemLinkFilters>
                        <ExternalLinkFilters FilterType="excludeAll" />
                        <WorkItemTypeFilters FilterType="include">
                           <Filter WorkItemType="Feature" />
                        </WorkItemTypeFilters>
                     </LinksControlOptions>
                   </Control>
                  </Tab>
                
  5. Import the file.

                  witadmin importwitd /collection:"http://fabrikam:8080/tfs/DefaultCollection" /p:"Phone Saver" /f:%userprofile%\documents\Initiative.xml
                

Now that you have an Initiative work item type, you'll want to add a category for initiatives to the set of categories visible in the team project.

  1. Export the Categories definition to an xml file.

                  witadmin exportcategories /collection:"http://fabrikam:8080/tfs/DefaultCollection" /p:"Phone Saver" /f:%userprofile%\documents\categories.xml
                
  2. Open the file and add the Initiative category. Here's an example, where the Initiative category uses the company name to identify it as a customization:

                  <CATEGORY refname="Fabrikam.InitiativeCategory" name="InitiativeCategory">
                  <DEFAULTWORKITEMTYPE name="Initiative" />
                
  3. Just as you did before, import the file.

                  witadmin importcategories /collection:"http://fabrikam:8080/tfs/DefaultCollection" /p:"Phone Saver" /f:%userprofile%\documents\categories.xml
                

Now all that's left to do is to add your initiatives to the hierarchy of work items that make up the portfolio backlog.

  1. Export the process configuration definition to an xml file.

                  witadmin exportprocessconfig /collection:"http://fabrikam:8080/tfs/DefaultCollection" /p:"Phone Saver" /f:%userprofile%\documents\MyProcessConfiguration.xml
                
  2. Open the file and add a PortfolioBacklog section for Initiatives within the PortfolioBacklogs section. At the same time, modify the PortfolioBacklog element for FeatureCategory so that Initiatives will be parent work items for Features.

                  <PortfolioBacklogs>
                  <PortfolioBacklog category="Fabrikam.InitiativeCategory" pluralName="Initiatives" singularName="Initiative">
                  <AddPanel>
                  <Fields>
                  <Field refname="System.Title" />
                  </Fields>
                  </AddPanel>
                  <Columns>
                  <Column width="100" refname="System.WorkItemType" />
                  <Column width="400" refname="System.Title" />
                  <Column width="100" refname="System.State" />
                  <Column width="50" refname="Microsoft.VSTS.Common.BusinessValue" />
                  <Column width="100" refname="Microsoft.VSTS.Scheduling.TargetDate" />
                  <Column width="200" refname="System.Tags" />
                  </Columns>
                  <States>
                  <State type="Proposed" value="New" />
                  <State type="InProgress" value="In Progress" />
                  <State type="Complete" value="Done" />
                  </States>
                  </PortfolioBacklog>
                  <PortfolioBacklog category="Microsoft.FeatureCategory" parent="Fabrikam.InitiativeCategory" pluralName="Features" singularName="Feature">
                
  3. Add the color to use for Initiative to the WorkItemColors section.

                  <WorkItemColor primary="FFFF6600" secondary="FFFEB380" name="Initiative" />
                

    This assigns a bright orange color as the primary color to use in list displays, and a paler orange color to use on the task board and Kanban board.

  4. Import the file.

                  witadmin importprocessconfig /collection:"http://fabrikam:8080/tfs/DefaultCollection" /p:"Phone Saver" /f:%userprofile%\documents\MyProcessConfiguration.xml
                

And you're done! You‘ve added a third backlog level called Initiatives.

 

Reference source: https://msdn.microsoft.com/en-us/library/dn306083(v=vs.120).aspx

Tags:

TFS Change the Maxiumum Allowed File Attachment Size

by 4. January 2017 13:58

http://localhost:8080/tfs/DefaultCollection/WorkItemTracking/v1.0/ConfigurationSettingsService.asmx?op=SetMaxAttachmentSize

Max allowed is 2GB.

SetMaxAttachmentSize, ConfigurationSettingsService

Tags:

TFS

TFS Locate and Delete Unused Custom Fields

by 4. January 2017 12:18

# Get list of all unused fields
witadmin listfields /collection:http://tfs:8080/tfs/collection /unused

# Confirm specific field details
witadmin listfields /collection:http://tfs:8080/tfs/collection /n:FieldName

# Delete field from collection
witadmin deletefield /collection:http://tfs:8080/tfs/collection /n:FieldName

Tags:

TFS

Error Connecting Microsoft Project to TFS Work Items (TF80070)

by 23. December 2016 10:27

TF80070: Team Foundation encountered an error while performing the operation. It is recommended that you save your work and restart the application.

Create winproj.exe.config file with the following contents and put it in the folder contianing winproj.exe (e.g. C:\Program Files\Microsoft Office\Office15)

<configuration>
 <system.diagnostics>
 <switches>
 <add name="General" value="3" />
 </switches>
 <trace autoflush="false" indentsize="3">
  <listeners>
   <add name="winprojExeListener" type="System.Diagnostics.TextWriterTraceListener"
   initializeData="c:\Logs\winprojExeListener.log" />
  </listeners>
 </trace>
 </system.diagnostics>
</configuration>

Tags:

TFS

TFS Customizing Work Item Types

by 21. November 2016 06:40

To customize TFS work item types (i.e. adding custom fields, etc.) you can export the existing work item type definitions to XML files (using the below command line method "witadmin exportwitd"), edit the files and then import back into TFS (using the below command line method "witadmin importwitd").  Editing the XML files can be managed more easily by installing the "Microsoft Visual Studio Team Foundation Server Power Tools" which will then provide you a nice GUI editor inside of Visual Studio (once the power tools are installed simply open one of the exported XML files in Visual Studio and it should display inside the editor).

===============================================================================
Navigate to this path (may differ for your version of Visual Studio:
C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE>
Then run the below commands to export the work item type definitions to XML.    
===============================================================================

witadmin exportwitd /collection:http://tfs01:8080/tfs/COLLECTION_NAME_HERE /p:PROJECT_NAME_HERE /n:"Epic" /f:"c:\temp\TFS_COLLECTION_NAME_HERE_PROJECT_NAME_HERE_Epic.xml"

witadmin exportwitd /collection:http://tfs01:8080/tfs/COLLECTION_NAME_HERE /p:PROJECT_NAME_HERE /n:"Feature" /f:"c:\temp\TFS_COLLECTION_NAME_HERE_PROJECT_NAME_HERE_Feature.xml"

witadmin exportwitd /collection:http://tfs01:8080/tfs/COLLECTION_NAME_HERE /p:PROJECT_NAME_HERE /n:"Product Backlog Item" /f:"c:\temp\TFS_COLLECTION_NAME_HERE_PROJECT_NAME_HERE_Product_Backlog_Item.xml"

witadmin exportwitd /collection:http://tfs01:8080/tfs/COLLECTION_NAME_HERE /p:PROJECT_NAME_HERE /n:"Task" /f:"c:\temp\TFS_COLLECTION_NAME_HERE_PROJECT_NAME_HERE_Task.xml"

witadmin exportwitd /collection:http://tfs01:8080/tfs/COLLECTION_NAME_HERE /p:PROJECT_NAME_HERE /n:"Bug" /f:"c:\temp\TFS_COLLECTION_NAME_HERE_PROJECT_NAME_HERE_Bug.xml"

===============================================================================
At this point you have exported the associated work item types as XML files.
Open each XML file in Visual Studio and edit accordingly.
Then run the below commands to import them back into TFS and apply the updates.
===============================================================================

witadmin importwitd /collection:http://tfs01:8080/tfs/COLLECTION_NAME_HERE /p:PROJECT_NAME_HERE /f:"c:\temp\TFS_COLLECTION_NAME_HERE_PROJECT_NAME_HERE_Epic.xml"

witadmin importwitd /collection:http://tfs01:8080/tfs/COLLECTION_NAME_HERE /p:PROJECT_NAME_HERE /f:"c:\temp\TFS_COLLECTION_NAME_HERE_PROJECT_NAME_HERE_Feature.xml"

witadmin importwitd /collection:http://tfs01:8080/tfs/COLLECTION_NAME_HERE /p:PROJECT_NAME_HERE /f:"c:\temp\TFS_COLLECTION_NAME_HERE_PROJECT_NAME_HERE_Product_Backlog_Item.xml"

witadmin importwitd /collection:http://tfs01:8080/tfs/COLLECTION_NAME_HERE /p:PROJECT_NAME_HERE /f:"c:\temp\TFS_COLLECTION_NAME_HERE_PROJECT_NAME_HERE_Task.xml"

witadmin importwitd /collection:http://tfs01:8080/tfs/COLLECTION_NAME_HERE /p:PROJECT_NAME_HERE /f:"c:\temp\TFS_COLLECTION_NAME_HERE_PROJECT_NAME_HERE_Bug.xml"

Tags:

TFS

Visual Studio Custom Templates

by 26. October 2016 13:21

To delete items from the cache, go to this folder (VS2013): %userprofile%\AppData\Roaming\Microsoft\VisualStudio\12.0\ItemTemplatesCache

Tags:

Visual Studio

Open Multiple xCode Application Instances from Terminal Command

by 25. October 2016 20:34
cd /  
cd Applications
cd Xcode.app
cd Contents/MacOS
sudo ./Xcode

Tags:

Add Existing XCode Project to Local Git Repository from Command Line

by 8. October 2016 12:24

Run terminal editor, navigate to the directory containing the XCode project then run the commands below:

  1. Quit Xcode (may not be necessary but I would do it just in case)
  2. Run Terminal
  3. Get into the project folder directory
  4. find .
  5. Find the file that says "UserInterfaceState.xcuserstate" and copy the entire filename up to the ./
  6. echo "paste the UserInterfaceState.xcuserstate file here" >.gitignore
  7. cat .gitignore
  8. git init
  9. git add .
  10. git commit -m "Initial Build (or whatever you like)"

Tags:

Visual Studio Error Loading TFS - Unexpected End of File

by 21. September 2016 17:08

When changing connections between different TFS servers, my Visual Studio seemed to get stuck with an issue where it would always error out with a message "unexpected end of file." and TFS could not load.  The solution was to delete all folders and files from this directory: C:\Users\USERID_HERE\AppData\Local\Microsoft\Team Foundation

Tags:

TFS | Visual Studio

VBA Script for Visio 2013 to Retrieve User Contact Information from SharePoint 2013 MySites

by 11. September 2016 13:03

Created a VBA code script (included below) to run in Visio and look for objects that have a custom property named "UserRef", taking the corresponding value entered into that custom property (assumed to be a Windows AD user account id) to lookup the users contact information (Name, Title, Department, Email, Phone, Office Location) from the users SharePoint "MySite".  Also, adds a hyperlink to the object that points to the users SharePoint MySite.  In my case I was using Visio 2013 and SharePoint 2013.

Sub PopulateUserInfoObjects()

    Dim page As Integer, pages As Integer, shape As Integer, shapes As Integer
    page = 1
    pages = Application.ActiveDocument.pages.Count
    
    While page <= pages
        Application.ActiveWindow.page = Application.ActiveDocument.pages(page)
        page = page + 1
        shape = 1
        shapes = Application.ActiveWindow.page.shapes.Count
        Debug.Print Application.ActiveWindow.page.name & " has " & shapes & " shapes"
        While shape <= shapes
            Dim visioShape As Visio.shape
            Set visioShape = Application.ActiveWindow.page.shapes(shape)
            Dim userRef As String
            userRef = GetCustomPropertyValue(visioShape, "UserRef")
            If userRef <> "" Then
                Dim chars As Visio.Characters
                Set chars = visioShape.Characters
                chars.Text = GetUserInfoFromIntranet(userRef, visioShape)
            End If
            shape = shape + 1
        Wend
    Wend

End Sub

Function GetUserInfoFromIntranet(userId As String, addHyperlink As Visio.shape)
    
    ' Required references:
    '   Microsoft Internet Controls
    '   Microsoft Shell Controls and Automation
    
    ' The InternetExplorerMedium object is required instead of InternetExplorer object 
    ' to avoid the following exception:
    '   Run-time error '-21474178848 (80010108)':
    '   Automation Error
    '   The object invoked has disconnected form its clients.
    
    Dim IE As InternetExplorerMedium
    Dim targetURL As String
    Dim webContent As String
    Dim sh
    Dim eachIE
    
    targetURL = "http://SHAREPOINT_MYSITES_URL_HERE/Person.aspx?accountname=DOMAIN_NAME_HERE%5C" & userId
    Set IE = New InternetExplorerMedium
    IE.Visible = False
    IE.Navigate targetURL
    
    While IE.Busy
      DoEvents
    Wend
    
    Do
      Set sh = New Shell32.Shell
      For Each eachIE In sh.Windows
        If InStr(1, eachIE.LocationURL, targetURL) Then
          Set IE = eachIE
            'In some environments, the new process defaults to Visible.
            IE.Visible = False  
          Exit Do
          End If
        Next eachIE
      Loop
    Set eachIE = Nothing
    Set sh = Nothing
    
    While IE.Busy  ' The new process may still be busy even after you find it
      DoEvents
    Wend
      
    Dim name As String
    name = IE.Document.getElementById("ctl00_PictureUrlImage_NameOverlay").innerHTML
    Dim title As String
    title = IE.Document.getElementById("ProfileViewer_ValueTitle").innerHTML
    Dim dept As String
    dept = IE.Document.getElementById("ProfileViewer_ValueDepartment").innerHTML
    Dim email As String
    email = IE.Document.getElementById("ProfileViewer_ValueWorkEmail").innerHTML
    Dim phone As String
    phone = IE.Document.getElementById("ProfileViewer_ValueWorkPhone").innerHTML
    Dim office As String
    office = IE.Document.getElementById("ProfileViewer_ValueOffice").innerHTML

    On Error Resume Next
    DeleteHyperlinks addHyperlink
    AddHyperlinkToShape addHyperlink, targetURL
 
    name = name & Chr(10) & title & Chr(10) & phone & Chr(10) & email 
    name = name & Chr(10) & dept & Chr(10) & "Location: " & office
    GetUserInfoFromIntranet = name 

End Function

Function GetCustomPropertyValue(TheShape As Visio.shape, ThePropertyName As String) As String
    Dim value As String
    If TheShape.CellExistsU("Prop." & ThePropertyName, 0) Then
        GetCustomPropertyValue = TheShape.CellsU("Prop." & ThePropertyName).ResultStr(visNone)
    Else
        GetCustomPropertyValue = ""
    End If
End Function

Sub AddHyperlinkToShape(shape As Visio.shape, url As String)
    Dim link As Visio.Hyperlink
    Set link = shape.Hyperlinks.Add
    link.IsDefaultLink = False
    link.Description = ""
    link.Address = url
    link.SubAddress = ""
End Sub

Sub DeleteHyperlinks(shape As Visio.shape)
    Dim i As Integer
    i = 1
    While i < shape.Hyperlinks.Count
        shape.Hyperlinks.ItemU(i).Delete
    Wend
End Sub

Tags:

Sharepoint | VBA Script | Visio

Extract PDF File(s) from Adobe PDF Portfolio File Using iTextSharp Open Source PDF Library

by 28. August 2016 07:23

Using iTextSharp open source PDF library, the below console application illustrates opening one or more PDF files (based on file path and file mask inputs) and extracting a desired single PDF file from each.

using iTextSharp.text.pdf;
using System;
using System.Collections.Generic;
using System.IO;

namespace PdfPortfolioSample
{
  class Program
  {
    static void Main(string[] args)
    {
      Console.Write("Enter source path: ");
      string sourcePath = Console.ReadLine();
      Console.Write("Enter file mask (e.g. *.pdf): ");
      string fileMask = Console.ReadLine();
      Console.Write("Recursive (y/n): ");
      bool recursive = Console.ReadLine().ToUpper() == "Y";
      Console.Write("Enter target path: ");
      string targetPath = Console.ReadLine();
      Console.Write("Enter document name to extract (e.g. MLPA.PDF): ");
      string docName = Console.ReadLine();
      List<string> files = GetFiles(sourcePath, fileMask, recursive);
      foreach (string file in files)
      {
        GetPdfFromPortfolio(file, targetPath, docName);
      }
    }
    private static void GetPdfFromPortfolio(string filePath, string targetPath, string docName)
    {
      PdfReader reader = new PdfReader(filePath);
      PdfDictionary root = reader.Catalog;
      PdfDictionary documentnames = root.GetAsDict(PdfName.NAMES);
      PdfDictionary embeddedfiles =
          documentnames.GetAsDict(PdfName.EMBEDDEDFILES);
      PdfArray filespecs = embeddedfiles.GetAsArray(PdfName.NAMES);
      for (int i = 0; i < filespecs.Size;)
      {
        filespecs.GetAsString(i++);
        PdfDictionary filespec = filespecs.GetAsDict(i++);
        PdfDictionary refs = filespec.GetAsDict(PdfName.EF);
        foreach (PdfName key in refs.Keys)
        {
          PRStream stream = (PRStream)PdfReader.GetPdfObject(
            refs.GetAsIndirectObject(key)
          );

          if (filespec.GetAsString(key).ToString().ToUpper() == docName.ToUpper())
            using (FileStream fs = new FileStream(
              targetPath + @"\" + Path.GetFileName(filePath).Substring(0, 10) + filespec.GetAsString(key).ToString(), FileMode.OpenOrCreate
            ))
            {
              byte[] attachment = PdfReader.GetStreamBytes(stream);
              fs.Write(attachment, 0, attachment.Length);
            }
        }
      }

    }
    private static List<string> GetFiles(string path, string fileMask = "", bool recursive = false, List<string> files = null)
    {
      if (files == null) files = new List<string>();
      try
      {
        foreach (var file in Directory.GetFiles(path, fileMask))
        {
          files.Add(file);
        }
        if (recursive)
          foreach (string dir in Directory.GetDirectories(path))
          {
            GetFiles(dir, fileMask, recursive, files);
          }
      }
      catch (System.Exception e)
      {
        Console.WriteLine(e.ToString());
      }
      return files;
    }
  }
}

Tags:

C# | iTextSharp | PDF

Configuring and Running Azure Powershell (for Azure Classic and Azure Resource Manager) on Windows Using Nuget

by 22. August 2016 07:57

Run Windows Powershell ISE as Administrator:
PS > Set-ExecutionPolicy RemoteSigned
PS > Import-Module PowerShellGet
PS > Install-Module Azure (Classic)
PS > Install-Module AzureRM (Resource Manager)

# To make sure the Azure PowerShell module is available after you install
Get-Module –ListAvailable 

# To login to Azure Resource Manager
Login-AzureRmAccount

# You can also use a specific Tenant if you would like a faster login experience
# Login-AzureRmAccount -TenantId xxxx

# To view all subscriptions for your account
Get-AzureRmSubscription

# To select a default subscription for your current session
Get-AzureRmSubscription –SubscriptionName “your sub” | Select-AzureRmSubscription

# View your current Azure PowerShell session context
# This session state is only applicable to the current session and will not affect other sessions
Get-AzureRmContext

# To select the default storage context for your current session
Set-AzureRmCurrentStorageAccount –ResourceGroupName “your resource group” –StorageAccountName “your storage account name”

# View your current Azure PowerShell session context
# Note: the CurrentStorageAccount is now set in your session context
Get-AzureRmContext

# To list all of the blobs in all of your containers in all of your accounts
Get-AzureRmStorageAccount | Get-AzureStorageContainer | Get-AzureStorageBlob

Tags:

Azure

Restart IIS Web Site from C# Code

by 24. April 2016 04:58

In some cases I have setup caching on the website for items such as menus, header, footer, etc.  However, when there is a CMS in place on the site and a user changes any of that relevant content there needs to be a way to reset the web cache.  One easy way is to force the IIS web site to restart by making a benign change in the web.config file, which will automatically force the restart.  Below is a sample version of code to do this, where I update an otherwise unused entry in the web.config that just indicates the last date/time of restart request by the user.  In the case of an MVC application I put this into a controller with some specific route provided to the CMS users so they can navigate to that route after making CMS changes that need to be updated in the cache.  As a side note, using this method will require granting write access to the web.config file for the IIS application pool user (by default "IIS AppPool\WebSiteName" user).

    public static void RestartWeb()
    {
      var configuration = WebConfigurationManager.OpenWebConfiguration("~");
      var section = (AppSettingsSection)configuration.GetSection("appSettings");
      section.Settings["LastRestart"].Value = 
        DateTime.Now.ToShortDateString() + " " + DateTime.Now.ToLongTimeString();
      configuration.Save();
    }

Tags:

ASP.Net | C#

Change the "SharePoint" Text in the Ttop Left Corner of SharePoint 2013 Site

by 20. April 2016 11:04

To change the text you can use PowerShell with the sample code snippet shown below.  NOTE: To use PowerShell for SharePoint make sure add the snapin (Add-PSSnapIn Microsoft.SharePoint.Powershell).

PowerShell Script Sample:

$webApp = Get-SPWebApplication http://MySiteUrlHere; $webApp.SuiteBarBrandingElementHtml = "<a href='/'>My Site Title Here</>"; $webApp.Update(); 

Tags:

Sharepoint

BlogEngine.Net Using TinyMCE Allow User to Paste Image Directly Onto Page

by 2. April 2016 09:18

By default the TinyMCE configuration in a standard BlogEngine.Net implementation may not be setup to allow users to paste images directly from their clipboard onto the page.  To make sure this feature is enabled, go to the "admin/editors/tinymce/editor.js" and add the two lines listed below into the tinymce.init method (sample of a full view of the method also shown below):

browser_spellcheck: true,
paste_data_images: true,

For any editor customization, check TinyMce website for plugins: https://www.tinymce.com/docs/plugins/paste/

tinymce.init({
    selector: '#txtContent',
    plugins: [
        "advlist autolink lists link image charmap print preview anchor",
        "searchreplace visualblocks code fullscreen textcolor imagetools",
        "insertdatetime media table contextmenu paste sh4tinymce filemanager"
    ],
    toolbar: "styleselect | bold underline italic | alignleft aligncenter alignright | bullist numlist | forecolor backcolor | link media sh4tinymce | fullscreen code | filemanager",
    autosave_ask_before_unload: false,
    max_height: 1000,
    min_height: 300,
    height: 500,
	browser_spellcheck: true,
	paste_data_images: true,
    menubar: false,
    relative_urls: false,
    browser_spellcheck: true,
    setup: function (editor) {
        editor.on('init', function (e) {
            if (htmlContent) {
                editor.setContent(htmlContent);
            }
        });
    }
});

Tags:

BlogEngine.NET

Setup Git Repo on Digital Ocean Droplet

by 2. April 2016 06:38

This tutorial will show you how to set up a fully fledged Git server using SSH keys for authentication. It will not have a web interface, this will just cover getting Git installed and your access to it set up. We'll use the host "git.droplet.com" in place of the domain you will use for your VPS.

This can be a great option if you want to keep your code private while you work. While open-souce tends to be the status quo, there are some times when you don't want to have your code freely available. An example would be if you are developing a mobile app, especially a paid one. Keep in mind this code can be read by anyone if they know the URL address to use for a clone, but that is only if they know it.

There is one major concern for many and that is a web interface to your repositories. GitHub accomplishes this amazingly well. There are applications that you can install such as Gitosis (https://wiki.archlinux.org/index.php/Gitosis), GitList (http://gofedora.com/insanely-awesome-web-interface-git-repos/), and Goblet (http://git.kaarsemaker.net/). We don't go over those in this tutorial, but if you rely heavily on a graphic interface then you may want to look over those and think about installing one of them as soon as you done installing your Git server.

Next, the VPS will need a user specifically for Git. Most people will simply create a user called "Git", and that is what we'll do for this tutorial but feel free to name this user whatever you'd like.

 

Setup a Git User and Install Git on your VPS

Log into your VPS, and gain root*:

 

su -

*Some people feel uncomfortable using root in this manner. If your VPS is set up to use sudo, then do so.

 

Add the Unix user (not necessarily Git user names) to handle the repositories:

 

useradd git

Then give your Git user a password:

 

passwd git

Now it's as easy as:

 

CentOS/Fedora: yum install git

Ubuntu/Debian: apt-get install git

Add your SSH Key to the Access List

At this point, you'll want to be logged in as the Git user. If you haven't already logged in to that user, use this command to switch to it:

 

su git

Now you need to upload your id_rsa.pub file to your Git user's home directory. Once you have done that, we need let the SSH daemon know what SSH keys to accept. This is done using the authorized keys file, and it resides in the dot folder "ssh". To create this, input:

 

mkdir ~/.ssh && touch ~/.ssh/authorized_keys

Note: Using the double '&' in your command chains them, so it tells the system to execute the first command and then the second. Using the 'tilde' at the beginning of the path will tell the system to use your home directory, so '~' becomes /home/git/ to your VPS.

 

We are going to use the 'cat' command, which will take the contents of a file and return them to the command line. We then use the '>>' modifier to do something with that output rather than just print it in your console. Be careful with this, as a single '>' will overwrite all the contents of the second file you specify. A double '>' will append it, so make sure you know what you want to do and in most cases it will be easier to just use ">>" so that you can always delete what you append rather than looking to restore what you mashed over.

 

Each line in this file is an entry for a key that you wish to have access to this account. To add the key that you just uploaded, type the following, replacing :

 

cat .ssh/id_rsa.pub | ssh user@123.45.56.78 "cat >> ~/.ssh/authorized_keys"

Now you can see the key there if you use cat on the authorized key file:

 

cat ~/.ssh/authorized_keys

If you want to add others to your access list, they simply need to give you their id_rsa.pub key and you append it to the authorized keys file.

 

Setup a Local Repository

This is a pretty simple process, you just call the Git command and initialize a bare repository in whichever directory you'd like. Let's say I want to use "My Project" as the project title. When creating the folder, I'd use all lower case, replace any spaces with hyphens, and append ".git" to the name. So "My Project" becomes "my-project.git".

 

To create that folder as an empty Git repository:

 

git init --bare my-project.git

Thats it! You now have a Git repository set up on your VPS. Let's move on to how to use it with your local computer.

 

Using your Git Server from your Local Computer

On Linux or Mac OS, you need to change the remote origin to your newly created server. If you already have a local repo that you want to push to the server, change the remote using this command:

 

git remote set-url origin git@git.droplet.com:my-project.git

If this is a new repository you are setting up, use this:

 

git init && git remote add origin git@git.droplet.com:my-project.git

Now you may add, push, pull, and even clone away knowing that your code is only accessible to yourself.

 

But what if you want a few trusted people to have access to this server and you want to keep things simple by sorting them by the names of your users? A simple and effective way to do that is to create a folder named after each person, so in the home folder for your Git user list, input:

 

mkdir user1 user2

Now when you specify the remote repository, it would look like this:

 

git remote add origin git@git.droplet.com:user1/user-project.git 

Step 1: Create SSH Public/Private Key Using PuTTY 

1. Download and start the puttygen.exe generator (download location: http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html).

2. In the "Parameters" section choose SSH2 DSA and press Generate.

3. Move your mouse randomly in the small screen in order to generate the key pairs.

4. Enter a key comment, which will identify the key (useful when you use several SSH keys).

5. Type in the passphrase and confirm it. The passphrase is used to protect your key. You will be asked for it when you connect via SSH.

6. Click "Save private key" and then "Save public key" to save both keys to your disk.

 

Tags:

Windows Task Scheduler Create Web Request (Web Site Keep Alive)

by 26. March 2016 18:09

Add Windows Schedule and from the "Actions" tab, select "Start a program" dropdown and enter "powershell" (without the quotes) in the "Program/script:" text box then enter a command like the one below in the "arguments" text box:

-Command "Get-Date > c:\pathToLogFile.txt; $req = [System.Net.WebRequest]::Create(\"http://url\"); $res = $req.GetResponse(); $str = $res.GetResponseStream(); $rdr = new-object System.IO.StreamReader $str; $dat = $rdr.ReadToEnd(); $dat >> c:\pathToLogFile.txt; Get-Date >> c:\pathToLogFile.txt;"

Powershell HTTP Request

$r = [System.Net.WebRequest]::Create("http://url/")
$resp = $r.GetResponse()
$reqstream = $resp.GetResponseStream()
$sr = new-object System.IO.StreamReader $reqstream
$result = $sr.ReadToEnd()
write-host $result

Username and passwords
$creds = new-object System.Net.NetworkCredential "username", "password"
$uri = mew-object System.Uri "http://url/"
$credcache = new-object System.Net.CredentialCache
$credcache.Add($uri, "Basic", $creds)
$webrequestobject.Credentials = $credcache

One Liner Version
Powershell -Command "$r = [System.Net.WebRequest]::Create('http://url/'); $resp = $r.GetResponse(); $respstream = $resp.GetResponseStream(); $sr =
new-object System.IO.StreamReader $respstream; $result = $sr.ReadToEnd(); write
-host $result"

Tags:

PowerShell