NpmDsc.psm1
# Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. using namespace System.Collections.Generic # Assert once that NPM is already installed on the system. Assert-Npm $global:useNpmCmd = $false $global:npmCmdPath = "$env:ProgramFiles\nodejs\npm.cmd" #region DSCResources [DSCResource()] class InstallNpm { # DSCResource requires a key. Do not set. [DscProperty(Key)] [string]$SID [DscProperty()] [string]$packageDirectory [DscProperty()] [string]$arguments [DscProperty()] [bool]$global [DscProperty(NotConfigurable)] [bool]$installAvailable [InstallNpm] Get() { if (-not ([string]::IsNullOrEmpty($this.packageDirectory))) { VerifyDirectoryAndSetLocation -directoryPath $this.packageDirectory } # `npm list` returns a nonzero exit code if there are missing packages to install. $listResult = Invoke-NpmList $this.installAvailable = $listResult.ExitCode -ne 0 return @{ packageDirectory = $this.packageDirectory arguments = $this.arguments global = $this.global installAvailable = $this.installAvailable } } [bool] Test() { $currentState = $this.Get() return $currentState.installAvailable -eq $false } [void] Set() { if ($this.Test() -eq $false) { Invoke-NpmInstall -Arguments $this.arguments -Global $this.global } } } [DSCResource()] class InstallNpmPackage { # DSCResource requires a key. Do not set. [DscProperty(Key)] [string]$SID [DscProperty(Mandatory)] [string[]]$packages [DscProperty()] [string]$packageDirectory [DscProperty()] [string]$arguments [DscProperty()] [bool]$global [DscProperty(NotConfigurable)] [bool]$installedStatus [InstallNpmPackage] Get() { if (-not ([string]::IsNullOrEmpty($this.packageDirectory))) { VerifyDirectoryAndSetLocation -directoryPath $this.packageDirectory } # Set initial value of installedStatus to true so that if any of the packages are not installed, it returns false. $this.installedStatus = $true foreach ($package in $this.packages) { $localResult = Invoke-NpmList -PackageName $package -Global $this.global $this.installedStatus = $this.installedStatus -and ($localResult.ExitCode -eq 0) } return @{ SID = $this.SID packageDirectory = $this.packageDirectory packages = $this.packages arguments = $this.arguments installedStatus = $this.installedStatus } } [bool] Test() { $currentState = $this.Get() return $currentState.installedStatus } [void] Set() { if ($this.Test() -eq $false) { foreach ($package in $this.packages) { Invoke-NpmInstall -PackageName $package -Arguments $this.arguments -Global $this.global } } } } #endregion DSCResources #region Functions function Assert-Npm { # Try invoking npm help with the alias. If it fails, switch to calling npm.cmd directly. # This may occur if npm is installed in the same shell window and the alias is not updated until the shell window is restarted. try { Invoke-Npm -command 'help' return } catch {} if (Test-Path -Path $global:npmCmdPath) { $global:useNpmCmd = $true; Write-Host "Calling npm.cmd directly located at: $global:useNpmCmd" } else { throw "NodeJS is not installed" } } function Invoke-NpmInstall { param ( [Parameter()] [string]$PackageName, [Parameter()] [string]$Arguments, [Parameter()] [bool]$Global ) $command = [List[string]]::new() $command.Add("install") $command.Add($PackageName) $command.Add($Arguments) if ($Global) { $command.Add("-g") } return Invoke-Npm -command $command } function Invoke-NpmList { param ( [Parameter()] [string]$PackageName, [Parameter()] [string]$Arguments, [Parameter()] [bool]$Global ) $command = [List[string]]::new() $command.Add("list") $command.Add($PackageName) $command.Add($Arguments) if ($Global) { $command.Add("-g") } return Invoke-Npm -command $command } function Invoke-NpmUninstall { param ( [Parameter(Mandatory)] [string]$PackageName, [Parameter()] [string]$Arguments ) $command = [List[string]]::new() $command.Add("uninstall") $command.Add($PackageName) $command.Add($Arguments) return Invoke-Npm -command $command } function Invoke-Npm { param ( [Parameter(Mandatory)] [string]$command ) if ($global:useNpmCmd) { return Start-Process -FilePath $global:npmCmdPath -ArgumentList $command -Wait -PassThru -WindowStyle hidden } else { return Start-Process -FilePath npm -ArgumentList $command -Wait -PassThru -WindowStyle hidden } } function VerifyDirectoryAndSetLocation { param ( [Parameter(Mandatory)] [string]$directoryPath ) if (Test-Path -Path $directoryPath -PathType Container) { Set-Location -Path $directoryPath } else { throw "Path does not point to a valid directory." } } #endregion Functions |