Unique output files:
- Date
- Random number
- Append
- Noclobber
-
When working with output files it is sometimes necessary to create some sort of uniqueness factor. The purpose of this uniqueness factor is to make sure that the files is not overwritten by a subsequent re-running of a script manually or even as part of a scheduled task. Other factors that may necessitate this uniqueness are keeping track of when a log file or results file were written for testing or eventually for production.
** One caveat to making the file name unique is that it could make it harder to find if a script needs the output for a later operation. We covered how to keep track of these in a previous Tip of the Week.
Uniqueness Factor Type – Date
One of the easiest uniqueness factors to use when generating a file name is a current date or current date and time. Depending on how often a script process is run and the log file generated, should help determine what date format to use. This is import as the Get-Date cmdlet in PowerShell can be used to formulate the date and time to something simple to very complete. Also remember that if using this for files names do not use characters that cannot be placed in file names like backslashes.
The default output of Get-Date is completely useless for file names:
As such we’ll need to tweak this output to the format we need. Some formatting conventions to help us move forward:
Date:
D Date in mm/dd/yy format (06/14/06)
x Date in standard format for locale (09/12/07 for English-US)
Year:
C Century (20 for 2006)
Y Year in 4-digit format (2006)
y Year in 2-digit format (06)
G Same as ‘Y’
g Same as ‘y’
Month:
b Month name – abbreviated (Jan)
B Month name – full (January)
h Same as ‘b’
m Month number (06)
Week:
W Week of the year (00-52)
V Week of the year (01-53)
U Same as ‘W’
Day:
a Day of the week – abbreviated name (Mon)
A Day of the week – full name (Monday)
u Day of the week – number (Monday = 1)
d Day of the month – 2 digits (05)
e Day of the month – digit preceded by a space ( 5)
j Day of the year – (1-366)
w Same as ‘u’
Time:
p AM or PM
r Time in 12-hour format (09:15:36 AM)
R Time in 24-hour format – no seconds (17:45)
T Time in 24 hour format (17:45:52)
X Same as ‘T’
Z Time zone offset from Universal Time Coordinate (UTC) (-07)
Hour:
H Hour in 24-hour format (17)
I Hour in 12 hour format (05)
k Same as ‘H’
l Same as ‘I’ (Upper-case I = Lower-case L)
Minutes & Seconds:
M Minutes (35)
S Seconds (05)
s Seconds elapsed since January 1, 1970 00:00:00 (1150451174.95705)
Special Characters:
n newline character (\n)
t Tab character (\t)
As you can see there are a lot of options for formatting the output of the Get-Date cmdlet. First, we’ll start simple and build out to a complex date format that can be used for file names.
Day, Month, Year
Now depending on your locality, the exact arrangement of the digits will differ. The key is to remember what you used for your date format. Because June 6, 2018 (20180606, 2018-06-06, 06-06-2018, 06-06-2018) is an easy one to work with. Whereas December first may cause confusion (20181201, 2018-12-01, 12-01-2018, 01-12-2018).
yyyy-mm-dd 2018-09-25
yyyy-dd-mm 2018-25-09
mm-dd-yyyy 09-25-2018
Dd-mm-yyyy 25-09-2018
For a script that is run on a daily basis, this is a good, simple data to return. Applying this to a log or data file is simple, like so:
[sourcecode language=”powershell”]
$OutPutFileNameBase1 = 'AllMailboxes-Cloud'
$LogFileNameBase1 = 'ScriptErrorLog'
$CurrentDate = Get-Date -Format yyyy-mm-dd
$OutPutFileNameFull1 = $OutPutFileNameBase1+"-"+$CurrentDate
$LogFileNameFull1 = $LogFileNameBase1+"-"+$CurrentDate
[/sourcecode]
Now we have a simple and unique name (if the script is run daily) allowing us to use this for logs, output and error files, for example. Now what if the script runs more often or needs a finer pinpoint on when the output file was generated? Well, we need to add some more detail to the date added to the file name.
[sourcecode language=”powershell”]
$CurrentDate = Get-Date -Format yyyymmdd-hhmmss
[/sourcecode]
Using the previous code as an example and changing the date format to be more specific, the code looks like this:
[sourcecode language=”powershell”]
$OutPutFileNameBase1 = 'AllMailboxes-Cloud'
$LogFileNameBase1 = 'ScriptErrorLog'
$CurrentDate = Get-Date -Format yyyyymmdd-hhmmss
$OutPutFileNameFull1 = $OutPutFileNameBase1+"-"+$CurrentDate
$LogFileNameFull1 = $LogFileNameBase1+"-"+$CurrentDate
[/sourcecode]
The output then looks like this:
Uniqueness Factor Type – Random Number
Another way to generate unique files is to keep the same base file name and add a random number to the end of the file. Depending on how often these files are generated, the number of digits for the random number may need to be high. Because there is absolutely no guarantee that the filename will be unique, you may need to build in logic to check for an existing file of that same name to prevent overwriting files. This caveat is one of the biggest reasons to use the Date in the file name and not a random number.
If we look for cmdlets in PowerShell that contain the word ‘Random’ in it:
Get-Command *random*
We see that there is only one cmdlet that meets that criteria. If we type the cmdlet into a PowerShell session, it generates a random 9+ digit number. Below are three samples from the cmdlet when run one after the other:
1131270443
556361410
1225835655
In order to tweak the output, you can set a minimum number, a maximum number and even provide a seed number to help generate the random numbers. For creating file names, the default length will probably be sufficient:
[sourcecode language=”powershell”]
$Random = Get-Random
[/sourcecode]
So using the code example from the previous example, we get something like this:
[sourcecode language=”powershell”]
$OutPutFileNameBase1 = 'AllMailboxes-Cloud'
$LogFileNameBase1 = 'ScriptErrorLog'
$Random = Get-Random
$OutPutFileNameFull1 = $OutPutFileNameBase1+"-"+$Random
$LogFileNameFull1 = $LogFileNameBase1+"-"+$Random
[/sourcecode]
If we are worried about duplicate file names, we can introduce logic to handle this:
[sourcecode language=”powershell”]
$RandomCheck1 = $OutPutFileNameBase1+"-"+$Random
If (-NOT (Test-Path $RandomCheck1)) {$OutPutFileNameFull1 = $OutPutFileNameBase1+"-"+$Random}
$RandomCheck2 = $LogFileNameBase1+"-"+$Random
If (-NOT (Test-Path $RandomCheck2)) {$LogFileNameFull1 = $LogFileNameBase1+"-"+$Random}
[/sourcecode]
Now when we run this, we’ll get these names for the files:
That’s it. Now you can go create your random files for output from your scripts.