If condition not working with DateTime entries - powershell

I am not able to get the correct report with the below part of code.
Here's what I am doing:
Importing .csv file into variable which contains UserName, LastSucessSync (date), Model.
With below foreach loop this will format the .html report and provide the values Green or Red.
Issue is, when Date is blank in .csv file it still shows GREEN or some times RED.
It also throws the below error:
Cannot convert value "" to type "System.DateTime". Error: "String was not
recognized as a valid DateTime."
At C:\MobileStats.ps1:87 char:4
+ if([datetime]$Entry.LastSuccessSync -lt (Get-Date).AddDays(-14) -or $Entry.LastS ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvalidCastParseTargetInvocationWithFormatProvider
Rest of all is fine. Just I want to mark it as RED when date is blank or 14 days before.
PowerShell Code:
foreach ($Entry in $Result) {
if ([datetime]$Entry.LastSuccessSync -lt (Get-Date).AddDays(-14) -or $Entry.LastSuccessSync -like "") {
$Cdrivecolor="RED"
} else {
$Cdrivecolor="Green"
}

Related

How to get this PowerShell command output into an iterable collection or array

This answer shows how to output a list of computer-names on the domain:
(([adsi]"WinNT://$((Get-WMIObject Win32_ComputerSystem).Domain)").Children).Where({$_.schemaclassname -eq 'computer'})
If the Pathproperty is appended
... .Where({$_.schemaclassname -eq 'computer'}).Path
it outputs a list in this format:
WinNT://{domainname}.net/{machine-name}
How would that succession of fully qualified machine names be made into an array or a collection that could be iterated by the script found here?
Can that command (i.e. its output) simply be assigned to an array variable?
[array]$ComputerNames = ... (([adsi]"WinNT://$((Get-WMIObject <snip> ).Path
I suspect not, since when I try that
$ComputerNames = ... (([adsi]"WinNT://$((Get-WMIObject <snip> ).Path
foreach($computer in $ComputerNames) {
if($regKey = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine', $computer)) {
I get an error:
Exception calling "OpenRemoteBaseKey" with "2" argument(s): "The network path was not found."
At C:\Users\{myusername}\Get-NetFrameworkVersion.ps1:40 char:8
+ if($regKey = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('Lo ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : IOException
My ultimate goal is to obtain the .NET versions installed on all PCs on the domain.

PowerShell - Add-Content- Unable to add multiple vars to a file

I'm trying to add an expression to a log file which contains Date,Time some data separated by ";". Unfortunately I get an error every time I change the position of the items in the -value brackets.
Whats seems to be wrong?
This is the code :
Add-Content -path C:\...\outlog.txt -Value($Date + ';' + $Time + ';Checked;' + $strFileName)
This is the error :
Cannot convert argument "1", with value: ";", for "op_Addition" to type "System.TimeSpan": "Cannot convert
value ";" to type "System.TimeSpan". Error: "String was not recognized as a valid TimeSpan.""
At C:\...\Untitled1.ps1:8 char:64
+ ... \outlog.txt -Value($($Date + ';' + $Time + ';'+ $str))
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodException
+ FullyQualifiedErrorId : MethodArgumentConversionInvalidCastArgument
Try this -
Add-Content -path C:\...\outlog.txt -Value("$Date; $Time; Checked; $strFileName")
If you look at get-help Add-Content -full, and look at the -value parameter, you will see -
-Value <Object[]>
Specifies the content to be added. Type a quoted string, such as "This data is for internal use only", or
specify an object that contains content, such as the DateTime object that Get-Date generates.
You cannot specify the contents of a file by typing its path, because the path is just a string, but you can
use a Get-Content command to get the content and pass it to the Value parameter.
Required? true
Position? 1
Default value None
Accept pipeline input? True (ByPropertyName, ByValue)
Accept wildcard characters? false
It says that it expects a quoted string or an object that contains content. It was missing in your case and hence the + operator was trying to add $date and time.

Trouble with [datetime]::parseexact

I know I must be missing something simple, but I've stared at it for a while and can't seem to see it.
I have the following powershell code
.".\Get-FileMetaDataReturnObject.ps1"
$BaseDirectory = "C:\Users\me\Desktop\Photo Test"
$Folders = get-childitem -path $BaseDirectory -Directory
foreach ($folder in $folders)
{
Write-Host "Folder name:$($folder.Name)"
$picture = Get-ChildItem -Path "$BaseDirectory\$($folder.Name)\"
$picMetaData = Get-FileMetaData -folder "$BaseDirectory\$($folder.Name)\"
$picDate = $picMetaData | Select 'Date Taken'
$picDateTaken = $picDate[0].'Date taken'
Write-Host $picDateTaken
$dateTime = [datetime]::parseexact($picDateTaken, "M/d/yyyy h:mm tt", [System.Globalization.CultureInfo]::InvariantCulture)
$dateStr = $dateTime.ToString('yyyy-MM-dd')
Write-Host $dateStr
}
When I run it I get the following error
Folder name:Deruta - Umbria, September 4, 2012
‎9/‎4/‎2012 ‏‎4:12 PM
Exception calling "ParseExact" with "3" argument(s): "String was not recognized as a valid DateTime."
At C:\Users\me\Desktop\Picture Folder Rename\PhotoFolderRename.ps1:18 char:5
+ $dateTime = [datetime]::parseexact($picDateTaken, "M/d/yyyy h:mm ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : FormatException
The meta data script is found here
I'm really not sure what I've screwed up with the date time parsing, so any help would be appreciated.
Comparing "9/‎4/‎2012 ‏‎4:12 PM".Length (20) with "9/4/2012 4:12 PM".Length (16) shows us something fishy is going on, and indeed this string is not what it appears to be; there are U+200E LEFT-TO-RIGHT MARK and U+200F RIGHT-TO-LEFT MARK control characters in there, which are invisible (or not, depending on your console settings). Replacing these out will make the string parseable:
$picDateTaken = $picDateTaken -replace "\u200e|\u200f", ""
Replacing control characters in general would be more involved, and I'm not sure if there isn't a better/more general way to get the metadata in an invariant format, but as long as you know exactly what you're dealing with this is good enough.

Powershell Catch print modified error only

I have the csv file with the following values:
User,TimeStamp
Pinky,11/4/2015 5:00
Brain,
Leo,never
Don,unspecified
I want to ensure this file for the TimeStamp column either has a date, or a $null value. To do this I am using the following code:
Function HealthCheckTimeStampColumn
{
Param ($userInputCsvFileWithPath)
Write-Host "Checking if TimeStamp column has invalid values..."
Import-Csv $userInputCsvFileWithPath | %{
if ($_.TimeStamp)
{
Try
{
([datetime]$_.TimeStamp).Ticks | Out-Null
}
Catch [system.exception]
{
$Error.Clear()
$invalidValue = $_.TimeStamp
Write-Error "Invalid Value found `"$_.TimeStamp`"; Value expected Date or `"`""
Exit
}
}
}
Write-Host "All values were found valid."
Write-Host "TimeStamp Healthcheck Column Passed"
Write-Host ""
}
With this code, I get this error:
Invalid Value found "Cannot convert value "never" to type "System.DateTime". Error: "The string was not recognized as
a valid DateTime. There is an unknown word starting at index 0.".TimeStamp"; Value expected Date or ""
At C:\Scripts\Tests\TestTime.ps1:247 char:42
+ Import-Csv $userInputCsvFileWithPath | %{
+ ~
+ CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
+ FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException
If I try this line of code Instead:
Write-Error "Invalid Value found `"$invalidValue`"; Value expected Date or `"`""
I get this error:
Invalid Value found ""; Value expected Date or ""
At C:\Scripts\Tests\TestTime.ps1:247 char:42
+ Import-Csv $userInputCsvFileWithPath | %{
+ ~
+ CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
+ FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException
The error I am expecting to see is this:
Invalid Value found "never"; Value expected Date or ""
At C:\Scripts\Tests\TestTime.ps1:247 char:42
+ Import-Csv $userInputCsvFileWithPath | %{
+ ~
+ CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
+ FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException
Can anyone tell me what I am doing wrong?
You don't really need a try/catch block for this one either. They are good for unexpected and unavoidable errors. However looking about_Type_Operators you will see -as and -is which handle this situation rather gracefully.
-is : Returns TRUE when the input is an instance of the specified .NET Framework type.
-as : Converts the input to the specified .NET Framework type.
When -as encounters a string or something that is not castable to [datetime] it will return a null. More importantly it will not error. I propose that you check all values for non nulls and invalid date times. Capture all of those in a variable. Then check if the variables has any values. Print all at once! and then exit if you want. I also second what user2460798's answer said about the use of exit.
Function HealthCheckTimeStampColumn{
Param ($userInputCsvFileWithPath)
$badRows = Import-Csv $userInputCsvFileWithPath |
Where-Object{-not [string]::IsNullOrEmpty($_.TimeStamp) -and ($_.TimeStamp -as [datetime]) -eq $null}
if($badRows){
$badRows | ForEach-Object{
Write-Host "'$($_.Timestamp)' is not a valid datetime" -ForegroundColor Red
}
Write-Error "$($badRows.Count) Invalid Value(s) found"
} else {
"All values were found valid.","TimeStamp Healthcheck Column Passed","" | Write-Host
}
}
Turning PerSerAl's observation into an answer:
$_ changes meaning from when it is in the foreach-object loop (but outside catch block) to when it is in catchblock. In the first case it is the current object (row), which apparently has the value "never" for its timestamp. But in the catch block it is the errorrecord that was generated as a result of the error. So to fix:
Function HealthCheckTimeStampColumn
{
Param ($userInputCsvFileWithPath)
Write-Host "Checking if TimeStamp column has invalid values..."
Import-Csv $userInputCsvFileWithPath | %{
$row = $_
if ($_.TimeStamp)
{
Try
{
([datetime]$_.TimeStamp).Ticks | Out-Null
}
Catch [system.exception]
{
$Error.Clear()
$invalidValue = $_.TimeStamp
Write-Error "Invalid Value found `"$row.TimeStamp`"; Value expected Date or `"`""
Exit
}
}
}
Write-Host "All values were found valid."
Write-Host "TimeStamp Healthcheck Column Passed"
Write-Host ""
}
BTW, if you want to process the whole file you'll need to remove exit from the catch block.

Powershell giving an error when trying to use -and in an If statement

I'm getting the error:
You must provide a value expression on the right-hand side of the '-and' operator.
At C:\shippinginterface\test.ps1:28 char:39
+ if (($TicketNumber.length -gt 0) -and <<<< IsNumeric($TicketNumber) -and IsNotVoid($DateOut))
+ CategoryInfo : ParserError: (:) [], ParseException
+ FullyQualifiedErrorId : ExpectedValueExpression
when running this test script.
function IsNumeric($value) {
return ($($value.Trim()) -match "^[-]?[0-9.]+$")
}
function IsNotVoid($value) {
$VoidPattern = [regex]"(?i)void"
return !$VoidPattern.Match($value).Success
}
############################
# START TEST
############################
$TicketNumber = "12345"
$DateOut = "3/14/2013"
## Verify there is a numeric ticket number, and row is not void for any reason
if (($TicketNumber.length -gt 0) -and IsNumeric($TicketNumber) -and IsNotVoid($DateOut))
{
write-host $intRow " " $TicketNumber
}
Why doesn't it like my use of -and? If I remove the first evaluation of string.length the statement works as expected.
I can't say exactly why it doesn't like your syntax, but this will work:
if (($TicketNumber.length -gt 0) -and (IsNumeric $TicketNumber) -and (IsNotVoid $DateOut))
That forces PowerShell to use the output of the expression between parentheses.
I also fixed the function calls. The PowerShell syntax states that functions are called without parentheses, and by separating arguments with spaces.