NVM is a life saver when you want to work with multiple version of node.js

NVM

Fixing – Error: Cannot find module ‘C:\Program Files\nodejs\node_modules\npm\bin\npm-cli.js’

A very common issue most people face when working with nvm tool is that after a fresh setup of this tool the npm command does not seem to find the npm-cli.js. The reason being that the setup process fail to copy few needed files to the expected location.

Though there is no official fix available for this issue as of now, a work around is available as below:

Existing environment:

  • Windows 10 professional x64
  • nvm installed path – C:\nvm

Steps

Visit the url – https://nodejs.org/en/download/releases/ and download the source for the node.js version that you are trying to work with.

Extract the zip content and copy the npm folder to “C:\nvm\v8.16.0\node_modules

once you are done with the above, you can use the npm command without any issue:

Note: You will need to repeat the above steps for each version of node.js that you are intending to use

if you don’t patch the installation as shown above, you will face with the following error:

Error: Cannot find module 'C:\Program Files\nodejs\node_modules\npm\bin\npm-cli.js'
    at Function.Module._resolveFilename (module.js:547:15)
    at Function.Module._load (module.js:474:25)
    at Function.Module.runMain (module.js:693:10)
    at startup (bootstrap_node.js:188:16)
    at bootstrap_node.js:609:3
module.js:549
    throw err;
    ^

Error: Cannot find module 'C:\Program Files\nodejs\node_modules\npm\bin\npm-cli.js'
    at Function.Module._resolveFilename (module.js:547:15)
    at Function.Module._load (module.js:474:25)
    at Function.Module.runMain (module.js:693:10)
    at startup (bootstrap_node.js:188:16)
    at bootstrap_node.js:609:3

Innovative Enablement of UX Drives Adoption

In Software Development, “Why you put User Experience before Programming?” The reason being that the UX is an integral component of problem solving. It is an essential discipline to follow when building a solution. UX gives a developer a clear direction and makes a strong impact in delivering software solutions. Without UX you can successfully implement a crappy solution which no one will adopt.

There are plenty of software out there are crappy, unusable and bloated with unnecessary features. No matter how effective, configurable, or powerful a software product may be, if users can’t learn to adopt to it quickly and painlessly, its value will be diluted.

The IT as a Utility

The IT infrastructure world has a history divided into:
<> The 90s for Networking
<> The 00s for Virtualization
<> The 10s for Cloud

So, if you still have not thought of cloud. you just living a life with trust issues and outdated technology.

Creating and Configuring Resource Mailboxes

  1. Create and Configure a Resource in Office 365 Admin

  2. Create and Configure a Resource in Exchange Online Admin

  3. Create a Resource with PowerShell

Create and Configure a Resource in Office 365 Admin

  1. Open your browser and navigate to http://portal.office.com
  2. Enter the account associated with your Office 365 tenant

2017-06-18_18-42-16

3. Navigate to the Admin Center by clicking the Waffle and Admin

image

4. Expand out Resources and click on Rooms & equipment

image

5. Click on + Add to add a new resource

6. Leave it set to type Room and then fill out the rest of the information: Name, Email, Capacity, Location and a Phone Number

7. Click Add at the bottom

8. You should now have a new resources added to your list.

9. Set the scheduling options by clicking Set scheduling options

10. This will show the room details you can configure around accepting requests for this resource.

11. You can either click save or Cancel.

You now have a new room added to your Office 365 tenant that is available for users to book when creating a meeting in Outlook.

Create and Configure a Resource in Exchange Online Admin

1. In the Office 365 Admin Center, expand out Admin Centers and click on Exchange

2. This will take you into the Exchange Online Admin Center. From here, click on resources under the recipients heading.

3. Here you can see the resources created earlier. To add another resource, click + and then click Equipment mailbox

4. This will popup a dialog box where you can enter the Equipment Name and E-mail address. Fill out the two text boxes and click Save. If you have multiple domains in your tenant, you can also select the FQDN for your mailbox.

5. You now have your new equipment resource created. Let’s edit this resource by double clicking on it.

6. Double click on the resource, it brings up all the additional information you saw when working with a resource in the Office 365 Admin Centre.

7. Click on booking delegates, this is where you can disable auto acceptance of requests and specify a delegate the must manually approve or deny resource requests.

8. Click on booking options next. Here is where we see those options that were available to us in the Office 365 Admin Center around configuring what is allowed or not allowed when booking a resource.

9. Uncheck Allow repeating meetings and click Save

10. Now, if any meeting requests come in that are recurring meetings to book this resource, they will be automatically denied.

Create a Resource with PowerShell

1. Log into a Windows machine with PowerShell installed

2. Open a PowerShell Console

3. Establish a new Exchange Online remote PowerShell session by running:

$UserCredential = Get-Credential
$Session = New-PSSession -ConfigurationName Microsoft.Exchange `
-ConnectionUri https://outlook.office365.com/powershell-liveid/ `
-Credential $UserCredential -Authentication Basic -AllowRedirection
Import-PSSession $Session 

4. Get what’s available. You can review existing resources by running the following PowerShell.

Get-Mailbox | Where {$_.ResourceType -eq "Room" -or $_.ResourceType -eq "Equipment"} 

5. Your window should like the one below:

6. Now, to create a new resource. Run

New-Mailbox -Name "PowerShell Room" -Room

This will create a new Room resource that will immediately show up when looking at the Office 365 Admin Centre or the Exchange Online Admin Centre. However, unlike the two mailboxes before, the Auto accept meeting requests will be Off.

7. Now that we have our new mailbox, run the following PowerShell again.

Get-Mailbox | Where {$_.ResourceType -eq "Room" -or $_.ResourceType -eq "Equipment"} 

You should see all three resource mailboxes now.  Let’s configure the one we just created.

8. First, let’s turn on Auto Accept with this PowerShell cmdlet

Set-CalendarProcessing -Identity "PowerShell Room" -AutomateProcessing AutoAccept 

9. Next, let’s configure a setting you can only set in PowerShell

Set-CalendarProcessing -EnforceSchedulingHorizon $false

If this is set to false, as long as a recurring meeting is scheduled to start on or before the window specified in the settings, the meeting request will be accepted rather than denied.

Search/Identify blocked file types in SharePoint

In SharePoint 2016 On-Prem, Microsoft has reduced the number of blocked file types from previous versions of SharePoint. It is totally different than the SharePoint 2010 / 2013. In SharePoint 2013, there are 105 default file types that are blocked by default but in SharePoint 2016, this number goes all the way down to 6. Interestingly, there is no blocked file type in SharePoint Online.

Self-Note:

Block type references:

Small Script to find all blocked file types:

$path = "C:\DRIVERS";
$extensitons = @("*.ade","*.adp","*.asa","*.ashx","*.asmx","*.asp","*.bas","*.bat","*.cdx","*.cer",`
                "*.chm","*.class","*.cmd","*.cnt","*.com","*.config","*.cpl","*.crt","*.csh","*.der",`
                "*.dll","*.exe","*.fxp","*.gadget","*.grp","*.hlp","*.hpj","*.hta","*.htr","*.htw","*.ida",`
                "*.idc","*.idq","*.ins","*.isp","*.its","*.jse","*.json","*.ksh","*.lnk","*.mad","*.maf","*.mag",`
                "*.mam","*.maq","*.mar","*.mas","*.mat","*.mau","*.mav","*.maw","*.mcf","*.mda","*.mdb",`
                "*.mde","*.mdt","*.mdw","*.mdz","*.ms-one-stub","*.msc","*.msh","*.msh1","*.msh1xml",`
                "*.msh2","*.msh2xml","*.mshxml","*.msi","*.msp","*.mst","*.ops","*.pcd","*.pif","*.pl",`
                "*.prf","*.prg","*.printer","*.ps1","*.ps1xml","*.ps2","*.ps2xml","*.psc1","*.psc2","*.pst",`
                "*.reg","*.rem","*.scf","*.scr","*.sct","*.shb","*.shs","*.shtm","*.shtml","*.soap",`
                "*.stm","*.svc","*.url","*.vb","*.vbe","*.vbs","*.vsix","*.ws","*.wsc","*.wsf","*.wsh","*.xamlx");

Get-Childitem -r -path $path\* -include $extensitons | %{$_.fullname}

#Optionally push results to a text file
#Get-Childitem -r -path $path\* -include $extensions | %{$_.fullname} > C:\File_Extensions.txt

image

Configuring Workflow Manager 1.0 (With Cumulative Update 3) for SharePoint Workflow 2013

Self Note:

  • Service account for Workflow Manager DEV\WFM_Service
  • Ensure Management Service for Internet Information Service is configured
  • Web Platform Installer Installed
  • Management Database SQL Instance    .\SQLEXPRESS

First things first, Workflow Manager is a separate installation from SharePoint, available on the web. I used the latest version of the Web Platform Installer to pull down the files. I had to install WPI first.

With WPI installed, open an elevated console and run the following command:

webpicmd /offline /Products:WorkflowManagerRefresh /Path:C:/Users/Administrator/WorkflowManagerFiles

We now have the Workflow Manager installation files in c:WorkflowManagerFiles. Installing WFM is a simple case of running the following command:

WebpiCmd.exe /Install /Products:WorkflowManagerRefresh /XML:C:/Users/Administrator/WorkflowManagerFiles/feeds/latest/webproductlist.xml

Note: Make sure you install the ‘Refresh’ of WFM if installing on Windows Server 2012 R2. Installing the original 1.0 version causes issues when registering WFM with SharePoint 2013. I strongly recommend patching SharePoint 2013 to SP1.

Configurewfm.ps1

$dbServer = ".\SQLEXPRESS";  #- SQL Alias for my SQL server (best to use an alias not the server name)
$dbPrefix = "SPDEV"; #- Prefix for all my database names
$spServiceAcctName = "DEV\WFM_Service"; #- Name of my service account (used for workflow manager)
$spServiceAcctPWD = "1qaz2wsx@"; #- Password for my service account
$spAdminAcct = "DEV\SP_Farm"; #- Admin account for SharePoint
$passphrase = "1qaz2wsx@"; #- Passphrase used by WFM when joining new hosts to the farm

function WFM-Configure {
    # Create new SB Farm
    $SBCertificateAutoGenerationKey = ConvertTo-SecureString -AsPlainText  -Force  -String $passphrase;
    $WFCertAutoGenerationKey = ConvertTo-SecureString -AsPlainText  -Force  -String $passphrase;
    $managementCS = 'Data Source=' + $dbServer + ';Initial Catalog=' + $dbPrefix + '_WFMSB_Management;Integrated Security=True;Encrypt=False';
    $gatewayCS = 'Data Source=' + $dbServer + ';Initial Catalog=' + $dbPrefix + '_WFMSB_Gateway;Integrated Security=True;Encrypt=False';
    $messageContCS = 'Data Source=' + $dbServer + ';Initial Catalog=' + $dbPrefix + '_WFMSB_MessageContainer;Integrated Security=True;Encrypt=False';
    Write-Host -ForegroundColor White ' - Creating new Service Bus farm...' -NoNewline;
    try {
        $sbFarm = Get-SBFarm -SBFarmDBConnectionString $managementCS;
        Write-Host -ForegroundColor White 'Already Exists';
    }
    catch {
        New-SBFarm -SBFarmDBConnectionString $managementCS -InternalPortRangeStart 9000 -TcpPort 9354 -MessageBrokerPort 9356 -RunAsAccount $spServiceAcctName `
            -AdminGroup 'BUILTINAdministrators' -GatewayDBConnectionString $gatewayCS -CertificateAutoGenerationKey $SBCertificateAutoGenerationKey `
            -MessageContainerDBConnectionString $messageContCS;
        Write-Host -ForegroundColor White 'Done';
    }
    # Create new WF Farm
    Write-Host -ForegroundColor white ' - Creating new Workflow Farm...' -NoNewline;
    $wfManagementCS = 'Data Source=' + $dbServer + ';Initial Catalog=' + $dbPrefix + '_WFM_Management;Integrated Security=True;Encrypt=False';
    $wfInstanceCS = 'Data Source=' + $dbServer + ';Initial Catalog=' + $dbPrefix + '_WFM_InstanceManagement;Integrated Security=True;Encrypt=False';
    $wfResourceCS = 'Data Source=' + $dbServer + ';Initial Catalog=' + $dbPrefix + '_WFM_ResourceManagement;Integrated Security=True;Encrypt=False';
    try {
        $wfFarm = Get-WFFarm -WFFarmDBConnectionString $wfManagementCS;
        Write-Host -ForegroundColor White 'Already Exists';
    }
    catch {
        New-WFFarm -WFFarmDBConnectionString $wfManagementCS -RunAsAccount $spServiceAcctName -AdminGroup 'BUILTINAdministrators' -HttpsPort 12290 -HttpPort 12291 `
            -InstanceDBConnectionString $wfInstanceCS -ResourceDBConnectionString $wfResourceCS -CertificateAutoGenerationKey $WFCertAutoGenerationKey;
        Write-Host -ForegroundColor white 'Done';
    }
    # Add SB Host
    Write-Host -ForegroundColor white ' - Adding Service Bus host...' -NoNewline;
    try {
        $SBRunAsPassword = ConvertTo-SecureString -AsPlainText  -Force  -String $spServiceAcctPwd;
        Add-SBHost -SBFarmDBConnectionString $managementCS -RunAsPassword $SBRunAsPassword -EnableHttpPort `
            -EnableFirewallRules $true -CertificateAutoGenerationKey $SBCertificateAutoGenerationKey;
        Write-Host -ForegroundColor white 'Done';
    } 
    catch {
        Write-Host -ForegroundColor white 'Already Exists';
    }
    Write-Host -ForegroundColor white ' - Creating Workflow Default Namespace...' -NoNewline;
    $sbNamespace = $dbPrefix + '-WorkflowNamespace';
    try {
        $defaultNS = Get-SBNamespace -Name $sbNamespace -ErrorAction SilentlyContinue;
        Write-Host -ForegroundColor white 'Already Exists';
    }
    catch {
        try {
            # Create new SB Namespace
            $currentUser = $env:userdomain + '' + $env:username;
            New-SBNamespace -Name $sbNamespace -AddressingScheme 'Path' -ManageUsers $spServiceAcctName,$spAdminAcctName,$currentUser;
            Start-Sleep -s 90
            Write-Host -ForegroundColor white 'Done';
        }
        catch [system.InvalidOperationException] {
            throw;
        }
    }
    # Get SB Client Configuration
    $SBClientConfiguration = Get-SBClientConfiguration -Namespaces $sbNamespace;
    # Add WF Host
    try {
        $WFRunAsPassword = ConvertTo-SecureString -AsPlainText  -Force  -String $spServiceAcctPwd;
        Write-Host -ForegroundColor White ' - Adding Workflow Host...' -NoNewline;
        Add-WFHost -WFFarmDBConnectionString $wfManagementCS `
        -RunAsPassword $WFRunAsPassword -EnableFirewallRules $true `
        -SBClientConfiguration $SBClientConfiguration -CertificateAutoGenerationKey $WFCertAutoGenerationKey;
        Write-Host -ForegroundColor White 'Done';
    }
    catch {
        Write-Host -ForegroundColor white "Already Exists";
    }
}

WFM-Configure -verbose

Execution Output:

Starting
Created and configured Service Bus farm management database.
Created and configured Service Bus gateway database.
Creating default container.


Processing completed
Created and configured farm management database.
Created and configured Workflow Manager resource management database.
Created and configured Workflow Manager instance management database.
Microsoft.Workflow.Deployment.Commands.WFFarmInfo

Processing completed
Validating input and configuration parameters.
Installing auto-generated certificate.
Granting 'Log on as Service' privilege to the run as account.
Windows Fabric configuration started.
Running Windows Fabric deployment.
Windows Fabric starting.
Service Bus configuration started.
Updating database.
Service Bus services starting.
Updating local registry.
Successfully added this host to the farm.


Processing completed
SubscriptionId: 00000000000000000000000000000000
State: Active
Name: WorkflowDefaultNamespace
AddressingScheme: Path
CreatedTime: 10/06/2017 4:46:14 AM
IssuerName: WorkflowDefaultNamespace
IssuerUri: WorkflowDefaultNamespace
ManageUsers: wfm_service@dev.com,administrator@dev.com
DnsEntry: 
PrimarySymmetricKey: 4xZiZqwtOD3Umv8t8gDo8uj1SJQuvtDFbjHr4BdyHgQ=
SecondarySymmetricKey: 


Processing completed
Endpoint=sb://sp.dev.com/WorkflowDefaultNamespace;StsEndpoint=https://sp.dev.com:9355/WorkflowDefaultNamespace;RuntimePort=9354;ManagementPort=9355

Processing completed
Installing auto-generated certificate.
Granting 'Log on as Service' privilege to the RunAs account.
Workflow Manager configuration starting.
Configuring Workflow Manager runtime settings.
Workflow service starting.
Updating database and local registry.
 Successfully added this host to the farm.
Microsoft.Workflow.Deployment.Commands.WFFarmInfo

Processing completed

“Replicating Directory Permissions” to the User Profile Synchronisation account

Self Note:

To create SharePoint managed service accounts see – https://consultantpoint.wordpress.com/2017/06/07/sharepoint-server-service-accounts-populating-in-active-directory/

Steps to add “Replicating Directory Permissions” to the User Profile Synchronisation account

1> Open “Active Directory Users and Computers”.  Right click on the domain name in the management console and select “Delegate Control…”

image

image

2.> On the “Delegation Control Wizard” click “Next” > On the “Users or Groups” screen used to delegate control.  Click “Add” and add your User Profile Sync account.  Click “Next”.

image

3.> On the “Tasks to Delegate” screen select the option “Create a custom task to delegate” > “Next”.

image

4.> On the “Active Directory Object Type” screen accept the default settings and click “Next”.

image

5.> On the “Permissions” screen check the box to allow “Replicate Directory Changes” and Click “Next”.  The last screen is for review and select “Finish”

To verify that this account got the right settings, run the following script:

import-module ActiveDirectory

# Functions to check AD Accounts has permissions  - I need to change Tobias Lekman's script to work for my environments - this is based on his script
function Check-ADUserPermission(
    [System.DirectoryServices.DirectoryEntry]$entry,
    [string]$user,
    [string]$permission)
{
    $dse = [ADSI]"LDAP://Rootdse"
    $ext = [ADSI]("LDAP://CN=Extended-Rights," + $dse.ConfigurationNamingContext)
	$domain =$env:USERDOMAIN

    $right = $ext.psbase.Children |
        ? { $_.DisplayName -eq $permission }

    if($right -ne $null)
    {
		$mvar = $entry.psbase.ObjectSecurity.Access;
		$objUser = New-Object System.Security.Principal.NTAccount($domain, $user)
        $perms = $entry.psbase.ObjectSecurity.Access |
            ? { $_.IdentityReference.Value.ToLower() -eq $env:USERDOMAIN.ToLower() + "\" + $user.ToLower() } |
            ? { $_.ObjectType -eq [GUID]$right.RightsGuid.Value }

        return ($perms -ne $null)
    }
    else
    {
        Write-Warning "Permission '$permission' not found."
        return $false
    }
}

# Functions to check AD Accounts has Replicating Directory Changes permissions  - based Tobias Lekman's script  http://lekman.codeplex.com/releases/view/65930
function Check-ReplicateChanges([string]$userName)
{
	$replicationPermissionName = "Replicating Directory Changes"
	$dse = [ADSI]"LDAP://Rootdse"
    $entries = @(
        [ADSI]("LDAP://" + $dse.defaultNamingContext),
        [ADSI]("LDAP://" + $dse.configurationNamingContext));
    Write-Host -ForegroundColor Blue " User '$userName': "
    foreach($entry in $entries)
    {
        $result = Check-ADUserPermission $entry $userName $replicationPermissionName
        if($result)
        {
            Write-Host "   has '$replicationPermissionName' permissions on '$($entry.distinguishedName)'" `
                -ForegroundColor Green
        }
        else
        {
            Write-Host "   does NOT have '$replicationPermissionName' permissions on '$($entry.distinguishedName)'" `
                -ForegroundColor Red
			# check if the user is a domain admin
			$user = New-Object System.Security.Principal.WindowsIdentity($userName)
			$WindowsPrincipal = New-Object System.Security.Principal.WindowsPrincipal($User)
			if($WindowsPrincipal.IsInRole("Administrators"))
			{   Write-Host "   is a Domain Administrator" -ForegroundColor Green }
			else
			{
				Write-Host "   add 'replication permissions' or a work around (less secure) is to add the User Profile Sync account as a local admin " -ForegroundColor Red
				Write-Host "   see http://blog.sharepointsite.co.uk/2012/11/powershell-to-create-user-accounts-for.html for instructions to setup accounts and replication" -ForegroundColor Red
			} 			

        }
    }
}

cls 

Check-ReplicateChanges("SP_ProfileSync")

image

The required path is working just fine, so I am not going to bother much about the rest of the path.

SharePoint Server Service Accounts Populating in Active Directory

Self-Note:

Script used to push minimal #service #accounts required for the #SharePoint development server – #PowerShell

$mydom = "dev.com"
$mydomDistinguishedname = (get-addomain).distinguishedname 
$password = "1qaz2wsx@" | ConvertTo-SecureString -AsPlainText -Force 
 
$ouNameSP = "SharePoint Accounts"
$oudnSP = "OU=$ounameSP,$mydomDistinguishedname"
 
$ouNameSQL = "SQL Accounts"
$oudnSQL = "OU=$ounameSQL,$mydomDistinguishedname"
 
#----------------------------> Organizational Unit <---------------------------- 
$spou = Get-ADOrganizationalUnit -Filter * -SearchBase $oudnSP;
if($spou -eq $null){
    New-ADOrganizationalUnit -Name $OUNameSP -Path $mydomDistinguishedname 
    $spou = Get-ADOrganizationalUnit -Filter * -SearchBase $oudnSP;
    Write-Host "$spou Created" -foregroundcolor green 
}
else{
    Write-Host "$spou already exists" -ForegroundColor Yellow
}

$sqlou = Get-ADOrganizationalUnit -Filter * -SearchBase $oudnSQL;
if($sqlou -eq $null){
    New-ADOrganizationalUnit -Name $OUNameSQL -Path $mydomDistinguishedname
    $sqlou = Get-ADOrganizationalUnit -Filter * -SearchBase $oudnSQL;
    Write-Host "$sqlou Created" -foregroundcolor green 
}
else{
    Write-Host "$sqlou already exists" -ForegroundColor Yellow
}
#-----------------------------> SharePoint 2016 <-------------------------------
 
$usersArraySP = @("SP_Farm", "SP_CacheSuperUser", "SP_CacheSuperReader", "SP_Services", "SP_PortalAppPool", "SP_ProfilesAppPool", "SP_SearchService", "SP_SearchContent", "SP_ProfileSync", "SP_ExcelUser", "SP_VisioUser", "SP_PerfPointUser")
 
foreach ($usp in $usersArraySP) {
        New-ADUser -Name $usp -DisplayName $usp -UserPrincipalName "$usp@$mydom" -SamAccountName $usp -AccountPassword $password `
        -ChangePasswordAtLogon  $false -CannotChangePassword $true -PassThru -PasswordNeverExpires $true -Path $spou -Enabled $True
        Write-Host "$usp Created" -foregroundcolor green
 }
 
#----------------------------------> SQL <--------------------------------------
$usersArraySQL = @("SQL_Admin","SQL_Service")
 
foreach ($usql in $usersArraySQL) {
       New-ADUser -Name $usql -DisplayName $usql -UserPrincipalName "$usql@$mydom" -SamAccountName $usql -AccountPassword $password `
        -ChangePasswordAtLogon  $false -CannotChangePassword $true -PassThru -PasswordNeverExpires $true -Path $sqlou -Enabled $True
        Write-Host "$usql Created" -foregroundcolor green
 }

Output:

SharePoint JavaScript Development Useful Links

 

Self-Note:

  • JavaScript Map Parser – When you are editing extremely large javascript files it’s very useful to have some set of tools to improve the performance of development process and avoid possible bugs. To solve this problems I’ve created this extension. Supported versions of Visual Studio: 2010-2015.
  • Web Essentials – Web Essentials extends Visual Studio with a lot of new features that web developers have been missing for many years. If you ever write CSS, HTML, JavaScript, TypeScript, CoffeeScript or LESS, then you will find many useful features that make your life as a developer easier. This is for all Web developers using Visual Studio.
  • JSLint.VS2015 – JSLint.NET for MSBuild adds JavaScript validation targets to any Visual Studio project.
  •  

go.dmann.me/SPJSRes