I need to kill the process if start time is less than 2 hours.
I have written the below cmdlet to find out the starttime but how to find out if is it less than 2 hours:
get-process process1 | select starttime
There is also a possibility that on some hosts process1 is not running. so I need to check first if the process1 is running
You can use a loop of your choice, in this example ForEach-Object in addition to an if condition to check if the StartTime value is lower than 2 hours.
If you need to check first is the process is running then you would need to get all processes and filter by the process name you're looking for. Then check if the returned value from Where-Object is $null or not.
$procName = 'myprocess'
$process = Get-Process | Where-Object Name -EQ $procName
if(-not $process) {
Write-Warning "$procName not found!"
}
else {
$process | ForEach-Object {
if($_.StartTime -lt [datetime]::Now.AddHours(-2)) {
try {
'Attempting to stop {0}' -f $_.Name
Stop-Process $_ -Force
'{0} successfully stopped.' -f $_.Name
}
catch {
Write-Warning $_.Exception.Message
}
}
}
}
Related
I need to kill the process if start time is less than 2 hours.
I need to add sleep for 30 mins if start time is more than 2 hours.
I need to keep repeating it until the process is no more running.
I have written the below script so far to perform the above action.
$procName = 'myprocess'
$process = Get-Process | Where-Object Name -EQ $procName
if(-not $process) {
Write-Warning "$procName not found!"
}
else {
$process | ForEach-Object {
if($_.StartTime -lt [datetime]::Now.AddHours(-2)) {
Stop-Process $_ -Force
}
else {
sleep(1800)
}
}
}
}
How to add the above program in a do-while or another loop so as to keep checking until the process is no more running?
Also, how to implement a maximum timer of 4 hours?
If I understood correctly, your else condition could look like this using a do-while loop:
else {
do {
"$procName is still running, sleeping for 1800 sec"
Start-Sleep -Seconds 1800
} while(Get-Process | Where-Object Name -EQ $procName)
}
However note that this could cause an infinite loop if the process never stops or you implement a maximum timer, etc.
Following your comment regarding implementing a maximum timer, there are many ways you could do it, my personal preference would be to use a StopWatch:
else {
$timer = [System.Diagnostics.Stopwatch]::StartNew()
do {
# Do this while the process is still running AND
# the timer hasn't yet reached 4 hours
"$procName is still running, sleeping for 1800 sec"
Start-Sleep -Seconds 1800
$stillRunning = Get-Process | Where-Object Name -EQ $procName
} while($stillRunning -and $timer.Elapsed.Hours -lt 4)
$timer.Stop()
}
I suggest you use a windows schedule task that launch your powershell script every 30 minutes or so instead of blocking resource with your powershell that is waiting.
You can launch powershell and pass a script.
PowerShell.exe -File "C:\script.ps1"
I need to check for running Services on different Windows Servers.
there can be two services running (old or new version or both, with slightly different names)
need the output like: "new version" , "old version" or "both versions"
I wanted to simply check with the Get-Process command but I can't really get to a conclusion how to get my output and how to check if both are running.
Started like the following: how can I finish my script? or am I completely wrong? couldn't find anything that helps.
if (Get-Service "NAME" -ErrorAction SilentlyContinue | Where-Object {$_.Status -eq "Running"})
{Write-Host "New Client running"
}
if (Get-Service "NAME_old" -ErrorAction SilentlyContinue | Where-Object {$_.Status -eq "Running"})
{Write-Host "old Client running"
}
Else {Write-Host ”No Client found”}
obviously this script doesn't quite work. tested on a Server where only the new client is running and it outputs:
New Client running
No Client found
Change the second if statement to elseif - this way the else block only runs if neither of the two preceding conditions hold true:
if (Get-Service "NAME" -ErrorAction SilentlyContinue | Where-Object {$_.Status -eq "Running"})
{
Write-Host "New Client running"
}
elseif (Get-Service "NAME_old" -ErrorAction SilentlyContinue | Where-Object {$_.Status -eq "Running"})
{
Write-Host "old Client running"
}
else {
Write-Host "No Client found"
}
You can do this with your three if statements if you track your Get-Service results:
if ($newclient = Get-Service "NAME" -ErrorAction SilentlyContinue | Where Status -eq Running) {
Write-Host 'New Client running'
}
if ($oldclient = Get-Service "NAME_old" -ErrorAction SilentlyContinue | Where Status -eq Running) {
Write-Host 'old Client running'
}
if (-not ($newclient -or $oldclient)) {
Write-Host 'No Client found'
}
Slightly different approach :
"name1", "name2" | Get-Service | foreach-object {
write-host $_.name $_.status
}
Of course depends on logic required after
if you are interested in a little more scalable solution, I would suggest following:
I used $appsRunning to increment each time the script find a running service, so if you are interested in a total count of running services (from the $services list) you could use that variable.
$services = #(
[pscustomobject]#{ Name = "NAME"; Description = "New App" },
[pscustomobject]#{ Name = "NAME_old"; Description = "Old App" }
)
$appsRunning = 0
foreach ($service in $services) {
$app = Get-Service $service.Name
if ($app.status -eq "Running"){
write-host $service.Description is $app.status
$appsRunning++
}
}
if ($appsRunning -eq 0) {
Write-Host "No app Running"
I have the following code that works in that it creates multiple jobs and runs what's inside the scriptblock on all of the computers in the array ($SMSMembers). The problem is that it doesn't give any sort of meaningful output back that I can use to determine if the code ran successfully or not. I have tried about 100 different things that I have Googled but none of the solutions seemed to work for me. This is the code I'm trying to run that I thought should work according to other posts I've seen on StackOverflow.
$SMSMembers = #("computer1","computer2","computer3")
$output = #()
foreach ($compName in $SMSMembers) {
$scriptblock = {
$file = {"test"}
$filepath = "\\$using:compName\c$\scripts\NEWFILE.txt"
$file | Out-File -FilePath $filepath
Start-Sleep -Seconds 5
Remove-Item $filepath
}
$output += Start-Job -ScriptBlock $scriptblock | Get-Job | Receive-Job
}
Get-Job | Wait-Job
foreach ($item in $output) {
Write-Host $item
}
This script doesn't do much except copy a file to a remote computer and then delete it. I would just like to get output if the job was successful or not. Like I said this code works like it should, I just don't get feedback.
My end goal is to be able to send a command to an array of computers ($SMSMembers) and request the current user with this code and get the username input back:
$user = gwmi Win32_ComputerSystem -Comp $compName |
select Username -ExpandProperty Username
You create the job, get the job info, and then receive the job back to back to back, before the job can complete. Instead, collect the job info, then outside the loop wait for the jobs to finish, and receive the output when the jobs are done.
$SMSMembers = #("computer1","computer2","computer3")
$scriptblock = {
$file = {"test"}
$filepath = "\\$using:compName\c$\scripts\NEWFILE.txt"
$file | out-file -FilePath $filepath
Start-Sleep -Seconds 5
remove-item $filepath
}
$Jobs = foreach($compName in $SMSMembers){
Start-Job -ScriptBlock $scriptblock
}
Wait-Job $Jobs
$Output = Receive-Job $Jobs
foreach ($item in $output){
write-host $item
}
Edit: Modified the script slightly so I wasn't randomly copying files around, but it should still function the same. Then tested it with the expected results:
$SMSMembers = #("computer1","computer2","computer3")
$scriptblock = {
$RndDly=Get-Random -Minimum 10 -Maximum 45
start-sleep -Seconds $RndDly
"Slept $RndDly, then completed for $using:compname"
}
$Jobs = foreach($compName in $SMSMembers){
Start-Job -ScriptBlock $scriptblock
}
Wait-Job $Jobs
$Output = Receive-Job $Jobs
foreach ($item in $output){
write-host $item
}
Id Name PSJobTypeName State HasMoreData Location Command
-- ---- ------------- ----- ----------- -------- -------
1 Job1 BackgroundJob Completed True localhost ...
3 Job3 BackgroundJob Completed True localhost ...
5 Job5 BackgroundJob Completed True localhost ...
Slept 30, then completed for computer1
Slept 27, then completed for computer2
Slept 11, then completed for computer3
Look at the below code and i think you should be able to figure this out.
> Get-job | Receive-Job 2>&1 >> c:\output.log
The 2>&1 >> with collect all output from Get-Job | Receive-Job it should work similarly for start-job
all.
I'm stuck. I have a PowerShell script which looks to a specific folder for files which are older than 30 days from the last modified date (additionally, it'll create the folder if it doesn't exist). It creates the folder, it gives me the total files, it'll list all of the files in a test query, but it won't actually count the number of 30+ day old files. I've tried several methods to get this count (some deriving from other solutions to delete old files from this site), but PowerShell just doesn't want to do it.
Here's my code so far...
$HomePath = $env:USERPROFILE
$CompanyFolder = "\Company"
$TimeSensativeFolder = "\TimeSensative"
$TimeSensativePath = $HomePath+$CompanyFolder+$TimeSensativeFolder
$OldFilesAmount = 0
$TotalFilesAmount = 0
$TimeLimit = (Get-Date).AddDays(-30)
$StatusOK = "No old files were found in the time sensative folder."
$StatusCreated = "The time sensative folder was created."
$StatusError1 = "There were old files found in the time sensative folder!"
$StatusError2 = "Unable to create the time sensative folder!"
function MakeTimeSensativeFolder ($TimeSensativePath) {
try {
md $TimeSensativePath -Force -ErrorAction Stop
Write-Host $StatusCreated
}
catch {
Write-Host $StatusError2
}
}
function CountOldFiles () {
$OldFilesAmount = $OldFilesAmount + 1
}
if(!(Test-Path $TimeSensativePath -PathType Container)) {
MakePHIFolder $TimeSensativePath
}
else {
}
try {
$TotalFilesAmount = (Get-ChildItem $PHIPath -Recurse -File | Measure-Object).Count
# I've tried this...
Get-Item $PHIPath | Foreach {$_.LastWriteTime} -ErrorAction Stop
if (Get-Content $_.LastWriteTime | Where-Object {$_ -gt $TimeLimit}) {
CountOldFiles
}
# And I've tried this...
Get-ChildItem -Path $PHIPath -Recurse -File | Foreach-Object {
if (Get-Content $_.LastWriteTime | Where-Object {$_ -gt $TimeLimit}) {
CountOldFiles
}
}
# I've even tried this...
Get-ChildItem $PHIPath -Recurse -File | ? {
-not $_.PSIsContainer -and $_.LastWriteTime -lt $TimeLimit
} | CountOldFiles
# And this, as well...
Get-ChildItem -Path $PHIPath -Recurse -File | Where-Object {$_.LastWriteTime -gt $TimeLimit} | CountOldFiles
}
catch {
MakeTimeSensativeFolder $TimeSensativePath
}
# Used for testing.
<#
Get-ChildItem $TimeSensativePath -Recurse -File
Write-Host "TimeSensative folder exists:" $TimeSensativePathExists
Write-Host "Home TimeSensative path:" $TimeSensativePath
Write-Host "Old files found:" $OldFilesAmount
Write-Host "Total files found:" $TotalFilesAmount
Exit
#>
# Determining proper grammar for status message based on old file count.
if ($OldFilesAmount -eq 1) {
$StatusError1 = "There was "+$OldFilesAmount+" old file of "+$TotalFilesAmount+" total found in the PHI folder!"
}
if ($OldFilesAmount -gt 1) {
$StatusError1 = "There were "+$OldFilesAmount+" old files of "+$TotalFilesAmount+" total found in the PHI folder!"
}
# Give statuses.
if ($OldFilesAmount -gt 0) {
Write-Host $StatusError1
}
else {
Write-Host $StatusOK
}
Depending on which I tried, I would get no result or I'd get something like this:
Get-Content : Cannot find drive. A drive with the name '12/22/2016 17' does not exist.
At C:\Users\nobody\Scripts\PS1\ts_file_age.ps1:54 char:14
+ if (Get-Content $_.LastWriteTime | Where-Object {$_ -gt $Tim ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (12/22/2016 17:String) [Get-Content], DriveNotFoundException
+ FullyQualifiedErrorId : DriveNotFound,Microsoft.PowerShell.Commands.GetContentCommand
In any instance, there's no old file count as I'm endeavoring to demand.
It's been a bit of a head scratcher. Any advice?
Thanks so much in advance!
Filtering files with last write time is easy enough. Like so,
$allFiles = gci
$d = (Get-Date).adddays(-30)
$newFiles = #()
$oldFiles = #()
$allFiles | % { if ($_.lastwritetime -ge $d) { $newFiles +=$_ } else { $oldFiles += $_ } }
What's done here is that first all the files are set in a collection. This isn't mandatory, but one can browse the collection to check that it's been populated properly. This is useful in cases one has complex paths or exclusion filters.
The second step is just to get a DateTime that is used later to divide files into old and new ones. Just like the sample did, so nothing interesting here. Actually, there's one little thing. The date is -30 days, but hours, minutes and seconds are based on current time. So if there's really tight limit, consider using midnight time ([datetime]::Today).AddDays(-30)
The third step is to declare two empty collections for new and old files.
The last step is to iterate through the $allFiles and check the last write time. If it's greater or equal to the cutpoint, add it into $newFiles, othervise $OldFiles.
After the last step, further processing should be simple enough.
This is what I do to get (delete in this case) files older than X days:
$Days = 5
$limit = (Get-Date).AddDays(-$Days)
$CurrentDate = Get-Date
#This will delete all files older than 5 days
Get-ChildItem -Path $Workdir -Recurse -Force | Where-Object { !$_.PSIsContainer -and $_.LastWriteTime -lt $limit } | Remove-Item -Force
I've to stop multiples services, check the services if they are correctly stopped THEN run multiple batch files. When the batch jobs are done, start again the stopped services at the first place. I started the following script but could not go further.
#Define Services
$service1 = 'StiSvc'
$service2 = 'AdobeARMservice'
$services = #(
$service1,
$service2
)
#Stop Services
Get-Service |
Where { $services -contains $_.Name } |
Foreach {
$_ | Stop-Service
}
#Verify Services
Get-Service |
Where { $services -contains $_.Name } |
Foreach {
if ((Get-Service $_.Name).Status -eq "stopped") {
Write-Host 'Service Stop Pass (0)'
} else {
Write-Host 'Service Stop Failed (1000)';
exit '1000'
}
}
#Start batch
if ($services.Status -eq "Stopped") {
Start-Process "cmd.exe" "/c C:\download\hello.bat"
} else {
Start-Sleep -s 10
}
The following should work:
$services = 'StiSvc', 'AdobeARMservice'
Stop-Service $services -ErrorAction Stop
& 'C:\download\hello.bat'
& 'C:\path\to\other.cmd'
#...
Start-Service $services
If it doesn't, you need to provide more information about what exactly fails, and how. Include all error and status messages.
Thank you all,
I modified the script as follow. The script stops 2 services, when the 2 services are stopped it start the batch file.
#Stop Services
Get-Service StiSvc, AdobeARMservice | Stop-Service
#Verify Services
if (((Get-Service StiSvc).Status -eq "stopped") -and
((Get-Service AdobeARMservice).Status -eq "stopped"))
# Start batch
{Start-Process "cmd.exe" "/c C:\download\hello.bat"}
I’m working on to improve the script. I’ll come back to you asap.
Regards