I built this open-file function in PowerShell for a GUI I wrote that lets you find and open various files on a server. I mainly use it for opening SolidWorks files as read-only, but also for PDF files and it should work for just about any other file if there is a file association for it.
The problem is that sometimes it doesn't work when opening the sldprt files. SolidWorks will either ignore the open file request or it wont open as read-only. I think this is mostly just a solidworks issue as sometimes it wont open files when double clicked on from windows explorer.
Anyway my solution is to set the file attribute to read-only. start a job that opens the file in SolidWorks, and then waits for the SolidWorks process to go idle before removing the read-only attribute. It does this through an event that watches for the job state to change. Since this is running through a GUI it has to be done in the background to prevent the GUI from locking up.
Is there a simpler way to open files as read-only with PowerShell?
I think it might be possible using the SolidWorks .dll files, but they are meant to be loaded in C# or VB-script and I have no idea what i'm doing in either of those languages.
function open-File{
param(
[parameter(Mandatory=$true)]$file,
[bool]$readOnly = $true,
$processName=$null
)
[scriptblock]$openFileScriptBlock = {
param(
$file,
$readOnly,
$processName=$null
)
#initiate variables
$loaded = $false
$file = get-item $file
$processLastCpu = 0
$timeout = 0
if ($readonly -and !$file.isReadOnly){
$file.isReadOnly = $true
#call file with default application
$attempts = 0
while ($true){
try{$startedProcess = start-process "$($file.fullname)" -PassThru; break}
catch{
$attempts++
if ($attempts -eq 3){return "cannot open file: $file, Error:$_"}
}
}
start-sleep -seconds 2
if ($processName){
$processName = $startedProcess.name
if ($processName -eq "SWSHEL~1"){$processName = "SLDWORKS"}
}
#wait until process shows up in the process manager
while ($loaded -eq $false -and $timeout -lt 25 ){
try {
$process = get-process -name $processName -erroraction 'stop'
if ($?){$loaded = $true; $timeout = 0} else {throw}
}catch{start-sleep -milliseconds 200; $timeout++}
}
start-sleep -seconds 2
#wait for process to go idle
while ($process.cpu -ne $processLastCpu -and $timeout -lt 10){
$processLastCpu = $process.cpu
start-sleep -milliseconds 500
$timeout++
}
$file.isreadonly = $false
} else {start-process "$($file.fullname)"}
return ,$file
}
if (!(test-path -path $file)){update-message "File not found: $file"; return}
$openFileJob = start-job -name 'openfile' -scriptblock $openFileScriptBlock -argumentlist $file, $readOnly, $processName
Register-ObjectEvent $OpenFileJob StateChanged -Action {
$jobResult = $sender | receive-job
$sender | remove-job -Force
unregister-event -sourceIdentifier $event.sourceIdentifier
remove-job -name $event.sourceIdentifier -force
try{update-message "opened file $($jobResult.name)"}
catch{update-message $jobResult}
} | out-null
}