Is Start-Process -Passthru unable to grab the process ID? - powershell

I have a PowerShell script able to open and close .txt and .exe via a returned PID from Start-process $type -Passthru. However, if I try to do this same thing with .pngs I get this error:
Start-Process : This command cannot be run completely because the system cannot find all the information required.
I am trying to get a returned PID so I can close the default photo editor without having to explicitly call it by name. Code sample:
$object = Get-ChildItem | Where-Object {$_.LastWriteTime -gt (Get-Date).AddDays(-730)} | Select-Object -Property Name
[System.Collections.ArrayList] $filearray = $object
$removed = $filearray[-1].Name
$open_photo = Start-Process -FilePath $removed -passthru
$open_photo.Id

Related

Powershell script to compare processes from text file

I need to do the following:
Get a list of all the current processes on the system and save them to a text file called “before.txt”
Launch a new browser window (Chrome, Edge, Firefox – your choice)
Get a new list of all the current processes on the system and save them to a text file called “after.txt”
Using the compare-object cmdlet in PowerShell, find the new process ID for the browser you just opened
Once the process ID has been identified, kill the process using that process ID
I'm having difficulty completing the last task of killing the identified process from the text file. Any help is greatly appreciated. Thank you!
########################## Current Script#########################
Get-Process | select-object -Expand Name > before.txt
Invoke-Item "C:\Program Files\Internet Explorer\iexplore.exe"
Start-Sleep -s 3
Get-Process | select-object -Expand Name > after.txt
Compare-Object (get-content before.txt) (Get-Content after.txt) > final.text
$list = Get-Content final.text; Get-Process $list | kill -force -Raw
The simple fix to your code is to change the compare-object line. Try running that line without the redirect and you'll see it's not a simple list of names. Try changing that line in your script to the following:
Compare-Object (get-content before.txt) (Get-Content after.txt) | select -ExpandProperty InputObject > final.text
However, in PowerShell you don't need to use all these temporary files. You can have arrays of items. A more PowerShell answer would be:
$before = Get-Process
Invoke-Item ...
$after = Get-Process
$list = Compare-Object $before $after
$list |% { stop-process $_.InputObject.id }

Adding each item from for loop to csv file

I am trying to use power shell to determine whether a server has a particular patch installed based on the KB and if not append the name to a csv. my input file has system names so I want to export that system name if it does not find the patch installed.
here is what i have so far. The export to csv part does not seem to work.
forEach-Object{
try{
$status = wmic /node:#sys.csv qfe list full /format:table | findstr /i $kb_number
if(!$status){
$output_file = New-Item C:\temp\$kb_number.csv -ItemType File
export-csv $output_file -append -Force
}
else{
write-output $status
}
}
catch{
$error_message = $_.Exception.Message
#write-output "the error message is" $error_message
write-output "Could not find any system with this patch installed."
}
}
Why your code might be failing
We don't see where you're setting the values of #sys.csv or $kb_number in the code you shared. Either of those could be throwing you off.
But the real issue is Export-Csv. For one, you're making a new CSV with every iteration of the loop. And for two, you have to pass in some item for the cmdlet to export as a CSV. Right now, you're only providing these values.
$output_file = New-Item C:\temp\$kb_number.csv -ItemType File
Export-csv -Path $output_file -append -Force
Export-Csv requires an input object. You're not giving it one now.
What do you want to export? If you just want a list of computers without a patch, do this instead.
if(-not(Test-path C:\temp\$kb_number.csv)){
#if file doesn't exist, make it
$output_file = New-Item C:\temp\$kb_number.txt -ItemType File
}
#adds computer name if it doesn't have the patch
Add-Content -Path $output_file -Value $computer
General Suggestions
Instead of using ForEach-Object, you might find it's easier to debug if you use a ForEach loop like this.
$computers = Get-Content C:\pathTo\Your\ComputerList.txt
ForEach($computer in $computers){
}
One additional source of trouble is that your code is using older dos commands in WMIC and then tries to use PowerShell to store the records. You don't need to do this and can make it easier on yourself if you swap out the calls to wmic for Get-WmiObject or Get-CimInstance, the PowerShell native versions of the commands.
To do that, change this line:
wmic /node:#sys.csv qfe list full /format:table | findstr /i $kb_number
translates into
$kb_number = "KB4576484"
Get-CimInstance Win32_QuickFixEngineering -Filter "HotfixID = '$kb_number'" -ComputerName $computer
Source Description HotFixID InstalledBy InstalledOn
------ ----------- -------- ----------- -----------
Update KB4576484 NT AUTHORITY\SYSTEM 9/14/2020 12:00:00 AM
You can store the output of that in a variable and then call Export-Csv on it and that should work.
When in doubt, remove the filter part and just get it working to export all patches to a csv. Then add complexity by adding back the filtering statements.

How to make a script run only while another one is running

I need your help resolving an exercise in Powershell.
I have to make a script which runs only when another one is running.
For example, I have to run a script which deletes files older than 1 day while a script which restarts a process runs.
I tried to use jobs to make the script run in parallel but I haven't had any succes.
--The script to delete files
Get-ChildItem -Path "a path" -include *.txt -Recurse | Where-Object {$_.LastWriteTime -lt $DateToDelete} | Remove-Item -Force
--The script to restart a process
Get-Process notepad | Stop-Process | Start-Process
I think your problem is with the second script, you can't restart a process like that.
If you tried this line Get-Process notepad | Stop-Process | Start-Process in the console it will prompt you requesting the FilePath to the process you want to start, that's because Stop-Process do not return any result to the pipeline and then Start-Process is not receiving anything from the pipeline.
Look here to see how to restart process using PowerShell
And take a look at this MS module Restart-Process
Use this code to run scripts as job:
$days = -1
$currentDate = Get-Date
$DateToDelete = $currentDate.AddDays($days)
start-job -ScriptBlock {
Get-ChildItem -Path "a path" -include *.txt -Recurse | Where-Object {$_.LastWriteTime -lt $DateToDelete} | Remove-Item -Force
}
start-job -ScriptBlock {
Get-Process notepad | Stop-Process
}

PowerShell script to run application (with commands)

I am trying to run an application from C:\Program Files\APP\app.exe with the application built in commands. When I run from the command prompt, I can get the result I wanted. But I would like to use the script which will check other components of servers along with this one to avoid running this command manually. I tried both of the mentioned scripts below & I am not getting any output. It just opens a command prompt window, runs the result, and closes the command prompt,but I would like to get the output in an output file. Any suggestions? Please let me know.
$Output = "C:\Information.txt"
Start-Process -FilePath "C:\Program Files\APP\app.exe" -ArgumentList "query mgmtclass" | Out-File $Output
Additionally, I also tried -
$Output = "C:\Information.txt"
Start-Process -FilePath "C:\Program Files\APP\app.exe" -PipelineVariable "query mgmtclass" | Out-File $Output
I was also thinking that I can write a batch file & get output written in the temp directory & get those output using the command mentioned below -
Get-Content -Path 'C:\Program Files\tivoli\tsm\baclient\dsmerror.log' | select-object -last 15
Can you try using the RedirectStandardOutput parameter instead of | Out-File:
$Output = "C:\Information.txt"
Start-Process -FilePath "C:\Program Files\APP\app.exe" -PipelineVariable "query mgmtclass" -RedirectStandardOutput $Output
Update:
The error you are getting ("Missing an argument") means exactly what it says. I can't see the line of code you ran to get the error, but I can replicate by omitting the value of RedirectStandardOutput. This example uses splatting so the line of code is not so long, and you can see more clearly what RedirectStandardOutput is:
$Output = "C:\Information.txt"
#{
FilePath = "C:\Program Files\APP\app.exe"
PipelineVariable = "query mgmtclass"
RedirectStandardOutput = $Output
} | % { Start-Process #_ }

Process list and write output to files named after list members

I'm trying to run a command which accepts a list of names. It should go through each member of the list and then output it to a text file in a specific location, and the name of that text file will be the member name from the list. Then the script continues to the next member run the command on it, and then write the output to a text file whose name will be the 2nd member in the list.
I'm sure a loop is involved, and perhaps a temporary variable which I have no idea how to declare :(
Invoke-Command -ComputerName (Get-Content "C:\ServerList.txt") -ScriptBlock {
Servermanagercmd.exe -query roles.xml
} -credential baloon\yellow | Out-File C:\OutputF.txt
Pull out the Get-Content of the serverlist file so the server name values are available down the pipeline:
Get-Content c:\serverlist.txt | Where {$_} |
Foreach { Invoke-Command -ComputerName $_ -Scriptblock {...} -Credential baloon\yellow |
Out-File "$_.txt" }
Note that the Where {$_} is to weed out any empty lines in the file.
Shall I assume this issue is that the data that is being output has no context since you wont know what system it is from?
$outputfile = C:\OutputF.txt
Set-Content -Path $outputfile -Value ""
ForEach($server in (Get-Content "C:\ServerList.txt")){
Add-Content -Path $outputfile -Value "Server: $server"
Invoke-Command -ComputerName $server -ScriptBlock {Servermanagercmd.exe -query roles.xml} -credential baloon\yellow |
Add-Content -Path $outputfile
}
Wipe the file to start new (remove this if you dont want to erase the file.). For each server in your list add the server name on its own line in the file and then run the Invoke-Command also sending its output to file.
This will might be inefficient depending on the number of server you are checking. At that point I would consider using jobs.
Update
After reading Keith Hills answer I realize that I misread your question. My logic would output all to one file with the server name separating the contents. You actually wanted separate files.