How extract two tags from an XML export of schtasks.exe

Hello -

  I need to generate a list of Windows Scheduled tasks on a server.  I need the Registration Date and the Task Name.  If I use:
schtasks /query /xml >c:\temp\tasks.xml
Each task is returned and those two tags are included.

<!-- \test_of_date -->
<Date>


The best option would be able to run that command and only ask for those two tags.  Another option would be to read the resulting file and grab just those two tags.

Any idea how I can do this?  I have investigated the Powershell module PowerScheduledTasks, but it doesn't seem to add any functionality beyond schtasks.exe

Example from the file:

<!-- \test_of_date -->
<?xml version="1.0" encoding="UTF-16"?>
<Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
  <RegistrationInfo>
    <Date>2015-10-15T16:22:22.9464466</Date>
    <Author>WRBTS\mmorris</Author>
  </RegistrationInfo>
  <Triggers>
    <CalendarTrigger>
      <StartBoundary>2015-10-15T16:21:58.3367566</StartBoundary>
      <Enabled>true</Enabled>
      <ScheduleByDay>
        <DaysInterval>1</DaysInterval>
      </ScheduleByDay>
    </CalendarTrigger>
  </Triggers>
  <Principals>
    <Principal id="Author">
      <RunLevel>LeastPrivilege</RunLevel>
      <UserId>WRBTS\mmorris</UserId>
      <LogonType>InteractiveToken</LogonType>
    </Principal>
  </Principals>
  <Settings>
    <MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>
    <DisallowStartIfOnBatteries>true</DisallowStartIfOnBatteries>
    <StopIfGoingOnBatteries>true</StopIfGoingOnBatteries>
    <AllowHardTerminate>true</AllowHardTerminate>
    <StartWhenAvailable>false</StartWhenAvailable>
    <RunOnlyIfNetworkAvailable>false</RunOnlyIfNetworkAvailable>
    <IdleSettings>
      <Duration>PT10M</Duration>
      <WaitTimeout>PT1H</WaitTimeout>
      <StopOnIdleEnd>true</StopOnIdleEnd>
      <RestartOnIdle>false</RestartOnIdle>
    </IdleSettings>
    <AllowStartOnDemand>true</AllowStartOnDemand>
    <Enabled>true</Enabled>
    <Hidden>false</Hidden>
    <RunOnlyIfIdle>false</RunOnlyIfIdle>
    <WakeToRun>false</WakeToRun>
    <ExecutionTimeLimit>P3D</ExecutionTimeLimit>
    <Priority>7</Priority>
  </Settings>
  <Actions Context="Author">
    <ShowMessage>
      <Title>hello world</Title>
      <Body>hello world</Body>
    </ShowMessage>
  </Actions>
</Task>

Open in new window

michelle0436Asked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Bill PrewCommented:
Just passing by, but here's a potential start at getting this info with just powershell.  Try this small script.

Get-ScheduledTask | foreach {
  [xml] $xml = Export-ScheduledTask -TaskName $_.TaskName -TaskPath $_.TaskPath
  $xml.Task.RegistrationInfo | Select Date,URI
}

Open in new window

~bp
0
footechCommented:
Not all tasks have a created date.
The schtasks command needs to be modified slightly for PowerShell to work with it.  You can parse the output directly in memory instead of writing it to a file.
$x = [xml](schtasks /query /xml one)
foreach ( $i in (0..($x.Tasks.Task.Count)) )
{
    If ( ($x.Tasks.Task)[$i].registrationinfo.date )
    {
        New-Object PsObject -Property @{
                                Taskname = "$($x.Tasks.'#comment'[$i])"
                                Date = Get-Date "$(($x.Tasks.task)[$i].RegistrationInfo.Date)"
                                }
    }
}

Open in new window

0
michelle0436Author Commented:
Thank you so much for your assistance!

Bill - I added Author to the Select list.  However I found that a task I built has an entry with the date and author, but the URI field is empty.  Is it possible to get just the task names and not the URI?  I tried substituting TaskName for URI, but the column is empty.

Footech - How could I change your script to report back on all tasks, not just the ones that have a date?  Also - How could I add Author to the output?

Michelle
0
Creating Active Directory Users from a Text File

If your organization has a need to mass-create AD user accounts, watch this video to see how its done without the need for scripting or other unnecessary complexities.

Bill PrewCommented:
Unfortunately it looks like the task name is actually in the first line of the extracted XML, but as a comment.  As a result no approach that loads the XML data and works with it will load the comment.

We could just treat the XML file as a TXT file I guess, and "find" the comment and look for the date, but that could be a bit less dependable.

~bp
0
footechCommented:
Not all tasks have an author property either, and if you look at the XML you'll see that quite a few have the author as what looks like a DLL resource (they all end up being Microsoft Corporation).
$x = [xml](schtasks /query /xml one)
foreach ( $i in (0..($x.Tasks.Task.Count)) )
{
    If ( ($x.Tasks.Task)[$i].registrationinfo.date )
    {
        $date = Get-Date "$(($x.Tasks.task)[$i].RegistrationInfo.Date)"
    }
    Else
    {
        $date = ""
    }
    If ( "$(($x.Tasks.task)[$i].RegistrationInfo.Author)" -match '^\$\(@%' )
    {
        $author = "Microsoft Corporation"
    }
    Else
    {
        $author  = "$(($x.Tasks.task)[$i].RegistrationInfo.Author)"
    }
    New-Object PsObject -Property @{
                            Taskname = "$($x.Tasks.'#comment'[$i])"
                            Date = $date
                            Author = $author
                            }
}

Open in new window

If you need additional info about tasks I'd suggest taking a look at https://gallery.technet.microsoft.com/scriptcenter/Retrieve-Remote-Scheduled-72985b8f to see if it gives you all you want.
0
footechCommented:
Here's a little refinement to the code I posted above.  I found a function that will extract the resource info, so I integrated that into the script.
# by Dr. Tobias Weltner 
# PowerShell Trainings throughout Europe 
# Hungry for a training? Get in touch: tobias.weltner (AT) email.de 
     
function Get-ResourceString { 
    param($path) 
     
    $code = @' 
    [DllImport("user32.dll", EntryPoint="LoadStringW", CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Unicode)] 
    public static extern int LoadString(IntPtr hModule, int resourceID, StringBuilder resourceValue, int len); 
    [DllImport("kernel32.dll", CharSet = CharSet.Unicode, ExactSpelling = true, EntryPoint = "LoadLibraryExW")] 
    public static extern IntPtr LoadLibraryEx(string lpFileName, IntPtr hFile, uint dwFlags); 
    [DllImport("kernel32.dll", ExactSpelling = true)] 
    public static extern int FreeLibrary(IntPtr hModule); 
'@ 
     
    $helper = Add-Type -MemberDefinition $code -Name ResourceStrings -Namespace Win32API -PassThru -UsingNamespace System.Text 
       
    $info = $path -split ','  
    $file = [System.Environment]::ExpandEnvironmentVariables( ($info[0] -replace '@','') ) 
    $id = [Math]::Abs($info[1]) 
     
    [IntPtr]$hMod = $helper::LoadLibraryEx($file, [IntPtr]::Zero, 3) 
    if($hMod -ne [IntPtr]::Zero) { 
        $sb = New-Object System.Text.StringBuilder(1024) 
        if($helper::LoadString($hMod, $id, $sb, $sb.Capacity) -ne 0) { 
            $sb.ToString() 
        } 
        [void]$helper::FreeLibrary($hMod); 
    }  
}


$x = [xml](schtasks /query /xml one)
foreach ( $i in (0..($x.Tasks.Task.Count)) )
{
    If ( ($x.Tasks.Task)[$i].registrationinfo.date )
    {
        $date = Get-Date "$(($x.Tasks.task)[$i].RegistrationInfo.Date)"
    }
    Else
    {
        $date = ""
    }
    If ( "$(($x.Tasks.task)[$i].RegistrationInfo.Author)" -match '^\$\(@%' )
    {
        $author = Get-ResourceString ("$(($x.Tasks.task)[$i].RegistrationInfo.Author)").Trim('$()')
    }
    Else
    {
        $author  = "$(($x.Tasks.task)[$i].RegistrationInfo.Author)"
    }
    New-Object PsObject -Property @{
                            Taskname = ("$($x.Tasks.'#comment'[$i])" -split "\\")[-1]
                            Date = $date
                            Author = $author
                            }
}

Open in new window

0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
younghvCommented:
I've requested that this question be deleted for the following reason:

Not enough information to confirm an answer.
0
footechCommented:
The script posted in https:#a41085464 does everything asked for.  Task Name, Creation Date, and Author are shown for every task where they are available.
0
Bill PrewCommented:
I tend to agree, while we haven't heard from the OP, I feel like the solution that was suggested is useful enough I'd like to see it kept for future reference and use by others.

~bp
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
XML

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.