I am storing timestamps in Azure AD User Extension Properties for a custom application.
My extension property is a String data type (available data types are String and Binary).
I am using -format o to get my timestamp string:
[String]$thisTimestamp = (Get-Date -f o)
This gives me a string containing my timestamp formatted as follows:
2017-11-17T18:26:13.5537900+00:00
When I store this string value in my AzureAD Extension Property it appears to go through a String-DateTime-String conversion which results in the default date formatting as follows:
Set-AzureADUserExtension -ObjectId $aadUser.ObjectId -ExtensionName $thisExtensionID -ExtensionValue $thisTimestamp
(Get-AzureADUserExtension -ObjectId $aadUser.ObjectId).get_item($thisExtensionID)
Returns: 17/11/2017 18:26:13
Looking at the stored value in the MS Graph Explorer, it is stored correctly as a timestamp. However, when I Get the value, either with Get-AzureADUserExtension or with Get-AzureADUser and examine the properties, the stored value is always returned as a string, with the format modified:
((Get-AzureADUser -ObjectId $aadUser.ObjectId).extensionproperty).$thisExtensionID
Returns:
17/11/2017 18:26:13
I have a workaround - adding a trailing space to my timestamp. This is correctly stored as a string, and converts back to a DateTime correctly.
[String]$thisTimestamp = (Get-Date -f o) + " "
Set-AzureADUserExtension -ObjectId $aadUser.ObjectId -ExtensionName $thisExtensionID -ExtensionValue $thisTimestamp
(Get-AzureADUserExtension -ObjectId $aadUser.ObjectId).get_item($thisExtensionID)
Returns: 2017-11-17T18:26:13.5537900+00:00 (with a trailing space)
$testDateTime = Get-Date (Get-AzureADUserExtension -ObjectId $aadUser.ObjectId).get_item($thisExtensionID)
Correctly creates a DateTime object and returns:
17 November 2017 18:26:13
It seems wrong to me that the Get-AzureADUser cmdlet and the Get-AzureADUserExtension (which I assume is based on Get-AzureADUser) seem to be interfering with the string as it is retrieved. Is this a bug, or am I doing something stoopid?
Related
I cannot parse and make a call using the current URL because when I use the $filter and $select query parameters it breaks the string, yet it works great in Postman and give me all the data I needed.
Connect-MSGraph
Invoke-MSGraphRequest -Url "https://graph.microsoft.com/beta/deviceManagement/managedDevices?$select=emailaddress,id,imei,operatingSystem,ownerType,managedDeviceOwnerType&$filter=(operatingSystem eq 'iOS')" -HttpMethod GET
I need to filter these devices then if the ownership is personal, I was going to use graph API again to Update the object device using PATCH. Please help with this
https://learn.microsoft.com/en-us/graph/query-parameters#filter-parameter
https://learn.microsoft.com/en-us/graph/api/intune-devices-manageddevice-get?view=graph-rest-1.0
The immediate solution to your problem is to simply escape the verbatim $'s with a backtick `:
Invoke-MSGraphRequest -Url "https://graph.microsoft.com/beta/deviceManagement/managedDevices?`$select=emailaddress,id,imei,operatingSystem,ownerType,managedDeviceOwnerType&`$filter=(operatingSystem eq 'iOS')" -HttpMethod GET
Or to use single-quotes ' to avoid PowerShell attempting to expand what looks like variables - literal single-quotes inside the URL will have to be escaped by doubling them:
Invoke-MSGraphRequest -Url 'https://graph.microsoft.com/beta/deviceManagement/managedDevices?$select=emailaddress,id,imei,operatingSystem,ownerType,managedDeviceOwnerType&$filter=(operatingSystem eq ''iOS'')' -HttpMethod GET
That being said, I'd personally recommend constructing the query parameters from simpler parts:
$endpointURL = 'https://graph.microsoft.com/beta/deviceManagement/managedDevices'
# assign variable parts of the filter to a variable
$targetOperatingSystem = 'iOS'
# construct a hashtable containing all the query parameters
$GraphParameters = [ordered]#{
'$select' = 'emailaddress,id,imei,operatingSystem,ownerType,managedDeviceOwnerType'
'$filter' = "(operatingSystem eq '$targetOperatingSystem')"
}
# construct query string and final URL from the individual parts above
$queryString = $GraphParameters.GetEnumerator().ForEach({ $_.Key,$_.Value -join '=' }) -join '&'
$URL = $endpointURL,$queryString -join '?'
And then finally invoke Invoke-MSGraphRequest -Url $URL -HttpMethod Get
I have a Csv file with 3 strings for DateTime.
Date;
202202230930;
202202220815;
202202220612;
Because I have to use the Date for naming Snapshots on Proxmox i cant use the - sign. I wanna convert these Dates in to yyyy-MM-dd HH:mm
Now i wanna create a datetime variable in Powershell using that csv file. With the format 'yyyy.MM.dd HH:mm'
I created a foreach so for each date it will ParseExact the string into a datetime.
$datesnapshot = import-csv -Path "D:\autosnap\Datetime.csv" -Delimiter ";"
Foreach($Date in $datesnapshot){
[datetime]::ParseExact($datesnapshot, 'yyyyMMddHH:mm', $null).ToString('yyyy-MM-dd HH:mm')
}
I get the error "String was not recognized as a valid DateTime." I don't know where the problem is because i typed in the Date it is expected to parse and the date i wanna receive. I hope somebody can help.
Kind regards
A few things to note, the first one:
[datetime]::ParseExact($datesnapshot...
You're iterating over the collection $datesnapshot but also you're giving ParseExact the same collection as argument, it should be $date (the item) instead. In addition, your CSV generates an array of objects (object[]), where each object has a property with name Date. If you want to reference the value of your objects you should be using $date.Date. See about_Properties for more info.
Lastly, the format you're yyyyMMddHH:mm using will not correctly parse your dates. The format you should use is yyyyMMddHHmm.
$datesnapshot = #'
Date;
202202230930;
202202220815;
202202220612;
'# | ConvertFrom-Csv -Delimiter ';'
foreach($Date in $datesnapshot){
[datetime]::ParseExact($Date.Date, 'yyyyMMddHHmm', [cultureinfo]::InvariantCulture).ToString('yyyy-MM-dd HH:mm')
}
I have below code in PS:
Connect-AzureAD
$PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent
Get-AzureADUser -All:$true |Select ObjectId,UserPrincipalName,#{Name='ExpirationDate'; Expression={(Get-AzureADUserExtension -ObjectId $_.ObjectId).Get_Item("createdDateTime")}}
| Export-CSV "$PSScriptRoot\userslist.csv"
Disconnect-AzureAD
I want to convert string createdDateTime to a dateTime format, so I can add +60 days to it (.AddDays(60)). I tried without conversion but it didn't work.
Expression={(...).Get_Item("createdDateTime")}}
I tried also with function [datetime]::ParseExact but I did something wrong (no error in the console), because the column in output was blank.
Please advise
EDIT
This is what I get after I run the whole script Pamela gave. No error in the console. Any ideas why is so?
Tried with your code and get the time, it looks like "2/16/2021 5:55:03 AM":
So I format the string with 'M/d/yyyy H:mm:ss tt'.
$string = "2/16/2021 5:55:03 AM"
[Datetime]::ParseExact($string, 'M/d/yyyy H:mm:ss tt', $null)
As you said in the comment, your CreationDate is like "19.10.2020 13:55:29", so d.M.yyyy H:mm:ss should work(not sure M or MM in yours, you could check more CreationDate).
Format the datetime and add 60 days:
Get-AzureADUser -All:$true |Select ObjectId,UserPrincipalName,#{Name='ExpirationDate'; Expression={[Datetime]::ParseExact((Get-AzureADUserExtension -ObjectId $_.ObjectId).Get_Item("createdDateTime"), 'd.M.yyyy H:mm:ss', $null).AddDays(60)}}
I have folders on the disk in the german format: "01.05.2019", which I want to convert into the english format: "2019-05-01".
I am using PowerShell. Is there a fancy function for doing this? Or should I get all substrings and reorder them?
Currently I only collect the strings:
$OrgDir = "P:\Fotos\Import"
$folders = Get-ChildItem $($OrgDir) -Directory
foreach ($dir in $folders) {
Write-Host "folder: " $dir
}
Use [DateTime]::ParseExact() to avoid the date parser mixing up the month and day:
$OrgDir = "P:\Fotos\Import"
$folders = Get-ChildItem $OrgDir -Directory
foreach ($dir in $folders) {
Write-Host "folder: $([DateTime]::ParseExact($dir.Name, "dd.MM.yyyy", $null).ToString("yyyy-MM-dd"))"
}
The above prints out the converted names. To efficiently rename the files however, I recommend this:
Get-ChildItem $OrgDir -Directory |
ForEach-Object {
$_ | Rename-Item -NewName (
[DateTime]::ParseExact($_.Name, "dd.MM.yyyy", $null).ToString("yyyy-MM-dd")
)
}
This line of PowerShell renames all directories at $OrgDir to the new date format, given that all directories in the folder are named this way.
Reference
UPDATE:
As #Matt Johnson pointed out, $null uses your system default culture for ParseExact(string, format, culture) (as well as ToString(format, culture)). This may or may not cause problems based on what culture setting your system currently has.
To ensure these settings do not interfere with this function, use [System.Globalization.CultureInfo]::InvariantCulture for the culture parameters in both ParseExact() and ToString().
Matt Johnson provides important pointers in his comments:
To write robust code that works independently of what culture is in effect, specify the culture context explicitly, both when:
parsing strings as [datetime] instances
formatting [datetime] instances as strings
Therefore, use the following in your case:
PS> [datetime]::Parse('01.05.2019', [cultureinfo] 'de-DE').
ToString('yyyy-MM-dd', [cultureinfo]::InvariantCulture)
2019-05-01
Since 01.05.2019 is a valid (day-first) short date in German, no custom parsing is needed, only de-DE (German / Germany) as the cultural context.
.ToString('yyyy-MM-dd', [cultureinfo]::InvariantCulture) specifies an explicit output-format string; [cultureinfo]::InvariantCulture - the invariant culture (based on US-English) - as the cultural context ensures that the date is interpreted based on the Gregorian calendar.
Note that in PowerShell casts (e.g., [datetime] '01.05.2019') and string interpolation (e.g., "$(get-date)") always use the invariant culture - whereas calling [datetime]::Parse() and .ToString() without an explicit culture (format-provider) argument uses the current culture.
Finally this did the trick for me:
PS> [datetime]::Parse('01.05.2019', [cultureinfo] 'de-DE').
ToString('yyyy-MM-dd', [cultureinfo]::InvariantCulture)
All other solutions ended in:
Get-Date : Cannot bind parameter 'Date'. Cannot convert value "15.12.2019" to type "System.DateTime". Error: "String was not recognized as a valid DateTime."
Thanks a lot mklement0.
I've found myriad methods to retrieve data FROM a string with substrings, but what I want to do is create a new string that contains substrings. The reason for this is that I want to pass that string to a CSV through the Export-CSV cmdlet. This is in a PowerShell Forms created app.
So the plan would be to
1). Read the contents of each text box:
(e.g. $endusername.text $endusernumber.text $locationname.text)
2). Store those into a new string with substrings
($formoutput.endusername $formoutput.endusernumber $formoutput.locationname)
3). Output the string to a .CSV
Export-CSV -InputObject $formoutput "c:\output\formoutput.csv"
Basically, if I take any existing cmdlet (say, Get-Mailbox), store its output as a string, and then pass that string through the Export-CSV in the way explained above, it performs exactly the way I like - creating a .CSV with each of the substrings as a column, and the contents of that substring in the appropriately headed column. I just want to be able to do that with a string containing substrings that I define.
I think you are confusing nomenclature a little bit. It sounds like what you want is a custom object not a string. Here is some pseudo-code to get you going in the right direction:
$formOutput = New-Object PsCustomObject -Property #{'EndUserName' = $endUserName.Text;
'EndUserNumber' = $endUserNumber.Text;
'LocationName' = $locatioName.Text}
$formOutput | Export-CSV .\FileName.csv -NoTypeHeader