CreoLauncher/CreoLauncher.ps1
2021-09-01 21:03:50 +03:00

575 lines
24 KiB
PowerShell
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# todo: Убрать автовыбор нескольких базовых лицензий
Add-Type -AssemblyName "PresentationFramework"
Add-Type -AssemblyName "System.Windows.Forms"
Add-Type -AssemblyName "System.Drawing"
<#
# Глобальные объекты необходимы для метода-заглушки CreoLaunching.LicenseUserRestrict($user).
# Где:
#
# $tableLicenseName - таблица дополнительных модулей: Код = Наименование
# $tableLicenseBase - таблица базовых модулей: Код = Наименование
# $tableLicenseServ - таблица серверов лицензий: Псевдоним = Порт@Адрес
# $tableLicenseLink - таблица ссылок на описание дополнительных модулей: Наименование = Ссылка
#
# При настоящей реализации получения списка ограничений для пользователя в методе CreoLaunching.LicenseUserRestrict($user)
# глобальные объекты и файл с таблицами могут быть удалены.
#>
$Global:tableLicenseName = New-Object HashtableMods -ArgumentList '.\CreoLauncher.txt', 'tableLicenseName'
$Global:tableLicenseLink = New-Object HashtableMods -ArgumentList '.\CreoLauncher.txt', 'tableLicenseLink'
$Global:tableLicenseBase = New-Object HashtableMods -ArgumentList '.\CreoLauncher.txt', 'tableLicenseBase'
$Global:tableLicenseServ = New-Object HashtableMods -ArgumentList '.\CreoLauncher.txt', 'tableLicenseServ'
<#
# Объекты выполняют роль конфигурации.
# Добавление/удаление записей таблиц, а также изменение содержимого записей, повлияет на логику выполнения.
#>
$creoPackageSpecs = New-Object CreoParamSpec @{
'CreoDir' = "$env:ProgramFiles\PTC\Creo*\Parametric\bin"
'CreoVer' = "0.0.0.0"
'CreoExe' = "parametric.exe"
'CreoPsf' = "\Parametric\bin\parametric.psf"
'CreoLnk' = "$env:ProgramData\Microsoft\Windows\Start Menu\Programs\PTC"
'CreoIco' = "\Parametric\install\nt\creologo.ico"
'LicExe' = "\Common Files\x86e_win64\obj\plpf_status.exe"
'LicRes' = "\Common Files\text\licensing\license.res"
'RegExpCreoVer' = "\d.\d.\d.\d"
'RegExpLicense' = "^\s+(?<License>\S+)\s+(?<InUse>\d+)\s+(?<Free>\d+)"
'EnvLicense' = "PTC_D_LICENSE_FILE"
'EnvLicsRes' = "PRO_LICENSE_RES"
'EnvFeature' = "CREOPMA_FEATURE_NAME"
'EnvDescPsf' = "DESC"
}
$tableMessageENUS = New-Object HashtableMods @{
'MsgSelectInvite' = 'Select the required modules'
'MsgSelectAvaile' = 'Available'
'MsgWinHeadError' = 'ERROR!'
'MsgErrCreoParam' = 'Not found Creo Parametric or its components on this computer'
'MsgRunCreoParam' = 'Start Creo Parametric'
'MsgRunPTCStatus' = 'Show license status'
}
$tableMessageRURU = New-Object HashtableMods @{
'MsgSelectInvite' = 'Выберите необходимые модули'
'MsgSelectAvaile' = 'Доступно'
'MsgWinHeadError' = 'ОШИБКА!'
'MsgErrCreoParam' = 'Не найден Creo Parametric или его компоненты на этом компьютере'
'MsgRunCreoParam' = 'Запуск Creo Parametric'
'MsgRunPTCStatus' = 'Отобразить все лицензии'
}
class ExecuteObject {
[System.Object] hidden $info
[System.Object] hidden $proc
ExecuteObject([System.String]$execPath, [System.String]$execArgs){
$this.info = New-Object System.Diagnostics.ProcessStartInfo
$this.info.FileName = $execPath
$this.info.Arguments = $execArgs
$this.info.RedirectStandardError = $true
$this.info.RedirectStandardOutput = $true
$this.info.UseShellExecute = $false
$this.info.WindowStyle = 'Hidden'
$this.info.CreateNoWindow = $true
}
[PSCustomObject] Start(){
$this.proc = New-Object System.Diagnostics.Process
Try{
$this.proc.StartInfo = $this.info
$this.proc.Start() | Out-Null
Return [PSCustomObject]@{
stdout = $this.proc.StandardOutput.ReadToEnd()
stderr = $this.proc.StandardError.ReadToEnd()
ExitCode = $this.proc.ExitCode
}
}
Catch {
Exit
}
}
}
class HashtableMods {
[System.Collections.Hashtable] $hashtable
HashtableMods ([System.Collections.Hashtable]$table){
$this.hashtable = $table
}
HashtableMods ([System.String]$path, [System.String]$block){
$table = @{}
$save = $false
Foreach ($line in $(Get-Content -Path $path)){
if (($line -match "\[") -and ($line -match "$block")){
$save = $true
}
elseif ($line -match "\["){
$save = $false
}
elseif ($save -and ($line -notmatch "^\s*#") -and ($line -match "=")){
$key = $line.Split("=")[0].Trim()
$val = $($line.Split(";")[0] -replace "$($key)\s*=\s*","").Trim()
try {
$table.Add($key, $val)
}
catch {
$table.Remove($key)
$table.Add($key, $val)
}
}
}
$this.hashtable = $table
}
[System.String] ToString(){
Return $this.ToString($false, $null)
}
[System.String] ToString([System.Boolean]$fromKey){
Return $this.ToString($fromKey, $null)
}
[System.String] ToString([System.Boolean]$fromKey, [System.String]$separator){
$string = ""
Foreach ($key in $this.hashtable.Keys){
if ($FromKey){
$string += $key.ToString()
}
else {
$string += $this.hashtable[$key].ToString()
}
$string += $separator
}
Return $string.TrimEnd($separator)
}
[HashtableMods] Filtrate([System.Boolean]$fromKey, [System.String]$target){
$filtrated = New-Object HashtableMods @{}
if ($FromKey){
Foreach ($element in $($this.hashtable.GetEnumerator() | Where-Object {$_.Key -eq $target})){
$filtrated.hashtable.Add($element.Name,$this.hashtable[$element.Name])
}
}
else {
Foreach ($element in $($this.hashtable.GetEnumerator() | Where-Object {$_.Value -eq $target})){
$filtrated.hashtable.Add($element.Name,$this.hashtable[$element.Name])
}
}
Return $filtrated
}
}
class UserInterface {
[System.Object] hidden $form
[System.Object] hidden $wordsFont
[System.Object] hidden $titleFont
[System.Int32] hidden $wordsSize = 10
[System.Int32] hidden $titleSize = $this.wordsSize * 1.5
[System.Int32] hidden $linesStep = $this.titleSize * 1.5
[System.Int32] hidden $linesNext = 0
[System.Int32] hidden $colmnStep = 0
[System.Int32] hidden $colmnNext = $this.titleSize * 1.5
UserInterface ([System.String]$header){
$this.wordsFont = New-Object System.Drawing.Font("Arial", $this.wordsSize <#, [System.Drawing.FontStyle]::Regular#>)
$this.titleFont = New-Object System.Drawing.Font("Arial", $this.titleSize <#, [System.Drawing.FontStyle]::Bold#>)
$this.form = New-Object System.Windows.Forms.Form
$this.form.AutoScroll = $true
$this.form.AutoSize = $true
$this.form.Text = $header
}
[System.Void] AddIcon ([System.String]$path){
$this.form.Icon = New-Object System.Drawing.Icon $path
}
[System.Void] AddSpaceVertical(){
$this.linesNext += $this.linesStep * 1.5
}
[PSCustomObject] AddTitle([System.String]$text){
$title = New-Object System.Windows.Forms.Label
$title.Location = New-Object System.Drawing.Size($this.colmnNext, $this.linesNext)
$title.Font = $this.titleFont
$title.Text = $text
$title.AutoSize = $true
$this.form.Controls.Add($title)
Return [PSCustomObject]@{
Width = $title.Width
Height = $title.Height
}
}
[PSCustomObject] AddText([System.String]$text){
$txt = New-Object System.Windows.Forms.Label
$txt.Location = New-Object System.Drawing.Size($this.colmnNext, $this.linesNext)
$txt.Font = $this.wordsFont
$txt.Text = $text
$txt.AutoSize = $true
$this.form.Controls.Add($txt)
Return [PSCustomObject]@{
Width = $txt.Width
Height = $txt.Height
}
}
[PSCustomObject] AddLink([System.String]$text, $function){
$lnk = New-Object System.Windows.Forms.LinkLabel
$lnk.Location = New-Object System.Drawing.Size($this.colmnNext, $this.linesNext)
$lnk.add_Click($function)
$lnk.Font = $this.wordsFont
$lnk.LinkColor = "BLUE"
$lnk.ActiveLinkColor = "BLACK"
$lnk.Text = $text
$lnk.AutoSize = $true
$this.form.Controls.Add($lnk)
Return [PSCustomObject]@{
Width = $lnk.Width
Height = $lnk.Height
}
}
[PSCustomObject] AddCheckbox([System.String]$name, [System.String]$text, $function){
$checkbox = New-Object System.Windows.Forms.CheckBox
$checkbox.Location = New-Object System.Drawing.Size($this.colmnNext, $this.linesNext)
$checkbox.Add_Click($function)
$checkbox.Font = $this.wordsFont
$checkbox.Text = $text
$checkbox.Name = $name
$checkbox.AutoSize = $true
$this.form.Controls.Add($checkbox)
Return [PSCustomObject]@{
Width = $checkbox.Width
Height = $checkbox.Height
}
}
[PSCustomObject] AddButton([System.String]$text, $function){
$button = New-Object System.Windows.Forms.Button
$button.Location = New-Object System.Drawing.Size($this.colmnNext, $this.linesNext)
$button.Add_Click($function)
$button.Font = $this.wordsFont
$button.Text = $text
$button.AutoSize = $true
$this.form.Controls.Add($button)
Return [PSCustomObject]@{
Width = $button.Width
Height = $button.Height
}
}
[System.Void] Show(){
$this.form.ShowDialog()
}
[HashtableMods] GetStateCheckbox(){
$state = New-Object HashtableMods @{}
Foreach ($checkbox in $this.form.Controls | Where-Object {$_.GetType() -like 'System.Windows.Forms.CheckBox'}){
$state.hashtable.Add($checkbox.Name, $($checkbox.Checked))
}
Return $state
}
}
class CreoParamSpec {
[System.String] $CreoDir
[System.String] $CreoVer
[System.String] $CreoExe
[System.String] $CreoPsf
[System.String] $CreoLnk
[System.String] $CreoIco
[System.String] $LicExe
[System.String] $LicRes
[System.String] $RegExpCreoVer
[System.String] $RegExpLicense
[System.String] $EnvLicense
[System.String] $EnvLicsRes
[System.String] $EnvFeature
[System.String] $EnvDescPsf
CreoParamSpec ([HashtableMods]$creoSpec){
Try{
$this.SpecToProperty($creoSpec.hashtable)
$this.AdjustProperty()
}
Catch{
$this.CreoDir = $null
$this.CreoVer = $null
$this.CreoExe = $null
$this.CreoPsf = $null
$this.CreoLnk = $null
$this.CreoIco = $null
$this.LicExe = $null
$this.LicRes = $null
$this.RegExpCreoVer = $null
$this.RegExpLicense = $null
$this.EnvLicense = $null
$this.EnvFeature = $null
}
}
[System.Void] hidden SpecToProperty([System.Collections.Hashtable]$table){
$properties = $this | Get-Member -MemberType Properties -Force | Where-Object {$_.Name -notcontains 'pstypenames'}
Foreach ($property in $properties){
if (!$table.ContainsKey($property.Name)){
Write-Host 'SPEC'
$this.RaiseException()
}
else{
$this.$($property.Name) = $table[$property.Name]
}
}
}
[System.Void] hidden AdjustProperty(){
if (!(Test-Path -Path $this.CreoDir -ErrorAction SilentlyContinue)){
$this.RaiseException("Not found CREO DIRECTORY")
}
else{
$found = Get-ChildItem -Path $this.CreoDir -Filter $this.CreoExe -Recurse
Foreach ($result in $found){
if (($result.FullName.ToString() -match $this.RegExpCreoVer) -and ($matches[0] -gt $this.CreoVer)){
$this.CreoVer = $matches[0]
$this.CreoExe = $result.FullName
$this.CreoDir = Split-Path -Path $result.FullName | Split-Path -Parent | Split-Path -Parent
}
}
$this.CreoPsf = $this.CreoDir + $this.CreoPsf
if (!(Test-Path -Path $this.CreoPsf -ErrorAction SilentlyContinue)){
$this.RaiseException("Not found CREO START FILE")
}
$this.LicExe = $this.CreoDir + $this.LicExe
if (!(Test-Path -Path $this.LicExe -ErrorAction SilentlyContinue)){
$this.RaiseException("Not found LICENSE STATUS EXE")
}
$this.LicRes = $this.CreoDir + $this.LicRes
if (!(Test-Path -Path $this.LicRes -ErrorAction SilentlyContinue)){
$this.RaiseException("Not found LICENSE RESOURCES FILE")
}
$this.CreoIco = $this.CreoDir + $this.CreoIco
if (!(Test-Path -Path $this.CreoIco -ErrorAction SilentlyContinue)){
$this.RaiseException("Not found CREO ICON")
}
$WshShell = $(New-Object -comObject WScript.Shell)
$this.CreoLnk = $WshShell.CreateShortcut($this.CreoLnk + "\Creo Parametric $($this.CreoVer).lnk").WorkingDirectory
if (!(Test-Path -Path $this.CreoLnk -ErrorAction SilentlyContinue)){
$this.RaiseException("Not found CREO LINK WITH WORKDIR")
}
}
}
[System.Void] hidden RaiseException($message){
throw $message
}
}
class CreoLaunching : UserInterface {
[System.String] hidden $user
[CreoParamSpec] hidden $creo
[HashtableMods] hidden $mesg
[HashtableMods[]] hidden $licenseRestricts
[HashtableMods] hidden $licenseAvailable
CreoLaunching([CreoParamSpec]$creoSpec, [System.String]$userName, [HashtableMods]$locale) : base("Creo $($creoSpec.CreoVer) Launcher"){
$this.user = $username
$this.creo = $creoSpec
$this.mesg = $locale
$this.AddIcon($this.creo.CreoIco)
$chboxPosX = $this.colmnNext
$buttnPosX = $this.colmnNext
$buttnPosY = $this.linesNext
$element = $this.AddTitle($($this.mesg.hashtable['MsgSelectInvite']))
$this.linesNext += $this.linesStep * 2
if (($sizeX = $element.Width + $this.colmnNext) -gt $this.colmnStep){
$this.colmnStep = $sizeX
}
$servrPosY = $this.linesNext
$this.colmnStep = $chboxPosX
$this.licenseRestricts = $this.LicenseUserRestrict($this.user)
$this.licenseAvailable = $this.LicenseServerStatus($this.licenseRestricts[0], $this.licenseRestricts[1], $this.licenseRestricts[2])
$licenseServ = $this.licenseRestricts[2].hashtable
$licenseName = $this.licenseRestricts[0].hashtable
Foreach ($servKey in $licenseServ.Keys){
$this.colmnNext = $this.colmnStep
$this.linesNext = $servrPosY
$element = $this.AddText($servKey)
$this.linesNext += $element.Height
if (($sizeX = $element.Width + $this.colmnNext) -gt $this.colmnStep){
$this.colmnStep = $sizeX
}
$chboxPosY = $this.linesNext
$linksPosX = $this.colmnNext
Foreach($licKey in $($this.licenseAvailable.hashtable.Keys | Where-Object {$_ -match $servKey})){
$licName = $licKey.Split(':')[1]
if ($licenseName.ContainsKey($licName)){
$licName = $licenseName[$licName]
}
$checkboxText = "$($this.mesg.hashtable['MsgSelectAvaile']) $($this.licenseAvailable.hashtable[$licKey]):"
$element = $this.AddCheckbox($licKey, $checkboxText, {$launcher.ExamCheckboxesState($this, $_)})
$this.linesNext += $this.linesStep * 1.5
if (($sizeX = $element.Width + $this.colmnNext) -gt $this.colmnStep){
$this.colmnStep = $sizeX
}
if (($sizeX = $element.Width + $this.colmnNext) -gt $linksPosX){
$linksPosX = $sizeX
}
}
$this.colmnNext = $linksPosX
$this.linesNext = $chboxPosY
Foreach($licKey in $($this.licenseAvailable.hashtable.Keys | Where-Object {$_ -match $servKey})){
$licName = $licKey.Split(':')[1]
if ($licenseName.ContainsKey($licName)){
$licName = $licenseName[$licName]
}
if ($this.licenseRestricts[3].hashtable.ContainsKey($licName)){
$element = $this.AddLink($licName, {$launcher.OpenLinkExternalApp($this)})
}
else {
$element = $this.AddText($licName)
}
$this.linesNext += $this.linesStep * 1.5
if (($sizeX = $element.Width + $this.colmnNext) -gt $this.colmnStep){
$this.colmnStep = $sizeX
}
}
if ($this.linesNext -gt $buttnPosY){
$buttnPosY = $this.linesNext
}
}
$this.colmnNext = $buttnPosX
$this.linesNext = $buttnPosY
$element = $this.AddButton($($this.mesg.hashtable['MsgRunCreoParam']), {$launcher.StartCreoParametric()})
$this.linesNext += $this.linesStep * 1.5
if (($sizeX = $element.Width + $this.colmnNext) -gt $this.colmnStep){
$this.colmnStep = $sizeX
}
}
[HashtableMods[]] hidden LicenseUserRestrict([System.String]$user){
<#
# Метод является заглушкой и использует глобальные переменные.
# Реализация настоящего запроса списка ограничений пользователя должна возвращать массив объектов HashtableMods.
# Где элементы массива:
# [0] - таблица дополнительных модулей в виде хеш-таблицы (словаря): Код = Наименование
# [1] - таблица базовых модулей в виде хеш-таблицы (словаря): Код = Наименование
# [2] - таблица серверов лицензий в виде хеш-таблицы (словаря): Псевдоним = Порт@Адрес
# [3] - таблица ссылок на описание дополнительных модулей в виде хеш-таблицы (словаря): Наименование = Ссылка
#>
[HashtableMods[]] $restrict = $Global:tableLicenseName, $Global:tableLicenseBase, $Global:tableLicenseServ, $Global:tableLicenseLink
Return $restrict
}
[HashtableMods] hidden LicenseServerStatus([HashtableMods]$licenseName, [HashtableMods]$licenseBase, [HashtableMods]$licenseServ){
$licAvailable = New-Object HashtableMods @{}
$exeArguments = '-a'
if (($licenseBase) -and ($licenseName)){
$exeArguments = '-f ' + $licenseBase.ToString($true, ' ') + ' ' + $licenseName.ToString($true, ' ')
}
Foreach ($servKey in $licenseServ.hashtable.Keys){
Remove-Item -Path Env:$($this.creo.EnvLicsRes) -ErrorAction SilentlyContinue
Set-Item -Path Env:$($this.creo.EnvLicense) -Value $licenseServ.hashtable[$servKey]
$response = $(New-Object ExecuteObject -ArgumentList $this.creo.LicExe, $exeArguments).Start()
Foreach ($line in $response.stdout.Split(@("`r`n", "`r", "`n"), [StringSplitOptions]::None)){
if (($line -match $this.creo.RegExpLicense) -and ($line -notmatch "\(\S+\)")){
$licKey = "$($servKey):$($matches['License'].Replace('*',''))"
$licVal = $matches['Free']
if (!$licAvailable.hashtable.ContainsKey($licKey)){
if ($licVal -gt 0){
$licAvailable.hashtable.Add($LicKey, $licVal)
}
}
else {
$licAvailable.hashtable[$licKey] = [System.String]([System.Int32]$licAvailable.hashtable[$licKey] + [System.Int32]$licVal)
}
}
}
}
Return $licAvailable
}
[System.Void] hidden ExamCheckboxesState($element, $events){
$servKey = $element.Name.Split(':')[0]
$licBase = $this.licenseRestricts[1].ToString($true, '|')
Foreach ($checkbox in $this.form.Controls | Where-Object {$_.GetType() -match 'System.Windows.Forms.CheckBox'}){
if ($checkbox.Name -notmatch $servKey){
$checkbox.Checked = $false
}
elseif ($checkbox.Name -match $servKey -and $checkbox.Name.Split(':')[1] -match "$licBase"){
$checkbox.Checked = $true
}
}
}
[System.String[]] hidden GeneratingStartFile(){
$selectedServer = ""
$selectedBaseLic = ""
$selectedFeature = ""
$checkboxState = $this.GetStateCheckbox().Filtrate($false, 'True')
if ($checkboxState.hashtable.Count -gt 0){
$foreseenBaseLic = $this.licenseRestricts[1].ToString($true, '|')
Foreach ($key in $checkboxState.hashtable.Keys){
$selectedServer = $this.licenseRestricts[2].hashtable[$key.Split(':')[0]]
$checkedFeature = $key.Split(':')[1]
if ($checkedFeature -match $foreseenBaseLic){
$selectedBaseLic += $checkedFeature + ' '
}
else {
$selectedFeature += $checkedFeature + ' '
}
}
$startFileData = Get-Content -Path $this.creo.CreoPsf | Select-String -NotMatch $this.creo.EnvFeature, $this.creo.EnvLicense, $this.creo.EnvDescPsf
$startFileData += "DESC=Creo Parametric ($($this.user))"
$startFileData += "ENV=$($this.creo.EnvLicense)-=$($selectedServer)"
$startFileData += "ENV=$($this.creo.EnvFeature)=$($selectedBaseLic)($($selectedFeature.Trim()))"
Return $startFileData
}
Return Get-Content -Path $this.creo.CreoPsf
}
[System.Void] hidden StartCreoParametric(){
$startFileBack = Get-Content -Path $this.creo.CreoPsf
$startFileData = $this.GeneratingStartFile()
Set-Content -Path $this.creo.CreoPsf -Value $startFileData -Force
Start-Process -FilePath $this.creo.CreoExe -WorkingDirectory $this.creo.CreoLnk
$this.form.Close()
Start-Sleep 60
Set-Content -Path $this.creo.CreoPsf -Value $startFileBack -Force
}
[System.Void] hidden OpenLinkExternalApp($element){
[System.Diagnostics.Process]::Start($this.licenseRestricts[3].hashtable[$element.Text])
}
}
$locale = $tableMessageENUS
if ((Get-Culture).Name -eq 'ru-RU'){
$locale = $tableMessageRURU
}
if ($creoPackageSpecs.CreoExe -ne ''){
$launcher = New-Object CreoLaunching -ArgumentList $creoPackageSpecs, "$env:USERNAME@$env:USERDNSDOMAIN", $locale
$launcher.Show()
}
else {
[System.Windows.MessageBox]::Show($locale.hashtable['MsgErrCreoParam'], $locale.hashtable['MsgWinHeadError'],'OK','Error')
}