Loop through a query in powershell TFS - powershell

I am new to TFS and powershell scripting.As a part of my assignment I got a task in which
I have an array with TFS workitem ID's and I need to loop through and
get the details of those id's and display the result.
As a part of it I tried as shown below
$TFSSERVER = "https://server"
$WId = #("1", "2", "3", "4")
$arr = #("")
$i = 0
Function Get-WorkItemData($WId)
{
foreach($Id in $WId)
{
$i++
$query = "SELECT [System.Id]
FROM WorkItemLinks " +
"WHERE [Source].[System.id] = $Id" +
"AND [System.Links.LinkType] = 'Parent'"
if($WId.length -ge $i)
{
$arr+= $query
}
}
$wiData = tfpt query /collection:$TFSSERVER /wiql:$arr
$wiData | out-file "C:\Path"
}
Here is the error i get when i run the script
TFPT.EXE : Expecting end of string. The error is caused by ½SELECT╗.
At line:28 char:22
+ $wiData = tfpt <<<< query /collection:$TFSSERVER /wiql:$b
+ CategoryInfo : NotSpecified: ( Expecting end ...ed by ½SELECT╗.:String) [], RemoteException
+ FullyQualifiedErrorId : NativeCommandError
Can anyone please help me to how to resolve the error and get list of all details. Please help me.

I do not know if this will resolve your error, but you at the very least have syntax issues on the line that starts with $query= as well as the following line. To fix this I would probably go with long single lined string (which in effect is what you are doing as is) or a HereString (if your executable allows for that).
A single lined string would work for you, and while it is long and a bit more troublesome to read it does avoid issues like what you are running into.
$query = "SELECT [System.Id] FROM WorkItemLinks WHERE [Source].[System.id] = $id AND [System.Links.LinkType] = 'Parent'"
A HereString is formatted similarly to what you have above, but may not be compatible with your application. It is formatted where the first line is #" with nothing after it, then however many lines of text that you want, then a line starting with "#. So in your case it would look like:
$query = #"
SELECT [System.Id]
FROM WorkItemLinks
WHERE [Source].[System.id] = $Id
AND [System.Links.LinkType] = 'Parent'
"#
This may not work for your needs, as I don't know if your TFPT.EXE application will accept a multi-line string as input for the query (and have serious doubts about it allowing it).
If you really, really want to continue formatting it like you have you can continue to do so, you just need to fix the first and second lines of that section at the least:
$query = "SELECT [System.Id] " +
"FROM WorkItemLinks " +
"WHERE [Source].[System.id] = $Id " +
"AND [System.Links.LinkType] = 'Parent';"

Related

PSCustomObject not liking inline if statements in NoteProperty's value

Not sure if I am doing something stupid or if it is a "feature" of PowerShell.
Taking the following example code snippet:
[array]$Strings = #(
"This is an example string"
"This another example string test"
"This is something else fun"
"Not in list"
)
$oData = #()
Foreach($string in $strings)
{
$split = if($string.substring(0,4) -eq "This"){$String.Split(" ")}
$oData += [pscustomobject]#{
Part1 = $Split[0]
Part2 = $Split[1]
Part3 = $Split[2]
Part4 = $split[3]
Part5 = $split[4]
}
}
$oData
This throws the error Cannot index into a null array which is expected as the fourth member of the array "Strings" is not in the list so it cannot be indexed. Fair enough. To mitigate this, I though of the following modification:
$oData = #()
Foreach($string in $strings)
{
$split = if($string.substring(0,4) -eq "This"){$String.Split(" ")}
$oData += [pscustomobject]#{
Part1 = if($Split){$split[0]}
}
}
Which works, until I go to add Part2 to the object:
$oData = #()
Foreach($string in $strings)
{
$split = if($string.substring(0,4) -eq "This"){$String.Split(" ")}
$oData += [pscustomobject]#{
Part1 = if($Split){$split[0]}
Part2 = if($Split){$split[1]}
}
}
ISE underlines "Part2" with the message Unexpected token 'Part2' in expression or statement and the last curly brace of "Part1" has a an underline with the message The hash literal was incomplete.
When I run the script, the error is:
At line:13 char:38
+ Part1 = if($Split){$split[0]}
+ ~
The hash literal was incomplete.
At line:14 char:9
+ Part2 = if($Split){$split[1]}
+ ~~~~~
Unexpected token 'Part2' in expression or statement.
At line:16 char:1
+ }
+ ~
Unexpected token '}' in expression or statement.
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : IncompleteHashLiteral
To me, it seems a valid way to handle the null array and I'm sure I've used if statements in PSCustomObject values before.
I can work around the problem as I've done in the past when I've come across this problem before but I was wondering if anyone can shed light on why PowerShell doesn't like it.
I'm not entirely certain of the reason, but if you end your lines (all but the last so just the first one here) with semicolon ; it works fine. You can of course end all of them in ; for consistency as well.
I speculate it has something to do with the way the parser handles these, and it just doesn't know that the expression has ended for sure, whether it should know or not.
$oData += [pscustomobject]#{
Part1 = if($Split){$split[0]};
Part2 = if($Split){$split[1]}
}
The easy answer seems to be to add the else. As in:
$oData = #()
Foreach($string in $strings)
{
$split = if($string.substring(0,4) -eq "This"){$String.Split(" ")}
$oData += [pscustomobject]#{
Part1 = if($Split){$split[0]}else{$null}
Part2 = if($Split){$split[1]}else{$null}
Part3 = if($Split){$split[2]}else{$null}
Part4 = if($Split){$split[3]}else{$null}
Part5 = if($Split){$split[4]}else{$null}
}
}
Strange that PS is happy with:
if($something -eq $true)
{
"Hello"
}
Without the else or elseif part outside of the [pscustomobject].

Advanced Powershell Error Handling for Microsoft Modules (eg Lync)

I have a fairly complex script that includes Lync functionality. For this I import the PSSession.
When one of these commands errors, my error handling returns the line and command within the Lync module it fails on (eg line 2055 $steppablePipeline.End() ) instead of the line and command in my code (eg line 18 Enable-CSUser)
Is there some way to capture my calling command and line?
The following is a simplified example of the script
Function Main
{
Try
{
LyncTest
MailboxTest
}
Catch {$rtn = ReturnErrorCatch $_ ; Return $rtn} #Return Failure
}
Function MailboxTest
{
$script:callline = (Get-PSCallStack)[1].ScriptLineNumber
Get-Mailbox "kfsjlxghkjsdh" -ErrorAction:Stop
}
Function LyncTest
{
$script:callline = (Get-PSCallStack)[1].ScriptLineNumber
Enable-CSUser "kfsjlxghkjsdh" -ErrorAction:Stop
}
Function ReturnErrorCatch ($catch)
{
If ($catch.InvocationInfo.InvocationName -eq "throw"){$errorreturn = $catch.Exception.Message.ToString()}
Else
{
$line = "Line: " + $catch.InvocationInfo.ScriptLineNumber.ToString()
$exception = $catch.Exception.Message.ToString() -replace "`n"," "
$command = "Command: " + ($catch.InvocationInfo.Line.ToString() -replace "`t","").Trim()
$activity = " (Activity: " + $catch.CategoryInfo.Activity +")"
$line = $line + "(" + $callline.ToString() + ")"
$errorreturn = $line + " " + $exception + "`r`n" + $command + $activity
}
$Output = New-Object PSObject -Property #{Result=1;ResultReason=$errorreturn}
Return $Output
}
$result = Main
$result | fl
This returns:
Result : 1
ResultReason : Line: 2055(5) If SIP address type (SipAddressType) is set to None or is not set, you must specify the SIP address (SipAddress).
Command: $steppablePipeline.End() (Activity: Enable-CsUser)
Within my script, I am able to get the calling line by putting the $script:callline line within every subfunction (better ways to do this?), so if I comment out the LyncTest, and run the mailboxtest, I get the expected error return with erroring command, the line it failed on, and the line the function was called from.
As this is for Exchange 2010, I cannot use any Powershell V3 functionality, it must be V2.

powershell ping with loop does not return StatusCode

Powershell 4.0 on Windows 7
My IP address is 192.168.0.102 and it does reply to ping from cmd prompt.
I am trying to run the following code which does not behave well:
[int]$intPing = 4
[string]$intNetwork = "192.168.0.102"
for ($i=1;$i -le $intPing; $i++)
{
$strQuery = "select * from win32_pingstatus where address = '" + $intNetwork + $i + "'"
$wmi = get-wmiobject -query $strQuery
#"Pinging $intNetwork attempt $i..."
"Pinging $intNetwork $i ... "
if ($wmi.statuscode -eq 0)
{"success"}
else
{"error: " + $wmi.StatusCode}
this is an example I found in a book, but is not working for some reason.
By supplying my IP it prints an error, but does not return the error code. The same problem without the error code happens if I use a bad IP address. If I use 127.0.0.1 it returns a "success". If I remove the stuff related to the looping it works fine.
The purpose is to learn about looping using "for", so I'm less interested in the best way to do this. I am interested in trying to keep this code as is so that I can learn from it.
So what have I done wrong? And how can I fix it?
Try changing this
$strQuery = "select * from win32_pingstatus where address = '" + $intNetwork + $i + "'"
to this
$strQuery = "select * from win32_pingstatus where address = '$intNetwork'"
The original contained the increment number, which was causing all of your pings to fail.

Copy output powershell TFS data into an excel sheet

I am querying TFS with TFPT.exe and powershell as shown below:
$TFSSERVER = "http://tfsserveraddress"
Function Get-WorkItem {
$query = "SELECT [System.Id], [System.Title], [System.State], [Completed Work] FROM WorkItems " +
"WHERE [System.AssignedTo] = 'xyz ' " +
"AND [System.State] <> 'Closed' " +
"AND [System.State] <> 'Resolved' " +
"ORDER BY [System.Id]"
tfpt query /collection:$TFSSERVER /wiql:$query /include:data >work.xls }
In the above code I am able to view the data as expected but I am trying to create and copy the data into an excel sheet which is not happening.
Can anyone please help me how to copy the output data into an excel sheet or in xml format.Pleas ehelp
Thank you.
Not having access to TFS server, I'm assuming that tfpt query command produces a table of data, which PowerShell converts to a PSObject.
This should produce a valid CSV file, which can be opened in Excel:
$data = tfpt query /collection:$TFSSERVER /wiql:$query /include:data
Export-Csv -Path "c:\temp\file.csv" -InputObject $data -NoTypeInformation
Note: You need PowerShell v.3 to run Export-Csv.

Concatenating PowerShell variables

$timeout = new-timespan -Minutes 1
$sw = [diagnostics.stopwatch]::StartNew()
$path = "d:\powershell\test.csv"
"Processor Load, Available Memory(MB), Max Memory(Bytes)" >> $path
while ($sw.elapsed -lt $timeout)
{
$a = gwmi -query "Select * from win32_processor"
$b = gwmi -query "Select * from win32_perfrawdata_perfOS_memory"
$c = gwmi -query "Select * from win32_physicalmemory"
$date = Get-Date -format s
$a.loadpercentage + "," + $b.availableMbytes + "," + $c.capacity >> $path
start-sleep -seconds 5
}
So I'm just looking to get a minute long snapshot of what's going on. I'm not just opening this in perfmon for reasons. Basically I'd expect to get a comma-delimited output in the CSV file mentioned. It works for a single variable, but when I try to add a second variable, or text I get the following error.
Cannot convert value ", test" to type "System.Int32". Error: "Input string was not in a
correct format."
At D:\powershell\VDIPerfMon.ps1:14 char:21
+ $a.loadpercentage + <<<< ", test" >> $path
+ CategoryInfo : NotSpecified: (:) [], RuntimeException
+ FullyQualifiedErrorId : RuntimeException
How can I fix this problem?
When you use the + operator PowerShell looks on the left hand side to determine the resulting type of the expression. It is seeing an int on the left of the + and a string (that can't be converted to an int) on the right. Try it this way:
"$($a.loadpercentage), $($b.availableMbytes), $($c.capacity)" >> $path
Also where you write your headers, you might not want to append i.e. in order to overwrite old attempts:
"Processor Load, Available Memory(MB), Max Memory(Bytes)" > $path
The error is because $a.loadpercentage is an int. You are then trying to add an int and a string.
One workaround is to explicitly call .ToString()
$a.loadpercentage.ToString() + "," + $b.availableMbytes.ToString() + "," + $c.capacity.ToString() >> $path
Another way is the PowerShell array join operator. It is quick easy, and types do not matter:
($a.loadpercentage, $b.availableMbytes, $c.capacity) -join "," |
Add-Content $path
Yet another way is with a string formatter. This will easily let you control the precision and display of each value:
'{0},{1},{2}' -f $a.loadpercentage, $b.availableMbytes, $c.capacity