Preventing ClickOnce Publishing a Debug Configuration

You’ve all had it happen. You just put the finishing touches on your project and you hit the Publish button. The files are automatically copied to the file server and users start get the updates right away. You double-check the publish and then you realize that you published the DEBUG version with all your program stops, disabled error checking, and wide open access to all program features!

Custom MSBuild targets to the rescue! Just add the following to your project file and it will prevent a publish when the DEBUG constant is defined. Place it at the bottom of your project file right before the </Project> tag. (For an example of editing your project file, see my post on Obfuscating a ClickOnce Publish.)

  <!-- The following makes sure we don't try to publish a configuration that defines the DEBUG constant -->
  <Target Name="BeforePublish">
    <Error Condition="'$(DefineDebug)'=='true'"
           Text="You attempted to publish a configuration that defines the DEBUG constant!" />
  </Target>

By the way, the DEBUG constant is the constant that you use in your code as a compiler constant, for example #If DEBUG Then. It can be found in the ‘Compile’ tab under ‘My Project’ by clicking ‘Advanced Compile Options…’:

Define DEBUG Constant

Posted in Coding | Tagged , , , | Leave a comment

MacBook Pro Right-Click Drag, Fxx Keys, etc.

The MBP comes with a beautiful backlit keyboard and a multitouch trackpad that is also a big button. Both are very pleasant and easy to use–unless you run Windows or run into an application that require that you press the Home key. Then you’re hunting newsgroups for the magical key combos.

Here are a couple of great links that I used to figure out the mysteries of the fn key:

Right-Click Drag

The tough thing is to figure out how to right-click drag. You can usually find some other way of accomplishing a right-click drag task, but sometimes you just can’t. If I want to share one folder to another in SourceSafe, there’s just no other practicable way.

When I need to, I activate System Preferences->Trackpad->Secondary Click and choose ‘Bottom-Right Corner’. Then you can simply click the big button in that corner with your right index finger and use your left index finger to move the item around. When you’re ready to drop, let go with your right finger. I always turn this setting off when I’m done because I end up right-clicking when I don’t want to.

Funtion Keys

The function keys are relatively useless on a MacBook Pro since most of the commands can be accomplished more easily by trackpad gestures. You usually use the alternative functions of the keys like volume and brightness controls.

The opposite it true on a PC, especially for thing like search where you keep hitting F3 or debugging in Visual Studio where you’re hitting F9 through F11 over and over. It gets to be a real pain to keep hitting that Fn key.

Fortunately, there’s an easy way to reverse the functionality of the Fn key so that the function keys are fired without pressing anything else and the volume, brightness, etc. controls are the ones enabled by pressing Fn.

Just go to System Preferences->Keyboard and check the box called Use all F1, F2, etc. keys as standard function keys. Here’s an example of the setting turned on.

When you’re done, then go ahead and uncheck the box. Ideally, you could create a script to quickly set and unset the setting for daily usage, but it’s really not too much to remember it.

Insert Key

Sometimes, when running Windows, you’ll need to use the Insert key. None of the keyboard mappings I’ve seen have indicated what to use except the Insert key on a full keyboard (duh!).

On a MBP, it’s simply:  Fn+Enter

Posted in Uncategorized | Tagged , , | Leave a comment

Obfuscating a ClickOnce Publish

I needed to create a ClickOnce publish of an obfuscated exe for a customer since he was concerned about theft of his intellectual property. I added in several security features, but they were worthless if I couldn’t harden the executable against decompilers like .Net Reflector. If you don’t believe me, try running .Net Reflector on your code. You’ll be shocked as to how much meaningful information is retained in the output. Not only is your code exposed, but so are all the string literals, member names, and resources.

So I shopped around for an obfuscating (et al.) program. I looked at the industry-standard, Dotfuscator, since a free version even ships with Visual Studio. But the free version is worthless since it only renames public members (again, don’t take my word and just peek into it yourself). The commercial version of Dotfuscator very easily supports obfuscating a ClickOnce publish (see this handy demo) and additional hardening techniques, but the price is $4950 or $5940 depending on which edition you choose. They have a special deal for companies less than 40 employees, but the price is still $2500. I figured it was worth some shoe leather to find a less expensive solution.

After some hunting around and having mixed results with various other products, I found a program called .Net Reactor. I like it because it’s straightforward, fully-featured, has comprehensive command-line support, and is very reasonably priced at $179.

Now that I had an obfuscation tool, I had to figure out how to make it work with ClickOnce. I was initially hopeful seeing the post-build command-line property in the project properties. However, if you simply add the obfuscation to the post-build event, the published exe is not obfuscated. It turns out your exe is compiled into an intermediate directory (e.g. “obj\Release”) and then copied to your build output path and/or used to create a ClickOnce publish. The post-build event is too late to affect the publish.

To hook in before the publish, you have to turn to MSBuild, the compile tool used in the background by Visual Studio to consume and compile a .Net project. It turns your project file (.vbproj or .csproj) are actually MSBuild files that you can edit directly for more features than are supported through the IDE.

(Forgive me if I’ve violated MSBuild best-practices in my tasks and properties, but there just isn’t a lot of help out there and the MSBuild syntax seems pretty sloppy to begin with.)

Steps

  1. Download this file and place it in the same directory as the project file of the project you want to protect.
    Download

    Obfuscation.targets


    This file is analogous to the .Net provided .targets files that are also included with your project by default. This file will override or add to tasks that are handled by those files.
  2. Right-click on the project that you will be publishing and click ‘Unload Project’. (If your project is source-controlled, you may get a warning that says you still have files checked out, but you can just click ‘Continue’ without causing any problems.)
  3. Right-click on the project again and click ‘Edit MyApp.vbproj’.
  4. Paste the non-highlighted XML into your project file between the highlighted lines (note, that the ‘.targets’ file may have a different file name if you’re using C# but it will still end in ‘.targets’).
      <Import Project="$(MSBuildBinPath)\Microsoft.VisualBasic.targets" />
      <!-- Use the following settings to control how and if the output is obfuscated. -->
      <Target Name="BeforeBuild" Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
        <CreateProperty Value="true">
          <Output TaskParameter="Value" PropertyName="Obfuscate" />
        </CreateProperty>
        <CreateProperty Value="false">
          <Output TaskParameter="Value" PropertyName="ShouldMergeAssemblies" />
        </CreateProperty>
      </Target>
      <Import Project="$(MSBuildProjectDirectory)\Obfuscation.targets" />
    </Project>
    

    You can change the ‘true’ or ‘false’ values to control whether or not the obfuscation is done at all and whether or not assemblies are merged when obfuscating. You can also change the configuration from ‘Release’ to some other configuration that you have defined.
    Note: If you don’t intend to merge assemblies, each dll or exe that is included with your project must be separately obfuscated (unless of course it’s a 3rd party include). When obfuscating these includes, make sure NOT to obfuscate their public members or your main assembly won’t be able to use them.

  5. After saving your changes, right-click on the project and click ‘Reload Project’. You may get a security warning, but just choose to ‘Load project normally’.
  6. If you’re intending to Publish and merge assemblies, there’s one more step required. You must exclude files that are merged into the main assembly and would be normally output with the publish. Otherwise, these unprotected files, though unused, will be available for the world to decompile.
    Go to the ‘Publish’ tab in ‘My Project’ and click on ‘Application Files’. For any dll or exe file listed as ‘Include’ or ‘Include (auto)’, change it to ‘Exclude’. If you have 3rd party files or files listed as ‘Prerequisite’, merging may not be an option and you may have to resort to individually protecting your includes by obfuscation and security checks to ensure usage only by your programs.
  7. Change your configuration to ‘Release’ and build or publish. Note: For whatever reason, the IDE sometimes forgets what solution configuration was last selected, so always check that you have the right configuration selected if the obfuscator doesn’t run.

Notes

  • When you’re working in XML, don’t forget to properly escape special characters. For example, a ‘<’ should be escaped as &lt;. Also, you must escape quotation marks inside a string literal (using &quot;) but you don’t have to if you’re only inside a tag, like when specifying a property value. Here’s a great thread on XML escape characters.
  • To make sure Messages are output, in VS IDE go to Tools->Options->Projects & Solutions->Build & Run and change Output Verbosity from ‘Minimal’ to ‘Normal’. It helps a lot when debugging custom MSBuild configs.
  • MSBuild will halt if a program’s exit code is not ’0′. If your obfuscator of choice uses a different exit code or always returns something non-zero, then make sure to trap it in the way I did above and throw an error when appropriate. Actually, the error trapping I did was redundant (I think), but it’s a handy example.
  • If you’re using another obfuscator, it should ideally conform to the MSBuild convention of returning 0 (zero) if successful and a non-zero number on an error. If your obfuscator works differently, for example, always returning 1 on success, or if you just want to ignore certain errors, you may use the following convention to trap and interpret exit codes. This example raises an error for all return values other than 0, effectively duplicating the standard MSBuild convention.
    <Exec Command="$(ObfuscatorLocation) -file &quot;$(SourceExe)&quot; -targetfile &quot;$(SecureExe)&quot; $(ObfuscatorOptions) ">
      <Output TaskParameter="ExitCode" PropertyName="ObfuscatorErrorCode" />
    </Exec>
    <Error Condition="'$(ObfuscatorErrorCode)' != '0'"
           Text="Error while executing '$(ObfuscatorName)'. Returned exit code of '$(ObfuscatorErrorCode)'." />
    

2010-05-30 Updated: Refined include method and added support for merging assemblies. Also, included instructions for trapping custom errors.

References

Posted in Coding | Tagged , , , , , , , | 5 Comments

Excellent Windows API Tool

I stumbled across this add-in which automates the insertion of various Windows API declarations. If you’re like me, you track down solutions to your problem on the Internet, but sometimes it uses an API declaration in C# or VB6. Even worse, sometimes someone will use a non-standard or just plain difficult declaration style, for example:

ByVal var As IntPtr

and marshalling a string rather than

ByVal bytes() As Byte

Anyhow, the tool is here: http://www.pinvoke.net/index.aspx

Posted in Coding | Tagged | Leave a comment

When Compiler Directives Aren’t Enough

If you’ve programmed for any length of time in .NET, you’re probably familiar with the DEBUG compiler constant that you can use to designate code to compile and run depending on your build configuration (e.g. Debug or Release).

But very often you don’t care about the configuration you’re running–what you do care about is distinguishing between you developing the software and the end user using it. In other words, you care whether you’re running in the IDE or not.

An example of when this would matter is if you accidentally publish in Debug mode, then the end user will get all your debug outputs, extra buttons, etc. You can mitigate this risk if your code is protected by a check for the presence of the debugger instead. This call is:

System.Diagnostics.Debugger.IsAttached

Now, the end-user can always load up your EXE in Visual Studio and attach a debugger instance, so don’t assume this call will protect anything super-sensitive in your program. But your code is very susceptible to a decompiler anyways, so always use compiler directives if you don’t want certain sections of your code to make it to the outside world.

Posted in Coding | Tagged , , | Leave a comment

Converting VB.NET 2003 WinForms to 2005/2008 Partial Classes

Ever been stuck working in VB.NET 2005 or 2008 with a project created in VB.NET 2003? Aside from language differences, you’re stuck with forms that except for resources are in one file. Not only is this ugly, but it makes the IDE slower, since it redraws when it detects any changes to a file that has designer info.

So I started hunting about for a quick solution to convert this over (why isn’t this automatic MS?) and found a great solution by Duncan Smart, on his blog here. I’ve modified it to work with VB and tested and ran it in VB 2008. Duncan’s didn’t seem to work right on VB code when iterating through the class members, but there does seem to be little predictability when it comes to using the macro system. I also added some extra error checking and a restore-on-error feature.

Here’s the code for the macro. Instructions for usage are in the comments on the top. Sorry for the sometimes sloppy style–I wrote it quick and dirty.

Imports System
Imports EnvDTE
Imports EnvDTE80
Imports EnvDTE90
Imports System.Diagnostics

Public Module ExtractWinFormsDesignerFile

    ' -------------------------------------------------------------------------
    ' Extract WinForms Designer File Visual Studio 2005/2008 Macro
    ' -------------------------------------------------------------------------
    ' Extracts the InitializeComponent() and Dispose() methods and control
    ' field delarations from a .NET 1.x VS 2003 project into a VS 2005/8
    ' style .NET 2.0 partial class in a *.Designer.VB file. (This tested to work
    ' with VB only.)
    '
    ' To use:
    '  * Copy the methods below into a Visual Studio Macro Module (use
    '    ALT+F11 to show the Macro editor)
    '  * Select a Windows Form in the Solution Explorer
    '  * Run the macro by showing the Macro Explorer (ALT+F8) and double
    '    clicking the 'ExtractWinFormsDesignerFile' macro.
    '
    ' Duncan Smart, InfoBasis, 2007
    ' From: http://blog.dotsmart.net/2008/05/20/converting-visual-studio-2003-winforms-to-visual-studio-20052008-partial-classes/
    ' Modified and updated by Nathan Jones, 2010
    ' See: http://www.nathanpjones.com/
    ' -------------------------------------------------------------------------

    Sub ExtractWinFormsDesignerFile()

        Dim item As ProjectItem = DTE.SelectedItems.Item(1).ProjectItem
        Dim sourceFileName As String = item.FileNames(1)
        Dim sourceDir As String = System.IO.Path.GetDirectoryName(sourceFileName)
        Dim origCode As String
        Dim bareName As String = System.IO.Path.GetFileNameWithoutExtension(sourceFileName)
        Dim newDesignerFile As String = sourceDir & "\" & bareName & ".Designer.vb"

        If IO.File.Exists(newDesignerFile) Then
            MsgBox("Designer file already exists!")
            Exit Sub
        Else
            If MsgBox("You are about to extract designer code from:" + vbCrLf + _
                      vbCrLf + _
                      "    " + sourceFileName + vbCrLf + _
                      vbCrLf + _
                      "To the following file:" + vbCrLf + _
                      vbCrLf + _
                      "    " + newDesignerFile + vbCrLf + _
                      vbCrLf + _
                      "MAKE SURE TO BACK UP FIRST!", _
                      MsgBoxStyle.OkCancel Or MsgBoxStyle.DefaultButton2 Or MsgBoxStyle.Question, _
                      "Confirm") = MsgBoxResult.Cancel Then Exit Sub
        End If
        origCode = System.IO.File.ReadAllText(sourceFileName)

        Dim codeClass As CodeClass
        Dim namespaceName As String

        codeClass = findClass(item.FileCodeModel.CodeElements)
        namespaceName = ""
        If codeClass.Namespace IsNot Nothing Then
            namespaceName = codeClass.Namespace.FullName
        End If

        Dim initComponentText As String
        Dim disposeText As String
        Dim fieldDecls() As String
        Try
            initComponentText = extractMember(codeClass.Members.Item("InitializeComponent"))
        Catch
            MsgBox("Error extracting InitializeComponent!")
            Exit Sub
        End Try
        Try
            disposeText = extractMember(codeClass.Members.Item("Dispose"))
        Catch
            MsgBox("Error extracting Dispose! Will restore source file.")
            System.IO.File.WriteAllText(sourceFileName, origCode)
            Exit Sub
        End Try
        Try
            fieldDecls = extractWinFormsFields(codeClass, initComponentText)
        Catch
            MsgBox("Error extracting field declares! Will restore source file.")
            System.IO.File.WriteAllText(sourceFileName, origCode)
            Exit Sub
        End Try

        Dim finalCode As String

        finalCode = IIf(namespaceName <> "", "Namespace " + namespaceName + vbCrLf + vbCrLf, "") + _
                    "<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _" + vbCrLf + _
                    "Partial Class " + codeClass.Name + vbCrLf + _
                    "    Inherits System.Windows.Forms.Form" + vbCrLf + _
                    vbCrLf + _
                    disposeText + vbCrLf + _
                    vbCrLf + _
                    fieldDecls(0) + vbCrLf + _
                    vbCrLf + _
                    initComponentText + vbCrLf + _
                    fieldDecls(1) + vbCrLf + _
                    "End Class" + vbCrLf + _
                    IIf(namespaceName <> "", vbCrLf + "End Namespace" + vbCrLf, "")

        ' Now write the new designer file

        System.IO.File.WriteAllText(newDesignerFile, finalCode)

        Dim newProjItem As ProjectItem = item.ProjectItems.AddFromFile(newDesignerFile)
        Try
            newProjItem.Open()
        Catch
        End Try
        Try
            DTE.ExecuteCommand("Edit.FormatDocument")
        Catch
        End Try

        MsgBox("Code separated successfully!" + vbCrLf + _
               "You may have residual comments or code regions in the source " + vbCrLf + _
               "class that should be deleted or moved to the new Designer.vb class.", _
               MsgBoxStyle.Information, _
               "Complete")

    End Sub

    Function findClass(ByVal items As System.Collections.IEnumerable) As CodeClass

        For Each codeEl As CodeElement In items

            If codeEl.Kind = vsCMElement.vsCMElementClass Then

                Return codeEl

            ElseIf codeEl.Children.Count > 0 Then

                Dim cls As CodeClass = findClass(codeEl.Children)
                If cls IsNot Nothing Then
                    Return findClass(codeEl.Children)
                End If

            End If

        Next

        Return Nothing

    End Function

    Function extractWinFormsFields(ByVal codeClass As CodeClass, ByVal initComponentsCode As String) As String()

        Dim member As CodeElement
        Dim fieldsCode As String
        Dim components As String
        Dim initComponentsCodeForComp As String = initComponentsCode.ToLower

        fieldsCode = ""
        For i As Integer = codeClass.Members.Count To 1 Step -1

            member = codeClass.Members.Item(i)

            If member.Kind = vsCMElement.vsCMElementVariable Then

                Dim field As CodeVariable = member

                If field.Type.TypeKind <> vsCMTypeRef.vsCMTypeRefArray Then

                    If field.Name.ToLower = "components" Then

                        ' We'll insert this separately
                        components = extractMember(field)

                    ElseIf initComponentsCodeForComp Like ("* Me." + field.Name + " = New *").ToLower Then

                        fieldsCode = extractMember(field) + vbCrLf + _
                                     fieldsCode

                    End If

                End If

            End If

        Next

        Return New String() {components, fieldsCode}

    End Function

    Function extractMember(ByVal memberElement As CodeElement) As String

        Dim memberStart As EditPoint = memberElement.GetStartPoint().CreateEditPoint()
        Dim memberText As String = String.Empty

        memberText += memberStart.GetText(memberElement.GetEndPoint())
        memberStart.Delete(memberElement.GetEndPoint())

        Return memberText

    End Function

End Module
Posted in Coding | Tagged , | 4 Comments

Parallels Desktop 5 vs. VMWare Fusion 3

As everyone else is weighing in with anecdotal evidence so will I. Since I use my Mac to run Windows to program in Windows and DOS for work, it’s very important to me to select the very best emulator. The odd thing is how each performed very well in different areas, both singularly excelling in areas that I would consider critical. That said, I think Parallels wins… read on.

Parallels Desktop 5

  • Faster Virtual Disk Access – And this is why it wins for me. Since so much of the performance of the VM is dependent on the virtual hard drive, this puts it way ahead of Fusion especially if you’re running antivirus on your VM.
  • Getures – Why can’t Fusion do this? Although I plug in a separate keyboard and mouse, several of my VM’s I use with the naked (so to speak) hardware. I was doing it by habit already so this is a win.
  • Serial Ports – To be honest I haven’t gotten the serial port to pipe to work (in about 30 min of trying), but the capabilities are far beyond Fusion, supporting even physical serial ports.
  • Configuration Options – It simply has more configuration options. Generally you don’t need them, but they’re there when you need them.
  • Better Host Integration Mgmt – Although turning these features off is anything but straightfoward, you have many more levels of integration from folder to MacLook that makes your Windows programs look like Mac programs. Also, there is (new to v5) a checkbox to completely isolate the VM from the host which will turn off all the other integration features.

VMWare Fusion 3

  • Workhorse CPU Virtualization – I have a testing program that tests the output of two different DOS programs running in the Windows XP DOS window (NTVDM). On a physical computer, these each consume up to 50% of the CPU. Parallels chokes and can run about .3-.4 units/sec whereas Fusion can test upwards of .6 units/sec. For whatever reason (probably lousy virtual drive performance), this doesn’t translate into overall better performance in Fusion.
  • FULL Keyboard Support – Fusion actually captures special keys like F12. I have Cmd+F12 mapped to the Pause/Break key. Parallels won’t allow this-won’t even allow setting it without turning off the OSX shortcut. Even in full screen it will bring up the Dashboard.
  • Good Mouse Support – Although it doesn’t support gestures, it did recognized the “Back” and “Forward” buttons on my Logitech mouse, and I don’t have any special Logitech drivers installed on the host or the VM.
  • Straightforward Config – Although not sufficient for the power-user, it does strike me as more accessible for the novice user.

These are just a few observations from regular use of both programs. Many of the basic features are identical, but Parallels really has the edge.

Posted in Reviews | Tagged , , , | Leave a comment

Microsoft Backup (NTBackup.exe)

I created this blog so I could post about different things I’m working on, and I resolve with the new year to start doing so. I thought I’d begin by relating a difficult situation I had setting up an automated backup for my brother-in-law’s computer.

I was trying to automate the use of NTBackup.exe which is the standard Microsoft backup tool that comes with Windows XP. I wanted something that would backup the ‘My Documents’ and ‘Desktop’ folders, but was having difficulty creating the ‘.BKS’ file that NTBackup uses as a list of source directories. The trick is that it has to be a Unicode text file and not you basic ASCII. You’ll see that below in how that file is created.

Here’s NTBackup.bat

@echo off
FOR /F "TOKENS=1* DELIMS= " %%A IN ('DATE/T') DO SET CDATE=%%B
FOR /F "TOKENS=1,2 eol=/ DELIMS=/ " %%A IN ('DATE/T') DO SET mm=%%B
FOR /F "TOKENS=1,2 DELIMS=/ eol=/" %%A IN ('echo %CDATE%') DO SET dd=%%B
FOR /F "TOKENS=2,3 DELIMS=/ " %%A IN ('echo %CDATE%') DO SET yyyy=%%B
rem SET date=%mm%%dd%%yyyy%
SET datepart=%yyyy%-%mm%-%dd%

SET backupdir=E:\Backups
SET backupfile=%backupdir%\%USERNAME%'s Backup.bkf
SET logdir=%HOMEDRIVE%%HOMEPATH%\Local Settings\Application Data\Microsoft\Windows NT\NTBackup\data
SET logfile=%backupdir%\Backup.log
SET selectionfile=Selections.bks
SET backupoptions=backup "@%selectionfile%" /a /d "Set created By NTBackup.bat" /v:no /r:no /rs:no /hc:off /m differential /j "Backup for %USERNAME%" /l:s /f "%backupfile%"

cls
echo.
echo.Nathan's Easy Backup
echo.--------------------
echo.
echo.This will backup the following folders:
echo.  %HOMEDRIVE%%HOMEPATH%\Desktop
echo.  %HOMEDRIVE%%HOMEPATH%\My Documents
echo.
echo.To the following destination:
echo.  %backupfile%
echo.
echo.And creating a log file:
echo.  %logfile%
echo.
echo.
echo.NOTE: If you already ran a backup today, then it will be overwritten
echo.with the current contents of the source folders.
echo.
echo.
echo.To abort, press Ctrl+C now or
pause

md "%backupdir%" > NUL
copy /V /Y NTBACKUP.MSI "%backupdir%"

rem Selections file MUST be in Unicode!!
cmd /U /C "echo.C:\BackupMaker > "%selectionfile%""
cmd /U /C "echo.%HOMEDRIVE%%HOMEPATH%\Desktop >> "%selectionfile%""
cmd /U /C "echo.%HOMEDRIVE%%HOMEPATH%\My Documents >> "%selectionfile%""

rem Erase old backup logs so the only one remaining is the one for our current backup
erase "%logdir%\*.*" /q

echo.
echo.
echo.The backup will start when you press a key. Please do not close this window
echo.before the backup has completed.
echo.
pause
ntbackup %backupoptions%

erase /F /Q "%logfile%"
ren "%logdir%\backup*.log" "backup.log"
move "%logdir%\backup.log" "%logfile%"

pause

When creating a simple backup, I also made a script for the popular ‘Robocopy.exe’ utility found in the ‘Windows Server Resource Kit Tools’. It does the same thing, but preserves a mirror of the source rather than creating a proprietary data file. Note that it excludes exe and dll files since these are usually downloaded or compiled files that are considered temporary.

Here’s RoboBackup.bat

@echo off
FOR /F "TOKENS=1* DELIMS= " %%A IN ('DATE/T') DO SET CDATE=%%B
FOR /F "TOKENS=1,2 eol=/ DELIMS=/ " %%A IN ('DATE/T') DO SET mm=%%B
FOR /F "TOKENS=1,2 DELIMS=/ eol=/" %%A IN ('echo %CDATE%') DO SET dd=%%B
FOR /F "TOKENS=2,3 DELIMS=/ " %%A IN ('echo %CDATE%') DO SET yyyy=%%B
rem SET date=%mm%%dd%%yyyy%
SET datepart=%yyyy%-%mm%-%dd%

SET backupdir=E:\%USERNAME%'s Backups\%datepart%
SET logfile=%backupdir%\Backup.log
SET backupoptions=/MIR /XF "thumbs.db" "*.exe" "*.dll" /LOG+:"%logfile%" /NP /TEE

cls
echo.
echo.Nathan's Easy Backup
echo.--------------------
echo.
echo.This will backup the following folders:
echo.  %HOMEDRIVE%%HOMEPATH%\Desktop
echo.  %HOMEDRIVE%%HOMEPATH%\My Documents
echo.
echo.To the following destination:
echo.  %backupdir%
echo.
echo.And creating a log file:
echo.  %logfile%
echo.
echo.
echo.NOTE: If you already ran a backup today, then it will be overwritten
echo.with the current contents of the source folders.
echo.
echo.
echo.To abort, press Ctrl+C now or
pause

md "%backupdir%" > NUL
erase "%logfile%" > NUL

md "%backupdir%\Desktop" > NUL
robocopy "%HOMEDRIVE%%HOMEPATH%\Desktop" "%backupdir%\Desktop" %backupoptions%

md "%backupdir%\My Documents" > NUL
robocopy "%HOMEDRIVE%%HOMEPATH%\My Documents" "%backupdir%\My Documents" %backupoptions%
Posted in Uncategorized | Tagged , | Leave a comment

CodeProject: StringEnum

Some time ago I submitted an article to CodeProject and I thought I’d post a link to it here. It’s not a new idea, but I think a novel implementation. The article’s purpose is to provide functionality like an Enum, but using a string as the target data type.

I’ve actually used it quite frequently at my job at JE Pistons. We deal with a lot of text databases and so most of our flag fields are one character strings. This is a lifesaver by not having to constantly refer to item lists.

Anyhow, here’s the link: CodeProject: StringEnum That Works Like System.Enum

Posted in Coding | Tagged , , , , | Comments Off

Hello world!

Okay, as a programmer I can’t resist the simple phrase of the title of this post. Such joy fills the heart of any programmer when he finally sees this little message.

Well, “Hello world!” indeed and welcome to this site. I hope you find it helpful and interesting.

Posted in Uncategorized | Comments Off