Duration of tasks with Windows Task scheduler - powershell

Is it possible to know the duration of a certain task to calculate from "Created Task Process" to "Task completed"?
Task scheduler only show the Last Run Time but not the duration of all execution.

You can do something like the following:
$TaskName = '\Task Name'
$StartTime = (Get-Date).Adddays(-7)
$EndTime = Get-Date
$filter = #{ LogName = 'Microsoft-Windows-TaskScheduler/Operational'
ID = 129,102
StartTime = $StartTime
EndTime = $EndTime
Data = $TaskName
}
Get-WinEvent -FilterHashTable $filter | Select-Object TimeCreated,#{n='Action';e={$_.TaskDisplayName}}
Explanation:
For $TaskName, you must enter the task name exactly as it would show in (Get-WinEvent).Properties. You can also see this exact name in the task history messages. It will likely contain the backslash in the name.
You can set $StartTime and $EndTime to whatever you like here. Having a time interval speeds up the query retrieval time.
$filter is where the magic happens. It will ultimately be pushed into the parameter -FilterHashTable. Since the ID key can accept an array of [int], we can just comma separate the values. 129 is Created Task Process. 102 is Task Completed. Data does not accept wildcards so we must be exact with the task name as it would show in a System.Diagnostics.Eventing.Reader.EventProperty property. If you do not use Data, you will have to rely on Where-Object to further filter your task data by the task name, which will be significantly slower.

Related

Is there a way to insert a string (specifically a colon) into an integer variable?

I'm trying to make a code that automates creating a scheduled task by pulling information from an .ini file using schtasks.exe in powershell. However the starttime parameter has a HH:mm format.
It doesn't accept the time in string format (invalid starttime value) and the : interferes with converting it to an integer.
I pulled the hours and minutes as separate variables (and converted them to integers) and tried to "connect" them with a : which gives me variable reference and unexpected token errors.
I've pulled the time from the .ini and removed the :, converted it to an integer, and then tried the .insert(2,':') which gives me
"invocation failed, int 32 does not contain a method named insert"
The code itself-
schtasks.exe /RU $username /RP $password /CREATE /SC DAILY /TN 'My Task' /TR 'powershell.exe C:\mycode.ps1' /ST $time
Process of pulling the time form the .ini-
$pull = Get-Content -Path 'C:\Info.ini' | Select -Skip 2 | ForEach-Object {$_ -replace '\D+(\d+)','$1'}
$inttime = [int]$pull
$time = $inttime.Insert(2,':')
Is there any way for me to get the : between the integers after pulling them from the file? Thank you.
You are currently attempting to use the Insert() method from String class on an Int32 object. You will need to cast the variable as a string or convert the value to a string to use the method.
$time = ([string]$inttime).Insert(2,':')
# OR
$time = $inttime.ToString().Insert(2,':')
If all of the digits you are trying to capture are in groups of 4, you can just perform this insert with your -replace operator.
$pull = Get-Content -Path 'C:\Info.ini' |
Select-Object -Skip 2 |
ForEach-Object { $_ -replace '\D+(\d{2})(\d{2})','$1:$2' }

duplicates when using directorysearcher

I have a script that is using DirectorySearcher to query Active Directory for around ~13k users total every day.
I have been told that there are duplicates in my report, but I cannot figure out why.
The duplicates usually appear at the end of the report, and has been 6-7 users so far. The only difference between these users & their previous entry in the report is that their last logon time has changed (the time of which is seconds AFTER the script was initially started)
#Get date for 3months back in datetime format
$Date = (Get-Date).AddDays(-90)
# Correct for daylight savings.
If ($Date.IsDaylightSavingTime)
{$Date = $Date.AddHours(-1)}
# Convert the datetime value, in UTC, into the number of ticks since
# 12:00 AM January 1, 1601.
$Value = ($Date.ToUniversalTime()).Ticks - ([DateTime]"January 1, 1601").Ticks
$Searcher = New-Object DirectoryServices.DirectorySearcher
$Searcher.PageSize = 30000
$Searcher.Filter = "(&(&(objectCategory=person)(objectClass=user))(lastLogonTimeStamp>=$value)(pwdLastSet>=$value)(!(userAccountControl:1.2.840.113556.1.4.803:=2)))"
$Searcher.SearchRoot = 'LDAP://dc=contoso,dc=net'
$results = $Searcher.FindAll()
foreach ($result in $results)
{
# Fetches different attributes for each user
# which is then appended to a .csv file via Add-Content
}
It feels like I am identifying additional users based on the fact that their last logon time was changed.. does anyone know anything about this? Maybe
How I can disable this behavior?
The script runs at 06:00:00.
Here is the last logon time for the duplicate entries
10/31/2015 06:00:24
10/31/2015 06:00:32
10/31/2015 06:02:07
10/31/2015 06:05:01
10/31/2015 06:06:05
10/31/2015 06:08:19
10/31/2015 06:08:36

Date / Time condition in powershell - SharePoint - LastItemModifiedDate - LastRunTime

I'm making a script that collect two dates from the system. One from when the scheduling task has last run and the date a list has last been modified. Problem is that the datetime format isn't correct .
LastItemModifiedDate from a SPList - output format 04/09/2015 12:48:48
LastRunTime from a scheduling task - output format 09.04.2015 10:50:03
What I want to do is to check if the list has been changed since the last time the scheduling task has run.
$scheduledTask = Get-ScheduledTask -TaskName "SharePoint scheduling" | Get-ScheduledTaskInfo
$scheduledTaskLastRunTime = $scheduledTask.LastRunTime
$listExist = $spSourceWeb.Lists | where{$_.Title -eq $listName}
if($listExist)
{
$spSourceList = $spSourceWeb.Lists[$listName]
if ($scheduledTaskLastRunTime -le $spSourceList.LastItemModifiedDate)
{
Write-Host " Changes found" -ForegroundColor Green
SetListColumnToCopy($listName)
}
Do I do the IF correct ? What magic do I have to do to check the datetime?
I've read that "don't need a special format to compare dates in Powershell" but is it true in this situation?
You should use ParseExact static method from DateTime class.
$dateToCompare = [datetime]::ParseExact("09.04.2015 10:50:03","MM.dd.yyyy hh:mm:ss", $null)

How can you continue executing a PowerShell script, only if it has been called 3 times in 1 minute?

I have a script that is being called via a Windows Scheduled Task, and that task is triggered based on a certain Windows Application Event. It is only critical to execute the script, though, if the event occurs 3 or more times in 1 minute; if the event occurs once a minute, no action should be taken.
I know this can be handled in the script itself. Let's say there are at least 2 new variables I will need:
# time window, in seconds
$maxTime = 60
# max number of times this script needs to be called, within $maxTime window,
# before executing the rest of the script
$maxCount = 3
I started outlining an algorithm using a temp file as tracking, but thought there might be a simpler solution that someone can show me. Thanks
You could store your execution times in an environment variable.
Before this script will work, you must create the LastExecutionTimes environment variable.
$maxTime = 60
$maxCount = 3
$now = Get-Date
# Get execution times within the time limit.
$times = #($env:LastExecutionTimes -split ';'|
Where-Object {$_ -and $now.AddSeconds(-1 * $maxTime) -lt $_})
$times += '{0:yyyy-MM-dd HH:mm:ss}' -f $now
$env:LastExecutionTimes = $times -join ';'
if($times.Length -lt $maxCount) {return}
# Reset the execution times
$env:LastExecutionTimes =''
Write-Host 'Continue Script' -ForegroundColor Yellow
I would write a text file and a secondary script or function to check it. Where essentially it will call it each time, and then writes the information writes to a text file at call time.
The something like this:
if(!((Get-Date).AddMinutes(-1) -lt $oldTime))
{
$CurDate = Get-Date
"$CurDate, 1" | out-File "TheCheck.txt"
}
else
{
$counter++
if($counter -ge 3) {Call WorkerFunction}
else{
"$oldTime, $counter" | Out-File "TheCheck.txt"
}
Its missing some variables, but overall should be functional as a supplemental script. Then what your scheduled task actually does is call this, if the time since the $oldTime is over 1 minute, then it over writes the file with the current time and 1 for a $counter variable. If its less than a minute since the first call it then checks the $counter and if it is 3 or higher (could also do -eq ) to 3 then it calls your main script.

how to use PowerShell to inventory Scheduled Tasks

Does anyone have a link or script that uses PowerShell to inventory the Scheduled Tasks on a server, including the Action?
I am able to get the Scheduled Service com object and what I would call "top level" properties (name, state, lastruntime), but would like to also get information from the "Actions" part of the Schedule Tasks (essentially, the name of Scheduled Task and its commandline).
For example:
$schedule = new-object -com("Schedule.Service")
$schedule.connect()
$tasks = $schedule.getfolder("\").gettasks(0)
$tasks | select Name, LastRunTime
foreach ($t in $tasks)
{
foreach ($a in $t.Actions)
{
$a.Path
}
}
The above snippet of code works in terms of listing the tasks; but the loop on the Actions simply does not seem to do anything, no error, no output whatsoever.
Any help would be appreciated.
This is probably very similar to current answers, but I wrote a quick script to get you going. The problem with your current script is that there is no Actions property in a task. You need to extract it from the xml task-definition that the comobject provides. The following script will return an array of objects, one per scheduled task. It includes the action if the action is to run one or more command. It's just to get you going, so you need to modify it to include more of the properties if you need them.
function getTasks($path) {
$out = #()
# Get root tasks
$schedule.GetFolder($path).GetTasks(0) | % {
$xml = [xml]$_.xml
$out += New-Object psobject -Property #{
"Name" = $_.Name
"Path" = $_.Path
"LastRunTime" = $_.LastRunTime
"NextRunTime" = $_.NextRunTime
"Actions" = ($xml.Task.Actions.Exec | % { "$($_.Command) $($_.Arguments)" }) -join "`n"
}
}
# Get tasks from subfolders
$schedule.GetFolder($path).GetFolders(0) | % {
$out += getTasks($_.Path)
}
#Output
$out
}
$tasks = #()
$schedule = New-Object -ComObject "Schedule.Service"
$schedule.Connect()
# Start inventory
$tasks += getTasks("\")
# Close com
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($schedule) | Out-Null
Remove-Variable schedule
# Output all tasks
$tasks
Ex. of output
PS > .\Untitled1.ps1 | ? { $_.Name -eq "test" }
Actions : notepad.exe c:\test.txt
calc.exe
Path : \test
Name : test
LastRunTime : 30.12.1899 00:00:00
NextRunTime : 17.03.2013 13:36:38
Get the PowerShellPack from the W7 RK, and try get-scheduledtask
http://archive.msdn.microsoft.com/PowerShellPack
Excerpt From MSDN:
The Windows 7 Resource Kit PowerShell Pack contains 10 modules to do all sorts of interesting things with PowerShell. Import-Module PowerShellPack actually imports 10 modules for you to use. Here’s a brief overview of each of the modules.
WPK Create rich user interfaces quick and easily from Windows PowerShell. Think HTA, but easy. Over 600 scripts to help you build quick user interfaces
TaskScheduler List scheduled tasks, create or delete tasks
FileSystem Monitor files and folders, check for duplicate files, and check disk space
IsePack Supercharge your scripting in the Integrated Scripting Environment with over 35 shortcuts
DotNet Explore loaded types, find commands that can work with a type, and explore how you can use PowerShell, DotNet and COM together
PSImageTools Convert, rotate, scale, and crop images and get image metadata
PSRSS Harness the FeedStore from PowerShell
PSSystemTools Get Operating System or Hardware Information
PSUserTools Get the users on a system, check for elevation, and start-processaadministrator
PSCodeGen Generates PowerShell scripts, C# code, and P/Invoke
Another way would be a script I wrote called Get-ScheduledTask.ps1, available in this article:
How-To: Use PowerShell to Report on Scheduled Tasks
In this way you only need this single script and you don't need to download or install anything else.
Bill
I know I'm late to the party, but the answer provided by #Frode F., while it works, is technically not correct.
You can access items of the Actions collection of a scheduled task via PowerShell, it's just not immediately obvious. I had to figure this out myself today as well.
Here's the code to do this all in PowerShell, without having to muck around with XML:
# I'm assuming that you have a scheduled task object in the variable $task:
$taskAction = $task.Definition.Actions.Item.Invoke(1) # Collections are 1-based
That's all there is to getting a single item out of the collection without using foreach.
Because the Actions property is a collection which contains a parameterized property Item (e.g. in C# you would write myTask.Actions[0] or in VB myTask.Actions.Item(1)), PowerShell represents the Item property as a PSParameterizedProperty object. To call the methods associated with the property, you use the Invoke method (for the getter) and InvokeSet method (for the setter).
I ran a quick test running the OP's code and it worked for me (I'm running PowerShell 4.0, however, so maybe that has something to do with it):
$schedule = new-object -com("Schedule.Service")
$schedule.connect()
$tasks = $schedule.getfolder("\").gettasks(0)
$tasks | select Name, LastRunTime
foreach ($t in $tasks)
{
foreach ($a in $t.Actions)
{
Write-Host "Task Action Path: $($a.Path)" # This worked
Write-Host "Task Action Working Dir: $($a.workingDirectory)" # This also worked
}
$firstAction = $t.Actions.Item.Invoke(1)
Write-Host "1st Action Path: $($firstAction.Path)"
Write-Host "1st Action Working Dir: $($firstAction.WorkingDirectory)"
}
HTH.
here a quick one based on: https://blogs.technet.microsoft.com/heyscriptingguy/2015/01/17/weekend-scripter-use-powershell-to-document-scheduled-tasks/
Uses Powershell: Get-ScheduledTask and Get-ScheduledTaskInfo
### run like >> Invoke-Command -ComputerName localhost, server1, server2 -FilePath C:\tmp\Get_WinTasks.ps1
$taskPath = "\"
$outcsv = "c:\$env:COMPUTERNAME-WinSchTaskDef.csv"
Get-ScheduledTask -TaskPath $taskPath |
ForEach-Object { [pscustomobject]#{
Server = $env:COMPUTERNAME
Name = $_.TaskName
Path = $_.TaskPath
Description = $_.Description
Author = $_.Author
RunAsUser = $_.Principal.userid
LastRunTime = $(($_ | Get-ScheduledTaskInfo).LastRunTime)
LastResult = $(($_ | Get-ScheduledTaskInfo).LastTaskResult)
NextRun = $(($_ | Get-ScheduledTaskInfo).NextRunTime)
Status = $_.State
Command = $_.Actions.execute
Arguments = $_.Actions.Arguments }} |
Export-Csv -Path $outcsv -NoTypeInformation