office 문서의 관리 / 편집을 프로그램으로 하기 위해서는 vb나 c#을 이용해야하죠. 특히 다음과 같은 마소의 본연 라이브러리로 하는데요, 기술의 발달로 .Net Framework 가 아닌 .NET core를 넘어 .NET Stardard에서
Microsoft.Office.Interop.Word
Microsoft.Office.Interop.Excel
Microsoft.Office.Interop.Powerpoint
Microsoft.Office.Interop.Outlook
의 com api를 사용하면 다음과 같은 에러메시지를 맞게 되었죠.
일단 이유에 대해서 설명드리겠습니다. 윈도우 전용이었던 .Net Framework 에서 cross platform을 추구하는 .NET core, .NET Standard로 넘어오면서 기본 세팅하에서는 com api를 인식할 수 없게 되었어요. com api는 윈도우에만 존재하기 때문이죠.
구글링했을때는 ".net core에서는 사용할 수 없다." 라고 기술되어 포기했었는데, 직접참조하면 된다고해서 도전을 다시 해봤죠. 역시나 안됐어요.
그렇다면 어떻게 세팅하면 사용할 수 있을까?
방법은 의외로 간단했어요.
platform 세팅을 any 에서 window로 바꾸는 것이죠.
1. 솔루션 바로 하단의 어플리케이션을 우클릭
2. 애플리케이션 -> 일반
3. 대상 OS를 찾아 기본값인 (없음)을 클릭
4.Windows를 클릭
5. 솔루션 내 종속성 우클릭 후 COM 참조 추가
(Nuget으로 microsoft.office.interop 라이브러리를 추가하면 에러가 나던데, 성공하신분 연락 또는 댓글로 방법 남겨주시기 바랍니다!!)
6. 필요한 라이브러리 추가 ( 스크린샷 예제에서는 Microsoft.Office.Interop.Word 를 사용하기 위해 word com object를 추가)
word com 객체를 추가하였고 이제 using Microsoft.Office.Interop.Word를 사용하면 라이브러리 사용이 가능하답니다.
주의할점!!!
1. 플랫폼을 바꾸면 어떻게 되느냐 - 당연히 지정한 플랫폼에서만 사용가능합니다. window10/11 등의 window os가 설치된 PC 또는 window server에서만 사용이 가능한 것이죠.
2. 위 예제에서 Microsoft Word 16.0 Object Library가 안보이시는 분들 특히, 이 com 객체를 추가하여 라이브러리를 사용하기 위해서는 개발된 어플리케이션이 설치될 pc에 office가 설치되어 있어야 합니다.
3. 이 포스팅을 업로드하는 시점까지 확정된 microsoft의 com api 지원기간은 2029년까지로 알려져있습니다.
지난번에 example 편에서 pdf.js의 공식 웹페이지 https://mozilla.github.io/pdf.js/ 의 example 탭에 있는 pdf.js의 기본 개념들을 익혀보았습니다. 이번에는 모듈로 구현해봅시다. 웹 프레임워크는 asp.net core mvc를 사용했습니다. 어짜피 프론트 모듈에 대한 포스트이기 때문에 node.js나 스프링을 쓰시더라도 주요 포인트는 동일하기 때문에 이해가 되실 것으로 봅니다.
pdf.js의 웹페이지 진입 후 다운로드(Download) 버튼을 클릭합니다. 아래 캡처 이미지에서 노란색으로 칠해놓았습니다.
https://mozilla.github.io/pdf.js/ 메인페이지
Getting Started 페이지로 진입하는데, Introduction의 바로 아래 Download가 있습니다. 구형 브라우저를 사용하신다면 older browsers를 클릭하셔도 좋고, git을 쓰는 것이 편하시다면 Source에서 clone 하고 오셔도 됩니다. 처음에는 git으로 받아와서 썼지만, git을 못쓰시는 분들을 위해 예제로는 modern browsers의 Prebuilt Stable (v4.10.38)을 다운로드했습니다.
압축을 푼 폴더를 소스의 파일시스템에 넣어줍니다. 각각 사용하시는 웹 프레임워크에서 프론트 부분에 넣으시면 되겠습니다. 참고로 저는 asp.net core mvc로 개발하기 위해 "프로젝트\wwwroot\lib"의 하위에 복사하였습니다.
node.js 같은 경우에 초반 구성은 공식 문서에 설명을 따라가는 것이 나으실 수도 있습니다. git clone(또는 압축해제) 후 npx gulp server를 실행하면 실행은 바로 된다고 기입되어 있습니다.
스프링이나 asp.net core mvc 사용자는 js와 뷰파일의 위치가 분리되어있으실테니 뷰어를 사용할 위치에 viewer.html을 복사해줍니다. 복사한 위치에서는 뷰 소스 내 상대참조 부분에서 에러가 나기 떄문에 참조를 수정해줍니다.
<!-- This snippet is used in production (included from viewer.html) -->
<link rel="resource" type="application/l10n" href="locale/locale.json">
<script src="../build/pdf.mjs" type="module"></script>
<link rel="stylesheet" href="viewer.css">
<script src="viewer.mjs" type="module"></script>
</head>
view.html을 보시면 위와 같이 기입된 부분이 title부 바로 하단에 있습니다. 이 내용들을 pdf.js 라이브러리 폴더를 옮겼던 부분으로 모두 수정해줍니다.
저는 asp.net core mvc를 사용했기 때문에 view.cshtml로 작성하였으며, 아까 말씀드렸던 "프로젝트\wwwroot\lib" 경로를 참조하기 위해 다음과 같이 수정했습니다. 그리고 아래 '여기에 입력하세요'라고 기입된 곳에서 pdf뷰어를 실행하면 됩니다.
<!-- This snippet is used in production (included from viewer.html) -->
<link rel="resource" type="application/l10n" href="/lib\pdfjs-4.10.38-dist\web\locale\locale.json">
<script src="~/lib\pdfjs-4.10.38-dist\build\pdf.mjs" type="module"></script>
<link rel="stylesheet" href="~/lib\pdfjs-4.10.38-dist\web\viewer.css">
<script src="~/lib\pdfjs-4.10.38-dist\web\viewer.mjs" type="module"></script>
<script type="module">
// 여기에 입력하세요.
</script>
pdf뷰어를 경로와 함께 지정하면 실행됩니다.
<script type="module">
PDFViewerApplication.open(서버 내 파일경로);
</script>
혹시 지난 sample편에서 base64string으로 뷰어를 띄우고 싶으신 분들 왜 정작 패키지에서는 실행할수 없을까 싶기도 할텐데요. 지난번에 말씀드렸던 개념 기억하실까요?
pdf 파일처리에 대해서는 example 예제를 그냥 삽입하시면 보통 잘 나옵니다.그래서 파일부분은 공식 문서의 설명과 크게 다르지 않을 수 있습니다.
다만, example 내에는미리보기라면 갖춰야할 확대 축소 기능이 없기 때문에 이 기능이 필요하신 분들 또는 base64String으로 불러오는 부분에는 페이징(previous, next 버튼 및 페이지 길이 표기)도 없기 때문에 이 부분이 필요하신 분들은 본문을 계속 따라 와주시면 됩니다.
제반요건 - 인터넷 연결 필요
(없이 가능하도록 만들 수 있습니다. 어려운일은 아니므로 여기서는 다루지 않습니다. 다만 댓글로 문의 주시면 답변은 드리겠습니다.)
1. 링크 접속 후 상단 메뉴의 [Example]을 클릭합니다.
2. example 페이지 내용을 요약해서 순서대로 적어보겠습니다.
먼저 모듈을 선언하여 불러와 줍니다. 그리고 pdfjsLib을 선언하고, 라이브러리의 기본옵션을 불러옵니다. (공통)
<script src="//mozilla.github.io/pdf.js/build/pdf.mjs" type="module"></script>
<script type="module">
var { pdfjsLib } = globalThis;
pdfjsLib.GlobalWorkerOptions.workerSrc = '//mozilla.github.io/pdf.js/build/pdf.worker.mjs';
// 여기 위치에 다음내용 입력들어갑니다!
</script>
다음은 미리보기할 문서를 불러와야겠죠.
어떤 문서를 미리보기할지에 따라 다른데, 서버의 파일경로로 존재하는 파일 / 또는 base64String 상태의 파일을 모두 불러 올 수 있습니다.
a. 서버경로의 파일을 불러오는 방법
var pdfFileUrl = 'https://어쩌구/저쩌구/test.pdf'
var loadingTask = pdfjsLib.getDocument(pdfFileUrl);
b. base64String 형식의 데이터를 불러오는법
var pdfFileBase64Data = atob('베이스64스트링')
var loadingTask = pdfjsLib.getDocument({data: pdfFileBase64Data});
a,b에서 보는바와 같이 getDocument는 url 또는 {data: ${atob('base64string')} }를 입력받습니다. 한 번더 강조하는 이유는 이미 고민하고 들어와서 아실 분들도 있을 것이고 아예 처음오신분들은 나중 설명에서 필요하니 기억해두도록 합시다!
데이터로 선언한 loadingTask는 promise 속성을 가지고 있어 resolve로 불러온 pdf파일을 객체로 돌려줍니다.
loadingTask.promise.then(function(pdf) {
// 공식 pdf.js 문서와 같이 이 자리부터 pdf파일을 다룰 수 있습니다.
});
이제 pdf 파일을 다룰 수 있고, 이후 기본적인 pdf.js의 흐름은 다음과 같아요. 페이지 불러오기 -> 불러온 페이지를 렌더링하기
공식페이지 예제 바탕으로 간단하게 써보자면 아래와 같습니다.
// pdf의 페이지를 가져온다.
pdf.getPage(1).then(function(page) {
// 불러온 페이지를 렌더링한다.
var scale = 1.5;
var viewport = page.getViewport({ scale: scale, });
// Support HiDPI-screens.
var outputScale = window.devicePixelRatio || 1;
var canvas = document.getElementById('the-canvas');
var context = canvas.getContext('2d');
canvas.width = Math.floor(viewport.width * outputScale);
canvas.height = Math.floor(viewport.height * outputScale);
canvas.style.width = Math.floor(viewport.width) + "px";
canvas.style.height = Math.floor(viewport.height) + "px";
var transform = outputScale !== 1
? [outputScale, 0, 0, outputScale, 0, 0]
: null;
var renderContext = {
canvasContext: context,
transform: transform,
viewport: viewport
};
page.render(renderContext);
});
앞서 설명드린내용을 모두 이어서 써서 보여드리겠습니다. pdf 파일은 공식문서의 것을 그대로 사용합니다. ( 혹시 저작권 문제가 있다면 즉시 삭제하겠습니다. )
// 모듈 선언 후 불러오기
<script src="//mozilla.github.io/pdf.js/build/pdf.mjs" type="module"></script>
<script type="module">
// 기본 라이브러리 및 옵션 정보 불러오기
var { pdfjsLib } = globalThis;
pdfjsLib.GlobalWorkerOptions.workerSrc = '//mozilla.github.io/pdf.js/build/pdf.worker.mjs';
// 파일주소로 페이지를 불러올 task 생성
var pdfFileUrl = 'https://raw.githubusercontent.com/mozilla/pdf.js/ba2edeae/examples/learning/helloworld.pdf'
var loadingTask = pdfjsLib.getDocument(pdfFileUrl);
// 프로미스로 리졸브를 pdf 객체로 반환받는다.
loadingTask.promise.then(function(pdf) {
// pdf의 페이지를 가져온다.
pdf.getPage(1).then(function(page) {
// 불러온 페이지를 렌더링한다.
var scale = 1.5;
var viewport = page.getViewport({ scale: scale, });
// Support HiDPI-screens.
var outputScale = window.devicePixelRatio || 1;
var canvas = document.getElementById('the-canvas');
var context = canvas.getContext('2d');
canvas.width = Math.floor(viewport.width * outputScale);
canvas.height = Math.floor(viewport.height * outputScale);
canvas.style.width = Math.floor(viewport.width) + "px";
canvas.style.height = Math.floor(viewport.height) + "px";
var transform = outputScale !== 1
? [outputScale, 0, 0, outputScale, 0, 0]
: null;
var renderContext = {
canvasContext: context,
transform: transform,
viewport: viewport
};
page.render(renderContext);
});
});
</script>
<h1>PDF.js 'Hello, world!' example</h1>
<p>Please use <a href="https://mozilla.github.io/pdf.js/getting_started/#download"><i>official releases</i></a> in production environments.</p>
<canvas id="the-canvas"></canvas>
약간의 응용을 시작하겠습니다. 간단하게, previous버튼, next버튼, (문서 길이 + 현재 페이지), 확대 축소를 구현해보겠습니다.
먼저 previous 버튼, next 버튼 구현입니다. 구현이라고 말씀드렸으나 이 두 버튼은 공식문서 example 페이지 내에 있습니다. 그러나 굳이 설명드리는 이유, 본문 서두에 말씀드렸지만 base64string의 예제는 없기 때문입니다.
아까 기억하라고 말씀드렸던 getDocument의 변수에는 서버파일의 경로와 base64string을 입력하는 data방식이 있었죠. getDocument을 호출할때 입력하는 변수 중 파일경로 문자열을 {data: 베이스64스트링 } 으로 교체만 해주면 됩니다!
[Previous/Next example]의 html 소스 내에서 getDocument 부분은 단 한 군데 존재합니다. 이것을 atob(base64string)로 받아온 byteArray-like data로 {data: 'byteArray-like data' } 대체해주면 됩니다. 아래 이미지에 표시해두었으니 참고하시기 바랍니다.
다음 확대 축소 구현입니다. 이 부분을 읽으시면 다른 속성들도 변경할 아이디어를 챙기실 수도 있을 것 같아요.
[Previous/Next example] 예제를 기준으로 설명드리겠습니다. 라이브러리 선언, 라이브러리 옵션이 추가된 다음 줄에 변수를 6개 선언하는데요, 이 중 크기를 나타내는 변수는 scale입니다.
그리고 그 아래 페이지를 랜더링하는 함수가 있죠. 자세히 뜯어 보실 필요는 없으나, 아래 이미지에서 표시한 부분, scale에서 이 부분을 입력 받음을 알 수 있습니다. 따라서 scale 변수를 변경하고, renderPage함수를 호출한다면 사이즈가 조정된다고 판단할 수 있습니다.
일단 확대 축소를 마우스 휠 등의 이벤트로도 하실 수 있겠지만, 저는 간단한 구현을 위해 확대 버튼과 축소 버튼을 구현하겠습니다.
회사에서 VMWare workstation Pro 15의 굴레에 갇혀있었는데 희소식이 있습니다.
VMWare를 인수한 Broadcom은 2024년 12월 11일 전면무료화를 선언했다는 점이죠.
AMD CPU 사용중인 window 11 Pro 사용자들에게 제약점이 많았죠. core수를 1개 넘게 가상머신을 생성하면 가상머신에서 access violation ( 0xc0000005 Exception)을 내뱉거나, 구동후에도 vmware tools 를 설치하지 않은 상태에서는 호환이 안되서 너무 느린 등의 문제 말이죠.
그러나 이제는 고통은 안지 않아도 됩니다. Broadcom에서 상업 무료화를 선언했기 때문이죠.
변경사항이 사용자들에게 미치는 영향
Vmware fusion pro와 workstation pro는 이제 유료 또는 구독이 아닙니다.
무료로 사용할 수 있습니다.
다만, 앞으로는 유료버전을 더 이상 구매할 수 없습니다. 이미 구매했던 사용자에 대한 cs지원은 계속될 전망이다.
이전의 개인 무료버전인 player는 스냅샷 캡처 등은 동작하지 않았는데, Pro가 무료화 되다보니 기존 유료 Pro버전에서 사용하던 모든 기능을 이용할 수 있다고 합니다.계약이 활성화 된 고객은 계속 적으로 지원포탈이나 지원팀에 연락하여 도움을 받을 수 있으나, 문제해결을 위한 support ticket 생성은 더이상 제공하지 않는다고 하네요.
그러나 무료화와 같이 지원 문서, 사용자 가이드, 커뮤니티 포럼으로 다양한 리소스를 활용할 수 있도록 하겠다는 공지사항입니다.
예상컨데 도커 등의 등장으로 사용자가 감소하고 있는 추세에 사용자들을 늘리고 협업, 커뮤니티, 피드백 등을 통한 성장을 바라보고 있을 것 같아서 긍정적으로 판단해도 단기적으로는 나쁘진 않을 정책인 것 같아요. 구버전의 VMWare Workstation Pro를 사용하기 위해 OS를 다운그레이드하는 슬픈일은 없어지겠네요.
다운로드 하는 방법은 broadcom vmware 홈페이지에 가입 후 로그인하여 시도하면 된답니다!
Get 방식의 http method는 정보의 조회 등인 경우가 많아 대부분 200번 즉 response.StatusCode 가 HttpStatusCode.OK일 거예요. 다만, 구체적으로 반환되는 HTTP Status Code는 API를 제작한 개발사/개발자에 문의 또는 설명문서를 참조하여 정하시는 것이 좋겠습니다.
다만, 200번대가 보통 성공을 나타낸다고 약속되어져 있습니다. (제가 약속한거 아닙니다.)
따라서 다음과 같은 방법으로 200번대면 성공이라고 가정, 아니면 실패를 예외를 던지는 속성과 함수도 존재합니다.
// response.IsSuccessStatusCode: response가 200번 대면 true를 반환하는 bool값
if(response.IsSuccessStatusCode) {
// 성공
}
// if문도 필요 없이 200번대면 다음 레코드를 읽고, 200번대가 아니면 예외를 던지는 함수
response.EnsureSuccessStatusCode();
응답이 성공했으면 원하는 응답을 읽어와야하고, 그 방법에는 여러가지가 있을텐데요. 두가지를 설명드리겠습니다.
1. 응답을 모두 string으로 받아오는 방법
c#의 함수나 속성명은 상당히 직관적입니다.
[응답]의 [내용]을 [문자열]으로 불러오겠습니다.
(response)(content)(string)
var responseContent = await response.Content.ReadAsStringAsync();
그런데 대부분은 string 자체를 사용하진 않을 것입니다. 약속된 API라면 반환값이 json형태의 문자열이기 때문이죠.
따라서 json형태의 문자열을 다음과 같이 클래스로 바꿔줍니다.( System.Text.Json 필요)
var result = JsonSerializer.Deserialize<ResultClass>(responseContent, new JsonSerializerOptions());
JsonSerializerOptions 옵션 등과 같은 System.Text.Json의 고유 기능은 제가 자세히 설명해놓은 글
저의 경우 NewtonSoft.Json은 .Net Framework에서는 많이 사용했지만. Net Standard에 와서는 내장된 System.Text.Json을 적극 사용하고 있습니다. 특히 아래 2번 방법과 JsonSerializerOptions 을 공유하고 있기 때문에 사용하시는 것을 권장드립니다.
2. 응답내용을 불러올때 클래스로 만드는 방법입니다. (using System.Net.Http.Json 필요)
ResultClass result = await response.Content.ReadFromJsonAsync<ResultClass>();
형태로 사용하거나 var로 선언하긴하지만, 여러분에게 명시적으로 보여드리기 위해 클래스로 선언부를 작성하였습니다.
개발 초기에는 응답내용을 전부 로그를 찍기 위해 1번으로 시작할때도 있지만, 주로 2번을 사용하고 있습니다.
ReadFromJsonAsync의 정의를 보면, System.Text.Json의 JsonSerializerOptions 옵션을 공유합니다.
null처리, 기본값 처리 등을 손쉽게 할 수 있고, 그에 따라 api의 상세한 요구조건을 컨트롤 할 수 있으니 반드시 알아두시면 좋겠습니다.
ResultClass가 무엇인가요? 라고 물으실 수 있을 것 같아요. 아무렇게나 작성한 임의의 클래스입니다.
{"number": 1} 이라는 형태의 json이 왔고 약속된 형태라면,
ResultClass은 아래와 같이 정의가 되었을 것입니다.
class ResultClass{
public int Number {get; set;}
}
// 또는
class ResultClass{
[JsonPropertyName("number")]
public int Sequence {get; set;}
}
serialize했을때 json이 되는 클래스를 만들었다라고 보시면 되겠습니다.
이 포스트는 json, json과 클래스의 관계에 대한 설명글이 아니기 때문에 이 정도만 작성하도록하고, 여태까지 설명 내용을 한 번에 보실 수 있도록 담아보겠습니다.
// json문자열을 역직렬화할 Model 클래스
class ResultClass{
[JsonPropertyName("number")]
public int Sequence {get; set;}
}
// HttpClient 선언
HttpClient httpClient = new(){
BaseAddress = new Uri("https://api.example.com/"),
Timeout = TimeSpan.FromSeconds(30) // 굳이 적지 않아도 되나 기본값이 30초
};
// 필요시 헤더 추가
if (!httpClient.DefaultRequestHeaders.Contains("Key"))
httpClient.DefaultRequestHeaders.Add("Key", "Value");
// Get 방식 호출
HttpResponseMessage response = await httpClient.GetAsync("/class/students");
// 성공 여부 검증
response.EnsureSuccessStatusCode();
// 성공시 json을 역직렬화하여 변수에 담는다.
var result = await response.Content.ReadFromJsonAsync<ResultClass>();
폴더 형태의 구조를 담은 DB 또는 그러한 형태를 반환하는 API를 경험할 일이 많아졌다.
[상위폴더 여부 | 상위 폴더 Id | 폴더 Id | 폴더 이름]
간추려 위와 같은 컬럼이 있는 DB가 있거나,
유사형태의 값을 반환하는 API를 만났다.
DB만 있었다면 DB에서 recurrsive 테이블로 재귀로 뽑아 내는 것도 방법이겠지만
API를 사용해야만 하는 시점에서는 위 형태의 반환 값을 폴더구조로 풀어내는 것에 대한 고민이 있었다.
(공부 뒤 블로그나 github에 올리지 못한 내용이 더 많아서 공부를 뜨문뜨문한다고 보실 분들도 있겠지만...
필자는 계속 책을 구매하거나 인강을 듣거나 아주 작은 단위의 프로젝트를 혼자 진행하며
공부하고 찾아보면서 학습중이었다는 점....)
그러다 DFS를 여기 적용할 수 있겠다는 생각이 들었다.
이 포스트에서는 그러한 예제를 풀어가려한다.
재직회사에서 C#을 쓰고 있어 C#으로 개발하였으니 다른언어를 하셨더라도 원리로 가져가면 될 것 같다.
특히,
폴더명으로 검색하기에는
a \ b
a \ c \ b
의 경우 처럼 이름은 같지만 다른 위치에 있는 것을 프로그램은 구분해서 조회할 수 없기 때문에 폴더구조로 뽑아오거나 id를 뽑아오는 것은 매우 필연적이기 떄문에 이 작업이 필요할때가 많다.
먼저 아래와 같은 클래스를 작성했다.
DB에서 4개 컬럼을 읽어다 넣었거나, API 반환값이거나, 혹은 읽거나 받은 정보를 여기에 담았다고 가정하자.
class Folder
{
public int ParentId { get; set; }
public int Id { get; set; }
public bool HasParent { get; set; }
public string Name { get; set; }
public string NameHierarchy { get; set; }
public string IdHierarchy { get; set; }
}
처음 개발을 공부할때 자바스프링을 인텔리제이를 구매해서 사용하겠다고 맥북을 사고는 homebrew를 애용했어요. 자바 스프링을 사용하던 회사에 문제가 많아 3개월 후 퇴사하고나서 c# .net을 사용하는 회사로 이직했는데요.
window를 사용하는 곳에 입사하다보니 window 노트북도 다시 세팅을 했고 맥북의 homebrew 같은 친구가 window에 있을까? 고민 하던 중 chocolatey를 알게 됐었죠. 한참을 당연하게 생각하고 있다가 최근에 RabbitMQ를 설치할 일이 있어서 설치 문서를 보다가 chocolatey가 있어서 겸사겸사 포스트합니다.
먼저 선행조건 - window, powershell v2+ (윈도우 10, 11 사용자는 그냥 된다고 보셔도 무방합니다.)
.net 4.8 설치
영어를 할 줄 아신다면, 공식 홈페이지 쭈욱 따라 가시면 됩니다.
영어가 익숙치 않은 분들을 위한 포스팅에 가깝다고 보시면 되겠습니다. 그러나 업계 특성상 시간이 조금만 흘러도 내용이 변경 되기 때문에 공식 홈페이지와 이 포스트간에 차이가 있다면 무조건 공식 홈페이지를 따르시는 것이 좋습니다. 영어를 설사 거의 하시 못하더라도 명령어 - copy 부분은 개발자니까 알아보실 거라고 믿어요!
설치가 완료되면 powershell을 실행합니다.
powershell의 Get-ExecutionPolicy의 기본값이 Bypass가 아닌 경우가 많은데,
Get-ExecutionPolicy를 cmd에서 입력 후에 Restricted가 나오면
Set-ExecutionPolicy AllSigned 또는 Set-ExecutionPolicy Bypass -Scope Process를 입력하시면 됩니다.
(계속 말씀드리지만 2024년 8월 20일 기준으로 번역에 가깝기 때문에 이러한 명령어의 복사 자체는 포스트의 것이 아닌, 공식 홈페이지를 방문하여 기술된 문구를 복사하는 것을 권장드립니다. 시간이 경과하여 문구가 바뀐 것은 포스트에서 팔로우 할 수 없음을 계속해서 말씀 드립니다.
설치가 완료된 것이예요! 명령어를 알고 있는 패키지는 cmd를 치셔도 되고
공식 홈페이지에서 검색을 하셔도 좋습니다. Looking for Packages를 클릭 후 검색하시면 되는데요,