Unable to set a global variable - sahi

I want to use a function and the parameter I am passing should be set to global all the time. How can I do that? Here is my code:
function ReadExcelfunction($FileName,$SheetName,$RowNum,$ColNum,$Parameter)
{
var $excel = _getExcel($FileName,$SheetName);
var $excelData=$excel.getData();
var $Parameter=$excelData[$RowNum][$ColNum];
//_setGlobal($Parameter,$excelData[$RowNum][$ColNum]) -- Commented
}
Now suppose I pass the parameters as -- File sheet 1 1 Name.
What I want is this: name with the Value is stored as Global value.
Earlier I used _setGlobal($Parameter,$excelData[$RowNum][$ColNum]) which solved the purpose but this API has been removed and now I need to change my script.
I am using the sahi scripting language which is similar to JavaScript.

You don't need to use _setGlobal, you only need to declare a var before the function declaration. For example, you can declare a new Array and then set/get values just like _setGlobal.
// www.google.com used as start URL
var $globalVariable = new Array();
function SetGlobalVariable(key, newValue) {
$globalVariable[key] = newValue;
}
SetGlobalVariable('inputValue', 'stack overflow');
_setValue(_textbox("q"), $globalVariable['inputValue']);

A probable solution for you is to write value to an existing excel sheet cell from the sahi script on the fly and then retrieve the same value from the corresponding cell of excel sheet from another sahi script.
I have done a similar thing using a simple text file.
First File
\\ script 1
var $str = "Hello World";
var$filePath = "C:\\temp\\mystring.txt";
_writeToFile($str, $filePath);
Second File
\\ script 2
var $filePath = "C:\\temp\\mystring.txt";
var $mystr = _readFile($filePath);
Edit: Extended Answer
--------------------------------
| VariableName | VariableValue |
--------------------------------
| MyVar1 | MyVar1Value |
--------------------------------
| MyVar2 | MyVar2Value |
--------------------------------
| MyVar3 | MyVar3Value |
--------------------------------
Create a Sahi Function to creating a new excel sheet:
function _createExcelFile($fileName, $sheetName){
if($sheetName == null || $sheetName == ""){
$sheetName = "Sheet1";
}
_debug("Excel File Name :: " + $fileName);
_debug("Excel File Sheet Name :: " + $sheetName);
var $excelPoi = new Packages.net.sf.sahi.util.ExcelPOI($fileName, $sheetName);
$excelPoi.createNew();
}
Further you can refer the _getExcel($filePath[, $sheetName]) API from Sahi Pro. You need to do some iterations to get things done. You can read and write data as required.
Note: I have tried this only in the latest version of Sahi Pro i.e. 6.1.0.

Related

How to convert Date and Time with mailmerge google slides from sheets as it is in cell

I have created a table with which I can record our check in times of our employees with the help of a generated Qr code in each line.The data in the table is generated as slides and converted into pdf. For this I use a script that I got to work with your help and it works. Here I would like to thank you especially #tanaike.
My problem is that the date and time are not copied to the slides to be generated as indicated in the cell but completely with Central European time and I added in the script to look in column if its empty to generate the slide. If it's not empty don't do anything. As I said everything is working except this two things.
I must confess I did not try to correct it somehow because I had already shot the script and I made some here despair. It would be really great if you write me the solutions and I can take them over. I will share the spreadsheet with you and the screenshot with ae and time. Thanks for your time and effort to help people like us; we are really trying.
As another approach, when I saw your question, I thought that if your Spreadsheet has the correct date values you expect, and in your script, you are retrieving the values using getValues, getValues is replaced with getDisplayValues(), it might be your expected result.
When I saw your provided sample Spreadsheet, I found your current script, when your script is modified, how about the following modification?
From:
var sheetContents = dataRange.getValues();
To:
sheetContents = dataRange.getDisplayValues();
Note:
When I saw your sample Spreadsheet, it seems that the column of the date has mixed values of both the string value and the date object. So, if you want to use the values as the date object using getValues, please be careful about this.
Reference:
getDisplayValues()
Added:
About your 2nd question of I mean that when a slide has been generated, the script saves the link from the slide in column D if the word YES is in column L. How do I make the script create the slide if there is JA in the column L and there is no link in column D. is a link in column D, the script should not generate a slide again. Thus, the script should only generate a slide if column D is empty and at the same time the word JA is in column L., when I proposed to modify from if (row[2] === "" && row[11] === "JA") { to if (row[3] == "" && ["JA", "YES"].includes(row[11])) {, you say as follows.
If ichanged as you descripted if (row[3] == "" && ["JA", "YES"].includes(row[11])) { i got this error. Syntax error: Unexpected token 'else' Line: 21 File: Code.gs
In this case, I'm worried that you might correctly reflect my proposed script. Because when I tested it, no error occurs. So, just in case, I add the modified script from your provided Spreadsheet as follows. Please test this.
Modified script:
function mailMergeSlidesFromSheets() {
var sheet = SpreadsheetApp.getActiveSheet();
var dataRange = sheet.getDataRange();
sheetContents = dataRange.getDisplayValues(); // Modified
sheetContents.shift();
var updatedContents = [];
var check = 0;
sheetContents.forEach(function (row) {
if (row[3] == "" && ["JA", "YES"].includes(row[11])) { // Modified
check++;
var slides = createSlidesFromRow(row);
var slidesId = slides.getId();
var slidesUrl = `https://docs.google.com/presentation/d/${slidesId}/edit`;
updatedContents.push([slidesUrl]);
slides.saveAndClose();
var pdf = UrlFetchApp.fetch(`https://docs.google.com/feeds/download/presentations/Export?exportFormat=pdf&id=${slidesId}`, { headers: { authorization: "Bearer " + ScriptApp.getOAuthToken() } }).getBlob().setName(slides.getName() + ".pdf");
DriveApp.getFolderById("1tRC505IWtTj8nnPB7XyydvTtCJmOb6Ek").createFile(pdf);
// Or DriveApp.getFolderById("###folderId###").createFile(pdf);
} else {
updatedContents.push([row[3]]);
}
});
if (check == 0) return;
sheet.getRange(2, 4, updatedContents.length).setValues(updatedContents);
}
function todaysDateAndTime() {
const dt = Utilities.formatDate(new Date(),Session.getScriptTimeZone(),"MM:dd:yyyy");
const tm = Utilities.formatDate(new Date(),Session.getScriptTimeZone(),"HH:mm:ss");
Logger.log(dt);
Logger.log(tm);
}

iText7: Allow ListItem to flow horizontal next to each other

I'm looking for a way to have up to 3 list items next to each other. I've seen similar question with text blocks in the past with the recommendation to use Table as future proof mechanism. This isn't possible in my case, because accessibility requires me to use the semantic correct element.
Visual example:
# Fruits
| 1. Apple | 2. Banana | 3. ...
| 4. ... | 5. ...
I tried the following and some neaunces of it:
List list = new List();
list.setWidth(UnitValue.createPercentValue(100));
var listItem1 = new ListItem("Apple");
listItem1.setWidth(UnitValue.createPercentValue(30));
listItem1.setKeepTogether(true);
listItem1.setHorizontalAlignment(HorizontalAlignment.LEFT);
listItem1.setVerticalAlignment(VerticalAlignment.TOP);
list.add(listItem1);
var listItem2 = new ListItem("Banana");
listItem2.setWidth(UnitValue.createPercentValue(30));
listItem2.setKeepTogether(true);
listItem2.setHorizontalAlignment(HorizontalAlignment.CENTER);
listItem2.setVerticalAlignment(VerticalAlignment.TOP);
list.add(listItem2);
var listItem3 = new ListItem("...");
listItem3.setWidth(UnitValue.createPercentValue(30));
listItem3.setKeepTogether(true);
listItem3.setHorizontalAlignment(HorizontalAlignment.RIGHT);
listItem3.setVerticalAlignment(VerticalAlignment.TOP);
list.add(listItem3);
document.add(list);

Accessing array outside of a PS function

I am having a hard time figuring out how to get the PSCustomObject/array out of the function. I have tried using $Global:ZipList as well as just passing the variables into an array directly w/o a custom object but no luck. The reason I need this, is I need to then loop through the array/list after I get the filenames and then was going to loop through this list and unzip each file and log it and process it based on the extension in the zip; this is to be used for multiple zips, so I can't predetermine the file extensions without grabbing the filenames in the zip into a list. I would just use a shell however some of the zips are password protected, haven't figured out how to pass a password scripted to the shell com unzip windows feature so stuck with 7z for now. Any help would be greatly appreciated! Thanks
Function ReadZipFile([string]$ZipFileName)
{
[string[]]$ReadZipFile = & 'C:\Program Files\7-Zip\7z.exe' l "$ZipFileName"
[bool]$separatorFound = $false
#$ZipList = #()
$ReadZipFile | ForEach-Object{
if ($_.StartsWith("------------------- ----- ------------ ------------"))
{
if ($separatorFound)
{
BREAK # Second separator; We're done!
}
$separatorFound = -not $separatorFound
}
else
{
if ($separatorFound)
{
[DateTime]$FileCreatedDate = [DateTime]::ParseExact($_.Substring(0, 19),"yyyy'-'MM'-'dd HH':'mm':'ss", [CultureInfo]::InvariantCulture)
[Int]$FileSize = [Int]"0$($_.Substring(26, 12).Trim())"
$ZipFileName = $_.Substring(53).TrimEnd()
$ZipList = [PSCustomObject] #{
ZipFileName=$ZipFileName
FileCreatedDate=$FileCreatedDate
FileSize=$FileSize}
}
}
}
}
$z = ReadZipFile $ZipFileName
$ZipList | Select-Object ZipFileName
To be able to select from array created in the function outside of it. I believe my if statements may be blocking the global variable feature when i tried using global:

Need a powershell script to use a parameter to manipulate/read in fields from another csv file

I have and existing PowerShell script (not written by me!) which is designed to use a passed-in parameter (SCOM Alert ID) to then set additional information in the alert, e.g. $alert.CustomField1 = $alert.PrincipleName etc etc.
I am looking to add functionality to this script to be able to add additional 'custom' information which is stored in a separate text/CSV file. The text/CSV file has header line
ServerName,ServiceOwner,Application Tier
so a row in the file would be
MYSERVER.CONTOSO.COM,Joe Bloggs, Tier 1
There will be one unique row for each server in our environment (over 600 rows).
So what I need to do is using the passed-in alert ID. I can use $alert.PrincipleName to find the corresponding row in the text file and pull in the additional details stored in field 2 and 3, i.e. ServiceOwner and ApplicationTier.
This logic holds for the majority of alerts but IF server name is a specific value (e.g. MYSTSERVER.CONTOSO.COM) then instead of using $alert.PrincipleName to match servername in text file, I need to match on another alert property $alert.MonitoringObjectDisplayName. However, the server name in this field is part of a larger string in the format, e.g. User Services Watcher for Pool [MYTARGETSERVER.CONTOSO.COM] - so I need to extract the severname from between the square brackets of the string to then perform the match with the text file.
Hopefully I have explained what I'm trying to do clearly - if not I'm happy to provide further clarification and can also post up the existing PS Script I'm trying to modify if thats any help.
You can react to the server name like this:
$csv = Import-Csv 'C:\path\to\your.csv'
...
if ( $alert.PrincipalName -eq 'MYSTSERVER.CONTOSO.COM' ) {
if ( $alert.MonitoringObjectDisplayName -match '.*\[(.*?)\]' ) {
$targetserver = $matches[1]
}
} else {
$targetserver = $alert.PrincipalName
}
$newdata = $csv | ? { $_.ServerName -eq $targetserver } `
| select ServiceOwner, 'Application Tier'
...
$alert.CustomField2 = $newdata.ServiceOwner
$alert.CustomField3 = $newdata.'Application Tier'
...

Fitnesse smartrics.rest.fitnesse.fixture.RestFixture.setBaseUrl

I have a requirement for a test to make a call to one REST endpoint that generates a security token then make a second to the actual system under test. In order to do this I am using smartrics.rest.fitnesse.fixture.RestFixture and setting the baseurl in instantiation to the first base. I am trying to make this call and then set the new baseurl to the new location but am having trouble doing so.
It appears from perusing the code that there is a method setBaseUrl(Url url) but I cannot find an example of using this and am failing trying to figure it out myself.
Has anyone had any luck with this or is there another, better/easier way to achieve this?
The problem lies in RestFixture:processRow - since it uses Java reflection, it attempts to call method without parameters. This will fail since setBaseUrl accepts one argument (Url). I have tried one modification, though not the best way to achieve it - current code RestFixture v3.0 (RestFixture.processRow()):
method1 = getClass().getMethod(methodName);
method1.invoke(this);
Modified code in RestFixture.processRow():
Method[] methods = getClass().getMethods();
int i = 0;
for(i = 0; i < methods.length; i++){
if(methodName.equals(methods[i].getName())){
method1 = methods[i];
break;
}
}
Class[] paramTypes = method1.getParameterTypes();
List<Object> params = new ArrayList<Object>();
for(i = 0; i < paramTypes.length; i++){
String cellText = row.getCell(i+1).text();
Object param = paramTypes[i].getConstructor(String.class).newInstance(cellText);
params.add(param);
}
method1.invoke(this, params.toArray());
Once this modification is done (you might need to add required imports - java.lang.InstantiationException, java.lang.Object, java.util.ArrayList; and an exception handler for InstantiationException), re-build the RestFixture and that should work.
We had what sounds like a similar requirement - we needed to use RestFixture(POST) to retrieve a URL for use in a subsequent RestFixture call(GET).
(Note that we're using an ancient RestFixture 1.1)
I modified the processArguments() method in RestFixture.java thus:
// baseUrl = new Url(args[0]); // original line
baseUrl = new Url(resolve(args[0])); // modified
With this modification in place, my Fitnesse test looks like this:
`!| RestFixture | http:///fds |
| setBody |{"param1":"blah","param2":"blather"} |
| POST | /GetThatUrl | 200 | | |
| let | $urlresult | body | |
!| RestFixture | $urlresult |
| GET| | 200 | Content-Length:[\d]+ | ||`
Without the code change, $urlresult was not resolved and I could not pass in the URL as a variable.