Attended Bot으로 등록된 Device에는 기본적으로 오케스트레이터에서 프로세스를 Triggering 할 수는 없다.

원칙적으로는 그렇지만 대부분 Attended Bot이 훨씬 가격이 저렴하기 때문에

작업 스케줄러를 통해 이를 보완하려고 하는 경우가 많다.

다만 이런 경우, 앞선 스케줄이 지체되어 뒷 스케줄의 Start Time을 넘어가 버리면

오케스트레이터에서 로그없이 Faulted로 처리되며 해당 과제는 재시도 하지 않고 실패하게 됨을 꼭 고지하자.

1) 먼저 오케스트레이터에 Process를 만든다. [Publish후 Attended Bot과 연결]

(Process 생성 시 Display Name은 자동생성 되도록 하는 게 좋음)

2) 해당 Attended Bot Device에 들어가 작업 스케줄러를 켠다.

3) 우측 작업 만들기 클릭

4) 작업 이름은 무슨 과제인지 알 수 있게 과제명으로 작성(웬만하면 영어로)

5) 트리거 탭에서 시간을 설정한다. (작업 반복 텀과 시간도 리스트에 있는 것만 선택 가능한 게 아니라 직접 입력 가능)

6) 동작 탭에서 프로그램 실행으로 UiRobot을 실행한다. 예시) C:\Program Files (x86)\UiPath\Studio\UiRobot.exe

파라미터로 -process "패키지명" 을 입력한다. [process 뒤에 한칸 띄고 입력]

 

프로세스명은 오케스트레이터에서 보이는 그대로 주면 되지만,

간혹 자동생성 name으로 인식해 실행이 안 되는 케이스도 있었다고 하니 웬만하면 자동생성 name으로 복붙하자.

 

*** 이렇게 하고 실행시켰는데 시작도 안 하고 그냥 끝나버린다면 권한문제일 가능성이 높다. 

작업 스케줄러 작업의 속성에서 일반-보안옵션-작업을 실행할 때 사용할 사용자 계정을 Users로 바꿔보자.

변경 - 고급 - 지금 찾기 하면 Users가 나온다.

RPA에서 컬럼을 동적으로 가져가야 하는 경우들이 생긴다.

번거롭지만 그리 어렵지 않게 가능하고, 컬럼 순서 변경 등에 자동으로 대응할 수 있다.

따로 만들어둔 모듈없이도 BalaReva의 Excel이나 EasyExcel을 살펴보면 Index만 줘도, 컬럼의 알파벳명을 가져올 수 있고

변수에 담아 할당하면 된다.

다만 RAW DATA, MASTER간의 동적인 컬럼 비교가 되는 경우 다음과 같은 이슈가 생긴다.

1. 비교로직 최적화 필요

- 비교할 컬럼이 몇 개 없다면 퍼포먼스에 큰 영향이 없을 수 있겠지만, 단순히 개발하면 N*N 로직이 나오기 때문에

 퍼포먼스 차이가 클 수 있다.

- 그나마 간단히 개발하면 Parsing중 해당 컬럼이 있는 경우 Continue 하게끔 개발해 그 절반정도(52%)의 경우의 수를 쓸 순 있다. [index만큼 Summation하기 때문에]

- 문제는 그렇게 비교할 때 마스터와 Raw Data의 컬럼명이 다르게 매칭된다면 매칭 마스터가 별도로 필요하다.

- 그럼 비교가 Raw Data - Raw Data 컬럼 마스터 - Master 순으로 비교되며 더더욱 퍼포먼스에 지장을 줄 가능성이 커진다.

2. 정합성 책임의 전가

- 1번 로직이 어떻게든 더 최적화되어 성공했다 하더라도 하나의 전제 조건이 생기게 된다. 실제 Raw Data의 컬럼이 변경되더라도 Master가 변경될 필요가 없다는 보장이 필요하다는 점이다.

- 만약 Raw Data가 바뀌었고 그에 맞춰 Master도 수정해 줘야할 필요가 생길 수 있다면, RPA가 아무리 컬럼을 맞춰준들 아침에 깨워줬더니 왜 늦게 깨웠냐는 식의 리액션을 받을 수도 있다.

- 심지어 이렇게 하더라도 결국 사람의 판단이 들어가는 컬럼 마스터와 Master 파일을 모두 체크하거나 갈아야 한다.

- 다시 말해, 기껏 개발했더니 에러가 실제 나야될 부분을 막는 행위가 될 수 있다.

 

따라서 단순 컬럼명이 아닌 컬럼명을 비교하며 동적으로 가져가는 경우는 웬만해선 안 받는 것이 좋다.

그런 류 로직이 필요하다면 처음와 끝만 비교하거나, 주요 컬럼만 비교하는 로직으로 협의하기를 추천한다.

현재 일반적으로 RPA SM파트에서 업무를 할 때,

CR이나 오케스트레이터를 모니터링 하게 된다.

수행 중 Faulted인 과제가 있으면 트러블 슈팅하고 history를 기록하게 되는데

과제가 많아지고 고도화 될 수록 SM인원 1인당 운영하는 과제가 많아진다.

 

과제가 적을 때는 에러에 대한 인지 텀을 길게 가져가도 별 문제가 되지 않지만,

과제가 많아지면 에러인지의 텀이 짧아져야만 효율적으로 SM업무가 가능해진다.

 

따라서 이런 툴이 있으면 어떨까 한다.

1. 모니터링할 과제를 오케스트레이터의 Process 기준으로 선택 / 혹은 Environment 기준으로 선택

2. 선택된 과제들에서 특정 이벤트 발생 시, 툴에서 소리가 나거나 활성화, 혹은 메세지.

3. 과제를 더블클릭하면 Job로깅, Job로깅에서 한 건을 클릭하면 그 건에 대한 상세로깅 출력

4. 이벤트는 'Running으로 상태 변경', '프로세스 성공 종료', 'Faulted 종료', '프로세스 kill됨' 중 옵션 선택할 수 있게끔.

5. 갱신 interval 설정 가능

 

어차피 오케에서 이리저리 찾으면 다 나오기 때문에 특별히 다른 정보가 추가로 필요할 것 같진 않다.

[현재 비슷한 기능의 툴을 만들어 쓰는 곳도 있음]

업데이트된 곳에 파란색 글씨를 입혔습니다.

Application

- 프로그램 중에 웹에서 실행시켜지는 프로그램인데 관리자 권한인 경우, 2가지 해결방법이 있음.

1. 수동 설치가 가능한 경우 : 관리자 권한으로 실행 체크 해제

2. 수동 설치가 불가능한 경우 : www.sysnet.pe.kr/2/0/1638

 

Windows: 90. 실행 파일로부터 관리자 요구 권한을 제거하는 방법(부제: 크랙 버전을 보다 안전하게

글쓴 사람 정성태 (techsharer at outlook.com) 홈페이지 첨부 파일 부모글 보이기/감추기 실행 파일로부터 관리자 요구 권한을 제거하는 방법(부제: 크랙 버전을 보다 안전하게 실행하는 방법) 쉽게 말

www.sysnet.pe.kr

 

 

Browser

- 크롬 시크릿 모드로 할 때는 확장프로그램의 세부정보로 들어가서 '시크릿 모드에서도 허용'을 True로 바꿔줘야 함

 - 탭을 꺼야 하는 경우, 브라우저의 타이틀을 유니크하게 잡을 수 있다면 Attach Browser - Close tab이 가장 안정적. 다만 그럴 수 없다면 close할 탭의 Element(그 창에만 있는 Element)에 Send hotkey로 ctrl+w를 써야 함. (이 경우 Retry scope으로 not exist 체크를 해줘야 함)

- Website를 다른 방식으로 켜야 하는 케이스가 있다면 "chrome.exe까지의 경로" "웹사이트주소" 형태로 CMD에서 실행하면 된다. 사이트주소 파라미터는 그냥 띄어쓰기로 받아짐. (Uipath 기준으로 Start Process)

ex) "C:\Program Files\Google\Chrome\Application\chrome.exe" www.naver.com

- open browser는 cmd에서 웹사이트 주소를 ""로 감싸지 않고 전달하기 때문에 Chrome에서 띄어쓰기가 포함된 URL의 경우 의도와는 달라진 결과를 얻을 수도 있다. 따라서 Uri.EscapeUriString(vURL) 형태로 URL을 인코딩하거나 빈 칸을 "+" 혹은 "%20"으로 Replace하여 진행하는 것을 추천.

- 크롬 복원 팝업창 끄기(https://forum.uipath.com/t/how-to-close-restore-pages-pop-up-in-chrome/213168/2).

값을 바꿀 때 "exit_type": "none" 으로 해야 함. 따옴표 빼먹으면 인식 X. (preference.bad 파일이 새로 생김)

 

* 경로중 Default는 기본으로 켰을 때 profile 유저를 말하며, 다른 유저를 생성하면 그 이름으로 폴더가 생기고 preference를 따로 가져간다는 의미. 이를 이용해 멀티세션 작업 등을 생각할 수도 있음. 다만 봇이 많아질수록 관리포인트가 그만큼 늘어난다는 것에 유의.[단, 환경세팅을 할 때 OS 템플릿을 써서 이미지로 import한다면 문제 없음]

- 크롬에서 다른 프로필을 만들고 켜려면 크롬뒤에 --profile-directory="프로필명" 을 파라미터로 넣어야 함. [start process 이용]

- 크롬은 open browser하면 가장 최근에 쓰인 profile로 켜지게 됨.

- 크롬 캐시 지우기 https://jnaul.tistory.com/214 [현재 크롬 폴더의 구조가 바뀌고 복잡해져서 무효함]

- 브라우저에서 특정 기능이 안 되는 경우는 개발자 도구의 콘솔을 보자

- 콘솔을 봐도 잘 모르겠을 땐 쿠키삭제 후 재시작 / 신뢰할 수 있는 사이트에 추가 /호환성 보기 설정에 추가

- 그룹정책으로 extension을 막는 케이스도 있음. chrome://policy/ 에서 확인 가능 [다른 브라우저도 비슷한 기능이 있음]

 

 

 

DataBase

- DB Insert는 Insert 구문 만들 필요없이 DataTable을 그대로 넣음

- 패키지 버전에 따라 Insert 구문이 에러났다는 경우가 있음[이 경우 1.4.0 부터 최신까지 왔다갔다 해보면 맞는 버전이 있음]

- DB Insert시 Type을 미리 맞춰야 함. 가령 주식 특정 종목의 시가총액 같은 건 숫자가 너무 커서 Int32가 아닌 Int64(Double)로 들어가야 함.

- Excel DB를 연결하는 경우 ODBC로 적힌 엔진이 아니라 OLEDB로 연결 (ODBC에서 MS가 채택한 기술을 추가 적용한 것이 OLEDB)

- Stored procedure 예시 

Execute Non Query로 Stored Procedure를 선택한 후에 sql문을 이런 형태로 주면 됨

sSQL = string.format("EXEC P_CRM_CUSTOMER_S @DC=N'{0}', @CUST_NM=N'{1}'",sDC,sCUST_NM)

혹은 "EXEC P_CRM_CUSTOMER_S @DC, @CUST_NM"으로 주고 파라미터를 in방향으로 @DC, @CUST_NM으로 주면 됨

** 최근에는 프로시져를 거의 안 쓰는 추세. 이 방법밖에 없다면 이걸 쓰고 아니면 최대한 api로 insert나 get을 구현하는 것이 더 안정적이고 대세. 개인적으로는 RPA에서 프로시져를 써야 한다면 거의 대부분 잘못된 PI가 되었다고 판단함. RPA가 할 일이 아님. 굳이 role을 보자면 RPA는 그냥 테이블에 넣기만 하고 db내 function만 call해서 처리하는 게 효율적임

DataTable

- datatable.clone => 데이터 테이블의 헤더만 가져옴[copy하고 clear 안 해도 됨]

- sort datatable로 order by가 제대로 안 되는 경우[보통 인식 type의 문제]

dtContainer.AsEnumerable().OrderByDescending(Function (row) row(“기준컬럼”)).Select(Function (row) row).ToArray.CopyToDatatable() [C#에서는 Function(row) 대신 row=> 이런 형태로 쓴다]

- DT에서 ColumnName 변경 : dtData.Columns(index).ColumnName = "바꾸고자 하는 이름" (index 대신에 old name도 가능)

- datatable.rows.indexof(datarow)를 쓰면 필터가 됐더라도 해당 datarow의 index 번호를 알 수 있다. 다만 다른 table에 copy되기 전이어야 함.

- datatable에서 떨군 datarow도 기본 복사가 참조 복사임. 따라서 dtData에서 drDataRow를 꺼내 drDataRow 내의 정보를 바꾸면 dtData에서 해당 row의 정보도 바뀌게 됨. 이게 싫다면 역시 dt를 .copy로 하거나 해당 row의 rowstate를 땔 수 있게 다른 ArrayRow로 convert 해야 함

- Filter DataTable의 비교는 Equals가 아니라 = 이기 때문에 엑셀의 서식에 따라 틀어질 수 있음. 가령 Object 형태나 int 형태로 인식되어서 toString하여 비교하면 의도한 필터링이 안 되는 경우 존재. 따라서 엑셀의 형태를 통제할 수 있다면 Filter DataTable을 쓰고, 아니면 Select문을 구성하는 게 좋음

- Filter Table이 제대로 먹지 않을 때[역시 대부분 Type 인식의 문제]

=> dtOutput = (From p In dtInput.Select Where p(Column_Index).ToString.Equals("StringValue") Select p).ToArray.CopyToDataTable <==== 둘 다 타입을 String으로 맞춰버리기 때문에 엑셀 서식으로 인한 타입 차이 제거

- Select문 구성보다는 가독성 좋은 소스가 좋아서 Filter Table을 꼭 쓰고 싶다면 다음과 같은 방법이 있음

[보통 거의 2단계에서 해결]

i) 비교되는 대상에 Tostring.Trim을 적용하고 되는지 체크

ii) i의 방법으로 안 되면 Filter Table 앞에서 input Table 루프를 만들어 row("비교하려는 컬럼명")=row("비교하려는 컬럼명").Tosring 으로 Assign하고 되는지 체크

iii) i,ii 둘 다 안 되는 경우 해당 DT의 원데이터가 Excel이라면 Excel을 읽는 방식을 변경(Excel Scope <> File Excel)

- 엑셀에서 Null값을 읽었을 때, Excel Application Scope을 써서 Read Range하면 []로 들어오지만, File 패키지에 있는 Activity로 Read Range를 하면 ""로 들어옴. (DataTable에서는 둘 다 그냥 ,, 형태로 들어가 있지만 DataRow로 떼어보면 [], ""로 달라짐.) 이게 간혹 FilterTable에서 값이 어긋나는 상태를 유발하는 것일 수 있음.

- DT가 Null이면 Merge가 되지 않음. DT에 Header가 없어도 Merge는 되나 MissingSchemaAction 옵션에 따라 컬럼이 옆으로 추가됨. 따라서 정합성을 맞춰 Merge를 쓰기 위해서는 둘 다 컬럼을 없애든가 둘 다 컬럼을 맞춰줘야 함. [둘 다 컬럼을 없애면 자동생성 이름으로 맞춰짐]

- 컬럼의 순서를 바꾸고 싶다면 Method를 쓰거나 Filter Table을 써야 하는데 후자가 더 쉽고 간편함

[단, Filter Table에서 컬럼 순서를 바꿀 때 컬럼명이 틀려도 에러가 나지 않으므로 체크 필요]

- DT1의 row를 다른 DT로 할당하고 싶다면 Assign할 때 row가 아닌 row.ItemArray로 할당해야 함[일반적으로 row는 추출된 dt에 종속되기 때문. 또 이렇게 더하는 경우 넣고자 하는 컬럼의 순서가 같아야 정합성이 보장됨.]

- row는 추출된 DT에 종속되기 때문에 row를 가져가서 다른 값으로 변경하면 DT내부 값도 변경됨. Argument로 이을 때도 마찬가지므로 주의. [일반적으로 간과하기 쉬운 게 Activity들에서 output으로 DT를 받을 때는 무조건 init을 하고 받아서 이런 특성을 인지하기 어려움]

- 따라서 참조 복사를 막기 위해선 DT.copy로 다른 DT에 Assign하여 진행해야 함

- Delete Row는 하면서 index가 바뀌기 때문에 마지막 인덱스부터 삭제해야 함

- DataTable의 Count가 0인 것과 DataTable이 Nothing인 것은 다름. 둘중 어느쪽인지 특정하기 어려운 경우 Build DataTable을 통해 일단 할당을 해놓고 Count를 세는 방법을 추천. 혹은 Nothing 체크를 먼저하고 그걸 통과한다면 Count를 세는 형태로 가야 함.

- DataTable의 Count가 0인 것과 DataTable이 nothing인 것은 다름. 특정하기 어렵다면 dtData isnot nothing AndAlso dtData.rows.count > 0 형태로 써주면 됨. 그럼 Nothing이 아닐 때만 AndAlso 구문을 검사하기 때문에 에러가 안 남.

- Filter Table에서 해당 컬럼을 Int로 인식하지 못 하는 경우 대소비교는 Start with를 이용.(가령 자연수를 남기고 싶다면 Start with "-", Start with "0" 으로 필터링) 혹은 Select문을 쓰거나 해당 DT를 루프돌려서 그 컬럼값을 Cint 해주고 진행.

- DataTable에서 별도의 index까지만 추출하기 위해선 dtvar.ASEnumerable.Take(2000).CopyToDataTable식으로 씀. 반대로 특정 index까지 제외하고 가려면 Take 대신 skip을 씀.

- String으로 쌓아놓고 나중에 Generate로 DataTable을 만드는 설계는 오류 가능성이 큼. 특별한 이유가 없다면 바로 DT에 Insert. (Gernerate DataTable은 어디까지나 String으로 가져올 수밖에 없는 OCR 같은 기능을 위한 것임)

- DataTable의 컬럼 구조를 동일하게 가져가고 싶다면 한번 해당 Data를 담은 다음에 Clear DataTable해서 씀. 일반적으론 해당 DT를 유지하고 다른 DT를 만들어 내용을 담기 때문에 Assign으로 Copy한 후 Clear. [이러면 Merge를 쓸 때 내용이 없더라도 NullPointException이 안 걸림]

- 두 dt를 비교해 하나의 DT에 있는 걸 다른 DT에서 제외하고 싶을 때

dt2 = dt2.AsEnumerable().Except(dt1.AsEnumerable(),DataRowComparer.Default).CopyToDataTable

이 기능을 쓸 때 흔히 실수하는 부분

1. 비교하는 DT가 같은 구조가 아닌 경우(가령 한쪽에는 Result 컬럼을 추가했다든가)

2. 같은 구조지만 중간에 다른 값을 할당하는 구조를 놓친 경우[한 마디로 단순비교 불가한 경우]

 

- DT의 컬럼순서를 특정 리스트에 있는 순서대로 바꿔야 하는 경우 :

0. 배열하고자 하는 이름 순으로 컬럼명이 들어가 있는 List를 생성

1. List에 대한 For each 생성

2. Loop안에 invoke public method => SetOrdinal[param으로 loop의 index 지정]

 => List에 적힌 순서대로 컬럼 정렬됨

- 엑셀 내부에 '='이 포함돼 있는 경우 Write하게 되면 에러가 발생하거나 일부가 잘려서 쓰여짐. equal로 시작할 개연성이 있는 경우 체크 필수(가령 사용자 comment 등)

- 서브쿼리 : SELECT * FROM dt1 WHERE column IN (SELECT manyVar FROM dt2)

- Excel에서 Header없이 읽으면 Column0부터 순서대로 잡힘. Build DataTable는 Column1부터 잡혀있음. (엑셀에서 얻은 데이터를 Container하게 만들 테이블이 필요할 때 init 주의)

- #N/A 같은 오류들은 읽었을 때 다음과 같은 값으로 변형되기 때문에 이걸로 필터링해야 함

  • -2146826281 = #DIV/0!
  • -2146826246 = #N/A
  • -2146826245 = #GETTING_DATA
  • -2146826259 = #NAME?
  • -2146826288 = #NULL!
  • -2146826252 = #NUM!
  • -2146826265 = #REF!
  • -2146826273 = #VALUE!

전체적으로 그냥 다 막고 싶으면 -2146으로 StartWith 필터를 걸면 됨.(데이터 자체에 이런 값이 있지 않다면)

- Linq로 Groupby해서 동일한 항목은 더해야 하는 경우

(From row In dtContainer.AsEnumerable() Group row By gList = New With {Key .Name = row("키컬럼"), .이름= row("출력하려는 추가 컬럼")} Into gListGroup = Group Select dtContainer.Rows.Add({gList.Name.ToString, gList.이름.ToString,  gListGroup.Sum(Function(x) CInt(x("더해지는컬럼").ToString))})).CopyToDataTable

- 특정 컬럼에 assign 할 때 invoke 에러가 나는 경우는 보통 max length를 넘는 데이터를 assign하려고 해서 그럼. max length는 -1로 하면 제일 편하고 아니면 적절히 크게 해주자.

 

Data Scraping

- Data scraping은 페이지가 뜨자마자 데이터가 로딩되기 전에 값을 추출해 빈 값을 가져오는 경우가 많음. 따라서 Retry Scope에서 output DT의 Rows가 0인지 체크하는 게 좋음.

- [주의] datascraping시에는 title이 같은 창들이 있으면, 에러나는 게 아니라 가장 처음 거를 가져옴 => 겹치지 않도록 Retry 시 Taskkill 이나 close tab 등 필수

- Data Scrapping의 Meta Data에 변수를 쓰려면 통으로 다른 데서 String을 할당하고 그 변수를 넣는 게 편함[20.10.6 버전에서도 확장된 창에서 변수를 넣을 수 없음]

- Data Scrapping을 반복적으로 사용하는 경우 DT가 Init되지 않는 현상이 있음. 같은 Data Table로 데이터를 가져오는 경우 앞에 DataTable Init을 추가하는 게 좋음.

- [Uipath 초보 매우 추천] https://jnaul.tistory.com/333 [Scraping 종합]

Date

- 기본적으로 String Format을 날짜로 인식시키기 위해서는 CDate를 사용. (yyyy, MM, dd간 구분자 없으면 강제 인식 필요)

- 말일 계산법 : (날짜).adddays(1-날짜.day).addmonth(1) 혹은 date.daysinmonth(날짜.year,날짜.Month)

- String 변수가 Date변수로 인지되지 않는 경우, 포맷을 정해서 강제 인식. Date.ParseExact(Str,"인식형식",System.Globalization.CultureInfo.CurrentCulture).ToString("원하는형식")

- Date값에서 분을 늘리고 싶다면 date1.AddMinutes(Value) 형식으로 쓸 수 있음. 혹은 DateAdd("n",Value,date1) 식으로도 가능. (기능은 같은데 DateAdd는 조정하는 값에 대한 포맷 문자열을 알아야 된다는 것때문에 조금 귀찮음.)

- OADate(OLE Automation Date)는 숫자형태로 표현됨. 43210 같이 Double 형태로 표현되며 System.DateTime.FromOADate(43210).ToString("yyyy-MM-dd") 를 써서 DateType인 String으로 변형할 수 있음.

- OADate는 1이하로 쓰면 시간만 나옴. (1일중 몇 %인지 보면 됨)

- 날짜 계산은 연산으로 가능함. 뒤에 차이를 무엇으로 뽑고 싶은지 메서드를 붙이면 됨. (CDate("날짜str")-Today).TotalDays => 이런 경우 Double로 받아야 되지만 귀찮다면 Cint를 붙임.

- String변수가 어떤 형식이 아닐 수도 있는 경우에 Parsing하려면 "형식.TryParse"라는 함수가 있음. Date.TryParse(sTargetStr, 비어있는 Date변수)를 하면 True, False로 Return해줌.

 

Download & Upload

- 다른 이름으로 저장할 때 path를 type into로 잡으려면 send window message로 하는 게 가장 안정적인 듯[다른 거는 Device에 따라 종종 path를 바꾸지 못하고 저장됨]

- 파일을 업로드할 때 경로를 ""로 묶고 띄어쓰기를 구분자로 넣으면 한번에 업로드 됨. 다만 전체 길이제한이 있음 주의.(한영 무관하게 260자만 들어감). 이런 이슈를 피할 수 있다면 한번에 업로드하여 퍼포먼스 향상 가능.

- Wait for Download라는 Activity가 있음. 경로 입력 시 다운로드를 기다려 파일이름을 갖다 줌. 또는 alphabet 패키지의 get newest file을 통해 받으려는 파일이 제대로 다운로드 됐는지 체크 가능. 크롬의 경우 crdownload 어쩌고 하는 임시파일로 받아짐.

- 웹에서 다른 이름으로 저장 관련 Selector는 App특성에 *를 넣거나 빼면 브라우저 상관없이 윈도우식 다운로드 창이 뜨는 곳에서는 다 동작함[다운로드 체크 관련해서 브라우저 상관없이 모듈화 가능]

Element

- 셀렉터의 내용에서 대소문자 구별을 하지 않으려면 casesensitive:<attribute-name>='false'를 추가하면 됨 (ex. <webctrl casesensitive:<aaname>='false' <aaname>='Test'> 면 aaname값의 일치여부를 따질 때 대소문자를 구별하지 않음)

- 목록의 마지막 element의 index를 알기 위해서 Data Scraping으로 가져와 row count를 세는 방법도 있지만 CSS Selector의 :last-child를 붙여 TableRow, Row 같은 index 속성을 가져오는 방법도 있음

- IFRAME을 잡을 때는 iframe 관련 셀렉터를 그냥 아예 지워버리는 것이 좋음. 관련 정보가 자꾸 바뀌기 때문. 이렇게 하면 유효한 UI를 찾을 수 없다고 하는데 무시하고 그냥 해보면 잘 잡힘.

- Input Method 관련 자주 거론되는 질문 : docs.uipath.com/studio/docs/input-methods

 

Input Methods

Input actions require you or the robot to directly interact with an opened application or web page. There are three types of input methods for click and type actions, that differ in terms of compatibility and capability. We generally recommend the Simulate

docs.uipath.com

=> 기본 방식은 하드 클릭, Simulate는 타겟 앱의 기능을 invoke, SendwindowMessages는 타겟 앱에 직접 구체적인 명령을 보내는 방식이라는 듯. Type into의 경우 기본 방식을 피해야 한/영 변환 등의 입력기 오류를 피해갈 수 있음.

- Type into에서 Simulate Type을 선택하는 경우 "["가 키입력 구문으로 해석되지 않음. 기본키나 SendwindowMessages에서 대괄호를 사용하고 싶은 경우 "["를 "[["으로 Escape가 가능하다. ("]]"는 Replace하지 않아도 됨) + (Selector가 없는 경우 simulate type은 자동으로 default로 정의되어 키 구문오류 발생할 수 있음)

- element를 잡았는데 관리자 권한 확인하라고 하는 경우 해당 Target 프로그램을 관리자 권한을 빼고 수행해보면 됨.

C:\Windows\System32\cmd.exe /min /c "set __COMPAT_LAYER=RUNASINVOKER && start "" "실행할 파일 경로"

Start 프로세스로 cmd.exe까지는 프로그램 경로, 그 뒤는 Parameter로 주면 됨.

[다만 이 방법을 썼을 때 필요한 곳까지 접근하지 못 하는 경우 해당 시스템 관리자에게 문의해야 함]

- Selector에 변수를 넣고자 할 때는 {{변수명}}으로 쓸 수 있다. 혹은 Ctrl+Space을 누르면 선택창이 뜬다. [단, Arguments는 선택되지 않음]

- Selector내에서 계산이 필요한 경우 바로 계산하면 먹힘. 가령 idx = '3+{{iCnt}}*5' 식으로 쓸 수 있음. 다만 전체를 괄호로 감싼다든가 해서 계산의 Result가 int가 아닌 '(15)' 같은 형태면 안 먹힘. => 소스 가독성이 떨어지기 때문에 추천하지는 않음. 그냥 변수에 웬만하면 담아서 쓰도록 하자.

- Select Item으로 잡히지 않고 Span이나 DIV로 쌓여있는 선택 폼은 클릭-클릭 하지 않고 simulate click하면 보통 잡힘. 안 된다면 앞에 클릭을 하나 추가하면 거의 됨. (그냥 안쪽에 있으면서 클릭 트리거에 반응하기 때문에 Back단으로 클릭하면 선택됨.)

- Layer가 겹쳐진 형태(예를 들어 팝업의 팝업의 팝업의 팝업)인 경우 최상단에 있는 것을 제대로 못 잡아 올 때가 있다.(특히 모달식) 그 경우 일반적으로 Type into가 제대로 안 먹힐 수 있음(뒤쪽 레이어에 input을 때리기 때문) => image click이 필요할 수 있음

- 보통 ListItem 형태인데 DIV로 잡혀있거나, Calendar Input인데 값이 입력되지 않는 경우 Type into에서 AlterIfDisable과 Simulate Type을 설정하고 시도하면 대개 값이 변경됨. Element에 값 자체를 때려넣는 방식이라 되는 듯함. [개발자 도구에서 넣듯이]

- Object의 ID값이 자주 변하는데 위치는 상대적으로 고정된 경우 Anchor Base를 쓰면 됨. 주의할 점은 Anchor가 되는 것이든 Action이 되는 것이든 대상을 지정할 때 Anchor Base 영역 안에서 할 것. [find element + anchor base]

- Type into로 키입력 하는 방법(단, simulate type으로 하면 문자 그대로 입력됨) : key down => [d(ctrl)] /// key up => [u(ctrl)] /// key down and up [k(ctrl)] 

- 역으로 simulate type이 아닌 키입력을 하는 값이 "["가 들어올 수 있다면 체크해야 함. 그렇지 않으면 에러가 발생.

- Type into의 방식에는 default, simulateType, sendWindowMessage가 있다. default는 입력기를 타고 그대로 입력하는 방식이며 simulateType은 해당 어플리케이션과 직접 통신하고 sendWindowMessage는 dll로 통신한다. => 다른 UI 방식중에도 비슷하게 방식을 고를 수 있는 Activity들이 있음.

- Column Name으로 index 얻는 방법. DT.Columns("ColumnName").Ordinal

- Generate Data Table을 하면 구분자를 설정해 테이블을 만들 수 있음[OCR이나 PDF 등을 통해 가져온 텍스트를 구조화] => 특정한 컬럼 형식이 없다면 CSV Parse를 하는 게 가장 베스트

- AlterDisable을 체크하면 값 할당이 되지 않는 날짜 Input에도 값을 넣을 수 있음

- MES 시스템에서 그리드가 전혀 안 잡히는 경우 index를 잡기 위해서 offset을 수열로 구성할 수 있다. 가령 index 1번째 클릭이 X:30 / Y:30 이고 2번째 클릭이 X:30 / Y:40 이라면 Y:30+10n 형태로 구성할 수 있다. 다만 페이징은 상황에 따라 고민해볼 부분. [보통 page down으로 처리]

- Spotfire 같은 시스템은 특정 object를 선택하고 ctrl+c하면 해당 값이 가지는 텍스트를 가져옴. 따라서 Ctrl+a로 선택해 가져오면 데이터를 분석해 특정 처리를 하는 것도 가능하다. 다만 이슈는 파이차트 등을 클릭해야 되는 경우임

- 로딩 시에 뜨는 object는 로딩이 끝나면 없어지는 게 아니라 크기를 0으로 줄이는 경우가 많다. 이럴 때는 position이라는 속성을 통해 Uipath.core.region 타입의 변수로 담기는 정보를 받아와 구별할 수 있다. 이를 이용해 분기하는 것도 가능하지만, 굳이 그러기 보다는 로딩 중에는 클릭해도 반응이 없는 버튼을 클릭하고 클릭에 반응이 오면 로딩이 종료된 것으로 체크하는 게 더 쉽다.

- 그럼에도 Loading Region을 읽어오려면 Uipath.Core.Region 타입의 변수를 만들어 position 속성을 받고, rRegion.Rectangle.Value.Width > 0 같은 옵션을 통해 로딩이 끝났음을 알 수 있음. #Region #Rectangle

- Region을 초기화할 필요가 있다면 New Uipath.Core.Region(New Rectangle(100, 100, 100, 100)) 이런 형태로 할 수 있음 #Region 초기화

- Web에서 text를 가져오는 경우 text-overflow가 적용되어 가져올 수 있음. 보통 title 같은 것으로 보완해놓기 때문에 그걸 가져오든, 어떤 depth를 들어가서 따로 가져오든 해야 함

- Web에서 &라는 문자가 있는 경우 가져오면 &amp; 형태가 될 수 있음. 거꾸로 &라는 문자가 있을 수 있는데 해당 위치에 변수를 넣은 경우 &amp;로 Replace 해주어야 함. 이렇게 다른 형태로 변경되어 출력되는 html 버전의 특수문자들이 있음.

- UIElement가 초기화 되지 않았다라는 메세지가 뜨면 거의 Attach window나 Attach Browser가 잡혀있음. 메인 프로그램에 대한 정보가 거기 담겨있어 Element에는 생략되었기 때문에 나오는 현상. Element 자체에 Attach에 있는 정보를 추가하든 해야 진행 가능.

- 환경에 따라 Set to Clipboard 에러가 나는 경우가 있음. 이땐 Uiautomation.Activities를 업데이트 하니 해결되었음. [이외의 Set to Clipboard 에러는 빈 문자열이 아닌 null을 할당한 경우임]

Excel

- Excel Application Scope에서 Create if not exist 옵션을 쓰는 경우 파일명에 대괄호가 들어가면 안 됨(읽을 때는 상관없으나 생성 로직 중 문법으로 인식되어 오류나는 것으로 보임. file is corrupt 메세지로 출력)

- Excel application Scope은 엑셀 설치없이 사용 불가능(엑셀 설치가 안 된 경우 system-file-workbook에서 사용)

- 행의 Header를 특정해야 되는 경우 범위를 잘 지정해야 함. [전체를 읽으면 무조건 첫 행이 헤더로 인식됨]

- 엑셀에서 Null값을 읽었을 때, Excel Application Scope을 써서 Read Range하면 []로 들어오지만, File 패키지에 있는 Activity로 Read Range를 하면 ""로 들어옴. (DataTable에서는 둘 다 그냥 ,, 형태로 들어가 있지만 DataRow로 떼어보면 [], ""로 달라짐.) 이게 간혹 FilterTable에서 값이 어긋나는 상태를 유발하는 것일 수 있음.

- Excel Application Scope의 Save Changes 옵션은 값이 하나 바뀔 때마다 세이브함. 따라서 파일이 무거운 경우 옵션을 제거하고 단계별로 save workbook을 쓰는 게 좋음. [이래야 디버깅용 자료 떨구기도 좋을 듯]

- 엑셀에서 Column Name을 가져올 때 EasyExcel의 get Column Name을 쓰면 됨. [int값만 입력하면 알파벳 리턴해줌]

- (주의) 엑셀에서 뜨는 Prompt창 일부에서 Type Into를 쓸 때 Empty Field를 선택하면 Excel Range String이 들어가는 경우가 있었음. ($A$14:$C$99 선택했던 범위 뒤로 Text가 Append됨) 

- UP에서 Join은 출력열을 조정하지 못 해서 무조건 각각 컬럼이 다 나옴. 가령 Key, Value / Key, Value 인 DT 2개를 Join했을 때 Key, Value, Key_1, Value_1 형태로 결과가 나옴. 이런 경우 그냥 Filter Table로 한쪽을 잘라서 쓰는 것도 방법

- 엑셀을 읽을 때 시트에서 한 DT만 읽어올 거라면 시작셀만 써도 알아서 읽어옴. 다만 DT를 2개 이상 가져와야 된다면 더 큰 범위에 있는 DT의 범위를 구체화 해야 함. (ex. Sheet1 // A1 || Sheet1 A15:E30) => 범위 자동인식에 대해 파일마다 이슈가 있을 수 있으므로 동적으로 가야되는 경우가 아니면 입력.

- VLOOKUP이나 INDEX 등 참조함수를 걸어주는 경우, 해당 엑셀 파일이 아닌 다른 엑셀 파일에서 걸어주는 경우 Target 엑셀을 연 상태에서 작업해 주어야 함. [Target Excel을 바깥쪽 Scope으로 감싸 진행]

- VLOOKUP이나 INDEX 등 참조함수를 쓴 경우, 일반적으로 쓰고나서 값복사를 통해 덮어쓰기 해주는 것이 좋음[현업이 받았을 때는 Target 엑셀이 없을 가능성이 크므로]

- 엑셀의 경우 Scope로 Open한 다음 Attach - Maximize할 때 Title을 그냥 '*' 형태로 할당하면 에러가 남. 원인은 모르겠으나 '*Excel*' 형태로 고치면 해결됨. [아마도 Excel.exe 관련 다른 프로그램이 켜지면서 창을 혼동하는 Exception이 뜨는 게 아닌가 하는 추정만 하고 있음]

- Excel Scope에서 꺼질 때 저장하는 기능은 필터링이나 영역선택을 저장하지는 않음. 그것까지 저장하고 싶다면 따로 Save Workbook 기능 사용해야 함.

- Excel Autofill을 하는 경우 한 줄이 아닌 여러 줄의 범위 Autofill을 하면 수식이 아닌 값일 때(가령 =VLOOKUP~~ 가 아닌 20210510일 때) 각각 다르게 동작함. 한 줄인 경우 복사가 되지만 여러 줄 범위가 되면 ROW에 따라 값이 변화함. [Autofill할 때 Ctrl을 누른 효과 / 아닌 효과가 각각 적용됨]

- xls파일을 xlsx로 Convert해야 하는 경우 “C:\Program Files\Microsoft Office\Office16\excelcnv.exe(해당 경로가 없다면 32비트 프로그램 폴더 또는 다른 버전에서 찾아보자) "-oice “"{input 파일 경로}”" ""{output 파일 경로}”"" 형태로 Command를 입력하는 게 가장 안정적. [Start Process를 이용해 앞단은 프로그램 경로에 -oice부터는 파라미터에 입력] (enc 같은 파일에서 변환하는 것도 가능해 보임)

- 특정 엑셀 파일에 대해 수기로 열면 문제가 없으나 UP로 열면 HRESULT가 뜨는 경우, NPOI(Author : NPOI Contributors)를 설치하면 보통 해결됨. 이는 NPOI가 엑셀을 Parsing 하는 데 다양한 예외까지 잡고 있기 때문으로 보임. (이 라이브러리는 엑셀이 없든 있든 동작해야 되므로)

- 특히 System-File에서 Workbook을 활용하는 경우 파일 문제는 거의 NPOI로 해결이 가능. (POI는 아파치에서 만든 엑셀 라이브러리이고 NPOI는 그것의 .Net 버전임)

- 엑셀에서 포맷을 안 바꾸고 싶으면 Excel scope에서 preserve format 체크 => 다만 row를 99999 이런 형식으로 쓰는 경우 매우 느려짐.[그 라인까지 포맷체크를 다 하기 때문] Read Column을 통해 Row Count를 잡고 필요한 줄만 체크

- file workbook을 쓸 때 숨김시트가 있고 잘못된 참조를 포함하는 경우 에러가 남(수식이 먹지 않는 경우도 생김) => 웬만하면 Excel Application Scope으로 진행

- Delete Row는 하면서 index가 바뀌기 때문에 마지막 인덱스부터 삭제해야 함

- BalaReva의 엑셀 시리즈에서 리스트를 넣어 row를 한번에 삭제하는 기능이 있으나, 리스트가 일정 크기 이상이되면 한번에 삭제가 되지 않음. 안 되면 Reverse해서 각각 지워야 함.

- Excel 데이터 서식을 바꿔야 하는 경우 BalaReva 엑셀시리즈 중 Change Cell Type으로 가능.

- 엑셀에서 날짜나 시간이 숫자로 읽히는 경우가 있는데, 그 경우 보통 OADate임.

- 엑셀에서 줄바꿈은 chr(10)으로 치환됨(environment.newline(chr(10)+chr(13))은 다른 줄바꿈임.)

- 엑셀에서의 줄바꿈을 변수로 불러서 쓰는 경우 \n으로 저장해놓고 chr(10)으로 치환해야 함

- 줄바꿈을 Replace 하려는 경우 chr(10)이나 chr(13)+chr(10)으로 쓰는 게 안전함. \n은 인식 못 하는 케이스가 있음.

- Excel Application Scope이 생각보다 불안함. 자주 에러나는 케이스의 경우 Try Catch로 감싸고 재시도 해줘야 되는 경우도 있음.

- Excel 필터에서 검색 기능을 쓸 때 (모두 선택)이나 '검색 결과 없음'은 팝업이 떠있다면 항상 존재함. 따라서 Continue On Error로 검색하는 것을 찾든 다른 형태로 체크해야 함.

- Excel 파일을 새로 만들 때 대괄호([ ])가 포함되면 생성되지 않음[기존 파일 이름에 대괄호가 포함되어 있어 읽는 경우는 문제가 없으나 생성하는 로직 중 문법에 대괄호가 포함된 것으로 보임]

- Excel Scope에서 Save Changes를 체크하는 경우 속도가 더 느리고 캐시 부담이 더 많이 감. 이걸 체크하면 다시 시도해야 될 때 파일을 초기화하기 어렵고, '다른 사용자가 파일을 사용 중입니다.' 에러가 더 자주 발생함. instancecaheperiod를 0으로 맞추고 save changes를 끈 다음 save workbook으로 처리하는 게 가장 깔끔

[원인을 정확히 특정할 수가 없으나 발생하면 동시다발적으로 발생하는 것으로 보아 환경적 요인으로 보임]

- Find는 Anchor를 쓸 때만 씀. 다른 용도는 사실 없다고 봐도 무방하지 않나 싶음.

- 셀에 색을 입히고 싶을 땐 Set Range Color를 씀. Color는 system.Drawing.Color.Red 식으로 지정.

- Excel에서 Header없이 읽으면 Column0부터 순서대로 잡힘. Build Data는 Column1부터 잡혀있음.

- Read Cell을 했는데 Converter 관련 에러가 나오면 output을 String이 아닌 Object로 받으면 해결됨. [Uipath가 판단한 변수 타입이 아니어서 에러난 것이기 때문] (이와 관련해 구글시트에서는 값을 Object로 받도록 강제하기도 함]

- Read Range를 할 때 틀고정된 파일 등은 Starting Cell만 적으면 무한펜딩이 걸리는 케이스가 있음. 요청 파일을 받아서 진행하는 과제의 경우 웬만하면 Read Colmun으로 Row수를 알아내어 End Position까지 입력해주는 게 좋음

- 엑셀에서 함수식을 쓰는 경우 =A:A 가 =@A:A로 변하는 버전이 존재. 원인은 수식 언어가 업그레이드 되면서 레거시를 호환하기 위해 자동으로 삽입되는 것으로 파악하고 있으나 이 기능을 끄는 방법을 아직 발견하지 못 했음. Select Range로 셀을 선택하고 클립보드에서 붙이는 방식으로 개발하는 것이 좋을 듯. [Empty Field 같은 기능이 이상하게 먹히므로 del키 + 붙이기 형태로 send hotkey를 나눠쓰길 권장]

Exception

- Rethrow를 하면 안쪽에 있는 Try Catch에서 뱉은 Exception을 그대로 Throw 해줌[이중 Try Catch 구조일 때 유용]

- Invoke된 파일에서 Rethrow하면 인수값이 넘어오지 않음. Throw가 되더라도 특정 인수값을 넘겨야 한다면 Exception에만 담아두고 밖에서 변수값을 체크해야 함.

- 변수를 할당하고 만들 때는 일단 그것이 null일 수 있다는 가정을 해야 함(특히 Dictionary, List 같은 변수들 초기화 필수)

- Exception관련 초기화를 위해 프로그램을 끌 때 kill process가 간혹 안 먹히는 경우가 있는데 이를 강제로 종료하려면 Start Process에서 "taskkill.exe" / 파라미터로 "/f /im 종료하려는프로그램" 형태로 쓰고 뒤에 딜레이를 2~3초 정도 부여. (딜레이를 부여하는 이유는 바로 다음에 해당 프로그램을 켜면 Taskkill 중에 프로그램이 켜지면서 종료되는 케이스들이 있기 때문. 여러개 프로그램을 종료 하려는 경우 /im을 붙여가면서 추가하면 됨.)

-- taskkill 사용시 tray에 잔상이 남아있는 케이스가 있는데 그 경우 taskill /im explorer.exe /f를 한 후,  start explorer.exe를 해주면 사라진다. 다만 메모장이나 탐색기 등 explorer의 자식 process도 함께 꺼진 후 다시 켜지기 때문에 그 부분은 감안할 필요가 있다. 대부분의 프로세스에서는 상관없을 것으로 보인다.

- Kill Process로 하면 간혹 안 먹고 살아있는 경우가 있다. 그 경우 확장자를 안 뺐을 확률이 큼. ex) chrome.exe 대신 chrome

File

- File Size 체크를 하는 경우 Int64 변수를 하나 만들어서 New System.IO.FileInfo("경로").Length 를 할당해 체크

- Folder의 경우 Folder Loop를 돌려도 되긴 하지만 Get Folder Info를 한 후 Output에 SizeInKB라는 메서드가 있음.

- 경로에서 ".."을 넣으면 상위폴더로 넘어감. path.combine("C:\","Temp","Test","..","Babo") = "C:\Temp\Babo"

GIT

- github로 연결 시 아직 프로그램 내부에서 Rollback하는 기능은 없음(SVN보단 불편함. 로컬 git으로 설치하면 괜찮은지는 확인 안 해봤음.)

- 프레임워크 같은, 많은 사람들이 수정, 개선할만한 소스인 경우 나쁘지 않아 보임

- Uipath를 github에 연결한 상태로 Repository 이름을 바꿔도 연결에는 영향도가 없음

Google API

- 구글 API는 https://console.cloud.google.com/ 에서 서비스 계정을 만들고 쓰려는 APP에 대해 허용해주는 방식이 가장 무난함.

구글 클라우드 키 생성.pptx
0.97MB

- 언제부터 바뀐지는 모르겠으나 Cloud Vision 같은 API는 Billing Account를 설정해야 함(2022. 03. 02. 기준)

- Cloud Vision Activities를 쓰는 경우 Service Account Key보다 API Key를 쓰는 게 더 간단함(Service Account Key는 scope이 제대로 돼있지 않다는 오류가 뜨는데 정식 App 등록을 하고 프로젝트 승인을 받으라는 것으로 보임)

- 아래 소스는 reCaptcha를 회피하기 위해 만들어본 소스이나 실제로는 환경세팅으로 회피하는 게 더 적절(다만 구글 Cloud Vision API를 쓰는 2가지 버전의 소스가 있으니 참고

 

captch2-demo-main.zip
3.58MB

- Google Sheet의 Copy and Paste 기능은 제대로 동작 안 하는 것으로 보임(2021.05.24. 기준)

- Google Sheet는 데이터 Queue가 제한되어 있음(minute limit, quantity limit once). 따라서 데이터가 많다면 퍼포먼스가 좀 내려가긴 해도 잘라서 올려야 함. dt1을 써야 되는데 너무 많아서 5천줄씩 올린다라면 dt1.Rows.count mod 5000만큼 도는 루프를 만들어 올리고 나머지를 올림.

- dtContainer = dt1.ASEnumerable.Skip(5000*idx).Take(5000).CopyToDataTable 이런 형태로 자르고 Container를 전달하는 방식. 당연하게도 Queue limit 때문에 쓰는 거니 루프의 delay를 많이 주는 것이 안정적. [+ 고객사에 유료고객 전환을 요청.]

- 데이터 제한 이외에도 접근하려는 구글시트에서 수식을 계산하고 있는 경우, 접근하면 에러가 남. 그런 가능성이 있는 시트에 접근하는 경우 for each + try catch를 통해 방어로직 구현 필요.

If

- 21.10부터 Else IF가 추가됨. 기존에 가독성을 위해 IF A / IF A&B 같은 형태로 썼던 소스들이 간소화될 수 있게 됨. 특히 A&B에서 B가 A가 충족되지 않으면 에러가 나는 경우(예를 들어 isnot nothing이 성립되어야 count가 성립하는 식)에는 어쩔 수 없이 겹쳐지는 케이스들이 있었는데 그 케이스들도 가독성을 가져가면서 개발하기 쉽게 됨.

- 3항 연산자 사용 가능. If(조건식,True인 경우,False인 경우) => String 아닌 경우에도 사용 가능함. 특히 BusinessRule Exception 변수와 System Exception 변수를 구분하여 에러메세지를 작성하는 경우 if(eSysExp isnot nothing, "Unexpected Error", eBusinessExp.Message) 같은 형태로 많이 쓰게 됨.

List

- list에서 다른 list에 있는 값 제외하기 : lList1.Except(lList2).ToArray

- System.Collections.Generic.List<System.Int32>로 List를 만들고 New List(Of Int32) 같은 형태로 생성할 수도 있음[좀 더 일반적으로 쓰는 것으로 보임. 이걸로 해야 Invoke Method인 Sort나 Reverse 같은 걸 쓸 수 있음] => 이제 string[] 변수도 해당 기능이 생겼으므로 그냥 라이브러리의 취향차이라 생각하면 됨.

- List는 System.Collections.Generic.List 형태로 만들어야 다양하게 쓰긴 하지만 정말 Append 정도만 하고 싶다면 String[]도 괜찮음. 선언은 New List(Of Type)이 아니라 {}로 하면 됨.

- 폴더의 파일 리스트를 ","나 줄바꿈으로 Join하고 싶다면. String.Join(","+Environment.NewLine,lList1) 형태로 쓸 수 있음

- List에서 Sort를 쓰기 위해선 Linq를 쓰는 게 가장 무난. arrTest.OrderByDescending(Function(x) x).ToArray() // arrTest.OrderBy(Function(x) x).ToArray()

- List에서 특정 index에 있는 값 없애기. (주의할점 : Enumerable Loop로 없애는 경우 큰 index부터 지워야 함) https://forum.uipath.com/t/how-can-i-delete-a-element-from-a-list-of-string-in-uipath/52817/6

 

How can i delete a element from a List of String in UiPath

@Rishabh_Lakhera Thank you for your comment!! Finally I was able to get what I wanted, Very friendly 😉

forum.uipath.com

License

- Studio와 Attended는 AD 계정이 겹칠 수 없음. Unattended는 겹칠 수 있음. 이러한 차이는 인증방식의 차이에서 발생. Studio와 Attended는 오케와의 통신이 필수적이지 않기 떄문에 인증 시 AD계정을 PK로 가져감. Unattended는 어차피 오케와의 통신으로 컨트롤되기 때문에 Runtime 방식으로 인증되므로 AD계정이 겹쳐도 무관함. 따라서 특정 AD계정에서만 작동해야 하는 시스템에 대해 개발하는 경우 한 AD계정으로 동시개발을 할 수 없음. 다른 AD계정으로 개발할 수 있는 Studio를 세팅해야 함.

Loop

- Times 반복문 : For each에 enumerable.range(startindex,n)을 넣어 n회 수행(ex. (1,3)이면 1,2,3. (0,3)이면 0,1,2)

- loop를 2개 겹쳐 쓰면 item이라는 이름이 겹쳐 의도한 로직대로 수행되지 않을 수 있음(변수명 안 겹치게 잘 써야 함)

- Index를 담은 컬럼이 있다면 조건에 부합할 때 Index만 담아두었다가 삭제 등을 할 수 있음[굳이 루프 전체를 다시 훑으며 가지 않아도 됨]

- File in Folder loop를 쓰면 CurrentFile이라는 item을 쓸 수 있는데 Name 특성도 있고, FullName 특성도 있다. 파일을 컨트롤 해야 한다면 폴더루프를 쓰면 소스를 단축시킬 수도 있다. (원래는 file list get하고 그걸로 for each 돌려서 파일이름만 필요하면 따로 떼고 하는 식)

 

Orchestrator

- Studio와 Attended는 AD 계정이 겹칠 수 없음. Unattended는 겹칠 수 있음. 이러한 차이는 인증방식의 차이에서 발생. Studio와 Attended는 오케와의 통신이 필수적이지 않기 떄문에 인증 시 AD계정을 PK로 가져감. Unattended는 어차피 오케와의 통신으로 컨트롤되기 때문에 Runtime 방식으로 인증되므로 AD계정이 겹쳐도 무관함. 따라서 특정 AD계정에서만 작동해야 하는 시스템에 대해 개발하는 경우 한 AD계정으로 동시개발을 할 수 없음. 다른 AD계정으로 개발할 수 있는 Studio를 세팅해야 함. [특이한 케이스]

- 운영 VM을 복사하는 경우, 복사하는 시점에 해당 VM이 job을 실행하고 있는 경우, 복사된 VM에서도 job이 실행되고 곧바로 실패처리되어 같은 작업에 End Time이 찍히는 케이스가 있음. 다만 원본 VM에서는 계속 job이 정상 수행됨. [Process - device(robot)의 결합을 unique한 조합으로 보고 연결하기 때문에, 환경이 복사되는 경우 job의 로깅이 꼬일 수 있음]

- 스튜디오 구버전들에서 개발된 소스들은 1.0.7823.12009 같은 식으로 버전이 나오는데 이를 최신 스튜디오로 편집해서 다시 올리면 버전업이 제대로 되지 않을 수 있음. 이때는 버전을 올릴 때, 1.0.8000.20000 같은 식으로 숫자를 크게 하여 최신 버전으로 인식시키면 됨.

- Trigger를 걸 때 파라미터를 주면 Start Job으로 된 과제와 구분이 가능

- 특정 로컬에 패키지 초기 설치가 제대로 안 된 경우에는 시작되었습니다. 종료되었습니다. 하는 로그만 남는 케이스가 있음. 이 경우는 누겟폴더를 찾아 직접 주입을 해주자. [이런 경우는 외부와 폐쇄망이거나 새로 VM을 할당받아 세팅했을 때 간간히 일어난다]

- 오케스트레이터 관련해선 가이드 문서를 통해 그나마 최신 정보를 확인

https://jnaul.tistory.com/259?category=853631 

 

오케스트레이터 가이드 :: 개발 갈무리

 

jnaul.tistory.com

- 오케스트레이터 폴더의 경로를 쓸 때는 "/"로 구분한다. 최상위는 그냥 쓰면 된다.

ex) "MainFolder/SubFolder1/SubFolder2"

- assistant에서 main(entry point)에 있는 argument를 넣을 수 있게 됐다. 다만 assistant에서 실행시키면 string 값이 null 되는 게 아니라 "" 빈 문자열로 들어가므로 체크 시 감안해야 한다.

 

 

 

Queue

- 'Queue'와 'Transaction'은 최초 상태에 대한 차이가 있다. Queue의 경우 Add 했을 때 프로세스의 과정 중 하나로 더해지기 때문에 New로 기록되지만 Transaction은 이미 한 프로세스를 시작하면서 동작하므로 In Progress로 기록된다.

- QueueItem은 Reference라는 Key를 할당할 수 있다. 해당 key를 통해 Filtering할 수도 있기 때문에 하나의 Queue Add하는 과제를 두고 Reference를 과제번호로 맞추면 하나의 Queue로 필터링하여 각각 다른 과제를 실행할 수도 있다.

 

Regex

- 정규표현식에서 자리수와 구성이 특정된 경우 ^구성조건$ 형태로 씀. (ex. 10자리 숫자로만 구성 => [^0-9]$) ^와 $를 쓰지 않으면 구성조건 앞뒤로 다른 문자, 숫자가 와도 True가 됨에 유의. 따라서 문자열에 특정 구성이 포함돼야 한다면 ^와 $를 빼고 쓰면 됨.

- Uipath에서 Regex를 할 때는 ^를 안에 넣어야 함. ex) ^[0-9]는 안 먹음. => [^0-9]

- Regex는 System.Text.RegularExpressions를 Import하고 쓰는 게 좋음.

- Regex.Replace(sTargetStr,"바꿀Regex표현형식","바꿀String값")으로 하면 string값에서 숫자만 걸러 낸다든가, 영어만 가져온다든가 할 수 있음

- System.Text.RegularExpressios.Regex.Replace(item.ToString,"\s+"," ") [빈 칸 여러 개 있으면 하나로 만들어 줌]

- Regex.replace(sInputString, "[^0-9|^a-z|^A-Z|^ㄱ-힣|^#|^&|^-|^_]","") [이모지 제거하고 DB에 넣기 위해 이렇게 만들었음]

Retry Scope

- Retry scope에서 가장 무난한 조건 값은 Is True인 것으로 보임[현재 check true라는 이름으로 변경됨]

- Retry scope을 대기시간만을 위해 쓰는 것은 적절하지 않음. Action에 뭐라도 Trigger가 있어야 함. (클릭이나 type into 같은 Action Trigger) 대기시간을 위해서라면 Timeout을 길게 늘이는 게 좋음.

- Retry Scope에 조건을 부여하지 않으면 모두 에러가 나지 않을 경우 그대로 진행함. 그러나 이는 Retry scope을 잘못 쓰고 있는 것. 보통 Action Trigger들이 에러가 난다는 건 페이지 로딩이 늦는 등의 문제기 때문에 Retry보단 Timeout으로 대체 가능함. 굳이 인식할 수 있는 정보를 잡지 않고 Retry하는 것은 세부 로깅만 잃어버리게 하므로 조건을 부여하지 않을 거라면 Retry를 이용한 방어로직을 쓰지 않도록 함.

- Retry Scope은 중간에 에러가 나도 Catch로 뛰지 않고 재시도함.[내부에 Catch가 포함돼있는 듯. 다만 exception이 제대로 떨어지지 않기 때문에, Retry Scope은 디버깅을 위해서라도 최대한 간단하게, 짧게 끊어서 써야 함.]

- Retry Scope은 에러가 나면 처음부터 다시 시작하기 때문에 init을 위해 일단 끝까지 진행돼야 하는 경우라면 continue on error를 설정해주자. [은근 이런 케이스가 많다]

SAP

- SAP Activity에서 Call T-Code를 쓰는 경우 /n을 치지 않아도 어디서든 이동함

- SAP 조회화면에서 Shell로 잡히는 곳의 레이아웃 선택 시 Select Menu Item으로 선택하면 한글 인코딩은 깨지는데 선택 가능해짐

- SAP에서 가장 많이 일어나는 문제는 권한 문제. 셀렉터가 잡히지 않거나 코드가 동작하지 않으면 대부분 관리자 권한으로 SAP이 켜졌을 확률이 높음.

ScreenShot

- [현재 테스트 중] Take Screenshot을 전체화면으로 찍을 때 간간히 에러가 나기도 하는데(RDP 세션이 물려있다든가 혹은 절전모드, 로그오프 등이 진행된 상태), Clipping을 아예 잡아주면 완화. 이벤트 뷰어에서도 핸들링 관련 에러가 나는 걸 보면 Windows에서 해상도(Resolution) 관련 값을 주지 못해 발생하는 것으로 보임.

Script

- Inject JS에서 크롬기준 Jquery는 안 먹음. 보통 console창에서 먹는 JS는 먹는데 간간히 안 먹는 사이트도 있음. (Click 같은 걸 하려면 ID값을 추천. JS에서 ClassName은 click 메서드 자체가 없는 듯)

String

- 문자열 구성은 String.Format(텍스트 변수, 파라미터1, 파라미터2, ....) 으로 하는 게 가장 깔끔해 보임. 파라미터가 들어갈 곳을 {0}, {1}, {2}, ... 로 쓰고 각각 할당. 파라미터들 대신에 리스트 변수를 써도 순서대로 들어감.

- String.Format안에 중괄호 자체를 쓰고 싶은 경우 {{, }} 식으로 Escape 해야 함

- 타겟 문자열이 특정 문자열의 앞뒤로 존재하는 경우(Before-After) : https://jnaul.tistory.com/240

- Path.combine(경로1,경로2,....) => 앞 변수에 \가 붙었냐 안 붙었냐 신경쓸 필요없이 이어서 경로로 만들어 줌.

- Path에 ".."을 포함하면 상위폴더로 인식 ex) C:\Test\Test2\..\test.xlsx => C:\Test\test.xlsx

- LocalPath 가공이 필요한 경우 : Path.Combine(Environment.CurrentDirectory,"Data/issue.xlsx")

- 어떤 변수에 빈 칸만 입력하고자 할 때 Space(n) 형태로 입력(n은 몇 개 쓸지)

- 텍스트끼리 대소 비교 가능[char No로 우선순위 결정되는 듯]

- Password를 Plain Text로 바꾸기 => plainStr = new System.Net.NetworkCredential(string.Empty, secureStr).Password [PW입력을 입력하는 경우 사용]

- 반대로 Plain Text를 password화 시켜야 되는 경우 SecureStr = new System.Net.NetworkCredential(string.Empty, Password).SecurePassword

- 폴더의 파일 리스트를 ","나 줄바꿈으로 Join하고 싶다면. String.Join(","+Environment.NewLine,lList1) 형태로 쓸 수 있음

- 정규식으로 Replace 쓰기. Regex.Replace(대상Str변수,정규식,대체될문자열) 

 (예를 들어, 숫자가 아닌 것들은 다 없애고 싶다 => Regex.Replace(sTest,"[^0-9]","") 식으로 쓸 수 있음)

[Regex가 바로 안 되는 경우 System.Text.RegularExpression.Regex~~ 로 쓰거나 Arguments 옆에 Import 탭에서 System.Text.RegularExpression를 추가하면 됨]

- Get Password의 경우 소스가 옮겨가면 오리지날 문자열을 다시 적어줘야 함

다시 안 적으면 "get password: 키를 지정된 상태에서 사용하기에 부적합합니다." 라는 메세지가 뜸.

 

Task

- 실행되고 있는 특정 program을 가져오려면 system.Diagnostics.Process.GetProcessesByName("chrome") 식으로 가져올 수 있다. (return은 process[]) count가 0보다 크냐로 보면 지금 실행되고 있는지 아닌지도 체크할 수 있다.

 

 

Uipath Tool

- Uipath에서 간혹 Drag & Drop이 안 먹히는 경우가 있음. 그 경우 ESC를 누르면 해결됨.

[뭔가를 처리하다가 끊긴 게 제대로 Exception 처리가 안 돼서 일어나는 현상인 듯]

- 스니펫 소환 => Ctrl+Shift+J

- 변수의 Scope을 잘 이용하면 시퀀스만 복사해서 비슷한 류의 코드를 빠르게 짤 수 있음

- 여러 케이스를 동시에 판단해야 되는 경우 Parallel을 이용해 각각 Exist 등의 Activity를 넣고 해당 변수를 Parallel Exit의 조건으로 작성. bTest1 Or bTest2 Or bTest3

- Parallel을 응용하면 Dialog의 Time-out도 줄 수 있음[Dialog를 켜놓고 click의 Before Delay를 조정]

- Xplatform도 아닌데 안 잡히는 경우, Plug-In을 살펴봐야 함. 보통 크롬의 경우는 잘 알려져 있으나 Java 프로그램 같은 경우도 플러그인이 깔려있는지 체크 필요. 일반적으로 잘 잡힘.

Xaml

- Invoke시 인수 대소문자 구별해야 함. 구별 안 하면 null값이 됨.

- 파일 소스를 열 수 없고 특정 위치를 명시하는 에러가 뜬다면 xml이 꼬인 것. 해당 위치에 있는 Argument를 다른 Argument들의 형태와 맞춰주고 조정하다 보면 다시 살리기 가능함. 원인은 아직 불명이고 간헐적으로 나타남. (자주 발생한 개발자나 Device에서 더 자주 발생하는 것으로 보아 특정 개발자의 습관에 관련되지 않았을까 추정)

 

Zip

- Compress(Zip)의 경우 System Activities를 업데이트 하면 기본 Activities가 존재

- Files로 해놓고 폴더와 파일을 같이 입력해도 잘 압축됨(Files와 Folder가 나뉘어 있는 이유는 폴더 버튼을 눌렀을 때 어디까지 보이게 할 건지를 체크하고자 했던 것으로 보임. 다만 User에겐 별 의미가 없는 듯)

 

포럼에서 봐도 20년 12월쯤에 아직 해결중이라는 댓글만 달려있는 에러

0xE0434352

기본적으로 근본 원인은 닷넷의 버전 문제로 보인다.

그럼에도 .Net Apache POI인 NPOI 패키지 버전을 올렸다가 내렸다가 해봤지만 해결되지 않았다.

[Uipath Studio Ver. 2020.10.4 | NPOI Ver. 2.3.0 -> 2.5.3]

현상적인 원인은 데이터의 인식에 있다.

일반적으로 Read Range를 하면 Starting Cell만 기입해도 값이 있는 부분만 자동으로 인식이 된다.

그러나 특정 파일의 경우, Starting Cell만 입력하거나 ""으로 입력하면 엑셀에서 수용가능한 모든 셀을 읽어오다가

메모리가 터진다.

 

결과적으로 엑셀을 업그레이드 하면 좋겠으나 보통 사이트에서 그런 위험을 감수하고 싶진 않아 한다.

RPA로 우회하는 방법은 2가지가 있다고 본다.

1. 엑셀DB로 연결해 Select

2. 넉넉한 Row를 할당하고 빈 칸을 Filter Data Table[혹은 Remove Duplicate Row]

기존에 이미 개발이 된 상태라면 2번, 아직 개발 전인데 이슈가 알려져 있다, xlsm 파일이다 라면 1번을 추천한다.

과제 개발 시 Combo box는 다양하게 나타나지만 결국 값을 입력하기 위한 input element이다.

Select Item으로 선택되지 않는 combox의 값을 select하는 방법을 3가지로 나눠봤다.

[Select Item은 무조건 먼저 해보길 권장한다. 리스트형인 모든 element에 이것 먼저 해보도록 하자]

 

1. (Click) + Type into

- Type into는 옵션을 어떻게 선택하느냐에 따라 기능이 깡패기 때문에 AlterIfDisable, Empty Filed, Simulate Type을 선택하면 그냥 선택하는 거든, 쓰는 게 막혀있는 거든 웬만해선 다 적어버린다.

- inner text를 주입하는 수준이기 때문에 딱 봐도 안 될 거 같다면 이 방식부터 쓰길 권장한다.

- 다만 몇몇 콤보박스의 경우 click을 Trigger로 값이 로딩되는 경우가 있으므로 click 추가 후 after delay를 주기 바란다.

 

2. (click) + Set Text

- 태그에 inner text를 주입하는 원리에 가까움 

- 다만 Type into는 키별 주입을 한다면 Set text는 String값 자체를 한번에 주입하는 느낌[그래봤자 비슷하다]

- 1번을 우선 해보고 안 될 때 시도

 

3. (click) + click

- 될 거 같은데? 하는 콤보박스라면 이거부터 시도하길 바람

- 뒤쪽의 클릭은 simulate type을 걸어두어야 스크롤이 생겨도 문제가 없음

  => 다만 제대로 submit 되는지 필히 체크해야 함. simulate 방식 특성상 값이 들어간 것처럼만 보이고 실제론 container에 들어가지 않았다든가 하는 경우가 있을 수 있음. 다만 한번 제대로 성공한 걸 확인했다면, 그 후론 헛클릭, 헛타이핑하지 않음. (simulate를 쓰는 이유. Default나 SendwindowsMsg는 그런 케이스가 1000번하면 대략 3~4번쯤 존재)

- 다른 방식은 값이 없어도 에러가 안 나기도 하는데, click은 높은 확률로 없으면 에러가 남 [정합성 검사 유리]

- 스크롤을 해야만 클릭이 되는 케이스도 있으므로 그 경우는 스크롤을 하면서 에러가 나지 않을 때까지 반복시키는 형태로 구성해야 함.

 

4. click + double click

- 클릭을 제대로 했음에도 불구하고 값이 default로 다시 바뀌는 현상(iframe환경)

- 클릭 후 더블클릭(simulate)하여 해결되었다고 함(before delay도 추가)

- 추정으로는 Selector가 실제 submit되는 값의 바깥쪽으로 잡혀서 제대로 Trigger가 되지 않은 것으로 보임

- 이 경우 첫번째 클릭이 일종의 그 dropdown list를 선택하는 형태가 되므로 default로 변경되는 것도 설명할 수 있음

- 비슷한 증상이라면 시도해볼만함

크로미움 엔진이 캐시를 랜더마이즈하게 저장하여 제대로 안 지워진다는 말을 듣고 수정함

방법1. 크롬을 아무 사이트로나 켜고 ctrl+shift+del을 눌러줌 => 캐시 삭제 클릭

방법2. 크롬을 켤 때 캐시 저장할 target 폴더를 파라미터로 지정 [invoke code나 start process 등 이용]

 

 

 

++ 추가 확인 이슈 : 간헐적으로 쿠키가 제대로 지워지지 않는 케이스를 발견함

++ 하위 폴더까지 강제 삭제 하도록 -recurse -force 옵션 추가

++ Sessions, Session Storage, Network 폴더 추가[각주:1]

 

보통 세션, 쿠키가 꼬이는 경우 프레임워크의 init단에 끼워넣을 수 있다.

최근 프로젝트 사이트에서 IE의 EOM종료로 인해 크롬으로 많이 갈아타는 추세기 때문에

크롬을 사용하는 사이트에서는 프레임워크의 killprocess 하는 소스 다음 부분에 쓰길 권장한다.

Powershell 코드를 쓰는 게 가장 베스트로 보여 갈무리 한다.

 

원본 코드 : https://forum.uipath.com/t/clear-cache-in-chrome-powershell-or-cmd-prompt/195110

 

Clear Cache in Chrome - Powershell or Cmd Prompt

Gurus, I have a process that runs for a bit and unfortunately I see chrome crashing with “Aw Snap”. In order to overcome this issue I am trying to clear the cache periodically via a Powershell or cmd line. I don’t want to use the screen so it appears

forum.uipath.com

 

1. Invoke PowerShell Activity를 가져옴

 

2. IsScript 체크

 

3. Type Argument를 String으로 변경

 

4. 스크립트에 다음과 같은 코드를 넣어줌 [각각 다른 액티비티로]

"taskkill.exe /im chrome.exe /f"+Environment.NewLine+"Start-Sleep -Seconds 2"

"$Items = @('Archived History','Cache\*','Network\*','Cookies-Journal\*','Cookies','History','Login Data','Top Sites','Visited Links','Web Data','Sessions\*','Session Storage\*')"+Environment.NewLine+"$Folder = ""$($env:LOCALAPPDATA)\Google\Chrome\User Data\Default"""+Environment.NewLine+"$Items | % { if (Test-Path ""$Folder\$_"") {Remove-Item ""$Folder\$_"" -Recurse -Force}}"

 

[내용을 보면 크롬 기본 유저의 쿠키 및 캐시, 방문기록들을 지워주는 코드이다. 멀티 프로필을 쓴다면 Default 부분을 변수로 사용해 지우면 된다.]

invoke powershell을 하면 크롬이 안 켜져 있는 경우 taskkill에 대해 에러로 인식하기 때문에 그냥 kill은 따로 앞쪽에 하도록 하자.

아니면 가운데 Environment.NewLine 넣고 하나의 액티비티로 하고 Continue On Error만 체크해주자.

[테스트 해보니 앞에서 에러가 나더라도 뒤에 코드는 실행을 한다.]

 

  1. Network 폴더가 쿠키, 세션 저장 폴더로 변경돼서 여태 제대로 안 지워졌던 걸로 보임 [본문으로]

+ Recent posts