PowerShell's Get-Date and "Cannot bind parameter 'Date' to the target" - powershell

I am very confused of this error message:
Get-Date : Cannot bind parameter 'Date' to the target. Exception setting "Date": "Object reference not set to an instance of an object."
The problem line is:
$logondate = $(Get-Date $([datetime]::Parse( $user.LastLogonDate)) -Format 'yyyy-MM-dd HH:mm:ss')
# User is vartype: System.Management.Automation.PSMethod
#$user.LastLogonDate in debug with this value: 10.06.2014 14:26:13 (dd.MM.yyyy)
What does this error mean?
From 30 AD accounts there are only three with this ParameterBindingException.
Full error message:
Get-Date : Cannot bind parameter 'Date' to the target. Exception setting "Date": "Object reference not set to an instance of an object."
At C:\scripts\AD.ps1:309 char:28
+ $logondate = $(get-date <<<< $([datetime]::Parse( $user.LastLogonDate)) -Format 'yyyy-MM-dd HH:mm:ss')
+ CategoryInfo : WriteError: (:) [Get-Date], ParameterBindingException
+ FullyQualifiedErrorId : ParameterBindingFailed,Microsoft.PowerShell.Commands.GetDateCommand

You get that error, because for some reason Parse() cannot parse $user.LastLogonDate into a date. Perhaps because the user never logged on (so the value is $null), or because Parse() doesn't recognize the default date format.
However, the LastLogonDate property (as created by Get-ADUser) already holds a DateTime value. What you're trying to do here is: implicitly convert the date to a string, parse that string back into a date, then create a formatted string from it again.
Don't.
Simply format the DateTime value you already have:
PS C:\> $user = Get-ADUser $env:USERNAME -Property *
PS C:\> $user.LastLogonDate.GetType().FullName
System.DateTime
PS C:\> $user.LastLogonDate
Monday, July 11, 2014 8:50:38 AM
PS C:\> $user.LastLogonDate.ToString('yyyy-MM-dd HH:mm:ss')
2014-07-07 08:50:38
Add a check for $null values to prevent errors for users that never logged on:
if ($u.LastLogonDate -ne $null) {
$user.LastLogonDate.ToString('yyyy-MM-dd HH:mm:ss')
}

Related

Convert string to DateTime in Powershell from CSV

I'm having the weirdest and most annoying problem with dealing with a string here that I need to convert to DateTime.
I'm doing the exact same thing from 2 different CSV files - it works perfectly on the first one, keeps returning an error on the second one.
$userDateOut = Get-Date $sourceLine.Date_OUT -Format "dd/MM/yyyy"
$userDateOut = ($userDateOut -as [datetime]).AddDays(+1)
$userDateOut = Get-Date $userDateOut -Format "dd/MM/yyyy"
In the first CSV, Date_OUT is just 31/12/2021 for example, and in the second one it's 31/12/2021 0:00:00.
So before the 3 lines to create $userDateOut, I do
$userDateOut = $sourceLine.Date_OUT.SubString(0,10)
Which makes me end up with the same type of variable as with the first CSV
PS C:\Windows\system32> $userDateOut = $sourceLine.Date_Out.Substring(0,10)
PS C:\Windows\system32> $userDateOut
31/12/2021
PS C:\Windows\system32> $userDateOut.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True String System.Object
However, with this variable, I'm getting
PS C:\Windows\system32> $userDateOut = Get-Date $userDateOut -Format "dd/MM/yyyy"
Get-Date : Cannot bind parameter 'Date'. Cannot convert value "31/12/2021" to type "System.DateTime". Error: "String was not recognized as a valid DateTime."
At line:1 char:25
+ $userDateOut = Get-Date $userDateOut -Format "dd/MM/yyyy"
+ ~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Get-Date], ParameterBindingException
+ FullyQualifiedErrorId : CannotConvertArgumentNoMessage,Microsoft.PowerShell.Commands.GetDateCommand
And I don't know why... Can someone help ?
-Format just converts [datetime] to a [string] - it doesn't influence parsing of input strings in any way.
For that, you need [datetime]::ParseExact():
$dateString = '31/12/2021'
# You can pass multiple accepted formats to ParseExact, this should cover both CSV files
$inputFormats = #(
'dd/MM/yyyy H:mm:ss'
'dd/MM/yyyy'
)
$parsedDatetime = [datetime]::ParseExact($dateString, $inputFormat, $null)
You can then use Get-Date -Format to convert it back to an intended output format if needed:

PowerShell hashtable question - office 365

I need to set OOF message for around 80 users in O365.
I found a cmdlet Set-MailboxAutoReplyConfiguration which I can use to automate the procedure,
and it's looks fine but I'am probably missing something.
Here is the code:
$usersfile = import-csv "C:\Users\Out Of office bulk\Users.csv"
$setmailbox = #{
'Identity' = $usersfile.UserPrincipalName
'AutoReplyState' = 'Scheduled'
'externalaudience' = 'all'
'InternalMessage' = 'I am not here'
'ExternalMessage' = 'I am not here'
'StartTime' = '01/02/2020 01:00:00'
'EndTime' = '02/02/2020 23:00:00'
}
Set-MailboxAutoReplyConfiguration #setmailbox
my issue is with the Identity parameter,
when I run the $setmailbox
I can see that it showing the right UPN from the csv file:
Name Value
---- -----
AutoReplyState Scheduled
externalaudience all
Identity {blah#blah.com, blah2#blah.com}
StartTime 01/02/2020 01:00:00
EndTime 02/02/2020 23:00:00
InternalMessage I am not here
ExternalMessage I am not here
But when I run the script, i'am getting this error:
Cannot process argument transformation on parameter 'Identity'. Cannot convert the "System.Collections.ArrayList" value of type "System.Collections.ArrayList" to type "Microsoft.Exchange.Configuration.Tasks.MailboxLocationIdParameter".
+ CategoryInfo : InvalidData: (:) [Set-MailboxAutoReplyConfiguration], ParameterBindin...mationException
+ FullyQualifiedErrorId : ParameterArgumentTransformationError,Set-MailboxAutoReplyConfiguration
+ PSComputerName : outlook.office365.com
I've tried to change this:
'Identity' = $usersfile.UserPrincipalName
to almost any thing, and it didn't work.
Thanks a lot for your help.
PS:
I know that I can do something like that:
Import-Csv 'C:\Users.csv' | ForEach-Object {
$user = $_."UserPrincipalName"
Set-MailboxAutoReplyConfiguration `
-Identity $user -AutoReplyState Scheduled -StartTime "07/10/2018 01:00:00" `
-EndTime "7/15/2018 23:00:00" -InternalMessage "I am not here" -ExternalMessage "I am not here."
}
but for practice purposes I prefer to do it with the hash table in order to understand it better.
Solution:
thanks to #Lee_Dailey, I didn't noticed that the identity parameter accepts only one user each time, so the solution for multi user is to use the foreach-object.

SCCM - Change existing deployment deadlines with PowerShell

We use SCCM 2016 to install Microsoft updates and have multiple deployments with deadlines of past dates. I'd like to be able to push those deadlines to a future date using a script, as manually changing per deployment with the GUI is time consuming.
This command shows me the deployments of interest:
Get-CMDeployment | Select-Object -Property * | Where-Object {`
$_.SoftwareName -like '*SecurityUpdates*' -and $_.CollectionName -like '*Servers*'
}
My research shows I should use Set-CMSoftwareUpdateDeployment to modify the deadline of existing deployments. However this is where I'm stuck. According to the following thread, the parameters I should use to define a new deadline are DeploymentExpireDay and DeploymentExpireTime, as well as make sure the deployment is set to required:
https://social.technet.microsoft.com/Forums/ie/en-US/11f977f4-09d1-4127-b8ce-7cdb19c88d1b/update-deployment-installation-deadlines-via-powershell?forum=configmanagersecurity
Unsure how to construct a working command, I consulted the cmdlet's MS documentation: https://learn.microsoft.com/en-us/powershell/module/configurationmanager/set-cmsoftwareupdatedeployment?view=sccm-ps
Looking at the doco, DeploymentExpireDay and DeploymentExpireTime aren't listed in the parameters list. Only DeploymentExpireDateTime is in the list. However, to add to the confusion, those two parameters are included in the examples whereas DeploymentExpireDateTime is not.
I connect to SCCM like this:
#Load Configuration Manager PowerShell Module
Import-module ($Env:SMS_ADMIN_UI_PATH.Substring(0,$Env:SMS_ADMIN_UI_PATH.Length-5) + '\ConfigurationManager.psd1')
#Get SiteCode and set Powershell Drive
$SiteCode = (Get-PSDrive -PSProvider CMSITE).Name
Push-Location "$($SiteCode):\"
I tried this:
$DeadlineDay = Get-Date -Month 11 -Day 08 -Year 2018
$DeadlineTime = Get-Date -Hour 16 -Minute 0 -Second 0
Set-CMSoftwareUpdateDeployment `
-DeploymentName "Deployment Name" `
-DeploymentType Required `
-DeploymentExpireDay $DeadlineDay `
-DeploymentExpireTime $DeadlineTime
But I get this:
Set-CMSoftwareUpdateDeployment : A parameter cannot be found that matches parameter name 'DeploymentExpireDay'.
At line:1 char:104
+ ... ment Name" -DeploymentType Required -DeploymentExpireDay $Deadli ...
+ ~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Set-CMSoftwareUpdateDeployment], ParameterBindingException
+ FullyQualifiedErrorId : NamedParameterNotFound,Microsoft.ConfigurationManagement.Cmdlets.Deployments.Commands.SetSoftwareUpdateDeploymentCommand
So I tried this:
$date = (Get-Date).AddDays(20)
Set-CMSoftwareUpdateDeployment `
-DeploymentName "Deployment Name" `
-DeploymentType Required `
-DeploymentExpireDateTime $date
But I get this:
cmdlet Set-CMSoftwareUpdateDeployment at command pipeline position 1
Supply values for the following parameters:
InputObject:
PS SCM:\>
Can anyone direct me as to what I'm doing wrong? Thanks in advance!
You probably need more information than just the DeploymentName to make this recognizable. Try Specifying The parameter -SoftwareUpdateGroupName as well was as -DeploymentName so
$date = (Get-Date).AddDays(20)
Set-CMSoftwareUpdateDeployment `
-DeploymentName "Deployment Name" `
-SoftwareUpdateGroupName "Software Update Group Name" `
-DeploymentType Required `
-DeploymentExpireDateTime $date
If you don't know the software update group name I would go a totally different route.
First get the deployments with
Get-CMSoftwareUpdateDeployment
I think in your case you will just want all of them anyway but if not you probably have to filter with "where" because the -Name parameter seems to be broken.
Then use the objects you get as InputObject for Set-CMSoftwareUpdateDeployment ingoring the name and modifying the time:
Get-CMSoftwareUpdateDeployment | where {$_.AssignmentName -eq "Deployment Name"}
| Set-CMSoftwareUpdateDeployment -DeploymentExpireDateTime (Get-Date).AddDays(20)

Compare dates with different formats in csv file

Whats a good way to compare dates in a csv file that looks like this:
Date1,Date2,Date3
11/10/2016 9:45:00 PM,20161110,11/10/2016
11/15/2016 11:24:00 PM,20160924,11/10/2016
If a match is found, append a column like so...
Date1,Date2,Date3,MatchDates
11/10/2016 9:45:00 PM,20161110,11/10/2016,Match Found
11/15/2016 11:24:00 PM,20160924,11/10/2016,No Match Found
updated
Trying the code that is in the comments:
When comparing this with 2 of the columns...
$csvFile = 'C:\Scripts\Tests\test1.csv'
Import-Csv $csvFile | Select-Object *, #{n='MatchDates';e={
if(([datetime]$_.Date1).Date -eq $_.Date3){
'Match Found'
}Else{
'No Match Found'
}}} |
Export-Csv "$csvFile-results.csv" -NoTypeInformation -Force
output (isCorrect)...
Date1,Date2,Date3,MatchDates
11/10/2016 9:45:00 PM,20161110,11/10/2016,Match Found
11/15/2016 11:24:00 PM,20160924,11/10/2016,No Match Found
However, if I try to compare all 3 columns using the following code
Import-Csv $csvFile | Select-Object *, #{n='MatchDates';e={
if((([datetime]$_.Date1).Date -eq $_.Date3) -and (([datetime]$_.Date2).Date -eq $_.Date3) -and (([datetime]$_.Date1).Date -eq $_.Date2)){
'Match Found'
}Else{
'No Match Found'
}}} |
Export-Csv "$csvFile-results.csv" -NoTypeInformation -Force
output (isNotCorrect)...
Date1,Date2,Date3,MatchDates
11/10/2016 9:45:00 PM,20161110,11/10/2016,
11/15/2016 11:24:00 PM,20160924,11/10/2016,No Match Found
As you can see the value of row 1 and the last column is $null instead of showing Match Found
Maybe I'm not understanding something correctly?
You were on the right track with what we discussed in comments. Problem was with that middle date. It does not convert to a [datetime] without some help. That is where ParseExact comes in handy. Consider the following:
PS D:\temp> [datetime]"20160924"
Cannot convert value "20160924" to type "System.DateTime". Error: "String was not recognized as a valid DateTime."
At line:1 char:1
+ [datetime]"20160924"
+ ~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvalidCastParseTargetInvocationWithFormatProvider
PS D:\temp> [datetime]::parseexact("20160924","yyyyMMdd",[System.Globalization.CultureInfo]::CurrentCulture)
Saturday, September 24, 2016 12:00:00 AM
Note the second example returned a proper date object.
Do you remember the transitive property from math? We use that for simple comparison to see if all dates are the same. Not the only way by far but a simple one nonetheless. Building off your calculated property code
$csv | Select-Object *,#{Name='MatchDates';Expression={
$date1 = ([datetime]$_.Date1).Date
$date2 = ([datetime]::parseexact($_.Date2,"yyyyMMdd",[System.Globalization.CultureInfo]::CurrentCulture)).Date
$date3 = ([datetime]$_.Date1).Date
if($date1 -eq $date2 -and $date2 -eq $date3){
'Match Found'
} else {
'No Match Found'
}
}
}
Cleared up the if logic by saving the casted values in temproary variables.

Powershell: How to pass variable correctly to command

I apologize if I butchered the terminology for this, and understand I'm very new to PowerShell. I have read over some of the guides and this concept is clearly not getting through to me.
Concept:
I want to remove a mobile device from a user in Exchange 2010
Identify user from input
Create variable from input of the PhoneID
Remove the Phone using phoneID variable
I believe my problem is in how I'm passing this data to the next command. I know the appended "#[Identity " that get's added should be removed and I remember reading something about how when you pass data like this Powershell has no context? Here is my very simple script.
Script
Add-PSSnapin Microsoft.Exchange.Management.PowerShell.E2010
. $env:ExchangeInstallPath\bin\RemoteExchange.ps1
Connect-ExchangeServer -auto
$PU = Read-Host "Enter Username"
$did = get-activesyncdevice -mailbox $PU | Select-Object identity
Remove-ActiveSyncDevice -Identity $did
Error
My error is as follows, and I've tried to research what I'm doing wrong but I'm just not getting it :-( , I replaced the actual output for the account with XX.
Remove-ActiveSyncDevice : Cannot bind parameter 'Identity'. Cannot convert value "#{Identity=XX" to type
"Microsoft.Exchange.Configuration.Tasks.ActiveSyncDeviceIdParameter". Error: "Cannot convert the "#{Identity=XX}" value of type
"Selected.Microsoft.Exchange.Data.Directory.SystemConfiguration.ActiveSyncDevice" to type "Microsoft.Exchange.Configuration.Tasks.ActiveSyncDeviceIdParameter"."
At line:1 char:35
+ Remove-ActiveSyncDevice -Identity $did
+ ~~~~
+ CategoryInfo : InvalidArgument: (:) [Remove-ActiveSyncDevice], ParameterBindingException
+ FullyQualifiedErrorId : CannotConvertArgumentNoMessage,Microsoft.Exchange.Management.Tasks.RemoveMobileDevice
Any help or advice on this would be amazing!
When you use Select-Object and give it just one property name, you get and object with just one property. But even though it only has one property, you still have to reference that one property by name:
Add-PSSnapin Microsoft.Exchange.Management.PowerShell.E2010
. $env:ExchangeInstallPath\bin\RemoteExchange.ps1
Connect-ExchangeServer -auto
$PU = Read-Host "Enter Username"
$did = get-activesyncdevice -mailbox $PU | Select-Object identity
Remove-ActiveSyncDevice -Identity $did.identity