How do I pass DateTime as a parameter in PowerShell? - datetime

I have a script that's calling another script and passing in parameters along with it. Whenever I try to pass in a datetime, parts of the datetime are used as arguments for the other parameters.
script1.ps1
$dateEnd = Get-Date "12/31/14"
$siteUrl = "http://foo.com"
$outputPath = "c:\myFolder"
$argumentList = "-file .\script2.ps1", "test1", $dateEnd, $siteUrl, $outputPath
Start-Process powershell.exe -ArgumentList $argumentList
script2.ps1
param
(
[string]$test1,
[DateTime]$dateEnd,
[string]$siteUrl,
[string]$outputFile
)
$test1
$dateEnd
$siteUrl
$outputFile
Read-Host -Prompt "Press Enter to exit"
This would result in:
test1
Wednesday, December 31, 2014 12:00:00 AM
00:00:00
http://foo.com
EDIT - string as date, typo on my part:
If I pass the string 12/31/14 it works fine, but I'd like to be able to pass a date.

In the line which assigns $argumentList, change the $dateEnd parameter to be $dateEnd.toString('s').
Arguments to Windows processes are strings, and not objects, so Start-Process must convert the ArgumentList into a string. Powershell.exe then parses that string by splitting on spaces (like any Windows process), and it turns it back into your parameters.
Normally, this should work perfectly well, but in this case notice what happens when you run (get-date).tostring(). The default output for a DateTime object contains a space, which is interfering with the parsing.
The solution, then, is to format the date parameter in your argument list to have no spaces and yet still be in a format that DateTime::Parse() can understand (so PowerShell can reload the variable on the other end). Passing 's' to DateTime::toString() gives you such a format.

This is due to a combination of positional parameter usage and quoting. Here's a single change that should make it work (quoted the date input):
$argumentList = "-file D:\script2.ps1", "test1", "`"$dateEnd`"", $siteUrl, $outputPath
Is there any reason you call a separate PowerShell process? You could call this like so:
#This will run in separate scope
& ".\script2.ps1" test1 $dateEnd $siteUrl $outputPath
#This will run in the local (current) scope:
. ".\script2.ps1" test1 $dateEnd $siteUrl $outputPath

I think this is an issue of you not using DateTime objects correctly. If you want to specify a date, then do so. What you suggest as your string is a Time, not a date. If you want to specify both then provide both to Get-Date.
$endDate = "12/31/14 08:00:00"
That's 8:00 AM on December 31st.
Then in your script call whatever it is that you want specifically.
param
(
[string]$test1,
[DateTime]$dateEnd,
[string]$siteUrl,
[string]$outputFile
)
$test1
$dateEnd.ToLongDateString()
$dateEnd.ToLongTimeString()
$siteUrl
$outputFile
When a DateTime object is passed to that (shown here with your other test data) you should get:
test1
Wednesday, December 31, 2014
8:00:00 AM
http://foo.com
C:\myfolder

Related

How to format a date in Visual Basic?

In Visual Basic, I have an object with an ItemDate key in it with the value being assigned to a label in ASPX. Here is the code:
lblItemDate.Text = .ItemDate
The result on the front end is '2021/11/15'. I want the result to be: 'November 15, 2021'
What do I need to do in Visual Basic to make the result on the front end be 'November 15, 2021' instead of '2021/11/15'?
In another VB file, the ItemDate object key is created this way:
oItem.ItemDate = Trim(odbcReader("ItemDate").ToString)
Assuming you really have a .Net DateTime struct:
lblItemDate.Text = .ItemDate.ToString("MMMM dd, yyyy")
Otherwise you have a string, in which case you want to parse into a .Net DateTime struct so you can use the same ToString() call above:
Dim MyDate As DateTime = DateTime.ParseExact( .ItemDate, "yyyy/MM/dd")
lblItemDate.Text = MyDate.ToString("MMMM dd, yyyy")
Even better if you can update your code so ItemDate is a DateTime value in the first place, and the Parse() call is moved to the point where the object is first created.
It's been a while, so I don't recall whether the .ItemDate shortcut is available in the context of a function call. You may need to use the full version of the variable name.
Besides the .Net functions mentioned in another answer, which work across different languages, there is also the Format(..) function traditionally included with professional implementations of BASIC since the early 70's (I first used it in DEC's BASIC-Plus in 1976).
To get 'November 15, 2021' you'd do it like this:
lblItemDate.Text = Format(.ItemDate, "MMMM d, yyyy")

Drupal7 format_date

Somebody could help me to how to change string date with format_date function.
Here is my code$datesql = format_date("2014-04-02 11:11:31", 'custom', 'Y-m-d');
drupal_set_message(t('date '.$datesql));
I suppose drupal to show this message "date 2014-04-02", but drupal just show the message "date", not $datesql. What is wrong in my code.
Thanks
Function "format_date" expects first parameter to be a timestamp, not a string. Try to wrap this first parameter with "strtotime" function and you will get a better result.
PS: do not include a variable in the first parameter of the "t" function. This could result in a lot of translatable strings. Pass it in the second parameter with "#myvar" as key. Check the "t" function documentation for more details.
try this
$date = new DateTime('2014-04-02 11:11:31');
$da = $date->format('Y-m-d H:i:s');
drupal_set_message('date '.$da,'status');
format_date() is use a covert a date in drupal created date not a convert a custom date
format_date($node->created, 'custom', 'Y-m-d');

DateTime parsing in PowerShell

I'm trying to write a PowerShell script that will generate a table of information with two columns: a name, and a date (which will be retrieved from a third-party application - in this case svn.exe).
The overall script works well, but I'm struggling to get the date that the server sends back into the DataTable. Here's a simplified version of my script:
# Set up a DataTable and initialise columns
$table = New-Object system.Data.DataTable “Test Table”
$col1 = New-Object system.Data.DataColumn Name,([string])
$col2 = New-Object system.Data.DataColumn DateFromServer,([DateTime])
$table.columns.add($col1)
$table.columns.add($col2)
# Create a new row and add the data
$row = $table.NewRow()
$row.Name = "Test"
$lastCommit = GetDateFromExternalApp
$lastCommit.GetType() # this returns DateTime as I would expect
$row.DateFromServer = $lastCommit # this throws up an error
$table.Rows.Add($row)
# Output the table
$table | Format-Table -AutoSize
# This function simulates what the actual function does
# (the real one goes to SVN and pulls down data, but it
# ends up with the same resulting date)
Function GetDateFromExternalApp
{
$externalAppDate = "2012-09-17T16:33:57.177516Z"
return [DateTime]($externalAppDate)
}
The problem (noted in comments in the script above) is that while the function seems to be happily returning a DateTime instance, when I try to add this into the table row's DateFromServer column it's throwing up an error:
Exception setting "DateFromServer": "Unable to cast object of type 'System.Management.Automation.PSObject' to type 'System.IConvertible'.Couldn't store <18/09/2012 2:33:57 AM> in DateFromServer Column. Expected type is DateTime." At line:13 char:6
+ $row. <<<< DateFromServer = $lastCommit
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : PropertyAssignmentException
However, the call to $lastCommit.GetType() shows that this is indeed a DateTime - and in fact if I add this line somewhere in the script:
$lastCommit
then I can see a nicely formatted datetime, suggesting that it is indeed parsing it and converting it correctly:
Date : 18/09/2012 12:00:00 AM
Day : 18
DayOfWeek : Tuesday
DayOfYear : 262
Hour : 2
Kind : Local
Millisecond : 177
Minute : 33
Month : 9
Second : 57
Ticks : 634835324371775160
TimeOfDay : 02:33:57.1775160
Year : 2012
DateTime : Tuesday, 18 September 2012 2:33:57 AM
As such I'm quite puzzled as to why I'm getting the exception above. I realise that PowerShell does function return values differently than C#, but it looks to me like the function is returning the right type!
The issue here is due to a bug in PowerShell's type adaptation system (I would recommend reporting this to Microsoft if you have not already done so).
When you work with objects in PowerShell, you are actually working with a PSObject wrapper. Most calls (like GetType) are forwarded to the underlying object, though you can add additional members that do not interact with the object itself:
PS> Get-Date | Add-Member NoteProperty Yowza 'for example' -PassThru | Format-List y*
Yowza : for example
Year : 2012
Normally this is not an issue, as PowerShell has extensive type coercion capabilities. In the case of DataRow however, there appears to be a bug with the DataRowAdapter type used to support the property access syntax. If you use the indexer directly, $row['DateFromServer'] = $lastCommit instead of $row.DateFromServer, the value is correctly unwrapped before it is sent to the .NET type.
You can also get around this by unwrapping the value yourself, either using a cast (as vonPryz already showed: [DateTime]$lastCommit), or by retrieving the BaseObject ($lastCommit.PSObject.BaseObject).
I'd like to know the reason for this behaviour too.
Anyway, you can work around the problem by casting the date variable as DateTime or by explicitly declaring it to be one. Like so,
...
$row.DateFromServer = [DateTime]$lastCommit # Doesn't throw exception
...
Or
...
[DateTime]$lastCommit = GetDateFromExternalApp
$row.DateFromServer = $lastCommit # Doesn't throw exception
...
I suspect the reason is as stated in the error message:
"Unable to cast object of type 'System.Management.Automation.PSObject' to type 'System.IConvertible'...Expected type is DateTime." At line:13 char:6
What that is saying is that PowerShell tried to convert $lastCommit into a date and time but failed. The best way is, as vonPryz suggests - cast it to [datetime]
To see the issue more clearly, try looking at the both:
$lastcommit.gettype() and
$row.DateFromServer.gettype()
I don't have the GetDateFromExternalApp to check

In PowerShell, how do I convert DateTime to UNIX time?

In PowerShell, how can I convert string of DateTime to sum of seconds?
PS H:\> (New-TimeSpan -Start $date1 -End $date2).TotalSeconds
1289923177.87462
New-TimeSpan can be used to do that. For example,
$date1 = Get-Date -Date "01/01/1970"
$date2 = Get-Date
(New-TimeSpan -Start $date1 -End $date2).TotalSeconds
Or just use this one line command
(New-TimeSpan -Start (Get-Date "01/01/1970") -End (Get-Date)).TotalSeconds
With .NET Framework 4.6 you can use ToUnixTimeSeconds method of DateTimeOffset class:
[DateTimeOffset]::Now.ToUnixTimeSeconds()
$DateTime = Get-Date #or any other command to get DateTime object
([DateTimeOffset]$DateTime).ToUnixTimeSeconds()
As mentioned, the UNIX Epoch is January 1st, 1970 at 12:00 AM (midnight) UTC.
To get the current seconds-since-the-epoch in UTC in a whole-number I use this 80-character one-liner
$ED=[Math]::Floor([decimal](Get-Date(Get-Date).ToUniversalTime()-uformat "%s"))
The code above is PowerShell 2.0 compliant & rounds-down (to ensure consistent behavior w/ UNIX)
Not sure when -UFormat was added to Get-Date but it allows you to get the date and time in UNIX epoch timestamp format:
[int64](Get-Date -UFormat %s)
It's supported by both the PowerShell and PowerShell Core.
This one-liner works for me (compared it to http://www.unixtimestamp.com/)
[int64](([datetime]::UtcNow)-(get-date "1/1/1970")).TotalSeconds
For milliseconds
[int64](([datetime]::UtcNow)-(get-date "1/1/1970")).TotalMilliseconds
To get seconds since 1970 independent of time zone, I would go with:
$unixEpochStart = new-object DateTime 1970,1,1,0,0,0,([DateTimeKind]::Utc)
[int]([DateTime]::UtcNow - $unixEpochStart).TotalSeconds
I just wanted to present yet another, and hopefully simpler, way to address this. Here is a one liner I used to obtain the current Unix(epoch) time in UTC:
$unixTime = [long] (Get-Date -Date ((Get-Date).ToUniversalTime()) -UFormat %s)
Breaking this down from the inside out:
(Get-Date).ToUniversalTime()
This gets the current date/time in UTC time zone. If you want the local time, just call Get-Date.
This is then used as input to...
[long] (Get-Date -Date (UTC date/time from above) -UFormat %s)
Convert the UTC date/time (from the first step) to Unix format.
The -UFormat %s tells Get-Date to return the result as Unix epoch time (seconds elapsed since January 01, 1970 00:00:00). Note that this returns a double data type (basically a decimal). By casting it to a long data type, it is automatically converted (rounded) to a 64-bit integer (no decimal). If you want the extra precision of the decimal, don't cast it to a long type.
Extra credit
Another way to convert/round a decimal number to a whole number is to use System.Math:
[System.Math]::Round(1485447337.45246)
Powershell
$epoch = (Get-Date -Date ((Get-Date).DateTime) -UFormat %s)
I suggest the following, which is based on ticks (Int64), rather than seconds (Int32), to avoid the Year 2038 problem. [Math]::Floor is used, as Unix time is based on the number of whole seconds since the epoch.
[long][Math]::Floor((($DateTime.ToUniversalTime() - (New-Object DateTime 1970, 1, 1, 0, 0, 0, ([DateTimeKind]::Utc))).Ticks / [timespan]::TicksPerSecond))
Here's a script which converts both TO and FROM CTIME that I've been using for a while (longer, because it was written for a "new to scripting" type crowd, with various comments.
# Here's a very quick variant to 'get the job done'
[Int64]$ctime=1472641743
[datetime]$epoch = '1970-01-01 00:00:00'
[datetime]$result = $epoch.AddSeconds($Ctime)
write-host $result
# A few example values for you to play with:
# 1290100140 should become ... 2010-11-18 17:09:00.000
# 1457364722 should become ... 2016-03-07 15:32:02.000
# 1472641743 should become ... 31/08/2016 11:09:03
# For repeated use / calculations, functions may be preferable. Here they are.
# FROM C-time converter function
# Simple function to convert FROM Unix/Ctime into EPOCH / "friendly" time
function ConvertFromCtime ([Int64]$ctime) {
[datetime]$epoch = '1970-01-01 00:00:00'
[datetime]$result = $epoch.AddSeconds($Ctime)
return $result
}
# INTO C-time converter function
# Simple function to convert into FROM EPOCH / "friendly" into Unix/Ctime, which the Inventory Service uses.
function ConvertToCTime ([datetime]$InputEpoch) {
[datetime]$Epoch = '1970-01-01 00:00:00'
[int64]$Ctime = 0
$Ctime = (New-TimeSpan -Start $Epoch -End $InputEpoch).TotalSeconds
return $Ctime
}
Hope that helps, especially if you just want something that's a little friendlier for beginners or so :).
For sending data to Grafana I needed the Unix Epoch time as 32 bit Integer from UTC. The best solution in the end was this:
$unixtime = (get-date -Date (get-date).ToUniversalTime() -UFormat %s).Substring(0,10)
This results in a string, but can easy converted to an integer:
[int]$unixtime = (get-date -Date (get-date).ToUniversalTime() -UFormat %s).Substring(0,10)
I tested this against an Ubuntu machine. The results from the commands above and the Linux command
date +%s
are identically.
Below cmdlet will convert the windows uptime into Unix understandable epoch time format:
$s=Get-WmiObject win32_operatingsystem | select csname,#{LABEL='LastBootUpTime';EXPRESSION{$_.ConverttoDateTime($_.lastbootuptime)}};
[Math]::Floor([decimal](Get-Date($s.LastBootUpTime.ToUniversalTime()).ToUniversalTime()-uformat "%s"))
Again comparing to http://www.unixtimestamp.com and building on others above
$date1 = (Get-Date -Date "01/01/1970").ToUniversalTime()
$date2 = (Get-Date).ToUniversalTime()
$epochTime = [Math]::Floor((New-TimeSpan -Start $date1 -End $date2).TotalSeconds)
This one should also work since javascript uses milliseconds since epoch :
ConvertTo-Json (Get-Date) | ? { $_ -Match '\(([0-9]+)\)' } | % { $Matches[1]/1000 }
Step by Step :
PS P:\> Get-Date
lundi 15 janvier 2018 15:12:22
PS P:\> ConvertTo-Json (Get-Date)
{
"value": "\/Date(1516025550690)\/",
"DisplayHint": 2,
"DateTime": "lundi 15 janvier 2018 15:12:30"
}
PS P:\> (ConvertTo-Json (Get-Date)) -Match '\(([0-9]+)\)'
True
PS P:\> $Matches
Name Value
---- -----
1 1516025613718
0 (1516025613718)
You can use the Uformat parameter of get-date. But first I like to be sure the date of a given workstation is correct (I consider a workstation connected to a company network where there is a server with a correct time set).
#Synchronize workstation time with server
cmd /c "sc config w32time start= auto"
cmd /c "w32tm /unregister"
cmd /c "w32tm /register"
cmd /c "net start w32time"
cmd /c 'tzutil.exe /s "W. Europe Standard Time"'
cmd /c 'reg add "HKLM\SYSTEM\CurrentControlSet\Control\TimeZoneInformation" /v DisableAutoDaylightTimeSet /t REG_DWORD /d 0 /f'
cmd /c "net time \\full-servername.ru /set /yes"
Then I get the actual unix timestamp to compare objects (accounts) between actual date and creation date (account deletion tasks when unix timestamp exceeds limit date)
#Get actual unix timestamp and compare it to something
$actual_date = (get-date -UFormat "%s")
$final_date = "some unix date of the database"
if(($final_date - $actual_date) -lt 0 ){
#make deletion task
}
Signal15's answer is a bit verbose for me. I did it this way:
[int] (Get-Date (Get-Date).ToUniversalTime() -uformat '%s')
Late answer...
Hare are both convert functions ConvertTo-UnixTime & ConvertFrom-UnixTime for convenience (both pipeline capable)
function ConvertFrom-UnixTime () {
[CmdletBinding()]
param(
[Parameter(Mandatory, ValueFromPipeline, Position = 0)]
[Int64]$UnixTime
)
begin {
$epoch = [DateTime]::SpecifyKind('1970-01-01', 'Utc')
}
process {
$epoch.AddSeconds($UnixTime)
}
}
function ConvertTo-UnixTime {
[CmdletBinding()]
param(
[Parameter(Mandatory, ValueFromPipeline, Position = 0)]
[DateTime]$DateTime
)
begin {
$epoch = [DateTime]::SpecifyKind('1970-01-01', 'Utc')
}
process {
[Int64]($DateTime.ToUniversalTime() - $epoch).TotalSeconds
}
}
A culture-independent, and actually pretty fast answer:
[int64]([double]::Parse((get-date -uformat "%s"),[cultureinfo][system.threading.thread]::currentthread.currentculture))
This invokes some .NET "magic" when it comes to actually produce a formatted string, it gets converted to double using current thread's culture settings, then it converts to int64 which by default does exactly floor the double provided. Should you desire a UTC timestamp, use -date ([DateTime]::UtcNow) in get-date to use current UTC time as the time to convert.
[int64]([double]::Parse((get-date -date ([DateTime]::UtcNow) -uformat "%s"),[cultureinfo][system.threading.thread]::currentthread.currentculture))
PS: Unless you really need a string as your output, having an integer is overall better to your programming culture.

How to format a DateTime in PowerShell

I can format the Get-Date cmdlet no problem like this:
$date = Get-Date -format "yyyyMMdd"
But once I've got a date in a variable, how do I format it? The statement below
$dateStr = $date -format "yyyMMdd"
returns this error:
"You must provide a value expression
on the right-hand side of the '-f'
operator"
The same as you would in .NET:
$DateStr = $Date.ToString("yyyyMMdd")
Or:
$DateStr = '{0:yyyyMMdd}' -f $Date
A simple and nice way is:
$time = (Get-Date).ToString("yyyy:MM:dd")
The question is answered, but there is some more information missing:
Variable vs. Cmdlet
You have a value in the $Date variable and the -f operator does work in this form: 'format string' -f values. If you call Get-Date -format "yyyyMMdd" you call a cmdlet with some parameters. The value "yyyyMMdd" is the value for parameter Format (try help Get-Date -param Format).
-f operator
There are plenty of format strings. Look at least at part1 and part2. She uses string.Format('format string', values'). Think of it as 'format-string' -f values, because the -f operator works very similarly as string.Format method (although there are some differences (for more information look at question at Stack Overflow: How exactly does the RHS of PowerShell's -f operator work?).
A very convenient -- but probably not all too efficient -- solution is to use the member function GetDateTimeFormats(),
$d = Get-Date
$d.GetDateTimeFormats()
This outputs a large string-array of formatting styles for the date-value. You can then pick one of the elements of the array via the []-operator, e.g.,
PS C:\> $d.GetDateTimeFormats()[12]
Dienstag, 29. November 2016 19.14
One thing you could do is:
$date.ToString("yyyyMMdd")
Do this if you absolutely need to use the -Format option:
$dateStr = Get-Date $date -Format "yyyMMdd"
However
$dateStr = $date.toString('yyyMMdd')
is probably more efficient.. :)
Very informative answer from #stej, but here is a short answer:
Among other options, you have 3 simple options to format [System.DateTime] stored in a variable:
Pass the variable to the Get-Date cmdlet:
Get-Date -Format "HH:mm" $date
Use toString() method:
$date.ToString("HH:mm")
Use Composite formatting:
"{0:HH:mm}" -f $date
For anyone trying to format the current date for use in an HTTP header use the "r" format (short for RFC1123) but beware the caveat...
PS C:\Users\Me> (get-date).toString("r")
Thu, 16 May 2019 09:20:13 GMT
PS C:\Users\Me> get-date -format r
Thu, 16 May 2019 09:21:01 GMT
PS C:\Users\Me> (get-date).ToUniversalTime().toString("r")
Thu, 16 May 2019 16:21:37 GMT
I.e. Don't forget to use "ToUniversalTime()"
If you got here to use this in cmd.exe (in a batch file):
powershell -Command (Get-Date).ToString('yyyy-MM-dd')
I needed the time and a slight variation on format. This works great for my purposes:
$((get-date).ToLocalTime()).ToString("yyyy-MM-dd HHmmss")
2019-08-16 215757
According to #mklement0 in comments, this should yield the same result:
(get-date).ToString("yyyy-MM-dd HHmmss")
Format Date Time to your Output Needs
If you want to format the date and assign the string to a variable.
I have combined both PowerShell and .NET to provide the flexibility.
$oDate = '{0}' -f ([system.string]::format('{0:yyyyMMddHHmmss}',(Get-Date)))
How this Works
PowerShell Operator - '{0}' -f (.....)
.NET Notation - [system.string]::format('customformat',InputObject)
Customised Format by combining PowerShell with .NET - '{0:yyyyMMddHHmmss}'
Input Object provided by PowerShell cmdlet - (Get-Date)
Stored in the PowerShell variable - $oDate
Example
If the date and time when run was Monday, 5 July 2021 5:45:22 PM (Format '{0:F}').
$oDate = 20210705174522
Using the Code
You can customise the the string to meet your requirements by modifying 'yyyMMddHHmmss' using the Microsoft .NET Custom Date Time Notation.
You could just use this to select the format you want and then past it wherever it is needed.
$DTFormats = (Get-Date).GetDateTimeFormats()
$Formats = #()
$i=0
While ($i -lt $DTFormats.Count){
$row = [PSCustomObject]#{
'IndexNumber' = $i
'DateTime Format' = $DTFormats[$i]
}
$Formats += $row
$i++
}
$DTSelection = ($Formats | Out-GridView -OutputMode Single -Title 'Select DateTime Format').IndexNumber
$MyDTFormat = "(Get-Date).GetDateTimeFormats()[$DTSelection]"
Write-Host " "
Write-Host " Use the following code snippet to get the DateTime format you selected:"
Write-Host " $MyDTFormat" -ForegroundColor Green
Write-Host " "
$MyDTFormat | Clip
Write-Host " The code snippet has been copied to your clipboard. Paste snippet where needed."
I converted my dueDate string to a datetime then formatted it.
[Datetime]::ParseExact($dueDate,'MM/dd/yyyy H:mm:ss',$null).ToString('MM/dd/yyyy')

Resources