I have the below stream in clearcase
[tthangavel#wtl-lbuild-4 fw]$ c lsstream
2016-05-23T03:32:31-04:00 my_stream_name user1
How do I check when was the stream last updated?
A view is updated, a stream is rebased.
You can check the minor events associated to its history (cleartool lshistory):
cleartool lshist -min stream:tcp_540_svcommon#\mypvob
(replace mypvob by the PVob or project vob of that stream, note: /vobs/mypvob on Unix \mypvob on Windows)
If that doesn't work, all you can do is check the date of the foundation baselines (using fmt_ccase):
cleartool descr -fmt "%[found_bls]CXp" stream:tcp_540_svcommon#\mypvob
For each baseline, check its date: the most recent is the last rebase.
The lshist -minor will tell you, if the data has not been scrubbed. But it's not pretty. lshistory -minor will tell you everything involved with the rebase, including removing and recreating the baseline hyperlinks.
Here is the lshistory -minor output of a new rebase:
C:\Users\bcowan.DEV>cleartool lshist -min stream:bcowan_Test_Project_mid#\projects
--08-29T16:02 bcowan set process variable on activity "bcowan_Test_Project_mid"
"Set activity process variable named "UCM_REBASE_MISC"."
--08-29T16:02 bcowan set process variable on activity "bcowan_Test_Project_mid"
"Set activity process variable named "UCM_REBASE"."
--08-29T16:02 bcowan change stream "bcowan_Test_Project_mid"
"Updated config_spec.
Regenerated config spec"
--08-29T16:02 bcowan set process variable on activity "bcowan_Test_Project_mid"
"Set activity process variable named "SUM_CSPEC_ID"."
--08-29T16:02 bcowan make hyperlink "UseBaseline" on activity "bcowan_Test_Project_mid"
"Attached hyperlink "UseBaseline#22347#\projects"."
--08-29T16:02 bcowan remove hyperlink "UseBaseline" from activity "bcowan_Test_Project_mid"
"Removed hyperlink "UseBaseline#562#\projects"."
--08-29T16:02 bcowan set process variable on activity "bcowan_Test_Project_mid"
"Set activity process variable named "UCM_REBASE"."
--08-29T16:02 bcowan set process variable on activity "bcowan_Test_Project_mid"
"Set activity process variable named "UCM_REBASE"."
--08-29T16:02 bcowan set process variable on activity "bcowan_Test_Project_mid"
"Set activity process variable named "UCM_REBASE"."
--08-29T16:02 bcowan set process variable on activity "bcowan_Test_Project_mid"
"Set activity process variable named "UCM_REBASE"."
--08-29T16:02 bcowan set process variable on activity "bcowan_Test_Project_mid"
"Set activity process variable named "UCM_REBASE"."
--08-29T16:02 bcowan set process variable on activity "bcowan_Test_Project_mid"
"Set activity process variable named "UCM_REBASE"."
--08-29T16:02 bcowan set process variable on activity "bcowan_Test_Project_mid"
"Set activity process variable named "UCM_REBASE"."
--08-29T16:02 bcowan set process variable on activity "bcowan_Test_Project_mid"
"Set activity process variable named "UCM_REBASE"."
--08-29T16:02 bcowan set process variable on activity "bcowan_Test_Project_mid"
"Set activity process variable named "UCM_REBASE_MISC"."
--08-29T16:02 bcowan set process variable on activity "bcowan_Test_Project_mid"
"Set activity process variable named "UCM_REBASE"."
This is a SINGLE component update rebase.
How long this data stays in the VOB is controlled by the vob_scrubber_params file (see the "vob_scrubber" man page). The default is to keep all this event data for up to 7 days, and the last on a given stream for 30 days.
Related
I have a small form I'm working on but I have something I'm confused about. I have a closing event
$Form.Add_Closing({}) In there I'm wanting to stop a custom logging module but it doesn't reflect the output to the console, same if I use write-output. If I use Write-Host though, that reflects to the console. Does the Closing event just have any real output capability?
$Form.Add_Closing({
# my logging function - doesn't work
Write-Log -Stop
# Write-Output - doesn't work
Write-Output 'Test message'
# Write-Host - does work
Write-Host 'Another Test message'
})
The problem applies to all events, not just Closing:
Inside a PowerShell script block serving as a .NET event delegate:
You can call arbitrary commands...
... but their success-stream (pipeline) output is discarded.
However, output to any of PowerShell's other output streams does surface in the caller's console, as you've experienced with Write-Host.
Therefore, if you simply want to print the called commands' success output to the caller's display, you can pipe them to Out-Host:
$Form.Add_Closing({
Write-Log -Stop | Out-Host
})
Note:
Out-Host's output - unlike Write-Host's - can fundamentally neither be captured nor suppressed.
Output from Write-Host, which since v5 writes via the information stream, can be suppressed with 6>$null, and in principle be captured via the common -InformationVariable parameter, if your script is an advanced script and it is invoked with, say, ./yourScript -InformationVariable capturedInfoStream.
However, this does not work with Write-Host calls made inside event-delegate script blocks.
If you want to collect success output emitted from event-delegate script blocks for later use in the script (which also allows you to control if the collected output is sent to the script's caller or not), create a list in the script scope, to which you can append from the event-delegate script blocks:
# Initialize a list to collect event-delegate output in.
$outputFromEventDelegates = [Collections.Generic.List[object]] #()
# ...
$Form.Add_Closing({
# Call the function of interest and add its output to the
# script-scope list.
$outputFromEventDelegates.AddRange(
#(Write-Log -Stop)
)
})
# ... after the .ShowDialog() call
# Now you can access all collected output.
Write-Verbose -Verbose "Output collected from event delegates:"
$outputFromEventDelegates
So I have a powershell script, mainly taken from a similar question here, that can detect when a certain type of file is added to a certain network and send emails when this happens:
Function Watcher{
param ($folder, $filter, $to, $Subject)
$watcher = New-Object IO.FileSystemWatcher $folder, $filter -Property #{
IncludeSubdirectories = $true
EnableRaisingEvents = $true
}
$changeAction = [scriptblock]::Create('
$path = $Event.SourceEventArgs.FullPath
$name = $Event.SourceEventArgs.Name
$changeType = $Event.SourceEventArgs.ChangeType
$timeStamp = $Event.TimeGenerated
Write-Host "The file $name was $changeType at $timeStamp"
$Body = "The file $name was $changeType at $timeStamp"
Email $to $Subject $Body
')
Register-ObjectEvent $Watcher -EventName "Created" -Action $changeAction
}
However, I want to modify this such that it can be useful for this application: right now there is a tool adding data (.datx files) to the network (several files per minute) and I would like to receive email notification the moment that the data is done being recorded. How can I most easily modify this such that when the initial watcher is triggered, it waits to see if it happens again and resets if so, but then continues if not? Or would creating a whole new script be best? Basically, how can I make the watcher activated by a lone .datx file being uploaded to the network, but not have it triggered by a stream of them (except for the very last one)
You can use the following batching approach:
Define the length of a sliding time window that resets if a new file is created within it; keep collecting events while ones arrive within that sliding window.
To prevent the collection from growing indefinitely, define a maximum batch size at which a batch is processed, even if further events are pending.
Once the time window elapses without new events having arrived, process the batch at hand, i.e., the events collected so far, then start a new batch.
Caveat:
The System.IO.FileSystemWatcher class can report duplicate events.
The code below eliminates duplicates in a given batch, but not across batches, which would require quite a bit more effort - see the source-code comments.
Implementation notes:
Instead of using an -Action script block passed to Register-ObjectEvent to process the events, they are processed synchronously - with a timeout - in a Wait-Event loop.
Wait-Event uses PowerShell's event queue and therefore usually doesn't miss events (although that can happen at the .NET level in high-volume situations); by contrast, the FileSystemWatcher's similar WaitForChanged method does not queue events and only reports a - single - event, if one happens to arrive while the method waits.
try {
# Specify the target folder: the system's temp folder in this example.
$dir = (Get-Item -EA Ignore temp:).FullName; if (-not $dir) { $dir = $env:TEMP }
# Create and initialize the watcher.
# Note the [ordered] to ensure that .EnableRaisingEvents is set last.
$watcher = [System.IO.FileSystemWatcher] [ordered] #{
Filter = '*.datx'
Path = $dir
EnableRaisingEvents = $true
}
# To simulate file creation, create *.datx files in the folder printed
# mentioned in the following status message.
Write-Host "Watching $dir for creation of $($watcher.Filter) files..."
# Register for (subscribe to) creation events:
# Determine a unique event-source ID...
[string] $sourceId = New-Guid
# ... and register for the watcher's Created event with it.
Register-ObjectEvent $watcher -EventName Created -SourceIdentifier $sourceId
# Initialize the ordered hashtable that collects all file names for a single
# batch.
# Note: Since any given file creation can trigger *multiple* events, we
# use an ordered hashtable (dictionary) to ensure that each file is
# only reported once.
# However, *across batches* duplicates can still occur - see below.
$batch = [ordered] #{}
# Determine the sliding time window during which newly created files are
# considered part of a single batch.
# That is, once a file has been created, each additional file created
# within that time window relative to previous file becomes part of the
# same batch.
# When a time window elapses without a new file having been created, the
# batch is considered complete and processed - see max. batch-size exception
# below.
# IMPORTANT:
# * The granularity is *seconds*, so the time window must be at least 1 sec.
# * Seemingly independently of the length of this window, duplicate events
# are likely to occur across batches the less time has elapsed between
# the end of a batch and the start of a new one - see below.
$batchTimeWindowSecs = 5
# How many names to allow a batch to contain at most, even if more
# files keep getting created in the sliding time window.
$maxBatchSize = 100
while ($true) {
# Run indefinitely; use Ctrl-C to exit.
# Wait for events in a sliding time window of $batchTimeWindowSecs length.
# Note: Using Wait-Event in a loop (1 event per iteration) is *more*
# predictable than the multi-event collecting Get-Event in terms of
# avoiding duplicates, but duplicates do still occur.
$batch.Clear()
while ($evt = Wait-Event -SourceIdentifier $sourceId -Timeout $batchTimeWindowSecs) {
$evt | Remove-Event # By default, events linger in the queue; they must be removed manually.
# Add the new file's name to the batch (unless already present)
# IMPORTANT:
# * Duplicates can occur both in a single batch and across batches.
# * To truly weed out all duplicates, you'd have to create a session-level
# dictionary of the files' names and their creation timestamps.
# With high-volume file creation, this session-level dictionary could
# grow large; periodic removal of obsolete entries would help.
$batch[$evt.SourceArgs.Name] = $null # dummy value; it is the *keys* that matter.
Write-Host ✔ -NoNewline # status output: signal that a new file was created
# If the max. batch size has been reached, submit the batch now, even if further
# events are pending within the timeout window.
if ($batch.Count -ge $maxBatchSize) {
Write-Warning "Max. batch size of $maxBatchSize reached; force-submitting batch."
break
}
}
# Completed batch available?
if ($batch.Count) {
# Simulate processing the batch.
Write-Host "`nBatch complete: Sending email for the following $($batch.Count) files:`n$($batch.Keys -join "`n")" #`
# Start a new batch.
$batch.Clear()
}
else {
Write-Host . -NoNewline # status output: signal that no new files were created in the most recent time window.
}
}
}
finally {
# Clean up:
# Unregister the event subscription.
Unregister-Event -SourceIdentifier $sourceId
# Dispose of the watcher.
$watcher.Dispose()
}
Sample output from creating a batch of 3 files first, then another with 5:
Watching C:\Users\jdoe\AppData\Local\Temp for creation of *.datx files...
............✔✔✔
Batch complete: Sending email for the following 3 files:
1.datx
2.datx
3.datx
.✔✔✔✔✔
Batch complete: Sending email for the following 5 files:
4.datx
5.datx
6.datx
7.datx
8.datx
....................
What is the fundamental difference between these two commands?
$myVar = & "notepad.exe"
and
& "notepad.exe" | Set-Variable "myVar"
With the first one, the command returns immediately without waiting for the exe to terminate, which was not what I expected.
With the second one (or anything else with pipeline, such as | Out-File or | Set-Content), the command waits properly for the exe to write a result in stdout and terminate.
Pipeline is nothing but taking the Output from the first set and passing it as an input to the second one. Pipelines act like a series of connected segments of pipe. Items moving along the pipeline must pass through each segment.
In your case, Powershell is actually waiting in both the cases. but if you use Measure-Command, there is a difference in execution time which is better in case of $myVar = & "C:\path to\program.exe" $argument
I am trying to print a PDF as XPS, the script opens the PDF Print Output As screen and enters the correct name before sending the ENTER command to the window to save the file.
How can I select the address bar to enter the desired path? Or how can I change the default save path?
EDIT: Thank you for the feedback. Here is the script:
function print_files($secure_pdf_dir){
#Retrieves the name for the .xps files
Get-ChildItem $secure_pdf_dir -Filter *.pdf -Recurse | Foreach-Object {
#For each .pdf file in that directory, continue
same_time $_.FullName
}
}
## The following function keeps checking for a new window called "Save Print Output As"
## When the window shows up, it enters the name of the file and press ENTER
function enter_my_names($xps_dir, $fullname){
$wshell = New-Object -ComObject wscript.shell;
while($wshell.AppActivate('Save Print Output As') -ne $true){
$wshell.AppActivate('Save Print Output As')
}
$basename = [io.path]::GetFileNameWithoutExtension($fullname)
#This is where the name is actually entered
$wshell.SendKeys($xps_dir\$basename)
$wshell.SendKeys("{ENTER}")
}
## The following function launches simultaneously a print job on the input file
## and a function waiting for the print job to show up to name the file
workflow same_time{
Param(
$fullname
)
parallel{
Start-Process -FilePath $fullname –Verb Print -PassThru
enter_my_names $xps_dir $fullname
}
}
#MAIN PROGRAM
#Here the script saves your current printer as default
$defprinter = Get-WmiObject -Query "Select * from Win32_Printer Where Default=$true"
#Queries for a XPS printer
$printer = Get-WmiObject -Query "Select * from Win32_Printer Where Name='Microsoft XPS Document Writer'"
#Sets the XPS printer as Default
$printer.SetDefaultPrinter()
#Starts the main job
print_files($secure_pdf_dir)
#Sets the old default printer back as default again
$defprinter.SetDefaultPrinter()
#This is a small delay to be sure everything is completed before closing Adobe Reader. You can probably shorten it a bit
sleep 2
#Finally, close Adobe Reader
Get-Process "acrord32" | Stop-Process
It seems that the $xps_dir variable is not being passed into the function properly.
Edit: Error I get when trying to add $xps_dir to the enter_my_names function:
Microsoft.PowerShell.Utility\Write-Error : Cannot validate argument on parameter
'FilePath'. The argument is null or empty. Provide an argument that is not null or
empty, and then try the command again.
At same_time:115 char:115
+
+ CategoryInfo : NotSpecified: (:) [Write-Error], ParameterBindingValidati
onException
+ FullyQualifiedErrorId : System.Management.Automation.ParameterBindingValidationEx
ception,Microsoft.PowerShell.Commands.WriteErrorCommand
+ PSComputerName : [localhost]
I'm not sure if you got this fully worked out or I misread your post, but I was able to implement some code from your initial post to finish my project [been beating my head against a wall as a non-traditional comp sci person]; so I wanted to share some things I did in hopes of helping you (in the event you're still at that crossroads).
Some points of interest:
-My overall process is a bulk report generator. A variable amount of .XML stylesheets are sent to IE because a javascript subroutine numbers the reports; to accomplish this I have visual basic doing some database parsing, passing values into custom scripts needed to form the .XML stylesheets, then VB creates PS .ps1 files with the various PS commands needed to create the IE com object. Finally, VB calls the .ps1 scripts, and the reports are generated by sending the stylesheet to IE, waiting for HTML render, send print command, and close the object.
-While your endgoal is to generate an XPS, mine was to fully render an HTML, then print it with a PDF printer; I assume we have a similar process in that we must engage a dialog box in the intermediate stage (in this case, using sendkeys to interact with it); this is specifically what I'm going to discuss below in hopes of helping out!
So, two points of discussion:
First, more of a general observation/query: I don't see where your $xps_dir variable is actually being defined; I mention this because there could be a string-related issue with the values being passed by the $xps_dir. One way to check your string to make sure its 'pretty' is to pass it to a .txt or something using the OUT-FILE command:
"$xps_dir" | Out-File -FilePath "C:\somefolder\sometext.txt" -Append
The text file itself doesn't need to exist, but the file does...the above command will create the text file.
Also, if you're ok with viewing the powershell prompt, a WRITE-HOST can be used.
Either way, I'm wondering if the final compiled string isn't compiled correctly, so its not recognizing it as a directory.
I think what more likely is happening is the SENDKEYS aren't being sent to the correct fields. For example, by using your code I was [FINALLY] able to set my 'Save As' dialog box as an object and interact with it. (When using my PDF printer, I get the 'Save As' dialog box).
At first, I tried to send the file name, then send enter. I assumed this would be fine, because during manual interaction the focus for the 'Save As' dialog box goes to the 'File Name' field; however, after trying:
$wshell.SendKeys($myfilename)
$wshell.SendKeys("{ENTER}")
I realized the SendKeys command was sending the keys to the 'Save in' drop down (or probably the first element of the Save As dialog box). So, I manually click inside of the 'Save in' field, then tabbed around until I got to 1. 'File Name' (wrote the # of tabs down), and 2. the 'Save' button (wrote # of tabs down). By adding SendKeys("{TAB}") to correspond with the number of tabs I observed, I was able to successfully enter my name string and close out the print dialog box:
$wshell.SendKeys("{TAB}")
$wshell.SendKeys("{TAB}")
$wshell.SendKeys("{TAB}")
$wshell.SendKeys("{TAB}")
$wshell.SendKeys("{TAB}")
$wshell.SendKeys($myfilename)
$wshell.SendKeys("{TAB}")
$wshell.SendKeys("{TAB}")
$wshell.SendKeys("{ENTER}")
NOTE: the number of tabs might be different for your dialog box, so I strongly recommend doing a manual run through to count how many tabs get you to the field you want to interact with.
In conclusion, I have one reflection for consideration:
I've used (to much success) VB and PS to use html elements to dynamically enhance my routines. Since we're able to set the dialog box as a Com object, my next goal will be to try to tap into the respective 'elements', similar to how html elements can be accessed (or more generally, object-oriented language allows). This way, I might be able to better interact with the dialog box without suffering the drawbacks of SendKeys:
Has to run as active process; user cannot engage any other windows else keys might be sent to them;
Keys are based on a count; any variation to that count will require the subroutine to be updated/edited, making it not elastic;
Also, I have not done any work regarding error windows, but one I've already noticed is the "your document has the same name blah blah", so just a heads up.
Even though we're doing two different things, here's my final code for this part of my routine in case it helps provide context:
#send command to internet explorer application with execWB; 6 for print, 2 for no user prompt on window
while ( $ie.busy ) { Start-Sleep -second 3 }
$ie.execWB(6,2)
#create dialog box object
$wshell = New-Object -ComObject wscript.shell;
while($wshell.AppActivate('Save As') -ne $true){ Start-Sleep -second 3 }{
$wshell.AppActivate('Save As')
}
#create file string from 3 strings: directory,basename returned, file extension
#the return from my output log is: "c:\test_folder\mybasenamestring.PDF"
$mydirectory = "c:\test_folder\"
$mybasename = [io.path]::GetFileNameWithoutExtension($fullname)
$myextension = ".PDF"
$myfilename = "$mydirectory$mybasename$myextension"
#Using tabs to navigate around the dialog window; send my string to the 'File Name' field, then tab to 'Save' and send enter
#This is where the name is actually entered
$wshell.SendKeys("{TAB}")
$wshell.SendKeys("{TAB}")
$wshell.SendKeys("{TAB}")
$wshell.SendKeys("{TAB}")
$wshell.SendKeys("{TAB}")
$wshell.SendKeys($myfilename)
$wshell.SendKeys("{TAB}")
$wshell.SendKeys("{TAB}")
$wshell.SendKeys("{ENTER}")
#going to add a command to report on the file size of the pdf; the pdf will stay 0kb until its fully generated. Once fully generated will add the $ie.quit or the kill command here for the $ie object
#this sends a stop process command to kill powershell since I'm running it as a ps1 file and it will remain open otherwise
stop-process -Id $PID
Last thing: I observed some weirdness with the capitalization, so I updated the final SendKeys to capitalize the string since I want all caps anyhow:
$wshell.SendKeys($myfilename.toupper())
Hope this helps! Thanks for posting; I was finally able to complete my entire process. As I clean and improve, if I find improvements for this area I'll try to remember to share. Thanks for your help!
Pass the variable containing the desired directory ($xps_dir in this case) to each function in the process until it gets to the enter_my_names function where it can then be sent to the window with the $wshell.SendKeys("$xps_dir\$basename").
function print_files($xps_dir, $secure_pdf_dir){
#Retrieves the name for the .xps files
Get-ChildItem $secure_pdf_dir -Filter *.pdf -Recurse | Foreach-Object {
#For each .pdf file in that directory, continue
same_time $xps_dir $_.FullName
}
}
## The following function keeps checking for a new window called "Save Print Output As"
## When the window shows up, it enters the name of the file and press ENTER
function enter_my_names{
param ($xps_dir, $fullname)
$wshell = New-Object -ComObject wscript.shell;
while($wshell.AppActivate('Save Print Output As') -ne $true){
$wshell.AppActivate('Save Print Output As')
}
$basename = [io.path]::GetFileNameWithoutExtension($fullname)
#This is where the name is actually entered
$wshell.SendKeys("$xps_dir\$basename")
$wshell.SendKeys("{ENTER}")
}
## The following function launches simultaneously a print job on the input file
## and a function waiting for the print job to show up to name the file
workflow same_time{
Param(
$xps_dir, $fullname
)
parallel{
Start-Process -FilePath $fullname –Verb Print -PassThru
enter_my_names $xps_dir $fullname
}
}
#MAIN PROGRAM
#Here the script saves your current printer as default
$defprinter = Get-WmiObject -Query "Select * from Win32_Printer Where Default=$true"
#Queries for a XPS printer
$printer = Get-WmiObject -Query "Select * from Win32_Printer Where Name='Microsoft XPS Document Writer'"
#Sets the XPS printer as Default
$printer.SetDefaultPrinter()
#Starts the main job
print_files $xps_dir $secure_pdf_dir
#Sets the old default printer back as default again
$defprinter.SetDefaultPrinter()
#This is a small delay to be sure everything is completed before closing Adobe Reader. You can probably shorten it a bit
sleep 2
#Finally, close Adobe Reader
Get-Process "acrord32" | Stop-Process
The file dialogue will accept a path in the file name field, so instead of sending the filename file.pdf send the full path to the file C:\folder\folder\file.pdf
EDIT:
You can send the folder path like so:
$wshell.SendKeys($xps_dir)
$wshell.SendKeys("{ENTER}")
$wshell.SendKeys($basename)
$wshell.SendKeys("{ENTER}")
In other words how can I get the command line of the script itself?
So, I know about $PSBoundParameters, but it is not the same. I just want to get the string containing the passed in parameters as is.
How do I do it?
See get-help about_Automatic_Variables.
$Args
Contains an array of the undeclared parameters and/or parameter
values that are passed to a function, script, or script block.
When you create a function, you can declare the parameters by using the
param keyword or by adding a comma-separated list of parameters in
parentheses after the function name.
In an event action, the $Args variable contains objects that represent
the event arguments of the event that is being processed. This variable
is populated only within the Action block of an event registration
command. The value of this variable can also be found in the SourceArgs
property of the PSEventArgs object (System.Management.Automation.PSEventArgs)
that Get-Event returns.
Example:
test.ps1
param (
)
Write-Output "Args:"
$args
Output:
PS L:\test> .\test.ps1 foo bar, 'this is extra'
Args:
foo
bar
this is extra
$MyInvocation.Line
Read about_Automatic_Variables:
$MyInvocation
Contains an information about the current command, such as the name,
parameters, parameter values, and information about how the command was
started, called, or "invoked," such as the name of the script that called
the current command.
$MyInvocation is populated only for scripts, function, and script blocks.
just want to get the string containing the passed in parameters as is.
You're looking for a powershell equivalent of "$#", not $*.
And the other answers in the thread are not equivalent. The best quick way I have found for this is:
$args | join-string -sep ' '
which can in turn be used for any string array you may have on hand, not just the $args array.