Passing date time as variable instead of where-object filter - powershell

I am trying to use below code with date range as Where-Object filter but that is slowing down my output speed as well as unable to export to csv.
$Prids = get-content -Path C:\Temp\sqltest.txt
foreach ($prid in $prids){
$filterDate = [datetime]::Today.AddDays(-22)
Get-CdPac2000Problems -PId $Prid | Where-Object {$_.ClosedDate.Date -ge $filterDate} |ft PID,ClosedDate,ClosedByELID,ResponsibleGroup,ReferredDate -autosize
}
How can I change Where-Object to parameter that looks something like -closedate $variable like I did with -PID? The biggest struggle for me is to creating a datetime variable.

First of, you should move the $filterDateout of the loop, second you should NEVER use Format-Table, and ABSOLUTELY NEVER in a loop.
Try this:
$filterDate = [datetime]::Today.AddDays(-22)
$Prids = get-content -Path C:\Temp\sqltest.txt
$Result = foreach ($prid in $prids){
Get-CdPac2000Problems -PId $Prid | Where-Object {(Get-Date $_.ClosedDate.Date) -ge $filterDate}
}
$Result | Format-Table PID,ClosedDate,ClosedByELID,ResponsibleGroup,ReferredDate -autosize
One of the most beautyfull things in PowerShell is, that you can interfere directly with all objects. All methods and properties are preserved, when passing the objects to a variable or to the next command in a pipe. Format-Table converts objects to a table - something human readable and something stripped from methods and life.

Related

Powershell sort two fields and and get latest from CSV

I am trying to find a way to sort a CSV by two fields and retrieve only the latest item.
CSV fields: time, computer, type, domain.
Item that works is below but is slow due to scale of CSV and I feel like there is a better way.
$sorted = $csv | Group-Object {$_.computer} | ForEach {$_.Group | Sort-Object Time -Descending | Select-Object -First 1}
As Lee_Dailey suggests, you'll probably have better luck with a hashtable instead, Group-Object (unless used with the -NoElement parameter) is fairly slow and memory-hungry.
The fastest way off the top of my head would be something like this:
# use the call operator & instead of ForEach-Object to avoid overhead from pipeline parameter binding
$csv |&{
begin{
# create a hashtable to hold the newest object per computer
$newest = #{}
}
process{
# test if the object in the pipeline is newer that the one we have
if(-not $newest.ContainsKey($_.Computer) -or $newest[$_.Computer].Time -lt $_.Time){
# update our hashtable with the newest object
$newest[$_.Computer] = $_
}
}
end{
# return the newest-per-computer object
$newest.Values
}
}

Powershell Get-ChildItem, filtered on date with Owner and export to txt or csv

I am trying to export a list of documents modified files after a set date, including its owners from a recursive scan using Get-ChildItem.
For some reason I cannot get it to port out to a file/csv:
$Location2 = "\\fs01\DATAIT"
$loc2 ="melb"
cd $Location2
Get-ChildItem -Recurse | Where-Object { $_.lastwritetime -gt [datetime]"2017/05/01" } | foreach { Write-Host $_.Name "," $_.lastwritetime "," ((get-ACL).owner) } > c:\output\filelisting-$loc2.txt
Could any of the PowerShell gurus on here shed some light please?
The problem with your code is that you are using Write-Host which explicitly sends output to the console (which you then can't redirect elsewhere). The quick fix is as follows:
Get-ChildItem -Recurse | Where-Object { $_.lastwritetime -gt [datetime]"2017/05/01" } | foreach { "$($_.Name),$($_.lastwritetime),$((get-ACL).owner)" } > filelisting-$loc2.txt
This outputs a string to the standard output (the equivalent of using Write-Output). I've made it a single string which includes the variables that you wanted to access by using the subexpression operator $() within a double quoted string. This operator is necessary to access the properties of objects or execute other cmdlets/complex code (basically anything more than a simple $variable) within such a string.
You could improve the code further by creating an object result, which would then allow you to leverage other cmdlets in the pipeline like Export-CSV. I suggest this:
Get-ChildItem -Recurse | Where-Object { $_.lastwritetime -gt [datetime]"2017/05/01" } | ForEach-Object {
$Properties = [Ordered]#{
Name = $_.Name
LastWriteTime = $_.LastWriteTime
Owner = (Get-ACL).Owner
}
New-Object -TypeName PSObject -Property $Properties
} | Export-CSV $Loc2.csv
This creates a hashtable #{} of the properties you wanted and then uses that hashtable to create a PowerShell Object with New-Object. This Object is then returned to standard output, which goes into the pipeline so when the ForEach-Object loop concludes all the objects are sent in to Export-CSV which then outputs them correctly as a CSV (as it takes object input).
As an aside, here is an interesting read from the creator of PowerShell on why Write-Host is considered harmful.
[Ordered] requires PowerShell 3 or above. If you're using PowerShell 2, remove it. It just keeps the order of the properties within the object in the order they were defined.

Using Powershell to compare two files and then output only the different string names

So I am a complete beginner at Powershell but need to write a script that will take a file, compare it against another file, and tell me what strings are different in the first compared to the second. I have had a go at this but I am struggling with the outputs as my script will currently only tell me on which line things are different, but it also seems to count lines that are empty too.
To give some context for what I am trying to achieve, I would like to have a static file of known good Windows processes ($Authorized) and I want my script to pull a list of current running processes, filter by the process name column so to just pull the process name strings, then match anything over 1 character, sort the file by unique values and then compare it against $Authorized, plus finally either outputting the different process strings found in $Processes (to the ISE Output Pane) or just to output the different process names to a file.
I have spent today attempting the following in Powershell ISE and also Googling around to try and find solutions. I heard 'fc' is a better choice instead of Compare-Object but I could not get that to work. I have thus far managed to get it to work but the final part where it compares the two files it seems to compare line by line, for which would always give me false positives as the line position of the process names in the file supplied would change, furthermore I only want to see the changed process names, and not the line numbers which it is reporting ("The process at line 34 is an outlier" is what currently gets outputted).
I hope this makes sense, and any help on this would be very much appreciated.
Get-Process | Format-Table -Wrap -Autosize -Property ProcessName | Outfile c:\users\me\Desktop\Processes.txt
$Processes = 'c:\Users\me\Desktop\Processes.txt'
$Output_file = 'c:\Users\me\Desktop\Extracted.txt'
$Sorted = 'c:\Users\me\Desktop\Sorted.txt'
$Authorized = 'c:\Users\me\Desktop\Authorized.txt'
$regex = '.{1,}'
select-string -Path $Processes -Pattern $regex |% { $_.Matches } |% { $_.Value } > $Output_file
Get-Content $Output_file | Sort-Object -Unique > $Sorted
$dif = Compare-Object -ReferenceObject $(Get-Content $Sorted) -DifferenceObject $(get-content $Authorized) -IncludeEqual
$lineNumber = 1
foreach ($difference in $dif)
{
if ($difference.SideIndicator -ne "==")
{
Write-Output "The Process at Line $linenumber is an Outlier"
}
$lineNumber ++
}
Remove-Item c:\Users\me\Desktop\Processes.txt
Remove-Item c:\Users\me\Desktop\Extracted.txt
Write-Output "The Results are Stored in $Sorted"
From the length and complexity of your script, I feel like I'm missing something, but your description seems clear
Running process names:
$ProcessNames = #(Get-Process | Select-Object -ExpandProperty Name)
.. which aren't blank: $ProcessNames = $ProcessNames | Where-Object {$_ -ne ''}
List of authorised names from a file:
$AuthorizedNames = Get-Content 'c:\Users\me\Desktop\Authorized.txt'
Compare:
$UnAuthorizedNames = $ProcessNames | Where-Object { $_ -notin $AuthorizedNames }
optional output to file:
$UnAuthorizedNames | Set-Content out.txt
or in the shell:
#(gps).Name -ne '' |? { $_ -notin (gc authorized.txt) } | sc out.txt
1 2 3 4 5 6 7 8
1. #() forces something to be an array, even if it only returns one thing
2. gps is a default alias of Get-Process
3. using .Property on an array takes that property value from every item in the array
4. using an operator on an array filters the array by whether the items pass the test
5. ? is an alias of Where-Object
6. -notin tests if one item is not in a collection
7. gc is an alias of Get-Content
8. sc is an alias of Set-Content
You should use Set-Content instead of Out-File and > because it handles character encoding nicely, and they don't. And because Get-Content/Set-Content sounds like a memorable matched pair, and Get-Content/Out-File doesn't.

Issue with Powershell custom table

I'm trying to create a custom table based on two other tables (csv-imported) - some kind of a VLOOKUP, but I can't seem to find a solution. I've come up with the following (failing) code:
$DrawPlaces | select Module, Workplace, #{ Name = "IPaddress"; Expression = {$Workstations.workstation.where($_.WorkPlace -eq $Workstations.Workplace)}} -First 15
Both Drawplaces and $Workplaces are PSCustomObject. The result of this would then go to another variable.
I'm not even sure the logic or syntax is correct, but the result table has the IPaddress column empty. I've also tried with -match instead of -eq.
This doesn't make sense: $Workstations.workstation.where($_.WorkPlace -eq $Workstations.Workplace)
.where() requires a scriptblock parameter like .where({}).
Keeping in mind that inside the where-statement $_ is refering to the current object in the $workstations.workstation-loop, your where-statement is testing ex. $workstations.workstation[0].workplace -eq $workstations.workplace. Is that really what you want?
Are you trying to achieve this?
$DrawPlaces |
Select-Object -First 15 -Property #(
"Module",
"Workplace",
#{ Name = "IPaddress"; Expression = {
#Save the Workspace-value for the current object from $DrawPlaces
$wp = $_.WorkPlace;
#Find the workstation with the same workplace as $wp
$Workstations | Where-Object { $_.WorkPlace -eq $wp} | ForEach-Object { $_.Workstation }
}
}
)

Issues with Powershell Import-CSV

Main Script
$Computers = Get-Content .\computers.txt
If ( test-path .\log.txt ) {
$Log_Successful = Import-CSV .\log.txt | Where-Object {$_.Result -eq "Succesful"}
} ELSE {
Add-Content "Computer Name,Is On,Attempts,Result,Time,Date"
}
$Log_Successful | format-table -autosize
Issues:
Log_Successful."Computer Name" works fine, but if i change 4 to read as the following
$Log_Successful = Import-CSV .\log.txt | Where-Object {$_.Result -eq "Failed"}
Log_Successful."Computer Name" no longer works... Any ideas why?
Dataset
Computer Name,Is On,Attempts,Result,Time,Date
52qkkgw-94210jv,False,1,Failed,9:48 AM,10/28/2012
HELLBOMBS-PC,False,1,Successful,9:48 AM,10/28/2012
52qkkgw-94210dv,False,1,Failed,9:48 AM,10/28/2012
In case of "Successful" a single object is returned. It contains the property "Computer Name". In case of "Failed" an array of two objects is returned. It (the array itself) does not contain the property "Computer Name". In PowerShell v3 in some cases it is possible to use notation $array.SomePropertyOfContainedObject but in PowerShell v2 it is an error always. That is what you probably see.
You should iterate through the array of result objects, e.g. foreach($log in $Log_Successful) {...} and access properties of the $log objects.
And the last tip. In order to ensure that the result of Import-Csv call is always an array (not null or a single object) use the #() operator.
The code after fixes would be:
$logs = #(Import-Csv ... | where ...)
# $logs is an array, e.g. you can use $logs.Count
# process logs
foreach($log in $logs) {
# use $log."Computer Name"
}
I'm not sure if this is the problem but you have a typo, in Where-Object you compare against "Succesful" and the value in the file is "Successful" (missing 's').
Anyway, what's not working?