I'm a powershell noob. How come the following code is also outputing the table at the end after the "File to Delete" loop?
$stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
# use partial hashes for files larger than 100KB:
# see documentation at: https://powershell.one/tricks/filesystem/finding-duplicate-files#finding-duplicate-files-fast
$result = Find-PSOneDuplicateFileFast -Path '\\READYNAS\Pictures\2020\10' #-Debug -Verbose
$stopwatch.Stop()
# output duplicates
$allFilesToDelete = #(foreach($key in $result.Keys)
{
#filters out the LAST item in the array of duplicates, because a file name of xxxx (0) comes before one without the (0)
$filesToDelete = $result[$key][0..($result[$key].count - 2)]
#add each remaining duplicate file to table
foreach($file in $filesToDelete)
{
$file |
Add-Member -MemberType NoteProperty -Name Hash -Value $key -PassThru |
Select-Object Hash, Length, FullName
}
}
)
$allFilesToDelete | Format-Table -GroupBy Hash -Property FullName | Out-String | Write-Host
$allFilesToDelete | Sort-Object -Property FullName -OutVariable allFilesToDelete
$allFilesToDelete | Format-Table -Property FullName | Out-String | Write-Host
$confirmation = Read-Host "Are you Sure You Want To Delete $($allFilesToDelete.count) files? (y/n)"
if ($confirmation -eq 'y') {
$i = 0
foreach($fileToDelete in $allFilesToDelete)
{
$i++
Write-Host "$i File to Delete: $($fileToDelete.FullName)"
#Remove-Item $file.FullName -Force -Verbose 4>&1 | % { $x = $_; Write-Host "Deleted file ($i) $x" }
}
} else {
Write-Host "User chose NOT to delete files!"
}
$allFilesToDelete | Sort-Object -Property FullName -OutVariable allFilesToDelete produces output (the input objects in the requested sort order), and since you're not capturing or redirecting it, it prints to the host (display, terminal) by default.
It seems your intent is to sort the objects stored in $allFilesToDelete, which your command does, but it also produces output (the common -OutVariable parameter does not affect a cmdlet's output behavior, it simply also stores the output objects in the given variable); you could simply assign the output back to the original variable, which wouldn't produce any output:
$allFilesToDelete = $allFilesToDelete | Sort-Object -Property FullName
In cases where actively suppressing (discarding) output is needed, $null = ... is the simplest solution:
See this answer for details and alternatives.
Also see this blog post, which you found yourself.
Because the output resulted in implicitly Format-Table-formatted display representations (for custom objects that have no predefined formatting data), the subsequent Read-Host and Write-Host statements - surprisingly - printed first.
The reason is that this implicit use of Format-Table results in asynchronous behavior: output objects are collected for 300 msecs. in an effort to determine suitable column widths, and during that period output to other output streams may print.
The - suboptimal - workaround is to force pipeline output to print synchronously to the host (display), using Out-Host.
See this answer for details.
I'm exporting my AAD users to CSV files, works fine with this code.
$allUsers = Get-AzureADUser -All $true
$users = $allUsers |
Select-Object -Property ObjectId,ObjectType,UserPrincipalName,DisplayName,AccountEnabled,AgeGroup,City,CompanyName,ConsentProvidedForMinor,Country,CreationType,Department,DirSyncEnabled,FacsimileTelephoneNumber,GivenName,IsCompromised,ImmutableId,JobTitle,LastDirSyncTime,LegalAgeGroupClassification,Mail,MailNickName,Mobile,OnPremisesSecurityIdentifier,PasswordPolicies,PhysicalDeliveryOfficeName,PostalCode,PreferredLanguage,RefreshTokensValidFromDateTime,ShowInAddressList,State,StreetAddress,Surname,TelephoneNumber,UsageLocation,UserState,UserStateChangedOn,UserType,DeletionTimestamp,AssignedLicenses,AssignedPlans,ProvisionedPlans |
ForEach-Object{
$_.DisplayName = $_.DisplayName -replace "\n", ' ' -replace '"', '`'
$_
}
$users | Export-Csv -Path $TempFileName -NoTypeInformation
$provisionedPlans = $users = $allUsers |
Select-Object -Property ObjectId,DisplayName,ProvisionedPlans
But, ProvisionedPlans comes out as a list, so I would like to export it for each entry in the list as 1 line.
This is a sample of the field
ProvisionedPlans : {class ProvisionedPlan {
CapabilityStatus: Enabled
ProvisioningStatus: Success
Service: MicrosoftCommunicationsOnline
}
, class ProvisionedPlan {
CapabilityStatus: Deleted
ProvisioningStatus: Success
Service: MicrosoftCommunicationsOnline
}
, class ProvisionedPlan {
CapabilityStatus: Deleted
ProvisioningStatus: Success
Service: MicrosoftCommunicationsOnline
}
, class ProvisionedPlan {
CapabilityStatus: Enabled
ProvisioningStatus: Success
Service: SharePoint
}
...}
So bottom line what I would like to see in the output would be
ObjectId,DisplayName,CapabilityStatus,ProvisioningStatus,Service
id1,User1,Enabled,Success,MicrosoftCommunicationsOnline
id1,User1,Deleted,Success,MicrosoftCommunicationsOnline
id1,User1,Deleted,Success,MicrosoftCommunicationsOnline
id1,User1,Enabled,Success,SharePoint
id2,User2,Enabled,Success,Whatever
So please feel free, i'm not a Powershell specialist.
Following your guidance of what you want as a bottom line please see the below adjustments to your script:
$allUsers = Get-AzureADUser -All $true
$Results = Foreach ($user in $allusers){
Foreach($Plan in $user.ProvisionedPlans){
$Plan | Select #{Name = 'ObjectId'; Expression = {$user.Objectid}},#{Name = 'DisplayName';Expression = {$user.DisplayName}},CapabilityStatus,ProvisioningStatus,Service
}
}
$Results | Export-Csv -Path $TempFileName -NoTypeInformation
I am not sure why you are replacing characters in the DisplayName but I have added this to the calculated properties in the Select Statemant.
I have also done this on the iteration of each provisioned plan as this seemed to be the easiest route.
I have removed the initial select with all of the properties as the properties you are interested in are being exported. (If you require all properties I would advise using Select * as it will pull the majority of properties in most cases and will look tidier in the code.)
I'm trying to extract all usernames that has failed login atempts from Event Viewer log and then list only the usernames. However the data for each entry is text so I have a hard time extracting only the names (Intruder123 in this case). It would be a couple of hundred account names stored in an array.
$String = Get-WinEvent #{LogName='Security';ProviderName='Microsoft-Windows-Security-Auditing';ID=4625 } -ComputerName SECRETSERVER |
Select-Object -ExpandProperty Message
$string -match "Account Name: (?<content>.*)"
$matches['content']
The data looks like this (multiple times):
Account For Which Logon Failed:
Security ID: S-1-0-0
Account Name: Intruder123
Account Domain: SECRET.LOCAL
I think you could collect some more information like the time the failed logon happened and on which computer. For that, create a resulting array of objects.
Also, trying to parse the Message property can be cumbersome and I think it is much better to get the info from the Event as XML:
$filter = #{LogName='Security';ProviderName='Microsoft-Windows-Security-Auditing';ID=4625 }
$result = Get-WinEvent -FilterHashtable $filter -ComputerName SECRETSERVER | ForEach-Object {
# convert the event to XML and grab the Event node
$eventXml = ([xml]$_.ToXml()).Event
$userName = ($eventXml.EventData.Data | Where-Object { $_.Name -eq 'TargetUserName' }).'#text'
$computer = ($eventXml.EventData.Data | Where-Object { $_.Name -eq 'WorkstationName' }).'#text'
# output the properties you need
[PSCustomObject]#{
Time = [DateTime]$eventXml.System.TimeCreated.SystemTime
UserName = $userName
Computer = $computer
}
}
# output on screen
$result
# output to CSV file
$result | Export-Csv -Path 'X:\FailedLogons.csv' -NoTypeInformation
Hello i want to get only the month and year of a file with Date context
for example:
Where-Object {$_.StartDate-eq (Get-Date).AddDays(0).ToString("mm.yyyy") } |
current status:
Get-Content "file" -Encoding:String |
Select -Skip 1 |
ConvertFrom-Csv |
Where-Object {$_.StartDate -eq (Get-Date).ToString("MM.yyyy") } |
Where-Object {-not $_.DestinationNumber.StartsWith("+49") -and $_.DestinationNumber.StartsWith("+")} |
ForEach { [DateTime]$_.EndTime - [DateTime]$_.StartTime } |
ForEach { $Total=0 } { $Total += $_.TotalMinutes}
[math]::Round($Total,2),'Minuten'
i hope any body can help me.
Lower Case 'm' denotes minutes, you will have to use upper case M for month. Something like..
{$_.StartDate-eq (Get-Date).AddDays(0).ToString("MM.yyyy")
You don't need to invoke AddDays method, if u just have to get the current date. You can simple try,
(Get-Date).ToString("MM.yyyy")
--EDIT as per OP Clarification--
From the context it appears that you want to convert $_.StartDate to MM.yyyy format. If that's the case (assuming you have a valid date time value in $_.StartDate) you can use the Get-Date method on it. Something like,
Where-Object {(Get-Date($_.StartDate)).ToString("MM.yyyy") -eq (Get-Date).ToString("MM.yyyy") }
I have the below powershell script and I want the format to show the whole string, as though I was using Format-Table with -Wrap and -Autosize. I've tried using those, but it doesn't show all the needed properties, not sure if I wasn't using it correctly or what was the case.
$threshold = 30 #Number of days to look for expiring certificates
$deadline = (Get-Date).AddDays($threshold) #Set deadline date
Invoke-Command -ComputerName { Dir Cert:\LocalMachine\My } | foreach {
If ($_.NotAfter -le $deadline) {
$_ | Select Issuer, Subject, NotAfter, #{Label="Expires In (Days)";
Expression={($_.NotAfter - (Get-Date)).Days}}
}
}
This is what my output currently looks like:
Issuer Subject NotAfter Expires In (Days)
CN=MASKEDMASKEDMASKED ... CN=masked.customer.masked.com, OU=... 2/21/2014 5:59:59 PM -17
CN=MASKEDMASKEDMASKED ... CN=masked.customer.masked.com, OU=... 2/21/2014 5:59:59 PM -17
Can anyone provide some assistance, please? I basically just need to expand those columns to see all the details.
If you don't plan to use the data after these commands, you can pipe them to Format-* as you mentioned. Select will get you the data, but not the friendly display. Is there a reason you need it displayed?
Here's a quick example where you get the best of both worlds:
#Assign output to a variable
$result = Invoke-Command -ComputerName { Dir Cert:\LocalMachine\My } | foreach {
If ($_.NotAfter -le $deadline) { $_ | Select Issuer, Subject, NotAfter, #{Label="Expires In (Days)";Expression={($_.NotAfter - (Get-Date)).Days}} }
}
#Write the results to the verbose stream. Use format table and out-string for appearances
#Change to write-host, debug, error, warning, etc. as needed
Write-Verbose "Results:`n$($result | Format-Table -AutoSize -Wrap | Out-String)"
#$result is still a usable object at this point
$result
*edit: I don't have the reputation to comment on Cole9350's suggestion - don't use ExpandProperty. That is for expanding a single property...
Use the -ExpandProperty Parameter of your Select-Object cmdlet