중요합니다
- 프로덕션 준비 미리 보기 기능입니다.
- 프로덕션 준비 미리 보기에는 추가 사용 약관이 적용됩니다.
ERP와 통합된 Dynamics 365 Project Operations 및 제조용 Dynamics 365 Project Operations에 적용됩니다.
경비 에이전트는 Microsoft Dynamics 365 Project Operations, 금융 및 운영 앱, Microsoft Copilot Studio, Power Automate 및 Dataverse의 기능을 결합하여 AI를 사용하여 경비 처리 워크플로를 자동화합니다. 이 기능은 시스템에서 영수증을 처리하고 사용자에 대한 경비 줄 및 비용 보고서를 생성할 수 있도록 하여 시간을 절약하고 수동 작업을 줄이는 데 도움이 됩니다. Microsoft Power Platform 커넥터를 사용하여 Outlook, Microsoft Teams, 사용자 일정 및 Dataverse 가상 엔터티를 통한 금융 및 운영 앱 환경과 통합합니다.
경비 에이전트에는 여러 흐름이 포함되며, 그 중 3개는 핵심 오케스트레이터 역할을 합니다.
- 이메일 처리 – 이 흐름은 구성된 사서함 폴더를 매시간 검색하고 첨부 파일을 Dynamics 365 Finance에 첨부되지 않은 영수증으로 저장합니다.
- 영수증 ID 추출 – 이 흐름은 연결되지 않은 영수증을 선택하고 에이전트를 트리거하여 영수증 세부 정보를 추출하고 연결되지 않은 경비 라인을 만듭니다.
- 프로세스 비용 보고서 – 이 흐름은 연결되지 않은 경비 줄을 변환하고 각 법인에 대해 애플리케이션에서 설정한 구성 별 그룹 보고서를 기반으로 비용 보고서를 생성합니다.
또한 에이전트는 Microsoft Teams와 통합되어 경비 보고서 검토 및 제출에 적응형 카드를 사용할 수 있습니다.
에이전트는 여러 Microsoft Power Platform 커넥터를 사용합니다. 이러한 커넥터는 제공된 Power Automate 흐름에서 자동으로 참조됩니다.
- Outlook(Office 365) – 이 커넥터는 공유 사서함에 액세스하여 영수증을 추출합니다.
- Dataverse(가상 엔터티) – 이 커넥터는 가상 엔터티를 통해 금융 및 운영 앱과 통합됩니다.
- Microsoft Copilot Studio – 이 커넥터는 AI 모델을 호출하여 영수증 정보를 추출합니다.
- Microsoft Teams – 이 커넥터는 사용자 상호 작용을 위한 적응형 카드를 보냅니다(Teams 통합을 사용하는 경우).
- Microsoft 365 사용자 – 이 커넥터는 사용자 일정 세부 정보를 검색합니다(영수증 구문 분석이 컨텍스트 인식인 경우 선택 사항).
필수 조건
- 재무 및 운영 환경: 에이전트를 설치하려면 재무 및 운영 환경의 최소 버전 10.0.44(10.0.2263.175 이상) 또는 10.0.45(10.0.2345.115 이상) 또는 10.0.46(10.0.2428.69 이상)이 필요합니다.
- Expense Agent 사용자를 설정하는 데 필요한 역할: 이 문서의 단계를 완료하려면 조직의 시스템 관리자여야 하며 Expense Agent 설치를 위한 경비 에이전트 사용자를 설정하려면 다음 역할이 있어야 합니다.
| 시스템 | 역할 | 코멘트 |
|---|---|---|
| Power Platform 관리 센터 | 시스템 관리자 |
|
| Finance and Operations | 시스템 관리자 |
|
| Microsoft 365 | Exchange 관리자 및 사용자 관리자 |
|
| Teams 관리 센터 | Teams 관리자 | Microsoft Teams 통합을 사용하도록 설정하려는 경우 필수 |
경비 에이전트를 설정하는 단계
Expense Agent를 설치하고 설정하려면 다음 단계를 수행합니다.
- 금융 및 운영 앱용 Copilot을 설치합니다.
- 사용자 환경에서 에이전트 기능을 활성화합니다.
- 에이전트 실행을 위한 경비 사용자를 만듭니다.
- 공유 사서함을 설정합니다.
- 경비 에이전트를 설정합니다.
- Microsoft Teams에서 경비 에이전트 활성화(선택 사항 - Microsoft Teams 통합이 필요한 경우)
다음 섹션에서는 각 단계를 자세히 설명합니다.
1단계: 금융 및 운영 앱용 Copilot 설치
경비 에이전트는 금융 및 운영 앱용 Copilot 패키지의 일부로 사용할 수 있습니다. 사용자 환경에 이 패키지를 설치한 후에는 에이전트, 환경 변수 및 Power Automate 흐름을 비롯한 모든 필수 자산을 자동으로 가져옵니다.
필요한 앱을 설치하려면 다음 단계를 수행합니다.
- 브라우저에서 Power Platform 관리 센터로 이동합니다.
- 환경 목록에서 앱을 설치할 환경 이름을 선택합니다.
- 환경의 세부 정보 페이지(왼쪽 탐색이 아님 )에서 리소스 섹션으로 이동하여 Dynamics 365 앱을 선택합니다.
- Dynamics 365 앱 목록 내에서 금융 및 운영 앱용 Copilot을 검색합니다. 이미 설치되어 있고 업데이트를 사용할 수 있는 경우 업데이트 버튼을 선택합니다.
- 앱이 Dynamics 365 앱 아래에 나열되지 않은 경우 앱 설치를 선택하고 금융 및 운영 앱용 Copilot을 선택하고, 프롬프트에 따라 설치를 완료합니다.
- 재무 및 운영 앱의 코파일럿은 버전 1.0.3231.4 이상이어야 합니다.
비고
금융 및 운영 앱에서 Copilot 기능 활성화에서 사용자 환경에 Copilot을 활성화하는 방법에 대해 자세히 알아봅니다.
팁 (조언)
패키지가 성공적으로 설치되었는지 확인하려면 다음 단계를 수행합니다.
- Power Apps Maker Portal >로 이동하여 환경을 선택하고 >솔루션을 선택합니다.> 기록 > 검색을 참조하고 msdyn_ExpenseAI > 세부 정보를 선택합니다.
-
결과 필드를 확인합니다.
- 결과에 성공이 표시되면 패키지가 올바르게 설치되었습니다.
- 결과에 성공이 표시되지 않으면 설치에 실패했습니다.
- 설치에 실패하면 msdyn_FnOCopilotAnchor 삭제하고(제거 섹션 참조) 재무 및 운영 앱에 대한 Copilot를 다시 설치합니다.
2단계: 사용자 환경에서 에이전트 기능 활성화
재무 및 운영 앱 패키지를 위한 Copilot를 설치한 후 Dataverse 및 재무 및 운영 환경 내에서 Expense Agent를 활성화합니다.
Dataverse에서 기능 활성화
Power Platform 관리 센터에서 Copilot 기능 플래그를 켭니다. Copilot 기능 플래그를 켜려면 다음 단계를 수행합니다.
- Power Platform 관리 센터로 이동합니다.
- 환경>을 선택하고 환경 >설정>제품>을 선택하고 기능을 선택합니다.
- Copilot 기능 플래그가 켜져 있는지 확인합니다.
금융 및 운영 환경에서 기능 활성화
재무 및 운영 앱에서 에이전트를 활성화하려면 다음 단계를 수행합니다.
- 금융 및 운영 환경에 로그인합니다.
- 기능 관리로 이동하여 몰입형 홈 기능 및 에이전트 관리 기능을 활성화합니다.
- 경비 에이전트(설정은 법인별 설정)를 구성하려면 비용 관리>설치>일반>비용 관리 매개 변수로 이동합니다.
- 경비 항목 에이전트 탭에서 다음 표와 같이 매개 변수를 구성합니다.
| 매개 변수 | 가치 | 코멘트 |
|---|---|---|
| 현재 법인에 대한 경비 에이전트 활성화 | Yes | 현재 법인에 대한 에이전트를 활성화하려면 예로 전환합니다. |
| 빈도 | 매일 또는 매주 | 조직에서 경비 보고서를 자동으로 만들기 위한 빈도를 구성합니다. |
| 그룹 보고서 기준 | 여행 또는 프로젝트 | 프로젝트 또는 여행에 따라 경비를 그룹화하도록 구성합니다. |
3단계: 에이전트 실행을 위한 경비 에이전트 사용자 만들기
에이전트가 직원의 ID와 독립적으로 실행되도록 전용 경비 에이전트 사용자를 만듭니다. 이 방법은 보안, 관리 효율성 및 장기 유지 관리에 도움이 됩니다. 필요한 권한이 있는 기존 사용자 계정을 사용할 수 있지만 시스템 소유 ID를 사용합니다.
Microsoft Entra ID에서 Expense Agent 사용자 만들기
- Azure Portal에 로그인합니다.
- 사용 가능한 Azure 서비스에서 Microsoft Entra ID를 선택합니다.
- Microsoft Entra ID에서 새 사용자를 만듭니다.
-
추가>사용자>새 사용자 만들기를 선택하고 다음 세부 정보를 입력합니다.
- 사용자 계정 이름
- 적합한 도메인 선택
- 표시 이름
- 암호
- 계정 표시 활성화됨
- 세부 정보를 보고 사용자 만들기 프로세스를 완료하려면 검토 + 만들기를 선택하고 만들기를 선택합니다.
- 사용자 페이지(관리> 사용자)에서 사용자를 선택하고 세부 정보 보기 페이지를 선택합니다.
- 속성 편집을 선택하고 설정 탭으로 이동하여 적절한 사용 위치를 입력합니다.
비고
조직 정책에 따라 암호를 변경하고 MFA(다단계 인증)를 설정해야 할 수 있습니다. 일반적으로 암호를 변경하고 MFA를 설정하기 위해 수행하는 단계를 수행합니다.
경비 에이전트 사용자에게 필요한 라이선스 할당
Expense Agent를 성공적으로 설치하려면 비용 에이전트 사용자에게 다음 라이선스를 할당합니다.
- Dynamics 365 Teams Members 라이선스
- Microsoft 365 Business Basic 또는 Microsoft Teams 및 Outlook을 포함하는 라이선스(예: Teams가 있는 Office 365 E5)
- 파워 앱스 프리미엄
라이선스를 할당하려면 다음 단계를 수행합니다.
- 라이선스 관리자 이상의 사용자인 라이선스를 할당하는 액세스 권한이 있는 사용자를 사용하여 Microsoft 365 관리 센터에 로그인합니다.
- 청구>라이선스>Dynamics 365 Teams Members 라이선스를 선택합니다.
- +라이선스 할당을 선택합니다.
- 이전 단계에서 만든 경비 에이전트 사용자를 검색합니다.
- 할당을 선택하여 라이선스 할당을 완료합니다.
- Microsoft 365 Business Basic 및 Power Apps Premium과 같은 다른 라이선스의 경우 2~5단계를 수행합니다.
비고
활성 사용자 사용 페이지를 사용하여 라이선스할당 및 할당 해제에서 라이선스를 확인하고 할당하는 방법에 대해 자세히 알아봅니다.
Power Platform 환경에 사용자 추가
Power Platform 환경에 사용자를 추가하려면 다음 단계를 수행합니다.
Power Platform 관리 센터에 로그인하고 적절한 환경을 선택합니다.
팁 (조언)
이 페이지에서는 Dataverse의 환경 ID, Dataverse의 환경 URL, 금융 및 운영 URL과 관련된 정보를 제공합니다. 이후 섹션에서 사용할 값을 저장합니다.
액세스 > 사용자 > 모두 보기로 이동합니다.
사용자 추가를 선택하고, 새로 만든 에이전트 사용자를 입력하고, 추가를 선택합니다.
보안 역할 관리 페이지에서 다음 역할을 추가합니다.
- 경비 관리 AI 에이전트 역할
- 금융 및 운영 에이전트 구성 관리자
- 시스템 사용자 지정자
역할 할당을 확인하려면 저장을 선택합니다.
이러한 역할은 에이전트가 작동해야 하는 Dataverse 및 Power Automate 구성 요소에 대한 액세스를 제공합니다.
팁 (조언)
사용자가 이미 있고 역할만 할당해야 하는 경우 Power Platform 관리 센터로 이동하여 적절한 환경을 선택합니다.
- 액세스 > 사용자 > 모두 보기로 이동합니다.
- 만든 에이전트 사용자를 선택합니다.
- 역할 관리를 선택하고 역할을 할당합니다.
금융 및 운영 환경에서 필요한 역할 할당
재무 및 운영 환경에서 ExpenseAgentRole 역할을 할당하려면 다음 단계를 수행합니다.
- 금융 및 운영 환경에서 시스템 관리>사용자로 이동합니다.
- 에이전트 사용자에 대한 사용자 레코드를 만듭니다.
- 사용자를 만든 후 사용자의 역할 섹션으로 이동하여 역할 할당을 선택하고 ExpenseAgentRole을 검색합니다.
- 저장을 선택합니다.
비고
ExpenseAgentRole은 10.0.44(10.0.2263.81) 및 10.0.45(10.0.2345.6)의 금융 및 운영 앱 버전과 금융 및 운영 앱용 Copilot 버전 1.0.3121.1에서 사용할 수 있습니다.
공유 사서함 액세스에 대한 액세스 할당
에이전트 사용자에게 Mail.Read.Shared Microsoft Graph 권한이 있어야 합니다. 이 권한을 통해 에이전트는 흐름 실행 중에 구성된 공유 사서함에서 영수증을 읽을 수 있습니다.
공유 사서함 액세스에 대한 액세스를 할당하려면 다음 단계를 수행합니다.
- Microsoft Graph Explorer로 이동하여 만든 에이전트 사용자를 사용하여 로그인합니다.
- 오른쪽 위 모서리에서 사용자 아이콘을 선택하여 >권한에 동의를 선택합니다.
- Mail.Read.Shared>에 대한 메일> 찾기 드롭다운 메뉴를 선택하고 동의를 선택하고 수락을 선택합니다.
만든 에이전트 사용자에 대한 필수 역할 요약
| 환경 | 역할 | 코멘트 |
|---|---|---|
| Dataverse | 언급된 역할을 통해 에이전트는 Dynamics 365 Finance에 연결된 Power Automate 흐름, 환경 변수 및 가상 엔터티와 상호 작용할 수 있습니다. | |
| Finance and Operations | 이 역할은 에이전트가 금융 및 운영 앱 환경에서 경비 항목을 만들고 관리하는 데 필요합니다. 참고: ExpenseAgentRole은 10.0.44 (10.0.2263.81) 및 10.0.45 (10.0.2345.6)의 금융 및 운영 앱 버전과 금융 및 운영 앱용 Copilot 버전 1.0.3121.1에서 사용할 수 있습니다. |
|
| Graph 탐색기를 사용하여 공유 사서함 액세스 | Mail.Read.Shared | 에이전트가 흐름 실행 중에 구성된 공유 사서함에서 영수증을 읽을 수 있는 Microsoft Graph 권한 |
4단계: 공유 사서함 설정
경비 에이전트는 공유 사서함을 사용하여 영수증 이메일을 받고 처리합니다. Exchange 관리자 역할이 있는 사용자는 Microsoft 365 관리 센터에서 이 사서함을 만들고 구성해야 합니다.
공유 사서함을 만들고 구성하려면 다음 단계를 수행합니다.
Exchange 관리자 계정을 사용하여 Microsoft 365 관리 센터에 로그인합니다.
왼쪽 창에서 Teams & 그룹>공유 사서함을 선택합니다.
팁 (조언)
전체 목록을 확장하려면 모두 표시 를 선택해야 할 수 있습니다.
공유 사서함 추가를 선택합니다.
공유 사서함의 이름과 전자 메일 주소를 입력합니다.
변경 내용 저장을 선택합니다.
다음 단계에서 이 공유 사서함에 구성원 추가를 선택합니다. (구성원 관리를 사용할 수 있게 되는 데 몇 분 정도 걸릴 수 있습니다.)
구성원 추가를 선택합니다.
만든 에이전트 사용자 및 사서함을 모니터링해야 하는 다른 사용자를 선택하고 추가를 선택합니다.
닫기를 선택합니다.
비고
다음 단계에서 공유 사서함의 전자 메일 주소를 사용합니다. 공유 사서함을 설정한 후에는 시간 및 경비 에이전트를 구성할 때 해당 전자 메일 주소와 폴더 경로(기본적으로 받은 편지함으로 설정)를 환경 변수로 제공해야 합니다. 자세한 내용은 5단계: Expense Agent 설정을 참조하세요.
5단계: 경비 에이전트 설정
경비 에이전트를 설정하는 두 가지 옵션이 있습니다.
- 옵션 A: PowerShell 스크립트 사용 (권장)
- 옵션 B: Power Apps에서 수동 설정 수행(PowerShell 없음)
중요합니다
Expense Agent 설치를 계속하기 전에 Microsoft Copilot Studio에서 에이전트가 성공적으로 프로비전되었는지 확인합니다.
에이전트가 성공적으로 프로비전되었는지 확인하려면 다음 단계를 수행합니다.
- Microsoft Copilot Studio에 로그인하고 환경을 선택합니다.
- 에이전트로 이동하여 ExpenseAgent-Line(프리뷰)을 검색합니다.
- 게시 단추가 사용하도록 설정되어 있는지 확인합니다.
- 활성화된 경우 설치를 계속 진행합니다. 비활성화된 경우 에이전트가 프로비전될 때까지 기다립니다.
- 이 단계를 반복하여 경비 항목 에이전트(프리뷰) 가 활성화되어 있는지 확인합니다.
팁 (조언)
Copilot 재무 및 운영 앱 프로비저닝에 5-6시간 이상이 걸리는 경우 앱을 제거하고 다시 설치하여 잠재적인 설치 지연을 해결합니다. 자세한 내용은 이 문서의 끝에 있는 비용 에이전트 제거 섹션을 참조하세요.
옵션 A: PowerShell 스크립트 사용(권장)
에이전트의 수동 설정에는 연결을 만들고 연결하고, Power Automate 흐름을 활성화하고, 솔루션을 게시하는 작업이 포함됩니다. 이 프로세스는 시간이 오래 걸릴 수 있으며 오류에 취약합니다. 설치를 자동화하려면 필요한 매개 변수를 업데이트한 후 PowerShell 스크립트를 사용합니다.
PowerShell 스크립트는 다음 작업을 자동화합니다.
- 필요한 환경 변수를 업데이트합니다.
- Microsoft Power Platform 연결을 솔루션 연결 참조와 연결합니다.
- 시간 및 경비 에이전트가 필요로 하는 모든 Power Automate 흐름을 활성화합니다.
- 코필로트 에이전트를 게시합니다.
- Dataverse 솔루션을 게시합니다.
스크립트를 실행하기 전에 install.ps1 파일의 각 커넥터에 대한 연결 ID를 제공해야 하므로 연결을 만들어야 합니다. 이러한 연결을 만들려면 만든 에이전트 사용자를 사용하여 다음 단계를 수행합니다.
- 새로 만든 에이전트 사용자를 사용하여 Power Apps Maker 포털 에 로그인하고 환경을 선택합니다.
- 왼쪽 창에서 자세히를 선택하고 연결을 선택합니다.
- 새 연결을 선택하고 다음 표의 연결 이름(예: Office 365 Outlook)을 사용하여 검색합니다.
- 목록에서 적절한 커넥터를 선택하고 만듭니다.
- 연결이 만들어지면 연결이 만들어진 사용자를 확인합니다. 이상적으로는 생성된 에이전트 사용자 ID여야 합니다. 다음 단계에서 만든 설치 파일에서 이 사용자 ID를 업데이트합니다.
- 다음 표에 나열된 나머지 필수 연결 각각에 대해 3단계와 4단계를 반복합니다.
| 연결 이름 | 연결 URL 형식 |
|---|---|
| Office 365 Outlook | https://make.powerapps.com/environments/environmentID/connections / shared_office365/connectionID/details |
| Office 365 사용자 | https://make.powerapps.com/environments/environmentID/connections / shared_office365users/연결 ID/세부사항 |
| Microsoft 팀 | https://make.powerapps.com/environments/environmentID/connections / shared_teams/connectionID/세부사항 |
| 마이크로소프트 데이터버스 | https://make.powerapps.com/environments/environmentID/connections / shared_commondataserviceforapps/connectionID/세부사항 |
| Microsoft Copilot Studio(프리뷰) | https://make.powerapps.com/environments/environmentID/connections / shared_microsoftcopilotstudio/연결ID/세부사항 |
설치 파일을 만드는 데 필요한 정보
설치 파일( install.ps1)을 만들려면 다음 정보를 사용할 수 있습니다. (참조를 위해 다음 표를 참조할 수 있습니다.)
| 매개 변수 | 기타 세부 정보 |
|---|---|
| Dataverse 환경 ID | Power Platform 관리 센터에서 가져오는 환경 ID를 입력합니다. 샘플 값: xxxx-xxxx-xxxx-xxx-xxxxxxxxxx |
| Dataverse 환경 URL | Power Platform 관리 센터에서 환경 URL을 입력합니다. 참고: 시작 부분에 https://가 있고 끝에 슬래시 '/'가 없어야 합니다. 샘플 값: https://org123.crm.contoso.com |
| 금융 및 운영 인스턴스 URL | 금융 및 운영 환경 세부 정보를 다음 형식으로 입력합니다. 샘플 값: https://org123.contoso.com 참고: 에서 시작 부분에 https://가 있고 끝에 ‘/’가 없어야 합니다. |
| OutlookFolderPath | 공유 사서함에서 만든 폴더 경로를 입력합니다. 다른 폴더가 만들어지지 않으면 기본적으로 받은 편지함으로 설정됩니다. 샘플 값: 받은 편지함 비용 관리를 위한 별도의 폴더를 만드는 것이 가장 좋습니다. |
| 사서함 주소 ID | 새로 만든 공유 사서함의 메일 주소를 입력합니다. 샘플 값: expenseagent@contoso.com |
| Microsoft Dataverse 연결 이름 Microsoft Copilot Studio 연결 이름 Microsoft Office Outlook 연결 이름 Microsoft Office 365 사용자 연결 이름 Microsoft Teams 연결 이름 |
모든 연결 이름에 대한 입력은 동일하며 생성된 에이전트 사용자의 사용자 이메일 ID입니다. 샘플 값: createdexpenseagentuser@contoso.com |
설치 스크립트 파일 만들기
다음 코드를 복사하여 설치 스크립트 파일을 만듭니다. 필요한 환경 변수를 스크립트에 삽입한 다음 PowerShell을 사용하여 스크립트를 실행합니다.
비고
로컬 데스크톱에 설치 스크립트 파일을 배치합니다. One Drive에 저장하지 마세요.
다음 코드를 사용하여 PowerShell 스크립트 파일을 만듭니다. 스크립트를 실행하기 전에 언급된 매개 변수를 업데이트합니다.
팁 (조언)
필수 = $true PowerShell은 매개 변수를 대화형으로 입력하라는 메시지를 표시하므로 스크립트 파일에서 직접 업데이트할 필요가 없습니다.
수동 입력을 방지하고 설치 스크립트 내에서 매개 변수를 미리 정의하려면 다음 샘플 코드의 Param 섹션에서 필수 = $false 설정합니다.
다음 코드를 설치 스크립트 파일에 복사하고 'Install.ps1'로 저장합니다. 매개 변수 섹션의 해당 매개 변수 필드에 있는 변수를 업데이트합니다. 10개의 변수를 업데이트해야 합니다.
팁 (조언)
이전 테이블을 참조로 사용하고 모든 샘플 값을 해당 세부 정보로 바꿉니다.
#requires -Version 7
Param(
[Parameter(Mandatory=$true, HelpMessage="Dataverse environment id")]
[string]$DataverseEnvironmentId = "xxxx-xxxx-xxxx-xxx-xxxxxxxxxx",
[Parameter(Mandatory=$true, HelpMessage="Dataverse environment URL")]
[string]$DataverseUrl = "https://org123.crm.dynamics.com",
[Parameter(Mandatory=$true, HelpMessage="Finance and Operations instance URL")]
[string]$D365FinanceAndOperationsUrl = "https://org123.operations.dynamics.com",
[Parameter(Mandatory=$true, HelpMessage="OutlookFolderPath")]
[string]$OutlookFolderPath = "Inbox",
[Parameter(Mandatory=$true, HelpMessage="Mailbox Address Id")]
[string]$MailboxAddressId = "expenseagent@contoso.com",
[Parameter(Mandatory=$true, HelpMessage="Microsoft Dataverse connection name")]
[string]$MicrosoftDataverseConnectionName = "createdexpenseagentuser@contoso.com",
[Parameter(Mandatory=$true, HelpMessage="Microsoft Copilot Studio connection name")]
[string]$MicrosoftCopilotStudioConnectionName = "createdexpenseagentuser@contoso.com",
[Parameter(Mandatory=$true, HelpMessage="Microsoft Office Outlook connection name")]
[string]$Office365OutlookConnectionName = "createdexpenseagentuser@contoso.com",
[Parameter(Mandatory=$true, HelpMessage="Microsoft Office 365 Users connection name")]
[string]$Office365UsersConnectionName = "createdexpenseagentuser@contoso.com",
[Parameter(Mandatory=$true, HelpMessage="Microsoft Teams connection name")]
[string]$MicrosoftTeamsConnectionName = "createdexpenseagentuser@contoso.com",
[Parameter(Mandatory=$false, HelpMessage="Checks for bot Sync Errors and if there is provisioning required before Agent publish step")]
[boolean]$CheckBotSyncStatusAndProvisionBots = $false
)
$flows = @(
"expense entry retry check",
"expense configuration",
"get expense outlook folder",
"generate expense report",
"send expense report adaptive card",
"auto match expenses",
"process emails",
"extract unattached receipt ids for copilot invocation",
"extract unattached receipt output using dataverse plugin",
"generate expense line",
"generate expense line without project id and status id",
"identify project ids",
"user calendar events",
"process expense report using copilot",
"invoke expense agent for receipt processing"
)
$agents = @(
"msdyn_ExpenseEntryAgent",
"msdyn_ExpenseReportAgent"
)
# Check PS version
if ($PSVersionTable.PSVersion.Major -lt 7) {
Write-Error 'This script requires at least PowerShell version 7' -ErrorAction Stop
}
# Install the required modules if not already installed or if the version is not 1.0.40
if (-not (Get-Module -ListAvailable -Name Microsoft.PowerApps.PowerShell | Where-Object { $_.Version -ge [Version]"1.0.40" })) {
Write-Host "Microsoft.PowerApps.PowerShell version 1.0.40 not found. Installing..." -ForegroundColor Yellow
Install-Module -Name Microsoft.PowerApps.PowerShell -RequiredVersion 1.0.40 -Force -AllowClobber -Scope CurrentUser
} else {
Write-Host "Microsoft.PowerApps.PowerShell version 1.0.40 is already installed." -ForegroundColor Green
}
if (-not (Get-Module -ListAvailable -Name Microsoft.PowerApps.Administration.PowerShell | Where-Object { $_.Version -ge [Version]"2.0.147" })) {
Install-Module -Name Microsoft.PowerApps.Administration.PowerShell -RequiredVersion 2.0.147 -Force -AllowClobber -Scope CurrentUser
}
# Install the required modules if not already installed
if (-not (Get-Module -ListAvailable -Name Az.Accounts | Where-Object { $_.Version -ge [Version]"5.0.1"})) {
Install-Module -Name Az.Accounts -RequiredVersion 5.0.1 -Force -AllowClobber -Scope CurrentUser
}
# Import required modulesds
Import-Module Az.Accounts
Import-Module Microsoft.PowerApps.PowerShell
Import-Module Microsoft.PowerApps.Administration.PowerShell
# global variable declaration
$filter = '$filter'
function Get-AccessToken {
# Retrieve the access token for the Dataverse environment
$accessToken = (Get-AzAccessToken -ResourceUrl "$DataverseUrl" -AsSecureString).Token
Write-Host "Access token for $userId retrieved successfully." -ForegroundColor Green
return $accessToken
}
function Get-AccessTokenPlainText {
param(
[Parameter(Mandatory=$true, HelpMessage="Access token for authentication")]
[securestring]$accessToken
)
# Retrieve the access token for the PVA environment
$token = [Runtime.InteropServices.Marshal]::PtrToStringAuto(
[Runtime.InteropServices.Marshal]::SecureStringToBSTR($accessToken))
return $token
}
function update-EnvironmentVaribleValue {
param (
[string]$accessToken,
[string]$env_key,
[string]$env_value # Access token for authentication
)
try
{
# Get the environment variable definition
$envVarDefinition = Invoke-RestMethod -Method Get -Uri "$DataverseUrl/api/data/v9.2/environmentvariabledefinitions?$filter=schemaname eq '$env_key'" -Headers @{
Authorization = "Bearer $accessToken"
}
if ($envVarDefinition.value -ne $null) {
$envVarDefId = $envVarDefinition.value[0].environmentvariabledefinitionid
# Get the environment variable value record
$filterValue = [System.Web.HttpUtility]::UrlEncode("_environmentvariabledefinitionid_value eq $envVarDefId")
$envVarValue = Invoke-RestMethod -Method Get -Uri "$DataverseUrl/api/data/v9.2/environmentvariablevalues?$filter=$filterValue" -Headers @{
Authorization = "Bearer $accessToken"
}
if ($envVarValue.value -ne $null) {
$envVarValueId = $envVarValue.value[0].environmentvariablevalueid
# Update the environment variable value
Invoke-RestMethod -Method Patch -Uri "$DataverseUrl/api/data/v9.2/environmentvariablevalues($envVarValueId)" -Headers @{
Authorization = "Bearer $accessToken"
"Content-Type" = "application/json"
} -Body (@{ value = $env_value } | ConvertTo-Json -Depth 1)
Write-Host "Environment variable updated with name $env_key and value $env_value" -ForegroundColor Green
} else {
Write-Host "Environment variable value not found for $env_key. Skipping..." -ForegroundColor Red
}
}
else {
Write-Host "Environment variable definition not found for $env_key. Skipping..." -ForegroundColor Yellow
}
}
catch {
Write-Host "Failed to update environment variable $env_key. Error: $($_)" -ForegroundColor Red
throw $_ # Re-throw the error to stop the script if this step is critical
}
}
function update_EnvironmentVariablesForExpense {
param (
[string]$accessToken # Access token for authentication
)
write-host "Updating environment variables..." -ForegroundColor Yellow
try
{
update-EnvironmentVaribleValue -accessToken $accessToken -env_key "msdyn_ExpenseFnoInstanceUrl" -env_value $D365FinanceAndOperationsUrl
update-EnvironmentVaribleValue -accessToken $accessToken -env_key "msdyn_ExpenseAgentOutlookFolderPath" -env_value $OutlookFolderPath
update-EnvironmentVaribleValue -accessToken $accessToken -env_key "msdyn_ExpenseAgentMailboxAddressId" -env_value $MailboxAddressId
}
Catch {
Write-Host "Failed to update environment variables. Error: $($_)" -ForegroundColor Red -ErrorAction Stop
}
}
# Function to publish the solution
function Publish-Solution {
param (
[string]$accessToken
)
Write-Host "Publishing All" -ForegroundColor Yellow
# Construct the API endpoint for publishing the solution
$uri = "$DataverseUrl/api/data/v9.2/PublishAllXml"
# Make the API call
try {
Invoke-RestMethod -Method Post `
-Uri $uri `
-Headers @{
Authorization = "Bearer $accessToken"
"Content-Type" = "application/json"
}
Write-Host "Publish All - Success!" -ForegroundColor Green
} catch {
Write-Host "Failed to publish. Error: $($_.Exception)" -ForegroundColor Red
}
}
function Get-FlowGuidByName {
param (
[string]$accessToken, # Access token for authentication
[string]$flowName # Name of the flow to search for
)
#Write-Host "Retrieving GUID for flow: $flowName" -ForegroundColor Yellow
# Construct the API endpoint with a filter for the flow name
$encodedFlowName = [System.Web.HttpUtility]::UrlEncode($flowName)
$uri = "$DataverseUrl/api/data/v9.2/workflows?$filter=name eq '$encodedFlowName'"
try {
# Make the API call
$response = Invoke-RestMethod -Method Get `
-Uri $uri `
-Headers @{
Authorization = "Bearer $accessToken"
"Content-Type" = "application/json"
}
# Check if the flow was found
if ($response.value.Count -gt 0) {
$flow = $response.value[0]
Write-Host "Flow found: $($flow.name) with GUID: $($flow.workflowid)" -ForegroundColor Green
return $flow.workflowid
} else {
Write-Host "No flow found with the name: $flowName" -ForegroundColor Red
return $null
}
} catch {
Write-Host "Failed to retrieve flow GUID. Error: $($_.Exception.Message)" -ForegroundColor Red
return $null
}
}
# Function to activate a Power Automate flow
function Activate-Flow {
param (
[string]$DataverseUrl, # Dataverse environment URL
[string]$accessToken, # Access token for authentication
[string]$flowId # GUID of the flow to activate
)
# Construct the request body
$body = @{
"statecode" = 1 # Activated
"statuscode" = 2 # Activated
} | ConvertTo-Json -Depth 1 -Compress
# Construct the API endpoint
$uri = "$DataverseUrl/api/data/v9.2/workflows($flowId)"
# Make the API call
try {
Invoke-RestMethod -Method Patch `
-Uri $uri `
-Headers @{
Authorization = "Bearer $accessToken"
"Content-Type" = "application/json"
} `
-Body $body
Write-Host "Flow activated successfully." -ForegroundColor Green
} catch {
Write-Host "Failed to activate flow. Error: $($_.Exception.Message)" -ForegroundColor Red
}
}
function Get-ConnectionRefIdFromLogicalName {
param (
[string]$accessToken,
[string]$connectionRefLogicalName
)
$uri = "$DataverseUrl/api/data/v9.2/connectionreferences?$filter=connectionreferencelogicalname eq '$connectionRefLogicalName'"
$response = Invoke-RestMethod -Method Get `
-Uri $uri `
-Headers @{
Authorization = "Bearer $accessToken"
"Content-Type" = "application/json"
}
if ($response -ne $null) {
write-host "Connection reference id found: $($response.value[0].connectionreferenceid) " -ForegroundColor Green
return $response.value[0].connectionreferenceid
}
else {
Write-Host "No connection reference found for logical name: $connectionRefLogicalName" -ForegroundColor Red
return $null
}
}
function Get-ConnectionId {
param (
[string]$userProvidedName,
[string]$providerName
)
try {
$matchedConnectionId = $null
# Added -ErrorAction Stop to ensure the catch block is triggered on failure
$connections = Get-PowerAppConnection -EnvironmentName $DataverseEnvironmentId -ConnectorNameFilter $providerName -ErrorAction Stop
foreach ($con in $connections) {
if (($con.ConnectionName -eq $userProvidedName) -or ($con.DisplayName -eq $userProvidedName)) {
$matchedConnectionId = $con.ConnectionName
break
}
}
if ($null -eq $matchedConnectionId) {
# Use 'throw' to create a terminating error that the calling function can catch
throw "Unable to find connection '$userProvidedName' for provider '$providerName'."
}
return $matchedConnectionId
}
catch {
# Catch any errors from Get-PowerAppConnection or the 'throw' statement above
Write-Error "Failed to get connection ID for '$userProvidedName'. Error: $_"
throw # Re-throw the error to stop the script if this step is critical
}
}
function Get-ConnectionReferenceId {
param(
[string]$connectionReferenceLogicalName,
[securestring]$accessToken
)
try {
$uri = "$DataverseUrl/api/data/v9.2/connectionreferences?$filter=connectionreferencelogicalname eq '$connectionReferenceLogicalName'"
# Added -ErrorAction Stop for clarity, though Invoke-RestMethod often terminates on HTTP errors
$response = Invoke-RestMethod -Method Get -Uri $uri -Authentication Bearer -Token $accessToken -ContentType 'application/json' -ErrorAction Stop
if ($null -eq $response -or $response.value.Count -eq 0) {
throw "Connection reference not found for logical name '$connectionReferenceLogicalName'."
}
$connectionReferenceDisplayName = $response.value[0].connectionreferencedisplayname
$connectionReferenceId = $response.value[0].connectionreferenceid
Write-Host "updating connection $connectionReferenceDisplayName for logical name $connectionReferenceLogicalName)"
return $connectionReferenceId
}
catch {
Write-Error "Failed to get connection reference ID for '$connectionReferenceLogicalName'. Error: $_"
throw # Re-throw to notify the calling function
}
}
function Set-ConnectionReferenceConnection {
param (
[string]$connectionReferenceLogicalName,
[string]$userProvidedConnectionName,
[string]$providerName,
[securestring]$accessToken
)
try {
# These functions will now throw terminating errors if they fail
$connectionReferenceId = Get-ConnectionReferenceId -connectionReferenceLogicalName $connectionReferenceLogicalName -accessToken $accessToken
$connectionId = Get-ConnectionId -userProvidedName $userProvidedConnectionName -providerName $providerName
$body = @{
"connectionid" = "$connectionId"
} | ConvertTo-Json -Depth 1
$uri = "$DataverseUrl/api/data/v9.2/connectionreferences($connectionReferenceId)"
# Write-Host "Updating connection reference URI: $uri with connection id $connectionId"
Invoke-RestMethod -Method Patch -Uri $uri -Authentication Bearer -Token $accessToken -ContentType 'application/json' -Body $body -ErrorAction Stop
Write-Host "Connection reference updated successfully." -ForegroundColor Green
}
catch {
# This block will catch errors from any of the functions called within the try block
Write-Error "Failed to set connection reference for '$connectionReferenceLogicalName'. Error: $_"
throw
}
}
function Activate-Flows {
param (
[string]$accessToken,
[array]$expenseAIFlows
)
foreach ($flowName in $expenseAIFlows) {
Write-Host "Activating flow: $flowName" -ForegroundColor Yellow
# Call the Get-FlowGuidByName function to get the flow GUID
$flowGuid = Get-FlowGuidByName -dataverseUrl $DataverseUrl -accessToken $accessToken -flowName $flowName
if ($flowGuid -ne $null) {
# Write-Host "Flow Name: $flowName, Flow GUID: $flowGuid" -ForegroundColor Green
Activate-Flow -dataverseUrl $DataverseUrl -accessToken $accessToken -flowId $flowGuid
# Write-Host "Flow Name: $flowName, Flow GUID: $flowGuid Activated" -ForegroundColor Green
} else {
Write-Host "Flow Name: $flowName not found." -ForegroundColor Red
}
}
}
# Function to retrieve the Agent ID by name
function Get-AgentIdBySchemaName {
param (
[string]$DataverseUrl,
[string]$accessToken,
[string]$agentSchemaName
)
Write-Host "Retrieving agent ID for agent schema: $agentSchemaName" -ForegroundColor Yellow
# Construct the API endpoint to retrieve the bot
$uri = "$DataverseUrl/api/data/v9.2/bots?$filter=schemaname eq '$agentSchemaName'"
try {
# Make the API call
$response = Invoke-RestMethod -Method Get -Uri $uri -Headers @{
Authorization = "Bearer $accessToken"
"Content-Type" = "application/json"
}
if ($response.value.Count -gt 0) {
$agentId = $response.value[0].botid
return $agentId
} else {
Write-Host "No agent found with the name: $agentSchemaName" -ForegroundColor Red
return $null
}
} catch {
Write-Host "Failed to retrieve agent ID. Error: $($_)" -ForegroundColor Red
return $null
}
}
function Check-BotSyncErrors {
param (
[string]$DataverseUrl,
[string]$accessToken,
[string]$botId
)
Write-Host "Retrieving Sync Status for bot ID: $botId" -ForegroundColor Yellow
# Construct the API endpoint to retrieve the bot
$uri = "$DataverseUrl/api/data/v9.2/bots($botId)"
try {
# Make the API call
$response = Invoke-RestMethod -Method Get -Uri $uri -Headers @{
Authorization = "Bearer $accessToken"
"Content-Type" = "application/json"
}
if ($null -ne $response.synchronizationstatus) {
# Parse the JSON string in synchronizationstatus
$syncStatusObj = $response.synchronizationstatus | ConvertFrom-Json
$state = $syncStatusObj.currentSynchronizationState.state
$provisioningStatus = $syncStatusObj.currentSynchronizationState.provisioningStatus
Write-Host "Synchronization State: $state" -ForegroundColor Green
Write-Host "Provisioning Status: $provisioningStatus" -ForegroundColor Green
if ( $state -contains "Error" -or $provisioningStatus -contains "Error") {
Write-Host "Bot has synchronization errors." -ForegroundColor Red
return 0
} else {
if ( $state -eq "Synchronized" -or $state -eq 'Synchronizing' -and ($provisioningStatus -eq "Provisioned" -or $provisioningStatus -eq "ProvisionedWithoutRegistration")) {
Write-Host "Bot synchronization is done." -ForegroundColor Yellow
return 1
} else {
Write-Host "Bot synchronization is in progress." -ForegroundColor Green
return 2
}
}
} else {
Write-Host "No synchronization status found for bot ID: $botId" -ForegroundColor Red
return $null
}
} catch {
Write-Host "Failed to retrieve agent ID. Error: $($_)" -ForegroundColor Red
return $null
}
}
# Function to provision a PVA bot
function Provision-Agent {
param (
[string]$DataverseUrl,
[string]$accessToken,
[string]$agentId
)
# Construct the API endpoint for publishing the bot
$uri = "$DataverseUrl/api/data/v9.2/bots($agentId)/Microsoft.Dynamics.CRM.PvaProvision"
try {
# Make the API call
Invoke-RestMethod -Method Post -Uri $uri -Headers @{
Authorization = "Bearer $accessToken"
"Content-Type" = "application/json"
}
Write-Host "Agent Provisioning successfully!" -ForegroundColor Green
# Add 30 second delay to allow the publish process to complete
Start-Sleep -Seconds 30
return $true
} catch {
Write-Host "Failed to Provision Agent. Error: $($_.Exception.Message)" -ForegroundColor Red
}
return $false
}
# Function to publish a PVA bot
function Publish-Agent {
param (
[string]$DataverseUrl,
[string]$accessToken,
[string]$agentId
)
Write-Host "Publishing agent with ID: $agentId" -ForegroundColor Yellow
# Construct the API endpoint for publishing the bot
$uri = "$DataverseUrl/api/data/v9.2/bots($agentId)/Microsoft.Dynamics.CRM.PvaPublish"
try {
# Make the API call
Invoke-RestMethod -Method Post -Uri $uri -Headers @{
Authorization = "Bearer $accessToken"
"Content-Type" = "application/json"
}
Write-Host "Agent published successfully!" -ForegroundColor Green
# Add 30 second delay to allow the publish process to complete
Start-Sleep -Seconds 30
} catch {
Write-Host "Failed to publish Agent. Error: $($_.Exception.Message)" -ForegroundColor Red
}
}
function Publish-Agents {
param (
[string]$accessToken,
[array]$agentSchemas
)
if (-not $agentSchemas -or $agentSchemas.Count -eq 0) {
Write-Host "No agent schemas provided. Skipping agent publishing." -ForegroundColor Yellow
return
}
foreach ($agentSchema in $agentSchemas) {
#Write-Host "Publishing agent schema: $agentSchema" -ForegroundColor Yellow
try {
# Construct the API endpoint for publishing the agent schema
$agentId = Get-AgentIdBySchemaName -dataverseUrl $DataverseUrl -accessToken $accessToken -agentSchemaName $agentSchema
if ($agentId -ne $null) {
# check for sync errors
if ($CheckBotSyncStatusAndProvisionBots) {
$syncStatus = Check-BotSyncErrors -dataverseUrl $DataverseUrl -accessToken $accessToken -botId $agentId
if (0 -eq $syncStatus) {
Write-Host "Agent has sync errors. Skipping the publish process. Please check the bot: $agentId details" -ForegroundColor Red
continue
} elseif (2 -eq $syncStatus) {
Write-Host "Agent synchronization is still in progress. reprovisioning the agent." -ForegroundColor Yellow
if (Provision-Agent -dataverseUrl $DataverseUrl -accessToken $accessToken -agentId $agentId -eq $false) {
Write-Host "Agent reprovisioning failed. Skipping the publish process. Please check the bot: $agentId details" -ForegroundColor Red
continue
}
} else {
Write-Host "Agent synchronization is done. Proceeding to publish." -ForegroundColor Green
}
}
# Step 4: Publish the bot
Publish-Agent -dataverseUrl $DataverseUrl -accessToken $accessToken -agentId $agentId
} else {
Write-Host "Agent not found. Cannot proceed with publishing.Skipping the step" -ForegroundColor Yellow
}
}
catch {
Write-Host "An error occurred while publishing agent schema: $agentSchema. Error: $_" -ForegroundColor Red
}
}
}
# Main script execution
try {
$expenseAIFlows = $flows
$agentSchemas = $agents
# Step 1: Interactive login to Azure
Connect-AzAccount -UseDeviceAuthentication
$accessToken = Get-AccessToken
$accessTokenPlainText = Get-AccessTokenPlainText -accessToken $accessToken
# Step 2: Setup ennviornment variables
update_EnvironmentVariablesForExpense -accessToken $accessTokenPlainText
Write-Host "Environment variables updated successfully!" -ForegroundColor Green
# Step 3: Check active connections
Set-ConnectionReferenceConnection -userProvidedConnectionName $MicrosoftDataverseConnectionName -providerName "/providers/Microsoft.PowerApps/apis/shared_commondataserviceforapps" -connectionReferenceLogicalName "msdyn_sharedcommondataserviceforapps_2c2d4" -accessToken $accessToken
Set-ConnectionReferenceConnection -userProvidedConnectionName $MicrosoftCopilotStudioConnectionName -providerName "/providers/Microsoft.PowerApps/apis/shared_microsoftcopilotstudio" -connectionReferenceLogicalName "msdyn_sharedmicrosoftcopilotstudio_26d9d" -accessToken $accessToken
Set-ConnectionReferenceConnection -userProvidedConnectionName $Office365OutlookConnectionName -providerName "/providers/Microsoft.PowerApps/apis/shared_office365" -connectionReferenceLogicalName "msdyn_sharedoffice365_9b471" -accessToken $accessToken
Set-ConnectionReferenceConnection -userProvidedConnectionName $MicrosoftTeamsConnectionName -providerName "/providers/Microsoft.PowerApps/apis/shared_teams" -connectionReferenceLogicalName "msdyn_sharedteams_8ea9c" -accessToken $accessToken
Set-ConnectionReferenceConnection -userProvidedConnectionName $Office365UsersConnectionName -providerName "/providers/Microsoft.PowerApps/apis/shared_office365users" -connectionReferenceLogicalName "msdyn_sharedoffice365users_909b9" -accessToken $accessToken
# Step 4: Activate flows
Activate-Flows -accessToken $accessTokenPlainText -expenseAIFlows $expenseAIFlows
# step 5: publish the agents
Publish-Agents -accessToken $accessTokenPlainText -agentSchemas $agentSchemas
# Step 6: Publish the solution
Publish-Solution -accessToken $accessTokenPlainText
Write-Host "Agent setup completed successfully!" -ForegroundColor Green
} catch {
Write-Host "An error occurred: $_" -ForegroundColor Red
}
PowerShell 파일을 트리거하려면 다음 단계를 수행합니다.
- PowerShell 을 엽니다(최소 버전 필요 - PowerShell 7).
- 파일을 저장한 위치로 이동합니다. (명령 cd <파일 위치>를 사용합니다).
- 설치 스크립트를 트리거합니다. (명령 '.\Install.ps1'을 사용합니다).
- 지침에 따라 Azure에 로그인합니다.
- 로그인한 후에는 한 번 더 권한을 부여해야 할 수 있습니다. (만든 에이전트 사용자 ID를 사용합니다.)
스크립트가 완전히 실행될 때까지 기다렸다가 에이전트 설치가 성공적으로 완료되었는지 확인합니다.
비고
위의 스크립트는 다음 작업을 수행합니다.
- 환경 변수를 설정합니다.
- 연결 참조를 확인하고 연결합니다.
- Power Automate 흐름을 사용하도록 설정합니다.
- 필요한 코필로트 에이전트를 게시합니다.
- Dataverse 솔루션을 게시합니다.
스크립트가 성공적으로 실행되면 경비 에이전트가 완전히 구성되고 사용할 준비가 된 것입니다.
옵션 B: Power Apps에서 수동으로 설정(PowerShell 없음)
PowerShell 스크립트를 사용하지 않으려면 Power Apps를 통해 Expense Agent를 수동으로 구성할 수 있습니다. 이 프로세스에는 환경 변수 업데이트, Power Automate 흐름 활성화 및 솔루션 게시가 포함됩니다.
환경 변수 업데이트
환경 변수를 업데이트하려면 다음 단계를 수행합니다.
Power Apps에 로그인하고 환경을 선택합니다.
솔루션을 선택한 다음 기본 솔루션(또는 에이전트가 설치된 솔루션)을 엽니다.
환경 변수로 이동하여 다음 값을 설정합니다.
변수 이름 설명 경비 관리 에이전트 Outlook 폴더 경로 공유 사서함에서 모니터링할 폴더 경로를 지정합니다(기본적으로 받은 편지함). 경비 관리 에이전트 공유 메일 박스 주소 ID 공유 사서함의 이메일 주소를 지정합니다 로그인한 사용자의 사서함을 사용하려면 NA를 입력합니다. 금융 및 운영 인스턴스 URL 금융 및 운영 앱 환경의 URL을 지정합니다(예: https://org123.contoso.com).
Power Automate 흐름을 활성화합니다.
경비 에이전트는 다음 Power Automate 흐름을 사용합니다.
- 경비 항목 재입력 확인
- 경비 구성
- 경비 Outlook 폴더 가져오기
- 경비 보고서 생성
- 경비 보고서 적응형 카드 보내기
- 비용 자동 일치
- 이메일 처리
- Copilot 호출에 대한 첨부되지 않은 영수증 ID 추출
- Dataverse 플러그 인을 사용하여 연결되지 않은 영수증 출력 추출
- 경비 라인 생성
- 프로젝트 ID 및 상태 ID 없이 경비 라인 생성
- 프로젝트 ID 식별
- 사용자 일정 이벤트
- Copilot으로 경비 보고서 처리
- 영수증 처리를 위해 경비 에이전트 호출
흐름을 사용하도록 설정하려면 다음 단계를 수행합니다.
Power Automate에 로그인하고 환경을 선택합니다.
내 흐름을 선택합니다.
이전 목록의 15개 흐름 각각에 대해 다음 단계를 수행합니다.
- 흐름을 찾습니다.
- 편집을 선택합니다.
- 새 디자이너 옵션을 해제하여 이전 디자이너 보기로 전환합니다.
- 필요한 연결을 인증합니다(녹색 확인 표시가 표시될 때까지).
- 계속을 선택한 다음 저장을 선택합니다.
- 흐름을 활성화하려면 켜기를 선택합니다.
솔루션을 게시합니다.
모든 환경 변수 및 흐름 구성을 완료한 후 다음 단계에 따라 솔루션을 게시합니다.
- Power Apps에서 솔루션으로 이동합니다.
- 환경 및 솔루션을 선택합니다.
- 모든 사용자 지정 게시를 선택합니다.
이러한 단계를 완료하면 Expense Agent가 완전히 구성되고 사용할 준비가 됩니다.
6단계: Microsoft Teams에서 경비 에이전트 활성화(선택 사항)
Expense Agent에 대한 Teams 기반 통신을 사용하도록 설정하려면 Power Apps의 에이전트에 Teams 채널을 추가합니다. 그러면 에이전트가 Teams를 통해 적응형 카드를 보낼 수 있습니다.
Teams 채널 활성화
Teams 채널을 사용하도록 설정하려면 다음 단계를 수행합니다.
- Copilot Studio에 로그인하고 올바른 환경을 선택합니다.
- 에이전트 탭에서 경비 항목 에이전트를 선택합니다.
- 에이전트 보기의 채널 탭에서 Teams 및 Microsoft 365 Copilot을 선택합니다.
- 채널 추가를 선택하여 Teams 통합을 활성화하고 Teams 앱 가용성 구성 섹션의 단계에 따라 앱을 공유할 사용자를 구성합니다.
Teams + Microsoft 365 채널의 구성 패널 열기에서 자세히 알아보십시오.
Teams 앱 가용성 구성
Teams 앱 가용성을 구성하려면 다음 단계를 수행합니다.
Teams 앱을 만든 후 가용성 옵션을 선택합니다.
앱을 공유할 사용자를 선택합니다.
- 조직 내의 특정 사용자
- 전체 조직
승인을 위해 앱을 제출합니다.
Teams 관리 센터에서 앱 게시
Teams 관리 센터에서 앱을 게시하려면 다음 단계를 수행합니다.
- Teams 관리 센터에 로그인합니다.
- Teams 앱 관리 앱>으로 이동합니다. "경비"를 검색하고 앱 상태가 차단된 경비 항목 에이전트 앱을 선택합니다.
- 앱 차단을 해제하려면 게시를 선택합니다. 게시 작업이 성공적으로 완료되면 앱 상태가 차단 해제로 변경되는지 확인합니다.
Teams 및 Microsoft 365 Copilot용 에이전트 연결 및 구성에서 자세히 알아보십시오.
이러한 단계를 완료하면 Expense Agent 를 사용할 준비가 됩니다.
비고
또한 Dynamics 365 Finance 환경 내에서 엄지 손가락 및 엄지 손가락 아래 아이콘과 피드백 팝업을 사용하여 에이전트에서 생성한 비용 줄 및 보고서에 대한 피드백을 제공할 수도 있습니다.
경비 에이전트 제거
Expense Agent를 제거 하려면 다음 단계를 수행합니다.
- Microsoft Power Apps Maker 포털에 로그인합니다.
- 솔루션을 선택하고, msdyn_ExpenseAI를 검색하고, 세 개의 점을 선택하고, 삭제를 선택합니다.
- msdyn_FnOCopilotAnchor 검색하고 솔루션을 삭제합니다.