{"id":1740,"date":"2016-04-20T21:29:33","date_gmt":"2016-04-21T02:29:33","guid":{"rendered":"http:\/\/wildow.com\/?p=1740"},"modified":"2016-04-20T21:29:33","modified_gmt":"2016-04-21T02:29:33","slug":"using-the-forfiles-command-to-delete-sql-server-backups","status":"publish","type":"post","link":"https:\/\/wildow.com\/?p=1740","title":{"rendered":"Using the FORFILES Command to Delete SQL Server Backups"},"content":{"rendered":"<p>Using the FORFILES Command to Delete SQL Server Backups<br \/>\nBy: Tim Ford | Read Comments (8) | Related Tips: More &gt; Backup<br \/>\nProblem<br \/>\nRecently I constructed a new backup process that I want to institute globally across all my SQL Server 2005 instances. This backup process will not only backup all the databases I point it towards, but at the same time will script out the backup commands to a single file in the format of F_YYYYMMDD.sql if the backup process is a full database backup or D|T_YYMMDD_HHMMSS.sql if the backup process is a differential (D) or transaction log (T) backup. These script files are then stored in a subfolder under the backup directory on the SQL Server. The process works great, but I only don&#8217;t want to keep every .sql file. I cant see the need to keep these scripts after 30 days. Is there a way I can automate a file deletion process from within SQL Server?<\/p>\n<p>Solution<br \/>\nWhile there are many ways the file deletion process can be handled with T-SQL code. I use the xp_cmdshell command along with the FORFILES command for a very similar process to what you have outlined. Solid information of FORFILES is available from Microsoft TechNet, but I will touch on much of the structure and use of FORFILES for your purposes in this tip.<\/p>\n<p>The FORFILES command will select a subset of files and execute a command against the set. The command requires the following parameters and accepts the following variables:<\/p>\n<p>Parameters<\/p>\n<p>Parameter Name Description<br \/>\n\/p Path<br \/>\n\/m Search Mask (default is *.*)<br \/>\n\/s Subdirectories will be searched recursively if this parameter is included<br \/>\n\/c &lt;command&gt; Command to be executed against each file in the result set, commands must be enclosed in double-quotes, default is &#8220;cmd c\/ echo @file&#8221;<br \/>\n\/d Date range for file selection, using Last Modified Date as the criterion for the file. When the \/d parameter is in the form of MM\/DD\/YYYY, file meeting the criteria of +\/- the specified date are included. When in the format of a smallint (-32,768 &#8211; 32,768) the files +\/- the files with a modified date +\/- that number of days from the current date are included in the file result set.<br \/>\nVariables<\/p>\n<p>Variable Name Description<br \/>\n@FILE File name<br \/>\n@FNAME File name without extension<br \/>\n@EXT File extension<br \/>\n@PATH Full path of the file<br \/>\n@RELPATH Relative path of the file<br \/>\n@ISDIR Evaluates as TRUE if the file type is a directory<br \/>\n@FSIZE File size in bytes<br \/>\n@FDATE Last modified date stamp on the file<br \/>\n@FTIME Last modified timestamp on the file<br \/>\nUsing these parameters the following examples could be constructed to take care of your dilemma for deleting your backup script files. You can create scripts based upon modification date\/time or backup type. You can even construct scripts that utilize both criteria. We will now take a closer look at these potential scripts. Remember that you will be executing these from within T-SQL code, so you will need to wrap the statements within an xp_cmdshell call in the format of EXEC xp_cmdshell &#8216;FORFILES COMMAND&#8217;. Please note that in all examples I am using the \/Q and \/F flags for the del command. These signify that the command will use quiet mode (\/Q) and will even delete read-only files (\/F).<\/p>\n<p>Examples<\/p>\n<p>Delete all .sql files in the C:\\Backup directory and its subfolders where the file modified date is older than 10\/18\/2008.<\/p>\n<p>EXEC xp_cmdshell &#8216;FORFILES \/p c:\\BACKUP \/s \/m *.sql \/d 10\/18\/2008 \/c &#8220;CMD \/C del \/Q \/F @FILE&#8221;&#8216;<br \/>\nDelete all .sql files in the C:\\Backup directory and its subfolders where the file modified date is more than 30 days old.<\/p>\n<p>EXEC xp_cmdshell &#8216;FORFILES \/p c:\\BACKUP \/s \/m *.sql \/d -30 \/c &#8220;CMD \/C del \/Q \/F @FILE&#8221;&#8216;<br \/>\nDelete all .sql files in the C:\\Backup directory and its subfolders where the file modified date is more than 30 days old and the file name starts with an &#8220;F_&#8221;.<\/p>\n<p>EXEC xp_cmdshell &#8216;FORFILES \/p c:\\BACKUP \/s \/m F_*.sql \/d -30 \/c &#8220;CMD \/C del \/Q \/F @FILE&#8221;&#8216;<br \/>\nNext Steps<\/p>\n<p>Modify the code above to fit your retention policy, file structure and needs.<br \/>\nAdd the modified code to a subsequent job step in the SQL Agent job that runs your backup process. Include verbose SQL Agent job logging to verify that the process is working correctly.<br \/>\nKeep in mind that the FORFILES command does a lot more than just deleting files. As an example, it can be used to list files for other processes as well.<br \/>\nReview other file deletion automation tips from MSSQLTips.com.<br \/>\nReview tips on xp_cmdshell at MSSQLTips.com<br \/>\nLast Update: 11\/3\/2008<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Using the FORFILES Command to Delete SQL Server Backups By: Tim Ford | Read Comments (8) | Related Tips: More &gt; Backup Problem Recently I constructed a new backup process that I want to institute globally across all my SQL &#8230; <a class=\"more-link\" href=\"https:\/\/wildow.com\/?p=1740\">Read More &raquo;<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-1740","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/wildow.com\/index.php?rest_route=\/wp\/v2\/posts\/1740","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wildow.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/wildow.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/wildow.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/wildow.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1740"}],"version-history":[{"count":1,"href":"https:\/\/wildow.com\/index.php?rest_route=\/wp\/v2\/posts\/1740\/revisions"}],"predecessor-version":[{"id":1741,"href":"https:\/\/wildow.com\/index.php?rest_route=\/wp\/v2\/posts\/1740\/revisions\/1741"}],"wp:attachment":[{"href":"https:\/\/wildow.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1740"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/wildow.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1740"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/wildow.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1740"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}