You're doing it right. I created a basic SSIS package. Has one Variable, FolderPath, type string. There is a single script task that fires an Information event and the contents of that expose the value of the FolderPath variable

I then created a basic C# console app like this
public class InformationListener : DefaultEvents
{
public override void OnInformation(DtsObject source, int informationCode, string subComponent, string description, string helpFile, int helpContext, string idofInterfaceWithError, ref bool fireAgain)
{
//base.OnInformation(source, informationCode, subComponent, description, helpFile, helpContext, idofInterfaceWithError, ref fireAgain);
Console.WriteLine(string.Format("{0} {1}", subComponent, description));
}
}
class Program
{
static void Main(string[] args)
{
string sourcePackage = string.Empty;
string path = string.Empty;
string variableName = string.Empty;
string designValue = string.Empty;
string newValue = string.Empty;
InformationListener listener = null;
sourcePackage = @"J:\Src\SO\SSIS\Package.dtsx";
path = @"J:\runtime";
variableName = "User::FolderPath";
listener = new InformationListener();
Application app = new Application();
Package pkg = null;
Variable ssisVariable = null;
pkg = app.LoadPackage(sourcePackage, null);
ssisVariable = pkg.Variables[variableName];
designValue = ssisVariable.Value.ToString();
Console.WriteLine(string.Format("Designtime value = {0}", designValue));
ssisVariable.Value = path;
newValue = ssisVariable.Value.ToString();
Console.WriteLine(string.Format("new value = {0}", newValue));
DTSExecResult results = DTSExecResult.Canceled;
results = pkg.Execute(null, null, listener, null, null);
Console.WriteLine("Press any key to continue");
Console.ReadKey();
}
}
As you can tell from the variable inspection

and from my print statements

the design-time value of C:\designTime
goes to J:
because I forgot to escape my string above but we can pretend it shows J:\runtime
.
All this said, unless we serialize the package with a call to the SaveToXml
method, the value of User::FolderPath resets to the design time value once the object goes out of scope. Permanently updating would look like
app.SaveToXml(sourcePackage, pkg, null);
OP EDIT this discussion and examples led me to the answer:
http://social.msdn.microsoft.com/Forums/sqlserver/en-US/dad8e218-1fe0-49db-89da-5715fb6d4b21/sql-2008-r2-ssis-c-script-task-not-setting-variable