public int Invoke(Dictionary<string, string> args)
        {
            var credentials = new Credentials(args[Arguments.Username], args[Arguments.Password]);
            var configId = args.ContainsKey(Arguments.ConfigId) ? args[Arguments.ConfigId] : null;
            var vpnId = args.ContainsKey(Arguments.VpnId) ? args[Arguments.VpnId] : null;
            var templateId = args[Arguments.TemplateId];
            var configName = args[Arguments.ConfigName];
            var configState = new ConfigurationState();

            var logger = LoggerFactory.GetLogger();

            // CreateConfiguration (returns ConfigID of the instantiated template)
            SkytapConfiguration newTargetConfig = SkytapApi.CreateConfiguration(credentials, templateId, configName);

            // Wait for Skytap to return the expected configuration state. Do this with a retry block
            // to test for the desired state every second for 5 minutes.
            Retry.Execute(() => SkytapApi.CheckConfigurationForDesiredState(credentials, newTargetConfig.ConfigurationUrl,
                                                                             new List<string> {ConfigurationStates.Suspended, ConfigurationStates.Stopped}),
                                                                             NumRetriesCheckConfigState,
                                                                             _retryIntervalCheckConfigState);

            // If VPNID supplied, make a VPN connection, if a configid, create ICNR Connection
            if (String.IsNullOrEmpty(vpnId))
            {
                // CreateIcnrConnection (between the TFSConfigNetwork and the newly instantiated config. Note that it
                // is important that the source network ID be the new configuration and the target network ID be
                // the (existing) TFS configuration. If the two are reversed, a 409 (conflict) error may occur.
                var tfsConfigNetworkId = SkytapApi.GetNetworkIdInConfiguration(credentials, configId);
                var icnrId = SkytapApi.CreateIcnrConnection(credentials, newTargetConfig.ConfigurationNetworkId, tfsConfigNetworkId );
                newTargetConfig.IcnrId = icnrId;
            }
            else
            {
                SkytapApi.AttachVpnConnection(credentials, newTargetConfig.ConfigurationUrl, newTargetConfig.ConfigurationNetworkId, vpnId);
                SkytapApi.ConnectVpn(credentials, newTargetConfig.ConfigurationUrl, newTargetConfig.ConfigurationNetworkId, vpnId);
                newTargetConfig.VpnId = vpnId;
            }

            // Need to wait again for ICNR or VPN to complete.
            //
            // Before starting the configuration, ensure that it is suspended. If it is not suspended (and perhaps stopped)
            // wait until it is in the desired state.
            var configurationState = SkytapApi.GetConfigurationState(credentials, newTargetConfig.ConfigurationUrl);

            if (configurationState != ConfigurationStates.Running)
            {
                // Attempt to start up the configuration using retry semantics just in case the first request doesn't work. This
                // could happen if the configuration tries to restart but the service is busy so the state is returned to
                // suspended and we need to retry the start-up.
                Retry.Execute(() =>
                    {
                        // Start up the configuration by changing its state to running. It is assumed there is a change to the
                        // runstate at this point, either to "busy" or "running". If the configuration ends up as "running",
                        // nothing else to do - just continue. If the state goes back to "suspended", need to retry the start
                        // logic a few more times until the number of retries is exhausted. If it never comes back from "busy" or
                        // enters some other unknown state, just exit once the retry threshold is reached.
                        SkytapApi.SetConfigurationState(credentials, newTargetConfig.ConfigurationUrl, ConfigurationStates.Running);

                        Retry.Execute(() => SkytapApi.CheckConfigurationForDesiredState(credentials, newTargetConfig.ConfigurationUrl,
                                                                            new List<string> { ConfigurationStates.Running, ConfigurationStates.Suspended }),
                                                                            NumRetriesCheckConfigState, _retryIntervalCheckConfigState);

                        // Re-get the configuration state so we can determine whether to give up attempting to start the
                        // configuration or try again. The exception will trigger a retry.
                        var currentConfigState = SkytapApi.GetConfigurationState(credentials, newTargetConfig.ConfigurationUrl);
                        if (currentConfigState == ConfigurationStates.Suspended)
                        {
                            throw new ApplicationException(Resources.TfsStartup_UnexpectedReversionToSuspended);
                        }
                    },
                    NumRetriesStartConfig, _retryIntervalStartConfig);
            }

            // Persist the log file path so that successive invocations of the EXE can use the
            // same log file.
            newTargetConfig.LogFilePath = ((TraceLogger) logger).LogFilePath;

            // Store Config Url so that we can run shutdown on it later since TFS isn't smart enough to do this for us
            var configStatePath = configState.Serialize(newTargetConfig);
            logger.LogInfo("Persisted configuration path: " + configStatePath);
            logger.LogInfo(newTargetConfig.ToString());

            return CommandResults.Success;
        }