设想
两种不同的方法,均在浏览器中打开 URL,当我将它们放入 powershell 中的作业中时,它们会停止工作,但如果我将它们放入类/对象的方法中,它们会停止工作。我验证了作业中的对象正在正确执行,因为它还执行了复制命令,我可以看到结果出现。
代码
这是未放置在对象中的工作代码:
# 5. Start job and execute a method of the object
Start-Job -Name ListStuffOnTable -ScriptBlock {
# attempt 1 opening default browser
$authUrl = "http://superuser.com"
Write-Host "visiting url="$authUrl
(New-Object -com Shell.Application).Open($authUrl)
# attempt 2 opening internet explorer
$ie = new-object -com "InternetExplorer.Application"
$ie.visible = $true
$ie.navigate("http://superuser.com")
}
Write-Host "Created job"
# Give the job 10 seconds to create a list of entries.
Start-Sleep -Milliseconds 10000
Write-Host "Running askSync"
#Run command that starts an infinite loop untill the browser is opened by the job.
wsl /home/testlinuxname/maintenance/./askSync.sh
Write-Host "Running stopjob"
# 6. Stop the job to get the data out.
Get-Job -Name ListStuffOnTable | Stop-Job
# 7. Verify it exists and functions correctly:
Write-Host "`n Deleting job"
# 8. Delete the job for correct bookkeeping:
Get-Job -Name ListStuffOnTable | Remove-Job
为了完整起见,这是不打开对象内部集成的 URL 的代码:
# 5. Start job and execute a method of the object
Start-Job -Name ListStuffOnTable -ScriptBlock {
# 5.1 first write the class
class GCalAccess{
# Properties
[String] $urlSourcePath
[String] $urlDestPath
[String] $urlFilename
[String] $absUrlSourceFilePath
[String] $absUrlDestFilePath
[HardCoded] $hardCoded
[String] $authUrl
[String] $defaultBrowserLocation
[String] $absUrlWinDestFilePath
# constructor
GCalAccess([HardCoded] $hardCoded)
{
$this.hardCoded = $hardCoded
Write-Host $this.hardCoded.getWindowsCurrentPath()
# create the source and destination of the file that containts the url (url.txt)
# it is coppied from inside the wsl to this folder, so that powershell can read it and open the url in browser
$this.urlSourcePath = "/home/"+"testlinuxname"+"/"+$this.hardCoded.getmaintenanceFolderName()+"/"+$this.hardCoded.getGCalSyncFolderName()+"/"
$this.urlDestPath = $this.hardCoded.getLinuxCurrentPath()+"/"
$this.urlFilename = $this.hardCoded.getAuthUrlFilename()
$this.absUrlSourceFilePath=$this.urlSourcePath+$this.urlFilename
$this.absUrlDestFilePath=$this.urlDestPath+$this.urlFilename
$this.absUrlWinDestFilePath = $this.hardCoded.getWindowsCurrentPath()+"/"+$this.urlFilename
Write-Host "WinPath="$this.absUrlWinDestFilePath
Write-Host $this.hardCoded.getWindowsCurrentPath()
Write-Host $this.hardCoded.getLinuxCurrentPath()
Write-Host "Url source file path = "$this.absUrlSourceFilePath
Write-Host "Url destination file path = "$this.absUrlDestFilePath
}
# Infinite loop that Scans the existance of the file
scanUrlFile(){
[boolean] $foundUrl = $false
# first copy the fail, regardless of whether it exists, then check if it is copied:
while(!$foundUrl)
{
$this.copyUrl()
if (Test-Path $this.absUrlWinDestFilePath -PathType leaf)
{
Write-Host "FOUND Url"
#do some stuff
$foundUrl = $true
}
}
# exit
# while(!$this.foundUrl())
# {
# # sleep 0.3 seconds
# Write-Host "Didn't find it yet."
# Start-Sleep -Milliseconds 300
# }
}
# Checks whether url file is found in the wsl
[boolean] foundUrl()
{
# create wsl command that checks whether the file exists
$command = "ls "+$this.absUrlSourceFilePath+" && echo FoundUrlFile"
Write-Host "Command="+$command
$output = bash "-c" $command
# evaluate the output of the command to see if it found (null if not found, ends in "FoundUrlFile" if it is found)
if($output-like "*FoundUrlFile"){
Write-Host "Output="$output"..."
return $true
}else {
return $false
}
}
# copy the file that contains the url
copyUrl() {
# create copy command
Write-Host "pathSource="$this.absUrlSourceFilePath
Write-Host "pathDest="$this.absUrlDestFilePath
[String] $command = "sudo cp "+$this.absUrlSourceFilePath+" `""+$this.absUrlDestFilePath+"`""
$output = bash "-c" $command
Write-Host $output
}
readUrlFromFile(){
$windowsUrlFilePath =$this.hardCoded.getWindowsCurrentPath()+"/"+$this.urlFilename
Write-Host "windowsUrlFilePath="$windowsUrlFilePath
$this.authUrl = Get-Content $windowsUrlFilePath -First 1
}
# open link to prefered browser
openUrlInBrowser(){
Write-Host "visiting url="$this.authUrl
(New-Object -com Shell.Application).Open($this.authUrl)
$ie = new-object -com "InternetExplorer.Application"
$ie.visible = $true
$ie.navigate("http://www.google.com")
}
# deletes the copied file with the authorization url after use
cleanUpWindowsUrlFileCopy(){
}
# TODO: CLick >nextnextnext if website allows it.
#############################ASSISTING FUNCTIONS#################
# returns the integer index in the url string of the occurence of "$scope"
[int] findIndexOfKeyword([String] $url){
return $url.IndexOf("&scope")
}
}
class HardCoded {
# object properties/fields
[String] $windowsCurrentPath
[String] $linuxCurrentPath
# create relative folder names
[String] $maintenanceFolderName = "maintenance"
[String] $gCalSyncFolderName = "gCal"
# create hardcoded localHost url for google calendar sync
[String] $authUrlFilePath = "/home/"+$this.linuxUsername+"/"+$this.getmaintenanceFolderName()+"/"+$this.getGCalSyncFolderName+"/"
[String] $authUrlFilename = "url.txt"
HardCoded () {
# set current paths
$this.windowsCurrentPath = $this.getCurrentPath()
$this.linuxCurrentPath = $this.convertWinPathToLinuxPath($this.windowsCurrentPath)+"/"
}
# convert Windows path to linux path:
[String] convertWinPathToLinuxPath([String] $winPath) {
$linuxPath = (($winPath -replace "\\","/") -replace ":","").Trim("/")
# convert drive letter to lowercase:
$linuxPath = $linuxPath.Substring(0,1).ToLower()+$linuxPath.Substring(1)
$linuxPath = "/mnt/"+$linuxPath
return $linuxPath
}
# return linux format of current path
[String] getCurrentPath() {
[String] $winPath = Split-Path -parent $PSCommandPath
return $winPath
}
# Getters
[String] getmaintenanceFolderName() {
return $this.maintenanceFolderName
}
# Getters
[String] getGCalSyncFolderName() {
return $this.gCalSyncFolderName
}
# Getters
[String] getAutoInstallTwProjectName() {
return $this.autoInstallTwProjectName
}
# Getters
[String] getDefaultLocalHostname() {
return $this.defaultLocalHostname
}
# Getters
[String] getWindowsCurrentPath() {
return $this.windowsCurrentPath
}
# Getters
[String] getLinuxCurrentPath() {
return $this.linuxCurrentPath
}
# Getters
[String] getAuthUrlFilePath() {
return $this.authUrlFilePath
}
# Getters
[String] getAuthUrlFilename() {
return $this.authUrlFilename
}
}
#Create objects that are used
[HardCoded] $hardCoded = [HardCoded]::new()
[GCalAccess] $gCalAccess = [GCalAccess]::new($hardCoded)
# Create a background job to scan for url file
# scan for the url file to emerge
$gCalAccess.scanUrlFile()
#$gCalAccess.copyUrl()
$gCalAccess.readUrlFromFile()
$gCalAccess.openUrlInBrowser()
}
Write-Host "Created job"
# Give the job 10 seconds to create a list of entries.
Start-Sleep -Milliseconds 10000
Write-Host "Running askSync"
#Run command that displays the url (and indirectly generates the url file) inside the installer
wsl /home/testlinuxname/maintenance/./askSync.sh
Write-Host "Running stopjob"
# 6. Stop the job to get the data out.
Get-Job -Name ListStuffOnTable | Stop-Job
# 7. Verify it exists and functions correctly:
Write-Host "`n Deleting job"
# 8. Delete the job for correct bookkeeping:
Get-Job -Name ListStuffOnTable | Remove-Job
问题
为什么方法对象中集成的代码无法打开浏览器?
解决方案
我的 xy 问题的解决方案是将网站打开代码放在对象之外,但我想更好地理解为什么 powershell 会这样做(或者发现我犯了一个我还没有看到的错误)。
答案1
Powershell 不会阻止在作业中的类中的方法内打开浏览器。我错误地且过于自信地认为从正常执行切换到作业执行时不会发生其他变化。
通过添加以下行:
New-Item -Path 'C:/output/logfile.txt' -ItemType File
Add-Content ('C:/output/logfile.txt') $someVariableThatIWantToPrintToFileFromInsideJob
我手动调试了代码,并确定了以下命令来确定当前路径在作业内部的设置与不在作业内部的设置不同:
$windowsCurrentPath = Split-Path -parent $PSCommandPath
Write-Host "CurrentPath="$windowsCurrentPath
通过确定作业之前的当前路径,并将其作为参数传递给作业,您可以获取作业内部的正确当前路径(即生成作业的 powershell 脚本所在的路径)。)
工作代码是:
$windowsCurrentPath = Split-Path -parent $PSCommandPath
Write-Host "CurrentPath="$windowsCurrentPath
# 5. Start job and execute a method of the object
Start-Job -Name ListStuffOnTable -ScriptBlock {
# 5.1 first write the class
class GCalAccess{
# Properties
[String] $urlSourcePath
[String] $urlDestPath
[String] $urlFilename
[String] $absUrlSourceFilePath
[String] $absUrlDestFilePath
[HardCoded] $hardCoded
[String] $authUrl
[String] $defaultBrowserLocation
[String] $absUrlWinDestFilePath
# constructor
GCalAccess([HardCoded] $hardCoded)
{
$this.hardCoded = $hardCoded
Write-Host $this.hardCoded.getWindowsCurrentPath()
# create the source and destination of the file that containts the url (url.txt)
# it is coppied from inside the wsl to this folder, so that powershell can read it and open the url in browser
$this.urlSourcePath = "/home/"+"testlinuxname"+"/"+$this.hardCoded.getmaintenanceFolderName()+"/"+$this.hardCoded.getGCalSyncFolderName()+"/"
$this.urlDestPath = $this.hardCoded.getLinuxCurrentPath()+"/"
$this.urlFilename = $this.hardCoded.getAuthUrlFilename()
$this.absUrlSourceFilePath=$this.urlSourcePath+$this.urlFilename
$this.absUrlDestFilePath=$this.urlDestPath+$this.urlFilename
$this.absUrlWinDestFilePath = $this.hardCoded.getWindowsCurrentPath()+"/"+$this.urlFilename
Write-Host "WinPath="$this.absUrlWinDestFilePath
Write-Host $this.hardCoded.getWindowsCurrentPath()
Write-Host $this.hardCoded.getLinuxCurrentPath()
Write-Host "Url source file path = "$this.absUrlSourceFilePath
Write-Host "Url destination file path = "$this.absUrlDestFilePath
}
# Infinite loop that Scans the existance of the file
scanUrlFile(){
[boolean] $foundUrl = $false
# first copy the fail, regardless of whether it exists, then check if it is copied:
while(!$foundUrl)
{
$this.copyUrl()
if (Test-Path $this.absUrlWinDestFilePath -PathType leaf)
{
Write-Host "FOUND Url"
#do some stuff
$foundUrl = $true
}
}
# exit
# while(!$this.foundUrl())
# {
# # sleep 0.3 seconds
# Write-Host "Didn't find it yet."
# Start-Sleep -Milliseconds 300
# }
}
# Checks whether url file is found in the wsl
[boolean] foundUrl()
{
# create wsl command that checks whether the file exists
$command = "ls "+$this.absUrlSourceFilePath+" && echo FoundUrlFile"
Write-Host "Command="+$command
$output = bash "-c" $command
# evaluate the output of the command to see if it found (null if not found, ends in "FoundUrlFile" if it is found)
if($output-like "*FoundUrlFile"){
Write-Host "Output="$output"..."
return $true
}else {
return $false
}
}
# copy the file that contains the url
copyUrl() {
# create copy command
Write-Host "pathSource="$this.absUrlSourceFilePath
Write-Host "pathDest="$this.absUrlDestFilePath
[String] $command = "sudo cp "+$this.absUrlSourceFilePath+" `""+$this.absUrlDestFilePath+"`""
$output = bash "-c" $command
Write-Host $output
}
readUrlFromFile(){
$windowsUrlFilePath =$this.hardCoded.getWindowsCurrentPath()+"/"+$this.urlFilename
Write-Host "windowsUrlFilePath="$windowsUrlFilePath
$this.authUrl = Get-Content $windowsUrlFilePath -First 1
}
# open link to prefered browser
openUrlInBrowser(){
Write-Host "visiting url="$this.authUrl
(New-Object -com Shell.Application).Open($this.authUrl)
$ie = new-object -com "InternetExplorer.Application"
$ie.visible = $true
$ie.navigate("http://www.google.com")
}
# deletes the copied file with the authorization url after use
cleanUpWindowsUrlFileCopy(){
}
# TODO: CLick >nextnextnext if website allows it.
#############################ASSISTING FUNCTIONS#################
# returns the integer index in the url string of the occurence of "$scope"
[int] findIndexOfKeyword([String] $url){
return $url.IndexOf("&scope")
}
}
class HardCoded {
# object properties/fields
[String] $windowsCurrentPath
[String] $linuxCurrentPath
# create relative folder names
[String] $maintenanceFolderName = "maintenance"
[String] $gCalSyncFolderName = "gCal"
# create hardcoded localHost url for google calendar sync
[String] $authUrlFilePath = "/home/"+$this.linuxUsername+"/"+$this.getmaintenanceFolderName()+"/"+$this.getGCalSyncFolderName+"/"
[String] $authUrlFilename = "url.txt"
HardCoded ([String] $incomingCurrentWindowsPath) {
# set current paths
$this.windowsCurrentPath = $incomingCurrentWindowsPath
$this.linuxCurrentPath = $this.convertWinPathToLinuxPath($this.windowsCurrentPath)+"/"
}
# convert Windows path to linux path:
[String] convertWinPathToLinuxPath([String] $winPath) {
$linuxPath = (($winPath -replace "\\","/") -replace ":","").Trim("/")
# convert drive letter to lowercase:
$linuxPath = $linuxPath.Substring(0,1).ToLower()+$linuxPath.Substring(1)
$linuxPath = "/mnt/"+$linuxPath
return $linuxPath
}
# Getters
[String] getmaintenanceFolderName() {
return $this.maintenanceFolderName
}
# Getters
[String] getGCalSyncFolderName() {
return $this.gCalSyncFolderName
}
# Getters
[String] getAutoInstallTwProjectName() {
return $this.autoInstallTwProjectName
}
# Getters
[String] getDefaultLocalHostname() {
return $this.defaultLocalHostname
}
# Getters
[String] getWindowsCurrentPath() {
return $this.windowsCurrentPath
}
# Getters
[String] getLinuxCurrentPath() {
return $this.linuxCurrentPath
}
# Getters
[String] getAuthUrlFilePath() {
return $this.authUrlFilePath
}
# Getters
[String] getAuthUrlFilename() {
return $this.authUrlFilename
}
}
#Create objects that are used
$incomingCurrentWindowsPath = $args[0]
[HardCoded] $hardCoded = [HardCoded]::new($incomingCurrentWindowsPath)
[GCalAccess] $gCalAccess = [GCalAccess]::new($hardCoded)
# Create a background job to scan for url file
# scan for the url file to emerge
$gCalAccess.scanUrlFile()
#$gCalAccess.copyUrl()
$gCalAccess.readUrlFromFile()
$gCalAccess.openUrlInBrowser()
} -ArgumentList @($windowsCurrentPath)
Write-Host "Created job"
# Give the job 10 seconds to create a list of entries.
Start-Sleep -Milliseconds 10000
Write-Host "Running askSync"
#Run command that displays the url (and indirectly generates the url file) inside the installer
wsl /home/testlinuxname/maintenance/./askSync.sh
Write-Host "Running stopjob"
# 6. Stop the job to get the data out.
Get-Job -Name ListStuffOnTable | Stop-Job
# 7. Verify it exists and functions correctly:
Write-Host "`n Deleting job"
# 8. Delete the job for correct bookkeeping:
Get-Job -Name ListStuffOnTable | Remove-Job
结论
您可以在 powershell 中某个作业内某个类内某个方法内打开浏览器。