/// <inheritdoc cref="DeployerBase"/>
        public void deploy()
        {
            var settings = this.GetSettings();

            this.Deployment.windowsUsername = "******" + this.Deployment.installedApplicationSettings.GetId();

            if (this.Deployment.GetPreviousDeployment() != null && this.Deployment.GetPreviousDeployment().windowsUsername != this.Deployment.windowsUsername)
            {
                this.Logger.LogWarning(
                    false,
                    "Windows account username has changed from '{0}' to '{1}', removal of account and granted permissions must be performed manually.",
                    this.Deployment.GetPreviousDeployment()?.windowsUsername,
                    this.Deployment.windowsUsername);
            }

            UtilsWindowsAccounts.EnsureUserExists(this.Deployment.WindowsUsernameFqdn(), this.Deployment.GetWindowsPassword(), this.Deployment.installedApplicationSettings.GetId(), this.Logger, this.GlobalSettings.directoryPrincipal);

            // Legacy behaviour, if no userGroups defined, create a chef_users groups and add the users
            // to it
            if (!(this.GlobalSettings.userGroups ?? new List <string>()).Any())
            {
                UtilsWindowsAccounts.EnsureGroupExists(LEGACY_CHEF_USERS_GROUPNAME, this.GlobalSettings.directoryPrincipal);
                UtilsWindowsAccounts.EnsureUserInGroup(this.Deployment.WindowsUsernameFqdn(), LEGACY_CHEF_USERS_GROUPNAME, this.Logger, this.GlobalSettings.directoryPrincipal);
            }

            // Add the user to the user groups
            foreach (var groupIdentifier in this.GlobalSettings.userGroups ?? new List <string>())
            {
                UtilsWindowsAccounts.EnsureUserInGroup(this.Deployment.WindowsUsernameFqdn(), groupIdentifier, this.Logger, this.GlobalSettings.directoryPrincipal);
            }

            // Add the user to any user groups defined at the application level
            foreach (var groupIdentifier in settings.user_groups ?? new List <string>())
            {
                UtilsWindowsAccounts.EnsureUserInGroup(this.Deployment.WindowsUsernameFqdn(), groupIdentifier, this.Logger, this.GlobalSettings.directoryPrincipal);
            }

            // Add any privileges if requested
            foreach (var privilegeName in settings.privileges ?? new List <string>())
            {
                UtilsWindowsAccounts.SetRight(this.Deployment.WindowsUsernameFqdn(), privilegeName, this.Logger);
            }

            // Getting security right at the OS level here is a little bit picky...
            // in order to have REALPATH to work in PHP we need to be able to read all directories
            // in a path i.e. D:\webs\chef\appnumber1\
            // What we will do is disconnect the USERS account here...
            string basePath = UtilsSystem.CombinePaths(this.GlobalSettings.GetDefaultApplicationStorage().path, this.Deployment.getShortId());

            UtilsSystem.EnsureDirectoryExists(basePath, true);

            UtilsWindowsAccounts.DisablePermissionInheritance(basePath);
            UtilsWindowsAccounts.RemoveAccessRulesForIdentity(new SecurityIdentifier(UtilsWindowsAccounts.WELL_KNOWN_SID_USERS), basePath, this.Logger);
            UtilsWindowsAccounts.AddPermissionToDirectoryIfMissing(this.Deployment.WindowsUsernameFqdn(), basePath, FileSystemRights.ReadAndExecute, this.GlobalSettings.directoryPrincipal);

            // Store this in the application storage location.
            this.Deployment.runtimePath = UtilsSystem.CombinePaths(basePath, "runtime");
            UtilsSystem.EnsureDirectoryExists(this.Deployment.runtimePath, true);

            this.Deployment.runtimePathWritable = UtilsSystem.CombinePaths(basePath, "runtime_writable");
            UtilsSystem.EnsureDirectoryExists(this.Deployment.runtimePathWritable, true);

            // Due to compatibility reasons with environments such as PHP (that do not play well with network file URIs such as shared folders)
            // by default these two directories are symlinked to a local path if they are network paths.

            // Temp dir
            string localTempPath  = UtilsSystem.CombinePaths(this.Deployment.runtimePath, "temp");
            string remoteTempPath = UtilsSystem.CombinePaths(this.GlobalSettings.GetDefaultTempStorage().path, this.Deployment.installedApplicationSettings.GetId());

            UtilsSystem.EnsureDirectoryExists(remoteTempPath, true);
            UtilsJunction.EnsureLink(localTempPath, remoteTempPath, this.Logger, false);
            this.Deployment.tempPath = localTempPath;

            // Temp dir sys
            this.Deployment.tempPathSys = UtilsSystem.CombinePaths(this.Deployment.runtimePathWritable, "_tmp");
            UtilsSystem.EnsureDirectoryExists(this.Deployment.tempPathSys, true);

            // Log dir
            string localLogPath  = UtilsSystem.CombinePaths(this.Deployment.runtimePath, "log");
            string remoteLogPath = UtilsSystem.CombinePaths(this.GlobalSettings.GetDefaultLogStorage().path, this.Deployment.installedApplicationSettings.GetId());

            UtilsSystem.EnsureDirectoryExists(remoteLogPath, true);
            UtilsJunction.EnsureLink(localLogPath, remoteLogPath, this.Logger, false);
            this.Deployment.logPath = localLogPath;

            this.Deployment.SetSetting("appstorage.base", basePath);
            this.Deployment.SetSetting("appstorage.temp", this.Deployment.tempPath);
            this.Deployment.SetSetting("appstorage.log", this.Deployment.logPath);

            this.Deployment.SetSetting("appstorage.remote_temp", remoteTempPath);
            this.Deployment.SetSetting("appstorage.remote_log", remoteLogPath);

            // We use this flag to detect transient storage
            // that must be removed when the deployer is "undeployed".
            AppBaseStorageType appBaseStorageType = AppBaseStorageType.Original;

            // TODO: Make this configurable through the chef.yml settings file.
            string ignoreOnDeployPattern = "^\\.git\\\\|^chef\\\\|^\\.vs\\\\";

            switch (this.Deployment.installedApplicationSettings.GetApplicationMountStrategy())
            {
            case ApplicationMountStrategy.Copy:
                this.Deployment.appPath = UtilsSystem.CombinePaths(basePath, "app");

                // TODO: We should consider the ability to symlink the code here, or to point/mount directly
                // to the original source path. This would probably require delegating this step to the artifact downloader
                // (artifact.getDownloader()) or having the downloader tell us how to deal with this (symlinks, direct, whatever)
                this.Logger.LogInfo(true, "Copying artifact files...");
                UtilsSystem.CopyFilesRecursivelyFast(this.Deployment.artifact.localPath, this.Deployment.appPath, false, ignoreOnDeployPattern, this.Logger);
                this.Logger.LogInfo(true, "Ensure app has proper user permissions for account '{0}'", this.Deployment.WindowsUsernameFqdn());
                UtilsWindowsAccounts.AddPermissionToDirectoryIfMissing(this.Deployment.WindowsUserPrincipalName(), this.Deployment.appPath, FileSystemRights.ReadAndExecute, this.GlobalSettings.directoryPrincipal);
                this.Deployment.artifact.DeleteIfRemote(this.Logger);
                appBaseStorageType = AppBaseStorageType.Transient;
                break;

            case ApplicationMountStrategy.Move:
                this.Deployment.appPath = UtilsSystem.CombinePaths(basePath, "app");

                // TODO: We should consider the ability to symlink the code here, or to point/mount directly
                // to the original source path. This would probably require delegating this step to the artifact downloader
                // (artifact.getDownloader()) or having the downloader tell us how to deal with this (symlinks, direct, whatever)
                this.Logger.LogInfo(true, "Moving artifact files...");
                UtilsSystem.MoveDirectory(this.Deployment.artifact.localPath, this.Deployment.appPath, this.Logger, ignoreOnDeployPattern);

                // We had issues in appveyor where _webs location is in C drive and thus not giving
                // permissions here would make tests fail.
                this.Logger.LogInfo(true, "Ensure app has proper user permissions for account '{0}'", this.Deployment.WindowsUsernameFqdn());
                UtilsWindowsAccounts.AddPermissionToDirectoryIfMissing(this.Deployment.WindowsUsernameFqdn(), this.Deployment.appPath, FileSystemRights.ReadAndExecute, this.GlobalSettings.directoryPrincipal);
                this.Deployment.artifact.DeleteIfRemote(this.Logger);
                appBaseStorageType = AppBaseStorageType.Transient;
                break;

            case ApplicationMountStrategy.Link:
                this.Logger.LogInfo(true, "Linking artifact files...");
                this.Deployment.appPath = UtilsSystem.CombinePaths(basePath, "app");
                UtilsJunction.EnsureLink(this.Deployment.appPath, this.Deployment.artifact.localPath, this.Logger, false);
                this.Logger.LogInfo(true, "Ensure app has proper user permissions for account '{0}'", this.Deployment.WindowsUsernameFqdn());
                UtilsWindowsAccounts.AddPermissionToDirectoryIfMissing(this.Deployment.WindowsUsernameFqdn(), this.Deployment.artifact.localPath, FileSystemRights.ReadAndExecute, this.GlobalSettings.directoryPrincipal);
                appBaseStorageType = AppBaseStorageType.Symlink;
                break;

            case ApplicationMountStrategy.Original:
                this.Logger.LogInfo(true, "Ensure app has proper user permissions for account '{0}'", this.Deployment.WindowsUsernameFqdn());
                UtilsWindowsAccounts.AddPermissionToDirectoryIfMissing(this.Deployment.WindowsUsernameFqdn(), this.Deployment.artifact.localPath, FileSystemRights.ReadAndExecute, this.GlobalSettings.directoryPrincipal);
                this.Deployment.appPath = UtilsSystem.CombinePaths(this.Deployment.artifact.localPath);
                appBaseStorageType      = AppBaseStorageType.Original;
                break;

            default:
                throw new NotImplementedException("The requested mount strategy for the application is not available: " + this.Deployment.installedApplicationSettings.GetApplicationMountStrategy());
            }

            this.Deployment.SetRuntimeSetting("deployment.appPath", this.Deployment.appPath);
            this.Deployment.SetRuntimeSetting("deployment.logPath", this.Deployment.logPath);
            this.Deployment.SetRuntimeSetting("deployment.tempPath", this.Deployment.tempPath);

            this.Deployment.SetSetting("appstorage.appBaseStorageType", appBaseStorageType);

            UtilsWindowsAccounts.AddPermissionToDirectoryIfMissing(this.Deployment.WindowsUsernameFqdn(), remoteTempPath, FileSystemRights.Write | FileSystemRights.Read | FileSystemRights.Delete, this.GlobalSettings.directoryPrincipal);
            UtilsWindowsAccounts.AddPermissionToDirectoryIfMissing(this.Deployment.WindowsUsernameFqdn(), remoteLogPath, FileSystemRights.Write | FileSystemRights.Read | FileSystemRights.Delete, this.GlobalSettings.directoryPrincipal);
            UtilsWindowsAccounts.AddPermissionToDirectoryIfMissing(this.Deployment.WindowsUsernameFqdn(), this.Deployment.runtimePath, FileSystemRights.ReadAndExecute, this.GlobalSettings.directoryPrincipal);
            UtilsWindowsAccounts.AddPermissionToDirectoryIfMissing(this.Deployment.WindowsUsernameFqdn(), this.Deployment.runtimePathWritable, FileSystemRights.Write | FileSystemRights.Read | FileSystemRights.Delete, this.GlobalSettings.directoryPrincipal);

            this.DeployFonts(settings);
        }