Wednesday, December 14, 2016

How to Really Pay Programmers Less
By: Larry Eisenstein

About a week ago, I was perusing my Google news feed on my phone and it was an article that was titled, “How to Pay Programmers Less”.  Naturally, I was intrigued, so I clicked the link and began reading.  As it turned out, it was a satirical piece that took some of the most popular ‘gimmicks’ companies are using today to pretend like they are modern, hip and cool and saying they could use these cheap ‘perks’ to get developers to accept less pay.  Ha….ha….  It’s funny because there is some truth to it.  The article was by Yegor Bugayenko (http://www.yegor256.com/2016/12/06/how-to-pay-programmers-less.html).

So, I thought I would write a counter article describing how you can REALLY pay developers less.  This won’t work with all developers because some are only concerned with the bottom line, but a surprisingly high number of others will take less.  My theory, counter intuitively says it’s some of the more experienced developers that this will work with.

Training
Some developers really love what they do.  So much so that they actually spend their own time (and money) cultivating their skills.  Training is so inexpensive these days, there is very little reason NOT to pay for this.  Have a couple open memberships to sites like PluralSight, Udemy, Lynda.com, and offer time off if there is a local conference.  This will only cost a few hundred dollars and will pay off in loyalty and increased productivity.
Also, promote learning by encouraging Meetups, pair programming, lunch & learns, and mentoring.  Don’t allow overzealous employees to step new programmers.  Base senior developer appraisals on how well they mentor junior programmers.  If a developer improves their productivity an amazing 10% every year, this would pale in comparison to a developer that could improve all his colleague’s performance by 2-3% per year.  This would be like the magic of compound interest, but for work productivity.

WFH
Working from home is becoming a huge deal.  It’s getting so big, many developers are skipping companies that do not have at least some sort of regular WFH policy in place.  Employees spend countless hours in traffic and are then expected to produce great code, in high stress, frantic, loud environments.  This is so insane and some developers have realized they are less stressed and produce more and better code when they are in the comforts of their home office. 
This is a no brainer.  You get happier, more productive employees and you can save money on office space too.  The draw back?  It does take a certain level of trust and good management to handle this.  You must be willing to punish or terminate any employee that takes advantage of the policy and resist the easy, knee-jerk reaction to take it away from everyone.



Appreciation
This is a big one and it’s not something you can find out about an employer during an interview.  Show appreciation to your employees for good work.  Go overboard in your praise and look for things to praise people about.  Don’t play favorites, just dole praise out to everyone that does a good job.  Don’t hold out to the end of the year; praise early, praise specifically, and praise often.  This is really where Dale Carnegie got it right in his book, “How to Win Friends and Influence People”.
Listen to and implement suggestions.  You are paying smart people a lot of money.  Why are you not taking and implementing their advice?  Because it will take a little time or money or you found one drawback after seeing 10 benefits?  Everyone understands not all ideas can be implemented, but if you continuously hold back (or even worse, take credit for) ideas, good people will leave.  Don’t get stuck in this trap.

Tools
This is probably one of the cheapest ways to increase employee morale and productivity at the same time.  Why are you frustrating your developers by giving them slow, outdated machines and not providing them with software that will make their jobs easier and more enjoyable?  There are tools out there that cost less than $100 and can literally save days of manual labor.  Why are you paying developers $100k or more and then having them spend 3 days writing some software that has already been created and can be purchased for $49?
Also, buy your developers good machines.  There is nothing more frustrating than writing some great code, and then having to wait 2-3 minutes for the test tools to start or for the website to come up.  For an extra few hundred dollars, you can have happier more productive developers.  Considering this machine will last 3 years, this is a inexpensive investment.

Environment
Joel’s Rule #8: Provide your developers with quiet, distraction free environment.  Joel describes the issue, so I won’t rehash it (https://www.joelonsoftware.com/2000/08/09/the-joel-test-12-steps-to-better-code/).  This problem is getting more serious with these idiotic “open space” office designs and unfortunately managers are eating this crap up.  They see they can fit more employees in a smaller space and then they allow some dumb consultant to convince them that this is a collaborative environment.  This might work for some types of work, but I’ve met very, very few developers that are OK with this setup.  We are though workers and we need quiet time to think.


Ok, now that I have gotten that off my chest, let’s take a slight detour back into reality.  I’ve been around long enough there is no magic “employee satisfaction” pill and some of these things are harder to implement than others.  I doubt there is a workplace out there that does a great job at all of these things, all the time.  But, if you can do 2 or 3 items from this article, you are WAY ahead of the game.  The great thing about these suggestions is they are not expensive (some even free) and it will make employees happier and more productive.

Sunday, September 13, 2015

HackHands Review

Recently, there seems to be several companies appear that are offering developer help and mentoring services.  I've been wanting a service like this for a long time since I've never had the opportunity to work with a mentor or even work with a more senior developer at any of my previous jobs.  This is a great idea and I wanted to fully support any company that would offer a service like this.  Since there aren't many reviews out there, I decided to try a few companies to see who I liked the best.  I started with HackHands since they were bought by PluralSight, another company I use for training videos.


Initial Sign Up  

Once you sign up, you can purchase credits that can be used to purchase time with an Expert.  Their dashboard is very simple and it seems you only have one way to interact with their Experts.  You put in a request with a description and the category (language) along with some tags.  You can then choose the maximum rate you are willing to pay.  Since you pay by the minute, you can choose anywhere from $1/minute to $5/minute.  They notify their experts that accept $1/minute and if no one responds, they move up the scale until they hit your max rate.  You have no way of searching for Experts or choosing a specific Expert unless you have worked with them in the past.  

They offer a 'Test' setup of your environment with the screen/video sharing software so you will know it works before scheduling a meeting.  This is supposed to make sure there are no technical difficulties once you start the meeting since you are paying by the minute and as soon as you connect, you are billed according to the timer.  I went through the process and everything seemed to be working fine.  The audio and video on the test were very high quality and I installed all the appropriate plugins.  Also, if you cancel within 5 minutes, you do not get charged.


Experience

My first experience with HackHands was mixed.  I am new to EF and Async programming and I had a simple problem with some code and I needed some clarification on how to use Async/Await.  I put in a request describing the problem and I was taken to a 'Wait' screen while they sent the request out.  While you are waiting, you can play a game or they have some sort of Desktop notification application you can install.  The screen said it might take up to 15 minutes to find the Expert.  They found someone for me in about 10 minutes and the session timer began.


Once the session began we started having some technical issues with audio.  I think it may have been with him having a laptop microphone and a headset microphone, but I'm not sure.
Our session was 13 minutes at $1/minute.  I would say a good 6 minutes of this time was spent trying to hear/understand each other and get the screen sharing done correctly.  We never got the audio issues completely fixed, but it was good enough to hear if I closed the door, listened carefully and asked him to speak up.

Once we got going, he was able to see what I was doing wrong in my code and helped me fix it immediately.  Then he gave me some background into async/await, but because of the audio issues I only got about half of what he said.  Over all, I was impressed with the Expert, but not happy about the connection issues.  Seeing that we had those issues, it would have been nice if he had 'Paused' the timer while we were figuring out the audio/connection issues.

After finishing the session, they asked me for a review.  I mentioned the technical problems, but their response was I should have stopped the session before the 5 minute mark so I wouldn't get charged.  I did not do this because by the time we got to 5 minutes, the problem was almost resolved.  I think this was poor customer service, but to be fair I was not using my own money.  I had received some free credits by signing up during one of their email marketing campaigns.


Conclusion  

I was pleased with the knowledge of the Expert, but technical problems and mediocre customer service made this a mixed experience.  Also, I don't like that you have no ability to pick/choose experts or even review them prior to the match up.  They could have great Experts available, but you may never get to talk to them because all their low level 'experts' keep accepting your request before your bid gets high enough for a real 'Expert' to accept it.  Also, their service seems to be focused on one-time, by the minute interactions.  I'd like for them to have an hourly rate where YOU could choose the Expert and not worry about the clock ticking away.

Thursday, November 21, 2013

9 Killer Questions to Ask an Interviewer

  1. How would you describe the general culture of the company and the workplace?
    • Personalities at a company are important.  If you don't like your co-workers and how management treats their employees, going to work will be painful.
  2. Why did you choose this company?
    • This is a good, subtle question.  Does the interviewer pause, or answer quickly?  Are they enthusiastic/passionate about the answer, or does it take them a while to fumble through an answer?  If they have to think long and hard to come up with something good about their company, this can be a red flag.  If you've ever worked at a company you were passionate about, you will be able to answer this quickly.
  3. Will there be any form of training provided?
    • With diminishing training budgets, its nice to work for a company that provides more than a log in to a site that provides Word and Excel training videos.
  4. What are some of the biggest challenges/successes facing the department currently?
    • This will help you understand the culture and see where you might face some hurdles in the future. 
  5. What process will be used to evaluate my employee performance?
    • It's good to know up-front, how you will be graded on performance
  6. Who will be my direct supervisor?
  7. Are there many opportunities for professional development within the company?
    • Again, training and being able to work with new technologies may be important to you.
  8. What is the usual time frame for making the hiring decision?
    • Everyone should ask this to show interest in the position and let them know you may be on the market for a limited time.
  9. May I contact you if any further questions arise?
    • It's good to follow up and try to remember the names of key people.

I'm adding a few questions of my own that will help determine if this is a job you really WANT
  • What causes you the MOST frustration within the company?
    • Try to find out where your future frustrations are going to come from and is it acceptable to you? 
  • If you could change 1 thing in the company (that would not cost a lot), what would it be?
    • Try to gauge how happy their current employees are.
  • Can you describe an advantage to working for  this company that you have NOT had at previous employers?
    • Again, the employee of a good company can quickly rattle off a few things.
  • As close as possible, describe the "perfect" personality traits of a candidate you would like to hire.
    • This question will help you determine their expectations for you.
  • Describe some of the personal traits of former [or current] employees that you do not like.
    • This one will 'really' let you know what their pet peeves are and help you determine what they really want in an employee.  If they mention they hate 'clock watchers' or they don't like to 'hand hold' people through learning, that "could" be some clues to issues they have had with previous employees that they will be sensitive to.

 

Wednesday, October 2, 2013

Developer Take Aways from Monster and CareerBuilder Access


I've had this posting in a Word document for a while, and finally, I'm getting around to publishing it.  A while ago, I was involved in the searching and recruiting of a new developer for our group.  We were given access to Monster and Careerbuilder to facilitate the search since our HR department had no clue how to sort out all the skills we were looking for.

Well, it was an eye opening experience, and I thought I'd share a few things I learned from this process.

1.       Make a small change to your resume every week to stay on top.  The default filter works by how recently you have updated your resume.  Usually, people will choose resumes updated within the past week, month, or 3 months.
2.       Put some buzz words in your Monster profile, if you have any decent experience (NOT in your resume, which I’ll talk about later).  It will get you more hits, but some of the hits may not be jobs you want, so carefully filter out jobs that don’t fit your skill set.
3.       Put down some lesser known technologies you’ve worked with in case someone wants to key in on that technology. (Like DotNetNuke, Mojo Portal, Kronos, etc).  A company may not be looking for a Mojo Portal developer, but if you know it, they may view that as a bonus and choose to give you an interview over the other 10K .NET developers out there.
4.       It’s hard to search by experience level and/or salary, so don’t feel the need to put salary requirements.  Use your title to let people determine that (like Junior or Senior).
5.       Make sure you have a descriptive  title and a target job title.  I can’t tell you how many resume’s I skipped because it said, “Joe Smith’s Resume” and had no target job title.  Monster is VERY slow at times and sometimes I just didn’t want to click on the link because I know it takes so long to pull up.
6.       Some companies want a Mid Level [or Senior] developer, but find out later that they can only afford a Junior Level [or Mid Level] person.  Don’t let titles scare you away, but be up front about your skills when applying for these jobs.  Be completely honest and transparent about what you have done and what you have not done.
7.       Recruiter fees DEFINITELY play a role in a hiring decision.  I personally know that I lost out on a position because the other candidate applied directly.   If you come from a recruiter, there is a 20%-25% markup.  You may be better than the other person, but if you are going to cost the company about $15K- $30K more (for similar skills), that can be a deciding factor if its close.
8.       Keep your certifications up (if you can), because when all else fails, acronyms are easy to search on AND the person doing the searching may have no clue what they mean.  You can tell me 100 stories about how certifications mean nothing, but for me it does three things:
a.       Gives me an easy way to search for a developer vs. some guy that knows the keywords I am searching for. (I’ve seen so many DBAs put Java and C# on their resume because they took a class in college or wired up a DataGrid to a table on a WinForm one time).
b.      Tells me the person is somewhat dedicated to their career.  Dedicated enough to study a book and take a test.  I put this in the same category as people that attend user group meetings for a particular technology.  You may not know much, but at least I know you care about your career enough to dedicate your own time/money to get the certification.  I know plenty of developers that go home and never touch a computer and have no side projects (a minus to me).
c.       They may just be learning monotonous details, but I’ve run into situations where a senior network engineer didn’t know a lot of the details of security policies that an MCSE would have known (and it ended up wasting 2 days troubleshooting a simple issue because of this).
9.        A cover letter is NOT important on Monster.  At least in my experience.  Disagree if you want.
10.   Get a skill that NOT everyone has.  There are a million .NET programmers out there at all levels and for all salaries.  So, learn some stuff like Perl, Python, RoR, Grails, Scala, etc.
11.   If you are a Web Developer, have some sort of public website, even if it’s just an online resume (and try to make it look decent).  I can’t believe you’ve been building websites/web applications for 6 years, but you’ve never created a public website.  That just shows lack of ambition.
12.   Putting special characters ( like the accented ‘e’ on Resume or a ‘tilde-n’ if you have a Hispanic name) in your resume’s file name can make it so it cannot be opened on some computers.
13.   Key in on some business terms to get Managers to take notice.  In healthcare, you could use: EDI, HL7, PQRI, etc.  We all know computers don’t care about what data they are displaying, but this excites managers to know that you may have some knowledge of their field that you can share with them (or that they don’t have to teach you).
14.   MOST IMPORTANTLY:   Don’t put things on your resume unless you can answer questions about them.  Use your Monster profile to add keywords/buzz words, but don’t put them on your resume because I’m GOING to ask you about them (while you are in front of me).  If I ask you a question about something on your resume and you can’t answer it at all, that makes you look like a liar.  I’d rather teach someone how to program than teach them how to be ethical.

Friday, May 31, 2013

Fixing CORS issue in Web API: "Origin is not allowed by Access-Control-Allow-Origin"

For security reasons browsers prohibit AJAX calls to Web API service outside the existing site. This means you can't provide a service exposed by Web API to a site on another domain. This is called Cross Origin Resource Sharing (CORS).

This problem should be resolved in .NET Framework 5 and I've found several articles on how to incorporate "Nightly ASP.NET Build" feature into your existing Web API service.  I'm not really comfortable with that and it can be hard to get it working properly. 



All you have to do to fix this issue is add a few lines to your web.config under the system.webServer:





   1:  <system.webServer>
   2:     <httpProtocol>
   3:        <customHeaders>
   4:           <add name="Access-Control-Allow-Origin" value="*"/>
   5:        </customHeaders>
   6:     </httpProtocol>
   7:  <system.webServer>

Wednesday, February 27, 2013

DNN Manage Button Hidden Behind Another Module

There is one issue I've run into several times with DNN and that is an HTML module covering up another module.  I had this issue with the Dark Knight skin.  An HTML module I had on the ContentPane was covering up the dropdown menu, so I had to make some CSS adjustments to the z-index property.

The issue I have now is slightly different.  I've written several modules that either:
  1. Do not display anything in the View (they work in the background), but you still need to access the Settings to make changes
  2. Do not display anything in the View if there is no data
The problem is if you are in Edit mode and nothing is being displayed, you cannot get to the Manage button because it is 'behind' the Manage button of the module below it.


I've come up with a simple fix for this that I include in my View.ascx file:


<% if(DotNetNuke.Common.Globals.IsEditMode()) { %> 
 
<div runat="server" id="showIfEditMode" >
   <br />
   <br />
   <br />
</div>
 
<% } %> 
 
 


This adds some padding below the module when you are in Edit mode. That way, your Manage button will be visible even when there is nothing to display.

Monday, February 11, 2013

Sorting ArrayList with Linq

This was my first forray into Linq, so I thought I'd post it in case I need it again in the near future.

I needed a list of user to populate a DropDownList.  In DotNetNuke, you can get an ArrayList of all users on the system with a call to: UserController.GetUsers(int PortalID).

The problem is the list is sorted by UserID, so when you open the DDL, you'll see all the users in what seems to be random order.  I wanted the list to be sorted by LastName, FirstName without having to write some sort of IComparer.

This is a great use case for Linq ( I've heard a lot about it, but never used it).


ArrayList a = UserController.GetUsers(0);
var so = from UserInfo s in a orderby s.LastName,s.FirstName select s;
            
ddlUser.DataSource = so;
ddlUser.DataValueField = "UserID"; // Alias Name from Sproc
ddlUser.DataTextField = "DisplayName";   // Alias name from sproc
ddlUser.DataBind();
ddlUser.Items.Insert(0, new ListItem("Select One", "0")); // Adds items to DDL


If you are using a custom object (ie UserInfo), then you must explicitly declare the type.
When using LINQ to query non-generic IEnumerable collections such as ArrayList, you must explicitly declare the type of the range variable to reflect the specific type of the objects in the collection.

Wednesday, August 15, 2012

asp.NET Password Requirements

For an asp.net website, using AspNetSqlMembershipProvider for authentication, there are several settings you can specify to handle password requirements.  Most corporate sites that want to make sure users are entering strong password have several things they look for in a password.

  1. Password Length
  2. Character Types
  3. Password Complexity
  4. Password History
  5. Encryption
  6. Attempts
Most of these settings are kept in the web.config.  Here is a standard setting for the membership provider:


<membership>
  <providers>
    <add 
      name="AspNetSqlMembershipProvider" 
      type="System.Web.Security.SqlMembershipProvider, ..." 
      connectionStringName="LocalSqlServer" 
      enablePasswordRetrieval="false" 
      enablePasswordReset="true" 
      requiresQuestionAndAnswer="true" 
      applicationName="/" 
      requiresUniqueEmail="false" 
      passwordFormat="Hashed" 
      maxInvalidPasswordAttempts="5" 
      minRequiredPasswordLength="7" 
      minRequiredNonalphanumericCharacters="1" 
      passwordAttemptWindow="10" 
      passwordStrengthRegularExpression="" 
    />
  </providers>
</membership>


To control the password complexity, you'll need to set the "passwordStrengthRegularExpression" under the "AspNetSqlMembershipProvider".

I'm not great with Regular Expressions, so I turned to StackOverflow for the following password requirements:
  • At least 8 Characters (up to 100)
  • Must have 3 of the 4 character types (Upper, Lower, Number, Symbol)



(?=^[^\s]{8,100}$)((?=.*?\d)(?=.*?[A-Z])(?=.*?[a-z])|(?=.*?\d)(?=.*?[^\w\d\s])(?=.*?[a-z])|(?=.*?[^\w\d\s])(?=.*?[A-Z])(?=.*?[a-z])|(?=.*?\d)(?=.*?[A-Z])(?=.*?[^\w\d\s]))^.*



An explanation of individual components:

• (?=^[^\s]{8,100}$) - contain between 8 and 100 non-whitespace characters

• (?=.*?\d) - contains 1 numeric

• (?=.*?[A-Z]) - contains 1 uppercase character

• (?=.*?[a-z]) - contains 1 lowercase character

• (?=.*?[^\w\d\s]) - contains 1 symbol

Notice after the length segment the double parens and later in the expression you'll see several
's. This allows for the either/or comparison of the 4 possible combinations that are allowed.

Also, check out RAD Regex Designer, for a FREE tool to test your Regular Expression!

Monday, July 16, 2012

Finding Duplicates in MS SQL Server

Here is a quick snippet on how to find duplicates:


SELECT a.[dr_id]
      ,a.[sch_type]
      ,COUNT(*) as '# records'
  FROM [LZ].[dbo].[lz_src_address1] a
  where a.sch_type = '23'
  group by a.dr_id, a.sch_type
  having COUNT(*) > 1


You only include the fields that you need to determine if its a duplicate and put them in the GROUP BY clausing.  the HAVING clause tells you if there is more than 1 record.

There are several ways to delete duplicates.  They way you choose will depend on if you have a unique key for each row.  If so, you can delete them with a single statement.  If not, you may need to use a cursor and/or temp tables.

Friday, June 29, 2012

MS SQL UPDATE with a JOIN

This describes how to UPDATE a table when you have to JOIN another table.  This is for MS SQL Server, so the syntax varies with other versions.

In this example, I am updating the [aspnet_Membership] table, but I want to join the [aspnet_Users] table so I can do it user UserName.  This script allows me to set the password of a user to my password so I can log in as that user.  This is done by updating the ASP.NET Membership table.  I would need to store the [Password] and [PasswordSalt] of this account if I wanted to change it back.



UPDATE m 
SET   m.[Password] = 'mrhLMUfIWCuTHDwOtm1s/I9ABMQsS=='
    , m.[PasswordSalt] = 'suyp+Nsd2lmMPpQ=='
FROM [dnnDB].[dbo].[aspnet_Membership] m
JOIN [dnnDB].[dbo].[aspnet_Users] u on m.UserId = u.UserId
WHERE 1=1
  AND u.UserName in 
  (
      'FirstUser'
    , 'SecondUser'
    , 'ThirdUser'
  )
  

Wednesday, March 14, 2012

View the Contents of a DataTable or DataView While Debugging

I always forget this because I use four different programming languages(3 different IDEs), so I'll put it up here in case I forget ...... again!  Also, credit to Rob Prouse (on StackOverflow).


The Visual Studio debugger comes with four standard visualizers. These are the text, HTML, and XML visualizers, all of which work on string objects, and the dataset visualizer, which works for DataSet, DataView, and DataTable objects.
To use it, break into your code, mouse over your DataSet, expand the quick watch, view the Tables, expand that, then view Table[0] (for example). You will see something like {Table1} in the quick watch, but notice that there is also a magnifying glass icon. Click on that icon and your DataTable will open up in a grid view.

Friday, March 9, 2012

ASPX Hyperlinks: Opening automatically and in New Windows

Here's a couple quick tips that took me some time to work out.

1. Opening a Hyperlink in a new window:

ASPX


<asp:HyperLink ID="jiraLink" 
runat="server">&nbsp;&nbsp;&nbsp;&nbsp;Click here to Expand Window </asp:HyperLink>

Code-behind:


String jiraURL = "http://" + jiraServerURL +"/jira/secure/IssueNavigator.jspa?sId=" + sessionGUID;
jiraLink.NavigateUrl = jiraURL;
jiraLink.Target = "_blank";



And, to automatically open a Hyperlink, put this in the Page_Load:


Response.Write("<script type='text/javascript'>window.open('" + serverURL+ "','_blank');</script>");

Tuesday, February 28, 2012

DotNetNuke Update Custom Profile fields

I had a good bit of trouble with this, but I was able to get it working.

You may need to make sure the custom property you have created is marked Visible, but this is the code that ended up working for me in DNN 6.1.2.




UserInfo _currentUser = DotNetNuke.Entities.Users.UserController.GetCurrentUserInfo();
// Create Token
string sessionGuid = TokenLibrary.TokenSupport.CreateToken(_currentUser).ToString();
 
if (sessionGuid == null || (sessionGuid.Trim().Length < 1 )
sessionGuid = "00000000-0000-0000-0000-000000000000";
 
// Set User Property called "sessionGUID"
_currentUser.Profile.SetProfileProperty("sessionGUID", sessionGuid);
UserController.UpdateUser(_currentUser.PortalID, _currentUser);

Tuesday, January 31, 2012

Bulk File Renaming Utility

I found a great free tool and thought I'd share it here. It's called "Bulk Rename Utility" and can be downloaded from http://www.bulkrenameutility.co.uk/Command.php.

This utility is GUI based, but the link above is the command-line version. I also highly recommend you download the manual to see all the features it has.


When you download the command line version, it is called BRC64.exe ( and they have a 32bit version). I just dropped this into the Windows system directory so its available from the command line no matter what directory I am in.

If you type: BRC64.exe /? , you will get all the command line options.
The main concept is if you run the command with the options, it WILL NOT MODIFY the filenames until you add the /EXECUTE option. So, you can play around with all the options and it will show you what WOULD HAPPEN, then you add /EXECUTE to make it happen.

Examples:

-- This will insert ACME in front of all .X01 files, then remove the .X01 and add .txt as the suffix
brc64.exe /PATTERN:*.X01 /INSERT:ACME-:0 /REMOVEEXT /SUFFIX:.txt /EXECUTE


-- This will replace 2012 with 2011 in all .txt file and change .txt to .asc
brc64.exe /PATTERN:*.txt /REPLACECI:2012:2011 /REMOVEEXT /SUFFIX:.asc /EXECUTE



There are a lot more features, but you get the idea. Just remember, it WILL NOT perform the rename until you add the /EXECUTE, so you can experiment all day.

Thursday, October 27, 2011

Grails 2.0 SQL Server Configuration

I just created my first test application with Grails 2.0RC1 and used SQL Server 2008 as the database.

Here are the quick steps:

1. Install JDK/JRE (I used 1.6.latest)
2. Unzip Grails 2.0RC1 to an C:\grails2rc1\ directory
3. Create environment variables for JAVA_HOME(point to jdk install)
4. Create environment variables for GRAILS_HOME(point to grails directory)
5. Add the following to PATH environment variable: ";%JAVA_HOME%\bin;%GRAILS_HOME%\bin"
6. Test that you can call "javac" and "grails --help" from C:\

7. Create a database for grails from Management Studio
8. Create a user/pass and give it access to this database(I usually give it dbo and sysadmin during the initial install phase. You should dial it back after that)
9. ** TRICK ** Make sure TCP/IP is ENABLED using SQL Server Configuration Manager, under SQL Server Network Configuration -> Protocols for MSSQLSERVER

10. Create a directory for your app (C:\work\apps)
11. Open a command prompt and "cd" to that directory
12. "grails create-app myapp" (This creates the Grails structure)

13. Download the latest jTDS Driver and extract the files to a temp directory
14. Copy the jtds-1.2.x.jar file to the directory C:\mayapp\lib
15. Your conf/DataSource.groovy should look something like this:
dataSource {
pooled = true
driverClassName = "net.sourceforge.jtds.jdbc.Driver"
dialect = "org.hibernate.dialect.SQLServerDialect"
}
... other stuff
development {
dataSource {
dbCreate = "create-drop" // one of 'create', 'create-drop', 'update', 'validate', ''
url = "jdbc:jtds:sqlserver://127.0.0.1:1433;databaseName=grails2rc1"
username = "grailsadmin"
password = "your-Pass123"
// logSql=true
}
}
... more

16. Create your 1st controller: "grails create-controller dashboard"
17. Save, then run "grails run-app"

Tuesday, May 24, 2011

Backing Up SQL Database to Network Drive - Operating system error 5(Access is denied)

I ran into this issue the other day while trying to run a backup and store it on a network drive. At first, I thought it was a file permissions issue so I checked in the Security Settings and Audit logs, but no matter what permissions I changed, it still did not work.

The issue ended up being that the account that the SQL Server service runs under needs to be a Domain account and have the proper permissions. There was also a few other configuration issues I stumbled across.

1. Local Security Policy: Under the Local Security Policy(or Group Policy), there is a policy called "Lock pages in memory" and this needs to be enabled for the domain service account that will be used for the SQL Server service (I also changed the SQL Agent service).

2. The next steps were to allow us to reconfigure SQL Server and allow the SQL Agent to run as domain account:


sp_configure 'show advanced options', 1;
RECONFIGURE;
 
 
sp_configure 'awe enabled', 1
RECONFIGURE;
 
 
sp_configure 'show advanced options', 1;
RECONFIGURE;
 
 
sp_configure 'Agent XPs', 1;
RECONFIGURE
 
 
sp_configure 'show advanced options', 0;
RECONFIGURE

3. Change your SQL Server Service and SQL Agent service Logon account to a domain account with privileges on the network drive.
Open Services -> Choose the Service -> Logon tab -> Choose "This Account" and enter DOMAIN\ACCT and enter the password.

Friday, March 25, 2011

Scheduled Task Not Running a Batch Job

I've recently ran into this several times, so I'm thought I'd document it here.

I've created batch jobs (.bat) that do various things, like copy, move, delete files, download stuff from SFTP servers, etc. In the past, I've just used my credentials to run these jobs, but if I changed my password, the jobs would fail. Now, our IT department created a service account for me to Schedule these tasks, but I've had many issues with Scheduled Tasks not working once I changed the credentials to the service account.

The scheduled task will not show an error code, it just won't work or it will be stuck in a "running" state.

Here is what I have found out:

1. The service account should be a local admin
2. Delete your old Scheduled Task
3. Log onto the server using the service account credentials
4. Re-Create the Scheduled Task while logged on as the service account and use the service account credentials

This applies to Scheduled Tasks that run a .BAT file. All my other scheduled tasks work normally.

Tuesday, February 15, 2011

Migrating users to DotNetNuke

I've been on a 2 month hiatus, but I've come back with some new skills.  I've been working on a DotNetNuke portal to replace our existing MojoPortal.  I really wanted to like MojoPortal because of it's simplicity and ease of setup, but in the end MojoPortal Core development pretty much came to a halt.  There are just too many standard features that are missing, plus DNN has so much out of the box, I couldn't resist.  Plus, the community behind DNN is huge.

While browsing Mitchel Sellers' blog, I found some SQL that allows me to migrate the 700+ user accounts in our MojoPortal to DotNetNuke.  I've put it in a script and parametized it.

After I created this, I created a table from my old MojoPortal, which contains: UserName, FirstName, LastName, DisplayName, Email, and RoleName (Primary Role, which must exist in DNN before running the script).  Then, I ran it through a cursor and added all the users.

** ADDITION NOTE:  If you are using {owner}{prefix} in DNN, you'll need to modify the script.



-- =======================================================================================================
-- Author:        Larry Eisenstein
-- Create date: 2/15/2011
-- Description:    Creates a DNN User by copying an existing user.
-- This can be used to script a single account creation or migrating users from another system.
-- This works by creating the NewUser from an existing user.
-- The script was pulled from Mitchel Sellers website.  He has a great blog, so you should visit it.
-- http://www.mitchelsellers.com/blogs/articletype/articleview/articleid/84/creating-a-standard-dotnetnuke-user-via-sql.aspx
-- 
-- 
-- Req: 
-- 1. Know the Username/Password of an existing user. The password for the user you create will be the password 
-- of this user
-- 2. If you are assigning Roles, the RoleName MUST existing in the DotNetNuke site
-- 
-- Defaults:  I set up some defaults, but these can be changed via params or just change the defaults in the script.
-- 
-- Notes: 
-- Stored Procs used: aspnet_Membership_CreateUser
-- Tables Updated: users, Roles, UserPortals
 
-- The password works by copying the encrypted password, passwordsalt of the ExistingUser to your new user.  Then, you can
-- just login with that user's password.
-- ==========================================================================================================
CREATE PROCEDURE [dbo].[AAA_MigrateUser_sp]
@ApplicationName varchar(255) = 'DotNetNuke',  -- Search for applicationName in your web.config
@ExistingUserName varchar(255) = 'TestUser',   -- This must be an existing DNN user
@FirstName varchar(255) = 'Migrated',            
@LastName varchar(255) = 'UserAccount',
@DisplayName varchar(255) = 'Migrated UserAccount',
@NewUserName varchar(255),
@RoleName varchar(255) = 'Registered Users',
@PortalId int = 0,
@Email nvarchar(256) = 'TestUser@email.org'
AS
BEGIN
 
DECLARE @PasswordQuestion varchar(256),
@PasswordAnswer varchar(256),
@Pw varchar(255),
@PasswordSalt varchar(255),
@PasswordFormat int,
@IsApproved bit,
@CurrentTimeUtc datetime,
@CreateDate datetime,
@UniqueEmail int,
@UserId uniqueidentifier,
@DNNUserId int,
@NumUsers int
 
 
SELECT    @PasswordQuestion = '',
@PasswordAnswer = '',
@IsApproved = 1,
@CurrentTimeUtc = GETDATE(),
@CreateDate = @CurrentTimeUtc,
@UniqueEmail = 0
 
 
 
 
SELECT @NumUsers = COUNT(*)
FROM aspnet_Users
WHERE UserName = @NewUserName
 
 
IF(@NumUsers != 0)
return -1
 
 
SELECT    @Pw = m.password,
@PasswordSalt = m.passwordsalt,
@PasswordFormat = m.passwordformat
FROM aspnet_users u
INNER JOIN aspnet_membership m  ON (u.userid = m.userid)
WHERE u.UserName = @ExistingUserName
 
 
 
-- Make the stored procedure call
EXEC dbo.aspnet_Membership_CreateUser @ApplicationName, @NewUserName, @Pw,
@PasswordSalt, @email, @passwordquestion, @PasswordAnswer, 
@IsApproved, @CurrentTimeUtc, @CreateDate, @UniqueEmail,
@PasswordFormat, @UserId
 
 
-- Insert the record into the DotNetNuke users table
INSERT INTO users (Username, FirstName, LastName, IsSuperUser, Email,
DisplayName, UpdatePassword)
VALUES(@NewUserName, @FirstName, @LastName, 0, @Email, @DisplayName, 0)
 
 
-- Get the new userid, from the DNN users table
SELECT @dnnuserid = userid
FROM Users
WHERE username = @NewUserName
 
 
-- Now, insert the record into the user portals table
INSERT INTO UserPortals (userId, PortalId, CreatedDate)
VALUES(@dnnuserid, @PortalId, GETDATE()) 
 
 
-- Now Give the user permissions to the User Group you specified
IF(@RoleName != 'Registered Users' and @RoleName IS NOT NULL)
BEGIN
INSERT INTO UserRoles (userId, roleId)
SELECT @dnnuserid,
roleId
FROM Roles
WHERE RoleName = @RoleName
END
 
-- Now Give the user permissions to the REGISTERED Users group
INSERT INTO UserRoles (userId, roleId)
SELECT @dnnuserid,
roleId
FROM Roles
WHERE RoleName = 'Registered Users'
 
 
 
END

Tuesday, December 14, 2010

Outlook 2007 Tip: Color Code Messages

This is something I've always wanted in Outlook.  You can 'Categorize' emails and assign a color, but this does not change the color in the Outlook Inbox view.

The work around for me was to create a 'Custom Flag' with a 'Due Date' in the past.  This will turn the text of the email in the Inbox view to Red.

You can also set up some Advance Formatting Rules to change the Font(color, size, underline, bold) based on the Category, but this takes some time.  Here is the link for that: http://www.howto-outlook.com/howto/coloremailadvanced.htm

Here is a sample of what it looks like:

Monday, November 29, 2010

@schedule_uid is not a parameter for procedure sp_add_jobschedule

I received this error when trying to copy a SQL job from one server to another, by trying to script out the create statement:

Msg 8145, Level 16, State 1, Procedure sp_add_jobschedule, Line 0

@schedule_uid is not a parameter for procedure sp_add_jobschedule



The problem is that the parameters for the stored procedure, sp_add_jobschedule, have changed from SQL2005 to SQL2008, so you need to change the script to match.

- SQL 2005 uses @schedule_id (an integer) and SQL 2008 uses @schedule_uid (a uniqueidentifier)


- All you have to do is change the parameter name and data-type to the correct value
    If it's @schedule_uid, change it to @schedule_id.
    Then, find an un-used integer value in: select * from sysjobschedules (MSDB database)

- If you are going the other way, you can change the parameter to @schedule_uid, then create a new
   uniqueidentifier by running:  select newid()