업데이트 중에 선택적 Windows 콘텐츠 마이그레이션 및 획득

이 문서에서는 운영 체제 업데이트 중에 언어 리소스 및 주문형 기능을 유지하는 문제에 대한 몇 가지 배경을 제공하며, 단기적으로 발전하고 장기적으로 준비하는 데 도움이 되는 지침을 제공합니다.

운영 체제를 업데이트하는 경우 언어 리소스 및 FOD(주문형 기능)를 유지하는 것이 중요합니다. 대부분의 상업 조직은 Configuration Manager 또는 기타 관리 도구를 사용하여 로컬 Windows 이미지 또는 WIM 파일(미디어 기반 또는 작업 순서 기반 업데이트)을 사용하여 Windows 클라이언트 설정을 배포하고 오케스트레이션합니다. 다른 사용자는 WSUS(Windows Server Update Services), Configuration Manager 또는 동등한 도구(서비스 기반 업데이트)를 사용하여 승인된 Windows 클라이언트 기능 업데이트를 사용하여 현재 위치 업데이트를 수행합니다.

두 방법 모두 사용자의 디바이스에 필요할 수 있는 Windows 선택적 기능의 전체 집합을 포함하지 않으므로 이러한 기능은 새 운영 체제로 마이그레이션되지 않습니다. 이전에는 기능 업데이트 후 온-프레미스 취득을 위해 Configuration Manager WSUS에서 이러한 기능을 사용할 수 없었습니다.

선택적 콘텐츠란?

선택적 콘텐츠에는 다음 항목이 포함됩니다.

  • FOD라고도 하는 주문형 일반 기능(예: Windows Mixed Reality)
  • 언어 기반 및 지역 FOD(예: Language.Basic~~~ja-jp~0.0.1.0)
  • 로컬 환경 팩
  • 언어 팩

선택적 콘텐츠는 VLSC(볼륨 라이선싱 서비스 센터)에서 사용할 수 있는 운영 체제 미디어의 일부인 Windows 이미지 파일에 기본적으로 포함되지 않습니다. 대신 VLSC에서 추가 ISO 파일로 릴리스됩니다. 운영 체제 미디어에서 이러한 기능을 배송하고 별도로 배송하면 Windows의 디스크 공간이 줄어듭니다. 이 방법은 사용자 데이터에 더 많은 공간을 제공합니다. 또한 월별 품질 업데이트를 설치하든 최신 버전으로 업그레이드하든 운영 체제를 서비스하는 데 필요한 시간을 줄입니다. 또한 기본 Windows 이미지가 작을수록 네트워크를 통해 전송할 데이터가 줄어듭니다.

선택적 콘텐츠를 획득하는 것이 어려운 이유는 무엇인가요?

선택적 콘텐츠를 둘러싼 과제는 일반적으로 다음 두 그룹으로 구성됩니다.

불완전한 운영 체제 업데이트

첫 번째 과제는 기능 업데이트 중 콘텐츠 마이그레이션과 관련이 있습니다. Windows 설치 프로그램이 현재 위치 업데이트를 수행하면 새 운영 체제가 임시 폴더의 이전 버전과 함께 사용자의 디스크에 기록됩니다. 여기서 두 번째 클린 운영 체제가 설치되고 사용자가 이동할 수 있도록 준비됩니다. 작업이 수행되면 Windows 설치 프로그램은 현재 버전에 이미 설치된 선택적 콘텐츠를 열거하고 새 운영 체제에 이 콘텐츠의 새 버전을 설치할 계획입니다.

Windows 설치 프로그램은 선택적 콘텐츠에 액세스해야 합니다. 선택적 콘텐츠는 기본적으로 Windows 이미지에 없으므로 Windows 설치 프로그램은 Windows 패키지를 가져와서 스테이징한 다음 새 운영 체제에 설치하기 위해 다른 곳을 찾아야 합니다. 콘텐츠를 찾을 수 없는 경우 결과는 디바이스의 기능이 누락된 업데이트, 좌절한 최종 사용자 및 지원 센터 호출일 가능성이 높습니다. 이 문제점을 업데이트하는 동안 선택적 콘텐츠를 마이그레이션하지 못했다고도 합니다. 미디어 기반 업데이트의 경우 Windows는 새 운영 체제가 부팅되면 자동으로 다시 시도합니다. 우리는이 잠재 인수를 호출합니다.

사용자가 시작한 기능 획득 실패

두 번째 과제는 사용자가 요청할 때 기능을 획득하지 못하는 것입니다. 클린 설치 또는 현재 위치 업데이트를 사용하여 새 버전의 Windows 클라이언트를 사용하여 디바이스를 실행하는 사용자를 상상해 보십시오. 사용자가 설정을 방문하여 두 번째 언어, 더 많은 언어 환경 기능 또는 기타 선택적 콘텐츠를 설치하려고 시도합니다. 다시 말하지만, 이러한 기능은 운영 체제에 없으므로 패키지를 획득해야 합니다. 인터넷에 액세스하는 일반적인 사용자의 경우 Windows는 근처의 Microsoft 콘텐츠 배달 네트워크에서 기능을 획득하고 모든 것이 설계된 대로 작동합니다. 상용 사용자의 경우 일부 사용자는 인터넷에 액세스하지 못하거나 인터넷을 통한 취득을 방지하기 위한 정책을 가지고 있지 않을 수 있습니다. 이러한 상황에서 Windows는 대체 위치에서 콘텐츠를 획득해야 합니다. 콘텐츠를 찾을 수 없으면 사용자가 좌절하고 다른 지원 센터 호출이 발생할 수 있습니다. 이 문제점을 선택적 콘텐츠를 획득하지 못했다고도 합니다.

선택적 콘텐츠를 획득하기 위한 옵션

대부분의 상업 조직은 위에서 설명한 문제점을 이해하고 있으며, 일반적으로 이러한 문제를 해결하기 위해 사용할 수 있는 계획을 묻는 논의가 시작됩니다. 다음 표에는 현재 Windows 클라이언트를 배포하는 방법에 따라 고려해야 할 여러 옵션이 포함되어 있습니다. 다음 정의는 테이블 제목에 사용됩니다.

  • 마이그레이션: 업데이트 중에 선택적 콘텐츠 마이그레이션을 지원합니다.
  • 취득: 선택적 콘텐츠 획득(즉, 사용자가 시작)을 지원합니다.
  • 미디어: 미디어 기반 배포에 적용됩니다.
  • 서비스: 서비스 기반 배포에 적용됩니다.
메서드 마이그레이션 Acquisition 미디어 서비스
옵션 1: Windows 업데이트 사용 아니오
옵션 2: UUP 통합과 함께 WSUS 사용 아니오
옵션 3: 동적 업데이트 사용 아니오
옵션 4: 배포하기 전에 Windows 이미지 사용자 지정 아니오 아니오
옵션 5: 배포 중 언어 기능 설치 부분 아니오 아니오
옵션 6: 배포 후 선택적 콘텐츠 설치 아니오
옵션 7: 주문형 기능에 대한 대체 원본 구성 아니오 부분

옵션 1: Windows 업데이트 사용

Windows 업데이트 클라이언트 정책은 선택적 콘텐츠 문제를 해결합니다. 선택적 콘텐츠는 Windows 설치 프로그램이 인근 Microsoft 콘텐츠 배달 네트워크에서 게시하고 획득할 수 있으며 통합 업데이트 플랫폼을 사용하여 획득합니다. 선택적 콘텐츠 마이그레이션 및 획득 시나리오는 디바이스가 Windows 업데이트 또는 Windows 업데이트 클라이언트 정책과 같은 통합 업데이트 플랫폼을 사용하는 업데이트 서비스에 연결된 경우에만 작동합니다. 어떤 이유로든 업데이트 중에 언어 팩을 설치하지 못하면 업데이트가 자동으로 롤백됩니다.

통합 업데이트 플랫폼은 기본 Windows 업데이트 기술이 개선되어 다운로드 크기가 줄어들고 업데이트를 확인하고, 필요한 패키지를 획득 및 설치하고, 한 업데이트 단계에서 최신 상태로 유지되는 보다 효율적인 프로토콜을 제공합니다. 이 기술은 Windows 클라이언트, Windows Server 및 HoloLens와 같은 기타 제품에 대한 업데이트 스택을 함께 제공하므로 통합됩니다.

Windows 업데이트 클라이언트 정책으로 이동하는 것이 좋습니다. 선택적 콘텐츠 시나리오는 오늘날 소비자 디바이스와 마찬가지로 원활하게 작동할 뿐만 아니라 더 작은 다운로드 크기의 모든 이점을 얻을 수 있습니다. 또한 운영 체제 설치 언어가 실수로 새 언어로 변경되는 경우 디바이스는 Windows 업그레이드의 어려움에 면역이 됩니다. 그렇지 않으면 설치 미디어에 다른 설치 언어가 있는 경우 향후 미디어 기반 기능 업데이트가 실패할 수 있습니다. 이 문제에 대한 자세한 내용은 설치 미디어가 원래 OS 설치 언어와 다른 Windows 10 디바이스 업그레이드를 참조하세요.

옵션 2: UUP 통합과 함께 WSUS 사용

2023년 3월부터 UUP는 WSUS 및 Configuration Manager 통합되어 온-프레미스 관리 솔루션에 Windows 업데이트 동일한 선택적 콘텐츠 및 획득 이점을 제공합니다. 예시:

  • FOD 및 언어는 WSUS의 승인된 Windows 11 버전 22H2 클라이언트 기능 업데이트를 사용하여 현재 위치 업데이트를 수행하는 디바이스에 대해 자동으로 마이그레이션됩니다. 마찬가지로 결합된 누적 업데이트, 설치 업데이트 및 안전한 OS 업데이트와 같은 업데이트가 포함되며 기능 업데이트가 승인된 달에 따라 현재 업데이트가 포함됩니다.

  • 로컬 Windows 이미지를 사용하여 업그레이드하지만 WSUS 또는 Configuration Manager 사용하여 결합된 누적 업데이트를 승인하는 디바이스는 업데이트된 Windows OS에서 선택적 콘텐츠 획득과 OS 자가 복구를 지원함으로써 이점을 얻을 수 있습니다.

이를 사용하도록 설정하는 데 필요한 콘텐츠는 인터넷 연결이 필요한 클라이언트 엔드포인트 없이 WSUS 또는 Configuration Manager 통해 획득됩니다. 이 개선을 사용하려면 주요 Windows 릴리스당 한 번 WSUS 콘텐츠 디렉터리 또는 배포 지점에 상당한 다운로드가 필요합니다. 여기에는 FOD 및 언어 획득을 지원하는 패키지와 손상으로 인한 OS 자가 복구를 사용하도록 설정하는 패키지가 포함됩니다. 자세한 내용은 WSUS 배포 계획을 참조하세요.

옵션 3: 동적 업데이트 사용

Windows 업데이트 이동할 준비가 되지 않은 경우 또 다른 옵션은 기능 업데이트 중에 동적 업데이트를 사용하도록 설정하는 것입니다. 미디어 기반 업데이트 또는 WSUS 기반 기능 업데이트를 통해 Windows 기능 업데이트가 시작되는 즉시 동적 업데이트가 호출되는 첫 번째 단계 중 하나입니다. Windows 설치 프로그램은 Microsoft에서 호스팅하는 인터넷 연결 URL에 연결하여 동적 업데이트 콘텐츠를 가져온 다음 해당 업데이트를 운영 체제 설치 미디어에 적용합니다. 획득한 콘텐츠에는 다음이 포함됩니다.

  • 설치 업데이트: Setup.exe 이진 파일 또는 설치 프로그램에서 기능 업데이트에 사용하는 파일을 수정합니다.
  • 안전한 OS 업데이트: WinRE(Windows 복구 환경)를 업데이트하는 데 사용되는 안전한 OS 에 대한 수정 사항입니다.
  • 서비스 스택 업데이트: Windows 서비스 스택 문제를 해결하는 데 필요하므로 기능 업데이트를 완료하는 데 필요한 수정 사항입니다.
  • 최신 누적 업데이트: 최신 누적 품질 업데이트를 설치합니다.
  • 드라이버 업데이트: 제조업체에서 이미 Windows 업데이트 게시하고 동적 업데이트를 위해 특별히 의미한 적용 가능한 드라이버의 최신 버전입니다.

새 운영 체제에 대한 이러한 업데이트 외에도 동적 업데이트는 업데이트 프로세스 중에 선택적 콘텐츠를 획득하여 업데이트가 완료되면 디바이스에 이 콘텐츠가 있는지 확인합니다. 따라서 디바이스가 Windows 업데이트 연결되어 있지는 않지만 가까운 Microsoft CDN(콘텐츠 다운로드 네트워크)에서 콘텐츠를 가져옵니다. 이 방법은 선택적 콘텐츠로 첫 번째 문제를 해결하지만 사용자가 시작한 취득은 처리하지 않습니다. 기본적으로 동적 업데이트 는 Windows 설치 프로그램에서 사용하도록 설정됩니다. Windows 설치 프로그램에서 /DynamicUpdate 옵션을 사용하여 동적 업데이트를 사용하거나 사용하지 않도록 설정할 수 있습니다. 서비스 기반 접근 방식을 사용하는 경우 를 사용하여 이 값을 setupconfig.ini설정할 수 있습니다. 자세한 내용은 Windows 설치 자동화 개요 를 참조하세요.

동적 업데이트는 추가 옵션으로 구성할 수 있습니다. 예를 들어, 최신 품질 업데이트를 자동으로 획득하지 않고도 선택적 콘텐츠 마이그레이션의 이점을 누릴 수 있습니다. Windows 설치 프로그램의 /DynamicUpdate NoLCU 옵션을 사용하여 이 작업을 수행할 수 있습니다. 그런 다음, 월별 업데이트를 테스트하고 승인하기 위해 기존 프로세스를 별도로 따릅니다. 이 방법의 단점은 기능 업데이트 중에 사용할 수 없었기 때문에 최신 누적 업데이트를 위해 디바이스를 다시 부팅하는 것입니다.

동적 업데이트를 사용할 때 한 가지 추가 고려 사항은 네트워크에 미치는 영향입니다. 이 접근 방식의 주요 방해 요소 중 하나는 각 디바이스가 Microsoft에서 이 콘텐츠를 별도로 가져올 것이라는 우려입니다. 설치 프로그램은 사용 가능한 경우 배달 최적화를 사용하여 동적 업데이트 콘텐츠를 다운로드합니다. 인터넷에 연결되지 않은 디바이스의 경우 WSUS 및 Microsoft 카탈로그를 사용하여 동적 업데이트 콘텐츠의 하위 집합을 사용할 수 있습니다.

옵션 4: 배포하기 전에 Windows 이미지 사용자 지정

많은 조직에서 배포 워크플로에는 미디어 기반 업데이트를 수행하는 Configuration Manager 작업 순서가 포함됩니다. 일부 고객은 인터넷에 연결되어 있지 않거나 연결이 좋지 않아 동적 업데이트를 사용하도록 설정할 수 없습니다. 이러한 경우 배포 전에 선택적 콘텐츠를 설치하는 것이 좋습니다. 이 작업을 설치 미디어 사용자 지정이라고도 합니다.

다음과 같은 방법으로 Windows 이미지를 사용자 지정할 수 있습니다.

  • 누적 업데이트 적용
  • 서비스 스택에 업데이트 적용
  • 설치 프로그램에서 기능 업데이트에 Setup.exe 사용하는 이진 파일 또는 기타 파일에 업데이트 적용
  • Windows 복구 환경에 사용되는 안전한 운영 체제 (SafeOS)에 대한 업데이트 적용
  • 언어 추가 또는 제거
  • 주문형 기능 추가 또는 제거

이 옵션의 이점은 Windows 이미지에 일회성 업데이트를 통해 추가 언어, 언어 환경 기능 및 기타 주문형 기능을 포함할 수 있다는 것입니다. 그런 다음 기존 작업 순서 또는 관련된 사용자 지정 배포에서 Setup.exe 사용할 수 있습니다. 이 방법의 단점은 추가 패키지를 설치하기 위해 DISM을 사용하여 스크립팅을 포함하여 이미지를 미리 준비해야 한다는 것입니다. 또한 이미지를 사용하는 모든 디바이스에서 이미지가 동일하며 일부 사용자가 필요로 하는 것보다 더 많은 기능을 포함할 수 있음을 의미합니다. 미디어 사용자 지정에 대한 자세한 내용은 동적 업데이트 패키지로 Windows 10 미디어 업데이트를 참조하세요. 동적 업데이트와 마찬가지로 선택적 콘텐츠 마이그레이션을 위한 솔루션이 있지만 사용자가 시작한 선택적 콘텐츠 취득을 지원하지는 않습니다. 또한 설치 직전에 디바이스 에서 미디어를 업데이트하는 이 옵션의 변형이 있습니다. 이 옵션을 사용하면 현재 설치된 항목에 따라 디바이스별 이미지 사용자 지정을 수행할 수 있습니다.

옵션 5: 배포 중 언어 기능 설치

업그레이드 중에 선택적 콘텐츠를 마이그레이션하지 못하는 첫 번째 문제를 해결하기 위한 부분적인 해결 방법은 업그레이드 프로세스 중에 선택적 콘텐츠의 하위 집합을 삽입하는 것입니다. 이 방법은 Windows 설치 옵션 /InstallLangPacks 를 사용하여 패키지가 포함된 폴더에서 언어 팩 및 언어 기능(예: 텍스트 음성 변환 인식)을 추가합니다. 이 방법을 사용하면 IT 전문가가 선택적 콘텐츠의 하위 집합을 가져와 네트워크 내에서 스테이징할 수 있습니다. 서비스 기반 접근 방식을 사용하는 경우 를 사용하여 setupconfig.iniInstallLangPacks를 구성할 수 있습니다. 자세한 내용은 Windows 설치 자동화 개요를 참조하세요.

설치 프로그램이 실행되면 설치하는 동안 이러한 패키지를 새 운영 체제에 삽입합니다. 동적 업데이트를 사용하도록 설정하거나 배포 전에 운영 체제 이미지를 사용자 지정하는 대신 사용할 수 있습니다. 패키지의 이름을 바꿀 수 없으므로 이 방법을 주의해야 합니다. 또한 콘텐츠는 두 개의 별도 릴리스 미디어 ISO에서 제공됩니다. 핵심은 FOD ISO의 FOD 패키지와 FOD 메타데이터 .cab 폴더로 복사하고 LPLIP ISO에서 아키텍처별 언어 팩 .cab 파일을 복사하는 것입니다. InstallLangPacks 오류를 치명적으로 처리하고 전체 업그레이드를 롤백합니다. 미디어 기반 업그레이드는 FOD 및 언어를 마이그레이션하지 않으므로(동적 업데이트를 사용하도록 설정하지 않는 한) 사용자를 잘못된 상태로 두지 않는 것이 좋습니다.

이 방법은 몇 가지 흥미로운 이점이 있습니다. 원래 Windows 이미지는 수정할 필요가 없으므로 시간과 스크립팅을 절약할 수 있습니다.

옵션 6: 배포 후 선택적 콘텐츠 설치

이 옵션은 배포된 후 더 많은 선택적 콘텐츠로 운영 체제 이미지를 사용자 지정한다는 측면에서 옵션 4와 같습니다. IT 전문가는 기능 업데이트 중 및 이후에 고유한 사용자 지정 작업 스크립트를 실행하여 Windows 설치 프로그램의 동작을 확장할 수 있습니다. 자세한 내용은 기능 업데이트 중에 사용자 지정 작업 실행을 참조하세요. 이 방법을 사용하면 운영 체제에 설치된 선택적 콘텐츠를 캡처한 다음 이 목록을 저장하여 새 운영 체제에 동일한 선택적 콘텐츠를 설치하여 선택적 콘텐츠의 디바이스별 마이그레이션을 만들 수 있습니다. 옵션 5와 마찬가지로 선택적 콘텐츠 패키지의 원본을 포함하는 네트워크 공유를 내부적으로 호스트합니다. 그런 다음 디바이스에서 설치 프로그램을 실행하는 동안 원본 운영 체제에서 설치된 선택적 콘텐츠 목록을 캡처하고 저장합니다. 나중에 설치가 완료되면 목록을 사용하여 선택적 콘텐츠를 설치합니다. 이 콘텐츠는 기능 손실 없이 사용자의 디바이스를 그대로 둡니다.

옵션 7: 선택적 콘텐츠에 대한 대체 원본 구성

일부 옵션은 현재 위치 업데이트 중에 선택적 콘텐츠 마이그레이션 문제를 해결하는 방법을 다룹니다. 사용자가 시작한 경우 선택적 콘텐츠를 쉽게 획득하는 두 번째 문제를 해결하려면 선택적 구성 요소 설치 및 구성 요소 복구 그룹 정책 대한 설정 지정을 사용하여 각 디바이스를 구성할 수 있습니다. 이 정책 설정은 운영 체제 손상을 복구하고 페이로드 파일이 제거된 선택적 기능을 사용하도록 설정하는 데 사용할 네트워크 위치를 지정합니다. 이 방법은 네트워크 내에서 호스트할 콘텐츠가 더 많을 경우(일부 클라이언트에 배포할 수 있는 운영 체제 이미지 외에도) 단점이 있지만 네트워크 내에서 콘텐츠를 획득할 수 있다는 장점이 있습니다. 이 정책에 대한 몇 가지 미리 알림:

  • 대체 원본의 파일 경로는 정규화된 경로여야 합니다. 여러 위치를 세미콜론으로 구분할 수 있습니다.
  • 이 설정은 대체 원본 파일 경로에서 언어 팩 설치를 지원하지 않으며 주문형 기능만 지원합니다. 정책이 Windows 업데이트 콘텐츠를 획득하도록 구성된 경우 언어 팩이 획득됩니다.
  • 이 설정을 구성하거나 사용하지 않도록 설정하지 않으면 기본 Windows 업데이트 위치(예: 클라이언트 정책 또는 WSUS Windows 업데이트)에서 파일이 다운로드됩니다.

자세한 내용은 Windows 복구 원본 구성WSUS 또는 Configuration Manager 사용할 때 주문형 기능 및 언어 팩을 사용할 수 있도록 하는 방법을 참조하세요.

추가 리소스

통합 업데이트 플랫폼 및 이 문서에 설명된 접근 방식에 대한 자세한 내용은 다음 리소스를 참조하세요.

샘플 스크립트

옵션 4 및 6은 가장 많은 스크립팅을 포함합니다. 옵션 4에 대한 샘플 스크립트가 이미 있으므로 옵션 6: 배포 후 선택적 콘텐츠 설치에 대한 샘플 스크립트를 살펴보겠습니다.

선택적 콘텐츠 리포지토리 만들기

시작하기 위해 네트워크 공유에 선택적 콘텐츠 및 호스트의 리포지토리를 빌드합니다. 이 콘텐츠는 각 릴리스와 함께 제공되는 FOD 및 언어 팩 ISO의 콘텐츠 하위 집합입니다. DISM /Export를 사용하여 organization 필요한 FOD만 사용하여 이 리포지토리 또는 리포지토리를 구성합니다. 예를 들어 기존 디바이스에 설치된 선택적 기능의 인벤토리를 사용하는 기반의 상위 집합입니다. 이 경우 Windows Mixed Reality 기능을 제외합니다. 또한 모든 언어 팩을 리포지토리의 루트에 복사합니다.

# Declare media for FOD and LPs
$LP_ISO_PATH = "C:\_IMAGE\2004_ISO\CLIENTLANGPACKDVD_OEM_MULTI.iso"
$FOD_ISO_PATH = "C:\_IMAGE\2004_ISO\FOD-PACKAGES_OEM_PT1_amd64fre_MULTI.iso"

# Declare folders
$WORKING_PATH = "C:\_IMAGE\BuildRepo"
$MEDIA_PATH = "C:\_IMAGE\2004_SETUP"

$MAIN_OS_MOUNT = $WORKING_PATH + "\MainOSMount"
$REPO_PATH = $WORKING_PATH + "\Repo"

# Create folders for mounting image optional content repository
if (Test-Path $MAIN_OS_MOUNT) {
    Remove-Item -Path $MAIN_OS_MOUNT -Force -Recurse -ErrorAction stop| Out-Null
}

if (Test-Path $REPO_PATH) {
    Remove-Item -Path $REPO_PATH -Force -Recurse -ErrorAction stop| Out-Null
}

New-Item -ItemType Directory -Force -Path $MAIN_OS_MOUNT -ErrorAction stop| Out-Null
New-Item -ItemType Directory -Force -Path $REPO_PATH -ErrorAction stop| Out-Null

# Mount the main OS, I'll use this throughout the script
Write-Host "Mounting main OS"
Mount-WindowsImage -ImagePath $MEDIA_PATH"\sources\install.wim" -Index 1 -Path $MAIN_OS_MOUNT -ErrorAction stop| Out-Null

# Mount the LP ISO
Write-Host "Mounting LP ISO"
$LP_ISO_DRIVE_LETTER = (Mount-DiskImage -ImagePath $LP_ISO_PATH -ErrorAction stop | Get-Volume).DriveLetter

# Declare language related cabs
$OS_LP_PATH = $LP_ISO_DRIVE_LETTER + ":\x64\langpacks\" + "*.cab"

# Mount the FOD ISO
Write-Host "Mounting FOD ISO"
$FOD_ISO_DRIVE_LETTER = (Mount-DiskImage -ImagePath $FOD_ISO_PATH -ErrorAction stop | Get-Volume).DriveLetter
$FOD_PATH = $FOD_ISO_DRIVE_LETTER + ":\"

# Export the FODs from the ISO that we are interested in
Write-Host "Exporting FODs to Repo"
DISM /image:$MAIN_OS_MOUNT /export-source /source:$FOD_PATH /target:$REPO_PATH `
    /capabilityname:Accessibility.Braille~~~~0.0.1.0 `
    /capabilityname:App.StepsRecorder~~~~0.0.1.0 `
    /capabilityname:App.WirelessDisplay.Connect~~~~0.0.1.0 `
    /capabilityname:Browser.InternetExplorer~~~~0.0.11.0 `
    /capabilityname:DirectX.Configuration.Database~~~~0.0.1.0 `
    /capabilityname:Language.Basic~~~af-za~0.0.1.0 `
    /capabilityname:Language.Basic~~~ar-sa~0.0.1.0 `
    /capabilityname:Language.Basic~~~as-in~0.0.1.0 `
    /capabilityname:Language.Basic~~~az-latn-az~0.0.1.0 `
    /capabilityname:Language.Basic~~~ba-ru~0.0.1.0 `
    /capabilityname:Language.Basic~~~be-by~0.0.1.0 `
    /capabilityname:Language.Basic~~~bg-bg~0.0.1.0 `
    /capabilityname:Language.Basic~~~bn-bd~0.0.1.0 `
    /capabilityname:Language.Basic~~~bn-in~0.0.1.0 `
    /capabilityname:Language.Basic~~~bs-latn-ba~0.0.1.0 `
    /capabilityname:Language.Basic~~~ca-es~0.0.1.0 `
    /capabilityname:Language.Basic~~~cs-cz~0.0.1.0 `
    /capabilityname:Language.Basic~~~cy-gb~0.0.1.0 `
    /capabilityname:Language.Basic~~~da-dk~0.0.1.0 `
    /capabilityname:Language.Basic~~~de-ch~0.0.1.0 `
    /capabilityname:Language.Basic~~~de-de~0.0.1.0 `
    /capabilityname:Language.Basic~~~el-gr~0.0.1.0 `
    /capabilityname:Language.Basic~~~en-au~0.0.1.0 `
    /capabilityname:Language.Basic~~~en-ca~0.0.1.0 `
    /capabilityname:Language.Basic~~~en-gb~0.0.1.0 `
    /capabilityname:Language.Basic~~~en-in~0.0.1.0 `
    /capabilityname:Language.Basic~~~en-us~0.0.1.0 `
    /capabilityname:Language.Basic~~~es-es~0.0.1.0 `
    /capabilityname:Language.Basic~~~es-mx~0.0.1.0 `
    /capabilityname:Language.Basic~~~es-us~0.0.1.0 `
    /capabilityname:Language.Basic~~~et-ee~0.0.1.0 `
    /capabilityname:Language.Basic~~~eu-es~0.0.1.0 `
    /capabilityname:Language.Basic~~~fa-ir~0.0.1.0 `
    /capabilityname:Language.Basic~~~fi-fi~0.0.1.0 `
    /capabilityname:Language.Basic~~~fil-ph~0.0.1.0 `
    /capabilityname:Language.Basic~~~fr-be~0.0.1.0 `
    /capabilityname:Language.Basic~~~fr-ca~0.0.1.0 `
    /capabilityname:Language.Basic~~~fr-ch~0.0.1.0 `
    /capabilityname:Language.Basic~~~fr-fr~0.0.1.0 `
    /capabilityname:Language.Basic~~~ga-ie~0.0.1.0 `
    /capabilityname:Language.Basic~~~gd-gb~0.0.1.0 `
    /capabilityname:Language.Basic~~~gl-es~0.0.1.0 `
    /capabilityname:Language.Basic~~~gu-in~0.0.1.0 `
    /capabilityname:Language.Basic~~~ha-latn-ng~0.0.1.0 `
    /capabilityname:Language.Basic~~~haw-us~0.0.1.0 `
    /capabilityname:Language.Basic~~~he-il~0.0.1.0 `
    /capabilityname:Language.Basic~~~hi-in~0.0.1.0 `
    /capabilityname:Language.Basic~~~hr-hr~0.0.1.0 `
    /capabilityname:Language.Basic~~~hu-hu~0.0.1.0 `
    /capabilityname:Language.Basic~~~hy-am~0.0.1.0 `
    /capabilityname:Language.Basic~~~id-id~0.0.1.0 `
    /capabilityname:Language.Basic~~~ig-ng~0.0.1.0 `
    /capabilityname:Language.Basic~~~is-is~0.0.1.0 `
    /capabilityname:Language.Basic~~~it-it~0.0.1.0 `
    /capabilityname:Language.Basic~~~ja-jp~0.0.1.0 `
    /capabilityname:Language.Basic~~~ka-ge~0.0.1.0 `
    /capabilityname:Language.Basic~~~kk-kz~0.0.1.0 `
    /capabilityname:Language.Basic~~~kl-gl~0.0.1.0 `
    /capabilityname:Language.Basic~~~kn-in~0.0.1.0 `
    /capabilityname:Language.Basic~~~kok-deva-in~0.0.1.0 `
    /capabilityname:Language.Basic~~~ko-kr~0.0.1.0 `
    /capabilityname:Language.Basic~~~ky-kg~0.0.1.0 `
    /capabilityname:Language.Basic~~~lb-lu~0.0.1.0 `
    /capabilityname:Language.Basic~~~lt-lt~0.0.1.0 `
    /capabilityname:Language.Basic~~~lv-lv~0.0.1.0 `
    /capabilityname:Language.Basic~~~mi-nz~0.0.1.0 `
    /capabilityname:Language.Basic~~~mk-mk~0.0.1.0 `
    /capabilityname:Language.Basic~~~ml-in~0.0.1.0 `
    /capabilityname:Language.Basic~~~mn-mn~0.0.1.0 `
    /capabilityname:Language.Basic~~~mr-in~0.0.1.0 `
    /capabilityname:Language.Basic~~~ms-bn~0.0.1.0 `
    /capabilityname:Language.Basic~~~ms-my~0.0.1.0 `
    /capabilityname:Language.Basic~~~mt-mt~0.0.1.0 `
    /capabilityname:Language.Basic~~~nb-no~0.0.1.0 `
    /capabilityname:Language.Basic~~~ne-np~0.0.1.0 `
    /capabilityname:Language.Basic~~~nl-nl~0.0.1.0 `
    /capabilityname:Language.Basic~~~nn-no~0.0.1.0 `
    /capabilityname:Language.Basic~~~nso-za~0.0.1.0 `
    /capabilityname:Language.Basic~~~or-in~0.0.1.0 `
    /capabilityname:Language.Basic~~~pa-in~0.0.1.0 `
    /capabilityname:Language.Basic~~~pl-pl~0.0.1.0 `
    /capabilityname:Language.Basic~~~ps-af~0.0.1.0 `
    /capabilityname:Language.Basic~~~pt-br~0.0.1.0 `
    /capabilityname:Language.Basic~~~pt-pt~0.0.1.0 `
    /capabilityname:Language.Basic~~~rm-ch~0.0.1.0 `
    /capabilityname:Language.Basic~~~ro-ro~0.0.1.0 `
    /capabilityname:Language.Basic~~~ru-ru~0.0.1.0 `
    /capabilityname:Language.Basic~~~rw-rw~0.0.1.0 `
    /capabilityname:Language.Basic~~~sah-ru~0.0.1.0 `
    /capabilityname:Language.Basic~~~si-lk~0.0.1.0 `
    /capabilityname:Language.Basic~~~sk-sk~0.0.1.0 `
    /capabilityname:Language.Basic~~~sl-si~0.0.1.0 `
    /capabilityname:Language.Basic~~~sq-al~0.0.1.0 `
    /capabilityname:Language.Basic~~~sr-cyrl-rs~0.0.1.0 `
    /capabilityname:Language.Basic~~~sr-latn-rs~0.0.1.0 `
    /capabilityname:Language.Basic~~~sv-se~0.0.1.0 `
    /capabilityname:Language.Basic~~~sw-ke~0.0.1.0 `
    /capabilityname:Language.Basic~~~ta-in~0.0.1.0 `
    /capabilityname:Language.Basic~~~te-in~0.0.1.0 `
    /capabilityname:Language.Basic~~~tg-cyrl-tj~0.0.1.0 `
    /capabilityname:Language.Basic~~~th-th~0.0.1.0 `
    /capabilityname:Language.Basic~~~tk-tm~0.0.1.0 `
    /capabilityname:Language.Basic~~~tn-za~0.0.1.0 `
    /capabilityname:Language.Basic~~~tr-tr~0.0.1.0 `
    /capabilityname:Language.Basic~~~tt-ru~0.0.1.0 `
    /capabilityname:Language.Basic~~~ug-cn~0.0.1.0 `
    /capabilityname:Language.Basic~~~uk-ua~0.0.1.0 `
    /capabilityname:Language.Basic~~~ur-pk~0.0.1.0 `
    /capabilityname:Language.Basic~~~uz-latn-uz~0.0.1.0 `
    /capabilityname:Language.Basic~~~vi-vn~0.0.1.0 `
    /capabilityname:Language.Basic~~~wo-sn~0.0.1.0 `
    /capabilityname:Language.Basic~~~xh-za~0.0.1.0 `
    /capabilityname:Language.Basic~~~yo-ng~0.0.1.0 `
    /capabilityname:Language.Basic~~~zh-cn~0.0.1.0 `
    /capabilityname:Language.Basic~~~zh-hk~0.0.1.0 `
    /capabilityname:Language.Basic~~~zh-tw~0.0.1.0 `
    /capabilityname:Language.Basic~~~zu-za~0.0.1.0 `
    /capabilityname:Language.Fonts.Arab~~~und-Arab~0.0.1.0 `
    /capabilityname:Language.Fonts.Beng~~~und-Beng~0.0.1.0 `
    /capabilityname:Language.Fonts.Cans~~~und-Cans~0.0.1.0 `
    /capabilityname:Language.Fonts.Cher~~~und-Cher~0.0.1.0 `
    /capabilityname:Language.Fonts.Deva~~~und-Deva~0.0.1.0 `
    /capabilityname:Language.Fonts.Ethi~~~und-Ethi~0.0.1.0 `
    /capabilityname:Language.Fonts.Gujr~~~und-Gujr~0.0.1.0 `
    /capabilityname:Language.Fonts.Guru~~~und-Guru~0.0.1.0 `
    /capabilityname:Language.Fonts.Hans~~~und-Hans~0.0.1.0 `
    /capabilityname:Language.Fonts.Hant~~~und-Hant~0.0.1.0 `
    /capabilityname:Language.Fonts.Hebr~~~und-Hebr~0.0.1.0 `
    /capabilityname:Language.Fonts.Jpan~~~und-Jpan~0.0.1.0 `
    /capabilityname:Language.Fonts.Khmr~~~und-Khmr~0.0.1.0 `
    /capabilityname:Language.Fonts.Knda~~~und-Knda~0.0.1.0 `
    /capabilityname:Language.Fonts.Kore~~~und-Kore~0.0.1.0 `
    /capabilityname:Language.Fonts.Laoo~~~und-Laoo~0.0.1.0 `
    /capabilityname:Language.Fonts.Mlym~~~und-Mlym~0.0.1.0 `
    /capabilityname:Language.Fonts.Orya~~~und-Orya~0.0.1.0 `
    /capabilityname:Language.Fonts.PanEuropeanSupplementalFonts~~~0.0.1.0 `
    /capabilityname:Language.Fonts.Sinh~~~und-Sinh~0.0.1.0 `
    /capabilityname:Language.Fonts.Syrc~~~und-Syrc~0.0.1.0 `
    /capabilityname:Language.Fonts.Taml~~~und-Taml~0.0.1.0 `
    /capabilityname:Language.Fonts.Telu~~~und-Telu~0.0.1.0 `
    /capabilityname:Language.Fonts.Thai~~~und-Thai~0.0.1.0 `
    /capabilityname:Language.Handwriting~~~af-za~0.0.1.0 `
    /capabilityname:Language.Handwriting~~~bs-latn-ba~0.0.1.0 `
    /capabilityname:Language.Handwriting~~~ca-es~0.0.1.0 `
    /capabilityname:Language.Handwriting~~~cs-cz~0.0.1.0 `
    /capabilityname:Language.Handwriting~~~cy-gb~0.0.1.0 `
    /capabilityname:Language.Handwriting~~~da-dk~0.0.1.0 `
    /capabilityname:Language.Handwriting~~~de-de~0.0.1.0 `
    /capabilityname:Language.Handwriting~~~el-gr~0.0.1.0 `
    /capabilityname:Language.Handwriting~~~en-gb~0.0.1.0 `
    /capabilityname:Language.Handwriting~~~en-us~0.0.1.0 `
    /capabilityname:Language.Handwriting~~~es-es~0.0.1.0 `
    /capabilityname:Language.Handwriting~~~es-mx~0.0.1.0 `
    /capabilityname:Language.Handwriting~~~eu-es~0.0.1.0 `
    /capabilityname:Language.Handwriting~~~fi-fi~0.0.1.0 `
    /capabilityname:Language.Handwriting~~~fr-fr~0.0.1.0 `
    /capabilityname:Language.Handwriting~~~ga-ie~0.0.1.0 `
    /capabilityname:Language.Handwriting~~~gd-gb~0.0.1.0 `
    /capabilityname:Language.Handwriting~~~gl-es~0.0.1.0 `
    /capabilityname:Language.Handwriting~~~hi-in~0.0.1.0 `
    /capabilityname:Language.Handwriting~~~hr-hr~0.0.1.0 `
    /capabilityname:Language.Handwriting~~~id-id~0.0.1.0 `
    /capabilityname:Language.Handwriting~~~it-it~0.0.1.0 `
    /capabilityname:Language.Handwriting~~~ja-jp~0.0.1.0 `
    /capabilityname:Language.Handwriting~~~ko-kr~0.0.1.0 `
    /capabilityname:Language.Handwriting~~~lb-lu~0.0.1.0 `
    /capabilityname:Language.Handwriting~~~mi-nz~0.0.1.0 `
    /capabilityname:Language.Handwriting~~~ms-bn~0.0.1.0 `
    /capabilityname:Language.Handwriting~~~ms-my~0.0.1.0 `
    /capabilityname:Language.Handwriting~~~nb-no~0.0.1.0 `
    /capabilityname:Language.Handwriting~~~nl-nl~0.0.1.0 `
    /capabilityname:Language.Handwriting~~~nn-no~0.0.1.0 `
    /capabilityname:Language.Handwriting~~~nso-za~0.0.1.0 `
    /capabilityname:Language.Handwriting~~~pl-pl~0.0.1.0 `
    /capabilityname:Language.Handwriting~~~pt-br~0.0.1.0 `
    /capabilityname:Language.Handwriting~~~pt-pt~0.0.1.0 `
    /capabilityname:Language.Handwriting~~~rm-ch~0.0.1.0 `
    /capabilityname:Language.Handwriting~~~ro-ro~0.0.1.0 `
    /capabilityname:Language.Handwriting~~~ru-ru~0.0.1.0 `
    /capabilityname:Language.Handwriting~~~rw-rw~0.0.1.0 `
    /capabilityname:Language.Handwriting~~~sk-sk~0.0.1.0 `
    /capabilityname:Language.Handwriting~~~sl-si~0.0.1.0 `
    /capabilityname:Language.Handwriting~~~sq-al~0.0.1.0 `
    /capabilityname:Language.Handwriting~~~sr-cyrl-rs~0.0.1.0 `
    /capabilityname:Language.Handwriting~~~sr-latn-rs~0.0.1.0 `
    /capabilityname:Language.Handwriting~~~sv-se~0.0.1.0 `
    /capabilityname:Language.Handwriting~~~sw-ke~0.0.1.0 `
    /capabilityname:Language.Handwriting~~~tn-za~0.0.1.0 `
    /capabilityname:Language.Handwriting~~~tr-tr~0.0.1.0 `
    /capabilityname:Language.Handwriting~~~wo-sn~0.0.1.0 `
    /capabilityname:Language.Handwriting~~~xh-za~0.0.1.0 `
    /capabilityname:Language.Handwriting~~~zh-cn~0.0.1.0 `
    /capabilityname:Language.Handwriting~~~zh-hk~0.0.1.0 `
    /capabilityname:Language.Handwriting~~~zh-tw~0.0.1.0 `
    /capabilityname:Language.Handwriting~~~zu-za~0.0.1.0 `
    /capabilityname:Language.LocaleData~~~zh-tw~0.0.1.0 `
    /capabilityname:Language.OCR~~~ar-sa~0.0.1.0 `
    /capabilityname:Language.OCR~~~bg-bg~0.0.1.0 `
    /capabilityname:Language.OCR~~~bs-latn-ba~0.0.1.0 `
    /capabilityname:Language.OCR~~~cs-cz~0.0.1.0 `
    /capabilityname:Language.OCR~~~da-dk~0.0.1.0 `
    /capabilityname:Language.OCR~~~de-de~0.0.1.0 `
    /capabilityname:Language.OCR~~~el-gr~0.0.1.0 `
    /capabilityname:Language.OCR~~~en-gb~0.0.1.0 `
    /capabilityname:Language.OCR~~~en-us~0.0.1.0 `
    /capabilityname:Language.OCR~~~es-es~0.0.1.0 `
    /capabilityname:Language.OCR~~~es-mx~0.0.1.0 `
    /capabilityname:Language.OCR~~~fi-fi~0.0.1.0 `
    /capabilityname:Language.OCR~~~fr-ca~0.0.1.0 `
    /capabilityname:Language.OCR~~~fr-fr~0.0.1.0 `
    /capabilityname:Language.OCR~~~hr-hr~0.0.1.0 `
    /capabilityname:Language.OCR~~~hu-hu~0.0.1.0 `
    /capabilityname:Language.OCR~~~it-it~0.0.1.0 `
    /capabilityname:Language.OCR~~~ja-jp~0.0.1.0 `
    /capabilityname:Language.OCR~~~ko-kr~0.0.1.0 `
    /capabilityname:Language.OCR~~~nb-no~0.0.1.0 `
    /capabilityname:Language.OCR~~~nl-nl~0.0.1.0 `
    /capabilityname:Language.OCR~~~pl-pl~0.0.1.0 `
    /capabilityname:Language.OCR~~~pt-br~0.0.1.0 `
    /capabilityname:Language.OCR~~~pt-pt~0.0.1.0 `
    /capabilityname:Language.OCR~~~ro-ro~0.0.1.0 `
    /capabilityname:Language.OCR~~~ru-ru~0.0.1.0 `
    /capabilityname:Language.OCR~~~sk-sk~0.0.1.0 `
    /capabilityname:Language.OCR~~~sl-si~0.0.1.0 `
    /capabilityname:Language.OCR~~~sr-cyrl-rs~0.0.1.0 `
    /capabilityname:Language.OCR~~~sr-latn-rs~0.0.1.0 `
    /capabilityname:Language.OCR~~~sv-se~0.0.1.0 `
    /capabilityname:Language.OCR~~~tr-tr~0.0.1.0 `
    /capabilityname:Language.OCR~~~zh-cn~0.0.1.0 `
    /capabilityname:Language.OCR~~~zh-hk~0.0.1.0 `
    /capabilityname:Language.OCR~~~zh-tw~0.0.1.0 `
    /capabilityname:Language.Speech~~~da-dk~0.0.1.0 `
    /capabilityname:Language.Speech~~~de-de~0.0.1.0 `
    /capabilityname:Language.Speech~~~en-au~0.0.1.0 `
    /capabilityname:Language.Speech~~~en-ca~0.0.1.0 `
    /capabilityname:Language.Speech~~~en-gb~0.0.1.0 `
    /capabilityname:Language.Speech~~~en-in~0.0.1.0 `
    /capabilityname:Language.Speech~~~en-us~0.0.1.0 `
    /capabilityname:Language.Speech~~~es-es~0.0.1.0 `
    /capabilityname:Language.Speech~~~es-mx~0.0.1.0 `
    /capabilityname:Language.Speech~~~fr-ca~0.0.1.0 `
    /capabilityname:Language.Speech~~~fr-fr~0.0.1.0 `
    /capabilityname:Language.Speech~~~it-it~0.0.1.0 `
    /capabilityname:Language.Speech~~~ja-jp~0.0.1.0 `
    /capabilityname:Language.Speech~~~pt-br~0.0.1.0 `
    /capabilityname:Language.Speech~~~zh-cn~0.0.1.0 `
    /capabilityname:Language.Speech~~~zh-hk~0.0.1.0 `
    /capabilityname:Language.Speech~~~zh-tw~0.0.1.0 `
    /capabilityname:Language.TextToSpeech~~~ar-eg~0.0.1.0 `
    /capabilityname:Language.TextToSpeech~~~ar-sa~0.0.1.0 `
    /capabilityname:Language.TextToSpeech~~~bg-bg~0.0.1.0 `
    /capabilityname:Language.TextToSpeech~~~ca-es~0.0.1.0 `
    /capabilityname:Language.TextToSpeech~~~cs-cz~0.0.1.0 `
    /capabilityname:Language.TextToSpeech~~~da-dk~0.0.1.0 `
    /capabilityname:Language.TextToSpeech~~~de-at~0.0.1.0 `
    /capabilityname:Language.TextToSpeech~~~de-ch~0.0.1.0 `
    /capabilityname:Language.TextToSpeech~~~de-de~0.0.1.0 `
    /capabilityname:Language.TextToSpeech~~~el-gr~0.0.1.0 `
    /capabilityname:Language.TextToSpeech~~~en-au~0.0.1.0 `
    /capabilityname:Language.TextToSpeech~~~en-ca~0.0.1.0 `
    /capabilityname:Language.TextToSpeech~~~en-gb~0.0.1.0 `
    /capabilityname:Language.TextToSpeech~~~en-ie~0.0.1.0 `
    /capabilityname:Language.TextToSpeech~~~en-in~0.0.1.0 `
    /capabilityname:Language.TextToSpeech~~~en-us~0.0.1.0 `
    /capabilityname:Language.TextToSpeech~~~es-es~0.0.1.0 `
    /capabilityname:Language.TextToSpeech~~~es-mx~0.0.1.0 `
    /capabilityname:Language.TextToSpeech~~~fi-fi~0.0.1.0 `
    /capabilityname:Language.TextToSpeech~~~fr-ca~0.0.1.0 `
    /capabilityname:Language.TextToSpeech~~~fr-ch~0.0.1.0 `
    /capabilityname:Language.TextToSpeech~~~fr-fr~0.0.1.0 `
    /capabilityname:Language.TextToSpeech~~~he-il~0.0.1.0 `
    /capabilityname:Language.TextToSpeech~~~hi-in~0.0.1.0 `
    /capabilityname:Language.TextToSpeech~~~hr-hr~0.0.1.0 `
    /capabilityname:Language.TextToSpeech~~~hu-hu~0.0.1.0 `
    /capabilityname:Language.TextToSpeech~~~id-id~0.0.1.0 `
    /capabilityname:Language.TextToSpeech~~~it-it~0.0.1.0 `
    /capabilityname:Language.TextToSpeech~~~ja-jp~0.0.1.0 `
    /capabilityname:Language.TextToSpeech~~~ko-kr~0.0.1.0 `
    /capabilityname:Language.TextToSpeech~~~ms-my~0.0.1.0 `
    /capabilityname:Language.TextToSpeech~~~nb-no~0.0.1.0 `
    /capabilityname:Language.TextToSpeech~~~nl-be~0.0.1.0 `
    /capabilityname:Language.TextToSpeech~~~nl-nl~0.0.1.0 `
    /capabilityname:Language.TextToSpeech~~~pl-pl~0.0.1.0 `
    /capabilityname:Language.TextToSpeech~~~pt-br~0.0.1.0 `
    /capabilityname:Language.TextToSpeech~~~pt-pt~0.0.1.0 `
    /capabilityname:Language.TextToSpeech~~~ro-ro~0.0.1.0 `
    /capabilityname:Language.TextToSpeech~~~ru-ru~0.0.1.0 `
    /capabilityname:Language.TextToSpeech~~~sk-sk~0.0.1.0 `
    /capabilityname:Language.TextToSpeech~~~sl-si~0.0.1.0 `
    /capabilityname:Language.TextToSpeech~~~sv-se~0.0.1.0 `
    /capabilityname:Language.TextToSpeech~~~ta-in~0.0.1.0 `
    /capabilityname:Language.TextToSpeech~~~th-th~0.0.1.0 `
    /capabilityname:Language.TextToSpeech~~~tr-tr~0.0.1.0 `
    /capabilityname:Language.TextToSpeech~~~vi-vn~0.0.1.0 `
    /capabilityname:Language.TextToSpeech~~~zh-cn~0.0.1.0 `
    /capabilityname:Language.TextToSpeech~~~zh-hk~0.0.1.0 `
    /capabilityname:Language.TextToSpeech~~~zh-tw~0.0.1.0 `
    /capabilityname:MathRecognizer~~~~0.0.1.0 `
    /capabilityname:Microsoft.Onecore.StorageManagement~~~~0.0.1.0 `
    /capabilityname:Microsoft.WebDriver~~~~0.0.1.0 `
    /capabilityname:Microsoft.Windows.MSPaint~~~~0.0.1.0 `
    /capabilityname:Microsoft.Windows.Notepad~~~~0.0.1.0 `
    /capabilityname:Microsoft.Windows.PowerShell.ISE~~~~0.0.1.0 `
    /capabilityname:Microsoft.Windows.StorageManagement~~~~0.0.1.0 `
    /capabilityname:Microsoft.Windows.WordPad~~~~0.0.1.0 `
    /capabilityname:Msix.PackagingTool.Driver~~~~0.0.1.0 `
    /capabilityname:NetFX3~~ `
    /capabilityname:Network.Irda~~~~0.0.1.0 `
    /capabilityname:OneCoreUAP.OneSync~~~~0.0.1.0 `
    /capabilityname:OpenSSH.Client~~~~0.0.1.0 `
    /capabilityname:OpenSSH.Server~~~~0.0.1.0 `
    /capabilityname:Print.EnterpriseCloudPrint~~~~0.0.1.0 `
    /capabilityname:Print.Fax.Scan~~~~0.0.1.0 `
    /capabilityname:Print.Management.Console~~~~0.0.1.0 `
    /capabilityname:Print.MopriaCloudService~~~~0.0.1.0 `
    /capabilityname:RasCMAK.Client~~~~0.0.1.0 `
    /capabilityname:RIP.Listener~~~~0.0.1.0 `
    /capabilityname:Rsat.ActiveDirectory.DS-LDS.Tools~~~~0.0.1.0 `
    /capabilityname:Rsat.BitLocker.Recovery.Tools~~~~0.0.1.0 `
    /capabilityname:Rsat.CertificateServices.Tools~~~~0.0.1.0 `
    /capabilityname:Rsat.DHCP.Tools~~~~0.0.1.0 `
    /capabilityname:Rsat.Dns.Tools~~~~0.0.1.0 `
    /capabilityname:Rsat.FailoverCluster.Management.Tools~~~~0.0.1.0 `
    /capabilityname:Rsat.FileServices.Tools~~~~0.0.1.0 `
    /capabilityname:Rsat.GroupPolicy.Management.Tools~~~~0.0.1.0 `
    /capabilityname:Rsat.IPAM.Client.Tools~~~~0.0.1.0 `
    /capabilityname:Rsat.LLDP.Tools~~~~0.0.1.0 `
    /capabilityname:Rsat.NetworkController.Tools~~~~0.0.1.0 `
    /capabilityname:Rsat.NetworkLoadBalancing.Tools~~~~0.0.1.0 `
    /capabilityname:Rsat.RemoteAccess.Management.Tools~~~~0.0.1.0 `
    /capabilityname:Rsat.RemoteDesktop.Services.Tools~~~~0.0.1.0 `
    /capabilityname:Rsat.ServerManager.Tools~~~~0.0.1.0 `
    /capabilityname:Rsat.Shielded.VM.Tools~~~~0.0.1.0 `
    /capabilityname:Rsat.StorageMigrationService.Management.Tools~~~~0.0.1.0 `
    /capabilityname:Rsat.StorageReplica.Tools~~~~0.0.1.0 `
    /capabilityname:Rsat.SystemInsights.Management.Tools~~~~0.0.1.0 `
    /capabilityname:Rsat.VolumeActivation.Tools~~~~0.0.1.0 `
    /capabilityname:Rsat.WSUS.Tools~~~~0.0.1.0 `
    /capabilityname:ServerCore.AppCompatibility~~~~0.0.1.0 `
    /capabilityname:SNMP.Client~~~~0.0.1.0 `
    /capabilityname:Tools.DeveloperMode.Core~~~~0.0.1.0 `
    /capabilityname:Tools.Graphics.DirectX~~~~0.0.1.0 `
    /capabilityname:Windows.Client.ShellComponents~~~~0.0.1.0 `
    /capabilityname:Windows.Desktop.EMS-SAC.Tools~~~~0.0.1.0 `
    /capabilityname:WMI-SNMP-Provider.Client~~~~0.0.1.0 `
    /capabilityname:XPS.Viewer~~~~0.0.1.0

    # This one is large, lets skip for now
    #/capabilityname:Analog.Holographic.Desktop~~~~0.0.1.0 `


# Copy language caps to the repo
Copy-Item -Path $OS_LP_PATH -Destination $REPO_PATH -Force -ErrorAction stop | Out-Null

# Dismount OS image
Dismount-WindowsImage -Path $MAIN_OS_MOUNT -Discard -ErrorAction ignore | Out-Null

# Dismount ISO images
Write-Host "Dismounting ISO images"
Dismount-DiskImage -ImagePath $LP_ISO_PATH -ErrorAction ignore | Out-Null
Dismount-DiskImage -ImagePath $FOD_ISO_PATH -ErrorAction ignore | Out-Null

원본 운영 체제에서 선택적 콘텐츠 저장

원본 운영 체제에 선택적 콘텐츠 상태를 저장하기 위해 운영 체제가 설치되기 전에 실행할 사용자 지정 작업 스크립트를 만듭니다. 이 스크립트에서는 선택적 기능 및 언어 리소스를 파일에 저장합니다. 또한 원본 운영 체제에 설치된 언어에 따라 필요한 파일만 사용하여 리포지토리의 로컬 복사본을 만듭니다. 이 작업은 복사할 파일을 제한합니다.

$OUTPUT_PATH = "C:\TEMP\"
$LOG_PATH = $OUTPUT_PATH + "log.txt"
$OUTPUT_PATH = "C:\TEMP\"
$LOG_PATH = $OUTPUT_PATH + "log.txt"
$LANG_PATH = $OUTPUT_PATH + "sourceLang.txt"
$CAP_PATH = $OUTPUT_PATH + "sourceCapability.txt"
$OSVERSION_PATH = $OUTPUT_PATH + "sourceVersion.txt"
$REPO_PATH = "Z:\Repo\"
$LOCAL_REPO_PATH = $OUTPUT_PATH + "Local_Repo\"

Function Get-TS { return "{0:HH:mm:ss}" -f (Get-Date) }

Function Log
{
	param (
        [Parameter(Mandatory=$True)]
        [string]$MESSAGE
	)

    $M = "$(Get-TS): PreInstall: $MESSAGE"
    Write-Host $M
    Add-Content -Path $LOG_PATH -Value $M

 }

Function IsLangFile
{
	param (
        [Parameter(Mandatory=$True)]
        [string]$PATH
	)

    if (($PATH -match '[-_~]ar[-_~]') -or ($PATH -match '[-_~]bg[-_~]') -or ($PATH -match '[-_~]cs[-_~]') -or `
        ($PATH -match '[-_~]da[-_~]') -or ($PATH -match '[-_~]de[-_~]') -or ($PATH -match '[-_~]el[-_~]') -or `
        ($PATH -match '[-_~]en[-_~]') -or ($PATH -match '[-_~]es[-_~]') -or ($PATH -match '[-_~]et[-_~]') -or `
        ($PATH -match '[-_~]fi[-_~]') -or ($PATH -match '[-_~]fr[-_~]') -or ($PATH -match '[-_~]he[-_~]') -or `
        ($PATH -match '[-_~]hr[-_~]') -or ($PATH -match '[-_~]hu[-_~]') -or ($PATH -match '[-_~]it[-_~]') -or `
        ($PATH -match '[-_~]ja[-_~]') -or ($PATH -match '[-_~]ko[-_~]') -or ($PATH -match '[-_~]lt[-_~]') -or `
        ($PATH -match '[-_~]lv[-_~]') -or ($PATH -match '[-_~]nb[-_~]') -or ($PATH -match '[-_~]nl[-_~]') -or `
        ($PATH -match '[-_~]pl[-_~]') -or ($PATH -match '[-_~]pt[-_~]') -or ($PATH -match '[-_~]ro[-_~]') -or `
        ($PATH -match '[-_~]ru[-_~]') -or ($PATH -match '[-_~]sk[-_~]') -or ($PATH -match '[-_~]sl[-_~]') -or `
        ($PATH -match '[-_~]sv[-_~]') -or ($PATH -match '[-_~]th[-_~]') -or ($PATH -match '[-_~]tr[-_~]') -or `
        ($PATH -match '[-_~]uk[-_~]') -or ($PATH -match '[-_~]zh[-_~]') -or ($PATH -match '[-_~]sr[-_~]')) {
        return $True
    }
    else {
        return $False
    }
 }

# Remove the log
Remove-Item -Path $LOG_PATH -Force -ErrorAction ignore | Out-Null
Log "Starting"

# Remove state files, keep repo if it exists
Remove-Item -Path $LANG_PATH -Force -ErrorAction ignore | Out-Null
Remove-Item -Path $CAP_PATH -Force -ErrorAction ignore | Out-Null
Remove-Item -Path $OSVERSION_PATH -Force -ErrorAction ignore | Out-Null

# Get OS version, to use later for detecting compat scans versus OS installation
$OSINFO = Get-CimInstance Win32_OperatingSystem
Log "OS Version: $($OSINFO.Version)"
Add-Content -Path $OSVERSION_PATH -Value $OSINFO.Version

# Get installed languages from international settings
$INTL = DISM.exe /Online /Get-Intl /English

# Save only output lines with installed languages
$LANGUAGES = $INTL | Select-String -SimpleMatch 'Installed language(s)'

# Replace with null so we have a simple list of language codes
$LANGUAGES = $LANGUAGES | ForEach-Object {$_.Line.Replace("Installed language(s): ","")}

# Save System Language, save only output line with default system language
$SYSLANG = $INTL | Select-String -SimpleMatch 'Default system UI language'

# Replace with null so we have the language code
$SYSLANG = $SYSLANG | ForEach-Object {$_.Line.Replace("Default system UI language : ","")}

# Save these languages
Log "Default system UI language on source OS: $($SYSLANG)"
ForEach ($ITEM in $LANGUAGES) {
    Log "Installed language on source OS: $($ITEM)"
    Add-Content -Path $LANG_PATH -Value $ITEM
}

# Get and save installed packages, we'll use this for debugging
$PACKAGES = Get-WindowsPackage -Online
ForEach ($ITEM in $PACKAGES) {
    if($ITEM.PackageState -eq "Installed") {
        Log "Package $($ITEM.PackageName) is installed"
    }
}

# Get and save capabilities
$CAPABILITIES = Get-WindowsCapability -Online
ForEach ($ITEM in $CAPABILITIES) {
    if($ITEM.State -eq "Installed") {
        Log "Capability $($ITEM.Name) is installed"
        Add-Content -Path $CAP_PATH -Value $ITEM.Name
    }
}

# Copy a subset of the Repo files locally, all neutral files and the languages needed
$REPO_FILES = Get-ChildItem $REPO_PATH -file -Recurse
ForEach ($FILE in $REPO_FILES) {
    $PATH = ($FILE.DirectoryName + "\") -Replace [Regex]::Escape($REPO_PATH), $LOCAL_REPO_PATH
    If (!(Test-Path $Path)) {
        New-Item -ItemType Directory -Path $PATH -Force | Out-Null
    }
    If ((IsLangFile $FILE.Name)) {

        # Only copy those files where we need the primary languages from the source OS
        ForEach ($ITEM in $LANGUAGES) {
            if ($FILE.Name -match $Item) {

                If (!(Test-Path (Join-Path $Path $File.Name))) {
                    Copy-Item $FILE.FullName -Destination $PATH -Force
                    Log "Copied file $($FILE.FullName) to local repository"
                }
                else {
                    Log "File $($FILE.Name) already exists in local repository"
                }
            }
        }
    } Else {

        # Copy all 'neutral files' and those language specific that are not in the core 38
        If (!(Test-Path (Join-Path $Path $File.Name))) {
            Copy-Item $FILE.FullName -Destination $PATH -Force
            Log "Copied file $($FILE.FullName) to local repository"
        }
        else {
            Log "File $($FILE.Name) already exists in local repository"
        }
    }
}

Log ("Exiting")

대상 운영 체제에서 선택적 콘텐츠 추가

설치가 성공적으로 완료되면 success.cmd 사용하여 원본 운영 체제에서 선택적 콘텐츠 상태를 검색하고 누락된 경우에만 새 운영 체제에 설치합니다. 그런 다음, 최신 월별 업데이트를 최종 단계로 적용합니다.

$OUTPUT_PATH = "C:\TEMP\"
$LOG_PATH = $OUTPUT_PATH + "log.txt"
$LANG_PATH = $OUTPUT_PATH + "sourceLang.txt"
$CAP_PATH = $OUTPUT_PATH + "sourceCapability.txt"
$OSVERSION_PATH = $OUTPUT_PATH + "sourceVersion.txt"
$LOCAL_REPO_PATH = $OUTPUT_PATH + "Local_Repo\"
$LCU_PATH = $OUTPUT_PATH + "Windows10.0-KB4565503-x64_PSFX.cab"
$PENDING = $false

Function Get-TS { return "{0:HH:mm:ss}" -f (Get-Date) }

Function Log
{
	param (
        [Parameter(Mandatory=$True)]
        [string]$MESSAGE
	)

    $M = "$(Get-TS): PostInstall: $MESSAGE"
    Write-Host $M
    Add-Content -Path $LOG_PATH -Value $M

 }

Log "Starting"

# Get OS version
$OSINFO = Get-CimInstance Win32_OperatingSystem
Log "OS Version: $($OSINFO.Version)"

# Check for source OS state, just to be sure
if (!(Test-Path $LANG_PATH) -or !(Test-Path $CAP_PATH) -or !(Test-Path $OSVERSION_PATH) ) {
    Log "Source OS state is missing."
}

# If this script is executing and the OS version hasn't changed, let's exit out.
else {

    # Retrive OS version from source OS
    $SOURCE_OSVERSION  = Get-Content -Path $OSVERSION_PATH
    if ($OSINFO.Version -eq $SOURCE_OSVERSION) {
        Log "OS Version hasn't changed."
    }

    else {

        # Retrive language list from source OS
        $SOURCE_LANGUAGES  = Get-Content -Path $LANG_PATH

        # Get installed languages from International Settings
        $INTL = DISM.exe /Online /Get-Intl /English

        # Save System Language, save only output line with default system language
        $SYS_LANG = $INTL | Select-String -SimpleMatch 'Default system UI language'

        # Replace with null so we have the language code
        $SYS_LANG = $SYS_LANG | ForEach-Object {$_.Line.Replace("Default system UI language : ","")}

        # Get and save installed packages, we'll use this for debugging
        $PACKAGES = Get-WindowsPackage -Online
        ForEach ($ITEM in $PACKAGES) {
            if($ITEM.PackageState -eq "Installed") {
                Log "Package $($ITEM.PackageName) is installed"
            }
        }

        # Loop through source OS languages, and install if missing on target OS
        ForEach ($SOURCE_ITEM in $SOURCE_LANGUAGES) {
            if ($SOURCE_ITEM -ne $SYS_LANG) {

                # add missing languages except the system language
                Log "Adding language Microsoft-Windows-Client-Language-Pack_x64_$($SOURCE_ITEM).cab"
                try {
                    Add-WindowsPackage -Online -PackagePath "$($LOCAL_REPO_PATH)\Microsoft-Windows-Client-Language-Pack_x64_$($SOURCE_ITEM).cab" -ErrorAction stop | Out-Null
                }
                catch {
                    Log $_.Exception.Message
                }
            }
        }

        # Retrieve capabilities from source OS and target OS
        $SOURCE_CAPABILITIES  = Get-Content -Path $CAP_PATH
        $CAPABILITIES = Get-WindowsCapability -Online

        # Loop through source OS capabilities, and install if missing on target OS
        ForEach ($SOURCE_ITEM in $SOURCE_CAPABILITIES) {
            $INSTALLED = $false
            ForEach ($ITEM in $CAPABILITIES) {
                if ($ITEM.Name -eq $($SOURCE_ITEM)) {
                    if ($ITEM.State -eq "Installed") {
                        $INSTALLED = $true
                        break
                    }
                }
            }

            # Add if not already installed
            if (!($INSTALLED)) {
                Log "Adding capability $SOURCE_ITEM"
                try {
                    Add-WindowsCapability -Online -Name $SOURCE_ITEM -Source $LOCAL_REPO_PATH -ErrorAction stop | Out-Null
                }
                catch {
                    Log $_.Exception.Message
                }
            }
            else {
                Log "Capability $SOURCE_ITEM is already installed"
            }
        }

        # Add LCU, this is required after adding FODs and languages
        Log ("Adding LCU")
        Add-WindowsPackage -Online -PackagePath $LCU_PATH -NoRestart

        # Get packages, we'll use this for debugging and to see if we need to restart to install
        $PACKAGES = Get-WindowsPackage -Online
        ForEach ($ITEM in $PACKAGES) {
            Log "Package $($ITEM.PackageName) is $($ITEM.PackageState)"
            if ($ITEM.PackageState -eq "InstallPending") {
                $PENDING = $true
            }
        }
    }
}

# Remove local repository and state files
Remove-Item -Path $LANG_PATH -Force -ErrorAction ignore | Out-Null
Remove-Item -Path $CAP_PATH -Force -ErrorAction ignore | Out-Null
Remove-Item -Path $OSVERSION_PATH -Force -ErrorAction ignore | Out-Null
Remove-Item -Path $LOCAL_REPO_PATH -Force -Recurse -ErrorAction ignore | Out-Null

# Restarting the computer to let setup process to exit cleanly
if ($PENDING) {
    Log ("Install pending packages exists, restarting in 10 seconds")
    Start-Process -FilePath cmd -ArgumentList "/C shutdown /r /t 10 /f"
}

Log ("Exiting")