Cannot run same script twice in same PowerShell session - powershell

I'm writing a PowerShell script that will open an application, run a process, then close it, and then open another application, run a process, and close it. (Ultimately more than two, but I'm starting small.)
I can run the following script, with no issues:
# Project Config
$projectName = "c:\temp\test3.egp"
$projectName2= "c:\temp\test4.egp"
# Start Enterprise Guide
$app = New-Object -ComObject SASEGObjectModel.Application.7.1
#Open the Enterprise Guide Project
$projectObject = $app.Open($projectName, "")
# Save the Enterprise Guide Project
$projectObject.Save()
# Close the Enterprise Guide Project
$projectObject.Close()
# Open the second project
$projectObject = $app.Open($projectName2, "")
# Save the second project
$projectObject.Save()
#Close the second project
$projectObject.Close()
# Quit Enterprise Guide
$app.Quit()
PS C:\temp> ./test.ps1
PS C:\temp>
However, if I run it a second time at that above prompt, without exiting PowerShell, I get errors.
PS C:\temp> ./test.ps1
Exception calling "Open" with "2" argument(s): "Path is not a directory 'C:': The filename, directory name, or volume label syntax is incorrect."
At C:\temp\test.ps1:9 char:27
+ $projectObject = $app.Open <<<< ($projectName, "")
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : ComMethodTargetInvocation
... more errors related to $projectObject not having a value, and then a second copy of each of these for the second attempt ...
PS C:\temp>
It works fine if I exit from Powershell, and reopen Powershell, and run it again.
Restrictions that are documented primarily include only one Project being able to be opened at one time; however, clearly $projectObject.Close() works fine, because it does successfully run two in one script. It's only when I've left the script and run it again that it's a problem.
Now, if I remove $app.Quit(), it then allows me to run it a second time in the same session; but I do want to quit the app (to ensure that any following run of the script isn't impacted by anything I just did; this is a programming environment, so things like setting session macro variables and such could have bad impacts). I also don't entirely understand why the line $app = New-Object ... doesn't create a new instance of the application (and so why the prior run's $app quit is relevant)?
Is there something in PowerShell I am doing wrong here? Or is this solely an issue with the API I'm using that I'll have to talk to SAS (the vendor)?

Inside your original PS session create a new PS session for each project: New-PSSession
More details and examples can be found on the Microsoft docs site here.

Related

How to move file on remote server to another location on the same remote server using PowerShell

Currently, I run the following command to fetch the files to my local system.
Get-SCPFile
-ComputerName $server
-Credential $credential
-RemoteFile ($origin + $target + ".csv")
-LocalFile ($destination + $target + ".csv")
It works as I'd like (although it sucks that I can't copy multiple files by regex and/or wildcard). However, after the operation has been carried out, I'd like to move the remote files to another directory on the remote server so instead of residing in $origin at $server, I want them to be placed in $origin + "/done" at the same server. Today, I have to use PuTTY for that but it would be so much more convenient to do that from PS.
Googling gave me a lot of material but I couldn't make it work. At the moment, I'm not sure if I'm specifying the path incorrectly somehow or if it's not possible to use the plain commands when working against an external, secured, Unix-server.
For copying files, I can't use Copy-Item, hence the function Get-SCPFile. I can imagine that remote moving, renaming and listing the items isn't possible neither for the same reason (whatever that reason is).
This example as well as this one produce error cannot find path despite the value being used for copying the file successfully with the script at the top. I'm pretty sure it's a misleading error message (not being enitrely sure, though).
$file = "\\" + $server + "" + $origin + "" + $target + ".csv"
# \\L234231.vds.afm.se/var/trans/ut/drish/sxx/meta001.csv
Remove-Item $file -force
Many answers (like this) are very simple, which supports my theory that the combination of Unix and secure raise an extra challenge. Perhaps I'm wording the question insufficiently well.
There's also more advanced examples, still not working, just hanging up the window with no error messages. I feel my competence prevents me from estimating the degree of screwuppiness in this approach.
In PowerShell you can create a PowerShell Session (PSSession) from your System remotly on another System (and into another Session on your System but thats details... ) and execute your commands there.
You can create a PSSession with New-PSSession but a lot of cmdlets have a-ComputerName parameter (or something similar) so that they can be executed remotley without creating a PSSession first.
A PSSession can be used with Enter-PSSession to get an interactive Session or with Invoke-Command to execute a ScriptBlock. That way you could test your Remove-Item command directly on the target server. Depending on the setup you might need to use Linux syntax within the remote session.
Here are some more infos about_PSSessions and using it with SSH to connect to Linux

TFS 2017 build executing powershell failing due to term not recognized error on line 1

I'm pretty new to TFS and I'm still learning how to use it (so hopefully this isn't just a stupid oversight on my end). I'm working an internship this summer at a seasonal developer position, and essentially my end goal is to automate load testing for the company's website. I'm using TFS to achieve this goal; the build I currently have has two tasks only right now: one to start the controller and the testing environment, and one to stop them. My problem is that the build keeps failing before it really even starts, due to a "term not recognized" error on line 1, specifically caused by what appears to be the default working folder not being recognized.
Here are the relevant log files:
2019-05-30T20:00:02.0942883Z Executing the following powershell script. (workingFolder = D:\RM_agent\_work\11\s)
2019-05-30T20:00:02.0942883Z D:\RM_agent\_work\11\s
2019-05-30T20:00:02.4999117Z ##[error]. : The term 'D:\RM_agent\_work\11\s' is not recognized as the name of a
2019-05-30T20:00:02.4999117Z ##[error]cmdlet, function, script file, or operable program. Check the spelling of the
2019-05-30T20:00:02.4999117Z ##[error]name, or if a path was included, verify that the path is correct and try again.
2019-05-30T20:00:02.4999117Z ##[error]At line:1 char:3
2019-05-30T20:00:02.4999117Z ##[error]+ . 'D:\RM_agent\_work\11\s'
2019-05-30T20:00:02.4999117Z ##[error]+ ~~~~~~~~~~~~~~~~~~~~~~~~
2019-05-30T20:00:02.4999117Z ##[error] + CategoryInfo : ObjectNotFound: (D:\RM_agent\_work\11\s:String)
2019-05-30T20:00:02.4999117Z ##[error] [], CommandNotFoundException
2019-05-30T20:00:02.4999117Z ##[error] + FullyQualifiedErrorId : CommandNotFoundException
I know that the working folder defaults to $(Build.SourcesDirectory), so I'm assuming that D:\RM_agent\_work\11\s is what $(Build.SourcesDirectory) evaluates to. RM_agent is obviously an agent, so /_work/11/s should be the local path where it stores the source code. Why is it unrecognized then?
I tried manually setting the working folder for the scripts through tfs to the folder where the build is stored, but the build still failed and the logs still showed that workingFolder = D:\RM_agent\_work\11\s.
Additionally, the line of code that the build is failing on, Executing the following powershell script. (workingFolder = D:\RM_agent\_work\11\s), is nowhere in the script I am trying to execute, which confuses me. Where is this script coming from?
(I can remove this if it doesn't fit the guidelines/is off topic, but if anyone could point me towards any resources about tfs and/or load testing it would be massively helpful as well)
EDIT: Here is the powershell script for the first task
########################################
# start environment
########################################
# import modules
Import-Module '\\neenah-san1\TSbuild\Deployment\Tools\PowerShell\Azure\JJK.TS.Azure.psm1' -Force -Prefix 'TS'
# provide azure credentials
$credential = Get-Credential
# login to azure subscription
Login-AzureRmAccount -Credential $credential
# start the controller
Get-AzureRmVM -ResourceGroupName 'TS-LoadTest-TST' | Where-Object {$_.Name -match 'vstc'} | Start-TSAzureVM -Credential $credential
# wait for controller to fully start
Start-Sleep -Seconds 120
# start the agents
Get-AzureRmVM -ResourceGroupName 'TS-LoadTest-TST' | Where-Object {$_.Name -match 'vsta'} | Start-TSAzureVM -Credential $credential
# check status of all servers
Get-AzureRmVM -ResourceGroupName 'TS-LoadTest-TST' -Status | Sort-Object -Property Name | Select-Object -Property Name, PowerState | Format-Table -AutoSize
Solution structure:
EDIT 2: [RESOLVED] It's all fixed now, thank you! I went into the repository and mapped the folder my scripts were in directly to $(build.sourcesDirectory). Consequently I was able to change the file path to $(build.sourcesDirectory)\StartControllerAndAgents.ps1 and the build is now able to find the files to run.
You need to specify the path to the script as $(Build.SourcesDirectory)\Path\To\Script. Not the TFVC path which you've configured now $/Project/Path/To/Script.
The exact path depends on the workspace mapping of the build definition.
The same applies to the working directory.
There are a number of variables in Azure Pipelines (the current name for the Build hub in TFS/Azure DevOps) that resolve to different standardized paths on the agent. Almost all tasks take a relative path off of those variables.

PowerShell and Onenote

I would like to read and write on OneNote pages using PowerShell scripts. I have been trying different scripts I found, but none of them even run on my machine. I am wondering if I have to enable something, or get some kind of library.
When trying to run some scripts I found, I get this error:
Unable to find type [Microsoft.Office.InterOp.OneNote.HierarchyScope].
At line:3 char:27
+ ... erarchy("", [Microsoft.Office.InterOp.OneNote.HierarchyScope]::hsPage ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (Microsoft.Offic....HierarchyScope:TypeName) [], RuntimeException
+ FullyQualifiedErrorId : TypeNotFound
Could someone point me in the right direction? Or is it even possible?
PS Version: 5.1.17134.407
OneNote 2013
Agreed with Theo on this one.
How are you trying to run them, consolehost, ISE, VSCode, other editor?
Did you set your ExecutionPolicy so that you could run them at all.
Is OneNote on your machine and activated or are you trying to hit a remote box?
However, there is a provider you can use to assist you here...
OneNotePowerShellProvider
# Example Scripts
Name
----
ConvertTo-Object.ps1
Create-OneNoteDocumentation.ps1
Export-PsOn.ps1
Get-OneNoteApplication.ps1
Get-OneNoteDigest.ps1
Get-OneNoteText.ps1
Get-ProviderTests.ps1
Import-FilesToOneNote.ps1
Robocopy-Items.ps1
Set-OneNoteDebug.ps1
Start-Tests.ps1
… as well as this article...
Read and Write Content from OneNote with PowerShell
# Examples
# get a table of all notebooks
$OneNote = New-Object -ComObject OneNote.Application
[xml]$Hierarchy = ""
$OneNote.GetHierarchy("", [Microsoft.Office.InterOp.OneNote.HierarchyScope]::hsPages, [ref]$Hierarchy)
$Hierarchy.Notebooks.Notebook | Format-Table Name, path, isUnread, isCurrentlyViewed

How to connect Powershell script to an already opened document?

I have a Powershell script that performs some modifications with a MSWord document. In the beginning of the script PS opens the document:
$word = New-Object -ComObject Word.Application
$desktop_path = [Environment]::GetFolderPath("Desktop")
$doc = $word.Documents.Open("$desktop_path" + "blabla.docx")
But as the requirements changed, I now need to run this PS script within an already opened document. Is there any options to force PowerShell find an opened document (by the name for example) and "connect" to it?
FYI: The sequense I want to obtain is: I open the file, launch some macros, call from VBA my PSScript (and here I need PS to be able to "fetch" an opened doc), launch other macros.
Thank you a lot in advance!
This should the same as for Excel:
$word = [Runtime.Interopservices.Marshal]::GetActiveObject('Word.Application')
Note the same-user limitation. I would recommend doing the whole thing programmatically via PowerShell though, as suggested by Guenther.
If word is not running, is running under a different user, or is running as admin (and PowerShell is not running as admin) you will get an error:
Exception calling "GetActiveObject" with "1" argument(s): "Operation unavailable (Exception from HRESULT: 0x800401E3 (MK_E_UNAVAILABLE))"
At line:1 char:1
+ $word = [Runtime.Interopservices.Marshal]::GetActiveObject('Word.Appl ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : COMException
As advised, check that PowerShell and Word are running under the same user. You can so this by going to Task Manager > Details, and checking the user name column for WINWORD.EXE and powershell.exe
To get a specific document based on name:
$doc = $word.Documents | Where-Object {$_.Name -eq "Document2"}
You can check how many documents are open by looking at the count:
$word.Documents.Count

Unzip with Powershell doesn't work on XP

I got the Request to unzip a .zip file with Powershell. On the Internet i found the following code multiple times:
param( [String]$newlocation, [String]$filepath)
if(($newlocation -and $filepath) -and ((test-path $newlocation) -and (test-path $filepath)))
{
Copy-Item $filepath $newlocation
$shell_app=new-object -com shell.application
$filename = $filepath.split("\")[-1]
if(Test-Path "$newlocation\$filename")
{
$zip_file = $shell_app.namespace("$newlocation\$filename")
$destination = $shell_app.namespace($newlocation)
$destination.Copyhere($zip_file.items())
}
}
As I implemented it into my script it changed a little bit. This above is the changed version. Now I've got an error:
Exception calling "NameSpace" with "1" argument(s): "The system cannot find the file specified. (Exception from HRESULT
: 0x80070002)"
At Z:\MyScripts\deploy.ps1:34 char:34
+ $zip_file = $shell_app.namespace <<<< ("$newlocation\$filename")
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : ComMethodTargetInvocation
And then another one, that is quite clear (caused by the first error
You cannot call a method on a null-valued expression.
At Z:\MyScripts\deploy.ps1:36 char:39
+ $destination.Copyhere($zip_file.items <<<< ())
+ CategoryInfo : InvalidOperation: (items:String) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
The File and the destination Path both exist and I've got rights to acces them (I created both). I'm running on Windows XP with PowerShell 2.0
Major Minor Build Revision
----- ----- ----- --------
2 0 -1 -1
Here is my entire dump from Powershell when I run it directly on the console.
I hope you guys can help me or at least tell me where I can go to find an answer.
I tried already to unzip the zip file manually and it worked, I have got access to both, the file and the file path (as I created both).
I've found this one on the web:
Also the code looks to me like it's dependent on the Windows Explorer support for zipFolders, which you may have turned off
Unregister (disable) XP Zip folders
REGSVR32 /u C:\Windows\System32\zipfldr.dll
Register (enable) XP Zip folders
REGSVR32 zipfldr.dll
It's from here.
I came to it during testing my script on several machines, e.g. on a Windows Server 2008 and on a Windows 7 client. Both worked, so I came to the conclusion that it's not my script,but it's my PC. After the registration of XP Zip folders, it worked.
Many thanks to the guy who wrote this one, I dumped too much time into this problem.
You might be running into a problem with accessing the COM objects. If you are using 64-bit windows, make sure you execute your script from a 64-bit powershell.exe. This means the powershell.exe in c:\windows\system32...\v1.0.... This was counter-intuitive for me, having the '32' in system32. I was executing powershell from Console2, which was a 32bit process, and was therefore launching 32-bit powershell (from c:\windows\syswow64...). Also make sure your powershell.exe is being run with administrator privileges.
Instead of trying to automate the Windows Shell, now in .NET Framework 4.5 there is a ZipFile class that you can use like this:
[System.Reflection.Assembly]::LoadWithPartialName('System.IO.Compression.FileSystem')
[System.IO.Compression.ZipFile]::ExtractToDirectory($sourceFile, $targetFolder)
Edit: Oops, .NET Framework 4.5 is not supported on Windows XP.
Anyhow, this answer might still prove useful for anyone else with ZIP problems in Powershell…