RTC SCM Query workspace exit code - version-control

I am trying to write a query to see if a workspace with specific name already exists in repository or not. Following is the query I am using after logging in a previous command:
$wsQueryResult = &scm query -r https://myrationaluri -w "name='myworkspace"
I get output similar to following:
At C:\scripts\vso-rtc\get-code-fromRTC.ps1:27 char:19
+ $wsQueryResult = &scm query -r myurl -w "name='my ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (Problem running 'query'::String) [], RemoteException
+ FullyQualifiedErrorId : NativeCommandError
No repository workspace matches the query "name='myworkspace'".
The query is inside a powershell script. I understand the last part of the response "No repository workspace matches the query..." However, why do I get Problem running query::String. The value of $wsQueryResult is null after this execution. I was hoping that there will be an exit code or something.
Is the problem in my query syntax or is this normal. If it is normal, do I need to examine the output for line "no repository workspace"
Thank you for your help.

I ended up examining the output from query and determining if the workspace was found or not. I used following code:
$workspaceName = $env:USERNAME + "-" + $patch
$output=scm query -r $rtcURI -w "name='$workspaceName'" *>&1
$output = $output | Select-String "No repository workspace matches"
if ($output -like "No repo*") {
write-host "Repository doesn't exist, will create new one"
scm create workspace -r $rtcURI -s $streamName $workspaceName
} else {
write-host "Workspace $workspaceName Already exists... will refresh"
}

Related

Why is Export-PnPFlows Skipping Flows?

This is my first post, so please pardon formatting errors!
I've been trying to export my tenant's Power Automate flows via Export-PnPFlow. I have a few hundred flows, so doing it by hand isn't really feasible.
The script works well enough for some flows, but is throwing an error for others, but I can't see why.
It does not seem to be caused by if it's enabled/disabled, owned by a certain user, in a certain environment, or in/out of a solution.
The ones that work, work perfectly; the others give the following error:
Export-PnPFlow : {"error":{"code":"ConnectionAuthorizationFailed","message":"The caller object id is '08#####-#####-####-###'. Connection '2#####-#####-####-####' to 'shared_logicflows' cannot be used to activate this flow, either because
this is not a valid connection or because it is not a connection you have access permission for. Either replace the connection with a valid connection you can access or have the connection owner activate the flow, so the connection is shared with you in the context of
this flow."}}
At C:\Users\jutrust\script.ps1:13 char:21
+ ... Export-PnPFlow -Environment $environment -Identity $flow. ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Export-PnPFlow], HttpRequestException
+ FullyQualifiedErrorId : System.Net.Http.HttpRequestException,PnP.PowerShell.Commands.PowerPlatform.PowerAutomate.ExportFlow
My question is, is it possible that these flows are deleted and that's why I get this error? If so, how can I check?
Code below.
Connect-PnPOnline -url https://########.sharepoint.com
$environments = get-pnppowerplatformenvironment
foreach($environment in $environments)
{
$flows = Get-PnPFlow -Environment $environment -AsAdmin
foreach ($flow in $flows)
{
$filename = $flow.Properties.DisplayName.Replace(" ", "")
$timestamp = Get-Date -Format "yyyymmddhhmmss"
$exportPath = "$($filename)_$($timestamp)"
$exportPath = $exportPath.Split([IO.Path]::GetInvalidFileNameChars()) -join '_'
Export-PnPFlow -Environment $environment -Identity $flow.Name | Out-File "C:\Users\jutrust\documents\$exportPath.json"
}
}
Help!
Edit: Updated error code

Add folder to zip

I am facing a problem how to add folder to existing ZIP file.
This zip file is created by PowerShell also.
I can only use system classes provided by Powershell 5. I cannot use any of user packages or plugins (7zip included).
Here is my code:
function addFileToArchiveTest ($filePathToAdd, $archivePathToUpdate) {
if ([System.IO.File]::Exists($filePathToAdd) -or (Test-Path $filePathToAdd)) {
$file = [System.IO.Path]::GetFileName($filePathToAdd);
Write-Host $filePathToAdd.Name;
Write-Host $filePathToAdd;
Write-Host $archivePathToUpdate;
$archive = [System.IO.Compression.ZipFile]::Open($archivePathToUpdate, [System.IO.Compression.ZipArchiveMode]::Update);
$compressionLevel = [System.IO.Compression.CompressionLevel]::NoCompression;
[System.IO.Compression.ZipFileExtensions]::CreateEntryFromFile($archive, $filePathToAdd, $file, "$compressionLevel");
$archive.Dispose();
} else {
Write-Host "[ERROR#function] <AddFileToArchive>: <filePathToAdd> does not exist!";
Write-Host "[ERROR#function] <Variable<filePathToAdd>>: $filePathToAdd";
Write-Host "[ERROR#function] <Variable<archivePathToUpdate>>: $archivePathToUpdate";
}
}
I am thinking about variable $file - there might be a problem, because folder doesn't have an extension.
I run script like this:
PS> addFileToArchiveTest "C:\TestFolder\FolderToArchive" "C:\TestFolder\thereIsAlreadyZipFile.zip"
It returns with error:
Exception calling "CreateEntryFromFile" with "4" argument(s): "Access to the
path 'C:\TestFolder\FolderToArchive' is denied."
At C:\Users\user\Desktop\testfolder.ps1:196 char:13
+ [System.IO.Compression.ZipFileExtensions]::CreateEntryFro ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : UnauthorizedAccessException
Noted I also try allow script and I am launching with admin rights.
Perhaps surprisingly, CreateEntryFromFile() is for adding files, not folders. You need to add each file individually:
Get-ChildItem $filePathToAdd | ForEach-Object {
[IO.Compression.ZipFileExtensions]::CreateEntryFromFile($archive, $_.FullName, $_.Name, "$compressionLevel")
}
As user #guiwhatsthat answered: PowerShell 5 does support Compress-Archive. It does exactly what you want.
That is working as I want.

Powershell: how to remove stack trace when command returns an error?

When a command returns an error, I get like an error message, plus what looks like a full stack of the error:
C:\> dir foo
dir : Cannot find path 'C:\foo' because it does not exist.
At line:1 char:1
+ dir foo
+ ~~~~~~~
+ CategoryInfo : ObjectNotFound: (C:\foo:String) [Get-ChildItem], ItemNotFoundException
+ FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand
Is there a way to only see the error (that's the only thing usefull for me) and not display the full stack ?
Like:
C:\> dir foo
dir : Cannot find path 'C:\foo' because it does not exist.
You need to catch the error if you want to control how or what is displayed:
try {
dir foo -ErrorAction Stop
} catch {
Write-Host $_
}
Sometimes you'll need to add -ErrorAction Stop (or $ErrorActionPreference = 'Stop') to ensure that all errors are terminating (so they can be caught).
All powershell errors are captured in the auto variable $error. The item at index zero ($error[0]) is the most recent, index 1 next to most recent, etc. Each object in the array is a System.Management.Automation.ErrorRecord. An ErrorRecord contains a number of properties. You can use the select-object cmdlet to see a subset of properties:
$error[0]|select * -excludeproperty *stacktrace
If you want to be able to view the error record at an arbitrary while you're developing a script I'd suggest a function in your profile maybe like:
function show-myError {
param( $errorIndex = 0)
# You can also add anything else you want to exclude
$error[0]|select * -exclude *stacktrace
}
sal err show-myError
On the other hand if you're getting an error at a specific place in a specific script you can use catch/try as suggested in earlier answer. Or if you don't have a specific place, but do have a specific script, then I suggest trap, which you can place at the top of a function or top of a PS1 file. In the catch block or trap block you can output $error[0] using select with the -exclude parameter.

How to found if a TFS workspace is a local or server workspace

Is there a way to find out if a specific folder mapped in an existing tfs workspace is a local workspace or a server workspace?
I'm mostly interested by an answer using the tf.exe command or powershell or even api (but not with the GUI!).
After a long search (hours and hours in the very bad msdn documentation about the tf.exe command!), I have found the way to get the information!
First you have to use the tf.exe workfold c:\your\path command to find out in which workspace the folder is. The command output something like that:
================================================================
Workspace : NameOfYourWorkspace (John Doe)
Collection: https://tfs.yourtfs.com/tfs/defaultcollection
$/: C:\your\path
Then you have to extract the 'workspace' (note: we really don't know why here the tf.exe command don't output the workspace in the format accepted everywhere by the tf.exe command i.e. "WorkspaceName;Owner" and consequently should be adapted!) and 'collection' data to use it in the tf.exe workspaces /format:detailed command, like that:
tf.exe" workspaces /format:detailed /collection:"https://tfs.yourtfs.com/tfs/defaultcollection" "NameOfYourWorkspace;John Doe"
The command output something like that:
===============================================
Workspace : NameOfYourWorkspace
Owner : John Doe
Computer : YOU_COMPUTER
Comment :
Collection : yourtfs.com\DefaultCollection
Permissions: Private
Location : Local
File Time : Current
Working folders:
$/: C:\your\path
The important data that I want here is Location : Local (or Server)
I have written a little powershell script, if it could be of little use for someone to extract the data in the output to use them:
function ExtractData($text, $key)
{
$pattern = "^$key *: *(.+)$"
$filteredText= $text | Select-String $key
$found = $filteredText -match $pattern
if ($found) {
return $matches[1]
}
exit 1
}
$currentWorkspaceData = (& "$env:VS120COMNTOOLS..\IDE\tf.exe" workfold .)
$workspace = ExtractData $currentWorkspaceData "Workspace"
$found = $workspace -match "^(.+) \((.+)\)$"
if (!$found) {
exit 1
}
$workspace = $matches[1] + ";" + $matches[2]
$collection = ExtractData $currentWorkspaceData "Collection"
$location=(ExtractData (& "$env:VS120COMNTOOLS..\IDE\tf.exe" workspaces /format:detailed /collection:$collection $workspace) "Location")
$localServer = $location -eq "Local"
if($localServer)
{
Write-Host "Local!!!"
}
else
{
Write-Host "Server!!!"
}
This script give the answer only for the current folder but could be easily adapted...

How to catch plink failure when host not known

I have a problem with one of my scripts. Basically it runs very smoothly but it needs some user input from an excel file. Users can cause Errors and thats my problem.
My Script connects via ssh with plink (lil PuTTY) to certain devices and sends them commands.
Now to the real problem: if someone just misspells the FQDN, the script will go on but I need to be reported via Email that one process has failed. If someone entirely screws up the Excel-Sheet the whole Script will fail - and I need to know again. I have already designed some parametres to send me emails. The only problem is errorhandling.
Code:
try {
$FQDN | foreach {
$directory = $dir[$counter]
$errorzahl = $error.count + [int]1
&$process -ssh -l $loginname[$counter] -pw $pw[$counter] $FQDN[$counter] "config global execute $cmd config ftp $filename $FTPADRESS $FTPLOGIN $FTPPW"
$names = $KN[$counter]
if ($error.Count -gt $errorzahl) {
$names = $KN[$counter]
$smtp.Send("$ErrorSender", "$ErrorRecipient", "Powershell Script Error",
"$Emailinhaltlow, Problems: $names")
}
$counter = $counter + [int]1
}
} catch {
$errornachricht = $_.Exception.Message
if ($_.Exception.Message) {
$smtp.Send("$ErrorSender", "$ErrorRecipient", "Powershell Error",
"$Emailinhalt, Probleme mit: $names")
unregister-scheduledjob -Name $jobname -Force
}
}
This doesn't work as it should. I get an email for every single String in the array FQDN, if there is just a single error in the excel sheet and the "try and catch" also sends me the errormail, what shouldn't happen if the scripts finishes its job.
If I just remove this conditional:
if ($error.Count -gt $errorzahl) {
$names = $KN[$counter]
$smtp.Send("$ErrorSender", "$ErrorRecipient", "Powershell Error",
"$Emailinhaltlow, Problems: $names")
}
I don't get any Emails. Even if there are some small errors in the foreach loop.
EDIT ERRORCODES (Powershelloutput in red)
Error - if someone forgets to connect once with ssh and accept the certificate once - !Stops the whole Script!:
plink.exe : The server's host key is not cached in the registry. You
In C:\Users\USER\Desktop\VPNscript.ps1:10 Zeichen:1
+ &$process -ssh -l $loginname -pw $pw $FQDN "y
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (The server's ho...e registry. You:String) [], RemoteException
+ FullyQualifiedErrorId : NativeCommandError
have no guarantee that the server is the computer you
think it is.
The server's rsa2 key fingerprint is:
ssh-rsa 2048 c2:ea:62:af:70:14:e4:f0:a0:79:88:45:85:fc:cd:cc
If you trust this host, enter "y" to add the key to
PuTTY's cache and carry on connecting.
If you want to carry on connecting just once, without
adding the key to the cache, enter "n".
If you do not trust this host, press Return to abandon the
connection.
Store key in cache? (y/n)
Not mainly the topic, but if I am already uploading the errors, someone might fix one, without oppening a new question. This is one of them. I can't send the "y" to plink.
Another Error - if the FQDN is Wrong (does not exist - spelling Error in the Excelsheet) - Script will continue, but fails with one line in the excelsheet:
plink.exe : Unable to open connection:
In Zeile:73 Zeichen:1
+ &$process -ssh -l $loginname[$counter] -pw $pw[$counter] $FQDN[$counter] "config ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (Unable to open connection::String) [], RemoteException
+ FullyQualifiedErrorId : NativeCommandError
Host does not exist
EDIT 2:
"y" | &$process -ssh -l $Loginname -pw $pw $FQDN
plink.exe : The server's host key is not cached in the registry. You
In Zeile:6 Zeichen:7
+ "y" | &$process -ssh -l $Loginname -pw $pw $FQDN
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (The server's ho...e registry. You:String) [], RemoteException
+ FullyQualifiedErrorId : NativeCommandError
have no guarantee that the server is the computer you
think it is.
The server's rsa2 key fingerprint is:
ssh-rsa 2048 c2:ea:62:af:70:14:e4:f0:a0:79:88:45:85:fc:cd:cc
If you trust this host, enter "y" to add the key to
PuTTY's cache and carry on connecting.
If you want to carry on connecting just once, without
adding the key to the cache, enter "n".
If you do not trust this host, press Return to abandon the
connection.
Store key in cache? (y/n)
plink failing doesn't throw a (PowerShell) error and thus doesn't increment the $error count. Check $LastExitCode if you want to detect whether the command succeeded or failed.
As for someone "messing up the Excel sheet": how exactly does the script fail in that case? Handling this error will depend greatly on the actual error.
The host key issue can be handled by echoing "y" into the command:
"y" | &$process -ssh -l $loginname[$counter] ...
or by writing the key to the registry before running the command:
$key = "HKCU:\Software\SimonTatham\PuTTY\SshHostKeys"
$val = "0x23,0x3857aee9..."
Set-ItemProperty $key "rsa2#22:$($FQDN[$counter])" $val
&$process -ssh -l $loginname[$counter] ...
Running plink against a non-existing FQDN did not raise a terminating error in my tests:
PS C:\> $process = "plink.exe"
PS C:\> $fqdn = "correct.intern.example.org", "fail.intern.example.org"
PS C:\> nslookup $fqdn[1]
Server: ns.intern.example.org
Address: 10.42.23.1
DNS request timed out.
timeout was 2 seconds.
DNS request timed out.
timeout was 2 seconds.
*** ns.intern.example.org can't find fail.intern.example.org: Non-existent domain
PS C:\> &$process -ssh -l username $fqdn[1] "echo foo"
Unable to open connection:
Host does not exist
not even when I set $ErrorActionPreference = "stop".
However, if you do get a terminating error, it should increment $error.Count as well. Your check won't work, though, because you remember the previous error count plus one:
$errorzahl = $error.Count + [int]1
and then check if the new error count is greater than that:
if ($error.Count -gt $errorzahl) {
...
Try this instead:
$errorzahl = $error.Count
...
if ($error.Count -gt $errorzahl) {
...
You might want to use a function like this ( from psake):
function Exec
{
[CmdletBinding()]
param(
[Parameter(Position=0,Mandatory=1)][scriptblock]$cmd,
[Parameter(Position=1,Mandatory=0)][string]$errorMessage = ($msgs.error_bad_command -f $cmd)
)
& $cmd
if ($lastexitcode -ne 0) {
throw ("Exec: " + $errorMessage)
}
}
Now you can call your external programs like:
Exec { external.exe } "Failed!"
I think is an issue with Powershell 2.0 in 4.0 the error is returned.
To force the error to be thrown append 2>&1 to the external command.
& $process -ssh -l username $fqdn "echo foo" 2>&1