I'm running this powershell command from a perl script and parsing the output.
powershell "Get-WinEvent -EA SilentlyContinue -FilterHashtable #{Logname='System';ID=7001,10,12,13,41,42,1129,5060,5719,6008,7045}| SELECT-Object ID,TimeCreated,MACHINENAME,MESSAGE|ConvertTo-Csv -NoTypeInformation | %{ $_ -replace """`r`n""",',' } | select -Skip 1"
Is there a way to change the format of the TimeGenerated field in the oputput to 2014-08-5 16:09:54 from 8/5/2014 4:09:54 PM
You can create values from hashtables at the Select portion of the pipe. This should do what you want:
powershell "Get-WinEvent -EA SilentlyContinue -FilterHashtable #{Logname='System';ID=7001,10,12,13,41,42,1129,5060,5719,6008,7045}| SELECT-Object ID,#{label='TimeCreated';expression={$_.TimeCreated.ToString("yyyy-M-d HH:mm:ss")}},MACHINENAME,MESSAGE|ConvertTo-Csv -NoTypeInformation | %{ $_ -replace """`r`n""",',' } | select -Skip 1"
I replaced TimeCreated with #{label=TimeCreated;expression={$_.TimeCreated.ToString("yyyy-M-d HH:mm:ss")}}. Let me break that down for you.
label=TimeCreated is what the property name will be going further down the pipe. I simply reused the same name.
expression={ScriptBlock} tells the system what the value for that property will be for each record.
As for the actual scriptblock, in this case we were already working with a [DateTime] object so I used its ToString() method, and specified a format of your design to output it as. That changes it, so it is now a [String] instead of a [DateTime] object, but seeing as you are just converting the whole thing to a CSV a string should do just fine.
Edit: You can add a switch into the scriptblock of the hashtable described above, it just gets long and can be hard to follow. I would do something like:
powershell "Get-WinEvent -EA SilentlyContinue -FilterHashtable #{Logname='System';ID=7001,10,12,13,41,42,1129,5060,5719,6008,7045}| SELECT-Object ID,#{l='ID Description';e={Switch($_.ID){
"7001" {"Text1"}
"10" {"Text2"}
"12" {"Text3"}
"13" {"Text4"}
"41" {"Text5"}
"42" {"Text6"}
"1129" {"Text7"}
"5060" {"Text8"}
"5719" {"Text9"}
"6008" {"Text10"}
"7045" {"Text11"}
}
}},#{label='TimeCreated';expression={$_.TimeCreated.ToString("yyyy-M-d HH:mm:ss")}},MACHINENAME,MESSAGE|ConvertTo-Csv -NoTypeInformation | %{ $_ -replace """`r`n""",',' } | select -Skip 1"
l= is short for label= and e= is short for expression=
Edit2: More switch info... You could do things based on multiple fields, you would want to do Switch($_) and then on each line put your conditions in a scriptblock, so something like:
Switch($_){
{$_.ID -eq "7001" -and $_.Message -match "catastrophic"}{"The dog ate my NetBIOS"}
{$_.ID -eq "7001" -and $_.Message -match "Lex Luthor"}{"Superman stole my WiFi"}
{<more conditions>}{<and their resultant values>}
}
You can specify an expression in the Select-Object command to create a calculated property. Here, I called this new property "Time" and used the ToString() method with the InvariantCulture to make sure the output is consistent on different computers.
Get-WinEvent -EA SilentlyContinue -FilterHashtable #{Logname='System';ID=7001,10,12,13,41,42,1129,5060,5719,6008,7045} | `
SELECT-Object -Property ID,#{Name="Time"; Expression = {$_.TimeCreated.Tostring("yyyy-MM-d HH:mm:ss", [CultureInfo]::InvariantCulture)}},MACHINENAME,MESSAGE | `
ConvertTo-Csv -NoTypeInformation | %{ $_ -replace """`r`n""",',' } | select -first 5
Related
Good morning,
so i got a bunch of IPs and wanted to get the DNS Name,
so i tried this.
Select-String -Allmatches -pattern '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}' |% { $_.Matches }| % { $_.Value }| select -Unique| %{Resolve-Dnsname -name $_}
This works, but when i output it to a file i only get the results where he could find an Hostname.
Is there a method to also display the errors.
I would probably do it this way:
Select-String -AllMatches -Pattern '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}' |
Select-Object -ExpandProperty Matches |
Select-Object -ExpandProperty Value -Unique |
ForEach-Object {
$Resolve = $null
$Resolve = Resolve-DnsName -Name $_ -ErrorAction SilentlyContinue
[PSCustomObject]#{
IP = $_
Name = $Resolve.Name
Type = $Resolve.Type
TTL = $Resolve.TTL
Section = $Resolve.Section
NameHost = $Resolve.NameHost
}
}
You can specify whatever fields you want in the custom object. I have simply included the default properties that Resolve-DnsName outputs to the screen.
In general, Select-Object -ExpandProperty <property> performs better than ForEach-Object { $_.<property> }.
I'm fairly certain the code I have above will work, but there's an outside chance that this:
Select-Object -ExpandProperty Value -Unique |
May need to be this:
Select-Object -ExpandProperty Value |
Select-Object -Unique |
What I'm trying to do
I have a configurable Powershell 5.1 script with the following variable:
[bool]$SourceFilter
Based on the value of this boolean, I may or may not trigger a Where-Object clause in the middle of a pipeline, which is filtering a large and complex Array of objects:
$objectArray <# | Where-Object {$_.Attributes.Value -NotLlike "*this*"} #> | Sort-Object -Property {$_.Attributes.Name}
How do I encode the Where-Object clause to only trigger if $SourceFilter = $true?
What I've tried
I've tried encoding the clause as a variable and then using Invoke-Expression to rationalise it into the pipeline, but can't seem to get this working:
$script = '| Where-Object {$_.Attributes.pointsource -NotLike "*AF*"}'
$output = if($SourceFilter)
{Invoke-Expression "$objectArray $script" | Sort-Object -Property {$_.Attributes.Name}}
else
{$objectArray | Sort-Object -Property {$_.Attributes.Name}}
This approach gives me an error which states that the $variable is not recognised as the name of a cmdlet, script or program.
You can have a scriptblock variable set to either your condition or true.
$sb1 = {$true}
$sb2 = {$_ -like 'a*'}
echo hi | where $sb1
hi
echo hi | where $sb2
I want to output all hostnames within a network first with a foreach loop, in order (for example) to be able to ping them.
However with the following code I do not get any output in the console. The CSV file will be saved, but what is written in the loop will not be executed.
Does anyone know what the reason for this is and how I can solve it?
Import-Module activedirectory
Get-ADComputer -Filter * -Property * | Select Name | Export-CSV -Path $env:TEMP\ZZZEXPORTE.csv -NoTypeInformation -Encoding UTF8 | ForEach {
$computerName = $_.Name
Write-Host $computerName
Write-Host "----"
}
This occurs because Export-CSV does not output an object. Sometimes cmdlets like this have a -PassThru parameter which you can use to have an object passed along, but thats not the case with Export-CSV, they simply expect it to always be the last cmdlet in the pipeline.
You should instead do this:
$Computers = Get-ADComputer -Filter * -Property * | Select Name
$Computers | Export-CSV -Path $env:TEMP\ZZZEXPORTE.csv -NoTypeInformation -Encoding UTF8
$Computers | ForEach {
$computerName = $_.Name
Write-Host $computerName
Write-Host "----"
}
You could also do this:
Get-ADComputer -Filter * -Property * | Select Name | ForEach {
$computerName = $_.Name
Write-Host $computerName
Write-Host "----"
$_
} | Export-CSV -Path $env:TEMP\ZZZEXPORTE.csv -NoTypeInformation -Encoding UTF8
Noting that we have to add $_ to our ForEach-Object loop so that it outputs the current item to the pipeline, but that our Write-Host statements don't effect the pipeline because they are writing to the console only. To be honest though, this is a bit harder to follow for anyone else reading your code.
$output = $data | Where-Object {$_.Name -eq "$serverName"} | Select-Object -Property Description1,Version | Where-Object {$_.Description1 -eq "Power controller Firmware"} | Select-Object -Property Version
Write-Host $output
Gives me the following output:
#{Version=3.4}
So $data is an array and I select what I want form it and assign it to a variable to eventually be inputted into a excel file but no matter what I seem to try I cant just select "3.4" Instead it selects like the above (#{Version=3.4}). Doesn't anybody know how to just select the "3.4" within my command?
Just replace last line with:
foreach( $out in $output )
{
Write-Host $out.Version
}
In fact your $output variable contains an array so you need to go through it with a foreach loop.
Then you can Write-Host or do anything with the Version property.
As stated by #okaram, if you want to make the same kind of looping but after a pipe you can do it this way:
$output | ForEach-Object {Write-Host $_.Version}
or
$output | %{Write-Host $_.Version}
Your last expression of
Select-Object -Property Version
Keeps the entire object in the pipeline, but filters down the properties to only Version. However, the -ExpandProperty will put the property value itself in the pipeline.
Select-Object -ExpandProperty Version
That should return the "3.4" result you expect.
Please try the following code:
$data | Where-Object {$_.Name -eq "$serverName"} | Select-Object -Property
Description1, Version | Where-Object {$_.Description1 -eq "Power controller
Firmware"} | write-Host $_.Version
So I have the following code to output all features and roles installed:
Import-Module ServerManager
$Arr = Get-WindowsFeature | Where-Object {$_.Installed -match “True”} | Select-Object -Property Name
$loopCount = $Arr.Count
For($i=0; $i -le $loopCount; $i++) {
Write-Host $Arr[$i]
}
However, the output is:
#{Name=Backup-Features}
#{Name=Backup}
#{Name=Backup-Tools}
How can I get rid of the # and {}'s ?
Use Select -ExpandProperty Name instead of Select -Property Name
Alternatively and also, I recommend using Foreach-Object instead of a C-style for loop.
Import-Module ServerManager
Get-WindowsFeature |
Where-Object {$_.Installed -match “True”} |
Select-Object -ExpandProperty Name |
Write-Host
Or
Import-Module ServerManager
Get-WindowsFeature |
Where-Object {$_.Installed -match “True”} |
ForEach-Object {
$_.Name | Write-Host
}
How about a nice one liner?
Get-WindowsFeature | ? {$_.Installed -match “True”} | Select -exp Name
If you can accept a totally static solution, this should work:
Write-Host $Arr[$i].Substring(2, $Arr[$i].Length-3)
If you're looking for a solution that looks specifically for those symbols and removes them, it would be a little different. Based on your question though, this should be just fine.