List all Server Features/Roles in Powershell - powershell

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.

Related

Output running services to csv with computer name

I need to generate a csv containing running services to csv with the corresponding computer name
I know there is a simple way to do this and I have been tinkering with creating a new psobject, but I am not sure how to pipe the results to the new-object...
Here is what I am using:
$Input = "SomePath"
$Output = "SomeOtherPath"
$CompNames = Get-Content -Path "$Input"
ForEach ($CompName in $CompNames){
Get-Service -ComputerName $CompName | Where-Object {$_.Status -eq "Running"} | Export-csv -Path "$Output"
}
What I need in the CSV is:
ComputerName, ServiceName, DisplayName
basically, I need to add the computer name to the array.
If you want to be able to pipe the results, use a foreach-object.
$Output = "SomeOtherPath"
Get-Content -Path "SomePath" | ForEach-Object {
Get-Service -ComputerName $_ | Where-Object {$_.Status -eq "Running"} | Select-Object ComputerName, ServiceName, DisplayName
} | Export-csv -Path "$Output"
If you want to stick to a foreach statement, collect it all first then export it.
$Output = "SomeOtherPath"
$CompNames = Get-Content -Path "SomePath"
$results = ForEach ($CompName in $CompNames){
Get-Service -ComputerName $CompName | Where-Object {$_.Status -eq "Running"} | Select-Object ComputerName, ServiceName, DisplayName
}
$results | Export-csv -Path "$Output"
Try like this (Don't use $Input as variable name)
$InputX = "SomePath"
$Output = "SomeOtherPath"
$CompNames = Get-Content -Path "$Input"
ForEach ($CompName in $CompNames){
Get-Service -ComputerName $CompName | Where-Object {$_.Status -eq "Running"} | Select-Object ComputerName, ServiceName, DisplayName | Export-csv -Path "$Output"
}

Get-WinEvent Script

I have a powershell script which is working as expected. I need some help with formatting the output.
$Date = (Get-Date).AddDays(-1)
Get-ChildItem –Path "D:\Log\" -Recurse | Where-Object {($_.LastWriteTime -lt $Date)} | Remove-Item
$filter = #{
LogName='Application'
StartTime=$Date
}
Get-WinEvent -FilterHashtable $filter | Select-Object TimeCreated,Message |
Where-Object { $_.Message -like '*renamed*' -and $_.Message -notlike "*csv*" } |
Out-File -FilePath D:\Log\DailyReport_$(get-date -Format yyyyddmm_hhmmtt).txt
The output is
TimeCreated Message
----------- -------
4/16/2020 4:03:30 AM 04712: renamed
I need the output to be
Date Time,File Name
4/16/2020 4:03:30 AM, 04712: renamed
The column header needs to be renamed with a comma. Any help will be greatly appreciated.
Thanks,
Arnab
You can rename the properties with Select-Object and convert to comma-separated values with ConvertTo-Csv or Export-Csv:
# ...
Get-WinEvent -FilterHashtable $filter |
Select-Object TimeCreated,Message |
Where-Object { $_.Message -like '*renamed*' -and $_.Message -notlike "*csv*" } |
Select-Object #{Name='Date Time';Expression='TimeCreated'},#{Name='File Name';Expression='Message'} |
Export-Csv D:\Log\DailyReport_$(get-date -Format yyyyddmm_hhmmtt).txt -NoTypeInformation

Compare CSV to Array

I have an empty array that's storing all my windows services that start with certain strings such as OPS-AmazonServer,not included in the code I provided is where I parse the service to just say it's application name.
I then have a CSV file with a list of service names labeled under 'Application Name'. It looks like this
ApplicationName,Instance,Priority
AuthBridge,,1
AmazonServer,,1
AmexEC,,1
What I want to do is compare the service stored in the array to the CSV list but I can't seem to figure out how the logic flows.
$services = get-service Centinel* -ComputerName $serverName | select -expand name
$centinelServices = #()
$services = get-service OPS* -ComputerName $serverName | select -expand name
$opsServices = #()
$services = #()
foreach($service in $centinelServices) {
$services += $service
}
foreach($service in $opsServices) {
$services += $service
}
$csvLocation = "\\logserver\Cardinal\OPS\QA\Task\conf\Centinel\app-restart.csv"
$masterList = import-csv $csvLocation
$applications = #()
$masterList | ForEach-Object {$applications += $_.ApplicationName}
forEach($service in $services){
forEach($application in $applications){
if($service -eq $application){
"$service match found"
}
else {
"$service match not found"
}
}
Ok, easiest way to do this is to use Compare-Object, and a little magic with Select.
I'm going to assume that the ApplicationName column in your CSV is a list of strings that match up with the Name property in your Windows Services list. So let's start by importing that CSV, and changing the property name of ApplicationName to just Name, so that it matches the related property on your Windows Service objects.
$masterList = Import-Csv $csvLocation | Select #{l='Name';e={$_.ApplicationName}}
Then we simply use Compare-Object to see what's in both lists:
Compare-Object (Get-Service) -DifferenceObject $masterList -Property Name -IncludeEqual
If you wanted to parse that you can always pipe it to a Where clause, or use combinations of -IncludeEqual and -ExcludeDifferent parameters:
$masterList = Import-Csv $csvLocation | Select #{l='Name';e={$_.ApplicationName}}
$myServices = Get-Service
$foundServices = Compare-Object $myServices -DifferenceObject $masterList -Property Name -IncludeEqual -ExcludeDifferent
$servicesNotInMaster = Compare-Object $myServices -DifferenceObject $masterList -Property Name | Where {$_.SideIndicator -eq '<='}
$servicesNotFoundLocally = Compare-Object $myServices -DifferenceObject $masterList -Property Name | Where {$_.SideIndicator -eq '=>'}
Or using the Switch cmdlet to do it all in one go:
$masterList = Import-Csv $csvLocation | Select #{l='Name';e={$_.ApplicationName}}
$myServices = Get-Service
Switch(Compare-Object $myServices -dif $masterList -prop Name -includeequal -PassThru){
{$_.SideIndicator -eq '<='} {[array]$servicesNotInMaster += $_}
{$_.SideIndicator -eq '=>'} {[array]$servicesNotFoundLocally += $_}
{$_.SideIndicator -eq '=='} {[array]$foundServices += $_}
}
Edit: Ok, updating from your addition to the OP. Looks like you could be well served by simply using a Where clause rather than getting services over and over.
$services = Get-Service -ComputerName $serverName | Where{$_.Name -like 'ops*' -or $_.Name -like 'Centinel*'} | Select -Expand Name
Then you import your CSV, and use Select -Expand again to get the value of the property, rather than looping through it like you were before.
$masterList = Import-Csv $csvLocation | Select -Expand ApplicationName
Now you just have two arrays of strings, so this actually gets even simpler than comparing objects... You can use the -in operator in a Where statement like this:
$services | Where{$_ -in $masterList} | ForEach{"$_ match found"}
That basically filters the $services array to look for any strings that are in the $masterList array. This will only work for exact matches though! So if the service is listed as 'OPS-AmazonServer', but in your CSV file it is listed at just 'AmazonServer' it will not work! I use that example specifically because you have that in your example in your question. You specifically call out the service named 'OPS-AmazonServer' and then in your CSV sample you list just 'AmazonServer'.
If the listings in the CSV are partial strings that you want to match against you could use RegEx to do it. This will probably make less sense if you aren't familiar with RegEx, but this would work:
$services = Get-Service -ComputerName $serverName | Where{$_.Name -like 'ops*' -or $_.Name -like 'Centinel*'} | Select -Expand Name
$masterList = (Import-Csv $csvLocation | ForEach{[regex]::escape($_.ApplicationName)}) -join '|'
$services | Where{ $_ -match $masterList } | ForEach{"$_ match found"}

powershell Get-Winevent change output date format?

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

Powershell Select-Object Formatting

$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