How To Use If Else In Where-Object Powershell - powershell

I am attempting to search HotFixes installed on a machine and pipe the machine name with the specified KB installed to an excel sheet "else" pipe the machine names without the KB installed to another excel sheet.
I've gotten the basic command down that will do this but because it uses the % (foreach) command, it is appending the machine name to the excel sheet for each KB it finds or doesn't find and I end up with dozens of duplicates.
How can I get this code to append a single entry for each search through all the KBs and not for each KB?
Get-HotFix | %{if($_.HotFixID -match "KB2687455"){(get-wmiobject win32_computersystem).name | Out-File C:\Installed.txt -append}` else{(get-wmiobject win32_computersystem).name | Out-File C:\NotInstalled.txt -Append}}
EDIT:
I have found a work around. Instead of trying to do this in a command line type of code I rewrote the code and surprisingly it worked. Let me know if you see any potential issues with this code.
if (Get-HotFix |?{$_.HotFixID -match "KB2687455"}) {
(get-wmiobject win32_computersystem).name | out-file C:\Installed.txt
}
else {
(get-wmiobject win32_computersystem).name | out-file C:\NotInstalled.txt
}

You are looping over the hot fixes that are installed, and writing results for each hot fixes when it looks like all you want to do is write whether a given machine has a hot fix installed or not. I'm assuming you will be running this on multiple machines and that the output file will be on a network share.
You need to break out of your else block after the initial pass:
Get-HotFix | % {
if ($_.HotFixID -match "KB2687455") {
(get-wmiobject win32_computersystem).name | Out-File C:\temp\Installed.txt -append
}
else
{
(get-wmiobject win32_computersystem).name | Out-File C:\temp\NotInstalled.txt -Append
break
}
}

Related

How do I get a list of the servers as well as respective application and version of that very same app to be exported properly into excel?

With this script, I am able to find a specific application on a list of multiple remote devices and determine the version number of the application on their corresponding host system. This is outputted beautifully in the PS window. However, I am having trouble exporting the results properly into excel, that is, I want each property (Name, Version, PSComputerName) to be in a separate column vs all in one column. So far, I've tried the following
$list = Get-Content -Path C:\Users\bob\AppList.txt
$Servers = Get-Content -Path C:\Users\bob\ServerList.txt
foreach ($Serv in $Servers) {
Get-WmiObject -Namespace ROOT\CIMV2 -Class Win32_Product -ComputerName $Serv |
Select-Object -Property Name, Version, PSComputerName |
Where-Object -FilterScript { $_.Name -like "*$list*" } |
Export-Csv -Path C:\Users\bob\ServerListResults.csv
}
This resulted in simply just one device's information being extracted while every other cell was empty
I added -append at the very end! Thank you anyways!

Ouput Server Name Along With InstallState of Service

I'm pretty new to Powershell. I have the following simple little script:
$serversall = (Get-Content ".\Servers.txt")
foreach($vm in $serversall){
Get-WindowsFeature Web-Server -ComputerName $vm |
Select-Object InstallState |
Export-Csv -path E:\Scripts\Output\IISWebServersStatus.csv -Append
}
This just gives me one column to let me know if the status is "Installed" or "Available". I want another column that would also show the server name next to the status of the service. Any idea how I would accomplish that?
I would recommend the following approach:
$serversall = (Get-Content ".\Servers.txt")
$output = #()
foreach($vm in $serversall) {
$installed = (Get-WindowsFeature Web-Server -ComputerName $vm).InstallState
$output += New-Object PSCustomObject -Property #{'ComputerName'=$vm; 'Status'=$installed }
}
$output | Export-Csv -path E:\Scripts\Output\IISWebServersStatus.csv -Append
Create an array, $output that you can use to store all the information. On each loop iteration, build an object that holds the the server name and the install state and append it to the output array.
After the loop is done, write the output array to the csv file.
Doing one file write at the end will save on i/o operations, so could save time. In this example, Get-WindowsFeature is a relatively slow operation so it probably makes little difference, but good to understand the theory nonetheless.

Export installed software to csv from multiple remote systems

My script does (somewhat) what it's supposed to do if I need the information from the local PC. I have it reaching to a txt file for a list of computers. The script will read the list and show "Processing:..." for the list of computers but the export only shows the local system. Even if I remove my local PC from the txt file, the export to csv still only shows the local system. It does create the correct columns and populates accordingly. I just need it to pull the data from remote systems as well. Since the script will be used by multiple people, the variables allow the txt file and output file to be on their systems.
Function Export-InstalledSoftware {
Process {
if (Test-Connection -ComputerName $_ -count 1 -quiet)
{
echo "Processing: $env:COMPUTERNAME"
Get-ItemProperty -path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*,HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* `
| Select-object #{n='ComputerName';e={$env:COMPUTERNAME}},#{n='DisplayName';e={$_.displayName}},#{n='Publisher';e={$_.Publisher}},#{n='DisplayVersion';e={$_.DisplayVersion}} `
| Sort displayName `
| Export-CSV C:\Users\$(get-content env:username)\Desktop\"SoftwareQuery_"$(get-date -f yyyy-MM-dd)".csv" -NoTypeInformation -Encoding ASCII
}
}
}
Get-Content "C:\Users\$(get-content env:username)\Desktop\systems.txt" -readcount 1 | Export-InstalledSoftware

Printer Migration - Powershell script

I have found some great examples on foreach loops in Powershell here but I just can't wrap my head around foreach loops for what I am doing.
I found great scripts that deal with migrating printer when migrating from one Windows print server to another however my challenge is that I am migrating from an Novell iPrint server to a Windows server.
The struggle is that the printer name or share name (or any printer property) for iPrint printer is not the hostname so I have to come up with some translation table with iPrint name and Printer hostname.
Initially, I wanted to just have column 2 of my translation table have it execute my powershell command to install a network printer which would make things easier.
I am in the process of trying to create a logon script to query printers that are installed on computer and have it do a 'foreach' loop against a CSV with iPrint names and hostnames.
csv 1
installediprintprintername1
installediprintprintername2
installediprintprintername3
printtranslationtable.csv
column 1 column 2
iprintprintername1 hostnameprinter1
iprintprintername2 hostnameprinter2
iprintprintername3 hostnameprinter3
iprintprintername4 hostnameprinter4
This is what I got so far but not able to get it to work. Any help would be appreciated!
$printers = #(Get-wmiobject win32_printer)
$path = "\\networkdrive\printtranslationtable.csv"
$printertranslation = Import-Csv -path $path
foreach ($iprintprinter in $printtranslationtable) {
foreach ($name in $csv1) {
if ($name -eq $printtranslationtable.column1) {
Write-Host $newPrinter = $printtranslationtable.column2
}
}
}
Update
So I was able to tweak the script #TheMadTechnician suggested and able to get this PS script to work in my environment. What I am trying to do is to check if new printers are installed and if they are then just exit script. This is what I have but can't get it to exit or break. I was also trying to write the new printers into text file but not necessary, I would like for it to stop executing script.
if (($printers.name -like "\winprint*") -eq $true) {
$printers.name -like "\winprint\" | out-file -FilePath "C:\windowsprinters.txt" -Append
{break} {exit}
}
When you read the file with Import-Csv, PowerShell creates an array of custom objects with property names from the header line. On the other hand Get-Content produces simple array of string values. I came up with this one liner, which goes thru the translation table and checks if the printer list contains one. This is not optimal if you have billions of printers, but keeps things clear:
printers.txt:
iprinter2
iprinter3
printertable.csv:
"Column1";"Column2"
"iprinter1";"hostname1"
"iprinter2";"hostname2"
"iprinter3";"hostname3"
"iprinter4";"hostname4"
PowerShell:
$printers = Get-Content .\printers.txt
$prtable = Import-Csv -Delimiter ";" .\printertable.csv
$prtable | ?{ $printers -contains $_.Column1 } | %{Write-Host "Install $($_.Column2)"}
Ok, so you query what printers are installed, and you have a translation table loaded from a CSV, now you just need to look at that translation table and cross reference which entries have a listing in the local computer's printer listings.
$printers = #(Get-wmiobject win32_printer)
$path = "\\networkdrive\printtranslationtable.csv"
$printertranslation = Import-Csv -path $path
$printertranslation | Where{$_.Column1 -in $printers.ShareName} | ForEach{ Add-Printer $_.Column2 }
I don't know what property of the win32_printer object aligns best for you, but I would suggest ShareName or DeviceId. Those should be something like:
ShareName: XeroxColor02
DeviceId: \\printserver\XeroxColor02

test-connection that supports wildcard? workaround?

trying to see if anyone has a known workaround for using the test-connection cmdlet in powershell to ping wildcard entries in DNS.
I'm trying to clean out our DNS db and exported a list from our BIND server and am in the process of just pinging through the 600+ machines to see if anything responds. I made my own simple script but have also found one that works slightly better on this forum. The script works but the cmdlet help files state that the -computername parameter does not support wildcards and sure enough, when i run the script all CNAME records are reporting down/false when they actually should be responding. The code I'm using is below and is kind of messy but I just needed something quick and it works, but I've included it below for reference:
Get-Content -path C:\Work\testy.txt | ForEach-Object { Test-Connection -ComputerName $_ -Count 1 -AsJob } | Get-Job | Receive-Job -Wait | Select-Object #{Name='ComputerName';Expression={$_.Address}},#{Name='Reachable';Expression={if ($_.StatusCode -eq 0) { $true } else { $false }}} |out-file -FilePath c:\work\TEST.txt
As pointed out by briantist, any non-existing record name will do. You could generate a GUID to substitute the * in your record name:
"subdomain.domain.tld","*.domain.tld" |ForEach-Object {
Test-Connection -ComputerName $($_ -replace '\*',"$([guid]::NewGuid())")
}
Your expression for whether it's "Reachable" or not can be simplified as well:
#{Name='Reachable'; Expression={[bool]($_.StatusCode -eq 0)}}